Snap for 7483611 from 66cbf51f47b5585e46283f32ec4b6a359f4ec4c7 to mainline-neuralnetworks-release

Change-Id: Ieb1d80f11631757445202c42ae404be4cd104b83
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..9f9ffe3
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+# See https://clang.llvm.org/docs/ClangFormatStyleOptions.html for the
+# various options that can be configured and for the definitions of each
+# of the below options.
+
+BasedOnStyle: Google
diff --git a/Android.bp b/Android.bp
index 47afd21..7ad70ee 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13,40 +13,44 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-subdirs = [
-    "common",
-    "guest",
-    "host",
-]
+package {
+    default_applicable_licenses: ["device_google_cuttlefish_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+    name: "device_google_cuttlefish_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-MIT",
+    ],
+    // large-scale-change unable to identify any license_text files
+}
 
 cc_library_headers {
     name: "cuttlefish_common_headers",
-    vendor: true,
+    vendor_available: true,
+    product_available: true,
     export_include_dirs: ["."],
     host_supported: true,
-}
-
-cc_library_headers {
-    name: "cuttlefish_common_headers_product",
-    product_specific: true,
-    export_include_dirs: ["."],
-    host_supported: true,
-}
-
-// TODO(b/67435044) Update the include paths and remove this
-cc_library_headers {
-    name: "cuttlefish_glog",
-    vendor: true,
-    export_include_dirs: ["common/libs"],
-    host_supported: true,
-}
-
-// TODO(b/67435044) Update the include paths and remove this
-cc_library_headers {
-    name: "cuttlefish_glog_product",
-    product_specific: true,
-    export_include_dirs: ["common/libs"],
-    host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
 }
 
 cc_defaults {
@@ -67,45 +71,45 @@
         },
     },
     cflags: ["-Werror", "-Wall", "-D_FILE_OFFSET_BITS=64"],
-    vendor: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
 }
 
+// Defaults for cuttlefish modules that are available only in the guest OS (i.e. cuttlefish running
+// in a guest VM).
+cc_defaults {
+    name: "cuttlefish_guest_only",
+    vendor: true,
+    defaults: ["cuttlefish_base"],
+}
+
+// Same as cuttlefish_guest_only, but modules are placed in /product partition.
 cc_defaults {
     name: "cuttlefish_guest_product_only",
     product_specific: true,
-    gnu_extensions: false,
-    header_libs: [
-        "cuttlefish_common_headers_product",
-    ],
-    target: {
-        host: {
-            host_ldlibs: ["-lrt"],
-            cflags: ["-DCUTTLEFISH_HOST"],
-            compile_multilib: "64",
-        },
-        // We don't need Darwin host-side builds
-        darwin: {
-            enabled: false,
-        },
-    },
-    cflags: ["-Werror", "-Wall"],
-}
-
-cc_defaults {
-    name: "cuttlefish_guest_only",
     defaults: ["cuttlefish_base"],
 }
 
+// Defaults for cuttlefish modules that are available only in the host-side OS. Here "host" includes
+// both (1) non-Android OS like gLinux or Ubuntu, and (2) Android OS that is capable of running
+// guest VM(s) in it. Note that, in the context of the Android build systm - Soong - (1) is called
+// as "host" and (2) is called as "target". But here, the term "host" is in the context of VMs. If a
+// module is for the host-side VM (either Android or non-Android), "cuttlefish_host" shall be used.
 cc_defaults {
-    name: "cuttlefish_host_only",
+    name: "cuttlefish_host",
+    host_supported: true, // this "host" means (1)
+    device_supported: true, // this is for (2)
+    vendor_available: true,
+    defaults: ["cuttlefish_base"],
+}
+
+// Same as "cuttlefish_host", but only for non-Android OS.
+cc_defaults {
+    name: "cuttlefish_buildhost_only",
+    host_supported: true,
     device_supported: false,
-    host_supported: true,
-    defaults: ["cuttlefish_base"],
-}
-
-cc_defaults {
-    name: "cuttlefish_host_and_guest",
-    host_supported: true,
     defaults: ["cuttlefish_base"],
 }
 
@@ -130,30 +134,19 @@
 }
 
 cc_defaults {
-    name: "cuttlefish_host_config",
+    name: "cuttlefish_libicuuc",
     target: {
-        linux_glibc: {
-            static_libs: [
-                 "libcuttlefish_host_config",
+        host: {
+            shared_libs: [
+                "libicuuc",
             ],
         },
     },
 }
 
 cc_defaults {
-    name: "cuttlefish_libicuuc",
-    shared_libs: [
-        "libicuuc",
-        "libandroidicu",
-    ],
-}
-
-cc_defaults {
     name: "cuttlefish_health_storage",
     defaults: ["enabled_on_q_and_later"],
-    vintf_fragments: [
-        "manifest_android.hardware.health.storage@1.0.cuttlefish.xml",
-    ],
 }
 
 java_test_host {
@@ -167,3 +160,8 @@
 
     test_suites: ["general-tests"],
 }
+
+filegroup {
+    name: "cf_dtb",
+    srcs: ["dtb.img"],
+}
diff --git a/Android.mk b/Android.mk
index 94584cc..59e9806 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,5 +20,9 @@
 include $(CLEAR_VARS)
 include $(LOCAL_PATH)/host_package.mk
 
-include $(call first-makefiles-under,$(LOCAL_PATH))
 endif
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidProducts.mk b/AndroidProducts.mk
index 0b37311..cee00d3 100644
--- a/AndroidProducts.mk
+++ b/AndroidProducts.mk
@@ -15,21 +15,31 @@
 #
 
 PRODUCT_MAKEFILES := \
+	aosp_cf_arm_only_phone:$(LOCAL_DIR)/vsoc_arm_only/phone/aosp_cf.mk \
 	aosp_cf_arm64_auto:$(LOCAL_DIR)/vsoc_arm64/auto/aosp_cf.mk \
 	aosp_cf_arm64_phone:$(LOCAL_DIR)/vsoc_arm64/phone/aosp_cf.mk \
+	aosp_cf_arm64_only_phone:$(LOCAL_DIR)/vsoc_arm64_only/phone/aosp_cf.mk \
+	aosp_cf_x86_64_auto:$(LOCAL_DIR)/vsoc_x86_64/auto/device.mk \
+	aosp_cf_x86_64_pc:$(LOCAL_DIR)/vsoc_x86_64/pc/aosp_cf.mk \
 	aosp_cf_x86_64_phone:$(LOCAL_DIR)/vsoc_x86_64/phone/aosp_cf.mk \
+	aosp_cf_x86_64_foldable:$(LOCAL_DIR)/vsoc_x86_64/phone/aosp_cf_foldable.mk \
+	aosp_cf_x86_64_only_phone:$(LOCAL_DIR)/vsoc_x86_64_only/phone/aosp_cf.mk \
 	aosp_cf_x86_auto:$(LOCAL_DIR)/vsoc_x86/auto/device.mk \
 	aosp_cf_x86_pasan:$(LOCAL_DIR)/vsoc_x86/pasan/aosp_cf.mk \
 	aosp_cf_x86_phone:$(LOCAL_DIR)/vsoc_x86/phone/aosp_cf.mk \
 	aosp_cf_x86_phone_noapex:$(LOCAL_DIR)/vsoc_x86_noapex/aosp_cf_noapex.mk \
+	aosp_cf_x86_only_phone:$(LOCAL_DIR)/vsoc_x86_only/phone/aosp_cf.mk \
 	aosp_cf_x86_go_phone:$(LOCAL_DIR)/vsoc_x86/go_phone/device.mk \
 	aosp_cf_x86_go_512_phone:$(LOCAL_DIR)/vsoc_x86/go_512_phone/device.mk \
 	aosp_cf_x86_tv:$(LOCAL_DIR)/vsoc_x86/tv/device.mk
 
+
 COMMON_LUNCH_CHOICES := \
 	aosp_cf_arm64_auto-userdebug \
 	aosp_cf_arm64_phone-userdebug \
+	aosp_cf_x86_64_pc-userdebug \
 	aosp_cf_x86_64_phone-userdebug \
+	aosp_cf_x86_64_foldable-userdebug \
 	aosp_cf_x86_auto-userdebug \
 	aosp_cf_x86_phone-userdebug \
 	aosp_cf_x86_tv-userdebug
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 34f1634..f235841 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -62,3 +62,9 @@
 
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.dumpstate@1.1-service.cuttlefish)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.dumpstate@1.1-service.cuttlefish.rc)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.health.storage@1.0-service.cuttlefish)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.health.storage@1.0-service.cuttlefish.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/manifest_android.hardware.health.storage@1.0.cuttlefish.xml)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/apex/com.android.gki.*)
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/OWNERS b/OWNERS
index 1944029..a670158 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,6 +1,7 @@
 # Current team members
 adelva@google.com
 jemoreira@google.com
+kwstephenkim@google.com
 malchev@google.com
 muntsinger@google.com
 natsu@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..7ba873b
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,7 @@
+[Builtin Hooks]
+clang_format = true
+rustfmt = true
+
+[Builtin Hooks Options]
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+rustfmt = --config-path=rustfmt.toml
diff --git a/README.md b/README.md
index 531f840..2220898 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,77 @@
-# So you want to try cuttlefish?
+# Cuttlefish Getting Started
 
-1. Download, build, and install the host debian package:
+## Try Cuttlefish
 
-```bash
-git clone https://github.com/google/android-cuttlefish
-cd android-cuttlefish
-debuild -i -us -uc -b
-sudo dpkg -i ../cuttlefish-common_*_amd64.deb
-sudo apt-get install -f
-```
+1. Make sure virtualization with KVM is available.
 
-2. Go to http://ci.android.com/
-3. Enter a branch name. Start with `aosp-master` if you don't know what you're
+   ```bash
+    grep -c -w "vmx\|svm" /proc/cpuinfo
+    ```
+
+   This should return a non-zero value. If running on a cloud machine, this may
+   take cloud-vendor-specific steps to enable. For Google Compute Engine
+   specifically, see the [GCE guide].
+
+   [GCE guide]: https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances
+
+2. Download, build, and install the host debian package:
+
+   ```bash
+   git clone https://github.com/google/android-cuttlefish
+   cd android-cuttlefish
+   debuild -i -us -uc -b
+   sudo dpkg -i ../cuttlefish-common_*_amd64.deb || sudo apt-get install -f
+   sudo reboot
+   ```
+
+   The reboot will trigger installing additional kernel modules and applying
+   udev rules.
+
+3. Go to http://ci.android.com/
+4. Enter a branch name. Start with `aosp-master` if you don't know what you're
    looking for
-4. Navigate to `aosp_cf_x86_phone` and click on `userdebug` for the latest build
-5. Click on `Artifacts`
-6. Scroll down to the OTA images. These packages look like
-   `aosp_cf_x86_phone-img-xxxxxx.zip` -- it will always have `img` in the name.
+5. Navigate to `aosp_cf_x86_64_phone` and click on `userdebug` for the latest build
+6. Click on `Artifacts`
+7. Scroll down to the OTA images. These packages look like
+   `aosp_cf_x86_64_phone-img-xxxxxx.zip` -- it will always have `img` in the name.
    Download this file
-7. Scroll down to `cvd-host_package.tar.gz`. You should always download a host
+8. Scroll down to `cvd-host_package.tar.gz`. You should always download a host
    package from the same build as your images.
-8. On your local system, combine the packages:
+9. On your local system, combine the packages:
 
-```bash
-mkdir cf
-cd cf
-tar xvf /path/to/cvd-host_package.tar.gz
-unzip /path/to/aosp_cf_x86_phone-img-xxxxxx.zip
-```
+   ```bash
+   mkdir cf
+   cd cf
+   tar xvf /path/to/cvd-host_package.tar.gz
+   unzip /path/to/aosp_cf_x86_64_phone-img-xxxxxx.zip
+   ```
 
-8. Launch cuttlefish with:
+10. Launch cuttlefish with:
 
    `$ HOME=$PWD ./bin/launch_cvd`
 
-9. Stop cuttlefish with:
+11. Stop cuttlefish with:
 
    `$ HOME=$PWD ./bin/stop_cvd`
 
-# So you want to debug cuttlefish?
+## Debug Cuttlefish
 
 You can use `adb` to debug it, just like a physical device:
 
    `$ ./bin/adb -e shell`
 
-# So you want to see cuttlefish?
+## Launch Viewer (WebRTC)
 
-You can use the [TightVNC JViewer](https://www.tightvnc.com/download.php). Once
-you have downloaded the *TightVNC Java Viewer JAR in a ZIP archive*, run it with
+When launching with `---start_webrtc` (the default), you can see a list of all
+available devices at `https://localhost:8443` . For more information, see the
+WebRTC on Cuttlefish
+[documentation](https://source.android.com/setup/create/cuttlefish-ref-webrtc).
+
+## Launch Viewer (VNC)
+
+When launching with `--start_vnc_server=true` , You can use the
+[TightVNC JViewer](https://www.tightvnc.com/download.php). Once you have
+downloaded the *TightVNC Java Viewer JAR in a ZIP archive*, run it with
 
    `$ java -jar tightvnc-jviewer.jar -ScalingFactor=50 -Tunneling=no -host=localhost -port=6444`
 
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 8c7bc4b..4067d27 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,9 @@
   "postsubmit" : [
     {
       "name": "tombstone_transmit_tests"
+    },
+    {
+      "name": "RebootRecoveryTest"
     }
   ],
   "presubmit": [
@@ -13,6 +16,9 @@
     },
     {
       "name": "hal_implementation_test"
+    },
+    {
+      "name": "vts_ibase_test"
     }
   ]
 }
diff --git a/build/Android.bp b/build/Android.bp
new file mode 100644
index 0000000..d516313
--- /dev/null
+++ b/build/Android.bp
@@ -0,0 +1,205 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "cuttlefish-soong-rules",
+    pkgPath: "android/soong/cuttlefish",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+    ],
+    srcs: [
+        "cvd-host-package.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
+// Allow cvd-host-package.go to read custom action config variables
+// from ctx.Config().VendorConfig("cvd")
+soong_config_module_type {
+    name: "cvd_host_package_customization",
+    module_type: "cvd_host_package",
+    config_namespace: "cvd",
+    value_variables: [
+        "launch_configs",
+        "custom_action_config",
+        "custom_action_servers",
+    ],
+}
+
+cvd_host_tools = [
+    "android.hardware.automotive.vehicle@2.0-virtualization-grpc-server",
+    "adb",
+    "adb_connector",
+    "adbshell",
+    "allocd",
+    "allocd_client",
+    "assemble_cvd",
+    "bt_connector",
+    "common_crosvm",
+    "config_server",
+    "console_forwarder",
+    "crosvm",
+    "cvd_host_bugreport",
+    "cvd_status",
+    "extract-ikconfig",
+    "extract-vmlinux",
+    "fsck.f2fs",
+    "gnss_grpc_proxy",
+    "kernel_log_monitor",
+    "launch_cvd",
+    "libgrpc++",
+    "libgrpc++_unsecure",
+    "log_tee",
+    "logcat_receiver",
+    "lpmake",
+    "lpunpack",
+    "lz4",
+    "make_f2fs",
+    "metrics",
+    "mkbootfs",
+    "mkbootimg",
+    "mkenvimage",
+    "modem_simulator",
+    "ms-tpm-20-ref",
+    "newfs_msdos",
+    "powerwash_cvd",
+    "restart_cvd",
+    "root-canal",
+    // TODO(b/186487510): remove libchrome and libbacktrace when ASan-related dependency issue is resolved.
+    "libchrome",
+    "libbacktrace",
+    "run_cvd",
+    "secure_env",
+    "socket_vsock_proxy",
+    "stop_cvd",
+    "tapsetiff",
+    "tombstone_receiver",
+    "toybox",
+    "unpack_bootimg",
+    "vnc_server",
+    "webRTC",
+    "webrtc_operator",
+]
+
+cvd_bluetooth_config_files = [
+    "controller_properties.json",
+    "default_commands",
+]
+
+cvd_host_tests = [
+    "cuttlefish_net_tests",
+    "modem_simulator_test",
+]
+
+cvd_host_webrtc_assets = [
+    "webrtc_adb.js",
+    "webrtc_app.js",
+    "webrtc_controls.js",
+    "webrtc_cf.js",
+    "webrtc_index.html",
+    "webrtc_rootcanal.js",
+    "webrtc_server.crt",
+    "webrtc_server.key",
+    "webrtc_server.p12",
+    "webrtc_style.css",
+    "webrtc_controls.css",
+    "webrtc_trusted.pem",
+]
+
+cvd_host_model_simulator_files = [
+    "iccprofile_for_sim0.xml_host",
+    "iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml_host",
+    "numeric_operator.xml_host",
+]
+
+cvd_host_seccomp_policy_x86_64 = [
+    "9p_device.policy_x86_64",
+    "balloon_device.policy_x86_64",
+    "block_device.policy_x86_64",
+    "cras_audio_device.policy_x86_64",
+    "fs_device.policy_x86_64",
+    "gpu_device.policy_x86_64",
+    "input_device.policy_x86_64",
+    "net_device.policy_x86_64",
+    "null_audio_device.policy_x86_64",
+    "pmem_device.policy_x86_64",
+    "rng_device.policy_x86_64",
+    "serial.policy_x86_64",
+    "tpm_device.policy_x86_64",
+    "vfio_device.policy_x86_64",
+    "vhost_net_device.policy_x86_64",
+    "vhost_vsock_device.policy_x86_64",
+    "video_device.policy_x86_64",
+    "vios_audio_device.policy_x86_64",
+    "wl_device.policy_x86_64",
+    "xhci.policy_x86_64",
+]
+
+cvd_host_seccomp_policy_arm64 = [
+    "9p_device.policy_aarch64",
+    "balloon_device.policy_aarch64",
+    "block_device.policy_aarch64",
+    "cras_audio_device.policy_aarch64",
+    "fs_device.policy_aarch64",
+    "gpu_device.policy_aarch64",
+    "input_device.policy_aarch64",
+    "net_device.policy_aarch64",
+    "null_audio_device.policy_aarch64",
+    "pmem_device.policy_aarch64",
+    "rng_device.policy_aarch64",
+    "serial.policy_aarch64",
+    "tpm_device.policy_aarch64",
+    "vhost_net_device.policy_aarch64",
+    "vhost_vsock_device.policy_aarch64",
+    "vios_audio_device.policy_aarch64",
+    "wl_device.policy_aarch64",
+    "xhci.policy_aarch64",
+]
+
+cvd_host_package_customization {
+    name: "cvd-host_package",
+    deps: cvd_host_tools +
+        cvd_host_tests,
+    multilib: {
+        common: {
+            deps: cvd_host_webrtc_assets +
+                cvd_host_model_simulator_files +
+                cvd_bluetooth_config_files,
+        },
+    },
+
+    arch: {
+        x86_64: {
+            multilib: {
+                common: {
+                    deps: cvd_host_seccomp_policy_x86_64,
+                },
+            },
+        },
+        arm64: {
+            multilib: {
+                common: {
+                    deps: cvd_host_seccomp_policy_arm64,
+                },
+            },
+        },
+    },
+    target: {
+        linux_bionic: {
+            multilib: {
+                common: {
+                    deps: ["tzdata_host"],
+                },
+            },
+        },
+        linux_bionic_x86_64: {
+            enabled: false,
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/build/README.md b/build/README.md
new file mode 100644
index 0000000..dc66c0a
--- /dev/null
+++ b/build/README.md
@@ -0,0 +1,27 @@
+## Custom Actions
+
+To add custom actions to the WebRTC control panel, create a custom action config
+JSON file in your virtual device product makefile directory, create a
+`prebuilt_etc_host` module for the JSON file with `sub_dir`
+`cvd_custom_action_config`, then set the build variable
+`SOONG_CONFIG_cvd_custom_action_config` to the name of that module. For example:
+
+```
+Android.bp:
+  prebuilt_etc_host {
+      name: "my_custom_action_config.json",
+      src: "my_custom_action_config.json",
+      // The sub_dir must always equal the following value:
+      sub_dir: "cvd_custom_action_config",
+  }
+
+my_virtual_device.mk:
+  SOONG_CONFIG_NAMESPACES += cvd
+  SOONG_CONFIG_cvd += custom_action_config
+  SOONG_CONFIG_cvd_custom_action_config := my_custom_action_config.json
+```
+
+TODO(b/171709037): Add documentation to source.android.com
+
+See https://source.android.com/setup/create/cuttlefish-control-panel for
+detailed information about the format of the config file.
diff --git a/build/cvd-host-package.go b/build/cvd-host-package.go
new file mode 100644
index 0000000..b025386
--- /dev/null
+++ b/build/cvd-host-package.go
@@ -0,0 +1,106 @@
+// 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.
+
+package cuttlefish
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("cvd_host_package", cvdHostPackageFactory)
+}
+
+type cvdHostPackage struct {
+	android.ModuleBase
+	android.PackagingBase
+}
+
+func cvdHostPackageFactory() android.Module {
+	module := &cvdHostPackage{}
+	android.InitPackageModule(module)
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+	module.IgnoreMissingDependencies = true
+	return module
+}
+
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	android.InstallAlwaysNeededDependencyTag // to force installation of both "deps" and manually added dependencies
+	android.PackagingItemAlwaysDepTag  // to force packaging of both "deps" and manually added dependencies
+}
+
+var cvdHostPackageDependencyTag = dependencyTag{}
+
+func (c *cvdHostPackage) DepsMutator(ctx android.BottomUpMutatorContext) {
+	c.AddDeps(ctx, cvdHostPackageDependencyTag)
+
+	variations := []blueprint.Variation{
+		{Mutator: "os", Variation: ctx.Target().Os.String()},
+		{Mutator: "arch", Variation: android.Common.String()},
+	}
+	for _, dep := range strings.Split(
+		ctx.Config().VendorConfig("cvd").String("launch_configs"), " ") {
+		if ctx.OtherModuleExists(dep) {
+			ctx.AddVariationDependencies(variations, cvdHostPackageDependencyTag, dep)
+		}
+	}
+
+	// If cvd_custom_action_config is set, include custom action servers in the
+	// host package as specified by cvd_custom_action_servers.
+	customActionConfig := ctx.Config().VendorConfig("cvd").String("custom_action_config")
+	if customActionConfig != "" && ctx.OtherModuleExists(customActionConfig) {
+		ctx.AddVariationDependencies(variations, cvdHostPackageDependencyTag,
+			customActionConfig)
+		for _, dep := range strings.Split(
+			ctx.Config().VendorConfig("cvd").String("custom_action_servers"), " ") {
+			if ctx.OtherModuleExists(dep) {
+				ctx.AddVariationDependencies(nil, cvdHostPackageDependencyTag, dep)
+			}
+		}
+	}
+}
+
+var pctx = android.NewPackageContext("android/soong/cuttlefish")
+
+func (c *cvdHostPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	zipFile := android.PathForModuleOut(ctx, "package.zip")
+	c.CopyDepsToZip(ctx, zipFile)
+
+	// Dir where to extract the zip file and construct the final tar.gz from
+	packageDir := android.PathForModuleOut(ctx, ".temp")
+	builder := android.NewRuleBuilder(pctx, ctx)
+	builder.Command().
+		BuiltTool("zipsync").
+		FlagWithArg("-d ", packageDir.String()).
+		Input(zipFile)
+
+	output := android.PathForModuleOut(ctx, "package.tar.gz")
+	builder.Command().Text("tar Scfz").
+		Output(output).
+		FlagWithArg("-C ", packageDir.String()).
+		Flag("--mtime='2020-01-01'"). // to have reproducible builds
+		Text(".")
+
+	builder.Command().Text("rm").Flag("-rf").Text(packageDir.String())
+
+	builder.Build("cvd_host_package", fmt.Sprintf("Packaging %s", c.BaseModuleName()))
+
+	ctx.InstallFile(android.PathForModuleInstall(ctx), c.BaseModuleName()+".tar.gz", output)
+}
diff --git a/common/Android.bp b/common/Android.bp
deleted file mode 100644
index 2280c23..0000000
--- a/common/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "commands",
-    "frontend",
-    "libs",
-]
diff --git a/common/commands/Android.bp b/common/commands/Android.bp
deleted file mode 100644
index 8264fcc..0000000
--- a/common/commands/Android.bp
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-]
diff --git a/common/frontend/Android.bp b/common/frontend/Android.bp
deleted file mode 100644
index 39a4dbb..0000000
--- a/common/frontend/Android.bp
+++ /dev/null
@@ -1,18 +0,0 @@
-//
-// Copyright (C) 2018 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.
-
-subdirs = [
-    "socket_vsock_proxy",
-]
diff --git a/common/frontend/socket_vsock_proxy/Android.bp b/common/frontend/socket_vsock_proxy/Android.bp
index 310244a..9335408 100644
--- a/common/frontend/socket_vsock_proxy/Android.bp
+++ b/common/frontend/socket_vsock_proxy/Android.bp
@@ -13,6 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary {
     name: "socket_vsock_proxy",
     srcs: [
@@ -22,21 +26,23 @@
         "libbase",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
+        "libcuttlefish_kernel_log_monitor_utils",
+        "libjsoncpp",
         "liblog",
     ],
     static_libs: [
         "libgflags",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     target: {
         host: {
             static_libs: [
                 "libcuttlefish_host_config",
-                "libjsoncpp",
             ],
         },
     },
-    defaults: ["cuttlefish_host_and_guest"]
+    // Don't inherit from cuttlefish_host because it is with `vendor_available: true` which isn't
+    // compatible with `vendor: true`.
+    defaults: ["cuttlefish_base"],
+    host_supported: true,
+    vendor: true,
 }
diff --git a/common/frontend/socket_vsock_proxy/main.cpp b/common/frontend/socket_vsock_proxy/main.cpp
index c11852f..cf68821 100644
--- a/common/frontend/socket_vsock_proxy/main.cpp
+++ b/common/frontend/socket_vsock_proxy/main.cpp
@@ -16,10 +16,15 @@
 
 #include <set>
 #include <thread>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include <gflags/gflags.h>
 
 #include "common/libs/fs/shared_fd.h"
+#include "host/commands/kernel_log_monitor/utils.h"
+
+#ifdef CUTTLEFISH_HOST
+#include "host/libs/config/logging.h"
+#endif // CUTTLEFISH_HOST
 
 constexpr std::size_t kMaxPacketSize = 8192;
 
@@ -30,12 +35,21 @@
 DEFINE_uint32(tcp_port, 0, "TCP port");
 DEFINE_uint32(vsock_port, 0, "vsock port");
 DEFINE_uint32(vsock_cid, 0, "Vsock cid to initiate connections to");
+DEFINE_int32(adbd_events_fd, -1, "A file descriptor. If set it will wait for "
+                                 "AdbdStarted boot event from the kernel log "
+                                 "monitor before creating a tcp-vsock tunnel."
+                                 "This option is used by --server=tcp only "
+                                 "when socket_vsock_proxy runs as a host service");
+DEFINE_int32(
+    server_fd, -1,
+    "A file descriptor. If set the passed file descriptor will be used as the "
+    "server and the corresponding port flag will be ignored");
 
 namespace {
 // Sends packets, Shutdown(SHUT_WR) on destruction
 class SocketSender {
  public:
-  explicit SocketSender(cvd::SharedFD socket) : socket_{socket} {}
+  explicit SocketSender(cuttlefish::SharedFD socket) : socket_{socket} {}
 
   SocketSender(SocketSender&&) = default;
   SocketSender& operator=(SocketSender&&) = default;
@@ -59,8 +73,8 @@
           socket_->Send(packet + written,
                         length - written, MSG_NOSIGNAL);
       if (just_written <= 0) {
-        LOG(INFO) << "Couldn't write to client: "
-                  << strerror(socket_->GetErrno());
+        LOG(WARNING) << "Couldn't write to client: "
+                     << strerror(socket_->GetErrno());
         return just_written;
       }
       written += just_written;
@@ -69,12 +83,12 @@
   }
 
  private:
-  cvd::SharedFD socket_;
+  cuttlefish::SharedFD socket_;
 };
 
 class SocketReceiver {
  public:
-  explicit SocketReceiver(cvd::SharedFD socket) : socket_{socket} {}
+  explicit SocketReceiver(cuttlefish::SharedFD socket) : socket_{socket} {}
 
   SocketReceiver(SocketReceiver&&) = default;
   SocketReceiver& operator=(SocketReceiver&&) = default;
@@ -93,7 +107,7 @@
   }
 
  private:
-  cvd::SharedFD socket_;
+  cuttlefish::SharedFD socket_;
 };
 
 void SocketToVsock(SocketReceiver socket_receiver,
@@ -106,7 +120,7 @@
       break;
     }
   }
-  LOG(INFO) << "Socket to vsock exiting";
+  LOG(DEBUG) << "Socket to vsock exiting";
 }
 
 void VsockToSocket(SocketSender socket_sender,
@@ -122,35 +136,63 @@
       break;
     }
   }
-  LOG(INFO) << "Vsock to socket exiting";
+  LOG(DEBUG) << "Vsock to socket exiting";
 }
 
 // One thread for reading from shm and writing into a socket.
 // One thread for reading from a socket and writing into shm.
-void HandleConnection(cvd::SharedFD vsock,
-                      cvd::SharedFD socket) {
+void HandleConnection(cuttlefish::SharedFD vsock,
+                      cuttlefish::SharedFD socket) {
   auto socket_to_vsock =
       std::thread(SocketToVsock, SocketReceiver{socket}, SocketSender{vsock});
   VsockToSocket(SocketSender{socket}, SocketReceiver{vsock});
   socket_to_vsock.join();
 }
 
+void WaitForAdbdToBeStarted(int events_fd) {
+  auto evt_shared_fd = cuttlefish::SharedFD::Dup(events_fd);
+  close(events_fd);
+  while (evt_shared_fd->IsOpen()) {
+    std::optional<monitor::ReadEventResult> read_result =
+        monitor::ReadEvent(evt_shared_fd);
+    if (!read_result) {
+      LOG(ERROR) << "Failed to read a complete kernel log adb event.";
+      // The file descriptor can't be trusted anymore, stop waiting and try to
+      // connect
+      return;
+    }
+
+    if (read_result->event == monitor::Event::AdbdStarted) {
+      LOG(DEBUG) << "Adbd has started in the guest, connecting adb";
+      return;
+    }
+  }
+}
+
+// intented to run as cuttlefish host service
 [[noreturn]] void TcpServer() {
-  LOG(INFO) << "starting TCP server on " << FLAGS_tcp_port << " for vsock port "
-            << FLAGS_vsock_port;
-  auto server = cvd::SharedFD::SocketLocalServer(FLAGS_tcp_port, SOCK_STREAM);
+  LOG(DEBUG) << "starting TCP server on " << FLAGS_tcp_port
+             << " for vsock port " << FLAGS_vsock_port;
+  cuttlefish::SharedFD server;
+  if (FLAGS_server_fd < 0) {
+    server =
+        cuttlefish::SharedFD::SocketLocalServer(FLAGS_tcp_port, SOCK_STREAM);
+  } else {
+    server = cuttlefish::SharedFD::Dup(FLAGS_server_fd);
+    close(FLAGS_server_fd);
+  }
   CHECK(server->IsOpen()) << "Could not start server on " << FLAGS_tcp_port;
-  LOG(INFO) << "Accepting client connections";
+  LOG(DEBUG) << "Accepting client connections";
   int last_failure_reason = 0;
   while (true) {
-    auto client_socket = cvd::SharedFD::Accept(*server);
+    auto client_socket = cuttlefish::SharedFD::Accept(*server);
     CHECK(client_socket->IsOpen()) << "error creating client socket";
-    cvd::SharedFD vsock_socket = cvd::SharedFD::VsockClient(
+    cuttlefish::SharedFD vsock_socket = cuttlefish::SharedFD::VsockClient(
         FLAGS_vsock_cid, FLAGS_vsock_port, SOCK_STREAM);
     if (vsock_socket->IsOpen()) {
       last_failure_reason = 0;
-      LOG(INFO) << "Connected to vsock:" << FLAGS_vsock_cid << ":"
-                << FLAGS_vsock_port;
+      LOG(DEBUG) << "Connected to vsock:" << FLAGS_vsock_cid << ":"
+                 << FLAGS_vsock_port;
     } else {
       // Don't log if the previous connection failed with the same error
       if (last_failure_reason != vsock_socket->GetErrno()) {
@@ -166,9 +208,9 @@
   }
 }
 
-cvd::SharedFD OpenSocketConnection() {
+cuttlefish::SharedFD OpenSocketConnection() {
   while (true) {
-    auto sock = cvd::SharedFD::SocketLocalClient(FLAGS_tcp_port, SOCK_STREAM);
+    auto sock = cuttlefish::SharedFD::SocketLocalClient(FLAGS_tcp_port, SOCK_STREAM);
     if (sock->IsOpen()) {
       return sock;
     }
@@ -189,22 +231,28 @@
   }
 }
 
+// intended to run inside Android guest
 [[noreturn]] void VsockServer() {
-  LOG(INFO) << "Starting vsock server on " << FLAGS_vsock_port;
-  cvd::SharedFD vsock;
-  do {
-    vsock = cvd::SharedFD::VsockServer(FLAGS_vsock_port, SOCK_STREAM);
-    if (!vsock->IsOpen() && !socketErrorIsRecoverable(vsock->GetErrno())) {
-      LOG(ERROR) << "Could not open vsock socket: " << vsock->StrError();
-      SleepForever();
-    }
-  } while (!vsock->IsOpen());
+  LOG(DEBUG) << "Starting vsock server on " << FLAGS_vsock_port;
+  cuttlefish::SharedFD vsock;
+  if (FLAGS_server_fd < 0) {
+    do {
+      vsock = cuttlefish::SharedFD::VsockServer(FLAGS_vsock_port, SOCK_STREAM);
+      if (!vsock->IsOpen() && !socketErrorIsRecoverable(vsock->GetErrno())) {
+        LOG(ERROR) << "Could not open vsock socket: " << vsock->StrError();
+        SleepForever();
+      }
+    } while (!vsock->IsOpen());
+  } else {
+    vsock = cuttlefish::SharedFD::Dup(FLAGS_server_fd);
+    close(FLAGS_server_fd);
+  }
   CHECK(vsock->IsOpen()) << "Could not start server on " << FLAGS_vsock_port;
   while (true) {
-    LOG(INFO) << "waiting for vsock connection";
-    auto vsock_client = cvd::SharedFD::Accept(*vsock);
+    LOG(DEBUG) << "waiting for vsock connection";
+    auto vsock_client = cuttlefish::SharedFD::Accept(*vsock);
     CHECK(vsock_client->IsOpen()) << "error creating vsock socket";
-    LOG(INFO) << "vsock socket accepted";
+    LOG(DEBUG) << "vsock socket accepted";
     auto client = OpenSocketConnection();
     CHECK(client->IsOpen()) << "error connecting to guest client";
     auto thread = std::thread(HandleConnection, std::move(vsock_client),
@@ -216,10 +264,24 @@
 }  // namespace
 
 int main(int argc, char* argv[]) {
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
+#ifdef CUTTLEFISH_HOST
+  cuttlefish::DefaultSubprocessLogging(argv);
+#else
+  ::android::base::InitLogging(argv, android::base::LogdLogger());
+#endif
+  google::ParseCommandLineFlags(&argc, &argv, true);
 
-  CHECK(FLAGS_tcp_port != 0) << "Must specify -tcp_port flag";
-  CHECK(FLAGS_vsock_port != 0) << "Must specify -vsock_port flag";
+  CHECK((FLAGS_server == "tcp" && FLAGS_server_fd >= 0) || FLAGS_tcp_port != 0)
+      << "Must specify -tcp_port or -server_fd (with -server=tcp) flag";
+  CHECK((FLAGS_server == "vsock" && FLAGS_server_fd >= 0) ||
+        FLAGS_vsock_port != 0)
+      << "Must specify -vsock_port or -server_fd (with -server=vsock) flag";
+
+  if (FLAGS_adbd_events_fd >= 0) {
+    LOG(DEBUG) << "Wating AdbdStarted boot event from the kernel log";
+    WaitForAdbdToBeStarted(FLAGS_adbd_events_fd);
+  }
+
   if (FLAGS_server == "tcp") {
     CHECK(FLAGS_vsock_cid != 0) << "Must specify -vsock_cid flag";
     TcpServer();
diff --git a/common/libs/Android.bp b/common/libs/Android.bp
deleted file mode 100644
index 40b7f0c..0000000
--- a/common/libs/Android.bp
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "device_config",
-    "fs",
-    "net",
-    "strings",
-    "tcp_socket",
-    "threads",
-    "time",
-    "utils",
-]
diff --git a/common/libs/concurrency/multiplexer.h b/common/libs/concurrency/multiplexer.h
new file mode 100644
index 0000000..065c1a2
--- /dev/null
+++ b/common/libs/concurrency/multiplexer.h
@@ -0,0 +1,78 @@
+/*
+ * 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 <condition_variable>
+#include <memory>
+#include <vector>
+
+#include "common/libs/concurrency/semaphore.h"
+#include "common/libs/concurrency/thread_safe_queue.h"
+
+namespace cuttlefish {
+namespace confui {
+template <typename T>
+class Multiplexer {
+ public:
+  Multiplexer(int n_qs, int max_elements) : sem_items_{0}, next_{0} {
+    auto drop_new = [](typename ThreadSafeQueue<T>::QueueImpl* internal_q) {
+      internal_q->pop_front();
+    };
+    for (int i = 0; i < n_qs; i++) {
+      auto queue = std::make_unique<ThreadSafeQueue<T>>(max_elements, drop_new);
+      queues_.push_back(std::move(queue));
+    }
+  }
+
+  int GetNewQueueId() {
+    CHECK(next_ < queues_.size())
+        << "can't get more queues than " << queues_.size();
+    return next_++;
+  }
+
+  void Push(const int idx, T&& t) {
+    CheckIdx(idx);
+    queues_[idx]->Push(t);
+    sem_items_.SemPost();
+  }
+
+  T Pop() {
+    // the idx must have an item!
+    // no waiting in fn()!
+    sem_items_.SemWait();
+    for (auto& q : queues_) {
+      if (q->IsEmpty()) {
+        continue;
+      }
+      return q->Pop();
+    }
+    CHECK(false) << "Multiplexer.Pop() should be able to return an item";
+    // must not reach here
+    return T{};
+  }
+
+ private:
+  void CheckIdx(const int idx) {
+    CHECK(idx >= 0 && idx < queues_.size()) << "queues_ array out of bound";
+  }
+  // total items across the queues
+  Semaphore sem_items_;
+  std::vector<std::unique_ptr<ThreadSafeQueue<T>>> queues_;
+  int next_;
+};
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/common/libs/concurrency/semaphore.h b/common/libs/concurrency/semaphore.h
new file mode 100644
index 0000000..5af43a7
--- /dev/null
+++ b/common/libs/concurrency/semaphore.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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 <condition_variable>
+#include <functional>
+#include <memory>
+#include <mutex>
+
+namespace cuttlefish {
+class Semaphore {
+ public:
+  Semaphore(const unsigned int init_val = 0, const unsigned int cap = 30000)
+      : count_{init_val}, capacity_{cap} {}
+
+  void SemWait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+    resoure_cv_.wait(lock, [this]() -> bool { return count_ > 0; });
+    --count_;
+    room_cv_.notify_one();
+  }
+
+  void SemPost() {
+    std::unique_lock<std::mutex> lock(mtx_);
+    room_cv_.wait(lock, [this]() -> bool { return count_ <= capacity_; });
+    ++count_;
+    resoure_cv_.notify_one();
+  }
+
+ private:
+  std::mutex mtx_;
+  std::condition_variable resoure_cv_;
+  std::condition_variable room_cv_;
+  unsigned int count_;
+  const unsigned int capacity_;  // inclusive upper limit
+};
+
+}  // namespace cuttlefish
diff --git a/common/libs/concurrency/thread_annotations.h b/common/libs/concurrency/thread_annotations.h
new file mode 100644
index 0000000..cd568b3
--- /dev/null
+++ b/common/libs/concurrency/thread_annotations.h
@@ -0,0 +1,72 @@
+#pragma once
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)  // no-op
+#endif
+
+#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define ACQUIRED_BEFORE(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+#define ACQUIRED_AFTER(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define REQUIRES(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define REQUIRES_SHARED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+#define ACQUIRE(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define ACQUIRE_SHARED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define RELEASE(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define RELEASE_SHARED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE_SHARED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define ASSERT_SHARED_CAPABILITY(x) \
+  THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define NO_THREAD_SAFETY_ANALYSIS \
+  THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
diff --git a/common/libs/concurrency/thread_safe_queue.h b/common/libs/concurrency/thread_safe_queue.h
new file mode 100644
index 0000000..9105299
--- /dev/null
+++ b/common/libs/concurrency/thread_safe_queue.h
@@ -0,0 +1,98 @@
+#pragma once
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <condition_variable>
+#include <deque>
+#include <iterator>
+#include <mutex>
+#include <utility>
+
+namespace cuttlefish {
+// Simple queue with Push and Pop capabilities.
+// If the max_elements argument is passed to the constructor, and Push is called
+// when the queue holds max_elements items, the max_elements_handler is called
+// with a pointer to the internal QueueImpl. The call is made while holding
+// the guarding mutex; operations on the QueueImpl will not interleave with
+// other threads calling Push() or Pop().
+// The QueueImpl type will be a SequenceContainer.
+template <typename T>
+class ThreadSafeQueue {
+ public:
+  using QueueImpl = std::deque<T>;
+  ThreadSafeQueue() = default;
+  explicit ThreadSafeQueue(std::size_t max_elements,
+                           std::function<void(QueueImpl*)> max_elements_handler)
+      : max_elements_{max_elements},
+        max_elements_handler_{std::move(max_elements_handler)} {}
+
+  T Pop() {
+    std::unique_lock<std::mutex> guard(m_);
+    while (items_.empty()) {
+      new_item_.wait(guard);
+    }
+    auto t = std::move(items_.front());
+    items_.pop_front();
+    return t;
+  }
+
+  QueueImpl PopAll() {
+    std::unique_lock<std::mutex> guard(m_);
+    while (items_.empty()) {
+      new_item_.wait(guard);
+    }
+    return std::move(items_);
+  }
+
+  void Push(T&& t) {
+    std::lock_guard<std::mutex> guard(m_);
+    DropItemsIfAtCapacity();
+    items_.push_back(std::move(t));
+    new_item_.notify_one();
+  }
+
+  void Push(const T& t) {
+    std::lock_guard<std::mutex> guard(m_);
+    DropItemsIfAtCapacity();
+    items_.push_back(t);
+    new_item_.notify_one();
+  }
+
+  bool IsEmpty() {
+    std::lock_guard<std::mutex> guard(m_);
+    return items_.empty();
+  }
+
+  bool IsFull() {
+    std::lock_guard<std::mutex> guard(m_);
+    return items_.size() == max_elements_;
+  }
+
+ private:
+  void DropItemsIfAtCapacity() {
+    if (max_elements_ && max_elements_ == items_.size()) {
+      max_elements_handler_(&items_);
+    }
+  }
+
+  std::mutex m_;
+  std::size_t max_elements_{};
+  std::function<void(QueueImpl*)> max_elements_handler_{};
+  std::condition_variable new_item_;
+  QueueImpl items_;
+};
+}  // namespace cuttlefish
diff --git a/common/libs/confui/Android.bp b/common/libs/confui/Android.bp
new file mode 100644
index 0000000..13ff2fd
--- /dev/null
+++ b/common/libs/confui/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2021 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+    name: "libcuttlefish_confui",
+    srcs: [
+        "packet.cpp",
+        "protocol.cpp",
+    ],
+    static: {
+        static_libs: [
+            "libbase",
+            "libcuttlefish_fs",
+        ],
+        shared_libs: [
+          "libcrypto", // libcrypto_static is not accessible from all targets
+        ],
+    },
+    defaults: ["cuttlefish_host"],
+}
diff --git a/common/libs/confui/confui.h b/common/libs/confui/confui.h
new file mode 100644
index 0000000..957fca1
--- /dev/null
+++ b/common/libs/confui/confui.h
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2021 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
+
+/**
+ * confirmation UI host and guest common library
+ *
+ * This header should be included by other components outside
+ * common/lib/confui. Those inside should use each individual
+ * header file(s)
+ *
+ */
+#include "common/libs/confui/packet.h"
+#include "common/libs/confui/protocol.h"
+#include "common/libs/confui/utils.h"
+
+namespace cuttlefish {
+namespace confui {
+using packet::RecvConfUiMsg;
+using packet::SendAck;
+using packet::SendCmd;
+using packet::SendResponse;
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/common/libs/confui/packet.cpp b/common/libs/confui/packet.cpp
new file mode 100644
index 0000000..d5be03a
--- /dev/null
+++ b/common/libs/confui/packet.cpp
@@ -0,0 +1,131 @@
+//
+// Copyright (C) 2021 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.
+
+#include "common/libs/confui/packet.h"
+
+#include <algorithm>
+#include <iostream>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include "common/libs/confui/protocol.h"
+#include "common/libs/confui/utils.h"
+#include "common/libs/fs/shared_buf.h"
+
+namespace cuttlefish {
+namespace confui {
+namespace packet {
+ConfUiMessage PayloadToConfUiMessage(const std::string& str_to_parse) {
+  auto tokens = android::base::Split(str_to_parse, ":");
+  ConfUiCheck(tokens.size() >= 3)
+      << "PayloadToConfUiMessage takes \"" + str_to_parse + "\""
+      << "and does not have 3 tokens";
+  std::string msg;
+  std::for_each(tokens.begin() + 2, tokens.end() - 1,
+                [&msg](auto& token) { msg.append(token + ":"); });
+  msg.append(*tokens.rbegin());
+  return {tokens[0], tokens[1], msg};
+}
+
+// Use only this function to make a packet to send over the confirmation
+// ui packet layer
+template <typename... Args>
+static Payload ToPayload(const ConfUiCmd cmd, const std::string& session_id,
+                         Args&&... args) {
+  std::string cmd_str = ToString(cmd);
+  std::string msg =
+      ArgsToString(session_id, ":", cmd_str, ":", std::forward<Args>(args)...);
+  PayloadHeader header;
+  header.payload_length_ = msg.size();
+  return {header, msg};
+}
+
+template <typename... Args>
+static bool WritePayload(SharedFD d, const ConfUiCmd cmd,
+                         const std::string& session_id, Args&&... args) {
+  if (!d->IsOpen()) {
+    LOG(ERROR) << "file, socket, etc, is not open to write";
+    return false;
+  }
+  auto [payload, msg] = ToPayload(cmd, session_id, std::forward<Args>(args)...);
+
+  auto nwrite =
+      WriteAll(d, reinterpret_cast<const char*>(&payload), sizeof(payload));
+  if (nwrite != sizeof(payload)) {
+    return false;
+  }
+  nwrite = cuttlefish::WriteAll(d, msg.c_str(), msg.size());
+  if (nwrite != msg.size()) {
+    return false;
+  }
+  return true;
+}
+
+static std::optional<ConfUiMessage> ReadPayload(SharedFD s) {
+  if (!s->IsOpen()) {
+    LOG(ERROR) << "file, socket, etc, is not open to read";
+    return std::nullopt;
+  }
+  PayloadHeader p;
+  auto nread = ReadExactBinary(s, &p);
+
+  if (nread != sizeof(p)) {
+    return std::nullopt;
+  }
+
+  if (p.payload_length_ == 0) {
+    return {{SESSION_ANY, ToString(ConfUiCmd::kUnknown), std::string{""}}};
+  }
+
+  if (p.payload_length_ >= kMaxPayloadLength) {
+    LOG(ERROR) << "Payload length must be less than " << kMaxPayloadLength;
+    return std::nullopt;
+  }
+
+  std::unique_ptr<char[]> buf{new char[p.payload_length_ + 1]};
+  nread = ReadExact(s, buf.get(), p.payload_length_);
+  buf[p.payload_length_] = 0;
+  if (nread != p.payload_length_) {
+    return std::nullopt;
+  }
+  std::string msg_to_parse{buf.get()};
+  auto [session_id, type, contents] = PayloadToConfUiMessage(msg_to_parse);
+  return {{session_id, type, contents}};
+}
+
+std::optional<ConfUiMessage> RecvConfUiMsg(SharedFD fd) {
+  return ReadPayload(fd);
+}
+
+bool SendCmd(SharedFD fd, const std::string& session_id, ConfUiCmd cmd,
+             const std::string& additional_info) {
+  return WritePayload(fd, cmd, session_id, additional_info);
+}
+
+bool SendAck(SharedFD fd, const std::string& session_id, const bool is_success,
+             const std::string& additional_info) {
+  return WritePayload(fd, ConfUiCmd::kCliAck, session_id,
+                      ToCliAckMessage(is_success, additional_info));
+}
+
+bool SendResponse(SharedFD fd, const std::string& session_id,
+                  const std::string& additional_info) {
+  return WritePayload(fd, ConfUiCmd::kCliRespond, session_id, additional_info);
+}
+
+}  // end of namespace packet
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/common/libs/confui/packet.h b/common/libs/confui/packet.h
new file mode 100644
index 0000000..848eb29
--- /dev/null
+++ b/common/libs/confui/packet.h
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2021 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 <cstdint>
+#include <functional>
+#include <optional>
+#include <string>
+#include <tuple>
+
+#include "common/libs/confui/protocol.h"
+#include "common/libs/fs/shared_fd.h"
+
+namespace cuttlefish {
+namespace confui {
+namespace packet {
+/*
+ * for communication between Confirmation UI guest and host.
+ *
+ * Payload is actually the header. When we send/recv, besides Payload,
+ * the "payload_length_" bytes should be additionally sent/recv'ed.
+ *
+ * The payload is assumed to be a text (e.g. char[N])
+ * The WritePayload will create the string. When read, however,
+ * the receiver should parse it
+ *
+ * The format we use for confirmation UI is:
+ *  session_id:type:contents
+ *
+ * e.g. GooglePay10354:start:my confirmaton message
+ */
+struct PayloadHeader {
+  std::uint32_t payload_length_;
+};
+
+// PayloadHeader + the message actually being sent
+using Payload = std::tuple<PayloadHeader, std::string>;
+
+// msg will look like "334522:start:Hello I am Here!"
+// this function returns 334522, start, "Hello I am Here!"
+// if no session id is given, it is regarded as SESSION_ANY
+ConfUiMessage PayloadToConfUiMessage(const std::string& str_to_parse);
+
+std::optional<ConfUiMessage> RecvConfUiMsg(SharedFD fd);
+bool SendAck(SharedFD fd, const std::string& session_id, const bool is_success,
+             const std::string& additional_info);
+bool SendResponse(SharedFD fd, const std::string& session_id,
+                  const std::string& additional_info);
+// for HAL
+bool SendCmd(SharedFD fd, const std::string& session_id, ConfUiCmd cmd,
+             const std::string& additional_info);
+
+// this is for short messages
+constexpr const ssize_t kMaxPayloadLength = 1000;
+
+}  // end of namespace packet
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/common/libs/confui/protocol.cpp b/common/libs/confui/protocol.cpp
new file mode 100644
index 0000000..6784034
--- /dev/null
+++ b/common/libs/confui/protocol.cpp
@@ -0,0 +1,102 @@
+//
+// Copyright (C) 2021 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.
+
+#include "common/libs/confui/protocol.h"
+
+#include <map>
+#include <sstream>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/strings.h>
+
+#include "common/libs/confui/utils.h"
+
+namespace cuttlefish {
+namespace confui {
+std::string ToDebugString(const ConfUiCmd& cmd, const bool is_debug) {
+  std::stringstream ss;
+  ss << "of " << Enum2Base(cmd);
+  std::string suffix = "";
+  if (is_debug) {
+    suffix.append(ss.str());
+  }
+  static std::unordered_map<ConfUiCmd, std::string> look_up_tab{
+      {ConfUiCmd::kUnknown, "kUnknown"},
+      {ConfUiCmd::kStart, "kStart"},
+      {ConfUiCmd::kStop, "kStop"},
+      {ConfUiCmd::kCliAck, "kCliAck"},
+      {ConfUiCmd::kCliRespond, "kCliRespond"},
+      {ConfUiCmd::kAbort, "kAbort"},
+      {ConfUiCmd::kSuspend, "kSuspend"},
+      {ConfUiCmd::kRestore, "kRestore"},
+      {ConfUiCmd::kUserInputEvent, "kUserInputEvent"}};
+  if (look_up_tab.find(cmd) != look_up_tab.end()) {
+    return look_up_tab[cmd] + suffix;
+  }
+  return "kUnknown" + suffix;
+}
+
+std::string ToString(const ConfUiCmd& cmd) { return ToDebugString(cmd, false); }
+
+ConfUiCmd ToCmd(std::uint32_t i) {
+  std::vector<ConfUiCmd> all_cmds{
+      ConfUiCmd::kStart,      ConfUiCmd::kStop,           ConfUiCmd::kCliAck,
+      ConfUiCmd::kCliRespond, ConfUiCmd::kAbort,          ConfUiCmd::kSuspend,
+      ConfUiCmd::kRestore,    ConfUiCmd::kUserInputEvent, ConfUiCmd::kUnknown};
+
+  for (auto& cmd : all_cmds) {
+    if (i == Enum2Base(cmd)) {
+      return cmd;
+    }
+  }
+  return ConfUiCmd::kUnknown;
+}
+
+ConfUiCmd ToCmd(const std::string& cmd_str) {
+  static std::map<std::string, ConfUiCmd> cmds = {
+      {"kStart", ConfUiCmd::kStart},
+      {"kStop", ConfUiCmd::kStop},
+      {"kCliAck", ConfUiCmd::kCliAck},
+      {"kCliRespond", ConfUiCmd::kCliRespond},
+      {"kAbort", ConfUiCmd::kAbort},
+      {"kSuspend", ConfUiCmd::kSuspend},
+      {"kRestore", ConfUiCmd::kRestore},
+      {"kUserInputEvent", ConfUiCmd::kUserInputEvent},
+  };
+  if (cmds.find(cmd_str) != cmds.end()) {
+    return cmds[cmd_str];
+  }
+  return ConfUiCmd::kUnknown;
+}
+
+std::string ToCliAckMessage(const bool is_success, const std::string& message) {
+  std::string header = "error:";
+  if (is_success) {
+    header = "success:";
+  }
+  return header + message;
+}
+
+std::string ToCliAckSuccessMsg(const std::string& message) {
+  return ToCliAckMessage(true, message);
+}
+
+std::string ToCliAckErrorMsg(const std::string& message) {
+  return ToCliAckMessage(false, message);
+}
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/common/libs/confui/protocol.h b/common/libs/confui/protocol.h
new file mode 100644
index 0000000..582b43e
--- /dev/null
+++ b/common/libs/confui/protocol.h
@@ -0,0 +1,63 @@
+//
+// Copyright (C) 2021 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 <cstdint>
+#include <string>
+
+namespace cuttlefish {
+namespace confui {
+// When you update this, please update all the utility functions
+// in conf.cpp: e.g. ToString, etc
+enum class ConfUiCmd : std::uint32_t {
+  kUnknown = 100,
+  kStart = 111,   // start rendering, send confirmation msg, & wait respond
+  kStop = 112,    // start rendering, send confirmation msg, & wait respond
+  kCliAck = 113,  // client acknowledged. "error:err_msg" or "success:command"
+  kCliRespond = 114,  //  with "confirm" or "cancel"
+  kAbort = 115,       // to abort the current session
+  kSuspend = 116,     // to suspend, so do save the context
+  kRestore = 117,
+  kUserInputEvent = 200
+};
+
+std::string ToString(const ConfUiCmd& cmd);
+std::string ToDebugString(const ConfUiCmd& cmd, const bool is_debug);
+ConfUiCmd ToCmd(const std::string& cmd_str);
+ConfUiCmd ToCmd(std::uint32_t i);
+
+struct UserResponse {
+  using type = std::string;
+  constexpr static const auto kConfirm = "user_confirm";
+  constexpr static const auto kCancel = "user_cancel";
+  constexpr static const auto kUnknown = "user_unknown";
+};
+
+// invalid/ignored session id
+constexpr char SESSION_ANY[] = "";
+
+std::string ToCliAckMessage(const bool is_success, const std::string& message);
+std::string ToCliAckErrorMsg(const std::string& message);
+std::string ToCliAckSuccessMsg(const std::string& message);
+
+struct ConfUiMessage {
+  std::string session_id_;
+  std::string type_;  // cmd, which cmd? ack, response, etc
+  std::string msg_;
+};
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/common/libs/confui/utils.h b/common/libs/confui/utils.h
new file mode 100644
index 0000000..2e4ac04
--- /dev/null
+++ b/common/libs/confui/utils.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2021 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 <sstream>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <android-base/logging.h>
+
+namespace cuttlefish {
+template <typename T>
+constexpr typename std::underlying_type_t<T> Enum2Base(T t) {
+  return static_cast<typename std::underlying_type_t<T>>(t);
+}
+}  // end of namespace cuttlefish
+
+namespace cuttlefish {
+namespace confui {
+template <typename Delim, typename... Args>
+std::string ArgsToStringWithDelim(Delim&& delim, Args&&... args) {
+  std::stringstream ss;
+  ([&ss, &delim](auto& arg) { ss << arg << delim; }(args), ...);
+  return ss.str();
+}
+
+// make t... to a single string with no blank in between
+template <typename... Args>
+std::string ArgsToString(Args&&... args) {
+  return ArgsToStringWithDelim("", std::forward<Args>(args)...);
+}
+
+// note that no () surrounding LOG(level) << "ConfUI:" is crucial
+#define ConfUiLog(LOG_LEVEL) LOG(LOG_LEVEL) << "ConfUI: "
+
+// TODO(kwstephenkim@google.com): make these look more like LOG(level)
+#define ConfUiCheck(cond) CHECK(cond) << "ConfUI: "
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/common/libs/device_config/Android.bp b/common/libs/device_config/Android.bp
index 4900d35..00a6a0a 100644
--- a/common/libs/device_config/Android.bp
+++ b/common/libs/device_config/Android.bp
@@ -13,28 +13,46 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+    name: "libcuttlefish_device_config_proto",
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+    },
+    srcs: [
+        "device_config.proto",
+    ],
+    defaults: ["cuttlefish_host"],
+}
+
 cc_library_shared {
     name: "libcuttlefish_device_config",
     srcs: [
         "device_config.cpp",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
+        "device_config_shared.cpp",
     ],
     shared_libs: [
         "libbase",
         "liblog",
+        "libcuttlefish_device_config_proto",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
+        "libprotobuf-cpp-full",
     ],
     target: {
         host: {
             srcs: [
                 "host_device_config.cpp",
             ],
+            shared_libs: [
+                "libjsoncpp",
+            ],
             static_libs: [
                 "libcuttlefish_host_config",
-                "libjsoncpp",
             ],
         },
         android: {
@@ -46,5 +64,6 @@
             ],
         },
     },
-    defaults: ["cuttlefish_host_and_guest"],
+    export_include_dirs: ["."],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/common/libs/device_config/device_config.cpp b/common/libs/device_config/device_config.cpp
index 69c489f..0bbe903 100644
--- a/common/libs/device_config/device_config.cpp
+++ b/common/libs/device_config/device_config.cpp
@@ -19,43 +19,18 @@
 #include <sstream>
 #include <type_traits>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
-namespace cvd {
+#include "common/libs/fs/shared_fd_stream.h"
 
-// TODO(jemoreira): Endianness when on arm64 guest and x86 host is a problem
-// Raw data is sent through a vsocket from host to guest, this assert tries to
-// ensure the binary representation of the struct is the same in both sides.
-static constexpr int kRawDataSize = 68 + 16;  // ril + screen
-static_assert(sizeof(DeviceConfig::RawData) == kRawDataSize &&
-                  std::is_trivial<DeviceConfig::RawData>().value,
-              "DeviceConfigRawData needs to be the same in host and guess, did "
-              "you forget to update the size?");
+namespace cuttlefish {
 
-namespace {
-
-static constexpr auto kDataSize = sizeof(DeviceConfig::RawData);
-
-}  // namespace
-
-bool DeviceConfig::SendRawData(cvd::SharedFD fd) {
-  std::size_t sent = 0;
-  auto buffer = reinterpret_cast<uint8_t*>(&data_);
-  while (sent < kDataSize) {
-    auto bytes = fd->Write(buffer + sent, kDataSize - sent);
-    if (bytes < 0) {
-      // Don't log here, let the caller do it.
-      return false;
-    }
-    sent += bytes;
-  }
-  return true;
+bool DeviceConfigHelper::SendDeviceConfig(SharedFD fd) {
+  SharedFDOstream stream(fd);
+  return device_config_.SerializeToOstream(&stream);
 }
 
-void DeviceConfig::generate_address_and_prefix() {
-  std::ostringstream ss;
-  ss << ril_ipaddr() << "/" << ril_prefixlen();
-  ril_address_and_prefix_ = ss.str();
-}
+DeviceConfigHelper::DeviceConfigHelper(const DeviceConfig& device_config)
+  : device_config_(device_config) {}
 
-}  // namespace cvd
\ No newline at end of file
+}  // namespace cuttlefish
diff --git a/common/libs/device_config/device_config.h b/common/libs/device_config/device_config.h
index 0e3680f..7655e49 100644
--- a/common/libs/device_config/device_config.h
+++ b/common/libs/device_config/device_config.h
@@ -16,74 +16,31 @@
 
 #pragma once
 
-#include <common/libs/fs/shared_fd.h>
-#include <stdint.h>
-
 #include <memory>
 #include <string>
 #include <vector>
 
+#include "common/libs/fs/shared_fd.h"
+#include "device/google/cuttlefish/common/libs/device_config/device_config.pb.h"
+
 #ifdef CUTTLEFISH_HOST
-#include <host/libs/config/cuttlefish_config.h>
+#include "host/libs/config/cuttlefish_config.h"
 #endif
 
-namespace cvd {
+namespace cuttlefish {
 
-class DeviceConfig {
+class DeviceConfigHelper {
  public:
-  /**
-   * WARNING: Consider the possibility of different endianness between host and
-   * guest when adding fields of more than one byte to this struct:
-   * This struct is meant to be sent from host to guest so the binary
-   * representation must be the same. There is a static test that checks for
-   * alignment problems, but there is no such thing for endianness.
-   */
-  struct RawData {
-    struct {
-      char ipaddr[16];  // xxx.xxx.xxx.xxx\0 = 16 bytes
-      char gateway[16];
-      char dns[16];
-      char broadcast[16];
-      uint8_t prefixlen;
-      uint8_t reserved[3];
-    } ril;
-    struct {
-      int32_t x_res;
-      int32_t y_res;
-      int32_t dpi;
-      int32_t refresh_rate;
-    } screen;
-  };
+  static std::unique_ptr<DeviceConfigHelper> Get();
 
-  static std::unique_ptr<DeviceConfig> Get();
+  const DeviceConfig& GetDeviceConfig() const { return device_config_; }
 
-  bool SendRawData(cvd::SharedFD fd);
-
-  const char* ril_address_and_prefix() const {
-    return ril_address_and_prefix_.c_str();
-  };
-  const char* ril_ipaddr() const { return data_.ril.ipaddr; }
-  const char* ril_gateway() const { return data_.ril.gateway; }
-  const char* ril_dns() const { return data_.ril.dns; }
-  const char* ril_broadcast() const { return data_.ril.broadcast; }
-  int ril_prefixlen() const { return data_.ril.prefixlen; }
-  int32_t screen_x_res() { return data_.screen.x_res; }
-  int32_t screen_y_res() { return data_.screen.y_res; }
-  int32_t screen_dpi() { return data_.screen.dpi; }
-  int32_t screen_refresh_rate() { return data_.screen.refresh_rate; }
+  bool SendDeviceConfig(SharedFD fd);
 
  private:
-  void generate_address_and_prefix();
-#ifdef CUTTLEFISH_HOST
-  DeviceConfig() = default;
-  bool InitializeNetworkConfiguration(const vsoc::CuttlefishConfig& config);
-  void InitializeScreenConfiguration(const vsoc::CuttlefishConfig& config);
-#else
-  explicit DeviceConfig(const RawData& data);
-#endif
+  explicit DeviceConfigHelper(const DeviceConfig& device_config);
 
-  RawData data_;
-  std::string ril_address_and_prefix_;
+  DeviceConfig device_config_;
 };
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/device_config/device_config.proto b/common/libs/device_config/device_config.proto
new file mode 100644
index 0000000..4a5a170
--- /dev/null
+++ b/common/libs/device_config/device_config.proto
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package cuttlefish;
+
+message DeviceConfig {
+
+  message RILConfig {
+    string ipaddr = 1;
+    string gateway = 2;
+    string dns = 3;
+    string broadcast = 4;
+    int32 prefixlen = 5;
+  };
+
+  RILConfig ril_config = 1;
+
+  message DisplayConfig {
+    int32 width = 1;
+    int32 height = 2;
+    int32 dpi = 3;
+    int32 refresh_rate_hz = 4;
+  };
+
+  repeated DisplayConfig display_config = 2;
+}
diff --git a/common/libs/device_config/device_config_shared.cpp b/common/libs/device_config/device_config_shared.cpp
new file mode 100644
index 0000000..ac4f8b4
--- /dev/null
+++ b/common/libs/device_config/device_config_shared.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "device_config.h"
+
+namespace cuttlefish {
+
+DeviceConfig GetDeviceConfig() {
+  const auto device_config_helper = cuttlefish::DeviceConfigHelper::Get();
+  return device_config_helper->GetDeviceConfig();
+}
+
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/device_config/device_config_shared.h b/common/libs/device_config/device_config_shared.h
new file mode 100644
index 0000000..3176917
--- /dev/null
+++ b/common/libs/device_config/device_config_shared.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 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 "device/google/cuttlefish/common/libs/device_config/device_config.pb.h"
+
+namespace cuttlefish {
+
+// Minimal version to share with Goldfish which doesn't include additional
+// Cuttlefish headers.
+//
+// TODO(natsu): switch ranchu hwcomposer to drm for display discovery.
+DeviceConfig GetDeviceConfig();
+
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/device_config/guest_device_config.cpp b/common/libs/device_config/guest_device_config.cpp
index fc2c587..6620748 100644
--- a/common/libs/device_config/guest_device_config.cpp
+++ b/common/libs/device_config/guest_device_config.cpp
@@ -19,18 +19,19 @@
 #include <chrono>
 #include <thread>
 
+#include <android-base/logging.h>
 #include <cutils/properties.h>
-#include <glog/logging.h>
 
-namespace cvd {
+#include "common/libs/fs/shared_fd_stream.h"
+
+namespace cuttlefish {
 
 namespace {
 
-static constexpr auto kDataSize = sizeof(DeviceConfig::RawData);
 static constexpr int kRetries = 5;
 static constexpr int kRetryDelaySeconds = 5;
 
-bool GetRawFromServer(DeviceConfig::RawData* data) {
+bool GetRawFromServer(DeviceConfig* data) {
   auto port_property = "ro.boot.cuttlefish_config_server_port";
   auto port = property_get_int64(port_property, -1);
   if (port < 0) {
@@ -39,41 +40,32 @@
     return false;
   }
   auto config_server =
-      cvd::SharedFD::VsockClient(2 /*host cid*/,
-                                 static_cast<unsigned int>(port), SOCK_STREAM);
+      SharedFD::VsockClient(2 /*host cid*/,
+                            static_cast<unsigned int>(port), SOCK_STREAM);
   if (!config_server->IsOpen()) {
     LOG(ERROR) << "Unable to connect to config server: "
                << config_server->StrError();
     return false;
   }
-  uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
-  size_t read_idx = 0;
-  while (read_idx < kDataSize) {
-    auto read = config_server->Read(buffer + read_idx, kDataSize - read_idx);
-    if (read == 0) {
-      LOG(ERROR) << "Unexpected EOF while reading from config server, read "
-                 << read_idx << " bytes, expected " << kDataSize;
-      return false;
-    }
-    if (read < 0) {
-      LOG(ERROR) << "Error reading from config server: "
-                 << config_server->StrError();
-      return false;
-    }
-    read_idx += read;
+
+  SharedFDIstream stream(config_server);
+  if (!data->ParseFromIstream(&stream)) {
+    LOG(ERROR) << "Error reading from config server: "
+               << config_server->StrError();
   }
   return true;
 }
 
 }  // namespace
 
-std::unique_ptr<DeviceConfig> DeviceConfig::Get() {
-  DeviceConfig::RawData data;
+std::unique_ptr<DeviceConfigHelper> DeviceConfigHelper::Get() {
+  DeviceConfig device_config;
 
   int attempts_remaining = 1 + kRetries;
   while (attempts_remaining > 0) {
-    if (GetRawFromServer(&data)) {
-      return std::unique_ptr<DeviceConfig>(new DeviceConfig(data));
+    if (GetRawFromServer(&device_config)) {
+      return std::unique_ptr<DeviceConfigHelper>(
+        new DeviceConfigHelper(device_config));
     }
 
     std::this_thread::sleep_for(std::chrono::seconds(kRetryDelaySeconds));
@@ -83,8 +75,4 @@
   return nullptr;
 }
 
-DeviceConfig::DeviceConfig(const DeviceConfig::RawData& data) : data_(data) {
-  generate_address_and_prefix();
-}
-
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/device_config/host_device_config.cpp b/common/libs/device_config/host_device_config.cpp
index 5359a06..35ec27f 100644
--- a/common/libs/device_config/host_device_config.cpp
+++ b/common/libs/device_config/host_device_config.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <arpa/inet.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include <ifaddrs.h>
 #include <stdio.h>
 #include <string.h>
@@ -23,7 +23,7 @@
 
 #include "device_config.h"
 
-namespace cvd {
+namespace cuttlefish {
 
 namespace {
 
@@ -41,18 +41,19 @@
   uint8_t ril_prefixlen = -1;
   std::string ril_ipaddr;
   std::string ril_gateway;
-  std::string ril_dns = "8.8.8.8";
+  std::string ril_dns;
   std::string ril_broadcast;
 
-  bool ObtainConfig(const std::string& interface) {
+  bool ObtainConfig(const std::string& interface, const std::string& dns) {
     bool ret = ParseInterfaceAttributes(interface);
     if (ret) {
-      LOG(INFO) << "Network config:";
-      LOG(INFO) << "ipaddr = " << ril_ipaddr;
-      LOG(INFO) << "gateway = " << ril_gateway;
-      LOG(INFO) << "dns = " << ril_dns;
-      LOG(INFO) << "broadcast = " << ril_broadcast;
-      LOG(INFO) << "prefix length = " << static_cast<int>(ril_prefixlen);
+      ril_dns = dns;
+      LOG(DEBUG) << "Network config:";
+      LOG(DEBUG) << "ipaddr = " << ril_ipaddr;
+      LOG(DEBUG) << "gateway = " << ril_gateway;
+      LOG(DEBUG) << "dns = " << ril_dns;
+      LOG(DEBUG) << "broadcast = " << ril_broadcast;
+      LOG(DEBUG) << "prefix length = " << static_cast<int>(ril_prefixlen);
     }
     return ret;
   }
@@ -127,66 +128,62 @@
   }
 };
 
-inline void CopyChars(char* dest, size_t size, const char* src) {
-  auto res = snprintf(dest, size, "%s", src);
-  if (res >= static_cast<int>(size)) {
-    LOG(ERROR) << "Longer(" << res << ") than expected(" << (size - 1)
-               << ") config string was truncated: " << dest;
-  }
-}
-
-}  // namespace
-
-std::unique_ptr<DeviceConfig> DeviceConfig::Get() {
-  auto config = vsoc::CuttlefishConfig::Get();
-  if (!config) return nullptr;
-  std::unique_ptr<DeviceConfig> dev_config(new DeviceConfig());
-  if (!dev_config->InitializeNetworkConfiguration(*config)) {
-    return nullptr;
-  }
-  dev_config->InitializeScreenConfiguration(*config);
-  return dev_config;
-}
-
-bool DeviceConfig::InitializeNetworkConfiguration(
-    const vsoc::CuttlefishConfig& config) {
-  auto instance = config.ForDefaultInstance();
+bool InitializeNetworkConfiguration(const CuttlefishConfig& cuttlefish_config,
+                                    DeviceConfig* device_config) {
+  auto instance = cuttlefish_config.ForDefaultInstance();
   NetConfig netconfig;
   // Check the mobile bridge first; this was the traditional way we configured
   // the mobile interface. If that fails, it probably means we are using a
   // newer version of cuttlefish-common, and we can use the tap device
   // directly instead.
-  if (!netconfig.ObtainConfig(instance.mobile_bridge_name())) {
-    if (!netconfig.ObtainConfig(instance.mobile_tap_name())) {
+  if (!netconfig.ObtainConfig(instance.mobile_bridge_name(),
+                              cuttlefish_config.ril_dns())) {
+    if (!netconfig.ObtainConfig(instance.mobile_tap_name(),
+                                cuttlefish_config.ril_dns())) {
       LOG(ERROR) << "Unable to obtain the network configuration";
       return false;
     }
   }
 
-  auto res = snprintf(data_.ril.ipaddr, sizeof(data_.ril.ipaddr), "%s",
-                      netconfig.ril_ipaddr.c_str());
-  if (res >= (int)sizeof(data_.ril.ipaddr)) {
-    LOG(ERROR) << "Longer than expected config string was truncated: "
-               << data_.ril.ipaddr;
-  }
-  CopyChars(data_.ril.gateway, sizeof(data_.ril.gateway),
-            netconfig.ril_gateway.c_str());
-  CopyChars(data_.ril.dns, sizeof(data_.ril.dns), netconfig.ril_dns.c_str());
-  CopyChars(data_.ril.broadcast, sizeof(data_.ril.broadcast),
-            netconfig.ril_broadcast.c_str());
-  data_.ril.prefixlen = netconfig.ril_prefixlen;
-
-  generate_address_and_prefix();
+  DeviceConfig::RILConfig* ril_config = device_config->mutable_ril_config();
+  ril_config->set_ipaddr(netconfig.ril_ipaddr);
+  ril_config->set_gateway(netconfig.ril_gateway);
+  ril_config->set_dns(netconfig.ril_dns);
+  ril_config->set_broadcast(netconfig.ril_broadcast);
+  ril_config->set_prefixlen(netconfig.ril_prefixlen);
 
   return true;
 }
 
-void DeviceConfig::InitializeScreenConfiguration(
-    const vsoc::CuttlefishConfig& config) {
-  data_.screen.x_res = config.x_res();
-  data_.screen.y_res = config.y_res();
-  data_.screen.dpi = config.dpi();
-  data_.screen.refresh_rate = config.refresh_rate_hz();
+void InitializeScreenConfiguration(const CuttlefishConfig& cuttlefish_config,
+                                   DeviceConfig* device_config) {
+  for (const auto& cuttlefish_display_config : cuttlefish_config.display_configs()) {
+    DeviceConfig::DisplayConfig* device_display_config =
+      device_config->add_display_config();
+
+    device_display_config->set_width(cuttlefish_display_config.width);
+    device_display_config->set_height(cuttlefish_display_config.height);
+    device_display_config->set_dpi(cuttlefish_config.dpi());
+    device_display_config->set_refresh_rate_hz(cuttlefish_config.refresh_rate_hz());
+  }
 }
 
-}  // namespace cvd
+}  // namespace
+
+std::unique_ptr<DeviceConfigHelper> DeviceConfigHelper::Get() {
+  auto cuttlefish_config = CuttlefishConfig::Get();
+  if (!cuttlefish_config) {
+    return nullptr;
+  }
+
+  DeviceConfig device_config;
+  if (!InitializeNetworkConfiguration(*cuttlefish_config, &device_config)) {
+    return nullptr;
+  }
+  InitializeScreenConfiguration(*cuttlefish_config, &device_config);
+
+  return std::unique_ptr<DeviceConfigHelper>(
+    new DeviceConfigHelper(device_config));
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/fs/Android.bp b/common/libs/fs/Android.bp
index 0e49e5a..c140e0d 100644
--- a/common/libs/fs/Android.bp
+++ b/common/libs/fs/Android.bp
@@ -13,12 +13,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library {
     name: "libcuttlefish_fs",
     srcs: [
         "shared_buf.cc",
         "shared_fd.cpp",
-        "tee.cpp",
+        "shared_fd_stream.cpp",
     ],
     shared: {
         shared_libs: [
@@ -39,7 +43,7 @@
             exclude_static_libs: ["liblog"],
         },
     },
-    defaults: ["cuttlefish_host_and_guest"],
+    defaults: ["cuttlefish_host"],
 }
 
 cc_library_static {
@@ -47,7 +51,7 @@
     srcs: [
         "shared_buf.cc",
         "shared_fd.cpp",
-        "tee.cpp",
+        "shared_fd_stream.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -57,20 +61,19 @@
     defaults: ["cuttlefish_guest_product_only"],
 }
 
-cc_test_host {
+cc_test {
     name: "libcuttlefish_fs_tests",
     srcs: [
         "shared_fd_test.cpp",
     ],
-    header_libs: ["cuttlefish_glog"],
     shared_libs: [
         "libcuttlefish_fs",
         "libbase",
     ],
     static_libs: [
         "libgmock",
-        "libgtest_host",
+        "libgtest",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
     test_suites: ["general-tests"],
 }
diff --git a/common/libs/fs/TEST_MAPPING b/common/libs/fs/TEST_MAPPING
deleted file mode 100644
index 162fcf6..0000000
--- a/common/libs/fs/TEST_MAPPING
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "libcuttlefish_fs_tests",
-      "host": true
-    }
-  ]
-}
diff --git a/common/libs/fs/shared_buf.cc b/common/libs/fs/shared_buf.cc
index 5ae1aa2..61ff51e 100644
--- a/common/libs/fs/shared_buf.cc
+++ b/common/libs/fs/shared_buf.cc
@@ -22,14 +22,14 @@
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
 
+namespace cuttlefish {
+
 namespace {
 
 const size_t BUFF_SIZE = 1 << 14;
 
 } // namespace
 
-namespace cvd {
-
 ssize_t WriteAll(SharedFD fd, const char* buf, size_t size) {
   size_t total_written = 0;
   ssize_t written = 0;
@@ -94,4 +94,36 @@
   return WriteAll(fd, buf.data(), buf.size());
 }
 
-} // namespace cvd
+bool SendAll(SharedFD sock, const std::string& msg) {
+  ssize_t total_written{};
+  if (!sock->IsOpen()) {
+    return false;
+  }
+  while (total_written < static_cast<ssize_t>(msg.size())) {
+    auto just_written = sock->Send(msg.c_str() + total_written,
+                                   msg.size() - total_written, MSG_NOSIGNAL);
+    if (just_written <= 0) {
+      return false;
+    }
+    total_written += just_written;
+  }
+  return true;
+}
+
+std::string RecvAll(SharedFD sock, const size_t count) {
+  size_t total_read{};
+  if (!sock->IsOpen()) {
+    return {};
+  }
+  std::unique_ptr<char[]> data(new char[count]);
+  while (total_read < count) {
+    auto just_read = sock->Read(data.get() + total_read, count - total_read);
+    if (just_read <= 0) {
+      return {};
+    }
+    total_read += just_read;
+  }
+  return {data.get(), count};
+}
+
+} // namespace cuttlefish
diff --git a/common/libs/fs/shared_buf.h b/common/libs/fs/shared_buf.h
index f8f86b7..eb63174 100644
--- a/common/libs/fs/shared_buf.h
+++ b/common/libs/fs/shared_buf.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <string>
 #include <thread>
@@ -20,7 +21,7 @@
 
 #include "common/libs/fs/shared_fd.h"
 
-namespace cvd {
+namespace cuttlefish {
 
 /**
  * Reads from fd until it is closed or errors, storing all data in buf.
@@ -118,4 +119,23 @@
   return WriteAll(fd, (const char*) binary_data, sizeof(*binary_data));
 }
 
-} // namespace cvd
+/**
+ * Sends contents of msg through sock, checking for socket error conditions
+ *
+ * On successful Send, returns true
+ *
+ * If a Send error is encountered, returns false. Some data may have already
+ * been written to 'sock' at that point.
+ */
+bool SendAll(SharedFD sock, const std::string& msg);
+
+/**
+ * Receives 'count' bytes from sock, checking for socket error conditions
+ *
+ * On successful Recv, returns a string containing the received data
+ *
+ * If a Recv error is encountered, returns the empty string
+ */
+std::string RecvAll(SharedFD sock, const size_t count);
+
+} // namespace cuttlefish
diff --git a/common/libs/fs/shared_fd.cpp b/common/libs/fs/shared_fd.cpp
index f02a0e9..8b21f0c 100644
--- a/common/libs/fs/shared_fd.cpp
+++ b/common/libs/fs/shared_fd.cpp
@@ -27,13 +27,14 @@
 #include <algorithm>
 #include <vector>
 
-#include "common/libs/glog/logging.h"
+#include "android-base/logging.h"
 #include "common/libs/fs/shared_select.h"
 
 // #define ENABLE_GCE_SHARED_FD_LOGGING 1
 
+namespace cuttlefish {
+
 namespace {
-using cvd::SharedFDSet;
 
 void MarkAll(const SharedFDSet& input, fd_set* dest, int* max_index) {
   for (SharedFDSet::const_iterator it = input.begin(); it != input.end();
@@ -84,8 +85,6 @@
 
 }  // namespace
 
-namespace cvd {
-
 bool FileInstance::CopyFrom(FileInstance& in, size_t length) {
   std::vector<char> buffer(8192);
   while (length > 0) {
@@ -123,6 +122,52 @@
   fd_ = -1;
 }
 
+int FileInstance::ConnectWithTimeout(const struct sockaddr* addr,
+                                     socklen_t addrlen,
+                                     struct timeval* timeout) {
+  int original_flags = Fcntl(F_GETFL, 0);
+  if (original_flags == -1) {
+    LOG(ERROR) << "Could not get current file descriptor flags: " << StrError();
+    return -1;
+  }
+  if (Fcntl(F_SETFL, original_flags | O_NONBLOCK) == -1) {
+    LOG(ERROR) << "Failed to set O_NONBLOCK: " << StrError();
+    return -1;
+  }
+  Connect(addr, addrlen);  // This will return immediately because of O_NONBLOCK
+
+  fd_set fdset;
+  FD_ZERO(&fdset);
+  FD_SET(fd_, &fdset);
+
+  int select_res = select(fd_ + 1, nullptr, &fdset, nullptr, timeout);
+
+  if (Fcntl(F_SETFL, original_flags) == -1) {
+    LOG(ERROR) << "Failed to restore original flags: " << StrError();
+    return -1;
+  }
+
+  if (select_res != 1) {
+    LOG(ERROR) << "Did not connect within the timeout";
+    return -1;
+  }
+
+  int so_error;
+  socklen_t len = sizeof(so_error);
+  if (GetSockOpt(SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
+    LOG(ERROR) << "Failed to get socket options: " << StrError();
+    return -1;
+  }
+
+  if (so_error != 0) {
+    LOG(ERROR) << "Failure in opening socket: " << so_error;
+    errno_ = so_error;
+    return -1;
+  }
+  errno_ = 0;
+  return 0;
+}
+
 bool FileInstance::IsSet(fd_set* in) const {
   if (IsOpen() && FD_ISSET(fd_, in)) {
     return true;
@@ -274,12 +319,26 @@
   }
 }
 
+SharedFD SharedFD::Mkstemp(std::string* path) {
+  int fd = mkstemp(path->data());
+  if (fd == -1) {
+    return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
+  } else {
+    return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
+  }
+}
+
 SharedFD SharedFD::ErrorFD(int error) {
   return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(-1, error)));
 }
 
 SharedFD SharedFD::SocketLocalClient(const std::string& name, bool abstract,
                                      int in_type) {
+  return SocketLocalClient(name, abstract, in_type, 0);
+}
+
+SharedFD SharedFD::SocketLocalClient(const std::string& name, bool abstract,
+                                     int in_type, int timeout_seconds) {
   struct sockaddr_un addr;
   socklen_t addrlen;
   MakeAddress(name.c_str(), abstract, &addr, &addrlen);
@@ -287,7 +346,9 @@
   if (!rval->IsOpen()) {
     return rval;
   }
-  if (rval->Connect(reinterpret_cast<sockaddr*>(&addr), addrlen) == -1) {
+  struct timeval timeout = {timeout_seconds, 0};
+  auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
+  if (rval->ConnectWithTimeout(casted_addr, addrlen, &timeout) == -1) {
     return SharedFD::ErrorFD(rval->GetErrno());
   }
   return rval;
@@ -297,7 +358,7 @@
   sockaddr_in addr{};
   addr.sin_family = AF_INET;
   addr.sin_port = htons(port);
-  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
   SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
   if (!rval->IsOpen()) {
     return rval;
@@ -314,7 +375,7 @@
   memset(&addr, 0, sizeof(addr));
   addr.sin_family = AF_INET;
   addr.sin_port = htons(port);
-  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
   SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
   if(!rval->IsOpen()) {
     return rval;
@@ -328,7 +389,7 @@
     LOG(ERROR) << "Bind failed " << rval->StrError();
     return SharedFD::ErrorFD(rval->GetErrno());
   }
-  if (type == SOCK_STREAM) {
+  if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
     if (rval->Listen(4) < 0) {
       LOG(ERROR) << "Listen failed " << rval->StrError();
       return SharedFD::ErrorFD(rval->GetErrno());
@@ -363,9 +424,10 @@
 
   /* Only the bottom bits are really the socket type; there are flags too. */
   constexpr int SOCK_TYPE_MASK = 0xf;
+  auto socket_type = in_type & SOCK_TYPE_MASK;
 
   // Connection oriented sockets: start listening.
-  if ((in_type & SOCK_TYPE_MASK) == SOCK_STREAM) {
+  if (socket_type == SOCK_STREAM || socket_type == SOCK_SEQPACKET) {
     // Follows the default from socket_local_server
     if (rval->Listen(1) == -1) {
       LOG(ERROR) << "Listen failed: " << rval->StrError();
@@ -383,7 +445,7 @@
 }
 
 SharedFD SharedFD::VsockServer(unsigned int port, int type) {
-  auto vsock = cvd::SharedFD::Socket(AF_VSOCK, type, 0);
+  auto vsock = SharedFD::Socket(AF_VSOCK, type, 0);
   if (!vsock->IsOpen()) {
     return vsock;
   }
@@ -396,7 +458,7 @@
     LOG(ERROR) << "Bind failed (" << vsock->StrError() << ")";
     return SharedFD::ErrorFD(vsock->GetErrno());
   }
-  if (type == SOCK_STREAM) {
+  if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
     if (vsock->Listen(4) < 0) {
       LOG(ERROR) << "Listen failed (" << vsock->StrError() << ")";
       return SharedFD::ErrorFD(vsock->GetErrno());
@@ -410,7 +472,7 @@
 }
 
 SharedFD SharedFD::VsockClient(unsigned int cid, unsigned int port, int type) {
-  auto vsock = cvd::SharedFD::Socket(AF_VSOCK, type, 0);
+  auto vsock = SharedFD::Socket(AF_VSOCK, type, 0);
   if (!vsock->IsOpen()) {
     return vsock;
   }
@@ -425,4 +487,28 @@
   return vsock;
 }
 
-}  // namespace cvd
+SharedFD WeakFD::lock() const {
+  auto locked_file_instance = value_.lock();
+  if (locked_file_instance) {
+    return SharedFD(locked_file_instance);
+  }
+  return SharedFD();
+}
+
+ScopedMMap::ScopedMMap(void* ptr, size_t len) : ptr_(ptr), len_(len) {}
+
+ScopedMMap::ScopedMMap() : ptr_(MAP_FAILED), len_(0) {}
+
+ScopedMMap::ScopedMMap(ScopedMMap&& other)
+    : ptr_(other.ptr_), len_(other.len_) {
+  other.ptr_ = MAP_FAILED;
+  other.len_ = 0;
+}
+
+ScopedMMap::~ScopedMMap() {
+  if (ptr_ != MAP_FAILED) {
+    munmap(ptr_, len_);
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/fs/shared_fd.h b/common/libs/fs/shared_fd.h
index bf54dfa..e712ab9 100644
--- a/common/libs/fs/shared_fd.h
+++ b/common/libs/fs/shared_fd.h
@@ -38,8 +38,11 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <string.h>
+#include <termios.h>
 #include <unistd.h>
 
+#include <android-base/cmsg.h>
+
 #include "vm_sockets.h"
 
 /**
@@ -61,7 +64,7 @@
  * it makes it easier to convert existing code to SharedFDs and avoids the
  * possibility that new POSIX functionality will lead to large refactorings.
  */
-namespace cvd {
+namespace cuttlefish {
 
 class FileInstance;
 
@@ -109,6 +112,8 @@
  * reported with a new, closed FileInstance with the errno set.
  */
 class SharedFD {
+  // Give WeakFD access to the underlying shared_ptr.
+  friend class WeakFD;
  public:
   inline SharedFD();
   SharedFD(const std::shared_ptr<FileInstance>& in) : value_(in) {}
@@ -124,11 +129,14 @@
   static bool Pipe(SharedFD* fd0, SharedFD* fd1);
   static SharedFD Event(int initval = 0, int flags = 0);
   static SharedFD MemfdCreate(const std::string& name, unsigned int flags = 0);
+  static SharedFD Mkstemp(std::string* path);
   static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
                          SharedFD* fd1);
   static SharedFD Socket(int domain, int socket_type, int protocol);
   static SharedFD SocketLocalClient(const std::string& name, bool is_abstract,
                                     int in_type);
+  static SharedFD SocketLocalClient(const std::string& name, bool is_abstract,
+                                    int in_type, int timeout_seconds);
   static SharedFD SocketLocalClient(int port, int type);
   static SharedFD SocketLocalServer(const std::string& name, bool is_abstract,
                                     int in_type, mode_t mode);
@@ -151,9 +159,9 @@
 
   std::shared_ptr<FileInstance> operator->() const { return value_; }
 
-  const cvd::FileInstance& operator*() const { return *value_; }
+  const FileInstance& operator*() const { return *value_; }
 
-  cvd::FileInstance& operator*() { return *value_; }
+  FileInstance& operator*() { return *value_; }
 
  private:
   static SharedFD ErrorFD(int error);
@@ -162,6 +170,47 @@
 };
 
 /**
+ * A non-owning reference to a FileInstance. The referenced FileInstance needs
+ * to be managed by a SharedFD. A WeakFD needs to be converted to a SharedFD to
+ * access the underlying FileInstance.
+ */
+class WeakFD {
+ public:
+  WeakFD(SharedFD shared_fd) : value_(shared_fd.value_) {}
+
+  // Creates a new SharedFD object that shares ownership of the underlying fd.
+  // Callers need to check that the returned SharedFD is open before using it.
+  SharedFD lock() const;
+
+ private:
+  std::weak_ptr<FileInstance> value_;
+};
+
+// Provides RAII semantics for memory mappings, preventing memory leaks. It does
+// not however prevent use-after-free errors since the underlying pointer can be
+// extracted and could survive this object.
+class ScopedMMap {
+ public:
+  ScopedMMap();
+  ScopedMMap(void* ptr, size_t size);
+  ScopedMMap(const ScopedMMap& other) = delete;
+  ScopedMMap& operator=(const ScopedMMap& other) = delete;
+  ScopedMMap(ScopedMMap&& other);
+
+  ~ScopedMMap();
+
+  void* get() { return ptr_; }
+  const void* get() const { return ptr_; }
+  size_t len() const { return len_; }
+
+  operator bool() const { return ptr_ != MAP_FAILED; }
+
+ private:
+  void* ptr_ = MAP_FAILED;
+  size_t len_;
+};
+
+/**
  * Tracks the lifetime of a file descriptor and provides methods to allow
  * callers to use the file without knowledge of the underlying descriptor
  * number.
@@ -200,6 +249,9 @@
     return rval;
   }
 
+  int ConnectWithTimeout(const struct sockaddr* addr, socklen_t addrlen,
+                         struct timeval* timeout);
+
   void Close();
 
   // Returns true if the entire input was copied.
@@ -259,6 +311,25 @@
   // in probably isn't modified, but the API spec doesn't have const.
   bool IsSet(fd_set* in) const;
 
+  /**
+   * Adds a hard link to a file descriptor, based on the current working
+   * directory of the process or to some absolute path.
+   *
+   * https://www.man7.org/linux/man-pages/man2/linkat.2.html
+   *
+   * Using this on a file opened with O_TMPFILE can link it into the filesystem.
+   */
+  // Used with O_TMPFILE files to attach them to the filesystem.
+  int LinkAtCwd(const std::string& path) {
+    std::string name = "/proc/self/fd/";
+    name += std::to_string(fd_);
+    errno = 0;
+    int rval = linkat(
+        -1, name.c_str(), AT_FDCWD, path.c_str(), AT_SYMLINK_FOLLOW);
+    errno_ = errno;
+    return rval;
+  }
+
   int Listen(int backlog) {
     errno = 0;
     int rval = listen(fd_, backlog);
@@ -296,6 +367,13 @@
     return rval;
   }
 
+  int EventfdRead(eventfd_t* value) {
+    errno = 0;
+    auto rval = eventfd_read(fd_, value);
+    errno_ = errno;
+    return rval;
+  }
+
   ssize_t Send(const void* buf, size_t len, int flags) {
     errno = 0;
     ssize_t rval = TEMP_FAILURE_RETRY(send(fd_, buf, len, flags));
@@ -310,6 +388,16 @@
     return rval;
   }
 
+  template <typename... Args>
+  ssize_t SendFileDescriptors(const void* buf, size_t len, Args&&... sent_fds) {
+    std::vector<int> fds;
+    android::base::Append(fds, std::forward<int>(sent_fds->fd_)...);
+    errno = 0;
+    auto ret = android::base::SendFileDescriptorVector(fd_, buf, len, fds);
+    errno_ = errno;
+    return ret;
+  }
+
   int Shutdown(int how) {
     errno = 0;
     int rval = shutdown(fd_, how);
@@ -326,6 +414,27 @@
     return rval;
   }
 
+  int GetSockOpt(int level, int optname, void* optval, socklen_t* optlen) {
+    errno = 0;
+    int rval = getsockopt(fd_, level, optname, optval, optlen);
+    errno_ = errno;
+    return rval;
+  }
+
+  int SetTerminalRaw() {
+    errno = 0;
+    termios terminal_settings;
+    int rval = tcgetattr(fd_, &terminal_settings);
+    errno_ = errno;
+    if (rval < 0) {
+      return rval;
+    }
+    cfmakeraw(&terminal_settings);
+    rval = tcsetattr(fd_, TCSANOW, &terminal_settings);
+    errno_ = errno;
+    return rval;
+  }
+
   const char* StrError() const {
     errno = 0;
     FileInstance* s = const_cast<FileInstance*>(this);
@@ -342,6 +451,14 @@
     return strerror_buf_;
   }
 
+  ScopedMMap MMap(void* addr, size_t length, int prot, int flags,
+                  off_t offset) {
+    errno = 0;
+    auto ptr = mmap(addr, length, prot, flags, fd_, offset);
+    errno_ = errno;
+    return ScopedMMap(ptr, length);
+  }
+
   ssize_t Truncate(off_t length) {
     errno = 0;
     ssize_t rval = TEMP_FAILURE_RETRY(ftruncate(fd_, length));
@@ -356,6 +473,20 @@
     return rval;
   }
 
+  int EventfdWrite(eventfd_t value) {
+    errno = 0;
+    int rval = eventfd_write(fd_, value);
+    errno_ = errno;
+    return rval;
+  }
+
+  bool IsATTY() {
+    errno = 0;
+    int rval = isatty(fd_);
+    errno_ = errno;
+    return rval;
+  }
+
  private:
   FileInstance(int fd, int in_errno) : fd_(fd), errno_(in_errno) {
     // Ensure every file descriptor managed by a FileInstance has the CLOEXEC
@@ -386,6 +517,6 @@
 
 inline SharedFD::SharedFD() : value_(FileInstance::ClosedInstance()) {}
 
-}  // namespace cvd
+}  // namespace cuttlefish
 
 #endif  // CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
diff --git a/common/libs/fs/shared_fd_stream.cpp b/common/libs/fs/shared_fd_stream.cpp
new file mode 100644
index 0000000..6eef1f5
--- /dev/null
+++ b/common/libs/fs/shared_fd_stream.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include "common/libs/fs/shared_fd_stream.h"
+
+#include <cstdio>
+#include <streambuf>
+
+#include "common/libs/fs/shared_buf.h"
+
+namespace cuttlefish {
+
+SharedFDStreambuf::SharedFDStreambuf(SharedFD shared_fd)
+  : shared_fd_(shared_fd) {}
+
+int SharedFDStreambuf::underflow() {
+  if (gptr() < egptr()) {
+    return *gptr();
+  }
+
+  size_t unget_size = 0;
+  constexpr size_t bytes_to_read = kBufferSize - kUngetSize;
+  if (read_buffer_ == nullptr) {
+    read_buffer_ = std::make_unique<char[]>(kBufferSize);
+  } else {
+    unget_size = std::min(gptr() - eback(), kUngetSize);
+    std::memcpy(read_buffer_.get(),
+                read_buffer_.get() + kBufferSize - unget_size,
+                unget_size);
+  }
+
+  ssize_t bytes_read = ReadExact(shared_fd_,
+                                 read_buffer_.get() + unget_size,
+                                 bytes_to_read);
+
+  setg(read_buffer_.get(),
+       read_buffer_.get() + unget_size,
+       read_buffer_.get() + unget_size + bytes_read);
+
+  if (bytes_read <= 0 || in_avail() == 0) {
+    return EOF;
+  }
+
+  return static_cast<int>(*gptr());
+}
+
+std::streamsize SharedFDStreambuf::xsgetn(char* dst, std::streamsize count) {
+  std::streamsize bytes_read = 0;
+  while (bytes_read < count) {
+    if (in_avail() == 0) {
+      if (underflow() == EOF) {
+        break;
+      }
+    }
+    std::streamsize buffer_count =
+        std::min(static_cast<std::streamsize>(in_avail()), count - bytes_read);
+    std::memcpy(dst + bytes_read, gptr(), buffer_count);
+    gbump(buffer_count);
+    bytes_read += buffer_count;
+  }
+  return bytes_read;
+}
+
+int SharedFDStreambuf::overflow(int c) {
+  if (c != EOF) {
+      char z = c;
+      if (WriteAll(shared_fd_, &z, 1) != 1) {
+          return EOF;
+      }
+  }
+  return c;
+}
+
+std::streamsize SharedFDStreambuf::xsputn(const char* src,
+                                          std::streamsize count) {
+  return static_cast<std::streamsize>(
+    WriteAll(shared_fd_, src, static_cast<std::size_t>(count)));
+}
+
+int SharedFDStreambuf::pbackfail(int c) {
+  if (c != EOF) {
+    if (gptr() != eback()) {
+      gbump(-1);
+      *(gptr()) = c;
+      return c;
+    }
+  }
+  return EOF;
+}
+
+SharedFDOstream::SharedFDOstream(SharedFD shared_fd)
+  : std::ostream(nullptr), buf_(shared_fd) { rdbuf(&buf_); }
+
+SharedFDIstream::SharedFDIstream(SharedFD shared_fd)
+  : std::istream(nullptr), buf_(shared_fd) { rdbuf(&buf_); }
+
+} // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/fs/shared_fd_stream.h b/common/libs/fs/shared_fd_stream.h
new file mode 100644
index 0000000..d5381d0
--- /dev/null
+++ b/common/libs/fs/shared_fd_stream.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Adapters for using SharedFD as std::istream and std::ostream.
+
+#ifndef CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_STREAM_H_
+#define CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_STREAM_H_
+
+#include <cstdio>
+#include <istream>
+#include <memory>
+#include <ostream>
+#include <streambuf>
+
+#include "common/libs/fs/shared_fd.h"
+
+namespace cuttlefish {
+
+class SharedFDStreambuf : public std::streambuf {
+ public:
+  SharedFDStreambuf(SharedFD shared_fd);
+
+ private:
+  // Reading characters from the SharedFD.
+  int underflow() override;
+  std::streamsize xsgetn(char* dest, std::streamsize count) override;
+
+  // Write characters to the SharedFD.
+  int overflow(int c) override;
+  std::streamsize xsputn(const char* source, std::streamsize count) override;
+
+  int pbackfail(int c) override;
+
+ private:
+  SharedFD shared_fd_;
+
+  static constexpr const ptrdiff_t kUngetSize = 128;
+  static constexpr const ptrdiff_t kBufferSize = 4096 + kUngetSize;
+  std::unique_ptr<char[]> read_buffer_ = nullptr;
+};
+
+class SharedFDIstream : public std::istream {
+ public:
+  SharedFDIstream(SharedFD shared_fd);
+
+ private:
+  SharedFDStreambuf buf_;
+};
+
+class SharedFDOstream : public std::ostream {
+ public:
+  SharedFDOstream(SharedFD shared_fd);
+
+ private:
+  SharedFDStreambuf buf_;
+};
+
+}  // namespace cuttlefish
+
+#endif
\ No newline at end of file
diff --git a/common/libs/fs/shared_fd_test.cpp b/common/libs/fs/shared_fd_test.cpp
index 7ca6204..ff43654 100644
--- a/common/libs/fs/shared_fd_test.cpp
+++ b/common/libs/fs/shared_fd_test.cpp
@@ -23,7 +23,7 @@
 
 #include <string>
 
-using cvd::SharedFD;
+namespace cuttlefish {
 
 char pipe_message[] = "Testing the pipe";
 
@@ -37,3 +37,5 @@
   EXPECT_EQ(sizeof(pipe_message), fds[0]->Read(buf, sizeof(buf)));
   EXPECT_EQ(0, strcmp(buf, pipe_message));
 }
+
+}
diff --git a/common/libs/fs/shared_select.h b/common/libs/fs/shared_select.h
index d103f1d..9e0e0ab 100644
--- a/common/libs/fs/shared_select.h
+++ b/common/libs/fs/shared_select.h
@@ -20,7 +20,7 @@
 
 #include "common/libs/fs/shared_fd.h"
 
-namespace cvd {
+namespace cuttlefish {
 /**
  * The SharedFD version of fdset for the Select call.
  *
@@ -76,6 +76,6 @@
 int Select(SharedFDSet* read_set, SharedFDSet* write_set,
            SharedFDSet* error_set, struct timeval* timeout);
 
-}  // namespace cvd
+}  // namespace cuttlefish
 
 #endif  // CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_SELECT_H_
diff --git a/common/libs/fs/tee.cpp b/common/libs/fs/tee.cpp
deleted file mode 100644
index 87ad432..0000000
--- a/common/libs/fs/tee.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-//
-// Copyright (C) 2019 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.
-
-#include <algorithm>
-#include <iostream>
-
-#include "common/libs/glog/logging.h"
-#include "common/libs/fs/shared_buf.h"
-#include "common/libs/fs/tee.h"
-
-static const std::size_t READ_SIZE = 512;
-
-namespace cvd {
-
-TeeSubscriber* Tee::AddSubscriber(TeeSubscriber subscriber) {
-  if (reader_.joinable()) {
-    return nullptr;
-  }
-  return &targets_.emplace_back(std::move(subscriber)).handler;
-}
-
-void Tee::Start(SharedFD source) {
-  reader_ = std::thread([this, source]() {
-    while (true) {
-      // TODO(schfufelen): Use multiple buffers at once for readv
-      // TODO(schuffelen): Reuse buffers
-      TeeBufferPtr buffer = std::make_shared<std::vector<char>>(READ_SIZE);
-      ssize_t read = source->Read(buffer->data(), buffer->size());
-      if (read <= 0) {
-        for (auto& target : targets_) {
-          target.content_queue.Push(nullptr);
-        }
-        break;
-      }
-      buffer->resize(read);
-      for (auto& target : targets_) {
-        target.content_queue.Push(buffer);
-      }
-    }
-  });
-  for (auto& target : targets_) {
-    target.runner = std::thread([&target]() {
-      while (true) {
-        auto queue_chunk = target.content_queue.PopAll();
-        // TODO(schuffelen): Pass multiple buffers to support writev
-        for (auto& buffer : queue_chunk) {
-          if (!buffer) {
-            return;
-          }
-          target.handler(buffer);
-        }
-      }
-    });
-  }
-}
-
-Tee::~Tee() {
-  Join();
-}
-
-void Tee::Join() {
-  if (reader_.joinable()) {
-    reader_.join();
-  }
-  auto it = targets_.begin();
-  while (it != targets_.end()) {
-    if (it->runner.joinable()) {
-      it->runner.join();
-    }
-    it = targets_.erase(it);
-  }
-}
-
-TeeSubscriber SharedFDWriter(SharedFD fd) {
-  return [fd](const TeeBufferPtr buffer) { WriteAll(fd, *buffer); };
-}
-
-// An alternative to this would have been to modify the logger, but that would
-// not capture logs from subprocesses.
-TeeStderrToFile::TeeStderrToFile() {
-  original_stderr_ = SharedFD::Dup(2);
-
-  SharedFD stderr_read, stderr_write;
-  SharedFD::Pipe(&stderr_read, &stderr_write);
-  stderr_write->UNMANAGED_Dup2(2);
-  stderr_write->Close();
-
-  tee_.AddSubscriber(SharedFDWriter(original_stderr_));
-  tee_.AddSubscriber(
-      [this](cvd::TeeBufferPtr data) {
-        std::unique_lock lock(mutex_);
-        while (!log_file_->IsOpen()) {
-          notifier_.wait(lock);
-        }
-        cvd::WriteAll(log_file_, *data);
-      });
-  tee_.Start(std::move(stderr_read));
-}
-
-TeeStderrToFile::~TeeStderrToFile() {
-  original_stderr_->UNMANAGED_Dup2(2);
-}
-
-void TeeStderrToFile::SetFile(SharedFD file) {
-  std::lock_guard lock(mutex_);
-  log_file_ = file;
-  notifier_.notify_all();
-}
-
-} // namespace
diff --git a/common/libs/fs/tee.h b/common/libs/fs/tee.h
deleted file mode 100644
index 23bc3d1..0000000
--- a/common/libs/fs/tee.h
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright (C) 2019 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 <condition_variable>
-#include <functional>
-#include <list>
-#include <memory>
-#include <mutex>
-#include <thread>
-#include <string>
-#include <vector>
-
-#include "common/libs/fs/shared_fd.h"
-#include "common/libs/thread_safe_queue/thread_safe_queue.h"
-
-namespace cvd {
-
-using TeeBufferPtr = std::shared_ptr<std::vector<char>>;
-using TeeSubscriber = std::function<void(const TeeBufferPtr)>;
-
-struct TeeTarget {
-  std::thread runner;
-  ThreadSafeQueue<TeeBufferPtr> content_queue;
-  TeeSubscriber handler;
-
-  TeeTarget(TeeSubscriber handler) : handler(handler) {}
-};
-
-class Tee {
-  std::thread reader_;
-  std::list<TeeTarget> targets_;
-public:
-  ~Tee();
-
-  TeeSubscriber* AddSubscriber(TeeSubscriber);
-
-  void Start(SharedFD source);
-  void Join();
-};
-
-TeeSubscriber SharedFDWriter(SharedFD fd);
-
-class TeeStderrToFile {
-  cvd::SharedFD log_file_;
-  cvd::SharedFD original_stderr_;
-  std::condition_variable notifier_;
-  std::mutex mutex_;
-  Tee tee_; // This should be destroyed first, so placed last.
-public:
-  TeeStderrToFile();
-  ~TeeStderrToFile();
-
-  void SetFile(SharedFD file);
-};
-
-} // namespace cvd
diff --git a/common/libs/glog/logging.h b/common/libs/glog/logging.h
deleted file mode 100644
index 8cd4a8a..0000000
--- a/common/libs/glog/logging.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifdef ANDROID
-#include <android-base/logging.h>
-
-#if defined(CUTTLEFISH_HOST)
-using ::android::base::VERBOSE;
-using ::android::base::INFO;
-using ::android::base::WARNING;
-using ::android::base::FATAL;
-
-#define LOG_IF(LEVEL, CONDITION) if (CONDITION) LOG(LEVEL)
-
-#endif  // CUTTLEFISH_HOST
-#else  // DEBIAN_HOST (by elimination)
-#include <glog/logging.h>
-#endif
diff --git a/common/libs/net/Android.bp b/common/libs/net/Android.bp
index ba7bbd3..802141e 100644
--- a/common/libs/net/Android.bp
+++ b/common/libs/net/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library_shared {
     name: "cuttlefish_net",
     srcs: [
@@ -23,15 +27,14 @@
         "libcuttlefish_fs",
         "libbase",
     ],
-    defaults: ["cuttlefish_host_and_guest"],
+    defaults: ["cuttlefish_host"],
 }
 
-cc_test_host {
+cc_test {
     name: "cuttlefish_net_tests",
     srcs: [
         "netlink_request_test.cpp",
     ],
-    header_libs: ["cuttlefish_glog"],
     shared_libs: [
         "libcuttlefish_fs",
         "cuttlefish_net",
@@ -39,8 +42,8 @@
     ],
     static_libs: [
         "libgmock",
-        "libgtest_host",
+        "libgtest",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
     test_suites: ["general-tests"],
 }
diff --git a/common/libs/net/TEST_MAPPING b/common/libs/net/TEST_MAPPING
deleted file mode 100644
index a06d72a..0000000
--- a/common/libs/net/TEST_MAPPING
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "cuttlefish_net_tests",
-      "host": true
-    }
-  ]
-}
diff --git a/common/libs/net/netlink_client.cpp b/common/libs/net/netlink_client.cpp
index 96eb4a9..7b2404f 100644
--- a/common/libs/net/netlink_client.cpp
+++ b/common/libs/net/netlink_client.cpp
@@ -22,9 +22,9 @@
 #include <sys/socket.h>
 
 #include "common/libs/fs/shared_fd.h"
-#include "common/libs/glog/logging.h"
+#include "android-base/logging.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace {
 // NetlinkClient implementation.
 // Talks to libnetlink to apply network changes.
@@ -165,4 +165,4 @@
   return &factory;
 }
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/net/netlink_client.h b/common/libs/net/netlink_client.h
index c8805c5..25ff7f4 100644
--- a/common/libs/net/netlink_client.h
+++ b/common/libs/net/netlink_client.h
@@ -21,7 +21,7 @@
 #include <string>
 #include "common/libs/net/netlink_request.h"
 
-namespace cvd {
+namespace cuttlefish {
 
 // Abstraction of Netlink client class.
 class NetlinkClient {
@@ -50,6 +50,6 @@
   virtual ~NetlinkClientFactory() = default;
 };
 
-}  // namespace cvd
+}  // namespace cuttlefish
 
 #endif  // COMMON_LIBS_NET_NETLINK_CLIENT_H_
diff --git a/common/libs/net/netlink_request.cpp b/common/libs/net/netlink_request.cpp
index 68adcf0..3900e8a 100644
--- a/common/libs/net/netlink_request.cpp
+++ b/common/libs/net/netlink_request.cpp
@@ -24,9 +24,9 @@
 #include <string>
 #include <vector>
 
-#include "common/libs/glog/logging.h"
+#include "android-base/logging.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace {
 uint32_t kRequestSequenceNumber = 0;
 }  // namespace
@@ -126,4 +126,4 @@
   return request_.size();
 }
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/net/netlink_request.h b/common/libs/net/netlink_request.h
index 541c04b..eee231c 100644
--- a/common/libs/net/netlink_request.h
+++ b/common/libs/net/netlink_request.h
@@ -24,7 +24,7 @@
 #include <string>
 #include <vector>
 
-namespace cvd {
+namespace cuttlefish {
 // Abstraction of Network link request.
 // Used to supply kernel with information about which interface needs to be
 // changed, and how.
@@ -108,5 +108,5 @@
   NetlinkRequest(const NetlinkRequest&) = delete;
   NetlinkRequest& operator= (const NetlinkRequest&) = delete;
 };
-}  // namespace cvd
+}  // namespace cuttlefish
 #endif  // COMMON_LIBS_NET_NETLINK_REQUEST_H_
diff --git a/common/libs/net/netlink_request_test.cpp b/common/libs/net/netlink_request_test.cpp
index 03a7dad..3e23358 100644
--- a/common/libs/net/netlink_request_test.cpp
+++ b/common/libs/net/netlink_request_test.cpp
@@ -19,7 +19,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include <iostream>
 #include <memory>
@@ -28,7 +28,7 @@
 using ::testing::MatchResultListener;
 using ::testing::Return;
 
-namespace cvd {
+namespace cuttlefish {
 namespace {
 extern "C" void klog_write(int /* level */, const char* /* format */, ...) {}
 
@@ -130,7 +130,7 @@
 
   memcpy(&expected.text, kLongString, sizeof(kLongString));
 
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   request.AddString(kDummyTag, kLongString);
   EXPECT_THAT(request, RequestDataIs(&expected, sizeof(expected)));
 }
@@ -146,7 +146,7 @@
     const uint32_t attr_value = kValue;
   } expected;
 
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   request.AddInt(kDummyTag, kValue);
   EXPECT_THAT(request, RequestDataIs(&expected, sizeof(expected)));
 }
@@ -188,7 +188,7 @@
     uint8_t attr_padding_u8[3] = {0, 0, 0};
   } expected = {};
 
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   request.AddInt<int64_t>(kDummyTag, kValue);
   request.AddInt<int32_t>(kDummyTag + 1, kValue);
   request.AddInt<int16_t>(kDummyTag + 2, kValue);
@@ -215,7 +215,7 @@
     const uint32_t attr_value = kValue;
   } expected;
 
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   request.PushList(kListTag);
   request.AddInt(kDummyTag, kValue);
   request.PopList();
@@ -240,7 +240,7 @@
     const uint32_t attr_value = kValue;
   } expected;
 
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   request.PushList(kList1Tag);
   request.PushList(kList2Tag);
   request.AddInt(kDummyTag, kValue);
@@ -272,7 +272,7 @@
     const uint32_t attr2_value = kValue2;
   } expected;
 
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   request.PushList(kList1Tag);
   request.AddInt(kDummy1Tag, kValue1);
   request.PopList();
@@ -305,7 +305,7 @@
     const uint32_t attr2_value = kValue2;
   } expected;
 
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   request.PushList(kList1Tag);
   request.PushList(kList2Tag);
   request.AddInt(kDummy1Tag, kValue1);
@@ -317,7 +317,7 @@
 }
 
 TEST(NetlinkClientTest, SimpleNetlinkCreateHeader) {
-  cvd::NetlinkRequest request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL);
+  NetlinkRequest request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL);
   constexpr char kValue[] = "random string";
   request.AddString(0, kValue);  // Have something to work with.
 
@@ -331,7 +331,7 @@
       NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST,
       base_seq));
 
-  cvd::NetlinkRequest request2(RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL);
+  NetlinkRequest request2(RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL);
   request2.AddString(0, kValue);  // Have something to work with.
   EXPECT_THAT(request2, RequestHeaderIs(
       kMsgLength,
@@ -341,7 +341,7 @@
 }
 
 TEST(NetlinkClientTest, SimpleNetlinkUpdateHeader) {
-  cvd::NetlinkRequest request(RTM_SETLINK, 0);
+  NetlinkRequest request(RTM_SETLINK, 0);
   constexpr char kValue[] = "random string";
   request.AddString(0, kValue);  // Have something to work with.
 
@@ -352,10 +352,10 @@
   EXPECT_THAT(request, RequestHeaderIs(
       kMsgLength, RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK, base_seq));
 
-  cvd::NetlinkRequest request2(RTM_SETLINK, 0);
+  NetlinkRequest request2(RTM_SETLINK, 0);
   request2.AddString(0, kValue);  // Have something to work with.
   EXPECT_THAT(request2, RequestHeaderIs(
       kMsgLength, RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK, base_seq + 1));
 }
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/net/network_interface.h b/common/libs/net/network_interface.h
index 2f4430d..323db53 100644
--- a/common/libs/net/network_interface.h
+++ b/common/libs/net/network_interface.h
@@ -18,7 +18,7 @@
 
 #include <string>
 
-namespace cvd {
+namespace cuttlefish {
 
 // Abstraction of network interfaces.
 // This interface provides means to modify network interface parameters.
@@ -111,6 +111,6 @@
   NetworkInterface& operator= (const NetworkInterface&);
 };
 
-}  // namespace cvd
+}  // namespace cuttlefish
 
 #endif  // GUEST_GCE_NETWORK_NETWORK_INTERFACE_H_
diff --git a/common/libs/net/network_interface_manager.cpp b/common/libs/net/network_interface_manager.cpp
index 0d1dc56..19371e6 100644
--- a/common/libs/net/network_interface_manager.cpp
+++ b/common/libs/net/network_interface_manager.cpp
@@ -24,10 +24,10 @@
 
 #include <memory>
 
-#include "common/libs/glog/logging.h"
+#include "android-base/logging.h"
 #include "common/libs/net/network_interface.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace {
 NetlinkRequest BuildLinkRequest(
     const NetworkInterface& interface) {
@@ -104,4 +104,4 @@
   return nl_client_->Send(BuildAddrRequest(iface));
 }
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/net/network_interface_manager.h b/common/libs/net/network_interface_manager.h
index f28b0ff..4ade909 100644
--- a/common/libs/net/network_interface_manager.h
+++ b/common/libs/net/network_interface_manager.h
@@ -22,7 +22,7 @@
 #include "common/libs/net/netlink_client.h"
 #include "common/libs/net/network_interface.h"
 
-namespace cvd {
+namespace cuttlefish {
 
 // Network interface manager class.
 // - Provides access for existing network interfaces,
@@ -67,6 +67,6 @@
   NetworkInterfaceManager& operator= (const NetworkInterfaceManager&);
 };
 
-}  // namespace cvd
+}  // namespace cuttlefish
 
 #endif  // COMMON_LIBS_NET_NETWORK_INTERFACE_MANAGER_H_
diff --git a/common/libs/security/Android.bp b/common/libs/security/Android.bp
new file mode 100644
index 0000000..4f22951
--- /dev/null
+++ b/common/libs/security/Android.bp
@@ -0,0 +1,61 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+    name: "libcuttlefish_security",
+    defaults: ["hidl_defaults", "cuttlefish_host"],
+    srcs: [
+        "gatekeeper_channel.cpp",
+        "keymaster_channel.cpp",
+    ],
+    header_libs: [
+        "libhardware_headers",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libgatekeeper",
+        "libkeymaster_messages",
+        "liblog",
+    ],
+}
+
+cc_test {
+    name: "libcuttlefish_security_tests",
+    srcs: [
+        "keymaster_channel_test.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_security",
+        "libgatekeeper",
+        "libkeymaster_messages",
+        "liblog",
+    ],
+    static_libs: [
+        "libgmock",
+        "libgtest",
+    ],
+    defaults: ["cuttlefish_buildhost_only"],
+    test_suites: ["general-tests"],
+    test_options: {
+        unit_test: true,
+    },
+}
diff --git a/common/libs/security/gatekeeper_channel.cpp b/common/libs/security/gatekeeper_channel.cpp
new file mode 100644
index 0000000..7038d67
--- /dev/null
+++ b/common/libs/security/gatekeeper_channel.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 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.
+ */
+
+#include "common/libs/security/gatekeeper_channel.h"
+
+#include <cstdlib>
+
+#include <android-base/logging.h>
+#include "keymaster/android_keymaster_utils.h"
+
+#include "common/libs/fs/shared_buf.h"
+
+namespace cuttlefish {
+
+ManagedGatekeeperMessage CreateGatekeeperMessage(
+    uint32_t command, bool is_response, size_t payload_size) {
+  auto memory = std::malloc(payload_size + sizeof(GatekeeperRawMessage));
+  auto message = reinterpret_cast<GatekeeperRawMessage*>(memory);
+  message->cmd = command;
+  message->is_response = is_response;
+  message->payload_size = payload_size;
+  return ManagedGatekeeperMessage(message);
+}
+
+void GatekeeperCommandDestroyer::operator()(GatekeeperRawMessage* ptr) {
+  {
+    keymaster::Eraser(ptr, sizeof(GatekeeperRawMessage) + ptr->payload_size);
+  }
+  std::free(ptr);
+}
+
+GatekeeperChannel::GatekeeperChannel(SharedFD input, SharedFD output)
+    : input_(input), output_(output) {
+}
+
+bool GatekeeperChannel::SendRequest(
+    uint32_t command, const gatekeeper::GateKeeperMessage& message) {
+  return SendMessage(command, false, message);
+}
+
+bool GatekeeperChannel::SendResponse(
+    uint32_t command, const gatekeeper::GateKeeperMessage& message) {
+  return SendMessage(command, true, message);
+}
+
+bool GatekeeperChannel::SendMessage(
+    uint32_t command,
+    bool is_response,
+    const gatekeeper::GateKeeperMessage& message) {
+  LOG(DEBUG) << "Sending message with id: " << command;
+  auto payload_size = message.GetSerializedSize();
+  auto to_send = CreateGatekeeperMessage(command, is_response, payload_size);
+  message.Serialize(to_send->payload, to_send->payload + payload_size);
+  auto write_size = payload_size + sizeof(GatekeeperRawMessage);
+  auto to_send_bytes = reinterpret_cast<const char*>(to_send.get());
+  auto written = WriteAll(output_, to_send_bytes, write_size);
+  if (written == -1) {
+    LOG(ERROR) << "Could not write Gatekeeper Message: " << output_->StrError();
+  }
+  return written == write_size;
+}
+
+ManagedGatekeeperMessage GatekeeperChannel::ReceiveMessage() {
+  struct GatekeeperRawMessage message_header;
+  auto read = ReadExactBinary(input_, &message_header);
+  if (read != sizeof(GatekeeperRawMessage)) {
+    LOG(ERROR) << "Expected " << sizeof(GatekeeperRawMessage) << ", received "
+               << read;
+    LOG(ERROR) << "Could not read Gatekeeper Message: " << input_->StrError();
+    return {};
+  }
+  LOG(DEBUG) << "Received message with id: " << message_header.cmd;
+  auto message = CreateGatekeeperMessage(message_header.cmd,
+                                         message_header.is_response,
+                                         message_header.payload_size);
+  auto message_bytes = reinterpret_cast<char*>(message->payload);
+  read = ReadExact(input_, message_bytes, message->payload_size);
+  if (read != message->payload_size) {
+    LOG(ERROR) << "Could not read Gatekeeper Message: " << input_->StrError();
+    return {};
+  }
+  return message;
+}
+
+} // namespace cuttlefish
diff --git a/common/libs/security/gatekeeper_channel.h b/common/libs/security/gatekeeper_channel.h
new file mode 100644
index 0000000..b4222e7
--- /dev/null
+++ b/common/libs/security/gatekeeper_channel.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 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 "gatekeeper/gatekeeper_messages.h"
+
+#include "common/libs/fs/shared_fd.h"
+
+#include <memory>
+
+namespace gatekeeper {
+
+/**
+ * GatekeeperRawMessage - Header and raw byte payload for a serialized
+ * gatekeeper message.
+ *
+ * @cmd: the command, one of gatekeeper::ENROLL and gatekeeper::VERIFY.
+ * @payload: start of the serialized command specific payload
+ */
+struct GatekeeperRawMessage {
+    uint32_t cmd : 31;
+    bool is_response : 1;
+    uint32_t payload_size;
+    uint8_t payload[0];
+};
+
+} // namespace gatekeeper
+
+namespace cuttlefish {
+
+using gatekeeper::GatekeeperRawMessage;
+
+/**
+ * A destroyer for GatekeeperRawMessage instances created with
+ * CreateGatekeeperMessage. Wipes memory from the GatekeeperRawMessage instances.
+ */
+class GatekeeperCommandDestroyer {
+public:
+  void operator()(GatekeeperRawMessage* ptr);
+};
+
+/** An owning pointer for a GatekeeperRawMessage instance. */
+using ManagedGatekeeperMessage =
+    std::unique_ptr<GatekeeperRawMessage, GatekeeperCommandDestroyer>;
+
+/**
+ * Allocates memory for a GatekeeperRawMessage carrying a message of size
+ * `payload_size`.
+ */
+ManagedGatekeeperMessage CreateGatekeeperMessage(
+    uint32_t command, bool is_response, size_t payload_size);
+
+/*
+ * Interface for communication channels that synchronously communicate Gatekeeper
+ * IPC/RPC calls. Sends messages over a file descriptor.
+ */
+class GatekeeperChannel {
+public:
+  GatekeeperChannel(SharedFD input, SharedFD output);
+
+  bool SendRequest(uint32_t command,
+                   const gatekeeper::GateKeeperMessage& message);
+  bool SendResponse(uint32_t command,
+                    const gatekeeper::GateKeeperMessage& message);
+  ManagedGatekeeperMessage ReceiveMessage();
+private:
+  SharedFD input_;
+  SharedFD output_;
+  bool SendMessage(uint32_t command, bool response,
+                   const gatekeeper::GateKeeperMessage& message);
+};
+
+} // namespace cuttlefish
diff --git a/common/libs/security/keymaster_channel.cpp b/common/libs/security/keymaster_channel.cpp
new file mode 100644
index 0000000..7b3ab86
--- /dev/null
+++ b/common/libs/security/keymaster_channel.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 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.
+ */
+
+#include "keymaster_channel.h"
+
+#include <android-base/logging.h>
+#include "keymaster/android_keymaster_utils.h"
+
+#include "common/libs/fs/shared_buf.h"
+
+namespace cuttlefish {
+
+ManagedKeymasterMessage CreateKeymasterMessage(
+    AndroidKeymasterCommand command, bool is_response, size_t payload_size) {
+  auto memory = new uint8_t[payload_size + sizeof(keymaster_message)];
+  auto message = reinterpret_cast<keymaster_message*>(memory);
+  message->cmd = command;
+  message->is_response = is_response;
+  message->payload_size = payload_size;
+  return ManagedKeymasterMessage(message);
+}
+
+void KeymasterCommandDestroyer::operator()(keymaster_message* ptr) {
+  {
+    keymaster::Eraser(ptr, sizeof(keymaster_message) + ptr->payload_size);
+  }
+  delete reinterpret_cast<uint8_t*>(ptr);
+}
+
+KeymasterChannel::KeymasterChannel(SharedFD input, SharedFD output)
+    : input_(input), output_(output) {
+}
+
+bool KeymasterChannel::SendRequest(
+    AndroidKeymasterCommand command, const keymaster::Serializable& message) {
+  return SendMessage(command, false, message);
+}
+
+bool KeymasterChannel::SendResponse(
+    AndroidKeymasterCommand command, const keymaster::Serializable& message) {
+  return SendMessage(command, true, message);
+}
+
+bool KeymasterChannel::SendMessage(
+    AndroidKeymasterCommand command,
+    bool is_response,
+    const keymaster::Serializable& message) {
+  auto payload_size = message.SerializedSize();
+  LOG(VERBOSE) << "Sending message with id: " << command << " and size "
+               << payload_size;
+  auto to_send = CreateKeymasterMessage(command, is_response, payload_size);
+  message.Serialize(to_send->payload, to_send->payload + payload_size);
+  auto write_size = payload_size + sizeof(keymaster_message);
+  auto to_send_bytes = reinterpret_cast<const char*>(to_send.get());
+  auto written = WriteAll(output_, to_send_bytes, write_size);
+  if (written != write_size) {
+    LOG(ERROR) << "Could not write Keymaster Message: " << output_->StrError();
+  }
+  return written == write_size;
+}
+
+ManagedKeymasterMessage KeymasterChannel::ReceiveMessage() {
+  struct keymaster_message message_header;
+  auto read = ReadExactBinary(input_, &message_header);
+  if (read != sizeof(keymaster_message)) {
+    LOG(ERROR) << "Expected " << sizeof(keymaster_message) << ", received "
+               << read;
+    LOG(ERROR) << "Could not read Keymaster Message: " << input_->StrError();
+    return {};
+  }
+  LOG(VERBOSE) << "Received message with id: " << message_header.cmd
+               << " and size " << message_header.payload_size;
+  auto message = CreateKeymasterMessage(message_header.cmd,
+                                        message_header.is_response,
+                                        message_header.payload_size);
+  auto message_bytes = reinterpret_cast<char*>(message->payload);
+  read = ReadExact(input_, message_bytes, message->payload_size);
+  if (read != message->payload_size) {
+    LOG(ERROR) << "Could not read Keymaster Message: " << input_->StrError();
+    return {};
+  }
+  return message;
+}
+
+}
diff --git a/common/libs/security/keymaster_channel.h b/common/libs/security/keymaster_channel.h
new file mode 100644
index 0000000..49c3843
--- /dev/null
+++ b/common/libs/security/keymaster_channel.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 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 "keymaster/android_keymaster_messages.h"
+#include "keymaster/serializable.h"
+
+#include "common/libs/fs/shared_fd.h"
+
+#include <memory>
+
+namespace keymaster {
+
+/**
+ * keymaster_message - Serial header for communicating with KM server
+ * @cmd: the command, one of AndroidKeymasterCommand.
+ * @payload: start of the serialized command specific payload
+ */
+struct keymaster_message {
+    AndroidKeymasterCommand cmd : 31;
+    bool is_response : 1;
+    uint32_t payload_size;
+    uint8_t payload[0];
+};
+
+} // namespace keymaster
+
+namespace cuttlefish {
+
+using keymaster::AndroidKeymasterCommand;
+using keymaster::keymaster_message;
+
+/**
+ * A destroyer for keymaster_message instances created with
+ * CreateKeymasterMessage. Wipes memory from the keymaster_message instances.
+ */
+class KeymasterCommandDestroyer {
+public:
+  void operator()(keymaster_message* ptr);
+};
+
+/** An owning pointer for a keymaster_message instance. */
+using ManagedKeymasterMessage =
+    std::unique_ptr<keymaster_message, KeymasterCommandDestroyer>;
+
+/**
+ * Allocates memory for a keymaster_message carrying a message of size
+ * `payload_size`.
+ */
+ManagedKeymasterMessage CreateKeymasterMessage(
+    AndroidKeymasterCommand command, bool is_response, size_t payload_size);
+
+/*
+ * Interface for communication channels that synchronously communicate Keymaster
+ * IPC/RPC calls. Sends messages over a file descriptor.
+ */
+class KeymasterChannel {
+public:
+  KeymasterChannel(SharedFD input, SharedFD output);
+
+  bool SendRequest(AndroidKeymasterCommand command,
+                   const keymaster::Serializable& message);
+  bool SendResponse(AndroidKeymasterCommand command,
+                    const keymaster::Serializable& message);
+  ManagedKeymasterMessage ReceiveMessage();
+private:
+  SharedFD input_;
+  SharedFD output_;
+  bool SendMessage(AndroidKeymasterCommand command, bool response,
+                   const keymaster::Serializable& message);
+};
+
+} // namespace cuttlefish
diff --git a/common/libs/security/keymaster_channel_test.cpp b/common/libs/security/keymaster_channel_test.cpp
new file mode 100644
index 0000000..aed5bed
--- /dev/null
+++ b/common/libs/security/keymaster_channel_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/keymaster_channel.h"
+#include "gtest/gtest.h"
+
+namespace cuttlefish {
+
+TEST(KeymasterChannel, SendAndReceiveRequest) {
+  SharedFD read_fd;
+  SharedFD write_fd;
+  ASSERT_TRUE(SharedFD::Pipe(&read_fd, &write_fd)) << "Failed to create pipe";
+
+  KeymasterChannel channel{read_fd, write_fd};
+
+  char buffer[] = {1, 2, 3, 4, 5, 6};
+  keymaster::Buffer request(buffer, sizeof(buffer));
+
+  ASSERT_TRUE(channel.SendRequest(keymaster::GET_VERSION, request))
+      << "Failed to send request";
+  auto response = channel.ReceiveMessage();
+  EXPECT_EQ(response->cmd, keymaster::GET_VERSION) << "Command mismatch";
+  EXPECT_FALSE(response->is_response) << "Request/response mismatch";
+
+  keymaster::Buffer read;
+  const uint8_t* read_data = response->payload;
+  EXPECT_TRUE(read.Deserialize(&read_data, read_data + response->payload_size))
+      << "Failed to deserialize request";
+  ASSERT_EQ(request.end() - request.begin(), read.end() - read.begin());
+  ASSERT_EQ(request.buffer_size(), read.buffer_size());
+  ASSERT_TRUE(std::equal(request.begin(), request.end(), read.begin()));
+}
+
+TEST(KeymasterChannel, SendAndReceiveResponse) {
+  SharedFD read_fd;
+  SharedFD write_fd;
+  ASSERT_TRUE(SharedFD::Pipe(&read_fd, &write_fd)) << "Failed to create pipe";
+
+  KeymasterChannel channel{read_fd, write_fd};
+
+  char buffer[] = {1, 2, 3, 4, 5, 6};
+  keymaster::Buffer request(buffer, sizeof(buffer));
+
+  ASSERT_TRUE(channel.SendResponse(keymaster::GET_VERSION, request))
+      << "Failed to send request";
+  auto response = channel.ReceiveMessage();
+  EXPECT_EQ(response->cmd, keymaster::GET_VERSION) << "Command mismatch";
+  EXPECT_TRUE(response->is_response) << "Request/response mismatch";
+
+  keymaster::Buffer read;
+  const uint8_t* read_data = response->payload;
+  EXPECT_TRUE(read.Deserialize(&read_data, read_data + response->payload_size))
+      << "Failed to deserialize request";
+  ASSERT_EQ(request.end() - request.begin(), read.end() - read.begin());
+  ASSERT_EQ(request.buffer_size(), read.buffer_size());
+  ASSERT_TRUE(std::equal(request.begin(), request.end(), read.begin()));
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/tcp_socket/Android.bp b/common/libs/tcp_socket/Android.bp
deleted file mode 100644
index c5f9550..0000000
--- a/common/libs/tcp_socket/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// Copyright (C) 2018 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.
-
-cc_library_shared {
-    name: "cuttlefish_tcp_socket",
-    srcs: [
-        "tcp_socket.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcuttlefish_fs",
-        "liblog",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
-    defaults: ["cuttlefish_host_and_guest"],
-}
diff --git a/common/libs/tcp_socket/tcp_socket.cpp b/common/libs/tcp_socket/tcp_socket.cpp
deleted file mode 100644
index 64da7d7..0000000
--- a/common/libs/tcp_socket/tcp_socket.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "common/libs/tcp_socket/tcp_socket.h"
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <cerrno>
-
-#include <glog/logging.h>
-
-using cvd::ClientSocket;
-using cvd::ServerSocket;
-
-ClientSocket::ClientSocket(int port)
-    : fd_(SharedFD::SocketLocalClient(port, SOCK_STREAM)) {}
-
-cvd::Message ClientSocket::RecvAny(std::size_t length) {
-  Message buf(length);
-  auto read_count = fd_->Read(buf.data(), buf.size());
-  if (read_count < 0) {
-    read_count = 0;
-  }
-  buf.resize(read_count);
-  return buf;
-}
-
-bool ClientSocket::closed() const {
-  std::lock_guard<std::mutex> guard(closed_lock_);
-  return other_side_closed_;
-}
-
-cvd::Message ClientSocket::Recv(std::size_t length) {
-  Message buf(length);
-  ssize_t total_read = 0;
-  while (total_read < static_cast<ssize_t>(length)) {
-    auto just_read = fd_->Read(&buf[total_read], buf.size() - total_read);
-    if (just_read <= 0) {
-      if (just_read < 0) {
-        LOG(ERROR) << "read() error: " << strerror(errno);
-      }
-      {
-        std::lock_guard<std::mutex> guard(closed_lock_);
-        other_side_closed_ = true;
-      }
-      return Message{};
-    }
-    total_read += just_read;
-  }
-  CHECK(total_read == static_cast<ssize_t>(length));
-  return buf;
-}
-
-ssize_t ClientSocket::SendNoSignal(const uint8_t* data, std::size_t size) {
-  std::lock_guard<std::mutex> lock(send_lock_);
-  ssize_t written{};
-  while (written < static_cast<ssize_t>(size)) {
-    if (!fd_->IsOpen()) {
-      LOG(ERROR) << "fd_ is closed";
-    }
-    auto just_written = fd_->Send(data + written, size - written, MSG_NOSIGNAL);
-    if (just_written <= 0) {
-      LOG(INFO) << "Couldn't write to client: " << strerror(errno);
-      {
-        std::lock_guard<std::mutex> guard(closed_lock_);
-        other_side_closed_ = true;
-      }
-      return just_written;
-    }
-    written += just_written;
-  }
-  return written;
-}
-
-ssize_t ClientSocket::SendNoSignal(const Message& message) {
-  return SendNoSignal(&message[0], message.size());
-}
-
-ServerSocket::ServerSocket(int port)
-    : fd_{SharedFD::SocketLocalServer(port, SOCK_STREAM)} {
-  if (!fd_->IsOpen()) {
-    LOG(FATAL) << "Couldn't open streaming server on port " << port;
-  }
-}
-
-ClientSocket ServerSocket::Accept() {
-  SharedFD client = SharedFD::Accept(*fd_);
-  if (!client->IsOpen()) {
-    LOG(FATAL) << "Error attemping to accept: " << strerror(errno);
-  }
-  return ClientSocket{client};
-}
-
-void cvd::AppendInNetworkByteOrder(Message* msg, const std::uint8_t b) {
-  msg->push_back(b);
-}
-
-void cvd::AppendInNetworkByteOrder(Message* msg, const std::uint16_t s) {
-  const std::uint16_t n = htons(s);
-  auto p = reinterpret_cast<const std::uint8_t*>(&n);
-  msg->insert(msg->end(), p, p + sizeof n);
-}
-
-void cvd::AppendInNetworkByteOrder(Message* msg, const std::uint32_t w) {
-  const std::uint32_t n = htonl(w);
-  auto p = reinterpret_cast<const std::uint8_t*>(&n);
-  msg->insert(msg->end(), p, p + sizeof n);
-}
-
-void cvd::AppendInNetworkByteOrder(Message* msg, const std::int32_t w) {
-  std::uint32_t u{};
-  std::memcpy(&u, &w, sizeof u);
-  AppendInNetworkByteOrder(msg, u);
-}
-
-void cvd::AppendInNetworkByteOrder(Message* msg, const std::string& str) {
-  msg->insert(msg->end(), str.begin(), str.end());
-}
diff --git a/common/libs/tcp_socket/tcp_socket.h b/common/libs/tcp_socket/tcp_socket.h
deleted file mode 100644
index e484f48..0000000
--- a/common/libs/tcp_socket/tcp_socket.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "common/libs/fs/shared_fd.h"
-
-#include <unistd.h>
-
-#include <cstddef>
-#include <cstdint>
-#include <mutex>
-#include <vector>
-
-namespace cvd {
-using Message = std::vector<std::uint8_t>;
-
-class ServerSocket;
-
-// Recv and Send wait until all data has been received or sent.
-// Send is thread safe in this regard, Recv is not.
-class ClientSocket {
- public:
-  ClientSocket(ClientSocket&& other) : fd_{other.fd_} {}
-
-  ClientSocket& operator=(ClientSocket&& other) {
-    fd_ = other.fd_;
-    return *this;
-  }
-
-  ClientSocket(int port);
-
-  ClientSocket(const ClientSocket&) = delete;
-  ClientSocket& operator=(const ClientSocket&) = delete;
-
-  Message Recv(std::size_t length);
-  // RecvAny will receive whatever is available.
-  // An empty message returned indicates error or close.
-  Message RecvAny(std::size_t length);
-  // Sends are called with MSG_NOSIGNAL to suppress SIGPIPE
-  ssize_t SendNoSignal(const std::uint8_t* data, std::size_t size);
-  ssize_t SendNoSignal(const Message& message);
-
-  template <std::size_t N>
-  ssize_t SendNoSignal(const std::uint8_t (&data)[N]) {
-    return SendNoSignal(data, N);
-  }
-
-  bool closed() const;
-
- private:
-  friend ServerSocket;
-  explicit ClientSocket(cvd::SharedFD fd) : fd_(fd) {}
-
-  cvd::SharedFD fd_;
-  bool other_side_closed_{};
-  mutable std::mutex closed_lock_;
-  std::mutex send_lock_;
-};
-
-class ServerSocket {
- public:
-  explicit ServerSocket(int port);
-
-  ServerSocket(const ServerSocket&) = delete;
-  ServerSocket& operator=(const ServerSocket&) = delete;
-
-  ClientSocket Accept();
-
- private:
-  cvd::SharedFD fd_;
-};
-
-void AppendInNetworkByteOrder(Message* msg, const std::uint8_t b);
-void AppendInNetworkByteOrder(Message* msg, const std::uint16_t s);
-void AppendInNetworkByteOrder(Message* msg, const std::uint32_t w);
-void AppendInNetworkByteOrder(Message* msg, const std::int32_t w);
-void AppendInNetworkByteOrder(Message* msg, const std::string& str);
-
-inline void AppendToMessage(Message*) {}
-
-template <typename T, typename... Ts>
-void AppendToMessage(Message* msg, T v, Ts... vals) {
-  AppendInNetworkByteOrder(msg, v);
-  AppendToMessage(msg, vals...);
-}
-
-template <typename... Ts>
-Message CreateMessage(Ts... vals) {
-  Message m;
-  AppendToMessage(&m, vals...);
-  return m;
-}
-
-}  // namespace cvd
diff --git a/common/libs/thread_safe_queue/thread_safe_queue.h b/common/libs/thread_safe_queue/thread_safe_queue.h
deleted file mode 100644
index 9970d31..0000000
--- a/common/libs/thread_safe_queue/thread_safe_queue.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <mutex>
-#include <condition_variable>
-#include <deque>
-#include <utility>
-#include <iterator>
-
-namespace cvd {
-// Simple queue with Push and Pop capabilities.
-// If the max_elements argument is passed to the constructor, and Push is called
-// when the queue holds max_elements items, the max_elements_handler is called
-// with a pointer to the internal QueueImpl. The call is made while holding
-// the guarding mutex; operations on the QueueImpl will not interleave with
-// other threads calling Push() or Pop().
-// The QueueImpl type will be a SequenceContainer.
-template <typename T>
-class ThreadSafeQueue {
- public:
-  using QueueImpl = std::deque<T>;
-  ThreadSafeQueue() = default;
-  explicit ThreadSafeQueue(std::size_t max_elements,
-                           std::function<void(QueueImpl*)> max_elements_handler)
-      : max_elements_{max_elements},
-        max_elements_handler_{std::move(max_elements_handler)} {}
-
-  T Pop() {
-    std::unique_lock<std::mutex> guard(m_);
-    while (items_.empty()) {
-      new_item_.wait(guard);
-    }
-    auto t = std::move(items_.front());
-    items_.pop_front();
-    return t;
-  }
-
-  QueueImpl PopAll() {
-    std::unique_lock<std::mutex> guard(m_);
-    while (items_.empty()) {
-      new_item_.wait(guard);
-    }
-    return std::move(items_);
-  }
-
-  void Push(T&& t) {
-    std::lock_guard<std::mutex> guard(m_);
-    DropItemsIfAtCapacity();
-    items_.push_back(std::move(t));
-    new_item_.notify_one();
-  }
-
-  void Push(const T& t) {
-    std::lock_guard<std::mutex> guard(m_);
-    DropItemsIfAtCapacity();
-    items_.push_back(t);
-    new_item_.notify_one();
-  }
-
- private:
-  void DropItemsIfAtCapacity() {
-    if (max_elements_ && max_elements_ == items_.size()) {
-      max_elements_handler_(&items_);
-    }
-  }
-
-  std::mutex m_;
-  std::size_t max_elements_{};
-  std::function<void(QueueImpl*)> max_elements_handler_{};
-  std::condition_variable new_item_;
-  QueueImpl items_;
-};
-}  // namespace cvd
diff --git a/common/libs/threads/thread_annotations.h b/common/libs/threads/thread_annotations.h
deleted file mode 100644
index 3ba67e7..0000000
--- a/common/libs/threads/thread_annotations.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
-#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
-#endif
-
-#define CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
-
-#define SCOPED_CAPABILITY \
-      THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
-
-#define GUARDED_BY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
-
-#define PT_GUARDED_BY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
-
-#define ACQUIRED_BEFORE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
-
-#define ACQUIRED_AFTER(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
-
-#define REQUIRES(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
-
-#define REQUIRES_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
-
-#define ACQUIRE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
-
-#define ACQUIRE_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
-
-#define RELEASE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
-
-#define RELEASE_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
-
-#define TRY_ACQUIRE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
-
-#define TRY_ACQUIRE_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
-
-#define EXCLUDES(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
-
-#define ASSERT_CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
-
-#define ASSERT_SHARED_CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
-
-#define RETURN_CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
-
-#define NO_THREAD_SAFETY_ANALYSIS \
-      THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
diff --git a/common/libs/time/Android.bp b/common/libs/time/Android.bp
deleted file mode 100644
index 972958f..0000000
--- a/common/libs/time/Android.bp
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-cc_library_shared {
-    name: "cuttlefish_time",
-    srcs: [
-        "monotonic_time.cpp",
-    ],
-    defaults: ["cuttlefish_host_and_guest"],
-}
-
-cc_test_host {
-    name: "monotonic_time_test",
-    srcs: [
-        "monotonic_time_test.cpp",
-    ],
-    shared_libs: [
-        "cuttlefish_time",
-    ],
-    defaults: ["cuttlefish_host_only"],
-    test_suites: ["general-tests"],
-}
diff --git a/common/libs/time/TEST_MAPPING b/common/libs/time/TEST_MAPPING
deleted file mode 100644
index 4c95014..0000000
--- a/common/libs/time/TEST_MAPPING
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "monotonic_time_test",
-      "host": true
-    }
-  ]
-}
diff --git a/common/libs/time/monotonic_time.cpp b/common/libs/time/monotonic_time.cpp
deleted file mode 100644
index 1d7bbd8..0000000
--- a/common/libs/time/monotonic_time.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-#include "common/libs/time/monotonic_time.h"
-
-namespace cvd {
-namespace time {
-MonotonicTimePointFactory* MonotonicTimePointFactory::GetInstance() {
-  static MonotonicTimePointFactory factory;
-
-  return &factory;
-}
-}  // namespace time
-}  // namespace cvd
diff --git a/common/libs/time/monotonic_time.h b/common/libs/time/monotonic_time.h
index 8f5de13..2839001 100644
--- a/common/libs/time/monotonic_time.h
+++ b/common/libs/time/monotonic_time.h
@@ -18,7 +18,7 @@
 #include <stdint.h>
 #include <time.h>
 
-namespace cvd {
+namespace cuttlefish {
 namespace time {
 
 static const int64_t kNanosecondsPerSecond = 1000000000;
@@ -226,17 +226,6 @@
   struct timespec ts_;
 };
 
-class MonotonicTimePointFactory {
- public:
-  static MonotonicTimePointFactory* GetInstance();
-
-  virtual ~MonotonicTimePointFactory() { }
-
-  virtual void FetchCurrentTime(MonotonicTimePoint* dest) const {
-    *dest = MonotonicTimePoint::Now();
-  }
-};
-
 class Seconds : public TimeDifference {
  public:
   explicit Seconds(const TimeDifference& difference) :
@@ -279,7 +268,7 @@
 };
 
 }  // namespace time
-}  // namespace cvd
+}  // namespace cuttlefish
 
 /**
  * Legacy support for microseconds. Use MonotonicTimePoint in new code.
@@ -287,6 +276,6 @@
 static const int64_t kSecsToUsecs = static_cast<int64_t>(1000) * 1000;
 
 static inline int64_t get_monotonic_usecs() {
-  return cvd::time::Microseconds(
-      cvd::time::MonotonicTimePoint::Now().SinceEpoch()).count();
+  return cuttlefish::time::Microseconds(
+      cuttlefish::time::MonotonicTimePoint::Now().SinceEpoch()).count();
 }
diff --git a/common/libs/time/monotonic_time_test.cpp b/common/libs/time/monotonic_time_test.cpp
deleted file mode 100644
index b1c07c9..0000000
--- a/common/libs/time/monotonic_time_test.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-#include "common/libs/time/monotonic_time.h"
-
-#include <gtest/gtest.h>
-#include <algorithm>
-
-using cvd::time::TimeDifference;
-
-class MonotonicTimeTest : public ::testing::Test {
- public:
-  MonotonicTimeTest() {}
-};
-
-TEST_F(MonotonicTimeTest, TimeDifferenceAdd1) {
-  TimeDifference td1(1, 10, 1);
-  TimeDifference td2(0, 100, 1);
-  EXPECT_EQ((td1+td2).count(), (1)*1000000000 + 110);
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceAdd2) {
-  TimeDifference td1(10, 1000, 1);
-  TimeDifference td2(100, 10000, 1);
-  EXPECT_EQ((td1+td2).count(), (110L)*1000000000L + 11000L);
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceAdd3) {
-  int64_t scale = 1000;
-  TimeDifference td1(10, 1000, scale);
-  TimeDifference td2(100, 10000, scale);
-  EXPECT_EQ((td1+td2).count(), ((110L)*1000000000L + 11000L)/scale);
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceAdd4) {
-  int64_t scale = 1;
-  TimeDifference td1(-10, 1000, scale);
-  TimeDifference td2(100, 10000, scale);
-  EXPECT_EQ((td1+td2).count(), ((90L)*1000000000L + 11000L)/scale);
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceAdd5) {
-  int64_t scale1 = 1, scale2 = 1000;
-  TimeDifference td1(-10, 1000, scale1);
-  TimeDifference td2(100, 10000, scale2);
-  EXPECT_EQ((td1+td2).count(), ((90L)*1000000000L + 11000L)/std::min(scale1, scale2));
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceAdd6) {
-  int64_t scale1 = 1000, scale2 = 1000;
-  TimeDifference td1(0, 995, scale1);
-  TimeDifference td2(0, 10, scale2);
-  EXPECT_EQ((td1+td2).count(), (1005L)/std::min(scale1, scale2));
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceSub1) {
-  int64_t scale = 1;
-  TimeDifference td1(10, 1000, scale);
-  TimeDifference td2(100, 10000, scale);
-  EXPECT_EQ((td2-td1).count(), ((90L)*1000000000L + 9000L)/scale);
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceSub2) {
-  int64_t scale = 1;
-  TimeDifference td1(10, 1000, scale);
-  TimeDifference td2(100, 10000, scale);
-  EXPECT_EQ((td1-td2).count(), ((-91L)*1000000000L + 1000000000L - 9000L)/scale);
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceSub3) {
-  int64_t scale1 = 1, scale2 = 1000;
-  TimeDifference td1(-10, 1000, scale1);
-  TimeDifference td2(100, 10000, scale2);
-  EXPECT_EQ((td1-td2).count(), ((-111L)*1000000000L + 1000000000L - 9000L)/std::min(scale1, scale2));
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceSub4) {
-  int64_t scale1 = 1000, scale2 = 1000;
-  TimeDifference td1(0, 995, scale1);
-  TimeDifference td2(0, 10, scale2);
-  EXPECT_EQ((td1-td2).count(), (985L)/std::min(scale1, scale2));
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceComp1) {
-  int64_t scale = 1;
-  TimeDifference td1(10, 10000, scale);
-  TimeDifference td2(100, 10, scale);
-  EXPECT_TRUE((td1 < td2));
-  EXPECT_FALSE(td2 < td1);
-}
-
-TEST_F(MonotonicTimeTest, TimeDifferenceComp2) {
-  int64_t scale = 1;
-  TimeDifference td1(100, 10000, scale);
-  TimeDifference td2(100, 10, scale);
-  EXPECT_TRUE((td2 < td1));
-  EXPECT_FALSE(td1 < td2);
-}
diff --git a/common/libs/usbforward/protocol.h b/common/libs/usbforward/protocol.h
deleted file mode 100644
index c55c3b6..0000000
--- a/common/libs/usbforward/protocol.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2017 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 <stdint.h>
-
-namespace usb_forward {
-
-// Commands that can be executed over serial port.
-// Use magic value to avoid accidental interpretation of commonly seen numbers.
-enum Command : uint32_t {
-  // Get device list.
-  // Request format:
-  // - RequestHeader{}
-  // Response format:
-  // - ResponseHeader{}
-  // - int32_t(num_devices)
-  // - num_devices times:
-  //   - DeviceInfo{}
-  //   - DeviceInfo.num_interfaces times:
-  //     - InterfaceInfo{}
-  CmdDeviceList = 0xcfad0001,
-
-  // Attach specified device.
-  // Request format:
-  // - RequestHeader{}
-  // - AttachRequestHeader{}
-  // Response format:
-  // - ResponseHeader{}
-  CmdAttach,
-
-  // Execute command on attached USB device.
-  // Request format:
-  // - RequestHeader{}
-  // - ControlTransfer{}
-  // - if transfer direction is host -> device
-  //   - uint8_t[ControlTransfer.length] data
-  // Response format:
-  // - ResponseHeader{}
-  // - if transfer direction is device -> host
-  //   - int32_t(actual length)
-  //   - uint8_t[actual length] bytes
-  CmdControlTransfer,
-
-  // Execute transfer on attached USB device.
-  // Request format:
-  // - RequestHeader{}
-  // - DataTransfer{}
-  // - if transfer direction is host -> device
-  //   - uint8_t[DataTransfer.length] data
-  // Response format:
-  // - ResponseHeader{}
-  // - if transfer direction is host -> device
-  //   - int32_t(actual length)
-  //   - int32_t[actual length] bytes
-  CmdDataTransfer,
-
-  // Heartbeat is used to detect whether device is alive.
-  // This is a trivial request/response mechanism.
-  // Response status indicates whether server is ready.
-  // Request format:
-  // - RequestHeader{}
-  // Response format:
-  // - ResponseHeader{}
-  CmdHeartbeat,
-};
-
-// Status represents command execution result, using USB/IP compatible values.
-enum Status : uint32_t {
-  // StatusSuccess indicates successful command execution.
-  StatusSuccess = 0,
-
-  // StatusFailure indicates error during command execution.
-  StatusFailure = 1
-};
-
-struct RequestHeader {
-  Command command;
-  uint32_t tag;
-};
-
-struct ResponseHeader {
-  Status status;
-  uint32_t tag;
-};
-
-// DeviceInfo describes individual USB device that was found attached to the
-// bus.
-struct DeviceInfo {
-  uint16_t vendor_id;
-  uint16_t product_id;
-  uint16_t dev_version;
-  uint8_t dev_class;
-  uint8_t dev_subclass;
-  uint8_t dev_protocol;
-  uint8_t bus_id;
-  uint8_t dev_id;
-  uint8_t speed;
-  uint8_t num_configurations;
-  uint8_t num_interfaces;
-  uint8_t cur_configuration;
-} __attribute__((packed));
-
-// InterfaceInfo describes individual interface attached to a USB device.
-struct InterfaceInfo {
-  uint8_t if_class;
-  uint8_t if_subclass;
-  uint8_t if_protocol;
-  uint8_t if_reserved;
-} __attribute__((packed));
-
-// AttachRequest specifies which device on which bus needs to be attached.
-struct AttachRequest {
-  uint8_t bus_id;
-  uint8_t dev_id;
-} __attribute__((packed));
-
-// ControlTransfer specifies target bus and device along with USB request.
-struct ControlTransfer {
-  uint8_t bus_id;
-  uint8_t dev_id;
-  uint8_t type;
-  uint8_t cmd;
-  uint16_t value;
-  uint16_t index;
-  uint16_t length;
-  uint32_t timeout;
-} __attribute__((packed));
-
-// DataTransfer is used to exchange data between host and device.
-struct DataTransfer {
-  uint8_t bus_id;
-  uint8_t dev_id;
-  uint8_t endpoint_id;
-  uint8_t is_host_to_device;
-  int32_t length;
-  uint32_t timeout;
-} __attribute__((packed));
-
-}  // namespace usb_forward
diff --git a/common/libs/utils/Android.bp b/common/libs/utils/Android.bp
index 268862f..f8ca5e2 100644
--- a/common/libs/utils/Android.bp
+++ b/common/libs/utils/Android.bp
@@ -13,6 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library {
     name: "libcuttlefish_utils",
     srcs: [
@@ -23,14 +27,15 @@
         "files.cpp",
         "users.cpp",
         "network.cpp",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
+        "base64.cpp",
+        "tcp_socket.cpp",
+        "tee_logging.cpp",
     ],
     shared: {
         shared_libs: [
             "libbase",
             "libcuttlefish_fs",
+            "libcrypto",
         ],
     },
     static: {
@@ -38,6 +43,9 @@
             "libbase",
             "libcuttlefish_fs",
         ],
+        shared_libs: [
+          "libcrypto", // libcrypto_static is not accessible from all targets
+        ],
     },
-    defaults: ["cuttlefish_host_and_guest"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/common/libs/utils/archive.cpp b/common/libs/utils/archive.cpp
index 36e6576..05fbf5f 100644
--- a/common/libs/utils/archive.cpp
+++ b/common/libs/utils/archive.cpp
@@ -20,11 +20,11 @@
 #include <vector>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/utils/subprocess.h"
 
-namespace cvd {
+namespace cuttlefish {
 
 Archive::Archive(const std::string& file) : file(file) {
 }
@@ -33,11 +33,11 @@
 }
 
 std::vector<std::string> Archive::Contents() {
-  cvd::Command bsdtar_cmd("/usr/bin/bsdtar");
+  Command bsdtar_cmd("/usr/bin/bsdtar");
   bsdtar_cmd.AddParameter("-tf");
   bsdtar_cmd.AddParameter(file);
   std::string bsdtar_input, bsdtar_output;
-  auto bsdtar_ret = cvd::RunWithManagedStdio(std::move(bsdtar_cmd), &bsdtar_input,
+  auto bsdtar_ret = RunWithManagedStdio(std::move(bsdtar_cmd), &bsdtar_input,
                                              &bsdtar_output, nullptr);
   if (bsdtar_ret != 0) {
     LOG(ERROR) << "`bsdtar -tf \"" << file << "\"` returned " << bsdtar_ret;
@@ -53,7 +53,7 @@
 
 bool Archive::ExtractFiles(const std::vector<std::string>& to_extract,
                            const std::string& target_directory) {
-  cvd::Command bsdtar_cmd("/usr/bin/bsdtar");
+  Command bsdtar_cmd("/usr/bin/bsdtar");
   bsdtar_cmd.AddParameter("-x");
   bsdtar_cmd.AddParameter("-v");
   bsdtar_cmd.AddParameter("-C");
@@ -64,8 +64,8 @@
   for (const auto& extract : to_extract) {
     bsdtar_cmd.AddParameter(extract);
   }
-  bsdtar_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut,
-                           cvd::Subprocess::StdIOChannel::kStdErr);
+  bsdtar_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut,
+                           Subprocess::StdIOChannel::kStdErr);
   auto bsdtar_ret = bsdtar_cmd.Start().Wait();
   if (bsdtar_ret != 0) {
     LOG(ERROR) << "bsdtar extraction on \"" << file << "\" returned " << bsdtar_ret;
@@ -74,7 +74,7 @@
 }
 
 std::string Archive::ExtractToMemory(const std::string& path) {
-  cvd::Command bsdtar_cmd("/usr/bin/bsdtar");
+  Command bsdtar_cmd("/usr/bin/bsdtar");
   bsdtar_cmd.AddParameter("-xf");
   bsdtar_cmd.AddParameter(file);
   bsdtar_cmd.AddParameter("-O");
@@ -90,4 +90,4 @@
   return stdout;
 }
 
-} // namespace cvd
+} // namespace cuttlefish
diff --git a/common/libs/utils/archive.h b/common/libs/utils/archive.h
index 7563ca0..ea548f2 100644
--- a/common/libs/utils/archive.h
+++ b/common/libs/utils/archive.h
@@ -18,7 +18,7 @@
 #include <string>
 #include <vector>
 
-namespace cvd {
+namespace cuttlefish {
 
 // Operations on archive files
 class Archive {
@@ -34,4 +34,4 @@
   std::string ExtractToMemory(const std::string& path);
 };
 
-} // namespace cvd
+} // namespace cuttlefish
diff --git a/common/libs/utils/base64.cpp b/common/libs/utils/base64.cpp
new file mode 100644
index 0000000..1aa09ce
--- /dev/null
+++ b/common/libs/utils/base64.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#include "common/libs/utils/base64.h"
+
+#include <openssl/base64.h>
+
+namespace cuttlefish {
+
+bool EncodeBase64(const void *data, size_t size, std::string *out) {
+  size_t enc_len = 0;
+  auto len_res = EVP_EncodedLength(&enc_len, size);
+  if (!len_res) {
+    return false;
+  }
+  out->resize(enc_len);
+  auto enc_res = EVP_EncodeBlock(reinterpret_cast<uint8_t *>(out->data()),
+                                 reinterpret_cast<const uint8_t *>(data), size);
+  if (enc_res < 0) {
+    return false;
+  }
+  out->resize(enc_res);  // Don't count the terminating \0 character
+  return true;
+}
+
+bool DecodeBase64(const std::string &data, std::vector<uint8_t> *buffer) {
+  size_t out_len;
+  auto len_res = EVP_DecodedLength(&out_len, data.size());
+  if (!len_res) {
+    return false;
+  }
+  buffer->resize(out_len);
+  return EVP_DecodeBase64(buffer->data(), &out_len, out_len,
+                          reinterpret_cast<const uint8_t *>(data.data()),
+                          data.size());
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/utils/base64.h b/common/libs/utils/base64.h
new file mode 100644
index 0000000..dd262c3
--- /dev/null
+++ b/common/libs/utils/base64.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <cinttypes>
+#include <string>
+#include <vector>
+
+namespace cuttlefish {
+
+bool EncodeBase64(const void* _data, size_t size, std::string* out);
+
+bool DecodeBase64(const std::string& data, std::vector<uint8_t>* buffer);
+
+}  // namespace cuttlefish
diff --git a/common/libs/utils/cf_endian.h b/common/libs/utils/cf_endian.h
new file mode 100644
index 0000000..6eb5dd1
--- /dev/null
+++ b/common/libs/utils/cf_endian.h
@@ -0,0 +1,56 @@
+//
+// 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 <inttypes.h>
+
+#include <android-base/endian.h>
+
+// The utilities in android-base/endian.h still require the use of regular int
+// types to store values with any endianness, which requires the user to
+// remember to manually do the required conversions, which is prone to errors.
+// The types introduced here allow handling these values safely.
+
+namespace cuttlefish {
+
+#define DECLARE_TYPE(new_type, base_type, to_new, to_base)                \
+  class new_type {                                                        \
+   public:                                                                \
+    new_type() = default;                                                 \
+    explicit new_type(base_type val) : inner_(to_new(val)) {}             \
+    new_type(const new_type&) = default;                                  \
+    new_type& operator=(const new_type& other) = default;                 \
+    volatile new_type& operator=(const new_type& other) volatile {        \
+      inner_ = other.inner_;                                              \
+      return *this;                                                       \
+    }                                                                     \
+    base_type as_##base_type() const volatile { return to_base(inner_); } \
+                                                                          \
+   private:                                                               \
+    base_type inner_;                                                     \
+  };                                                                      \
+  static_assert(sizeof(new_type) == sizeof(base_type))
+
+DECLARE_TYPE(Le16, uint16_t, htole16, le16toh);
+DECLARE_TYPE(Le32, uint32_t, htole32, le32toh);
+DECLARE_TYPE(Le64, uint64_t, htole64, le64toh);
+DECLARE_TYPE(Be16, uint16_t, htobe16, be16toh);
+DECLARE_TYPE(Be32, uint32_t, htobe32, be32toh);
+DECLARE_TYPE(Be64, uint64_t, htobe64, be64toh);
+
+#undef DECLARE_TYPE
+
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/utils/environment.cpp b/common/libs/utils/environment.cpp
index e6cacd0..ec27290 100644
--- a/common/libs/utils/environment.cpp
+++ b/common/libs/utils/environment.cpp
@@ -15,12 +15,15 @@
  */
 
 #include "common/libs/utils/environment.h"
+#include "common/libs/utils/files.h"
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <iostream>
 
-namespace cvd {
+#include <android-base/logging.h>
+
+namespace cuttlefish {
 
 std::string StringFromEnv(const std::string& varname,
                           const std::string& defval) {
@@ -38,7 +41,7 @@
  *
  * @return arch string on success, "" on failure
  */
-std::string HostArch() {
+std::string HostArchStr() {
   static std::string arch;
   static bool cached = false;
 
@@ -48,7 +51,7 @@
   cached = true;
 
   // good to check if uname exists and is executable
-  // or, guarantee uname is availabe by dependency list
+  // or, guarantee uname is available by dependency list
   FILE* pip = popen("uname -m", "r");
   if (!pip) {
     return std::string{};
@@ -82,4 +85,40 @@
   return arch;
 }
 
-}  // namespace cvd
+Arch HostArch() {
+  std::string arch_str = HostArchStr();
+  if (arch_str == "aarch64") {
+    return Arch::Arm64;
+  } else if (arch_str == "arm") {
+    return Arch::Arm;
+  } else if (arch_str == "x86_64") {
+    return Arch::X86_64;
+  } else if (arch_str.size() == 4 && arch_str[0] == 'i' && arch_str[2] == '8' &&
+             arch_str[3] == '6') {
+    return Arch::X86;
+  } else {
+    LOG(FATAL) << "Unknown host architecture: " << arch_str;
+    return Arch::X86;
+  }
+}
+
+bool IsHostCompatible(Arch arch) {
+  Arch host_arch = HostArch();
+  return arch == host_arch || (arch == Arch::Arm && host_arch == Arch::Arm64) ||
+         (arch == Arch::X86 && host_arch == Arch::X86_64);
+}
+
+static bool IsRunningInDocker() {
+  // if /.dockerenv exists, it's inside a docker container
+  static std::string docker_env_path("/.dockerenv");
+  static bool ret =
+      FileExists(docker_env_path) || DirectoryExists(docker_env_path);
+  return ret;
+}
+
+bool IsRunningInContainer() {
+  // TODO: add more if we support other containers than docker
+  return IsRunningInDocker();
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/utils/environment.h b/common/libs/utils/environment.h
index 5a83b49..004a849 100644
--- a/common/libs/utils/environment.h
+++ b/common/libs/utils/environment.h
@@ -17,11 +17,22 @@
 
 #include <string>
 
-namespace cvd {
+namespace cuttlefish {
+
+enum class Arch {
+  Arm,
+  Arm64,
+  X86,
+  X86_64,
+};
 
 std::string StringFromEnv(const std::string& varname,
                           const std::string& defval);
 
-std::string HostArch();
+std::string HostArchStr();
+Arch HostArch();
+bool IsHostCompatible(Arch arch);
 
-}  // namespace cvd
+bool IsRunningInContainer();
+
+}  // namespace cuttlefish
diff --git a/common/libs/utils/files.cpp b/common/libs/utils/files.cpp
index 3d0ba06..ea84b32 100644
--- a/common/libs/utils/files.cpp
+++ b/common/libs/utils/files.cpp
@@ -16,17 +16,23 @@
 
 #include "common/libs/utils/files.h"
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include <array>
 #include <climits>
 #include <cstdio>
 #include <cstdlib>
+#include <fstream>
+#include <libgen.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <dirent.h>
+#include <vector>
 
-namespace cvd {
+#include "common/libs/fs/shared_fd.h"
+
+namespace cuttlefish {
 
 bool FileExists(const std::string& path) {
   struct stat st;
@@ -37,6 +43,19 @@
   return FileSize(path) > 0;
 }
 
+std::vector<std::string> DirectoryContents(const std::string& path) {
+  std::vector<std::string> ret;
+  std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(path.c_str()), closedir);
+  CHECK(dir != nullptr) << "Could not read from dir \"" << path << "\"";
+  if (dir) {
+    struct dirent *ent;
+    while ((ent = readdir(dir.get()))) {
+      ret.push_back(ent->d_name);
+    }
+  }
+  return ret;
+}
+
 bool DirectoryExists(const std::string& path) {
   struct stat st;
   if (stat(path.c_str(), &st) == -1) {
@@ -48,6 +67,27 @@
   return true;
 }
 
+bool IsDirectoryEmpty(const std::string& path) {
+  auto direc = ::opendir(path.c_str());
+  if (!direc) {
+    LOG(ERROR) << "IsDirectoryEmpty test failed with " << path
+               << " as it failed to be open" << std::endl;
+    return false;
+  }
+
+  decltype(::readdir(direc)) sub = nullptr;
+  int cnt {0};
+  while ( (sub = ::readdir(direc)) ) {
+    cnt++;
+    if (cnt > 2) {
+    LOG(ERROR) << "IsDirectoryEmpty test failed with " << path
+               << " as it exists but not empty" << std::endl;
+      return false;
+    }
+  }
+  return true;
+}
+
 std::string AbsolutePath(const std::string& path) {
   if (path.empty()) {
     return {};
@@ -55,6 +95,10 @@
   if (path[0] == '/') {
     return path;
   }
+  if (path[0] == '~') {
+    LOG(WARNING) << "Tilde expansion in path " << path <<" is not supported";
+    return {};
+  }
 
   std::array<char, PATH_MAX> buffer{};
   if (!realpath(".", buffer.data())) {
@@ -83,11 +127,33 @@
   return std::chrono::system_clock::time_point(seconds);
 }
 
+bool RenameFile(const std::string& old_name, const std::string& new_name) {
+  LOG(DEBUG) << "Renaming " << old_name << " to " << new_name;
+  if(rename(old_name.c_str(), new_name.c_str())) {
+    LOG(ERROR) << "File rename failed due to " << strerror(errno);
+    return false;
+  }
+
+  return true;
+}
+
 bool RemoveFile(const std::string& file) {
-  LOG(INFO) << "Removing " << file;
+  LOG(DEBUG) << "Removing " << file;
   return remove(file.c_str()) == 0;
 }
 
+
+std::string ReadFile(const std::string& file) {
+  std::string contents;
+  std::ifstream in(file, std::ios::in | std::ios::binary);
+  in.seekg(0, std::ios::end);
+  contents.resize(in.tellg());
+  in.seekg(0, std::ios::beg);
+  in.read(&contents[0], contents.size());
+  in.close();
+  return(contents);
+}
+
 std::string CurrentDirectory() {
   char* path = getcwd(nullptr, 0);
   std::string ret(path);
@@ -95,4 +161,65 @@
   return ret;
 }
 
-}  // namespace cvd
+FileSizes SparseFileSizes(const std::string& path) {
+  auto fd = SharedFD::Open(path, O_RDONLY);
+  if (!fd->IsOpen()) {
+    LOG(ERROR) << "Could not open \"" << path << "\": " << fd->StrError();
+    return {};
+  }
+  off_t farthest_seek = fd->LSeek(0, SEEK_END);
+  LOG(VERBOSE) << "Farthest seek: " << farthest_seek;
+  if (farthest_seek == -1) {
+    LOG(ERROR) << "Could not lseek in \"" << path << "\": " << fd->StrError();
+    return {};
+  }
+  off_t data_bytes = 0;
+  off_t offset = 0;
+  while (offset < farthest_seek) {
+    off_t new_offset = fd->LSeek(offset, SEEK_HOLE);
+    if (new_offset == -1) {
+      // ENXIO is returned when there are no more blocks of this type coming.
+      if (fd->GetErrno() == ENXIO) {
+        break;
+      } else {
+        LOG(ERROR) << "Could not lseek in \"" << path << "\": " << fd->StrError();
+        return {};
+      }
+    } else {
+      data_bytes += new_offset - offset;
+      offset = new_offset;
+    }
+    if (offset >= farthest_seek) {
+      break;
+    }
+    new_offset = fd->LSeek(offset, SEEK_DATA);
+    if (new_offset == -1) {
+      // ENXIO is returned when there are no more blocks of this type coming.
+      if (fd->GetErrno() == ENXIO) {
+        break;
+      } else {
+        LOG(ERROR) << "Could not lseek in \"" << path << "\": " << fd->StrError();
+        return {};
+      }
+    } else {
+      offset = new_offset;
+    }
+  }
+  return (FileSizes) { .sparse_size = farthest_seek, .disk_size = data_bytes };
+}
+
+std::string cpp_basename(const std::string& str) {
+  char* copy = strdup(str.c_str()); // basename may modify its argument
+  std::string ret(basename(copy));
+  free(copy);
+  return ret;
+}
+
+std::string cpp_dirname(const std::string& str) {
+  char* copy = strdup(str.c_str()); // dirname may modify its argument
+  std::string ret(dirname(copy));
+  free(copy);
+  return ret;
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/utils/files.h b/common/libs/utils/files.h
index d42edc5..ff1c8d3 100644
--- a/common/libs/utils/files.h
+++ b/common/libs/utils/files.h
@@ -20,13 +20,19 @@
 #include <chrono>
 #include <string>
 
-namespace cvd {
+namespace cuttlefish {
 bool FileExists(const std::string& path);
 bool FileHasContent(const std::string& path);
+std::vector<std::string> DirectoryContents(const std::string& path);
 bool DirectoryExists(const std::string& path);
+bool IsDirectoryEmpty(const std::string& path);
 off_t FileSize(const std::string& path);
 bool RemoveFile(const std::string& file);
+bool RenameFile(const std::string& old_name, const std::string& new_name);
+std::string ReadFile(const std::string& file);
 std::chrono::system_clock::time_point FileModificationTime(const std::string& path);
+std::string cpp_dirname(const std::string& str);
+std::string cpp_basename(const std::string& str);
 
 // The returned value may contain .. or . if these are present in the path
 // argument.
@@ -34,4 +40,10 @@
 std::string AbsolutePath(const std::string& path);
 
 std::string CurrentDirectory();
-}  // namespace cvd
+
+struct FileSizes {
+  off_t sparse_size;
+  off_t disk_size;
+};
+FileSizes SparseFileSizes(const std::string& path);
+}  // namespace cuttlefish
diff --git a/common/libs/utils/network.cpp b/common/libs/utils/network.cpp
index 5b67c8e..d1f5f59 100644
--- a/common/libs/utils/network.cpp
+++ b/common/libs/utils/network.cpp
@@ -16,22 +16,28 @@
 
 #include "common/libs/utils/network.h"
 
+#include <arpa/inet.h>
 #include <linux/if.h>
 #include <linux/if_tun.h>
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/ether.h>
 #include <string.h>
 
 #include <android-base/strings.h>
-#include "common/libs/glog/logging.h"
+#include "android-base/logging.h"
 
+#include "common/libs/fs/shared_buf.h"
 #include "common/libs/utils/environment.h"
 #include "common/libs/utils/subprocess.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace {
 
 static std::string DefaultHostArtifactsPath(const std::string& file_name) {
-  return (cvd::StringFromEnv("ANDROID_HOST_OUT",
-                             cvd::StringFromEnv("HOME", ".")) +
+  return (StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
           "/") +
          file_name;
 }
@@ -50,6 +56,35 @@
 // u16 num_buffers;
 // };
 static constexpr int SIZE_OF_VIRTIO_NET_HDR_V1 = 12;
+
+bool ParseAddress(const std::string& address, const std::string& separator,
+                  const std::size_t expected_size, int base, std::uint8_t* out) {
+  auto components = android::base::Split(address, separator);
+  if (components.size() != expected_size) {
+    LOG(ERROR) << "Address \"" << address << "\" had wrong number of parts. "
+               << "Had " << components.size() << ", expected " << expected_size;
+    return false;
+  }
+  for (int i = 0; i < expected_size; i++) {
+    auto out_part = std::stoi(components[i], nullptr, base);
+    if (out_part < 0 || out_part > 255) {
+      LOG(ERROR) << "Address part " << i << " (" << out_part
+                 << "): outside range [0,255]";
+      return false;
+    }
+    out[i] = (std::uint8_t) out_part;
+  }
+  return true;
+}
+
+bool ParseMacAddress(const std::string& address, std::uint8_t mac[6]) {
+  return ParseAddress(address, ":", 6, 16, mac);
+}
+
+bool ParseIpAddress(const std::string& address, std::uint8_t ip[4]) {
+  return ParseAddress(address, ".", 4, 10, ip);
+}
+
 }  // namespace
 
 SharedFD OpenTapInterface(const std::string& interface_name) {
@@ -61,16 +96,16 @@
     return tap_fd;
   }
 
-  if (cvd::HostArch() == "aarch64") {
+  if (HostArch() == Arch::Arm64) {
     auto tapsetiff_path = DefaultHostArtifactsPath("bin/tapsetiff");
-    cvd::Command cmd(tapsetiff_path);
+    Command cmd(tapsetiff_path);
     cmd.AddParameter(tap_fd);
     cmd.AddParameter(interface_name.c_str());
     int ret = cmd.Start().Wait();
     if (ret != 0) {
       LOG(ERROR) << "Unable to run tapsetiff.py. Exited with status " << ret;
       tap_fd->Close();
-      return cvd::SharedFD();
+      return SharedFD();
     }
   } else {
     struct ifreq ifr;
@@ -83,7 +118,7 @@
       LOG(ERROR) << "Unable to connect to " << interface_name
                  << " tap interface: " << tap_fd->StrError();
       tap_fd->Close();
-      return cvd::SharedFD();
+      return SharedFD();
     }
 
     // The interface's configuration may have been modified or just not set
@@ -120,4 +155,159 @@
   }
   return tap_interfaces;
 }
-}  // namespace cvd
+
+std::vector<DnsmasqDhcp4Lease> ParseDnsmasqLeases(SharedFD lease_file) {
+  std::string lease_file_content;
+  if (ReadAll(lease_file, &lease_file_content) < 0) {
+    LOG(ERROR) << "Could not read lease_file: \"" << lease_file->StrError()
+               << "\". This may result in difficulty connecting to guest wifi.";
+    return {};
+  }
+  std::vector<DnsmasqDhcp4Lease> leases;
+  auto lease_file_lines = android::base::Split(lease_file_content, "\n");
+  for (const auto& line : lease_file_lines) {
+    if (line == "") {
+      continue;
+    }
+    auto line_elements = android::base::Split(line, " ");
+    if (line_elements.size() != 5) {
+      LOG(WARNING) << "Could not parse lease line: \"" << line << "\"\n";
+      continue;
+    }
+    DnsmasqDhcp4Lease lease;
+    lease.expiry = std::stoll(line_elements[0]);
+    if (!ParseMacAddress(line_elements[1], &lease.mac_address[0])) {
+      LOG(WARNING) << "Could not parse MAC address: \'" << line_elements[1]
+                   << "\"";
+      continue;
+    }
+    if (!ParseIpAddress(line_elements[2], &lease.ip_address[0])) {
+      LOG(WARNING) << "Could not parse IP address: " << line_elements[2]
+                   << "\"";
+    }
+    lease.hostname = line_elements[3];
+    lease.client_id = line_elements[4];
+    leases.push_back(lease);
+  }
+  return leases;
+}
+
+std::ostream& operator<<(std::ostream& out, const DnsmasqDhcp4Lease& lease) {
+  out << "DnsmasqDhcp4Lease(lease_time = \"" << std::dec << lease.expiry
+      << ", mac_address = \"" << std::hex;
+  for (int i = 0; i < 5; i++) {
+    out << (int) lease.mac_address[i] << ":";
+  }
+  out << (int) lease.mac_address[5] << "\", ip_address = \"" << std::dec;
+  for (int i = 0; i < 3; i++) {
+    out << (int) lease.ip_address[i] << ".";
+  }
+  return out << (int) lease.ip_address[3] << "\", hostname = \""
+             << lease.hostname << "\", client_id = \"" << lease.client_id
+             << "\")";
+}
+
+struct __attribute__((packed)) Dhcp4MessageTypeOption {
+  std::uint8_t code;
+  std::uint8_t len;
+  std::uint8_t message_type;
+};
+
+struct __attribute__((packed)) Dhcp4ServerIdentifier {
+  std::uint8_t code;
+  std::uint8_t len;
+  std::uint8_t server_ip[4];
+};
+
+struct __attribute__((packed)) Dhcp4ReleaseMessage {
+  std::uint8_t op;
+  std::uint8_t htype;
+  std::uint8_t hlen;
+  std::uint8_t hops;
+  __be32 xid;
+  __be16 secs;
+  __be16 flags;
+  std::uint8_t client_ip[4];
+  std::uint8_t assigned_ip[4];
+  std::uint8_t server_ip[4];
+  std::uint8_t gateway_ip[4];
+  std::uint8_t client_harware_address[16];
+  std::uint8_t server_name[64];
+  std::uint8_t boot_filename[128];
+  std::uint8_t magic_cookie[4];
+  Dhcp4MessageTypeOption message_type;
+  Dhcp4ServerIdentifier server_identifier;
+  std::uint8_t end_code;
+};
+
+struct __attribute__((packed)) CompleteReleaseFrame {
+  std::uint8_t vnet[SIZE_OF_VIRTIO_NET_HDR_V1];
+  ether_header eth;
+  iphdr ip;
+  udphdr udp;
+  Dhcp4ReleaseMessage dhcp;
+};
+
+static std::uint16_t ip_checksum(std::uint16_t *buf, std::size_t size) {
+  std::uint32_t sum = 0;
+  for (std::size_t i = 0; i < size; i++) {
+    sum += buf[i];
+  }
+  sum = (sum >> 16) + (sum & 0xFFFF);
+  sum += sum >> 16;
+  return (std::uint16_t) ~sum;
+}
+
+bool ReleaseDhcp4(SharedFD tap, const std::uint8_t mac_address[6],
+                  const std::uint8_t ip_address[4],
+                  const std::uint8_t dhcp_server_ip[4]) {
+  CompleteReleaseFrame frame = {};
+  *reinterpret_cast<std::uint16_t*>(&frame.vnet[2]) = // hdr_len, little-endian
+      htole16(sizeof(ether_header) + sizeof(iphdr) + sizeof(udphdr));
+
+  memcpy(frame.eth.ether_shost, mac_address, 6);
+  memset(frame.eth.ether_dhost, 255, 6); // Broadcast
+  frame.eth.ether_type = htobe16(ETH_P_IP);
+
+  frame.ip.ihl = 5;
+  frame.ip.version = 4;
+  frame.ip.id = 0;
+  frame.ip.ttl = 64; // hops
+  frame.ip.protocol = 17; // UDP
+  memcpy((std::uint8_t*) &frame.ip.saddr, ip_address, 4);
+  frame.ip.daddr = *(std::uint32_t*) dhcp_server_ip;
+  frame.ip.tot_len = htobe16(sizeof(frame.ip) + sizeof(frame.udp)
+                             + sizeof(frame.dhcp));
+  iphdr ip_copy = frame.ip; // original, it's in a packed struct
+  frame.ip.check = ip_checksum((unsigned short*) &ip_copy,
+                               sizeof(ip_copy) / sizeof(short));
+
+  frame.udp.source = htobe16(68);
+  frame.udp.dest = htobe16(67);
+  frame.udp.len = htobe16(sizeof(frame.udp) + sizeof(frame.dhcp));
+
+  frame.dhcp.op = 1; /* bootrequest */
+  frame.dhcp.htype = 1; // Ethernet
+  frame.dhcp.hlen = 6; /* mac address length */
+  frame.dhcp.xid = rand();
+  frame.dhcp.secs = htobe16(3);
+  frame.dhcp.flags = 0;
+  memcpy(frame.dhcp.client_ip, ip_address, 4);
+  memcpy(frame.dhcp.client_harware_address, mac_address, 6);
+  std::uint8_t magic_cookie[4] = {99, 130, 83, 99};
+  memcpy(frame.dhcp.magic_cookie, magic_cookie, sizeof(magic_cookie));
+  frame.dhcp.message_type = { .code = 53, .len = 1, .message_type = 7 };
+  frame.dhcp.server_identifier.code = 54;
+  frame.dhcp.server_identifier.len = 4;
+  memcpy(frame.dhcp.server_identifier.server_ip, dhcp_server_ip, 4);
+  frame.dhcp.end_code = 255;
+
+  if (tap->Write((void*) &frame, sizeof(frame)) != sizeof(frame)) {
+    LOG(ERROR) << "Could not write dhcprelease frame: \"" << tap->StrError()
+               << "\". Connecting to wifi will likely not work.";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/utils/network.h b/common/libs/utils/network.h
index 221d88e..64b562e 100644
--- a/common/libs/utils/network.h
+++ b/common/libs/utils/network.h
@@ -15,12 +15,14 @@
  */
 #pragma once
 
+#include <cstddef>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "common/libs/fs/shared_fd.h"
 
-namespace cvd {
+namespace cuttlefish {
 // Creates, or connects to if it already exists, a tap network interface. The
 // user needs CAP_NET_ADMIN to create such interfaces or be the owner to connect
 // to one.
@@ -28,4 +30,23 @@
 
 // Returns a list of TAP devices that have open file descriptors
 std::set<std::string> TapInterfacesInUse();
+
+struct DnsmasqDhcp4Lease {
+  std::uint64_t expiry;
+  std::uint8_t mac_address[6];
+  std::uint8_t ip_address[4];
+  std::string hostname;
+  std::string client_id;
+};
+
+// Parses a dnsmasq lease file
+std::vector<DnsmasqDhcp4Lease> ParseDnsmasqLeases(SharedFD lease_file);
+
+std::ostream& operator<<(std::ostream&, const DnsmasqDhcp4Lease&);
+
+// Sends a DHCPRELEASE message over the socket;
+bool ReleaseDhcp4(SharedFD tap, const std::uint8_t mac_address[6],
+                  const std::uint8_t ip_address[4],
+                  const std::uint8_t dhcp_server_ip[4]);
+
 }
diff --git a/common/libs/utils/size_utils.cpp b/common/libs/utils/size_utils.cpp
index 0f7ed3c..9f25445 100644
--- a/common/libs/utils/size_utils.cpp
+++ b/common/libs/utils/size_utils.cpp
@@ -18,11 +18,11 @@
 
 #include <unistd.h>
 
-namespace cvd {
+namespace cuttlefish {
 
-uint32_t AlignToPowerOf2(uint32_t val, uint8_t align_log) {
-  uint32_t align = 1 << align_log;
+uint64_t AlignToPowerOf2(uint64_t val, uint8_t align_log) {
+  uint64_t align = 1ULL << align_log;
   return ((val + (align - 1)) / align) * align;
 }
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/utils/size_utils.h b/common/libs/utils/size_utils.h
index 42044ec..625cdd8 100644
--- a/common/libs/utils/size_utils.h
+++ b/common/libs/utils/size_utils.h
@@ -17,9 +17,15 @@
 
 #include <stdint.h>
 
-namespace cvd {
+namespace cuttlefish {
+
+// Keep the full disk size a multiple of 64k, for crosvm's virtio_blk driver
+constexpr int DISK_SIZE_SHIFT = 16;
+
+// Keep all partitions 4k aligned, for host performance reasons
+constexpr int PARTITION_SIZE_SHIFT = 12;
 
 // Returns the smallest multiple of 2^align_log greater than or equal to val.
-uint32_t AlignToPowerOf2(uint32_t val, uint8_t align_log);
+uint64_t AlignToPowerOf2(uint64_t val, uint8_t align_log);
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/utils/subprocess.cpp b/common/libs/utils/subprocess.cpp
index 23cce91..7c05219 100644
--- a/common/libs/utils/subprocess.cpp
+++ b/common/libs/utils/subprocess.cpp
@@ -28,18 +28,19 @@
 #include <set>
 #include <thread>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/fs/shared_buf.h"
 
+namespace cuttlefish {
 namespace {
 
 // If a redirected-to file descriptor was already closed, it's possible that
 // some inherited file descriptor duped to this file descriptor and the redirect
 // would override that. This function makes sure that doesn't happen.
 bool validate_redirects(
-    const std::map<cvd::Subprocess::StdIOChannel, int>& redirects,
-    const std::map<cvd::SharedFD, int>& inherited_fds) {
+    const std::map<Subprocess::StdIOChannel, int>& redirects,
+    const std::map<SharedFD, int>& inherited_fds) {
   // Add the redirected IO channels to a set as integers. This allows converting
   // the enum values into integers instead of the other way around.
   std::set<int> int_redirects;
@@ -57,8 +58,7 @@
   return true;
 }
 
-void do_redirects(
-    const std::map<cvd::Subprocess::StdIOChannel, int>& redirects) {
+void do_redirects(const std::map<Subprocess::StdIOChannel, int>& redirects) {
   for (const auto& entry : redirects) {
     auto std_channel = static_cast<int>(entry.first);
     auto fd = entry.second;
@@ -74,29 +74,30 @@
   ret.push_back(NULL);
   return ret;
 }
+
+void UnsetEnvironment(const std::unordered_set<std::string>& unenv) {
+  for (auto it = unenv.cbegin(); it != unenv.cend(); ++it) {
+    unsetenv(it->c_str());
+  }
+}
 }  // namespace
-namespace cvd {
 
 Subprocess::Subprocess(Subprocess&& subprocess)
     : pid_(subprocess.pid_),
       started_(subprocess.started_),
-      control_socket_(subprocess.control_socket_),
       stopper_(subprocess.stopper_) {
   // Make sure the moved object no longer controls this subprocess
   subprocess.pid_ = -1;
   subprocess.started_ = false;
-  subprocess.control_socket_ = SharedFD();
 }
 
 Subprocess& Subprocess::operator=(Subprocess&& other) {
   pid_ = other.pid_;
   started_ = other.started_;
-  control_socket_ = other.control_socket_;
   stopper_ = other.stopper_;
 
   other.pid_ = -1;
   other.started_ = false;
-  other.control_socket_ = SharedFD();
   return *this;
 }
 
@@ -162,14 +163,6 @@
   }
   return true;
 }
-Command::ParameterBuilder::~ParameterBuilder() { Build(); }
-void Command::ParameterBuilder::Build() {
-  auto param = stream_.str();
-  stream_ = std::stringstream();
-  if (param.size()) {
-    cmd_->AddParameter(param);
-  }
-}
 
 Command::~Command() {
   // Close all inherited file descriptors
@@ -198,8 +191,8 @@
   return true;
 }
 
-bool Command::RedirectStdIO(cvd::Subprocess::StdIOChannel channel,
-                            cvd::SharedFD shared_fd) {
+bool Command::RedirectStdIO(Subprocess::StdIOChannel channel,
+                            SharedFD shared_fd) {
   if (!shared_fd->IsOpen()) {
     return false;
   }
@@ -219,25 +212,11 @@
 bool Command::RedirectStdIO(Subprocess::StdIOChannel subprocess_channel,
                             Subprocess::StdIOChannel parent_channel) {
   return RedirectStdIO(subprocess_channel,
-                       cvd::SharedFD::Dup(static_cast<int>(parent_channel)));
+                       SharedFD::Dup(static_cast<int>(parent_channel)));
 }
 
 Subprocess Command::Start(SubprocessOptions options) const {
   auto cmd = ToCharPointers(command_);
-  // The parent socket will get closed on the child on the call to exec, the
-  // child socket will be closed on the parent when this function returns and no
-  // references to the fd are left
-  SharedFD parent_socket, child_socket;
-  if (options.WithControlSocket()) {
-    if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &parent_socket,
-                              &child_socket)) {
-      LOG(ERROR) << "Unable to create control socket pair: " << strerror(errno);
-      return Subprocess(-1, {});
-    }
-    // Remove FD_CLOEXEC from the child socket, ensure the parent has it
-    child_socket->Fcntl(F_SETFD, 0);
-    parent_socket->Fcntl(F_SETFD, FD_CLOEXEC);
-  }
 
   if (!validate_redirects(redirects_, inherited_fds_)) {
     return Subprocess(-1, {});
@@ -268,10 +247,11 @@
     // the environment of the child process. To force an empty emvironment for
     // the child process pass the address of a pointer to NULL
     if (use_parent_env_) {
-      rval = execv(cmd[0], const_cast<char* const*>(cmd.data()));
+      UnsetEnvironment(unenv_);
+      rval = execvp(cmd[0], const_cast<char* const*>(cmd.data()));
     } else {
       auto envp = ToCharPointers(env_);
-      rval = execve(cmd[0], const_cast<char* const*>(cmd.data()),
+      rval = execvpe(cmd[0], const_cast<char* const*>(cmd.data()),
                     const_cast<char* const*>(envp.data()));
     }
     // No need for an if: if exec worked it wouldn't have returned
@@ -282,14 +262,18 @@
   if (pid == -1) {
     LOG(ERROR) << "fork failed (" << strerror(errno) << ")";
   }
-  if (options.Verbose()) {
-    LOG(INFO) << "Started (pid: " << pid << "): " << cmd[0];
-    int i = 1;
-    while (cmd[i]) {
-      LOG(INFO) << cmd[i++];
+  if (options.Verbose()) { // "more verbose", and LOG(DEBUG) > LOG(VERBOSE)
+    LOG(DEBUG) << "Started (pid: " << pid << "): " << cmd[0];
+    for (int i = 1; cmd[i]; i++) {
+      LOG(DEBUG) << cmd[i];
+    }
+  } else {
+    LOG(VERBOSE) << "Started (pid: " << pid << "): " << cmd[0];
+    for (int i = 1; cmd[i]; i++) {
+      LOG(VERBOSE) << cmd[i];
     }
   }
-  return Subprocess(pid, parent_socket, subprocess_stopper_);
+  return Subprocess(pid, subprocess_stopper_);
 }
 
 // A class that waits for threads to exit in its destructor.
@@ -311,7 +295,7 @@
                         SubprocessOptions options) {
   /*
    * The order of these declarations is necessary for safety. If the function
-   * returns at any point, the cvd::Command will be destroyed first, closing all
+   * returns at any point, the Command will be destroyed first, closing all
    * of its references to SharedFDs. This will cause the thread internals to fail
    * their reads or writes. The ThreadJoiner then waits for the threads to
    * complete, as running the destructor of an active std::thread crashes the
@@ -322,22 +306,22 @@
    */
   std::thread stdin_thread, stdout_thread, stderr_thread;
   ThreadJoiner thread_joiner({&stdin_thread, &stdout_thread, &stderr_thread});
-  cvd::Command cmd = std::move(cmd_tmp);
+  Command cmd = std::move(cmd_tmp);
   bool io_error = false;
   if (stdin != nullptr) {
-    cvd::SharedFD pipe_read, pipe_write;
-    if (!cvd::SharedFD::Pipe(&pipe_read, &pipe_write)) {
+    SharedFD pipe_read, pipe_write;
+    if (!SharedFD::Pipe(&pipe_read, &pipe_write)) {
       LOG(ERROR) << "Could not create a pipe to write the stdin of \""
                 << cmd.GetShortName() << "\"";
       return -1;
     }
-    if (!cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, pipe_read)) {
+    if (!cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, pipe_read)) {
       LOG(ERROR) << "Could not set stdout of \"" << cmd.GetShortName()
                 << "\", was already set.";
       return -1;
     }
     stdin_thread = std::thread([pipe_write, stdin, &io_error]() {
-      int written = cvd::WriteAll(pipe_write, *stdin);
+      int written = WriteAll(pipe_write, *stdin);
       if (written < 0) {
         io_error = true;
         LOG(ERROR) << "Error in writing stdin to process";
@@ -345,19 +329,19 @@
     });
   }
   if (stdout != nullptr) {
-    cvd::SharedFD pipe_read, pipe_write;
-    if (!cvd::SharedFD::Pipe(&pipe_read, &pipe_write)) {
+    SharedFD pipe_read, pipe_write;
+    if (!SharedFD::Pipe(&pipe_read, &pipe_write)) {
       LOG(ERROR) << "Could not create a pipe to read the stdout of \""
                 << cmd.GetShortName() << "\"";
       return -1;
     }
-    if (!cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, pipe_write)) {
+    if (!cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, pipe_write)) {
       LOG(ERROR) << "Could not set stdout of \"" << cmd.GetShortName()
                 << "\", was already set.";
       return -1;
     }
     stdout_thread = std::thread([pipe_read, stdout, &io_error]() {
-      int read = cvd::ReadAll(pipe_read, stdout);
+      int read = ReadAll(pipe_read, stdout);
       if (read < 0) {
         io_error = true;
         LOG(ERROR) << "Error in reading stdout from process";
@@ -365,19 +349,19 @@
     });
   }
   if (stderr != nullptr) {
-    cvd::SharedFD pipe_read, pipe_write;
-    if (!cvd::SharedFD::Pipe(&pipe_read, &pipe_write)) {
+    SharedFD pipe_read, pipe_write;
+    if (!SharedFD::Pipe(&pipe_read, &pipe_write)) {
       LOG(ERROR) << "Could not create a pipe to read the stderr of \""
                 << cmd.GetShortName() << "\"";
       return -1;
     }
-    if (!cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdErr, pipe_write)) {
+    if (!cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, pipe_write)) {
       LOG(ERROR) << "Could not set stderr of \"" << cmd.GetShortName()
                 << "\", was already set.";
       return -1;
     }
     stderr_thread = std::thread([pipe_read, stderr, &io_error]() {
-      int read = cvd::ReadAll(pipe_read, stderr);
+      int read = ReadAll(pipe_read, stderr);
       if (read < 0) {
         io_error = true;
         LOG(ERROR) << "Error in reading stderr from process";
@@ -389,10 +373,11 @@
   if (!subprocess.Started()) {
     return -1;
   }
+  auto cmd_short_name = cmd.GetShortName();
   {
     // Force the destructor to run by moving it into a smaller scope.
     // This is necessary to close the write end of the pipe.
-    cvd::Command forceDelete = std::move(cmd);
+    Command forceDelete = std::move(cmd);
   }
   int wstatus;
   subprocess.Wait(&wstatus, 0);
@@ -404,7 +389,7 @@
     auto join_threads = std::move(thread_joiner);
   }
   if (io_error) {
-    LOG(ERROR) << "IO error communicating with " << cmd.GetShortName();
+    LOG(ERROR) << "IO error communicating with " << cmd_short_name;
     return -1;
   }
   return WEXITSTATUS(wstatus);
@@ -435,4 +420,4 @@
   return subprocess.Wait();
 }
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/utils/subprocess.h b/common/libs/utils/subprocess.h
index 633c9f5..777a026 100644
--- a/common/libs/utils/subprocess.h
+++ b/common/libs/utils/subprocess.h
@@ -21,11 +21,14 @@
 #include <map>
 #include <sstream>
 #include <string>
+#include <unordered_set>
 #include <vector>
 
+#include <android-base/logging.h>
+
 #include <common/libs/fs/shared_fd.h>
 
-namespace cvd {
+namespace cuttlefish {
 class Command;
 class Subprocess;
 class SubprocessOptions;
@@ -43,10 +46,9 @@
     kStdErr = 2,
   };
 
-  Subprocess(pid_t pid, SharedFD control, SubprocessStopper stopper = KillSubprocess)
+  Subprocess(pid_t pid, SubprocessStopper stopper = KillSubprocess)
       : pid_(pid),
         started_(pid > 0),
-        control_socket_(control),
         stopper_(stopper) {}
   // The default implementation won't do because we need to reset the pid of the
   // moved object.
@@ -62,7 +64,6 @@
   // fork() succeeded or not, it says nothing about exec or successful
   // completion of the command, that's what Wait is for.
   bool Started() const { return started_; }
-  SharedFD control_socket() { return control_socket_; }
   pid_t pid() const { return pid_; }
   bool Stop() { return stopper_(this); }
 
@@ -74,24 +75,16 @@
   Subprocess& operator=(const Subprocess&) = delete;
   pid_t pid_ = -1;
   bool started_ = false;
-  SharedFD control_socket_;
   SubprocessStopper stopper_;
 };
 
 class SubprocessOptions {
-  bool with_control_socket_;
   bool verbose_;
   bool exit_with_parent_;
   bool in_group_;
 public:
-  SubprocessOptions() : with_control_socket_(false), verbose_(true),
-                        exit_with_parent_(true) {}
+  SubprocessOptions() : verbose_(true), exit_with_parent_(true) {}
 
-  // If with_control_socket is true the Subprocess instance will have a SharedFD
-  // that enables communication with the child process.
-  void WithControlSocket(bool with_control_socket) {
-    with_control_socket_ = with_control_socket;
-  }
   void Verbose(bool verbose) {
     verbose_ = verbose;
   }
@@ -103,7 +96,6 @@
     in_group_ = in_group;
   }
 
-  bool WithControlSocket() const { return with_control_socket_; }
   bool Verbose() const { return verbose_; }
   bool ExitWithParent() const { return exit_with_parent_; }
   bool InGroup() const { return in_group_; }
@@ -128,25 +120,6 @@
   }
 
  public:
-  class ParameterBuilder {
-   public:
-    ParameterBuilder(Command* cmd) : cmd_(cmd){};
-    ParameterBuilder(ParameterBuilder&& builder) = default;
-    ~ParameterBuilder();
-
-    template <typename T>
-    ParameterBuilder& operator<<(T t) {
-      cmd_->BuildParameter(&stream_, t);
-      return *this;
-    }
-
-    void Build();
-
-   private:
-    cvd::Command* cmd_;
-    std::stringstream stream_;
-  };
-
   // Constructs a command object from the path to an executable binary and an
   // optional subprocess stopper. When not provided, stopper defaults to sending
   // SIGKILL to the subprocess.
@@ -169,6 +142,14 @@
     use_parent_env_ = false;
     env_ = env;
   }
+
+  // Specify environment variables to be unset from the parent's environment
+  // for the subprocesses to be started.
+  void UnsetFromEnvironment(const std::vector<std::string>& env) {
+    use_parent_env_ = true;
+    std::copy(env.cbegin(), env.cend(), std::inserter(unenv_, unenv_.end()));
+  }
+
   // Adds a single parameter to the command. All arguments are concatenated into
   // a single string to form a parameter. If one of those arguments is a
   // SharedFD a duplicate of it will be used and won't be closed until the
@@ -183,11 +164,24 @@
     }
     return false;
   }
-
-  ParameterBuilder GetParameterBuilder() { return ParameterBuilder(this); }
+  // Similar to AddParameter, except the args are appended to the last (most
+  // recently-added) parameter in the command.
+  template <typename... Args>
+  bool AppendToLastParameter(Args... args) {
+    if (command_.empty()) {
+      LOG(ERROR) << "There is no parameter to append to.";
+      return false;
+    }
+    std::stringstream ss;
+    if (BuildParameter(&ss, args...)) {
+      command_[command_.size()-1] += ss.str();
+      return true;
+    }
+    return false;
+  }
 
   // Redirects the standard IO of the command.
-  bool RedirectStdIO(Subprocess::StdIOChannel channel, cvd::SharedFD shared_fd);
+  bool RedirectStdIO(Subprocess::StdIOChannel channel, SharedFD shared_fd);
   bool RedirectStdIO(Subprocess::StdIOChannel subprocess_channel,
                      Subprocess::StdIOChannel parent_channel);
 
@@ -203,15 +197,16 @@
 
  private:
   std::vector<std::string> command_;
-  std::map<cvd::SharedFD, int> inherited_fds_{};
+  std::map<SharedFD, int> inherited_fds_{};
   std::map<Subprocess::StdIOChannel, int> redirects_{};
   bool use_parent_env_ = true;
   std::vector<std::string> env_{};
+  std::unordered_set<std::string> unenv_{};
   SubprocessStopper subprocess_stopper_;
 };
 
 /*
- * Consumes a cvd::Command and runs it, optionally managing the stdio channels.
+ * Consumes a Command and runs it, optionally managing the stdio channels.
  *
  * If `stdin` is set, the subprocess stdin will be pipe providing its contents.
  * If `stdout` is set, the subprocess stdout will be captured and saved to it.
@@ -222,7 +217,7 @@
  * If some setup fails, `command` fails to start, or `command` exits due to a
  * signal, the return value will be negative.
  */
-int RunWithManagedStdio(cvd::Command&& command, const std::string* stdin,
+int RunWithManagedStdio(Command&& command, const std::string* stdin,
                         std::string* stdout, std::string* stderr,
                         SubprocessOptions options = SubprocessOptions());
 
@@ -234,4 +229,4 @@
             const std::vector<std::string>& env);
 int execute(const std::vector<std::string>& command);
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/common/libs/utils/tcp_socket.cpp b/common/libs/utils/tcp_socket.cpp
new file mode 100644
index 0000000..3b56725
--- /dev/null
+++ b/common/libs/utils/tcp_socket.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "common/libs/utils/tcp_socket.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <cerrno>
+
+#include <android-base/logging.h>
+
+namespace cuttlefish {
+
+ClientSocket::ClientSocket(int port)
+    : fd_(SharedFD::SocketLocalClient(port, SOCK_STREAM)) {}
+
+Message ClientSocket::RecvAny(std::size_t length) {
+  Message buf(length);
+  auto read_count = fd_->Read(buf.data(), buf.size());
+  if (read_count < 0) {
+    read_count = 0;
+  }
+  buf.resize(read_count);
+  return buf;
+}
+
+bool ClientSocket::closed() const {
+  std::lock_guard<std::mutex> guard(closed_lock_);
+  return other_side_closed_;
+}
+
+Message ClientSocket::Recv(std::size_t length) {
+  Message buf(length);
+  ssize_t total_read = 0;
+  while (total_read < static_cast<ssize_t>(length)) {
+    auto just_read = fd_->Read(&buf[total_read], buf.size() - total_read);
+    if (just_read <= 0) {
+      if (just_read < 0) {
+        LOG(ERROR) << "read() error: " << strerror(errno);
+      }
+      {
+        std::lock_guard<std::mutex> guard(closed_lock_);
+        other_side_closed_ = true;
+      }
+      return Message{};
+    }
+    total_read += just_read;
+  }
+  CHECK(total_read == static_cast<ssize_t>(length));
+  return buf;
+}
+
+ssize_t ClientSocket::SendNoSignal(const uint8_t* data, std::size_t size) {
+  std::lock_guard<std::mutex> lock(send_lock_);
+  ssize_t written{};
+  while (written < static_cast<ssize_t>(size)) {
+    if (!fd_->IsOpen()) {
+      LOG(ERROR) << "fd_ is closed";
+    }
+    auto just_written = fd_->Send(data + written, size - written, MSG_NOSIGNAL);
+    if (just_written <= 0) {
+      LOG(INFO) << "Couldn't write to client: " << strerror(errno);
+      {
+        std::lock_guard<std::mutex> guard(closed_lock_);
+        other_side_closed_ = true;
+      }
+      return just_written;
+    }
+    written += just_written;
+  }
+  return written;
+}
+
+ssize_t ClientSocket::SendNoSignal(const Message& message) {
+  return SendNoSignal(&message[0], message.size());
+}
+
+ServerSocket::ServerSocket(int port)
+    : fd_{SharedFD::SocketLocalServer(port, SOCK_STREAM)} {
+  if (!fd_->IsOpen()) {
+    LOG(FATAL) << "Couldn't open streaming server on port " << port;
+  }
+}
+
+ClientSocket ServerSocket::Accept() {
+  SharedFD client = SharedFD::Accept(*fd_);
+  if (!client->IsOpen()) {
+    LOG(FATAL) << "Error attemping to accept: " << strerror(errno);
+  }
+  return ClientSocket{client};
+}
+
+void AppendInNetworkByteOrder(Message* msg, const std::uint8_t b) {
+  msg->push_back(b);
+}
+
+void AppendInNetworkByteOrder(Message* msg, const std::uint16_t s) {
+  const std::uint16_t n = htons(s);
+  auto p = reinterpret_cast<const std::uint8_t*>(&n);
+  msg->insert(msg->end(), p, p + sizeof n);
+}
+
+void AppendInNetworkByteOrder(Message* msg, const std::uint32_t w) {
+  const std::uint32_t n = htonl(w);
+  auto p = reinterpret_cast<const std::uint8_t*>(&n);
+  msg->insert(msg->end(), p, p + sizeof n);
+}
+
+void AppendInNetworkByteOrder(Message* msg, const std::int32_t w) {
+  std::uint32_t u{};
+  std::memcpy(&u, &w, sizeof u);
+  AppendInNetworkByteOrder(msg, u);
+}
+
+void AppendInNetworkByteOrder(Message* msg, const std::string& str) {
+  msg->insert(msg->end(), str.begin(), str.end());
+}
+
+}
diff --git a/common/libs/utils/tcp_socket.h b/common/libs/utils/tcp_socket.h
new file mode 100644
index 0000000..292decd
--- /dev/null
+++ b/common/libs/utils/tcp_socket.h
@@ -0,0 +1,108 @@
+#pragma once
+
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "common/libs/fs/shared_fd.h"
+
+#include <unistd.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <mutex>
+#include <vector>
+
+namespace cuttlefish {
+using Message = std::vector<std::uint8_t>;
+
+class ServerSocket;
+
+// Recv and Send wait until all data has been received or sent.
+// Send is thread safe in this regard, Recv is not.
+class ClientSocket {
+ public:
+  ClientSocket(ClientSocket&& other) : fd_{other.fd_} {}
+
+  ClientSocket& operator=(ClientSocket&& other) {
+    fd_ = other.fd_;
+    return *this;
+  }
+
+  ClientSocket(int port);
+
+  ClientSocket(const ClientSocket&) = delete;
+  ClientSocket& operator=(const ClientSocket&) = delete;
+
+  Message Recv(std::size_t length);
+  // RecvAny will receive whatever is available.
+  // An empty message returned indicates error or close.
+  Message RecvAny(std::size_t length);
+  // Sends are called with MSG_NOSIGNAL to suppress SIGPIPE
+  ssize_t SendNoSignal(const std::uint8_t* data, std::size_t size);
+  ssize_t SendNoSignal(const Message& message);
+
+  template <std::size_t N>
+  ssize_t SendNoSignal(const std::uint8_t (&data)[N]) {
+    return SendNoSignal(data, N);
+  }
+
+  bool closed() const;
+
+ private:
+  friend ServerSocket;
+  explicit ClientSocket(SharedFD fd) : fd_(fd) {}
+
+  SharedFD fd_;
+  bool other_side_closed_{};
+  mutable std::mutex closed_lock_;
+  std::mutex send_lock_;
+};
+
+class ServerSocket {
+ public:
+  explicit ServerSocket(int port);
+
+  ServerSocket(const ServerSocket&) = delete;
+  ServerSocket& operator=(const ServerSocket&) = delete;
+
+  ClientSocket Accept();
+
+ private:
+  SharedFD fd_;
+};
+
+void AppendInNetworkByteOrder(Message* msg, const std::uint8_t b);
+void AppendInNetworkByteOrder(Message* msg, const std::uint16_t s);
+void AppendInNetworkByteOrder(Message* msg, const std::uint32_t w);
+void AppendInNetworkByteOrder(Message* msg, const std::int32_t w);
+void AppendInNetworkByteOrder(Message* msg, const std::string& str);
+
+inline void AppendToMessage(Message*) {}
+
+template <typename T, typename... Ts>
+void AppendToMessage(Message* msg, T v, Ts... vals) {
+  AppendInNetworkByteOrder(msg, v);
+  AppendToMessage(msg, vals...);
+}
+
+template <typename... Ts>
+Message CreateMessage(Ts... vals) {
+  Message m;
+  AppendToMessage(&m, vals...);
+  return m;
+}
+
+}  // namespace cuttlefish
diff --git a/common/libs/utils/tee_logging.cpp b/common/libs/utils/tee_logging.cpp
new file mode 100644
index 0000000..66b46c1
--- /dev/null
+++ b/common/libs/utils/tee_logging.cpp
@@ -0,0 +1,228 @@
+//
+// 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.
+
+#include "tee_logging.h"
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/threads.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/utils/environment.h"
+
+using android::base::GetThreadId;
+using android::base::FATAL;
+using android::base::LogSeverity;
+using android::base::StringPrintf;
+
+namespace cuttlefish {
+
+static LogSeverity GuessSeverity(
+    const std::string& env_var, LogSeverity default_value) {
+  using android::base::VERBOSE;
+  using android::base::DEBUG;
+  using android::base::INFO;
+  using android::base::WARNING;
+  using android::base::ERROR;
+  using android::base::FATAL_WITHOUT_ABORT;
+  using android::base::FATAL;
+  std::string env_value = StringFromEnv(env_var, "");
+  using android::base::EqualsIgnoreCase;
+  if (EqualsIgnoreCase(env_value, "VERBOSE")
+      || env_value == std::to_string((int) VERBOSE)) {
+    return VERBOSE;
+  } else if (EqualsIgnoreCase(env_value, "DEBUG")
+      || env_value == std::to_string((int) DEBUG)) {
+    return DEBUG;
+  } else if (EqualsIgnoreCase(env_value, "INFO")
+      || env_value == std::to_string((int) INFO)) {
+    return INFO;
+  } else if (EqualsIgnoreCase(env_value, "WARNING")
+      || env_value == std::to_string((int) WARNING)) {
+    return WARNING;
+  } else if (EqualsIgnoreCase(env_value, "ERROR")
+      || env_value == std::to_string((int) ERROR)) {
+    return ERROR;
+  } else if (EqualsIgnoreCase(env_value, "FATAL_WITHOUT_ABORT")
+      || env_value == std::to_string((int) FATAL_WITHOUT_ABORT)) {
+    return FATAL_WITHOUT_ABORT;
+  } else if (EqualsIgnoreCase(env_value, "FATAL")
+      || env_value == std::to_string((int) FATAL)) {
+    return FATAL;
+  } else {
+    return default_value;
+  }
+}
+
+LogSeverity ConsoleSeverity() {
+  return GuessSeverity("CF_CONSOLE_SEVERITY", android::base::INFO);
+}
+
+LogSeverity LogFileSeverity() {
+  return GuessSeverity("CF_FILE_SEVERITY", android::base::DEBUG);
+}
+
+TeeLogger::TeeLogger(const std::vector<SeverityTarget>& destinations)
+    : destinations_(destinations) {
+}
+
+// Copied from system/libbase/logging_splitters.h
+static std::pair<int, int> CountSizeAndNewLines(const char* message) {
+  int size = 0;
+  int new_lines = 0;
+  while (*message != '\0') {
+    size++;
+    if (*message == '\n') {
+      ++new_lines;
+    }
+    ++message;
+  }
+  return {size, new_lines};
+}
+
+// Copied from system/libbase/logging_splitters.h
+// This splits the message up line by line, by calling log_function with a pointer to the start of
+// each line and the size up to the newline character.  It sends size = -1 for the final line.
+template <typename F, typename... Args>
+static void SplitByLines(const char* msg, const F& log_function, Args&&... args) {
+  const char* newline = strchr(msg, '\n');
+  while (newline != nullptr) {
+    log_function(msg, newline - msg, args...);
+    msg = newline + 1;
+    newline = strchr(msg, '\n');
+  }
+
+  log_function(msg, -1, args...);
+}
+
+// Copied from system/libbase/logging_splitters.h
+// This adds the log header to each line of message and returns it as a string intended to be
+// written to stderr.
+static std::string StderrOutputGenerator(const struct tm& now, int pid, uint64_t tid,
+                                         LogSeverity severity, const char* tag, const char* file,
+                                         unsigned int line, const char* message) {
+  char timestamp[32];
+  strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
+
+  static const char log_characters[] = "VDIWEFF";
+  static_assert(arraysize(log_characters) - 1 == FATAL + 1,
+                "Mismatch in size of log_characters and values in LogSeverity");
+  char severity_char = log_characters[severity];
+  std::string line_prefix;
+  if (file != nullptr) {
+    line_prefix = StringPrintf("%s %c %s %5d %5" PRIu64 " %s:%u] ", tag ? tag : "nullptr",
+                               severity_char, timestamp, pid, tid, file, line);
+  } else {
+    line_prefix = StringPrintf("%s %c %s %5d %5" PRIu64 " ", tag ? tag : "nullptr", severity_char,
+                               timestamp, pid, tid);
+  }
+
+  auto [size, new_lines] = CountSizeAndNewLines(message);
+  std::string output_string;
+  output_string.reserve(size + new_lines * line_prefix.size() + 1);
+
+  auto concat_lines = [&](const char* message, int size) {
+    output_string.append(line_prefix);
+    if (size == -1) {
+      output_string.append(message);
+    } else {
+      output_string.append(message, size);
+    }
+    output_string.append("\n");
+  };
+  SplitByLines(message, concat_lines);
+  return output_string;
+}
+
+// TODO(schuffelen): Do something less primitive.
+static std::string StripColorCodes(const std::string& str) {
+  std::stringstream sstream;
+  bool in_color_code = false;
+  for (char c : str) {
+    if (c == '\033') {
+      in_color_code = true;
+    }
+    if (!in_color_code) {
+      sstream << c;
+    }
+    if (c == 'm') {
+      in_color_code = false;
+    }
+  }
+  return sstream.str();
+}
+
+void TeeLogger::operator()(
+    android::base::LogId,
+    android::base::LogSeverity severity,
+    const char* tag,
+    const char* file,
+    unsigned int line,
+    const char* message) {
+  for (const auto& destination : destinations_) {
+    std::string output_string;
+    if (destination.metadata_level == MetadataLevel::ONLY_MESSAGE) {
+      output_string = message + std::string("\n");
+    } else {
+      struct tm now;
+      time_t t = time(nullptr);
+      localtime_r(&t, &now);
+      output_string = StderrOutputGenerator(now, getpid(), GetThreadId(),
+                                            severity, tag, file, line, message);
+    }
+    if (severity >= destination.severity) {
+      if (destination.target->IsATTY()) {
+        WriteAll(destination.target, output_string);
+      } else {
+        WriteAll(destination.target, StripColorCodes(output_string));
+      }
+    }
+  }
+}
+
+static std::vector<SeverityTarget> SeverityTargetsForFiles(
+    const std::vector<std::string>& files) {
+  std::vector<SeverityTarget> log_severities;
+  for (const auto& file : files) {
+    auto log_file_fd =
+        SharedFD::Open(
+          file,
+          O_CREAT | O_WRONLY | O_APPEND,
+          S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+    if (!log_file_fd->IsOpen()) {
+      LOG(FATAL) << "Failed to create log file: " << log_file_fd->StrError();
+    }
+    log_severities.push_back(
+        SeverityTarget{LogFileSeverity(), log_file_fd, MetadataLevel::FULL});
+  }
+  return log_severities;
+}
+
+TeeLogger LogToFiles(const std::vector<std::string>& files) {
+  return TeeLogger(SeverityTargetsForFiles(files));
+}
+
+TeeLogger LogToStderrAndFiles(const std::vector<std::string>& files) {
+  std::vector<SeverityTarget> log_severities = SeverityTargetsForFiles(files);
+  log_severities.push_back(SeverityTarget{ConsoleSeverity(),
+                                          SharedFD::Dup(/* stderr */ 2),
+                                          MetadataLevel::ONLY_MESSAGE});
+  return TeeLogger(log_severities);
+}
+
+} // namespace cuttlefish
diff --git a/common/libs/utils/tee_logging.h b/common/libs/utils/tee_logging.h
new file mode 100644
index 0000000..6306e62
--- /dev/null
+++ b/common/libs/utils/tee_logging.h
@@ -0,0 +1,60 @@
+//
+// 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>
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include "common/libs/fs/shared_fd.h"
+
+namespace cuttlefish {
+
+android::base::LogSeverity ConsoleSeverity();
+android::base::LogSeverity LogFileSeverity();
+
+enum class MetadataLevel {
+  FULL,
+  ONLY_MESSAGE,
+};
+
+struct SeverityTarget {
+  android::base::LogSeverity severity;
+  SharedFD target;
+  MetadataLevel metadata_level;
+};
+
+class TeeLogger {
+private:
+  std::vector<SeverityTarget> destinations_;
+public:
+  TeeLogger(const std::vector<SeverityTarget>& destinations);
+  ~TeeLogger() = default;
+
+  void operator()(
+      android::base::LogId log_id,
+      android::base::LogSeverity severity,
+      const char* tag,
+      const char* file,
+      unsigned int line,
+      const char* message);
+};
+
+TeeLogger LogToFiles(const std::vector<std::string>& files);
+TeeLogger LogToStderrAndFiles(const std::vector<std::string>& files);
+
+} // namespace cuttlefish
diff --git a/common/libs/utils/users.cpp b/common/libs/utils/users.cpp
index 0ec92c2..31a4a5e 100644
--- a/common/libs/utils/users.cpp
+++ b/common/libs/utils/users.cpp
@@ -25,8 +25,9 @@
 #include <algorithm>
 #include <vector>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
+namespace cuttlefish {
 namespace {
 gid_t GroupIdFromName(const std::string& group_name) {
   struct group grp{};
@@ -45,7 +46,7 @@
     if (grp_p != nullptr) {
       return grp.gr_gid;
     } else {
-      LOG(ERROR) << "Group " << group_name << " does not exist";
+      // Caller may be checking with non-existent group name
       return -1;
     }
   } else {
@@ -73,7 +74,7 @@
 }
 }  // namespace
 
-bool cvd::InGroup(const std::string& group) {
+bool InGroup(const std::string& group) {
   auto gid = GroupIdFromName(group);
   if (gid == static_cast<gid_t>(-1)) {
     return false;
@@ -89,4 +90,6 @@
     return true;
   }
   return false;
-}
\ No newline at end of file
+}
+
+} // namespace cuttlefish
diff --git a/common/libs/utils/users.h b/common/libs/utils/users.h
index 2fbbdd4..16fcbeb 100644
--- a/common/libs/utils/users.h
+++ b/common/libs/utils/users.h
@@ -17,8 +17,8 @@
 
 #include <string>
 
-namespace cvd {
+namespace cuttlefish {
 
 bool InGroup(const std::string& group);
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/default-permissions.xml b/default-permissions.xml
index 4b42770..eb50a4d 100644
--- a/default-permissions.xml
+++ b/default-permissions.xml
@@ -42,7 +42,8 @@
     -->
 
     <exception
-            package="com.google.android.apps.pixelmigrate">
+            package="com.google.android.apps.restore"
+            sha256-cert-digest="56:BE:13:2B:78:06:56:FE:24:44:CD:34:32:6E:B5:D7:AA:C9:1D:20:96:AB:F0:FE:67:3A:99:27:06:22:EC:87">
         <!-- External storage -->
         <permission name="android.permission.READ_EXTERNAL_STORAGE" fixed="false"/>
         <permission name="android.permission.WRITE_EXTERNAL_STORAGE" fixed="false"/>
@@ -52,9 +53,8 @@
         <!-- Call logs -->
         <permission name="android.permission.READ_CALL_LOG" fixed="false"/>
         <permission name="android.permission.WRITE_CALL_LOG" fixed="false"/>
-        <!-- SMS -->
-        <permission name="android.permission.RECEIVE_SMS" fixed="false"/>
-        <permission name="android.permission.READ_PHONE_NUMBERS" fixed="false"/>
+        <!-- Used to set up a Wi-Fi P2P network -->
+        <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="false"/>
     </exception>
 
     <exception
@@ -67,27 +67,6 @@
         <permission name="android.permission.RECEIVE_SMS" fixed="false"/>
     </exception>
 
-    <exception
-            package="com.google.android.projection.gearhead"
-            sha256-cert-digest="FD:B0:0C:43:DB:DE:8B:51:CB:31:2A:A8:1D:3B:5F:A1:77:13:AD:B9:4B:28:F5:98:D7:7F:8E:B8:9D:AC:EE:DF">
-        <!-- Gearhead legacy -->
-        <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="false"/>
-        <permission name="android.permission.CALL_PHONE" fixed="false"/>
-        <permission name="android.permission.READ_CALL_LOG" fixed="false"/>
-        <permission name="android.permission.READ_CONTACTS" fixed="false"/>
-        <permission name="android.permission.READ_PHONE_STATE" fixed="false"/>
-        <permission name="android.permission.RECEIVE_SMS" fixed="false"/>
-        <permission name="android.permission.RECORD_AUDIO" fixed="false"/>
-        <permission name="android.permission.SEND_SMS" fixed="false"/>
-        <permission name="android.permission.READ_CALENDAR" fixed="false"/>
-        <!-- For Top Gear -->
-        <permission name="android.permission.PROCESS_OUTGOING_CALLS" fixed="false"/>
-        <permission name="android.permission.READ_SMS" fixed="false"/>
-        <permission name="android.permission.RECEIVE_MMS" fixed="false"/>
-        <permission name="android.permission.WRITE_CALL_LOG" fixed="false"/>
-        <permission name="android.permission.ACCESS_COARSE_LOCATION" fixed="false"/>
-    </exception>
-
     <exception package="com.google.android.settings.intelligence">
         <!-- Calendar -->
         <permission name="android.permission.READ_CALENDAR" fixed="true"/>
@@ -96,14 +75,14 @@
         <permission name="android.permission.ACCESS_BACKGROUND_LOCATION" fixed="true"/>
     </exception>
 
-    <exception package="com.google.android.cbrsnetworkmonitor">
+    <exception package="com.google.android.apps.cbrsnetworkmonitor">
         <!-- Location access to create CBRS geofences-->
         <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="true"/>
         <permission name="android.permission.ACCESS_BACKGROUND_LOCATION" fixed="true"/>
     </exception>
 
     <exception package="com.google.android.apps.scone">
-        <!-- NLP Location access to determine proximity to country border -->
+        <!-- Location access to determine proximity to a CBRS network coverage area -->
         <permission name="android.permission.ACCESS_COARSE_LOCATION" fixed="false"/>
         <permission name="android.permission.ACCESS_BACKGROUND_LOCATION" fixed="false"/>
         <!-- Used to call ActivityTransition API for Smart OOS & Smart PNO -->
diff --git a/guest/Android.bp b/guest/Android.bp
deleted file mode 100644
index 95584bc..0000000
--- a/guest/Android.bp
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = ["*"]
diff --git a/guest/Android.mk b/guest/Android.mk
new file mode 100644
index 0000000..428f4b5
--- /dev/null
+++ b/guest/Android.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2021 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/guest/commands/Android.bp b/guest/commands/Android.bp
deleted file mode 100644
index 088948b..0000000
--- a/guest/commands/Android.bp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-  "vsock_logcat",
-  "ip_link_add",
-  "vport_trigger",
-  "vsoc_input_service",
-]
diff --git a/guest/commands/bt_vhci_forwarder/Android.bp b/guest/commands/bt_vhci_forwarder/Android.bp
new file mode 100644
index 0000000..72dd7c9
--- /dev/null
+++ b/guest/commands/bt_vhci_forwarder/Android.bp
@@ -0,0 +1,20 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "bt_vhci_forwarder",
+    srcs: [
+        "main.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+    ],
+    static_libs: [
+        "libgflags",
+        "libbt-rootcanal",
+    ],
+    defaults: ["cuttlefish_guest_only"]
+}
diff --git a/guest/commands/bt_vhci_forwarder/main.cpp b/guest/commands/bt_vhci_forwarder/main.cpp
new file mode 100644
index 0000000..5d5fcce
--- /dev/null
+++ b/guest/commands/bt_vhci_forwarder/main.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <sys/uio.h>
+#include <termios.h>
+#include <unistd.h>
+#include <iomanip>
+#include <ios>
+#include <optional>
+
+#include <gflags/gflags.h>
+
+#include "android-base/logging.h"
+
+#include "model/devices/h4_packetizer.h"
+
+// Copied from net/bluetooth/hci.h
+#define HCI_ACLDATA_PKT 0x02
+#define HCI_SCODATA_PKT 0x03
+#define HCI_EVENT_PKT 0x04
+#define HCI_ISODATA_PKT 0x05
+#define HCI_VENDOR_PKT 0xff
+#define HCI_MAX_ACL_SIZE 1024
+#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
+
+// Include H4 header byte, and reserve more buffer size in the case of excess
+// packet.
+constexpr const size_t kBufferSize = (HCI_MAX_FRAME_SIZE + 1) * 2;
+
+constexpr const char* kVhciDev = "/dev/vhci";
+DEFINE_string(virtio_console_dev, "", "virtio-console device path");
+
+ssize_t send(int fd_, uint8_t type, const uint8_t* data, size_t length) {
+  struct iovec iov[] = {{&type, sizeof(type)},
+                        {const_cast<uint8_t*>(data), length}};
+  ssize_t ret = 0;
+  do {
+    ret = TEMP_FAILURE_RETRY(writev(fd_, iov, sizeof(iov) / sizeof(iov[0])));
+  } while (-1 == ret && EAGAIN == errno);
+  if (ret == -1) {
+    PLOG(ERROR) << "virtio-console to vhci failed";
+  }
+  return ret;
+}
+
+ssize_t forward(int from, int to, std::optional<unsigned char> filter_out,
+                unsigned char* buf) {
+  ssize_t count = TEMP_FAILURE_RETRY(read(from, buf, kBufferSize));
+  if (count < 0) {
+    PLOG(ERROR) << "read failed";
+    return count;
+  } else if (count == 0) {
+    return count;
+  }
+  if (filter_out && buf[0] == *filter_out) {
+    LOG(INFO) << "ignore 0x" << std::hex << std::setw(2) << std::setfill('0')
+              << (unsigned)buf[0] << " packet";
+    return 0;
+  }
+  count = TEMP_FAILURE_RETRY(write(to, buf, count));
+  if (count < 0) {
+    PLOG(ERROR) << "write failed, type: 0x" << std::hex << std::setw(2)
+               << std::setfill('0') << (unsigned)buf[0];
+  }
+  return count;
+}
+
+ssize_t forward(int from, int to, unsigned char* buf) {
+  return forward(from, to, std::nullopt, buf);
+}
+
+int setTerminalRaw(int fd_) {
+  termios terminal_settings;
+  int rval = tcgetattr(fd_, &terminal_settings);
+  if (rval < 0) {
+    return rval;
+  }
+  cfmakeraw(&terminal_settings);
+  rval = tcsetattr(fd_, TCSANOW, &terminal_settings);
+  return rval;
+}
+
+int main(int argc, char** argv) {
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+  int vhci_fd = open(kVhciDev, O_RDWR);
+  int virtio_fd = open(FLAGS_virtio_console_dev.c_str(), O_RDWR);
+  setTerminalRaw(virtio_fd);
+
+  struct pollfd fds[2];
+
+  fds[0].fd = vhci_fd;
+  fds[0].events = POLLIN;
+  fds[1].fd = virtio_fd;
+  fds[1].events = POLLIN;
+  unsigned char buf[kBufferSize];
+
+  auto h4 = test_vendor_lib::H4Packetizer(
+      virtio_fd,
+      [](const std::vector<uint8_t>& /* raw_command */) {
+        LOG(ERROR)
+            << "Unexpected command: command pkt shouldn't be sent as response.";
+      },
+      [vhci_fd](const std::vector<uint8_t>& raw_event) {
+        send(vhci_fd, HCI_EVENT_PKT, raw_event.data(), raw_event.size());
+      },
+      [vhci_fd](const std::vector<uint8_t>& raw_acl) {
+        send(vhci_fd, HCI_ACLDATA_PKT, raw_acl.data(), raw_acl.size());
+      },
+      [vhci_fd](const std::vector<uint8_t>& raw_sco) {
+        send(vhci_fd, HCI_SCODATA_PKT, raw_sco.data(), raw_sco.size());
+      },
+      [vhci_fd](const std::vector<uint8_t>& raw_iso) {
+        send(vhci_fd, HCI_ISODATA_PKT, raw_iso.data(), raw_iso.size());
+      },
+      []() { LOG(INFO) << "HCI socket device disconnected"; });
+
+  while (true) {
+    int ret = TEMP_FAILURE_RETRY(poll(fds, 2, -1));
+    if (ret < 0) {
+      PLOG(ERROR) << "poll failed";
+      continue;
+    }
+    if (fds[0].revents & (POLLIN | POLLERR)) {
+      // TODO(b/182245475) Ignore HCI_VENDOR_PKT
+      // because root-canal cannot handle it.
+      ssize_t c = forward(vhci_fd, virtio_fd, HCI_VENDOR_PKT, buf);
+      if (c < 0) {
+        PLOG(ERROR) << "vhci to virtio-console failed";
+      }
+    }
+
+    if (fds[1].revents & (POLLIN | POLLERR)) {
+      // 'virtio-console to vhci' depends on H4Packetizer because vhci expects
+      // full packet, but the data from virtio-console could be partial.
+      h4.OnDataReady(virtio_fd);
+    }
+  }
+}
\ No newline at end of file
diff --git a/guest/commands/ip_link_add/Android.bp b/guest/commands/ip_link_add/Android.bp
deleted file mode 100644
index 6c155f0..0000000
--- a/guest/commands/ip_link_add/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Copyright (C) 2019 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.
-
-
-cc_binary {
-    name: "ip_link_add",
-    srcs: [
-        "main.cpp",
-    ],
-    shared_libs: [
-        "cuttlefish_net",
-    ],
-    defaults: ["cuttlefish_guest_only"]
-}
diff --git a/guest/commands/ip_link_add/main.cpp b/guest/commands/ip_link_add/main.cpp
deleted file mode 100644
index 5b07798..0000000
--- a/guest/commands/ip_link_add/main.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include "common/libs/net/netlink_client.h"
-#include "common/libs/net/netlink_request.h"
-#include "common/libs/net/network_interface.h"
-#include "common/libs/net/network_interface_manager.h"
-
-#include <linux/rtnetlink.h>
-#include <net/if.h>
-#include <iostream>
-#include <string>
-
-int main(int argc, char *argv[]) {
-  if (!((argc == 5 && std::string(argv[1]) == "vlan") ||
-        (argc == 4 && std::string(argv[1]) == "virt_wifi"))) {
-    std::cerr << "usages:\n";
-    std::cerr << "  " << argv[0] << " vlan [ethA] [ethB] [index]\n";
-    std::cerr << "  " << argv[0] << " virt_wifi [ethA] [ethB]\n";
-    return -1;
-  }
-  const char *const name = argv[2];
-  int32_t index = if_nametoindex(name);
-  if (index == 0) {
-    fprintf(stderr, "%s: invalid interface name '%s'\n", argv[2], name);
-    return -2;
-  }
-  const char *const new_name = argv[3];
-  auto factory = cvd::NetlinkClientFactory::Default();
-  std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
-
-  // http://maz-programmersdiary.blogspot.com/2011/09/netlink-sockets.html
-  cvd::NetlinkRequest link_add_request(RTM_NEWLINK, NLM_F_REQUEST|NLM_F_ACK|0x600);
-  link_add_request.Append(ifinfomsg {
-    .ifi_change = 0xFFFFFFFF,
-  });
-  link_add_request.AddString(IFLA_IFNAME, std::string(new_name));
-  link_add_request.AddInt(IFLA_LINK, index);
-
-  link_add_request.PushList(IFLA_LINKINFO);
-  link_add_request.AddString(IFLA_INFO_KIND, argv[1]);
-  link_add_request.PushList(IFLA_INFO_DATA);
-  if (std::string(argv[1]) == "vlan") {
-    uint16_t vlan_index = atoi(argv[4]);
-    link_add_request.AddInt(IFLA_VLAN_ID, vlan_index);
-  }
-  link_add_request.PopList();
-  link_add_request.PopList();
-
-  nl->Send(link_add_request);
-
-  cvd::NetlinkRequest bring_up_backing_request(RTM_SETLINK, NLM_F_REQUEST|NLM_F_ACK|0x600);
-  bring_up_backing_request.Append(ifinfomsg {
-    .ifi_index = index,
-    .ifi_flags = IFF_UP,
-    .ifi_change = 0xFFFFFFFF,
-  });
-
-  nl->Send(bring_up_backing_request);
-
-  return 0;
-}
diff --git a/guest/commands/rename_netiface/Android.bp b/guest/commands/rename_netiface/Android.bp
index b93a465..f7b71be 100644
--- a/guest/commands/rename_netiface/Android.bp
+++ b/guest/commands/rename_netiface/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary {
     name: "rename_netiface",
     srcs: [
diff --git a/guest/commands/rename_netiface/main.cpp b/guest/commands/rename_netiface/main.cpp
index 3703107..b48184d 100644
--- a/guest/commands/rename_netiface/main.cpp
+++ b/guest/commands/rename_netiface/main.cpp
@@ -35,11 +35,11 @@
     return -2;
   }
   const char *const new_name = argv[2];
-  auto factory = cvd::NetlinkClientFactory::Default();
-  std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
-  std::unique_ptr<cvd::NetworkInterfaceManager> nm(
-      cvd::NetworkInterfaceManager::New(factory));
-  std::unique_ptr<cvd::NetworkInterface> ni(nm->Open(new_name, name));
+  auto factory = cuttlefish::NetlinkClientFactory::Default();
+  std::unique_ptr<cuttlefish::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
+  std::unique_ptr<cuttlefish::NetworkInterfaceManager> nm(
+      cuttlefish::NetworkInterfaceManager::New(factory));
+  std::unique_ptr<cuttlefish::NetworkInterface> ni(nm->Open(new_name, name));
   bool res = false;
   if (ni) {
     ni->SetName(new_name);
diff --git a/guest/commands/sensor_injection/Android.bp b/guest/commands/sensor_injection/Android.bp
new file mode 100644
index 0000000..a29250a
--- /dev/null
+++ b/guest/commands/sensor_injection/Android.bp
@@ -0,0 +1,18 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "cuttlefish_sensor_injection",
+    srcs: ["main.cpp"],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.1",
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    defaults: ["cuttlefish_guest_only"],
+}
diff --git a/guest/commands/sensor_injection/main.cpp b/guest/commands/sensor_injection/main.cpp
new file mode 100644
index 0000000..6eadb4a
--- /dev/null
+++ b/guest/commands/sensor_injection/main.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include <thread>
+
+#include "android/hardware/sensors/2.1/ISensors.h"
+
+using android::sp;
+using android::hardware::sensors::V1_0::OperationMode;
+using android::hardware::sensors::V1_0::Result;
+using android::hardware::sensors::V1_0::SensorStatus;
+using android::hardware::sensors::V2_1::Event;
+using android::hardware::sensors::V2_1::ISensors;
+using android::hardware::sensors::V2_1::SensorInfo;
+using android::hardware::sensors::V2_1::SensorType;
+
+sp<ISensors> startSensorInjection() {
+  const sp<ISensors> sensors = ISensors::getService();
+  if (sensors == nullptr) {
+    LOG(FATAL) << "Unable to get ISensors.";
+  }
+
+  // Place the ISensors HAL into DATA_INJECTION mode so that we can
+  // inject events.
+  Result result = sensors->setOperationMode(OperationMode::DATA_INJECTION);
+  if (result != Result::OK) {
+    LOG(FATAL) << "Unable to set ISensors operation mode to DATA_INJECTION: "
+               << toString(result);
+  }
+
+  return sensors;
+}
+
+int getSensorHandle(SensorType type, const sp<ISensors> sensors) {
+  // Find the first available sensor of the given type.
+  int handle = -1;
+  const auto& getSensorsList_result =
+      sensors->getSensorsList_2_1([&](const auto& list) {
+        for (const SensorInfo& sensor : list) {
+          if (sensor.type == type) {
+            handle = sensor.sensorHandle;
+            break;
+          }
+        }
+      });
+  if (!getSensorsList_result.isOk()) {
+    LOG(FATAL) << "Unable to get ISensors sensors list: "
+               << getSensorsList_result.description();
+  }
+  if (handle == -1) {
+    LOG(FATAL) << "Unable to find sensor.";
+  }
+  return handle;
+}
+
+void endSensorInjection(const sp<ISensors> sensors) {
+  // Return the ISensors HAL back to NORMAL mode.
+  Result result = sensors->setOperationMode(OperationMode::NORMAL);
+  if (result != Result::OK) {
+    LOG(FATAL) << "Unable to set sensors operation mode to NORMAL: "
+               << toString(result);
+  }
+}
+
+// Inject ACCELEROMETER events to corresponding to a given physical
+// device orientation: portrait or landscape.
+void InjectOrientation(bool portrait) {
+  sp<ISensors> sensors = startSensorInjection();
+  int handle = getSensorHandle(SensorType::ACCELEROMETER, sensors);
+
+  // Create a base ISensors accelerometer event.
+  Event event;
+  event.sensorHandle = handle;
+  event.sensorType = SensorType::ACCELEROMETER;
+  if (portrait) {
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 9.2;
+  } else {
+    event.u.vec3.x = 9.2;
+    event.u.vec3.y = 0;
+  }
+  event.u.vec3.z = 3.5;
+  event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+
+  // Repeatedly inject accelerometer events. The WindowManager orientation
+  // listener responds to sustained accelerometer data, not just a single event.
+  android::base::Timer timer;
+  Result result;
+  while (timer.duration() < 1s) {
+    event.timestamp = android::elapsedRealtimeNano();
+    result = sensors->injectSensorData_2_1(event);
+    if (result != Result::OK) {
+      LOG(FATAL) << "Unable to inject ISensors accelerometer event: "
+                 << toString(result);
+    }
+    std::this_thread::sleep_for(10ms);
+  }
+
+  endSensorInjection(sensors);
+}
+
+// Inject a single HINGE_ANGLE event at the given angle.
+void InjectHingeAngle(int angle) {
+  sp<ISensors> sensors = startSensorInjection();
+  int handle = getSensorHandle(SensorType::HINGE_ANGLE, sensors);
+
+  // Create a base ISensors hinge_angle event.
+  Event event;
+  event.sensorHandle = handle;
+  event.sensorType = SensorType::HINGE_ANGLE;
+  event.u.scalar = angle;
+  event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+  event.timestamp = android::elapsedRealtimeNano();
+  Result result = sensors->injectSensorData_2_1(event);
+  if (result != Result::OK) {
+    LOG(FATAL) << "Unable to inject HINGE_ANGLE data: " << toString(result);
+  }
+
+  endSensorInjection(sensors);
+}
+
+int main(int argc, char** argv) {
+  if (argc == 2) {
+    LOG(FATAL) << "Expected command line args 'rotate <portrait|landscape>' or "
+                  "'hinge_angle <value>'";
+  }
+
+  if (!strcmp(argv[1], "rotate")) {
+    bool portrait = true;
+    if (!strcmp(argv[2], "portrait")) {
+      portrait = true;
+    } else if (!strcmp(argv[2], "landscape")) {
+      portrait = false;
+    } else {
+      LOG(FATAL) << "Expected command line arg 'portrait' or 'landscape'";
+    }
+    InjectOrientation(portrait);
+  } else if (!strcmp(argv[1], "hinge_angle")) {
+    int angle = std::stoi(argv[2]);
+    if (angle < 0 || angle > 360) {
+      LOG(FATAL) << "Bad hinge_angle value: " << argv[2];
+    }
+    InjectHingeAngle(angle);
+  } else {
+    LOG(FATAL) << "Unknown arg: " << argv[1];
+  }
+}
diff --git a/guest/commands/setup_wifi/Android.bp b/guest/commands/setup_wifi/Android.bp
index e578af2..21472b1 100644
--- a/guest/commands/setup_wifi/Android.bp
+++ b/guest/commands/setup_wifi/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary {
     name: "setup_wifi",
     srcs: [
diff --git a/guest/commands/setup_wifi/main.cpp b/guest/commands/setup_wifi/main.cpp
index 494a767..0a07c97 100644
--- a/guest/commands/setup_wifi/main.cpp
+++ b/guest/commands/setup_wifi/main.cpp
@@ -46,11 +46,10 @@
   return mac;
 }
 
-// TODO(schuffelen): Merge this with the ip_link_add binary.
 int CreateWifiWrapper(const std::string& source,
                       const std::string& destination) {
-  auto factory = cvd::NetlinkClientFactory::Default();
-  std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
+  auto factory = cuttlefish::NetlinkClientFactory::Default();
+  std::unique_ptr<cuttlefish::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
 
   LOG(INFO) << "Setting " << source << " mac address to " << FLAGS_mac_address;
   int32_t index = if_nametoindex(source.c_str());
@@ -59,7 +58,7 @@
   // https://elixir.bootlin.com/linux/v5.4.44/source/net/core/rtnetlink.c#L2460
   // Setting the address seems to work better on the underlying ethernet device,
   // and this mac address is inherited by the virt_wifi device.
-  cvd::NetlinkRequest fix_mac_request(
+  cuttlefish::NetlinkRequest fix_mac_request(
       RTM_SETLINK, NLM_F_REQUEST|NLM_F_ACK|0x600);
   fix_mac_request.Append(ifinfomsg {
     .ifi_index = index,
@@ -73,7 +72,7 @@
   }
 
   // http://maz-programmersdiary.blogspot.com/2011/09/netlink-sockets.html
-  cvd::NetlinkRequest link_add_request(RTM_NEWLINK,
+  cuttlefish::NetlinkRequest link_add_request(RTM_NEWLINK,
                                        NLM_F_REQUEST|NLM_F_ACK|0x600);
   link_add_request.Append(ifinfomsg {
     .ifi_change = 0xFFFFFFFF,
@@ -97,7 +96,7 @@
     return -3;
   }
 
-  cvd::NetlinkRequest bring_up_backing_request(RTM_SETLINK,
+  cuttlefish::NetlinkRequest bring_up_backing_request(RTM_SETLINK,
                                                NLM_F_REQUEST|NLM_F_ACK|0x600);
   bring_up_backing_request.Append(ifinfomsg {
     .ifi_index = index,
@@ -116,7 +115,7 @@
 
 int RenameNetwork(const std::string& name, const std::string& new_name) {
   static auto net_manager =
-      cvd::NetworkInterfaceManager::New(cvd::NetlinkClientFactory::Default());
+      cuttlefish::NetworkInterfaceManager::New(cuttlefish::NetlinkClientFactory::Default());
   auto connection = net_manager->Open(name, "ignore");
   if (!connection) {
     LOG(ERROR) << "setup_network: could not open " << name << " on device.";
diff --git a/guest/commands/vport_trigger/Android.bp b/guest/commands/vport_trigger/Android.bp
deleted file mode 100644
index 621b9c5..0000000
--- a/guest/commands/vport_trigger/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Copyright (C) 2019 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.
-
-
-cc_binary {
-    name: "vport_trigger",
-    srcs: [
-        "main.cpp",
-    ],
-    shared_libs: [
-        "libcutils",
-    ],
-    defaults: ["cuttlefish_guest_only"]
-}
diff --git a/guest/commands/vport_trigger/main.cpp b/guest/commands/vport_trigger/main.cpp
deleted file mode 100644
index b8d8867..0000000
--- a/guest/commands/vport_trigger/main.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include <cutils/properties.h>
-
-#include <sys/cdefs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <dirent.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <climits>
-#include <cerrno>
-#include <string>
-
-// Taken from android::base, which wasn't available on platform versions
-// earlier than nougat.
-
-static bool ReadFdToString(int fd, std::string* content) {
-  content->clear();
-  char buf[BUFSIZ];
-  ssize_t n;
-  while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
-    content->append(buf, n);
-  }
-  return (n == 0) ? true : false;
-}
-
-static bool ReadFileToString(const std::string& path, std::string* content,
-                             bool follow_symlinks) {
-  int flags = O_RDONLY | O_CLOEXEC | (follow_symlinks ? 0 : O_NOFOLLOW);
-  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags));
-  if (fd == -1) {
-    return false;
-  }
-  bool result = ReadFdToString(fd, content);
-  close(fd);
-  return result;
-}
-
-int main(int argc __unused, char *argv[] __unused) {
-  const char sysfs_base[] = "/sys/class/virtio-ports/";
-  DIR *dir = opendir(sysfs_base);
-  if (dir) {
-    dirent *dp;
-    while ((dp = readdir(dir)) != nullptr) {
-      std::string dirname = dp->d_name;
-      std::string sysfs(sysfs_base + dirname + "/name");
-      struct stat st;
-      if (stat(sysfs.c_str(), &st)) {
-        continue;
-      }
-      std::string content;
-      if (!ReadFileToString(sysfs, &content, true)) {
-        continue;
-      }
-      if (content.empty()) {
-        continue;
-      }
-      content.erase(content.end() - 1);
-      // Leaves 32-11=22 characters for the port name from QEMU.
-      std::string dev("/dev/" + dirname);
-      std::string propname("vendor.ser." + content);
-      property_set(propname.c_str(), dev.c_str());
-      // Property was renamed; this is for compatibility
-      std::string legacy_propname("sys.cf.ser." + content);
-      property_set(legacy_propname.c_str(), dev.c_str());
-    }
-  }
-  return 0;
-}
diff --git a/guest/commands/vsoc_input_service/Android.bp b/guest/commands/vsoc_input_service/Android.bp
index 6c99127..79ac989 100644
--- a/guest/commands/vsoc_input_service/Android.bp
+++ b/guest/commands/vsoc_input_service/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary {
     name: "vsoc_input_service",
     srcs: [
@@ -29,12 +33,10 @@
     ],
     shared_libs: [
         "libcuttlefish_device_config",
+        "libcuttlefish_device_config_proto",
         "libcuttlefish_fs",
         "libbase",
         "liblog",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     defaults: ["cuttlefish_guest_only"]
 }
diff --git a/guest/commands/vsoc_input_service/main.cpp b/guest/commands/vsoc_input_service/main.cpp
index c9e93ed..65d6c6c 100644
--- a/guest/commands/vsoc_input_service/main.cpp
+++ b/guest/commands/vsoc_input_service/main.cpp
@@ -21,7 +21,7 @@
 
 int main(int argc, char* argv[]) {
   gflags::ParseCommandLineFlags(&argc, &argv, true);
-  vsoc_input_service::VSoCInputService service;
+  cuttlefish_input_service::VSoCInputService service;
   if (!service.SetUpDevices()) {
     return -1;
   }
diff --git a/guest/commands/vsoc_input_service/virtual_device_base.cpp b/guest/commands/vsoc_input_service/virtual_device_base.cpp
index 0abb0cd..b96ee39 100644
--- a/guest/commands/vsoc_input_service/virtual_device_base.cpp
+++ b/guest/commands/vsoc_input_service/virtual_device_base.cpp
@@ -16,15 +16,16 @@
 
 #include "virtual_device_base.h"
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "log/log.h"
 
-using vsoc_input_service::VirtualDeviceBase;
+using cuttlefish_input_service::VirtualDeviceBase;
 
 namespace {
 
diff --git a/guest/commands/vsoc_input_service/virtual_device_base.h b/guest/commands/vsoc_input_service/virtual_device_base.h
index d25e0e4..2932753 100644
--- a/guest/commands/vsoc_input_service/virtual_device_base.h
+++ b/guest/commands/vsoc_input_service/virtual_device_base.h
@@ -22,7 +22,7 @@
 #include <functional>
 #include <vector>
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 class VirtualDeviceBase {
  public:
@@ -48,4 +48,4 @@
   int fd_ = -1;
 };
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsoc_input_service/virtual_keyboard.cpp b/guest/commands/vsoc_input_service/virtual_keyboard.cpp
index 80cf0e0..7ffcea5 100644
--- a/guest/commands/vsoc_input_service/virtual_keyboard.cpp
+++ b/guest/commands/vsoc_input_service/virtual_keyboard.cpp
@@ -16,7 +16,7 @@
 
 #include "virtual_keyboard.h"
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 VirtualKeyboard::VirtualKeyboard()
     : VirtualDeviceBase("VSoC keyboard", 0x6008) {}
@@ -63,4 +63,4 @@
   return keys;
 }
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsoc_input_service/virtual_keyboard.h b/guest/commands/vsoc_input_service/virtual_keyboard.h
index b343699..0dd1f42 100644
--- a/guest/commands/vsoc_input_service/virtual_keyboard.h
+++ b/guest/commands/vsoc_input_service/virtual_keyboard.h
@@ -17,7 +17,7 @@
 
 #include "virtual_device_base.h"
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 class VirtualKeyboard : public VirtualDeviceBase {
  public:
@@ -28,4 +28,4 @@
   const std::vector<const uint32_t>& GetKeys() const override;
 };
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsoc_input_service/virtual_power_button.cpp b/guest/commands/vsoc_input_service/virtual_power_button.cpp
index d1758e0..595630b 100644
--- a/guest/commands/vsoc_input_service/virtual_power_button.cpp
+++ b/guest/commands/vsoc_input_service/virtual_power_button.cpp
@@ -16,7 +16,7 @@
 
 #include "virtual_power_button.h"
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 VirtualPowerButton::VirtualPowerButton()
     : VirtualDeviceBase("VSoC power button", 0x6007) {}
@@ -30,4 +30,4 @@
   return keys;
 }
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsoc_input_service/virtual_power_button.h b/guest/commands/vsoc_input_service/virtual_power_button.h
index 220bfdc..95811db 100644
--- a/guest/commands/vsoc_input_service/virtual_power_button.h
+++ b/guest/commands/vsoc_input_service/virtual_power_button.h
@@ -17,7 +17,7 @@
 
 #include "virtual_device_base.h"
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 class VirtualPowerButton : public VirtualDeviceBase {
  public:
@@ -28,4 +28,4 @@
   const std::vector<const uint32_t>& GetKeys() const override;
 };
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsoc_input_service/virtual_touchscreen.cpp b/guest/commands/vsoc_input_service/virtual_touchscreen.cpp
index 72a0d3f..c678573 100644
--- a/guest/commands/vsoc_input_service/virtual_touchscreen.cpp
+++ b/guest/commands/vsoc_input_service/virtual_touchscreen.cpp
@@ -16,7 +16,7 @@
 
 #include "virtual_touchscreen.h"
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 const std::vector<const uint32_t>& VirtualTouchScreen::GetEventTypes() const {
   static const std::vector<const uint32_t> evt_types{EV_ABS, EV_KEY};
@@ -43,4 +43,4 @@
   dev_.absmax[ABS_Y] = height;
 }
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsoc_input_service/virtual_touchscreen.h b/guest/commands/vsoc_input_service/virtual_touchscreen.h
index 9ac806e..a32bcb5 100644
--- a/guest/commands/vsoc_input_service/virtual_touchscreen.h
+++ b/guest/commands/vsoc_input_service/virtual_touchscreen.h
@@ -17,7 +17,7 @@
 
 #include "virtual_device_base.h"
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 class VirtualTouchScreen : public VirtualDeviceBase {
  public:
@@ -30,4 +30,4 @@
   virtual const std::vector<const uint32_t>& GetAbs() const;
 };
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsoc_input_service/vsoc_input_service.cpp b/guest/commands/vsoc_input_service/vsoc_input_service.cpp
index 8b75b45..6d39a81 100644
--- a/guest/commands/vsoc_input_service/vsoc_input_service.cpp
+++ b/guest/commands/vsoc_input_service/vsoc_input_service.cpp
@@ -22,19 +22,19 @@
 
 #include <thread>
 
+#include <android-base/logging.h>
 #include <gflags/gflags.h>
-#include "log/log.h"
-#include <glog/logging.h>
+#include <log/log.h>
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/device_config/device_config.h"
 
-using vsoc::input_events::InputEvent;
-using vsoc_input_service::VirtualDeviceBase;
-using vsoc_input_service::VirtualKeyboard;
-using vsoc_input_service::VirtualPowerButton;
-using vsoc_input_service::VirtualTouchScreen;
-using vsoc_input_service::VSoCInputService;
+using cuttlefish::input_events::InputEvent;
+using cuttlefish_input_service::VirtualDeviceBase;
+using cuttlefish_input_service::VirtualKeyboard;
+using cuttlefish_input_service::VirtualPowerButton;
+using cuttlefish_input_service::VirtualTouchScreen;
+using cuttlefish_input_service::VSoCInputService;
 
 DEFINE_uint32(keyboard_port, 0, "keyboard vsock port");
 DEFINE_uint32(touch_port, 0, "keyboard vsock port");
@@ -61,14 +61,19 @@
     return false;
   }
 
-  auto config = cvd::DeviceConfig::Get();
-  if (!config) {
+  auto config_helper = cuttlefish::DeviceConfigHelper::Get();
+  if (!config_helper) {
     LOG(ERROR) << "Failed to open device config";
     return false;
   }
 
+  const auto& device_config = config_helper->GetDeviceConfig();
+  CHECK_GE(device_config.display_config_size(), 1);
+  const auto& display_config = device_config.display_config(0);
+
   virtual_touchscreen_.reset(
-      new VirtualTouchScreen(config->screen_x_res(), config->screen_y_res()));
+      new VirtualTouchScreen(display_config.width(),
+                             display_config.height()));
   if (!virtual_touchscreen_->SetUp()) {
     return false;
   }
@@ -77,12 +82,12 @@
 }
 
 bool VSoCInputService::ProcessEvents() {
-  cvd::SharedFD keyboard_fd;
-  cvd::SharedFD touch_fd;
+  cuttlefish::SharedFD keyboard_fd;
+  cuttlefish::SharedFD touch_fd;
 
   LOG(INFO) << "Connecting to the keyboard at " << FLAGS_keyboard_port;
   if (FLAGS_keyboard_port) {
-    keyboard_fd = cvd::SharedFD::VsockClient(2, FLAGS_keyboard_port, SOCK_STREAM);
+    keyboard_fd = cuttlefish::SharedFD::VsockClient(2, FLAGS_keyboard_port, SOCK_STREAM);
     if (!keyboard_fd->IsOpen()) {
       LOG(ERROR) << "Could not connect to the keyboard at vsock:2:" << FLAGS_keyboard_port;
     }
@@ -90,7 +95,7 @@
   }
   LOG(INFO) << "Connecting to the touchscreen at " << FLAGS_keyboard_port;
   if (FLAGS_touch_port) {
-    touch_fd = cvd::SharedFD::VsockClient(2, FLAGS_touch_port, SOCK_STREAM);
+    touch_fd = cuttlefish::SharedFD::VsockClient(2, FLAGS_touch_port, SOCK_STREAM);
     if (!touch_fd->IsOpen()) {
       LOG(ERROR) << "Could not connect to the touch at vsock:2:" << FLAGS_touch_port;
     }
diff --git a/guest/commands/vsoc_input_service/vsoc_input_service.h b/guest/commands/vsoc_input_service/vsoc_input_service.h
index edf196d..d8aea81 100644
--- a/guest/commands/vsoc_input_service/vsoc_input_service.h
+++ b/guest/commands/vsoc_input_service/vsoc_input_service.h
@@ -21,7 +21,7 @@
 #include "virtual_power_button.h"
 #include "virtual_touchscreen.h"
 
-namespace vsoc {
+namespace cuttlefish {
 namespace input_events {
 
 struct InputEvent {
@@ -31,9 +31,9 @@
 };
 
 } // namespace input_events
-} // namespace vsoc
+} // namespace cuttlefish
 
-namespace vsoc_input_service {
+namespace cuttlefish_input_service {
 
 class VSoCInputService {
  public:
@@ -46,4 +46,4 @@
   std::shared_ptr<VirtualTouchScreen> virtual_touchscreen_;
 };
 
-}  // namespace vsoc_input_service
+}  // namespace cuttlefish_input_service
diff --git a/guest/commands/vsock_logcat/Android.bp b/guest/commands/vsock_logcat/Android.bp
deleted file mode 100644
index 52575d7..0000000
--- a/guest/commands/vsock_logcat/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Copyright (C) 2019 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.
-
-
-cc_binary {
-    name: "vsock_logcat",
-    srcs: [
-        "main.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libcuttlefish_fs",
-        "libcuttlefish_utils",
-        "liblog",
-    ],
-    static_libs: [
-        "libgflags",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
-    defaults: ["cuttlefish_guest_only"]
-}
diff --git a/guest/commands/vsock_logcat/main.cpp b/guest/commands/vsock_logcat/main.cpp
deleted file mode 100644
index 2abc20b..0000000
--- a/guest/commands/vsock_logcat/main.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#define LOG_TAG "vsock_logcat"
-
-#include <string.h>
-
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <fstream>
-#include <sstream>
-#include <string>
-
-#include <cutils/properties.h>
-#include <gflags/gflags.h>
-#include <glog/logging.h>
-
-#include "common/libs/fs/shared_fd.h"
-#include "common/libs/utils/files.h"
-#include "common/libs/utils/subprocess.h"
-
-DEFINE_uint32(
-    port,
-    static_cast<uint32_t>(property_get_int64("ro.boot.vsock_logcat_port", 0)),
-    "VSOCK port to send logcat output to");
-DEFINE_uint32(cid, 2, "VSOCK CID to send logcat output to");
-DEFINE_string(pipe_name, "/dev/cf_logcat_pipe",
-              "The path for the named pipe logcat will write to");
-
-namespace {
-
-constexpr char kLogcatExitMsg[] = "\nDetected exit of logcat process\n\n";
-
-class ServiceStatus {
- public:
-  static const char* kServiceStatusProperty;
-  static const char* kStatusStarted;
-  static const char* kStatusFailed;
-
-  ServiceStatus() {
-    // This can fail if the property isn't set (the first time it runs), so
-    // ignore the result.
-    property_get(kServiceStatusProperty, status_, kStatusStarted);
-  }
-
-  bool Set(const char* status) {
-    auto ret = property_set(kServiceStatusProperty, status);
-
-    if (ret == 0) {
-      strcpy(status_, status);
-      return true;
-    }
-    return false;
-  }
-
-  const char* Get() { return status_; }
-
- private:
-  char status_[PROP_VALUE_MAX];
-};
-
-const char* ServiceStatus::kServiceStatusProperty = "vendor.vsock_logcat_status";
-const char* ServiceStatus::kStatusStarted = "started";
-const char* ServiceStatus::kStatusFailed = "failed";
-
-void LogFailed(const std::string& msg, ServiceStatus* status) {
-  // Only log if status is not failed, ensuring it logs once per fail.
-  if (strcmp(status->Get(), ServiceStatus::kStatusFailed) != 0) {
-    LOG(ERROR) << msg;
-    std::ofstream kmsg;
-    kmsg.open("/dev/kmsg");
-    kmsg << LOG_TAG << ": " << msg;
-    kmsg << "";
-    kmsg.close();
-  }
-  auto ret = status->Set(ServiceStatus::kStatusFailed);
-  if (!ret) {
-    LOG(ERROR) << "Unable to set value of property: "
-               << ServiceStatus::kServiceStatusProperty;
-  }
-}
-}  // namespace
-
-int main(int argc, char** argv) {
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
-
-  CHECK(FLAGS_port != 0) << "Port flag is required";
-
-  ServiceStatus status;
-
-  auto log_fd = cvd::SharedFD::VsockClient(FLAGS_cid, FLAGS_port, SOCK_STREAM);
-  if (!log_fd->IsOpen()) {
-    std::ostringstream msg;
-    msg << "Unable to connect to vsock:" << FLAGS_cid << ":" << FLAGS_port
-        << ": " << log_fd->StrError();
-    LogFailed(msg.str(), &status);
-    return 1;
-  }
-  auto ret = status.Set(ServiceStatus::kStatusStarted);
-  if (!ret) {
-    LOG(ERROR) << "Unable to set value of property: "
-               << ServiceStatus::kServiceStatusProperty;
-  }
-
-  if (cvd::FileExists(FLAGS_pipe_name)) {
-    LOG(WARNING) << "The file " << FLAGS_pipe_name << " already exists. Deleting...";
-    cvd::RemoveFile(FLAGS_pipe_name);
-  }
-  auto pipe = mkfifo(FLAGS_pipe_name.c_str(), 0600);
-  if (pipe != 0) {
-    LOG(FATAL) << "unable to create pipe: " << strerror(errno);
-  }
-  property_set("vendor.ser.cf-logcat", FLAGS_pipe_name.c_str());
-  while (1) {
-    auto conn = cvd::SharedFD::Open(FLAGS_pipe_name.c_str(), O_RDONLY);
-    while (conn->IsOpen()) {
-      char buff[4096];
-      auto read = conn->Read(buff, sizeof(buff));
-      if (read) {
-        log_fd->Write(buff, read);
-      } else {
-        conn->Close();
-      }
-    }
-    log_fd->Write(kLogcatExitMsg, sizeof(kLogcatExitMsg) - 1);
-  }
-}
diff --git a/guest/hals/Android.bp b/guest/hals/Android.bp
deleted file mode 100644
index 6d01e72..0000000
--- a/guest/hals/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "gps",
-    "health",
-    "hwcomposer",
-]
diff --git a/guest/hals/audio/Android.bp b/guest/hals/audio/Android.bp
index 93a7455..c6faae7 100644
--- a/guest/hals/audio/Android.bp
+++ b/guest/hals/audio/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library_shared {
     name: "audio.primary.cutf",
     relative_install_path: "hw",
diff --git a/guest/hals/audio/audio_hw.c b/guest/hals/audio/audio_hw.c
index 7db1ec1..51110d7 100644
--- a/guest/hals/audio/audio_hw.c
+++ b/guest/hals/audio/audio_hw.c
@@ -45,11 +45,10 @@
 #define PCM_CARD 0
 #define PCM_DEVICE 0
 
-
-#define OUT_PERIOD_MS 15
+#define OUT_PERIOD_MS 10
 #define OUT_PERIOD_COUNT 4
 
-#define IN_PERIOD_MS 15
+#define IN_PERIOD_MS 10
 #define IN_PERIOD_COUNT 4
 
 struct generic_audio_device {
@@ -739,7 +738,8 @@
 
 static int refine_input_parameters(uint32_t *sample_rate, audio_format_t *format, audio_channel_mask_t *channel_mask)
 {
-    static const uint32_t sample_rates [] = {8000, 11025, 16000, 22050, 44100, 48000};
+    // Crosvm only supports 48kHz streams for input
+    static const uint32_t sample_rates [] = {48000};
     static const int sample_rates_count = sizeof(sample_rates)/sizeof(uint32_t);
     bool inval = false;
     // Only PCM_16_bit is supported. If this is changed, stereo to mono drop
@@ -1322,6 +1322,12 @@
     return strdup("");
 }
 
+static int adev_get_audio_port(struct audio_hw_device *dev,
+                               struct audio_port *port)
+{
+    return 0;
+}
+
 static int adev_init_check(const struct audio_hw_device *dev)
 {
     return 0;
@@ -1439,9 +1445,12 @@
     struct generic_audio_device *adev = (struct generic_audio_device *)dev;
     struct generic_stream_in *in;
     int ret = 0;
+    uint32_t orig_sample_rate = config->sample_rate;
+    audio_format_t orig_audio_format = config->format;
+    audio_channel_mask_t orig_channel_mask = config->channel_mask;
     if (refine_input_parameters(&config->sample_rate, &config->format, &config->channel_mask)) {
         ALOGE("Error opening input stream format %d, channel_mask %04x, sample_rate %u",
-              config->format, config->channel_mask, config->sample_rate);
+              orig_audio_format, orig_channel_mask, orig_sample_rate);
         ret = -EINVAL;
         goto error;
     }
@@ -1773,6 +1782,7 @@
     adev->device.get_mic_mute = adev_get_mic_mute;
     adev->device.set_parameters = adev_set_parameters;       // no op
     adev->device.get_parameters = adev_get_parameters;       // no op
+    adev->device.get_audio_port = adev_get_audio_port;       // no op
     adev->device.get_input_buffer_size = adev_get_input_buffer_size;
     adev->device.open_output_stream = adev_open_output_stream;
     adev->device.close_output_stream = adev_close_output_stream;
diff --git a/guest/hals/bt/OWNERS b/guest/hals/bt/OWNERS
new file mode 100644
index 0000000..e8a4a00
--- /dev/null
+++ b/guest/hals/bt/OWNERS
@@ -0,0 +1,2 @@
+include platform/system/bt:/OWNERS
+jeongik@google.com
\ No newline at end of file
diff --git a/guest/hals/bt/data/Android.bp b/guest/hals/bt/data/Android.bp
new file mode 100644
index 0000000..845223f
--- /dev/null
+++ b/guest/hals/bt/data/Android.bp
@@ -0,0 +1,9 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+prebuilt_etc_host {
+    name: "default_commands",
+    src: "default_commands",
+    sub_dir: "rootcanal/data",
+}
diff --git a/guest/hals/bt/data/default_commands b/guest/hals/bt/data/default_commands
new file mode 100644
index 0000000..9182915
--- /dev/null
+++ b/guest/hals/bt/data/default_commands
@@ -0,0 +1,4 @@
+add beacon be:ac:01:55:00:01 1000
+add_device_to_phy 0 1
+add beacon be:ac:01:55:00:02 1000
+add_device_to_phy 1 1
\ No newline at end of file
diff --git a/guest/hals/bt/remote/Android.bp b/guest/hals/bt/remote/Android.bp
new file mode 100644
index 0000000..5ad483a
--- /dev/null
+++ b/guest/hals/bt/remote/Android.bp
@@ -0,0 +1,32 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth@1.1-service.remote",
+    defaults: ["cuttlefish_guest_only", "hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "remote_bluetooth.cpp",
+        "service.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth@1.1",
+        "libcuttlefish_fs",
+        "libbase",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+        "libcutils",
+        "libprotobuf-cpp-lite",
+    ],
+    static_libs: [
+        "libbt-rootcanal",
+        "libbt-rootcanal-types",
+        "async_fd_watcher",
+    ],
+    init_rc: ["android.hardware.bluetooth@1.1-service.remote.rc"],
+}
diff --git a/guest/hals/bt/remote/android.hardware.bluetooth@1.1-service.remote.rc b/guest/hals/bt/remote/android.hardware.bluetooth@1.1-service.remote.rc
new file mode 100644
index 0000000..f4ed9e24
--- /dev/null
+++ b/guest/hals/bt/remote/android.hardware.bluetooth@1.1-service.remote.rc
@@ -0,0 +1,4 @@
+service vendor.bluetooth-1-1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.remote
+    class hal
+    user bluetooth
+    group bluetooth
diff --git a/guest/hals/bt/remote/remote_bluetooth.cpp b/guest/hals/bt/remote/remote_bluetooth.cpp
new file mode 100644
index 0000000..dbcede3
--- /dev/null
+++ b/guest/hals/bt/remote/remote_bluetooth.cpp
@@ -0,0 +1,195 @@
+//
+// Copyright 2021 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.
+//
+
+#define LOG_TAG "android.hardware.bluetooth@1.1.remote"
+
+#include "remote_bluetooth.h"
+
+#include <cutils/properties.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <termios.h>
+#include <utils/Log.h>
+#include "log/log.h"
+
+namespace {
+int SetTerminalRaw(int fd) {
+  termios terminal_settings;
+  int rval = tcgetattr(fd, &terminal_settings);
+  if (rval < 0) {
+    return rval;
+  }
+  cfmakeraw(&terminal_settings);
+  rval = tcsetattr(fd, TCSANOW, &terminal_settings);
+  return rval;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_1 {
+namespace remote {
+
+using ::android::hardware::hidl_vec;
+
+class BluetoothDeathRecipient : public hidl_death_recipient {
+ public:
+  BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
+
+  void serviceDied(
+      uint64_t /* cookie */,
+      const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+    LOG(ERROR)
+        << "BluetoothDeathRecipient::serviceDied - Bluetooth service died";
+    has_died_ = true;
+    mHci->close();
+  }
+  sp<IBluetoothHci> mHci;
+  bool getHasDied() const { return has_died_; }
+  void setHasDied(bool has_died) { has_died_ = has_died; }
+
+ private:
+  bool has_died_;
+};
+
+BluetoothHci::BluetoothHci(const std::string& dev_path)
+    : death_recipient_(new BluetoothDeathRecipient(this)),
+      dev_path_(dev_path) {}
+
+Return<void> BluetoothHci::initialize(
+    const sp<V1_0::IBluetoothHciCallbacks>& cb) {
+  return initialize_impl(cb, nullptr);
+}
+
+Return<void> BluetoothHci::initialize_1_1(
+    const sp<V1_1::IBluetoothHciCallbacks>& cb) {
+  return initialize_impl(cb, cb);
+}
+
+Return<void> BluetoothHci::initialize_impl(
+    const sp<V1_0::IBluetoothHciCallbacks>& cb,
+    const sp<V1_1::IBluetoothHciCallbacks>& cb_1_1) {
+  LOG(INFO) << __func__;
+
+  cb_ = cb;
+  cb_1_1_ = cb_1_1;
+  fd_ = open(dev_path_.c_str(), O_RDWR);
+  if (fd_ < 0) {
+    LOG(FATAL) << "Could not connect to bt: " << fd_;
+  }
+  if (int ret = SetTerminalRaw(fd_) < 0) {
+    LOG(FATAL) << "Could not make " << fd_ << " a raw terminal: " << ret;
+  }
+
+  if (cb == nullptr) {
+    LOG(ERROR)
+        << "cb == nullptr! -> Unable to call initializationComplete(ERR)";
+    return Void();
+  }
+
+  death_recipient_->setHasDied(false);
+  auto link_ret = cb->linkToDeath(death_recipient_, 0);
+
+  unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
+    if (death_recipient->getHasDied())
+      LOG(INFO) << "Skipping unlink call, service died.";
+    else {
+      auto ret = cb->unlinkToDeath(death_recipient);
+      if (!ret.isOk()) {
+        CHECK(death_recipient_->getHasDied())
+            << "Error calling unlink, but no death notification.";
+      }
+    }
+  };
+
+  auto init_ret = cb->initializationComplete(V1_0::Status::SUCCESS);
+  if (!init_ret.isOk()) {
+    CHECK(death_recipient_->getHasDied())
+        << "Error sending init callback, but no death notification.";
+  }
+  h4_ = test_vendor_lib::H4Packetizer(
+      fd_,
+      [](const std::vector<uint8_t>& /* raw_command */) {
+        LOG_ALWAYS_FATAL("Unexpected command!");
+      },
+      [this](const std::vector<uint8_t>& raw_event) {
+        cb_->hciEventReceived(hidl_vec<uint8_t>(raw_event));
+      },
+      [this](const std::vector<uint8_t>& raw_acl) {
+        cb_->hciEventReceived(hidl_vec<uint8_t>(raw_acl));
+      },
+      [this](const std::vector<uint8_t>& raw_sco) {
+        cb_->hciEventReceived(hidl_vec<uint8_t>(raw_sco));
+      },
+      [this](const std::vector<uint8_t>& raw_iso) {
+        if (cb_1_1_) {
+          cb_1_1_->hciEventReceived(hidl_vec<uint8_t>(raw_iso));
+        }
+      },
+      []() { LOG(INFO) << "HCI socket device disconnected"; });
+  fd_watcher_.WatchFdForNonBlockingReads(
+      fd_, [this](int fd) { h4_.OnDataReady(fd); });
+  return Void();
+}
+
+Return<void> BluetoothHci::close() {
+  LOG(INFO) << __func__;
+  fd_watcher_.StopWatchingFileDescriptors();
+  ::close(fd_);
+
+  return Void();
+}
+
+Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& packet) {
+  send(test_vendor_lib::PacketType::COMMAND, packet);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& packet) {
+  send(test_vendor_lib::PacketType::ACL, packet);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& packet) {
+  send(test_vendor_lib::PacketType::SCO, packet);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& packet) {
+  send(test_vendor_lib::PacketType::ISO, packet);
+  return Void();
+}
+
+void BluetoothHci::send(test_vendor_lib::PacketType type,
+                        const ::android::hardware::hidl_vec<uint8_t>& v) {
+  h4_.Send(static_cast<uint8_t>(type), v.data(), v.size());
+}
+
+/* Fallback to shared library if there is no service. */
+IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* /* name */) {
+  return new BluetoothHci();
+}
+
+}  // namespace remote
+}  // namespace V1_1
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/guest/hals/bt/remote/remote_bluetooth.h b/guest/hals/bt/remote/remote_bluetooth.h
new file mode 100644
index 0000000..a7aa24c
--- /dev/null
+++ b/guest/hals/bt/remote/remote_bluetooth.h
@@ -0,0 +1,101 @@
+//
+// Copyright 2021 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 <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+
+#include <android-base/logging.h>
+#include <hidl/MQDescriptor.h>
+#include <string>
+#include "async_fd_watcher.h"
+#include "model/devices/h4_packetizer.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_1 {
+namespace remote {
+
+class BluetoothDeathRecipient;
+
+// This Bluetooth HAL implementation is connected with the root-canal process in
+// the host side via virtio-console device(refer to dev_path_). It receives and
+// deliver responses and requests from/to Bluetooth HAL.
+class BluetoothHci : public IBluetoothHci {
+ public:
+  // virtio-console device connected with root-canal in the host side.
+  BluetoothHci(const std::string& dev_path = "/dev/hvc5");
+
+  ::android::hardware::Return<void> initialize(
+      const sp<V1_0::IBluetoothHciCallbacks>& cb) override;
+  ::android::hardware::Return<void> initialize_1_1(
+      const sp<V1_1::IBluetoothHciCallbacks>& cb) override;
+
+  ::android::hardware::Return<void> sendHciCommand(
+      const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
+  ::android::hardware::Return<void> sendAclData(
+      const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
+  ::android::hardware::Return<void> sendScoData(
+      const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
+  ::android::hardware::Return<void> sendIsoData(
+      const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
+  ::android::hardware::Return<void> close() override;
+
+  static void OnPacketReady();
+
+  static BluetoothHci* get();
+
+ private:
+  int fd_{-1};
+  ::android::sp<V1_0::IBluetoothHciCallbacks> cb_ = nullptr;
+  ::android::sp<V1_1::IBluetoothHciCallbacks> cb_1_1_ = nullptr;
+
+  test_vendor_lib::H4Packetizer h4_{fd_,
+                                    [](const std::vector<uint8_t>&) {},
+                                    [](const std::vector<uint8_t>&) {},
+                                    [](const std::vector<uint8_t>&) {},
+                                    [](const std::vector<uint8_t>&) {},
+                                    [](const std::vector<uint8_t>&) {},
+                                    [] {}};
+
+  ::android::hardware::Return<void> initialize_impl(
+      const sp<V1_0::IBluetoothHciCallbacks>& cb,
+      const sp<V1_1::IBluetoothHciCallbacks>& cb_1_1);
+
+  sp<BluetoothDeathRecipient> death_recipient_;
+
+  const std::string dev_path_;
+
+  std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
+
+  ::android::hardware::bluetooth::async::AsyncFdWatcher fd_watcher_;
+
+  void send(test_vendor_lib::PacketType type,
+            const ::android::hardware::hidl_vec<uint8_t>& packet);
+};
+
+extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
+
+}  // namespace remote
+}  // namespace V1_1
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/guest/hals/bt/remote/service.cpp b/guest/hals/bt/remote/service.cpp
new file mode 100644
index 0000000..10ed3bc
--- /dev/null
+++ b/guest/hals/bt/remote/service.cpp
@@ -0,0 +1,39 @@
+//
+// Copyright 2021 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.
+//
+
+#define LOG_TAG "android.hardware.bluetooth@1.1-service.remote"
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "remote_bluetooth.h"
+
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_1::remote::BluetoothHci;
+
+int main(int /* argc */, char** /* argv */) {
+  sp<IBluetoothHci> bluetooth = new BluetoothHci();
+  configureRpcThreadpool(1, true);
+  android::status_t status = bluetooth->registerAsService();
+  if (status == android::OK)
+    joinRpcThreadpool();
+  else
+    LOG(ERROR) << "Could not register as a service!";
+}
diff --git a/guest/hals/camera/Android.mk b/guest/hals/camera/Android.mk
deleted file mode 100644
index 994d82f..0000000
--- a/guest/hals/camera/Android.mk
+++ /dev/null
@@ -1,182 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Emulator camera module########################################################
-
-emulator_camera_module_relative_path := hw
-emulator_camera_cflags := -fno-short-enums $(VSOC_VERSION_CFLAGS)
-emulator_camera_cflags += \
-    -std=gnu++17 \
-    -Wall \
-    -Werror
-
-emulator_camera_shared_libraries := \
-    libbase \
-    libbinder \
-    libexif \
-    liblog \
-    libutils \
-    libcutils \
-    libui \
-    libdl \
-    libjpeg \
-    libcamera_metadata \
-    libhardware
-
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -lt 27; echo $$?))
-emulator_camera_shared_libraries += libcamera_client
-else
-emulator_camera_static_libraries += android.hardware.camera.common@1.0-helper
-endif
-
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -le 22; echo $$?))
-emulator_camera_shared_libraries += libjsoncpp
-else
-emulator_camera_static_libraries += libjsoncpp
-endif
-
-
-emulator_camera_static_libraries += android.hardware.camera.common@1.0-helper
-
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -le 26; echo $$?))
-emulator_camera_static_libraries += libyuv_static
-else
-emulator_camera_static_libraries += libyuv
-endif
-
-emulator_camera_c_includes := \
-    device/google/cuttlefish \
-    frameworks/native/include/media/hardware \
-    $(call include-path-for, camera) \
-
-emulator_camera_src := \
-	CameraConfiguration.cpp \
-	EmulatedCameraHal.cpp \
-	EmulatedCameraFactory.cpp \
-	EmulatedBaseCamera.cpp \
-	EmulatedCamera.cpp \
-		EmulatedCameraDevice.cpp \
-		EmulatedFakeCamera.cpp \
-		EmulatedFakeCameraDevice.cpp \
-		Exif.cpp \
-		Thumbnail.cpp \
-		Converters.cpp \
-		PreviewWindow.cpp \
-		CallbackNotifier.cpp \
-		JpegCompressor.cpp
-emulated_camera2_src := \
-	VSoCEmulatedCameraHotplugThread.cpp \
-	EmulatedCamera2.cpp \
-		EmulatedFakeCamera2.cpp \
-		fake-pipeline2/Scene.cpp \
-		fake-pipeline2/Sensor.cpp \
-		fake-pipeline2/JpegCompressor.cpp
-emulated_camera3_src := \
-	EmulatedCamera3.cpp \
-		EmulatedFakeCamera3.cpp
-
-
-emulated_camera2_stub_src := \
-	StubEmulatedCamera2.cpp \
-		StubEmulatedFakeCamera2.cpp
-
-enable_emulated_camera3 = $(shell test $(PLATFORM_SDK_VERSION) -ge 23 && echo yes)
-enable_emulated_camera2 = $(shell test $(PLATFORM_SDK_VERSION) -ge 19 && echo yes)
-
-# Emulated camera - cuttlefish / vbox_x86 build###################################
-#
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 24; echo $$?))
-emulator_camera_c_includes += external/libjpeg-turbo
-else
-emulator_camera_c_includes += external/jpeg
-endif
-
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 21; echo $$?))
-LOCAL_MODULE_RELATIVE_PATH := ${emulator_camera_module_relative_path}
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/${emulator_camera_module_relative_path}
-endif
-ifeq (true, $(TARGET_TRANSLATE_2ND_ARCH))
-LOCAL_MULTILIB := first
-endif
-LOCAL_CFLAGS := ${emulator_camera_cflags}
-LOCAL_CLANG_CFLAGS += ${emulator_camera_clang_flags}
-
-LOCAL_SHARED_LIBRARIES := ${emulator_camera_shared_libraries}
-LOCAL_STATIC_LIBRARIES := ${emulator_camera_static_libraries}
-LOCAL_C_INCLUDES += ${emulator_camera_c_includes}
-LOCAL_SRC_FILES := ${emulator_camera_src} ${emulator_camera_ext_src} \
-	$(if $(enable_emulated_camera2),$(emulated_camera2_src),) \
-	$(if $(enable_emulated_camera3),$(emulated_camera3_src),)
-
-LOCAL_MODULE := camera.cutf
-LOCAL_MODULE_TAGS := optional
-LOCAL_VENDOR_MODULE := true
-
-include $(BUILD_SHARED_LIBRARY)
-
-# JPEG stub#####################################################################
-
-include $(CLEAR_VARS)
-
-jpeg_module_relative_path := hw
-jpeg_cflags := \
-    -fno-short-enums \
-    -Wall \
-    -Werror
-
-jpeg_shared_libraries := \
-    libcutils \
-    libexif \
-    liblog \
-    libjpeg \
-
-jpeg_c_includes := external/libexif \
-                   frameworks/native/include
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 24; echo $$?))
-jpeg_c_includes += external/libjpeg-turbo
-else
-jpeg_c_includes += external/jpeg
-endif
-
-jpeg_src := \
-    Compressor.cpp \
-    JpegStub.cpp \
-
-# JPEG stub - cuttlefish build####################################################
-
-ifeq (true, $(TARGET_TRANSLATE_2ND_ARCH))
-LOCAL_MULTILIB := first
-endif
-
-LOCAL_C_INCLUDES += ${jpeg_c_includes}
-LOCAL_SRC_FILES := ${jpeg_src}
-
-LOCAL_MODULE_RELATIVE_PATH := ${jpeg_module_relative_path}
-LOCAL_CFLAGS += ${jpeg_cflags}
-
-LOCAL_SHARED_LIBRARIES := ${jpeg_shared_libraries}
-
-LOCAL_C_INCLUDES += ${jpeg_c_includes}
-LOCAL_SRC_FILES := ${jpeg_src}
-
-LOCAL_MODULE := camera.cutf.jpeg
-LOCAL_MODULE_TAGS := optional
-LOCAL_VENDOR_MODULE := true
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/guest/hals/camera/CallbackNotifier.cpp b/guest/hals/camera/CallbackNotifier.cpp
deleted file mode 100644
index 765d4e7..0000000
--- a/guest/hals/camera/CallbackNotifier.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class CallbackNotifier that manages callbacks
- * set via set_callbacks, enable_msg_type, and disable_msg_type camera HAL API.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_CallbackNotifier"
-#include "CallbackNotifier.h"
-#include <MetadataBufferType.h>
-#include <log/log.h>
-#include "EmulatedCameraDevice.h"
-#include "JpegCompressor.h"
-#include "Exif.h"
-#include "Thumbnail.h"
-
-namespace android {
-
-/* String representation of camera messages. */
-static const char* lCameraMessages[] = {"CAMERA_MSG_ERROR",
-                                        "CAMERA_MSG_SHUTTER",
-                                        "CAMERA_MSG_FOCUS",
-                                        "CAMERA_MSG_ZOOM",
-                                        "CAMERA_MSG_PREVIEW_FRAME",
-                                        "CAMERA_MSG_VIDEO_FRAME",
-                                        "CAMERA_MSG_POSTVIEW_FRAME",
-                                        "CAMERA_MSG_RAW_IMAGE",
-                                        "CAMERA_MSG_COMPRESSED_IMAGE",
-                                        "CAMERA_MSG_RAW_IMAGE_NOTIFY",
-                                        "CAMERA_MSG_PREVIEW_METADATA"};
-static const int lCameraMessagesNum = sizeof(lCameraMessages) / sizeof(char*);
-
-/* Builds an array of strings for the given set of messages.
- * Param:
- *  msg - Messages to get strings for,
- *  strings - Array where to save strings
- *  max - Maximum number of entries in the array.
- * Return:
- *  Number of strings saved into the 'strings' array.
- */
-static int GetMessageStrings(uint32_t msg, const char** strings, int max) {
-  int index = 0;
-  int out = 0;
-  while (msg != 0 && out < max && index < lCameraMessagesNum) {
-    while ((msg & 0x1) == 0 && index < lCameraMessagesNum) {
-      msg >>= 1;
-      index++;
-    }
-    if ((msg & 0x1) != 0 && index < lCameraMessagesNum) {
-      strings[out] = lCameraMessages[index];
-      out++;
-      msg >>= 1;
-      index++;
-    }
-  }
-
-  return out;
-}
-
-/* Logs messages, enabled by the mask. */
-static void PrintMessages(uint32_t msg) {
-  const char* strs[lCameraMessagesNum];
-  const int translated = GetMessageStrings(msg, strs, lCameraMessagesNum);
-  for (int n = 0; n < translated; n++) {
-    ALOGV("    %s", strs[n]);
-  }
-}
-
-CallbackNotifier::CallbackNotifier()
-    : mNotifyCB(NULL),
-      mDataCB(NULL),
-      mDataCBTimestamp(NULL),
-      mGetMemoryCB(NULL),
-      mCBOpaque(NULL),
-      mLastFrameTimestamp(0),
-      mFrameRefreshFreq(0),
-      mMessageEnabler(0),
-      mJpegQuality(90),
-      mVideoRecEnabled(false),
-      mTakingPicture(false) {}
-
-CallbackNotifier::~CallbackNotifier() {}
-
-/****************************************************************************
- * Camera API
- ***************************************************************************/
-
-void CallbackNotifier::setCallbacks(
-    camera_notify_callback notify_cb, camera_data_callback data_cb,
-    camera_data_timestamp_callback data_cb_timestamp,
-    camera_request_memory get_memory, void* user) {
-  ALOGV("%s: %p, %p, %p, %p (%p)", __FUNCTION__, notify_cb, data_cb,
-        data_cb_timestamp, get_memory, user);
-
-  Mutex::Autolock locker(&mObjectLock);
-  mNotifyCB = notify_cb;
-  mDataCB = data_cb;
-  mDataCBTimestamp = data_cb_timestamp;
-  mGetMemoryCB = get_memory;
-  mCBOpaque = user;
-}
-
-void CallbackNotifier::enableMessage(uint msg_type) {
-  ALOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type);
-  PrintMessages(msg_type);
-
-  Mutex::Autolock locker(&mObjectLock);
-  mMessageEnabler |= msg_type;
-  ALOGV("**** Currently enabled messages:");
-  PrintMessages(mMessageEnabler);
-}
-
-void CallbackNotifier::disableMessage(uint msg_type) {
-  ALOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type);
-  PrintMessages(msg_type);
-
-  Mutex::Autolock locker(&mObjectLock);
-  mMessageEnabler &= ~msg_type;
-  ALOGV("**** Currently enabled messages:");
-  PrintMessages(mMessageEnabler);
-}
-
-status_t CallbackNotifier::enableVideoRecording(int fps) {
-  ALOGV("%s: FPS = %d", __FUNCTION__, fps);
-
-  Mutex::Autolock locker(&mObjectLock);
-  mVideoRecEnabled = true;
-  mLastFrameTimestamp = 0;
-  mFrameRefreshFreq = 1000000000LL / fps;
-
-  return NO_ERROR;
-}
-
-void CallbackNotifier::disableVideoRecording() {
-  ALOGV("%s:", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  mVideoRecEnabled = false;
-  mLastFrameTimestamp = 0;
-  mFrameRefreshFreq = 0;
-}
-
-void CallbackNotifier::releaseRecordingFrame(const void* opaque) {
-  List<camera_memory_t*>::iterator it = mCameraMemoryTs.begin();
-  for (; it != mCameraMemoryTs.end(); ++it) {
-    if ((*it)->data == opaque) {
-      (*it)->release(*it);
-      mCameraMemoryTs.erase(it);
-      break;
-    }
-  }
-}
-
-status_t CallbackNotifier::storeMetaDataInBuffers(bool enable) {
-  // Return error if metadata is request, otherwise silently agree.
-  return enable ? INVALID_OPERATION : NO_ERROR;
-}
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-void CallbackNotifier::cleanupCBNotifier() {
-  Mutex::Autolock locker(&mObjectLock);
-  mMessageEnabler = 0;
-  mNotifyCB = NULL;
-  mDataCB = NULL;
-  mDataCBTimestamp = NULL;
-  mGetMemoryCB = NULL;
-  mCBOpaque = NULL;
-  mLastFrameTimestamp = 0;
-  mFrameRefreshFreq = 0;
-  mJpegQuality = 90;
-  mVideoRecEnabled = false;
-  mTakingPicture = false;
-}
-
-void CallbackNotifier::onNextFrameAvailable(const void* frame,
-                                            nsecs_t timestamp,
-                                            EmulatedCameraDevice* camera_dev) {
-  if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME) && isVideoRecordingEnabled() &&
-      isNewVideoFrameTime(timestamp)) {
-    camera_memory_t* cam_buff =
-        mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, mCBOpaque);
-    if (NULL != cam_buff && NULL != cam_buff->data) {
-      memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize());
-      mDataCBTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, cam_buff, 0,
-                       mCBOpaque);
-
-      mCameraMemoryTs.push_back(cam_buff);
-    } else {
-      ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
-    }
-  }
-
-  if (isMessageEnabled(CAMERA_MSG_PREVIEW_FRAME)) {
-    camera_memory_t* cam_buff =
-        mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, mCBOpaque);
-    if (NULL != cam_buff && NULL != cam_buff->data) {
-      memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize());
-      mDataCB(CAMERA_MSG_PREVIEW_FRAME, cam_buff, 0, NULL, mCBOpaque);
-      cam_buff->release(cam_buff);
-    } else {
-      ALOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__);
-    }
-  }
-
-  if (mTakingPicture) {
-    /* This happens just once. */
-    mTakingPicture = false;
-    /* The sequence of callbacks during picture taking is:
-     *  - CAMERA_MSG_SHUTTER
-     *  - CAMERA_MSG_RAW_IMAGE_NOTIFY
-     *  - CAMERA_MSG_COMPRESSED_IMAGE
-     */
-    if (isMessageEnabled(CAMERA_MSG_SHUTTER)) {
-      mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCBOpaque);
-    }
-    if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
-      mNotifyCB(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCBOpaque);
-    }
-    if (isMessageEnabled(CAMERA_MSG_COMPRESSED_IMAGE)) {
-      /* Compress the frame to JPEG. Note that when taking pictures, we
-       * have requested camera device to provide us with NV21 frames. */
-      NV21JpegCompressor compressor;
-      const CameraParameters* cameraParameters = camera_dev->getCameraParameters();
-      if (cameraParameters == nullptr) {
-        ALOGE("%s: Could not get camera parameters to take picture.", __FUNCTION__);
-        return;
-      }
-
-      ExifData* exifData = createExifData(*cameraParameters);
-
-      // Create a thumbnail and place the pointer and size in the EXIF
-      // data structure. This transfers ownership to the EXIF data and
-      // the memory will be deallocated in the freeExifData call below.
-      int width = camera_dev->getFrameWidth();
-      int height = camera_dev->getFrameHeight();
-      int thumbWidth = cameraParameters->getInt(
-              CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
-      int thumbHeight = cameraParameters->getInt(
-              CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
-      if (thumbWidth > 0 && thumbHeight > 0) {
-          if (!createThumbnail(static_cast<const unsigned char*>(frame),
-                               width, height, thumbWidth, thumbHeight,
-                               mJpegQuality, exifData)) {
-              // Not really a fatal error, we'll just keep going
-              ALOGE("%s: Failed to create thumbnail for image",
-                    __FUNCTION__);
-          }
-      }
-
-      status_t res = compressor.compressRawImage(frame, exifData, mJpegQuality, width, height);
-      if (res == NO_ERROR) {
-        camera_memory_t* jpeg_buff =
-            mGetMemoryCB(-1, compressor.getCompressedSize(), 1, mCBOpaque);
-        if (NULL != jpeg_buff && NULL != jpeg_buff->data) {
-          compressor.getCompressedImage(jpeg_buff->data);
-          mDataCB(CAMERA_MSG_COMPRESSED_IMAGE, jpeg_buff, 0, NULL, mCBOpaque);
-          jpeg_buff->release(jpeg_buff);
-        } else {
-          ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
-        }
-      } else {
-        ALOGE("%s: Compression failure in CAMERA_MSG_VIDEO_FRAME",
-              __FUNCTION__);
-      }
-      freeExifData(exifData);
-    }
-  }
-}
-
-void CallbackNotifier::onCameraDeviceError(int err) {
-  if (isMessageEnabled(CAMERA_MSG_ERROR) && mNotifyCB != NULL) {
-    mNotifyCB(CAMERA_MSG_ERROR, err, 0, mCBOpaque);
-  }
-}
-
-void CallbackNotifier::onCameraFocusAcquired() {
-  if (isMessageEnabled(CAMERA_MSG_FOCUS) && mNotifyCB != NULL) {
-    mNotifyCB(CAMERA_MSG_FOCUS, 1, 0, mCBOpaque);
-  }
-}
-
-/****************************************************************************
- * Private API
- ***************************************************************************/
-
-bool CallbackNotifier::isNewVideoFrameTime(nsecs_t timestamp) {
-  Mutex::Autolock locker(&mObjectLock);
-  if ((timestamp - mLastFrameTimestamp) >= mFrameRefreshFreq) {
-    mLastFrameTimestamp = timestamp;
-    return true;
-  }
-  return false;
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/CallbackNotifier.h b/guest/hals/camera/CallbackNotifier.h
deleted file mode 100644
index 38a5979..0000000
--- a/guest/hals/camera/CallbackNotifier.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_CALLBACK_NOTIFIER_H
-#define HW_EMULATOR_CAMERA_CALLBACK_NOTIFIER_H
-
-/*
- * Contains declaration of a class CallbackNotifier that manages callbacks set
- * via set_callbacks, enable_msg_type, and disable_msg_type camera HAL API.
- */
-
-#include <hardware/camera.h>
-#include <utils/List.h>
-#include <utils/Mutex.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-class EmulatedCameraDevice;
-
-/* Manages callbacks set via set_callbacks, enable_msg_type, and
- * disable_msg_type camera HAL API.
- *
- * Objects of this class are contained in EmulatedCamera objects, and handle
- * relevant camera API callbacks.
- * Locking considerations. Apparently, it's not allowed to call callbacks
- * registered in this class, while holding a lock: recursion is quite possible,
- * which will cause a deadlock.
- */
-class CallbackNotifier {
- public:
-  /* Constructs CallbackNotifier instance. */
-  CallbackNotifier();
-
-  /* Destructs CallbackNotifier instance. */
-  ~CallbackNotifier();
-
-  /****************************************************************************
-   * Camera API
-   ***************************************************************************/
-
- public:
-  /* Actual handler for camera_device_ops_t::set_callbacks callback.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::set_callbacks callback.
-   */
-  void setCallbacks(camera_notify_callback notify_cb,
-                    camera_data_callback data_cb,
-                    camera_data_timestamp_callback data_cb_timestamp,
-                    camera_request_memory get_memory, void* user);
-
-  /* Actual handler for camera_device_ops_t::enable_msg_type callback.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::enable_msg_type callback.
-   */
-  void enableMessage(uint msg_type);
-
-  /* Actual handler for camera_device_ops_t::disable_msg_type callback.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::disable_msg_type callback.
-   */
-  void disableMessage(uint msg_type);
-
-  /* Actual handler for camera_device_ops_t::store_meta_data_in_buffers
-   * callback. This method is called by the containing emulated camera object
-   * when it is handing the camera_device_ops_t::store_meta_data_in_buffers
-   * callback.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  status_t storeMetaDataInBuffers(bool enable);
-
-  /* Enables video recording.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::start_recording callback.
-   * Param:
-   *  fps - Video frame frequency. This parameter determins when a frame
-   *      received via onNextFrameAvailable call will be pushed through the
-   *      callback.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  status_t enableVideoRecording(int fps);
-
-  /* Disables video recording.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::stop_recording callback.
-   */
-  void disableVideoRecording();
-
-  /* Releases video frame, sent to the framework.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::release_recording_frame callback.
-   */
-  void releaseRecordingFrame(const void* opaque);
-
-  /* Actual handler for camera_device_ops_t::msg_type_enabled callback.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::msg_type_enabled callback.
-   * Note: this method doesn't grab a lock while checking message status, since
-   * upon exit the status would be undefined anyway. So, grab a lock before
-   * calling this method if you care about persisting a defined message status.
-   * Return:
-   *  0 if message is disabled, or non-zero value, if message is enabled.
-   */
-  inline int isMessageEnabled(uint msg_type) {
-    return mMessageEnabler & msg_type;
-  }
-
-  /* Checks id video recording is enabled.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::recording_enabled callback.
-   * Note: this method doesn't grab a lock while checking video recordin status,
-   * since upon exit the status would be undefined anyway. So, grab a lock
-   * before calling this method if you care about persisting of a defined video
-   * recording status.
-   * Return:
-   *  true if video recording is enabled, or false if it is disabled.
-   */
-  inline bool isVideoRecordingEnabled() { return mVideoRecEnabled; }
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  /* Resets the callback notifier. */
-  void cleanupCBNotifier();
-
-  /* Next frame is available in the camera device.
-   * This is a notification callback that is invoked by the camera device when
-   * a new frame is available.
-   * Note that most likely this method is called in context of a worker thread
-   * that camera device has created for frame capturing.
-   * Param:
-   *  frame - Captured frame, or NULL if camera device didn't pull the frame
-   *      yet. If NULL is passed in this parameter use GetCurrentFrame method
-   *      of the camera device class to obtain the next frame. Also note that
-   *      the size of the frame that is passed here (as well as the frame
-   *      returned from the GetCurrentFrame method) is defined by the current
-   *      frame settings (width + height + pixel format) for the camera device.
-   * timestamp - Frame's timestamp.
-   * camera_dev - Camera device instance that delivered the frame.
-   */
-  void onNextFrameAvailable(const void* frame, nsecs_t timestamp,
-                            EmulatedCameraDevice* camera_dev);
-
-  /* Entry point for notifications that occur in camera device.
-   * Param:
-   *  err - CAMERA_ERROR_XXX error code.
-   */
-  void onCameraDeviceError(int err);
-
-  /* Reports focus operation completion to camera client.
-   */
-  void onCameraFocusAcquired();
-
-  /* Sets, or resets taking picture state.
-   * This state control whether or not to notify the framework about compressed
-   * image, shutter, and other picture related events.
-   */
-  void setTakingPicture(bool taking) { mTakingPicture = taking; }
-
-  /* Sets JPEG quality used to compress frame during picture taking. */
-  void setJpegQuality(int jpeg_quality) { mJpegQuality = jpeg_quality; }
-
-  /****************************************************************************
-   * Private API
-   ***************************************************************************/
-
- protected:
-  /* Checks if it's time to push new video frame.
-   * Note that this method must be called while object is locked.
-   * Param:
-   *  timestamp - Timestamp for the new frame. */
-  bool isNewVideoFrameTime(nsecs_t timestamp);
-
-  /****************************************************************************
-   * Data members
-   ***************************************************************************/
-
- protected:
-  /* Locks this instance for data change. */
-  Mutex mObjectLock;
-
-  /*
-   * Callbacks, registered in set_callbacks.
-   */
-
-  camera_notify_callback mNotifyCB;
-  camera_data_callback mDataCB;
-  camera_data_timestamp_callback mDataCBTimestamp;
-  camera_request_memory mGetMemoryCB;
-  void* mCBOpaque;
-
-  /* video frame queue for the CameraHeapMemory destruction */
-  List<camera_memory_t*> mCameraMemoryTs;
-
-  /* Timestamp when last frame has been delivered to the framework. */
-  nsecs_t mLastFrameTimestamp;
-
-  /* Video frequency in nanosec. */
-  nsecs_t mFrameRefreshFreq;
-
-  /* Message enabler. */
-  uint32_t mMessageEnabler;
-
-  /* JPEG quality used to compress frame during picture taking. */
-  int mJpegQuality;
-
-  /* Video recording status. */
-  bool mVideoRecEnabled;
-
-  /* Picture taking status. */
-  bool mTakingPicture;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_CALLBACK_NOTIFIER_H */
diff --git a/guest/hals/camera/CameraConfiguration.cpp b/guest/hals/camera/CameraConfiguration.cpp
deleted file mode 100644
index 32ac332..0000000
--- a/guest/hals/camera/CameraConfiguration.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#include "CameraConfiguration.h"
-
-#define LOG_TAG "CameraConfiguration"
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <log/log.h>
-#include <json/json.h>
-#include <json/reader.h>
-#include <stdlib.h>
-
-namespace cvd {
-namespace {
-////////////////////// Device Personality keys //////////////////////
-//
-// **** Camera ****
-//
-// Example segment (transcribed to constants):
-//
-// kCameraDefinitionsKey: [
-//   {
-//     kCameraDefinitionOrientationKey: "front",
-//     kCameraDefinitionHalVersionKey: "1",
-//     kCameraDefinitionResolutionsKey: [
-//       {
-//         kCameraDefinitionResolutionWidthKey: "1600",
-//         kCameraDefinitionResolutionHeightKey: "1200",
-//       },
-//       {
-//         kCameraDefinitionResolutionWidthKey: "1280",
-//         kCameraDefinitionResolutionHeightKey: "800",
-//       }
-//     ]
-//   },
-//   {
-//     kCameraDefinitionOrientationKey: "back",
-//     kCameraDefinitionHalVersionKey: "1",
-//     kCameraDefinitionResolutionsKey: [
-//       {
-//         kCameraDefinitionResolutionWidthKey: "1024",
-//         kCameraDefinitionResolutionHeightKey: "768",
-//       },
-//       {
-//         kCameraDefinitionResolutionWidthKey: "800",
-//         kCameraDefinitionResolutionHeightKey: "600",
-//       }
-//     ]
-//   }
-// ]
-//
-
-// Location of the camera configuration files.
-const char* const kConfigurationFileLocation = "/vendor/etc/config/camera.json";
-
-//
-// Array of camera definitions for all cameras available on the device (array).
-// Top Level Key.
-const char* const kCameraDefinitionsKey = "camera_definitions";
-
-// Camera orientation of currently defined camera (string).
-// Currently supported values:
-// - "back",
-// - "front".
-const char* const kCameraDefinitionOrientationKey = "orientation";
-
-// Camera HAL version of currently defined camera (int).
-// Currently supported values:
-// - 1 (Camera HALv1)
-// - 2 (Camera HALv2)
-// - 3 (Camera HALv3)
-const char* const kCameraDefinitionHalVersionKey = "hal_version";
-
-// Array of resolutions supported by camera (array).
-const char* const kCameraDefinitionResolutionsKey = "resolutions";
-
-// Width of currently defined resolution (int).
-// Must be divisible by 8.
-const char* const kCameraDefinitionResolutionWidthKey = "width";
-
-// Height of currently defined resolution (int).
-// Must be divisible by 8.
-const char* const kCameraDefinitionResolutionHeightKey = "height";
-
-// Convert string value to camera orientation.
-bool ValueToCameraOrientation(const std::string& value,
-                              CameraDefinition::Orientation* orientation) {
-  if (value == "back") {
-    *orientation = CameraDefinition::kBack;
-    return true;
-  } else if (value == "front") {
-    *orientation = CameraDefinition::kFront;
-    return true;
-  }
-  ALOGE("%s: Invalid camera orientation: %s.", __FUNCTION__, value.c_str());
-  return false;
-}
-
-// Convert string value to camera HAL version.
-bool ValueToCameraHalVersion(const std::string& value,
-                             CameraDefinition::HalVersion* hal_version) {
-  int temp;
-  char* endptr;
-
-  temp = strtol(value.c_str(), &endptr, 10);
-  if (endptr != value.c_str() + value.size()) {
-    ALOGE("%s: Invalid camera HAL version. Expected number, got %s.",
-          __FUNCTION__, value.c_str());
-    return false;
-  }
-
-  switch (temp) {
-    case 1:
-      *hal_version = CameraDefinition::kHalV1;
-      break;
-
-    case 2:
-      *hal_version = CameraDefinition::kHalV2;
-      break;
-
-    case 3:
-      *hal_version = CameraDefinition::kHalV3;
-      break;
-
-    default:
-      ALOGE("%s: Invalid camera HAL version. Version %d not supported.",
-            __FUNCTION__, temp);
-      return false;
-  }
-
-  return true;
-}
-
-bool ValueToCameraResolution(const std::string& width,
-                             const std::string& height,
-                             CameraDefinition::Resolution* resolution) {
-  char* endptr;
-
-  resolution->width = strtol(width.c_str(), &endptr, 10);
-  if (endptr != width.c_str() + width.size()) {
-    ALOGE("%s: Invalid camera resolution width. Expected number, got %s.",
-          __FUNCTION__, width.c_str());
-    return false;
-  }
-
-  resolution->height = strtol(height.c_str(), &endptr, 10);
-  if (endptr != height.c_str() + height.size()) {
-    ALOGE("%s: Invalid camera resolution height. Expected number, got %s.",
-          __FUNCTION__, height.c_str());
-    return false;
-  }
-
-  // Validate width and height parameters are sane.
-  if (resolution->width <= 0 || resolution->height <= 0) {
-    ALOGE("%s: Invalid camera resolution: %dx%d", __FUNCTION__,
-          resolution->width, resolution->height);
-    return false;
-  }
-
-  // Validate width and height divisible by 8.
-  if ((resolution->width & 7) != 0 || (resolution->height & 7) != 0) {
-    ALOGE(
-        "%s: Invalid camera resolution: width and height must be "
-        "divisible by 8, got %dx%d (%dx%d).",
-        __FUNCTION__, resolution->width, resolution->height,
-        resolution->width & 7, resolution->height & 7);
-    return false;
-  }
-
-  return true;
-}
-
-// Process camera definitions.
-// Returns true, if definitions were sane.
-bool ConfigureCameras(const Json::Value& value,
-                      std::vector<CameraDefinition>* cameras) {
-  if (!value.isObject()) {
-    ALOGE("%s: Configuration root is not an object", __FUNCTION__);
-    return false;
-  }
-
-  if (!value.isMember(kCameraDefinitionsKey)) return true;
-  for (Json::ValueConstIterator iter = value[kCameraDefinitionsKey].begin();
-       iter != value[kCameraDefinitionsKey].end(); ++iter) {
-    cameras->push_back(CameraDefinition());
-    CameraDefinition& camera = cameras->back();
-
-    if (!iter->isObject()) {
-      ALOGE("%s: Camera definition is not an object", __FUNCTION__);
-      continue;
-    }
-
-    // Camera without orientation -> invalid setting.
-    if (!iter->isMember(kCameraDefinitionOrientationKey)) {
-      ALOGE("%s: Invalid camera definition: key %s is missing.", __FUNCTION__,
-            kCameraDefinitionOrientationKey);
-      return false;
-    }
-
-    if (!ValueToCameraOrientation(
-            (*iter)[kCameraDefinitionOrientationKey].asString(),
-            &camera.orientation))
-      return false;
-
-    // Camera without HAL version -> invalid setting.
-    if (!(*iter).isMember(kCameraDefinitionHalVersionKey)) {
-      ALOGE("%s: Invalid camera definition: key %s is missing.", __FUNCTION__,
-            kCameraDefinitionHalVersionKey);
-      return false;
-    }
-
-    if (!ValueToCameraHalVersion(
-            (*iter)[kCameraDefinitionHalVersionKey].asString(),
-            &camera.hal_version))
-      return false;
-
-    // Camera without resolutions -> invalid setting.
-    if (!iter->isMember(kCameraDefinitionResolutionsKey)) {
-      ALOGE("%s: Invalid camera definition: key %s is missing.", __FUNCTION__,
-            kCameraDefinitionResolutionsKey);
-      return false;
-    }
-
-    const Json::Value& json_resolutions =
-        (*iter)[kCameraDefinitionResolutionsKey];
-
-    // Resolutions not an array, or an empty array -> invalid setting.
-    if (!json_resolutions.isArray() || json_resolutions.empty()) {
-      ALOGE("%s: Invalid camera definition: %s is not an array or is empty.",
-            __FUNCTION__, kCameraDefinitionResolutionsKey);
-      return false;
-    }
-
-    // Process all resolutions.
-    for (Json::ValueConstIterator json_res_iter = json_resolutions.begin();
-         json_res_iter != json_resolutions.end(); ++json_res_iter) {
-      // Check presence of width and height keys.
-      if (!json_res_iter->isObject()) {
-        ALOGE("%s: Camera resolution item is not an object", __FUNCTION__);
-        continue;
-      }
-      if (!json_res_iter->isMember(kCameraDefinitionResolutionWidthKey) ||
-          !json_res_iter->isMember(kCameraDefinitionResolutionHeightKey)) {
-        ALOGE(
-            "%s: Invalid camera resolution: keys %s and %s are both required.",
-            __FUNCTION__, kCameraDefinitionResolutionWidthKey,
-            kCameraDefinitionResolutionHeightKey);
-        return false;
-      }
-
-      camera.resolutions.push_back(CameraDefinition::Resolution());
-      CameraDefinition::Resolution& resolution = camera.resolutions.back();
-
-      if (!ValueToCameraResolution(
-              (*json_res_iter)[kCameraDefinitionResolutionWidthKey].asString(),
-              (*json_res_iter)[kCameraDefinitionResolutionHeightKey].asString(),
-              &resolution))
-        return false;
-    }
-  }
-
-  return true;
-}
-}  // namespace
-
-bool CameraConfiguration::Init() {
-  cameras_.clear();
-  std::string config;
-  if (!android::base::ReadFileToString(kConfigurationFileLocation, &config)) {
-    ALOGE("%s: Could not open configuration file: %s", __FUNCTION__,
-          kConfigurationFileLocation);
-    return false;
-  }
-
-  Json::Reader config_reader;
-  Json::Value root;
-  if (!config_reader.parse(config, root)) {
-    ALOGE("Could not parse configuration file: %s",
-          config_reader.getFormattedErrorMessages().c_str());
-    return false;
-  }
-
-  return ConfigureCameras(root, &cameras_);
-}
-
-}  // namespace cvd
diff --git a/guest/hals/camera/CameraConfiguration.h b/guest/hals/camera/CameraConfiguration.h
deleted file mode 100644
index 983963b..0000000
--- a/guest/hals/camera/CameraConfiguration.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#ifndef GUEST_HALS_CAMERA_CAMERACONFIGURATION_H_
-#define GUEST_HALS_CAMERA_CAMERACONFIGURATION_H_
-
-#undef max
-#undef min
-#include <algorithm>
-#include <vector>
-
-namespace cvd {
-
-// Camera properties and features.
-struct CameraDefinition {
-  // Camera facing direction.
-  enum Orientation { kFront, kBack };
-
-  // Camera recognized HAL versions.
-  enum HalVersion { kHalV1, kHalV2, kHalV3 };
-
-  struct Resolution {
-    int width;
-    int height;
-  };
-
-  Orientation orientation;
-  HalVersion hal_version;
-  std::vector<Resolution> resolutions;
-};
-
-class CameraConfiguration {
- public:
-  CameraConfiguration() {}
-  ~CameraConfiguration() {}
-
-  const std::vector<CameraDefinition>& cameras() const { return cameras_; }
-
-  bool Init();
-
- private:
-  std::vector<CameraDefinition> cameras_;
-};
-
-}  // namespace cvd
-
-#endif  // GUEST_HALS_CAMERA_CAMERACONFIGURATION_H_
diff --git a/guest/hals/camera/Compressor.cpp b/guest/hals/camera/Compressor.cpp
deleted file mode 100644
index 3fe0bd6..0000000
--- a/guest/hals/camera/Compressor.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
-* Copyright (C) 2016 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.
- */
-
-#include "Compressor.h"
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_JPEGStub_Compressor"
-#include <log/log.h>
-#include <libexif/exif-data.h>
-
-Compressor::Compressor() {
-
-}
-
-bool Compressor::compress(const unsigned char* data,
-                          int width, int height, int quality,
-                          ExifData* exifData) {
-    if (!configureCompressor(width, height, quality)) {
-        // The method will have logged a more detailed error message than we can
-        // provide here so just return.
-        return false;
-    }
-
-    return compressData(data, exifData);
-}
-
-const std::vector<uint8_t>& Compressor::getCompressedData() const {
-    return mDestManager.mBuffer;
-}
-
-bool Compressor::configureCompressor(int width, int height, int quality) {
-    mCompressInfo.err = jpeg_std_error(&mErrorManager);
-    // NOTE! DANGER! Do not construct any non-trivial objects below setjmp!
-    // The compiler will not generate code to destroy them during the return
-    // below so they will leak. Additionally, do not place any calls to libjpeg
-    // that can fail above this line or any error will cause undefined behavior.
-    if (setjmp(mErrorManager.mJumpBuffer)) {
-        // This is where the error handler will jump in case setup fails
-        // The error manager will ALOG an appropriate error message
-        return false;
-    }
-
-    jpeg_create_compress(&mCompressInfo);
-
-    mCompressInfo.image_width = width;
-    mCompressInfo.image_height = height;
-    mCompressInfo.input_components = 3;
-    mCompressInfo.in_color_space = JCS_YCbCr;
-    jpeg_set_defaults(&mCompressInfo);
-
-    jpeg_set_quality(&mCompressInfo, quality, TRUE);
-    // It may seem weird to set color space here again but this will also set
-    // other fields. These fields might be overwritten by jpeg_set_defaults
-    jpeg_set_colorspace(&mCompressInfo, JCS_YCbCr);
-    mCompressInfo.raw_data_in = TRUE;
-    mCompressInfo.dct_method = JDCT_IFAST;
-    // Set sampling factors
-    mCompressInfo.comp_info[0].h_samp_factor = 2;
-    mCompressInfo.comp_info[0].v_samp_factor = 2;
-    mCompressInfo.comp_info[1].h_samp_factor = 1;
-    mCompressInfo.comp_info[1].v_samp_factor = 1;
-    mCompressInfo.comp_info[2].h_samp_factor = 1;
-    mCompressInfo.comp_info[2].v_samp_factor = 1;
-
-    mCompressInfo.dest = &mDestManager;
-
-    return true;
-}
-
-static void deinterleave(const uint8_t* vuPlanar, std::vector<uint8_t>& uRows,
-                         std::vector<uint8_t>& vRows, int rowIndex, int width,
-                         int height, int stride) {
-    int numRows = (height - rowIndex) / 2;
-    if (numRows > 8) numRows = 8;
-    for (int row = 0; row < numRows; ++row) {
-        int offset = ((rowIndex >> 1) + row) * stride;
-        const uint8_t* vu = vuPlanar + offset;
-        for (int i = 0; i < (width >> 1); ++i) {
-            int index = row * (width >> 1) + i;
-            uRows[index] = vu[1];
-            vRows[index] = vu[0];
-            vu += 2;
-        }
-    }
-}
-
-
-bool Compressor::compressData(const unsigned char* data, ExifData* exifData) {
-    const uint8_t* y[16];
-    const uint8_t* cb[8];
-    const uint8_t* cr[8];
-    const uint8_t** planes[3] = { y, cb, cr };
-
-    int i, offset;
-    int width = mCompressInfo.image_width;
-    int height = mCompressInfo.image_height;
-    const uint8_t* yPlanar = data;
-    const uint8_t* vuPlanar = data + (width * height);
-    std::vector<uint8_t> uRows(8 * (width >> 1));
-    std::vector<uint8_t> vRows(8 * (width >> 1));
-
-    // NOTE! DANGER! Do not construct any non-trivial objects below setjmp!
-    // The compiler will not generate code to destroy them during the return
-    // below so they will leak. Additionally, do not place any calls to libjpeg
-    // that can fail above this line or any error will cause undefined behavior.
-    if (setjmp(mErrorManager.mJumpBuffer)) {
-        // This is where the error handler will jump in case compression fails
-        // The error manager will ALOG an appropriate error message
-        return false;
-    }
-
-    jpeg_start_compress(&mCompressInfo, TRUE);
-
-    attachExifData(exifData);
-
-    // process 16 lines of Y and 8 lines of U/V each time.
-    while (mCompressInfo.next_scanline < mCompressInfo.image_height) {
-        //deinterleave u and v
-        deinterleave(vuPlanar, uRows, vRows, mCompressInfo.next_scanline,
-                     width, height, width);
-
-        // Jpeg library ignores the rows whose indices are greater than height.
-        for (i = 0; i < 16; i++) {
-            // y row
-            y[i] = yPlanar + (mCompressInfo.next_scanline + i) * width;
-
-            // construct u row and v row
-            if ((i & 1) == 0) {
-                // height and width are both halved because of downsampling
-                offset = (i >> 1) * (width >> 1);
-                cb[i/2] = &uRows[offset];
-                cr[i/2] = &vRows[offset];
-            }
-          }
-        jpeg_write_raw_data(&mCompressInfo, const_cast<JSAMPIMAGE>(planes), 16);
-    }
-
-    jpeg_finish_compress(&mCompressInfo);
-    jpeg_destroy_compress(&mCompressInfo);
-
-    return true;
-}
-
-bool Compressor::attachExifData(ExifData* exifData) {
-    if (exifData == nullptr) {
-        // This is not an error, we don't require EXIF data
-        return true;
-    }
-
-    // Save the EXIF data to memory
-    unsigned char* rawData = nullptr;
-    unsigned int size = 0;
-    exif_data_save_data(exifData, &rawData, &size);
-    if (rawData == nullptr) {
-        ALOGE("Failed to create EXIF data block");
-        return false;
-    }
-
-    jpeg_write_marker(&mCompressInfo, JPEG_APP0 + 1, rawData, size);
-    free(rawData);
-    return true;
-}
-
-Compressor::ErrorManager::ErrorManager() {
-    error_exit = &onJpegError;
-}
-
-void Compressor::ErrorManager::onJpegError(j_common_ptr cinfo) {
-    // NOTE! Do not construct any non-trivial objects in this method at the top
-    // scope. Their destructors will not be called. If you do need such an
-    // object create a local scope that does not include the longjmp call,
-    // that ensures the object is destroyed before longjmp is called.
-    ErrorManager* errorManager = reinterpret_cast<ErrorManager*>(cinfo->err);
-
-    // Format and log error message
-    char errorMessage[JMSG_LENGTH_MAX];
-    (*errorManager->format_message)(cinfo, errorMessage);
-    errorMessage[sizeof(errorMessage) - 1] = '\0';
-    ALOGE("JPEG compression error: %s", errorMessage);
-    jpeg_destroy(cinfo);
-
-    // And through the looking glass we go
-    longjmp(errorManager->mJumpBuffer, 1);
-}
-
-Compressor::DestinationManager::DestinationManager() {
-    init_destination = &initDestination;
-    empty_output_buffer = &emptyOutputBuffer;
-    term_destination = &termDestination;
-}
-
-void Compressor::DestinationManager::initDestination(j_compress_ptr cinfo) {
-    auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest);
-
-    // Start out with some arbitrary but not too large buffer size
-    manager->mBuffer.resize(16 * 1024);
-    manager->next_output_byte = &manager->mBuffer[0];
-    manager->free_in_buffer = manager->mBuffer.size();
-}
-
-boolean Compressor::DestinationManager::emptyOutputBuffer(
-        j_compress_ptr cinfo) {
-    auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest);
-
-    // Keep doubling the size of the buffer for a very low, amortized
-    // performance cost of the allocations
-    size_t oldSize = manager->mBuffer.size();
-    manager->mBuffer.resize(oldSize * 2);
-    manager->next_output_byte = &manager->mBuffer[oldSize];
-    manager->free_in_buffer = manager->mBuffer.size() - oldSize;
-    return manager->free_in_buffer != 0;
-}
-
-void Compressor::DestinationManager::termDestination(j_compress_ptr cinfo) {
-    auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest);
-
-    // Resize down to the exact size of the output, that is remove as many
-    // bytes as there are left in the buffer
-    manager->mBuffer.resize(manager->mBuffer.size() - manager->free_in_buffer);
-}
-
diff --git a/guest/hals/camera/Compressor.h b/guest/hals/camera/Compressor.h
deleted file mode 100644
index 10f5e80..0000000
--- a/guest/hals/camera/Compressor.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef CUTTLEFISH_CAMERA_JPEG_STUB_COMPRESSOR_H
-#define CUTTLEFISH_CAMERA_JPEG_STUB_COMPRESSOR_H
-
-#include <setjmp.h>
-#include <stdlib.h>
-extern "C" {
-#include <jpeglib.h>
-#include <jerror.h>
-}
-
-#include <vector>
-
-struct _ExifData;
-typedef _ExifData ExifData;
-
-class Compressor {
-public:
-    Compressor();
-
-    /* Compress |data| which represents raw NV21 encoded data of dimensions
-     * |width| * |height|. |exifData| is optional EXIF data that will be
-     * attached to the compressed data if present, set to null if not needed.
-     */
-    bool compress(const unsigned char* data,
-                  int width, int height, int quality,
-                  ExifData* exifData);
-
-    /* Get a reference to the compressed data, this will return an empty vector
-     * if compress has not been called yet
-     */
-    const std::vector<unsigned char>& getCompressedData() const;
-
-private:
-    struct DestinationManager : jpeg_destination_mgr {
-        DestinationManager();
-
-        static void initDestination(j_compress_ptr cinfo);
-        static boolean emptyOutputBuffer(j_compress_ptr cinfo);
-        static void termDestination(j_compress_ptr cinfo);
-
-        std::vector<unsigned char> mBuffer;
-    };
-    struct ErrorManager : jpeg_error_mgr {
-        ErrorManager();
-
-        static void onJpegError(j_common_ptr cinfo);
-
-        jmp_buf mJumpBuffer;
-    };
-
-    jpeg_compress_struct mCompressInfo;
-    DestinationManager mDestManager;
-    ErrorManager mErrorManager;
-
-    bool configureCompressor(int width, int height, int quality);
-    bool compressData(const unsigned char* data, ExifData* exifData);
-    bool attachExifData(ExifData* exifData);
-};
-
-#endif  // CUTTLEFISH_CAMERA_JPEG_STUB_COMPRESSOR_H
-
diff --git a/guest/hals/camera/Converters.cpp b/guest/hals/camera/Converters.cpp
deleted file mode 100644
index 7553d95..0000000
--- a/guest/hals/camera/Converters.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implemenation of framebuffer conversion routines.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Converter"
-#include "Converters.h"
-#include <log/log.h>
-
-namespace android {
-
-static void _YUV420SToRGB565(const uint8_t* Y, const uint8_t* U,
-                             const uint8_t* V, int dUV, uint16_t* rgb,
-                             int width, int height) {
-  const uint8_t* U_pos = U;
-  const uint8_t* V_pos = V;
-
-  for (int y = 0; y < height; y++) {
-    for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
-      const uint8_t nU = *U;
-      const uint8_t nV = *V;
-      *rgb = YUVToRGB565(*Y, nU, nV);
-      Y++;
-      rgb++;
-      *rgb = YUVToRGB565(*Y, nU, nV);
-      Y++;
-      rgb++;
-    }
-    if (y & 0x1) {
-      U_pos = U;
-      V_pos = V;
-    } else {
-      U = U_pos;
-      V = V_pos;
-    }
-  }
-}
-
-static void _YUV420SToRGB32(const uint8_t* Y, const uint8_t* U,
-                            const uint8_t* V, int dUV, uint32_t* rgb, int width,
-                            int height) {
-  const uint8_t* U_pos = U;
-  const uint8_t* V_pos = V;
-
-  for (int y = 0; y < height; y++) {
-    for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
-      const uint8_t nU = *U;
-      const uint8_t nV = *V;
-      *rgb = YUVToRGB32(*Y, nU, nV);
-      Y++;
-      rgb++;
-      *rgb = YUVToRGB32(*Y, nU, nV);
-      Y++;
-      rgb++;
-    }
-    if (y & 0x1) {
-      U_pos = U;
-      V_pos = V;
-    } else {
-      U = U_pos;
-      V = V_pos;
-    }
-  }
-}
-
-void YV12ToRGB565(const void* yv12, void* rgb, int width, int height) {
-  const int pix_total = width * height;
-  const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
-  const uint8_t* U = Y + pix_total;
-  const uint8_t* V = U + pix_total / 4;
-  _YUV420SToRGB565(Y, U, V, 1, reinterpret_cast<uint16_t*>(rgb), width, height);
-}
-
-void YV12ToRGB32(const void* yv12, void* rgb, int width, int height) {
-  const int pix_total = width * height;
-  const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
-  const uint8_t* V = Y + pix_total;
-  const uint8_t* U = V + pix_total / 4;
-  _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
-}
-
-void YU12ToRGB32(const void* yu12, void* rgb, int width, int height) {
-  const int pix_total = width * height;
-  const uint8_t* Y = reinterpret_cast<const uint8_t*>(yu12);
-  const uint8_t* U = Y + pix_total;
-  const uint8_t* V = U + pix_total / 4;
-  _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
-}
-
-/* Common converter for YUV 4:2:0 interleaved to RGB565.
- * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
- */
-static void _NVXXToRGB565(const uint8_t* Y, const uint8_t* U, const uint8_t* V,
-                          uint16_t* rgb, int width, int height) {
-  _YUV420SToRGB565(Y, U, V, 2, rgb, width, height);
-}
-
-/* Common converter for YUV 4:2:0 interleaved to RGB32.
- * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
- */
-static void _NVXXToRGB32(const uint8_t* Y, const uint8_t* U, const uint8_t* V,
-                         uint32_t* rgb, int width, int height) {
-  _YUV420SToRGB32(Y, U, V, 2, rgb, width, height);
-}
-
-void NV12ToRGB565(const void* nv12, void* rgb, int width, int height) {
-  const int pix_total = width * height;
-  const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
-  _NVXXToRGB565(y, y + pix_total, y + pix_total + 1,
-                reinterpret_cast<uint16_t*>(rgb), width, height);
-}
-
-void NV12ToRGB32(const void* nv12, void* rgb, int width, int height) {
-  const int pix_total = width * height;
-  const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
-  _NVXXToRGB32(y, y + pix_total, y + pix_total + 1,
-               reinterpret_cast<uint32_t*>(rgb), width, height);
-}
-
-void NV21ToRGB565(const void* nv21, void* rgb, int width, int height) {
-  const int pix_total = width * height;
-  const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
-  _NVXXToRGB565(y, y + pix_total + 1, y + pix_total,
-                reinterpret_cast<uint16_t*>(rgb), width, height);
-}
-
-void NV21ToRGB32(const void* nv21, void* rgb, int width, int height) {
-  const int pix_total = width * height;
-  const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
-  _NVXXToRGB32(y, y + pix_total + 1, y + pix_total,
-               reinterpret_cast<uint32_t*>(rgb), width, height);
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/Converters.h b/guest/hals/camera/Converters.h
deleted file mode 100644
index 9d7f6a9..0000000
--- a/guest/hals/camera/Converters.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_CONVERTERS_H
-#define HW_EMULATOR_CAMERA_CONVERTERS_H
-
-#include <endian.h>
-
-#ifndef __BYTE_ORDER
-#error "could not determine byte order"
-#endif
-
-/*
- * Contains declaration of framebuffer conversion routines.
- *
- * NOTE: RGB and big/little endian considerations. Wherewer in this code RGB
- * pixels are represented as WORD, or DWORD, the color order inside the
- * WORD / DWORD matches the one that would occur if that WORD / DWORD would have
- * been read from the typecasted framebuffer:
- *
- *      const uint32_t rgb = *reinterpret_cast<const uint32_t*>(framebuffer);
- *
- * So, if this code runs on the little endian CPU, red color in 'rgb' would be
- * masked as 0x000000ff, and blue color would be masked as 0x00ff0000, while if
- * the code runs on a big endian CPU, the red color in 'rgb' would be masked as
- * 0xff000000, and blue color would be masked as 0x0000ff00,
- */
-
-namespace android {
-
-/*
- * RGB565 color masks
- */
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-static const uint16_t kRed5 = 0x001f;
-static const uint16_t kGreen6 = 0x07e0;
-static const uint16_t kBlue5 = 0xf800;
-#else   // __BYTE_ORDER
-static const uint16_t kRed5 = 0xf800;
-static const uint16_t kGreen6 = 0x07e0;
-static const uint16_t kBlue5 = 0x001f;
-#endif  // __BYTE_ORDER
-static const uint32_t kBlack16 = 0x0000;
-static const uint32_t kWhite16 = kRed5 | kGreen6 | kBlue5;
-
-/*
- * RGB32 color masks
- */
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-static const uint32_t kRed8 = 0x000000ff;
-static const uint32_t kGreen8 = 0x0000ff00;
-static const uint32_t kBlue8 = 0x00ff0000;
-#else   // __BYTE_ORDER
-static const uint32_t kRed8 = 0x00ff0000;
-static const uint32_t kGreen8 = 0x0000ff00;
-static const uint32_t kBlue8 = 0x000000ff;
-#endif  // __BYTE_ORDER
-static const uint32_t kBlack32 = 0x00000000;
-static const uint32_t kWhite32 = kRed8 | kGreen8 | kBlue8;
-
-/*
- * Extracting, and saving color bytes from / to WORD / DWORD RGB.
- */
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-/* Extract red, green, and blue bytes from RGB565 word. */
-#define R16(rgb) static_cast<uint8_t>(rgb & kRed5)
-#define G16(rgb) static_cast<uint8_t>((rgb & kGreen6) >> 5)
-#define B16(rgb) static_cast<uint8_t>((rgb & kBlue5) >> 11)
-/* Make 8 bits red, green, and blue, extracted from RGB565 word. */
-#define R16_32(rgb) \
-  static_cast<uint8_t>(((rgb & kRed5) << 3) | ((rgb & kRed5) >> 2))
-#define G16_32(rgb) \
-  static_cast<uint8_t>(((rgb & kGreen6) >> 3) | ((rgb & kGreen6) >> 9))
-#define B16_32(rgb) \
-  static_cast<uint8_t>(((rgb & kBlue5) >> 8) | ((rgb & kBlue5) >> 14))
-/* Extract red, green, and blue bytes from RGB32 dword. */
-#define R32(rgb) static_cast<uint8_t>(rgb & kRed8)
-#define G32(rgb) static_cast<uint8_t>(((rgb & kGreen8) >> 8) & 0xff)
-#define B32(rgb) static_cast<uint8_t>(((rgb & kBlue8) >> 16) & 0xff)
-/* Build RGB565 word from red, green, and blue bytes. */
-#define RGB565(r, g, b) \
-  static_cast<uint16_t>((((static_cast<uint16_t>(b) << 6) | g) << 5) | r)
-/* Build RGB32 dword from red, green, and blue bytes. */
-#define RGB32(r, g, b) \
-  static_cast<uint32_t>((((static_cast<uint32_t>(b) << 8) | g) << 8) | r)
-#else  // __BYTE_ORDER
-/* Extract red, green, and blue bytes from RGB565 word. */
-#define R16(rgb) static_cast<uint8_t>((rgb & kRed5) >> 11)
-#define G16(rgb) static_cast<uint8_t>((rgb & kGreen6) >> 5)
-#define B16(rgb) static_cast<uint8_t>(rgb & kBlue5)
-/* Make 8 bits red, green, and blue, extracted from RGB565 word. */
-#define R16_32(rgb) \
-  static_cast<uint8_t>(((rgb & kRed5) >> 8) | ((rgb & kRed5) >> 14))
-#define G16_32(rgb) \
-  static_cast<uint8_t>(((rgb & kGreen6) >> 3) | ((rgb & kGreen6) >> 9))
-#define B16_32(rgb) \
-  static_cast<uint8_t>(((rgb & kBlue5) << 3) | ((rgb & kBlue5) >> 2))
-/* Extract red, green, and blue bytes from RGB32 dword. */
-#define R32(rgb) static_cast<uint8_t>((rgb & kRed8) >> 16)
-#define G32(rgb) static_cast<uint8_t>((rgb & kGreen8) >> 8)
-#define B32(rgb) static_cast<uint8_t>(rgb & kBlue8)
-/* Build RGB565 word from red, green, and blue bytes. */
-#define RGB565(r, g, b) \
-  static_cast<uint16_t>((((static_cast<uint16_t>(r) << 6) | g) << 5) | b)
-/* Build RGB32 dword from red, green, and blue bytes. */
-#define RGB32(r, g, b) \
-  static_cast<uint32_t>((((static_cast<uint32_t>(r) << 8) | g) << 8) | b)
-#endif  // __BYTE_ORDER
-
-/* An union that simplifies breaking 32 bit RGB into separate R, G, and B
- * colors.
- */
-typedef union RGB32_t {
-  uint32_t color;
-  struct {
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-    uint8_t r;
-    uint8_t g;
-    uint8_t b;
-    uint8_t a;
-#else   // __BYTE_ORDER
-    uint8_t a;
-    uint8_t b;
-    uint8_t g;
-    uint8_t r;
-#endif  // __BYTE_ORDER
-  };
-} RGB32_t;
-
-/* Clips a value to the unsigned 0-255 range, treating negative values as zero.
- */
-static __inline__ int clamp(int x) {
-  if (x > 255) return 255;
-  if (x < 0) return 0;
-  return x;
-}
-
-/********************************************************************************
- * Basics of RGB -> YUV conversion
- *******************************************************************************/
-
-/*
- * RGB -> YUV conversion macros
- */
-#define RGB2Y(r, g, b) \
-  (uint8_t)(((66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16)
-#define RGB2U(r, g, b) \
-  (uint8_t)(((-38 * (r)-74 * (g) + 112 * (b) + 128) >> 8) + 128)
-#define RGB2V(r, g, b) \
-  (uint8_t)(((112 * (r)-94 * (g)-18 * (b) + 128) >> 8) + 128)
-
-/* Converts R8 G8 B8 color to YUV. */
-static __inline__ void R8G8B8ToYUV(uint8_t r, uint8_t g, uint8_t b, uint8_t* y,
-                                   uint8_t* u, uint8_t* v) {
-  *y = RGB2Y((int)r, (int)g, (int)b);
-  *u = RGB2U((int)r, (int)g, (int)b);
-  *v = RGB2V((int)r, (int)g, (int)b);
-}
-
-/* Converts RGB565 color to YUV. */
-static __inline__ void RGB565ToYUV(uint16_t rgb, uint8_t* y, uint8_t* u,
-                                   uint8_t* v) {
-  R8G8B8ToYUV(R16_32(rgb), G16_32(rgb), B16_32(rgb), y, u, v);
-}
-
-/* Converts RGB32 color to YUV. */
-static __inline__ void RGB32ToYUV(uint32_t rgb, uint8_t* y, uint8_t* u,
-                                  uint8_t* v) {
-  RGB32_t rgb_c;
-  rgb_c.color = rgb;
-  R8G8B8ToYUV(rgb_c.r, rgb_c.g, rgb_c.b, y, u, v);
-}
-
-/********************************************************************************
- * Basics of YUV -> RGB conversion.
- * Note that due to the fact that guest uses RGB only on preview window, and the
- * RGB format that is used is RGB565, we can limit YUV -> RGB conversions to
- * RGB565 only.
- *******************************************************************************/
-
-/*
- * YUV -> RGB conversion macros
- */
-
-/* "Optimized" macros that take specialy prepared Y, U, and V values:
- *  C = Y - 16
- *  D = U - 128
- *  E = V - 128
- */
-#define YUV2RO(C, D, E) clamp((298 * (C) + 409 * (E) + 128) >> 8)
-#define YUV2GO(C, D, E) clamp((298 * (C)-100 * (D)-208 * (E) + 128) >> 8)
-#define YUV2BO(C, D, E) clamp((298 * (C) + 516 * (D) + 128) >> 8)
-
-/*
- *  Main macros that take the original Y, U, and V values
- */
-#define YUV2R(y, u, v) clamp((298 * ((y)-16) + 409 * ((v)-128) + 128) >> 8)
-#define YUV2G(y, u, v) \
-  clamp((298 * ((y)-16) - 100 * ((u)-128) - 208 * ((v)-128) + 128) >> 8)
-#define YUV2B(y, u, v) clamp((298 * ((y)-16) + 516 * ((u)-128) + 128) >> 8)
-
-/* Converts YUV color to RGB565. */
-static __inline__ uint16_t YUVToRGB565(int y, int u, int v) {
-  /* Calculate C, D, and E values for the optimized macro. */
-  y -= 16;
-  u -= 128;
-  v -= 128;
-  const uint16_t r = (YUV2RO(y, u, v) >> 3) & 0x1f;
-  const uint16_t g = (YUV2GO(y, u, v) >> 2) & 0x3f;
-  const uint16_t b = (YUV2BO(y, u, v) >> 3) & 0x1f;
-  return RGB565(r, g, b);
-}
-
-/* Converts YUV color to RGB32. */
-static __inline__ uint32_t YUVToRGB32(int y, int u, int v) {
-  /* Calculate C, D, and E values for the optimized macro. */
-  y -= 16;
-  u -= 128;
-  v -= 128;
-  RGB32_t rgb;
-  rgb.r = YUV2RO(y, u, v) & 0xff;
-  rgb.g = YUV2GO(y, u, v) & 0xff;
-  rgb.b = YUV2BO(y, u, v) & 0xff;
-  return rgb.color;
-}
-
-/* YUV pixel descriptor. */
-struct YUVPixel {
-  uint8_t Y;
-  uint8_t U;
-  uint8_t V;
-
-  inline YUVPixel() : Y(0), U(0), V(0) {}
-
-  inline explicit YUVPixel(uint16_t rgb565) { RGB565ToYUV(rgb565, &Y, &U, &V); }
-
-  inline explicit YUVPixel(uint32_t rgb32) { RGB32ToYUV(rgb32, &Y, &U, &V); }
-
-  inline void get(uint8_t* pY, uint8_t* pU, uint8_t* pV) const {
-    *pY = Y;
-    *pU = U;
-    *pV = V;
-  }
-};
-
-/* Converts an YV12 framebuffer to RGB565 framebuffer.
- * Param:
- *  yv12 - YV12 framebuffer.
- *  rgb - RGB565 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void YV12ToRGB565(const void* yv12, void* rgb, int width, int height);
-
-/* Converts an YV12 framebuffer to RGB32 framebuffer.
- * Param:
- *  yv12 - YV12 framebuffer.
- *  rgb - RGB32 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void YV12ToRGB32(const void* yv12, void* rgb, int width, int height);
-
-/* Converts an YU12 framebuffer to RGB32 framebuffer.
- * Param:
- *  yu12 - YU12 framebuffer.
- *  rgb - RGB32 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void YU12ToRGB32(const void* yu12, void* rgb, int width, int height);
-
-/* Converts an NV12 framebuffer to RGB565 framebuffer.
- * Param:
- *  nv12 - NV12 framebuffer.
- *  rgb - RGB565 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void NV12ToRGB565(const void* nv12, void* rgb, int width, int height);
-
-/* Converts an NV12 framebuffer to RGB32 framebuffer.
- * Param:
- *  nv12 - NV12 framebuffer.
- *  rgb - RGB32 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void NV12ToRGB32(const void* nv12, void* rgb, int width, int height);
-
-/* Converts an NV21 framebuffer to RGB565 framebuffer.
- * Param:
- *  nv21 - NV21 framebuffer.
- *  rgb - RGB565 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void NV21ToRGB565(const void* nv21, void* rgb, int width, int height);
-
-/* Converts an NV21 framebuffer to RGB32 framebuffer.
- * Param:
- *  nv21 - NV21 framebuffer.
- *  rgb - RGB32 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void NV21ToRGB32(const void* nv21, void* rgb, int width, int height);
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_CONVERTERS_H */
diff --git a/guest/hals/camera/EmulatedBaseCamera.cpp b/guest/hals/camera/EmulatedBaseCamera.cpp
deleted file mode 100644
index 8ef553a..0000000
--- a/guest/hals/camera/EmulatedBaseCamera.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/*
- * Contains implementation of a class EmulatedBaseCamera that encapsulates
- * functionality common to all emulated camera device versions ("fake",
- * "webcam", "video file", "cam2.0" etc.).  Instances of this class (for each
- * emulated camera) are created during the construction of the
- * EmulatedCameraFactory instance.  This class serves as an entry point for all
- * camera API calls that are common across all versions of the
- * camera_device_t/camera_module_t structures.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_BaseCamera"
-#include <log/log.h>
-
-#include "EmulatedBaseCamera.h"
-
-namespace android {
-
-EmulatedBaseCamera::EmulatedBaseCamera(int cameraId, uint32_t cameraVersion,
-                                       struct hw_device_t* device,
-                                       struct hw_module_t* module)
-    : mCameraInfo(NULL),
-      mCameraID(cameraId),
-      mCameraDeviceVersion(cameraVersion) {
-  /*
-   * Initialize camera_device descriptor for this object.
-   */
-
-  /* Common header */
-  device->tag = HARDWARE_DEVICE_TAG;
-  device->version = cameraVersion;
-  device->module = module;
-  device->close = NULL;  // Must be filled in by child implementation
-}
-
-EmulatedBaseCamera::~EmulatedBaseCamera() {}
-
-status_t EmulatedBaseCamera::getCameraInfo(struct camera_info* info) {
-  ALOGV("%s", __FUNCTION__);
-
-  info->device_version = mCameraDeviceVersion;
-  if (mCameraDeviceVersion >= HARDWARE_DEVICE_API_VERSION(2, 0)) {
-    info->static_camera_characteristics = mCameraInfo;
-  } else {
-    info->static_camera_characteristics = (camera_metadata_t*)0xcafef00d;
-  }
-
-  return NO_ERROR;
-}
-
-status_t EmulatedBaseCamera::plugCamera() {
-  ALOGE("%s: not supported", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-status_t EmulatedBaseCamera::unplugCamera() {
-  ALOGE("%s: not supported", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-camera_device_status_t EmulatedBaseCamera::getHotplugStatus() {
-  return CAMERA_DEVICE_STATUS_PRESENT;
-}
-
-status_t EmulatedBaseCamera::setTorchMode(bool /* enabled */) {
-  ALOGE("%s: not supported", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-} /* namespace android */
diff --git a/guest/hals/camera/EmulatedBaseCamera.h b/guest/hals/camera/EmulatedBaseCamera.h
deleted file mode 100644
index ba4b98e..0000000
--- a/guest/hals/camera/EmulatedBaseCamera.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_BASE_CAMERA_H
-#define HW_EMULATOR_CAMERA_EMULATED_BASE_CAMERA_H
-
-#include <hardware/camera_common.h>
-#include <utils/Errors.h>
-#include "CameraConfiguration.h"
-#include <CameraParameters.h>
-using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
-
-namespace android {
-
-/*
- * Contains declaration of a class EmulatedBaseCamera that encapsulates
- * functionality common to all emulated camera device versions ("fake",
- * "webcam", "video file", etc.).  Instances of this class (for each emulated
- * camera) are created during the construction of the EmulatedCameraFactory
- * instance.  This class serves as an entry point for all camera API calls that
- * are common across all versions of the camera_device_t/camera_module_t
- * structures.
- */
-
-class EmulatedBaseCamera {
- public:
-  EmulatedBaseCamera(int cameraId, uint32_t cameraVersion,
-                     struct hw_device_t* device, struct hw_module_t* module);
-
-  virtual ~EmulatedBaseCamera();
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  /* Initializes EmulatedCamera instance.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  virtual status_t Initialize(const cvd::CameraDefinition& params) = 0;
-
-  /****************************************************************************
-   * Camera API implementation
-   ***************************************************************************/
-
- public:
-  /* Creates connection to the emulated camera device.
-   * This method is called in response to hw_module_methods_t::open callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negative EXXX statuses.
-   */
-  virtual status_t connectCamera(hw_device_t** device) = 0;
-
-  /* Plug the connection for the emulated camera. Until it's plugged in
-   * calls to connectCamera should fail with -ENODEV.
-   */
-  virtual status_t plugCamera();
-
-  /* Unplug the connection from underneath the emulated camera.
-   * This is similar to closing the camera, except that
-   * all function calls into the camera device will return
-   * -EPIPE errors until the camera is reopened.
-   */
-  virtual status_t unplugCamera();
-
-  virtual camera_device_status_t getHotplugStatus();
-
-  /* Closes connection to the emulated camera.
-   * This method is called in response to camera_device::close callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negative EXXX statuses.
-   */
-  virtual status_t closeCamera() = 0;
-
-  /* Gets camera information.
-   * This method is called in response to camera_module_t::get_camera_info
-   * callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negative EXXX statuses.
-   */
-  virtual status_t getCameraInfo(struct camera_info* info) = 0;
-
-  /* Gets camera parameters.
-   * This method is called to collect metadata for (currently) taken picture.
-   */
-  virtual const CameraParameters* getCameraParameters() {
-      return NULL;
-  }
-
-  /* Set torch mode.
-   * This method is called in response to camera_module_t::set_torch_mode
-   * callback.
-   */
-  virtual status_t setTorchMode(bool enabled);
-
-  /****************************************************************************
-   * Data members
-   ***************************************************************************/
-
- protected:
-  /* Fixed camera information for camera2 devices. Must be valid to access if
-   * mCameraDeviceVersion is >= HARDWARE_DEVICE_API_VERSION(2,0)  */
-  camera_metadata_t* mCameraInfo;
-
-  /* Zero-based ID assigned to this camera. */
-  int mCameraID;
-
- private:
-  /* Version of the camera device HAL implemented by this camera */
-  int mCameraDeviceVersion;
-};
-
-} /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_BASE_CAMERA_H */
diff --git a/guest/hals/camera/EmulatedCamera.cpp b/guest/hals/camera/EmulatedCamera.cpp
deleted file mode 100644
index e48d579..0000000
--- a/guest/hals/camera/EmulatedCamera.cpp
+++ /dev/null
@@ -1,1034 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class EmulatedCamera that encapsulates
- * functionality common to all emulated cameras ("fake", "webcam", "video file",
- * etc.). Instances of this class (for each emulated camera) are created during
- * the construction of the EmulatedCameraFactory instance. This class serves as
- * an entry point for all camera API calls that defined by camera_device_ops_t
- * API.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Camera"
-#include <log/log.h>
-#include "EmulatedCamera.h"
-//#include "EmulatedFakeCameraDevice.h"
-#include "Converters.h"
-
-/* Defines whether we should trace parameter changes. */
-#define DEBUG_PARAM 1
-
-namespace android {
-namespace {
-const char* kSupportedFlashModes[] = {
-    CameraParameters::FLASH_MODE_OFF,   CameraParameters::FLASH_MODE_AUTO,
-    CameraParameters::FLASH_MODE_ON,    CameraParameters::FLASH_MODE_RED_EYE,
-    CameraParameters::FLASH_MODE_TORCH, NULL};
-
-std::string BuildParameterValue(const char** value_array) {
-  std::string result;
-
-  for (int index = 0; value_array[index] != NULL; ++index) {
-    if (index) result.append(",");
-    result.append(value_array[index]);
-  }
-  return result;
-}
-
-bool CheckParameterValue(const char* value, const char** supported_values) {
-  for (int index = 0; supported_values[index] != NULL; ++index) {
-    if (!strcmp(value, supported_values[index])) return true;
-  }
-  return false;
-}
-
-}  // namespace
-
-#if DEBUG_PARAM
-/* Calculates and logs parameter changes.
- * Param:
- *  current - Current set of camera parameters.
- *  new_par - String representation of new parameters.
- */
-static void PrintParamDiff(const CameraParameters& current,
-                           const char* new_par);
-#else
-#define PrintParamDiff(current, new_par) (void(0))
-#endif /* DEBUG_PARAM */
-
-EmulatedCamera::EmulatedCamera(int cameraId, struct hw_module_t* module)
-    : EmulatedBaseCamera(cameraId, HARDWARE_DEVICE_API_VERSION(1, 0), &common,
-                         module),
-      mPreviewWindow(),
-      mCallbackNotifier() {
-  /* camera_device v1 fields. */
-  common.close = EmulatedCamera::close;
-  ops = &mDeviceOps;
-  priv = this;
-}
-
-EmulatedCamera::~EmulatedCamera() {}
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-status_t EmulatedCamera::Initialize(const cvd::CameraDefinition&) {
-  /* Preview formats supported by this HAL. */
-  char preview_formats[1024];
-  snprintf(preview_formats, sizeof(preview_formats), "%s,%s,%s",
-           CameraParameters::PIXEL_FORMAT_YUV420SP,
-           CameraParameters::PIXEL_FORMAT_YUV420P,
-           CameraParameters::PIXEL_FORMAT_RGBA8888);
-
-  /*
-   * Fake required parameters.
-   */
-
-  mParameters.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES,
-                  "320x240,0x0");
-
-  mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "512");
-  mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "384");
-  mParameters.set(CameraParameters::KEY_JPEG_QUALITY, "90");
-  mParameters.set(CameraParameters::KEY_FOCAL_LENGTH, "4.31");
-  mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "54.8");
-  mParameters.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "42.5");
-  mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "90");
-
-  /* Preview format settings used here are related to panoramic view only. It's
-   * not related to the preview window that works only with RGB frames, which
-   * is explicitly stated when set_buffers_geometry is called on the preview
-   * window object. */
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
-                  preview_formats);
-  mParameters.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
-
-  /* We don't relay on the actual frame rates supported by the camera device,
-   * since we will emulate them through timeouts in the emulated camera device
-   * worker thread. */
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
-                  "30,24,20,15,10,5");
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
-                  "(5000,30000),(15000,15000),(30000,30000)");
-  mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "5000,30000");
-  mParameters.setPreviewFrameRate(30000);
-
-  /* Only PIXEL_FORMAT_YUV420P is accepted by video framework in emulator! */
-  mParameters.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
-                  CameraParameters::PIXEL_FORMAT_YUV420P);
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
-                  CameraParameters::PIXEL_FORMAT_JPEG);
-  mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
-
-  /* Set exposure compensation. */
-  mParameters.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, "6");
-  mParameters.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, "-6");
-  mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, "0.5");
-  mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, "0");
-
-  /* Sets the white balance modes and the device-dependent scale factors. */
-  char supported_white_balance[1024];
-  snprintf(supported_white_balance, sizeof(supported_white_balance),
-           "%s,%s,%s,%s", CameraParameters::WHITE_BALANCE_AUTO,
-           CameraParameters::WHITE_BALANCE_INCANDESCENT,
-           CameraParameters::WHITE_BALANCE_DAYLIGHT,
-           CameraParameters::WHITE_BALANCE_TWILIGHT);
-  mParameters.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
-                  supported_white_balance);
-  mParameters.set(CameraParameters::KEY_WHITE_BALANCE,
-                  CameraParameters::WHITE_BALANCE_AUTO);
-  getCameraDevice()->initializeWhiteBalanceModes(
-      CameraParameters::WHITE_BALANCE_AUTO, 1.0f, 1.0f);
-  getCameraDevice()->initializeWhiteBalanceModes(
-      CameraParameters::WHITE_BALANCE_INCANDESCENT, 1.38f, 0.60f);
-  getCameraDevice()->initializeWhiteBalanceModes(
-      CameraParameters::WHITE_BALANCE_DAYLIGHT, 1.09f, 0.92f);
-  getCameraDevice()->initializeWhiteBalanceModes(
-      CameraParameters::WHITE_BALANCE_TWILIGHT, 0.92f, 1.22f);
-  getCameraDevice()->setWhiteBalanceMode(CameraParameters::WHITE_BALANCE_AUTO);
-
-  /*
-   * Not supported features
-   */
-  mParameters.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
-                  CameraParameters::FOCUS_MODE_FIXED);
-  mParameters.set(CameraParameters::KEY_FOCUS_MODE,
-                  CameraParameters::FOCUS_MODE_FIXED);
-  mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
-                  BuildParameterValue(kSupportedFlashModes).c_str());
-  mParameters.set(CameraParameters::KEY_FLASH_MODE,
-                  CameraParameters::FLASH_MODE_OFF);
-  mParameters.set(CameraParameters::KEY_FOCUS_DISTANCES, "0.1,0.1,0.1");
-  mParameters.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW, "0");
-  mParameters.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW, "0");
-  mParameters.set(CameraParameters::KEY_ZOOM_RATIOS, "100");
-  mParameters.set(CameraParameters::KEY_ZOOM_SUPPORTED,
-                  CameraParameters::FALSE);
-  mParameters.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED,
-                  CameraParameters::FALSE);
-  mParameters.set(CameraParameters::KEY_ZOOM, "0");
-  mParameters.set(CameraParameters::KEY_MAX_ZOOM, "0");
-
-  return NO_ERROR;
-}
-
-void EmulatedCamera::onNextFrameAvailable(const void* frame, nsecs_t timestamp,
-                                          EmulatedCameraDevice* camera_dev) {
-  /* Notify the preview window first. */
-  mPreviewWindow.onNextFrameAvailable(frame, timestamp, camera_dev);
-
-  /* Notify callback notifier next. */
-  mCallbackNotifier.onNextFrameAvailable(frame, timestamp, camera_dev);
-}
-
-void EmulatedCamera::onCameraDeviceError(int err) {
-  /* Errors are reported through the callback notifier */
-  mCallbackNotifier.onCameraDeviceError(err);
-}
-
-void EmulatedCamera::onCameraFocusAcquired() {
-  mCallbackNotifier.onCameraFocusAcquired();
-}
-
-/****************************************************************************
- * Camera API implementation.
- ***************************************************************************/
-
-status_t EmulatedCamera::connectCamera(hw_device_t** device) {
-  ALOGV("%s", __FUNCTION__);
-
-  status_t res = EINVAL;
-  EmulatedCameraDevice* const camera_dev = getCameraDevice();
-  ALOGE_IF(camera_dev == NULL, "%s: No camera device instance.", __FUNCTION__);
-
-  if (camera_dev != NULL) {
-    /* Connect to the camera device. */
-    res = getCameraDevice()->connectDevice();
-    if (res == NO_ERROR) {
-      *device = &common;
-    }
-  }
-
-  return -res;
-}
-
-status_t EmulatedCamera::closeCamera() {
-  ALOGV("%s", __FUNCTION__);
-
-  return cleanupCamera();
-}
-
-status_t EmulatedCamera::getCameraInfo(struct camera_info* info) {
-  ALOGV("%s", __FUNCTION__);
-
-  const char* valstr = NULL;
-
-  valstr = mParameters.get(EmulatedCamera::FACING_KEY);
-  if (valstr != NULL) {
-    if (strcmp(valstr, EmulatedCamera::FACING_FRONT) == 0) {
-      info->facing = CAMERA_FACING_FRONT;
-    } else if (strcmp(valstr, EmulatedCamera::FACING_BACK) == 0) {
-      info->facing = CAMERA_FACING_BACK;
-    }
-  } else {
-    info->facing = CAMERA_FACING_BACK;
-  }
-
-  valstr = mParameters.get(EmulatedCamera::ORIENTATION_KEY);
-  if (valstr != NULL) {
-    info->orientation = atoi(valstr);
-  } else {
-    info->orientation = 0;
-  }
-
-  info->resource_cost = 100;
-  info->conflicting_devices = NULL;
-  info->conflicting_devices_length = 0;
-
-  return EmulatedBaseCamera::getCameraInfo(info);
-}
-
-const CameraParameters* EmulatedCamera::getCameraParameters() {
-  return &mParameters;
-}
-
-status_t EmulatedCamera::setPreviewWindow(struct preview_stream_ops* window) {
-  /* Callback should return a negative errno. */
-  return -mPreviewWindow.setPreviewWindow(window,
-                                          mParameters.getPreviewFrameRate());
-}
-
-void EmulatedCamera::setCallbacks(
-    camera_notify_callback notify_cb, camera_data_callback data_cb,
-    camera_data_timestamp_callback data_cb_timestamp,
-    camera_request_memory get_memory, void* user) {
-  mCallbackNotifier.setCallbacks(notify_cb, data_cb, data_cb_timestamp,
-                                 get_memory, user);
-}
-
-void EmulatedCamera::enableMsgType(int32_t msg_type) {
-  mCallbackNotifier.enableMessage(msg_type);
-}
-
-void EmulatedCamera::disableMsgType(int32_t msg_type) {
-  mCallbackNotifier.disableMessage(msg_type);
-}
-
-int EmulatedCamera::isMsgTypeEnabled(int32_t msg_type) {
-  return mCallbackNotifier.isMessageEnabled(msg_type);
-}
-
-status_t EmulatedCamera::startPreview() {
-  /* Callback should return a negative errno. */
-  return -doStartPreview();
-}
-
-void EmulatedCamera::stopPreview() { doStopPreview(); }
-
-int EmulatedCamera::isPreviewEnabled() {
-  return mPreviewWindow.isPreviewEnabled();
-}
-
-status_t EmulatedCamera::storeMetaDataInBuffers(int enable) {
-  /* Callback should return a negative errno. */
-  return -mCallbackNotifier.storeMetaDataInBuffers(enable);
-}
-
-status_t EmulatedCamera::startRecording() {
-  /* Callback should return a negative errno. */
-  return -mCallbackNotifier.enableVideoRecording(
-      mParameters.getPreviewFrameRate());
-}
-
-void EmulatedCamera::stopRecording() {
-  mCallbackNotifier.disableVideoRecording();
-}
-
-int EmulatedCamera::isRecordingEnabled() {
-  return mCallbackNotifier.isVideoRecordingEnabled();
-}
-
-void EmulatedCamera::releaseRecordingFrame(const void* opaque) {
-  mCallbackNotifier.releaseRecordingFrame(opaque);
-}
-
-status_t EmulatedCamera::setAutoFocus() {
-  ALOGV("%s", __FUNCTION__);
-
-  /* Trigger auto-focus. Focus response cannot be sent directly from here. */
-  getCameraDevice()->startAutoFocus();
-
-  /* TODO: Future enhancements. */
-  return NO_ERROR;
-}
-
-status_t EmulatedCamera::cancelAutoFocus() {
-  ALOGV("%s", __FUNCTION__);
-
-  /* TODO: Future enhancements. */
-  return NO_ERROR;
-}
-
-status_t EmulatedCamera::takePicture() {
-  ALOGV("%s", __FUNCTION__);
-
-  status_t res;
-  int width, height;
-  uint32_t org_fmt;
-
-  /* Collect frame info for the picture. */
-  mParameters.getPictureSize(&width, &height);
-  const char* pix_fmt = mParameters.getPictureFormat();
-  if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
-    org_fmt = V4L2_PIX_FMT_YUV420;
-  } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
-    org_fmt = V4L2_PIX_FMT_RGB32;
-  } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
-    org_fmt = V4L2_PIX_FMT_NV21;
-  } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_JPEG) == 0) {
-    /* We only have JPEG converted for NV21 format. */
-    org_fmt = V4L2_PIX_FMT_NV21;
-  } else {
-    ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
-    return EINVAL;
-  }
-  /* Get JPEG quality. */
-  int jpeg_quality = mParameters.getInt(CameraParameters::KEY_JPEG_QUALITY);
-  if (jpeg_quality <= 0) {
-    jpeg_quality = 90; /* Fall back to default. */
-  }
-
-  /*
-   * Make sure preview is not running, and device is stopped before taking
-   * picture.
-   */
-
-  const bool preview_on = mPreviewWindow.isPreviewEnabled();
-  if (preview_on) {
-    doStopPreview();
-  }
-
-  /* Camera device should have been stopped when the shutter message has been
-   * enabled. */
-  EmulatedCameraDevice* const camera_dev = getCameraDevice();
-  if (camera_dev->isStarted()) {
-    ALOGW("%s: Camera device is started", __FUNCTION__);
-    camera_dev->stopDeliveringFrames();
-    camera_dev->stopDevice();
-  }
-
-  /* Compute target FPS rate.
-   * Pretend to simulate generation of (max_fps_rate) */
-  int min_fps_rate, max_fps_rate;
-  mParameters.getPreviewFpsRange(&min_fps_rate, &max_fps_rate);
-
-  /*
-   * Take the picture now.
-   */
-
-  /* Start camera device for the picture frame. */
-  ALOGD("Starting camera for picture: %.4s(%s)[%dx%d]",
-        reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
-  res = camera_dev->startDevice(width, height, org_fmt, max_fps_rate);
-  if (res != NO_ERROR) {
-    if (preview_on) {
-      doStartPreview();
-    }
-    return res;
-  }
-
-  /* Deliver one frame only. */
-  mCallbackNotifier.setJpegQuality(jpeg_quality);
-  mCallbackNotifier.setTakingPicture(true);
-  res = camera_dev->startDeliveringFrames(true);
-  if (res != NO_ERROR) {
-    mCallbackNotifier.setTakingPicture(false);
-    if (preview_on) {
-      doStartPreview();
-    }
-  }
-  return res;
-}
-
-status_t EmulatedCamera::cancelPicture() {
-  ALOGV("%s", __FUNCTION__);
-
-  return NO_ERROR;
-}
-
-status_t EmulatedCamera::setParameters(const char* parms) {
-  ALOGV("%s", __FUNCTION__);
-  PrintParamDiff(mParameters, parms);
-
-  CameraParameters new_param;
-  String8 str8_param(parms);
-  new_param.unflatten(str8_param);
-
-  /*
-   * Check if requested dimensions are valid.
-   */
-  if (!CheckParameterValue(new_param.get(CameraParameters::KEY_FLASH_MODE),
-                           kSupportedFlashModes)) {
-    ALOGE("%s: Unsupported flash mode: %s", __FUNCTION__,
-          new_param.get(CameraParameters::KEY_FLASH_MODE));
-    return -EINVAL;
-  }
-  if (strcmp(new_param.get(CameraParameters::KEY_FOCUS_MODE),
-             CameraParameters::FOCUS_MODE_FIXED)) {
-    ALOGE("%s: Unsupported flash mode: %s", __FUNCTION__,
-          new_param.get(CameraParameters::KEY_FOCUS_MODE));
-    return -EINVAL;
-  }
-
-  int preview_width, preview_height;
-  new_param.getPreviewSize(&preview_width, &preview_height);
-  if (preview_width <= 0 || preview_height <= 0) return -EINVAL;
-
-  /*
-   * Check for new exposure compensation parameter.
-   */
-  int new_exposure_compensation =
-      new_param.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION);
-  const int min_exposure_compensation =
-      new_param.getInt(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION);
-  const int max_exposure_compensation =
-      new_param.getInt(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION);
-
-  // Checks if the exposure compensation change is supported.
-  if ((min_exposure_compensation != 0) || (max_exposure_compensation != 0)) {
-    if (new_exposure_compensation > max_exposure_compensation) {
-      new_exposure_compensation = max_exposure_compensation;
-    }
-    if (new_exposure_compensation < min_exposure_compensation) {
-      new_exposure_compensation = min_exposure_compensation;
-    }
-
-    const int current_exposure_compensation =
-        mParameters.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION);
-    if (current_exposure_compensation != new_exposure_compensation) {
-      const float exposure_value =
-          new_exposure_compensation *
-          new_param.getFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP);
-
-      getCameraDevice()->setExposureCompensation(exposure_value);
-    }
-  }
-
-  const char* new_white_balance =
-      new_param.get(CameraParameters::KEY_WHITE_BALANCE);
-  const char* supported_white_balance =
-      new_param.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE);
-
-  if ((supported_white_balance != NULL) && (new_white_balance != NULL) &&
-      (strstr(supported_white_balance, new_white_balance) != NULL)) {
-    const char* current_white_balance =
-        mParameters.get(CameraParameters::KEY_WHITE_BALANCE);
-    if ((current_white_balance == NULL) ||
-        (strcmp(current_white_balance, new_white_balance) != 0)) {
-      ALOGV("Setting white balance to %s", new_white_balance);
-      getCameraDevice()->setWhiteBalanceMode(new_white_balance);
-    }
-  }
-
-  mParameters = new_param;
-
-  return NO_ERROR;
-}
-
-/* A dumb variable indicating "no params" / error on the exit from
- * EmulatedCamera::getParameters(). */
-static char lNoParam = '\0';
-char* EmulatedCamera::getParameters() {
-  String8 params(mParameters.flatten());
-  char* ret_str =
-      reinterpret_cast<char*>(malloc(sizeof(char) * (params.length() + 1)));
-  memset(ret_str, 0, params.length() + 1);
-  if (ret_str != NULL) {
-    strncpy(ret_str, params.string(), params.length() + 1);
-    return ret_str;
-  } else {
-    ALOGE("%s: Unable to allocate string for %s", __FUNCTION__,
-          params.string());
-    /* Apparently, we can't return NULL fron this routine. */
-    return &lNoParam;
-  }
-}
-
-void EmulatedCamera::putParameters(char* params) {
-  /* This method simply frees parameters allocated in getParameters(). */
-  if (params != NULL && params != &lNoParam) {
-    free(params);
-  }
-}
-
-status_t EmulatedCamera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
-  ALOGV("%s: cmd = %d, arg1 = %d, arg2 = %d", __FUNCTION__, cmd, arg1, arg2);
-
-  switch (cmd) {
-    case CAMERA_CMD_START_FACE_DETECTION:
-    case CAMERA_CMD_STOP_FACE_DETECTION:
-      return -EINVAL;
-  }
-
-  /* TODO: Future enhancements. */
-  return 0;
-}
-
-void EmulatedCamera::releaseCamera() {
-  ALOGV("%s", __FUNCTION__);
-
-  cleanupCamera();
-}
-
-status_t EmulatedCamera::dumpCamera(int /*fd*/) {
-  ALOGV("%s", __FUNCTION__);
-
-  /* TODO: Future enhancements. */
-  return -EINVAL;
-}
-
-/****************************************************************************
- * Preview management.
- ***************************************************************************/
-
-status_t EmulatedCamera::doStartPreview() {
-  ALOGV("%s", __FUNCTION__);
-
-  EmulatedCameraDevice* camera_dev = getCameraDevice();
-  if (camera_dev->isStarted()) {
-    camera_dev->stopDeliveringFrames();
-    camera_dev->stopDevice();
-  }
-
-  status_t res = mPreviewWindow.startPreview();
-  if (res != NO_ERROR) {
-    return res;
-  }
-
-  /* Make sure camera device is connected. */
-  if (!camera_dev->isConnected()) {
-    res = camera_dev->connectDevice();
-    if (res != NO_ERROR) {
-      mPreviewWindow.stopPreview();
-      return res;
-    }
-  }
-
-  int width, height;
-  /* Lets see what should we use for frame width, and height. */
-  if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != NULL) {
-    mParameters.getVideoSize(&width, &height);
-  } else {
-    mParameters.getPreviewSize(&width, &height);
-  }
-  /* Lets see what should we use for the frame pixel format. Note that there
-   * are two parameters that define pixel formats for frames sent to the
-   * application via notification callbacks:
-   * - KEY_VIDEO_FRAME_FORMAT, that is used when recording video, and
-   * - KEY_PREVIEW_FORMAT, that is used for preview frame notification.
-   * We choose one or the other, depending on "recording-hint" property set by
-   * the framework that indicating intention: video, or preview. */
-  const char* pix_fmt = NULL;
-  const char* is_video = mParameters.get(EmulatedCamera::RECORDING_HINT_KEY);
-  if (is_video == NULL) {
-    is_video = CameraParameters::FALSE;
-  }
-  if (strcmp(is_video, CameraParameters::TRUE) == 0) {
-    /* Video recording is requested. Lets see if video frame format is set. */
-    pix_fmt = mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
-  }
-  /* If this was not video recording, or video frame format is not set, lets
-   * use preview pixel format for the main framebuffer. */
-  if (pix_fmt == NULL) {
-    pix_fmt = mParameters.getPreviewFormat();
-  }
-  if (pix_fmt == NULL) {
-    ALOGE("%s: Unable to obtain video format", __FUNCTION__);
-    mPreviewWindow.stopPreview();
-    return EINVAL;
-  }
-
-  /* Convert framework's pixel format to the FOURCC one. */
-  uint32_t org_fmt;
-  if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
-    org_fmt = V4L2_PIX_FMT_YUV420;
-  } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
-    org_fmt = V4L2_PIX_FMT_RGB32;
-  } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
-    org_fmt = V4L2_PIX_FMT_NV21;
-  } else {
-    ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
-    mPreviewWindow.stopPreview();
-    return EINVAL;
-  }
-
-  /* Fetch the desired frame rate. */
-  int min_fps_rate, max_fps_rate;
-  mParameters.getPreviewFpsRange(&min_fps_rate, &max_fps_rate);
-
-  ALOGD("Starting camera: %dx%d -> %.4s(%s)", width, height,
-        reinterpret_cast<const char*>(&org_fmt), pix_fmt);
-  res = camera_dev->startDevice(width, height, org_fmt, max_fps_rate);
-  if (res != NO_ERROR) {
-    mPreviewWindow.stopPreview();
-    return res;
-  }
-
-  res = camera_dev->startDeliveringFrames(false);
-  if (res != NO_ERROR) {
-    camera_dev->stopDevice();
-    mPreviewWindow.stopPreview();
-  }
-
-  return res;
-}
-
-status_t EmulatedCamera::doStopPreview() {
-  ALOGV("%s", __FUNCTION__);
-
-  status_t res = NO_ERROR;
-  if (mPreviewWindow.isPreviewEnabled()) {
-    /* Stop the camera. */
-    if (getCameraDevice()->isStarted()) {
-      getCameraDevice()->stopDeliveringFrames();
-      res = getCameraDevice()->stopDevice();
-    }
-
-    if (res == NO_ERROR) {
-      /* Disable preview as well. */
-      mPreviewWindow.stopPreview();
-    }
-  }
-
-  return NO_ERROR;
-}
-
-/****************************************************************************
- * Private API.
- ***************************************************************************/
-
-status_t EmulatedCamera::cleanupCamera() {
-  status_t res = NO_ERROR;
-
-  /* If preview is running - stop it. */
-  res = doStopPreview();
-  if (res != NO_ERROR) {
-    return -res;
-  }
-
-  /* Stop and disconnect the camera device. */
-  EmulatedCameraDevice* const camera_dev = getCameraDevice();
-  if (camera_dev != NULL) {
-    if (camera_dev->isStarted()) {
-      camera_dev->stopDeliveringFrames();
-      res = camera_dev->stopDevice();
-      if (res != NO_ERROR) {
-        return -res;
-      }
-    }
-    if (camera_dev->isConnected()) {
-      res = camera_dev->disconnectDevice();
-      if (res != NO_ERROR) {
-        return -res;
-      }
-    }
-  }
-
-  mCallbackNotifier.cleanupCBNotifier();
-
-  return NO_ERROR;
-}
-
-/****************************************************************************
- * Camera API callbacks as defined by camera_device_ops structure.
- *
- * Callbacks here simply dispatch the calls to an appropriate method inside
- * EmulatedCamera instance, defined by the 'dev' parameter.
- ***************************************************************************/
-
-int EmulatedCamera::set_preview_window(struct camera_device* dev,
-                                       struct preview_stream_ops* window) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->setPreviewWindow(window);
-}
-
-void EmulatedCamera::set_callbacks(
-    struct camera_device* dev, camera_notify_callback notify_cb,
-    camera_data_callback data_cb,
-    camera_data_timestamp_callback data_cb_timestamp,
-    camera_request_memory get_memory, void* user) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user);
-}
-
-void EmulatedCamera::enable_msg_type(struct camera_device* dev,
-                                     int32_t msg_type) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->enableMsgType(msg_type);
-}
-
-void EmulatedCamera::disable_msg_type(struct camera_device* dev,
-                                      int32_t msg_type) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->disableMsgType(msg_type);
-}
-
-int EmulatedCamera::msg_type_enabled(struct camera_device* dev,
-                                     int32_t msg_type) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->isMsgTypeEnabled(msg_type);
-}
-
-int EmulatedCamera::start_preview(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->startPreview();
-}
-
-void EmulatedCamera::stop_preview(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->stopPreview();
-}
-
-int EmulatedCamera::preview_enabled(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->isPreviewEnabled();
-}
-
-int EmulatedCamera::store_meta_data_in_buffers(struct camera_device* dev,
-                                               int enable) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->storeMetaDataInBuffers(enable);
-}
-
-int EmulatedCamera::start_recording(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->startRecording();
-}
-
-void EmulatedCamera::stop_recording(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->stopRecording();
-}
-
-int EmulatedCamera::recording_enabled(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->isRecordingEnabled();
-}
-
-void EmulatedCamera::release_recording_frame(struct camera_device* dev,
-                                             const void* opaque) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->releaseRecordingFrame(opaque);
-}
-
-int EmulatedCamera::auto_focus(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->setAutoFocus();
-}
-
-int EmulatedCamera::cancel_auto_focus(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->cancelAutoFocus();
-}
-
-int EmulatedCamera::take_picture(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->takePicture();
-}
-
-int EmulatedCamera::cancel_picture(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->cancelPicture();
-}
-
-int EmulatedCamera::set_parameters(struct camera_device* dev,
-                                   const char* parms) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->setParameters(parms);
-}
-
-char* EmulatedCamera::get_parameters(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return NULL;
-  }
-  return ec->getParameters();
-}
-
-void EmulatedCamera::put_parameters(struct camera_device* dev, char* params) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->putParameters(params);
-}
-
-int EmulatedCamera::send_command(struct camera_device* dev, int32_t cmd,
-                                 int32_t arg1, int32_t arg2) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->sendCommand(cmd, arg1, arg2);
-}
-
-void EmulatedCamera::release(struct camera_device* dev) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return;
-  }
-  ec->releaseCamera();
-}
-
-int EmulatedCamera::dump(struct camera_device* dev, int fd) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->dumpCamera(fd);
-}
-
-int EmulatedCamera::close(struct hw_device_t* device) {
-  EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(
-      reinterpret_cast<struct camera_device*>(device)->priv);
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->closeCamera();
-}
-
-/****************************************************************************
- * Static initializer for the camera callback API
- ****************************************************************************/
-
-camera_device_ops_t EmulatedCamera::mDeviceOps = {
-    EmulatedCamera::set_preview_window,
-    EmulatedCamera::set_callbacks,
-    EmulatedCamera::enable_msg_type,
-    EmulatedCamera::disable_msg_type,
-    EmulatedCamera::msg_type_enabled,
-    EmulatedCamera::start_preview,
-    EmulatedCamera::stop_preview,
-    EmulatedCamera::preview_enabled,
-    EmulatedCamera::store_meta_data_in_buffers,
-    EmulatedCamera::start_recording,
-    EmulatedCamera::stop_recording,
-    EmulatedCamera::recording_enabled,
-    EmulatedCamera::release_recording_frame,
-    EmulatedCamera::auto_focus,
-    EmulatedCamera::cancel_auto_focus,
-    EmulatedCamera::take_picture,
-    EmulatedCamera::cancel_picture,
-    EmulatedCamera::set_parameters,
-    EmulatedCamera::get_parameters,
-    EmulatedCamera::put_parameters,
-    EmulatedCamera::send_command,
-    EmulatedCamera::release,
-    EmulatedCamera::dump};
-
-/****************************************************************************
- * Common keys
- ***************************************************************************/
-
-const char EmulatedCamera::FACING_KEY[] = "prop-facing";
-const char EmulatedCamera::ORIENTATION_KEY[] = "prop-orientation";
-const char EmulatedCamera::RECORDING_HINT_KEY[] = "recording-hint";
-
-/****************************************************************************
- * Common string values
- ***************************************************************************/
-
-const char EmulatedCamera::FACING_BACK[] = "back";
-const char EmulatedCamera::FACING_FRONT[] = "front";
-
-/****************************************************************************
- * Parameter debugging helpers
- ***************************************************************************/
-
-#if DEBUG_PARAM
-static void PrintParamDiff(const CameraParameters& current,
-                           const char* new_par) {
-  char tmp[2048];
-  const char* wrk = new_par;
-
-  /* Divided with ';' */
-  const char* next = strchr(wrk, ';');
-  while (next != NULL) {
-    snprintf(tmp, sizeof(tmp), "%.*s", (int)(intptr_t)(next - wrk), wrk);
-    /* in the form key=value */
-    char* val = strchr(tmp, '=');
-    if (val != NULL) {
-      *val = '\0';
-      val++;
-      const char* in_current = current.get(tmp);
-      if (in_current != NULL) {
-        if (strcmp(in_current, val)) {
-          ALOGD("=== Value changed: %s: %s -> %s", tmp, in_current, val);
-        }
-      } else {
-        ALOGD("+++ New parameter: %s=%s", tmp, val);
-      }
-    } else {
-      ALOGW("No value separator in %s", tmp);
-    }
-    wrk = next + 1;
-    next = strchr(wrk, ';');
-  }
-}
-#endif /* DEBUG_PARAM */
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedCamera.h b/guest/hals/camera/EmulatedCamera.h
deleted file mode 100644
index a2de643..0000000
--- a/guest/hals/camera/EmulatedCamera.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_H
-
-/*
- * Contains declaration of a class EmulatedCamera that encapsulates
- * functionality common to all version 1.0 emulated camera devices ("fake",
- * "webcam", "video file", etc.).  Instances of this class (for each emulated
- * camera) are created during the construction of the EmulatedCameraFactory
- * instance.  This class serves as an entry point for all camera API calls that
- * defined by camera_device_ops_t API.
- */
-
-#include <CameraParameters.h>
-using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
-using ::android::hardware::camera::common::V1_0::helper::Size;
-
-#include "CallbackNotifier.h"
-#include "EmulatedBaseCamera.h"
-#include "EmulatedCameraDevice.h"
-#include "PreviewWindow.h"
-
-namespace android {
-
-/* Encapsulates functionality common to all version 1.0 emulated camera devices
- * ("fake", "webcam", "file stream", etc.).
- *
- * Note that EmulatedCameraFactory instantiates object of this class just once,
- * when EmulatedCameraFactory instance gets constructed. Connection to /
- * disconnection from the actual camera device is handled by calls to
- * connectDevice(), and closeCamera() methods of this class that are ivoked in
- * response to hw_module_methods_t::open, and camera_device::close callbacks.
- */
-class EmulatedCamera : public camera_device, public EmulatedBaseCamera {
- public:
-  /* Constructs EmulatedCamera instance.
-   * Param:
-   *  cameraId - Zero based camera identifier, which is an index of the camera
-   *      instance in camera factory's array.
-   *  module - Emulated camera HAL module descriptor.
-   */
-  EmulatedCamera(int cameraId, struct hw_module_t* module);
-
-  /* Destructs EmulatedCamera instance. */
-  virtual ~EmulatedCamera();
-
-  /****************************************************************************
-   * Abstract API
-   ***************************************************************************/
-
- public:
-  /* Gets emulated camera device used by this instance of the emulated camera.
-   */
-  virtual EmulatedCameraDevice* getCameraDevice() = 0;
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  /** Override of base class method */
-  virtual status_t Initialize(const cvd::CameraDefinition& properties);
-
-  /* Next frame is available in the camera device.
-   * This is a notification callback that is invoked by the camera device when
-   * a new frame is available.
-   * Note that most likely this method is called in context of a worker thread
-   * that camera device has created for frame capturing.
-   * Param:
-   *  frame - Captured frame, or NULL if camera device didn't pull the frame
-   *      yet. If NULL is passed in this parameter use GetCurrentFrame method
-   *      of the camera device class to obtain the next frame. Also note that
-   *      the size of the frame that is passed here (as well as the frame
-   *      returned from the GetCurrentFrame method) is defined by the current
-   *      frame settings (width + height + pixel format) for the camera device.
-   * timestamp - Frame's timestamp.
-   * camera_dev - Camera device instance that delivered the frame.
-   */
-  virtual void onNextFrameAvailable(const void* frame, nsecs_t timestamp,
-                                    EmulatedCameraDevice* camera_dev);
-
-  /* Entry point for notifications that occur in camera device.
-   * Param:
-   *  err - CAMERA_ERROR_XXX error code.
-   */
-  virtual void onCameraDeviceError(int err);
-
-  /* Device acquired focus.
-   * This is a notification callback that is invoked by the camera device
-   * when focusing operation (requested by client) completes.
-   */
-  virtual void onCameraFocusAcquired();
-
-  /****************************************************************************
-   * Camera API implementation
-   ***************************************************************************/
-
- public:
-  /** Override of base class method */
-  virtual status_t connectCamera(hw_device_t** device);
-
-  /** Override of base class method */
-  virtual status_t closeCamera();
-
-  /** Override of base class method */
-  virtual status_t getCameraInfo(struct camera_info* info);
-
-  /** Override of base class method */
-  virtual const CameraParameters* getCameraParameters() override;
-
-  /****************************************************************************
-   * Camera API implementation.
-   * These methods are called from the camera API callback routines.
-   ***************************************************************************/
-
- protected:
-  /* Actual handler for camera_device_ops_t::set_preview_window callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t setPreviewWindow(struct preview_stream_ops* window);
-
-  /* Actual handler for camera_device_ops_t::set_callbacks callback.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void setCallbacks(camera_notify_callback notify_cb,
-                            camera_data_callback data_cb,
-                            camera_data_timestamp_callback data_cb_timestamp,
-                            camera_request_memory get_memory, void* user);
-
-  /* Actual handler for camera_device_ops_t::enable_msg_type callback.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void enableMsgType(int32_t msg_type);
-
-  /* Actual handler for camera_device_ops_t::disable_msg_type callback.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void disableMsgType(int32_t msg_type);
-
-  /* Actual handler for camera_device_ops_t::msg_type_enabled callback.
-   * NOTE: When this method is called the object is locked.
-   * Return:
-   *  0 if message(s) is (are) disabled, != 0 if enabled.
-   */
-  virtual int isMsgTypeEnabled(int32_t msg_type);
-
-  /* Actual handler for camera_device_ops_t::start_preview callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t startPreview();
-
-  /* Actual handler for camera_device_ops_t::stop_preview callback.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void stopPreview();
-
-  /* Actual handler for camera_device_ops_t::preview_enabled callback.
-   * NOTE: When this method is called the object is locked.
-   * Return:
-   *  0 if preview is disabled, != 0 if enabled.
-   */
-  virtual int isPreviewEnabled();
-
-  /* Actual handler for camera_device_ops_t::store_meta_data_in_buffers
-   * callback. NOTE: When this method is called the object is locked. Note that
-   * failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t storeMetaDataInBuffers(int enable);
-
-  /* Actual handler for camera_device_ops_t::start_recording callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t startRecording();
-
-  /* Actual handler for camera_device_ops_t::stop_recording callback.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void stopRecording();
-
-  /* Actual handler for camera_device_ops_t::recording_enabled callback.
-   * NOTE: When this method is called the object is locked.
-   * Return:
-   *  0 if recording is disabled, != 0 if enabled.
-   */
-  virtual int isRecordingEnabled();
-
-  /* Actual handler for camera_device_ops_t::release_recording_frame callback.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void releaseRecordingFrame(const void* opaque);
-
-  /* Actual handler for camera_device_ops_t::auto_focus callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t setAutoFocus();
-
-  /* Actual handler for camera_device_ops_t::cancel_auto_focus callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t cancelAutoFocus();
-
-  /* Actual handler for camera_device_ops_t::take_picture callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t takePicture();
-
-  /* Actual handler for camera_device_ops_t::cancel_picture callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t cancelPicture();
-
-  /* Actual handler for camera_device_ops_t::set_parameters callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t setParameters(const char* parms);
-
-  /* Actual handler for camera_device_ops_t::get_parameters callback.
-   * NOTE: When this method is called the object is locked.
-   * Return:
-   *  Flattened parameters string. The caller will free the buffer allocated
-   *  for the string by calling camera_device_ops_t::put_parameters callback.
-   */
-  virtual char* getParameters();
-
-  /* Actual handler for camera_device_ops_t::put_parameters callback.
-   * Called to free the string returned from camera_device_ops_t::get_parameters
-   * callback. There is nothing more to it: the name of the callback is just
-   * misleading.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void putParameters(char* params);
-
-  /* Actual handler for camera_device_ops_t::send_command callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
-
-  /* Actual handler for camera_device_ops_t::release callback.
-   * NOTE: When this method is called the object is locked.
-   */
-  virtual void releaseCamera();
-
-  /* Actual handler for camera_device_ops_t::dump callback.
-   * NOTE: When this method is called the object is locked.
-   * Note that failures in this method are reported as negave EXXX statuses.
-   */
-  virtual status_t dumpCamera(int fd);
-
-  /****************************************************************************
-   * Preview management.
-   ***************************************************************************/
-
- protected:
-  /* Starts preview.
-   * Note that when this method is called mPreviewWindow may be NULL,
-   * indicating that framework has an intention to start displaying video
-   * frames, but didn't create the preview window yet.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  virtual status_t doStartPreview();
-
-  /* Stops preview.
-   * This method reverts DoStartPreview.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  virtual status_t doStopPreview();
-
-  /****************************************************************************
-   * Private API.
-   ***************************************************************************/
-
- protected:
-  /* Cleans up camera when released. */
-  virtual status_t cleanupCamera();
-
-  /****************************************************************************
-   * Camera API callbacks as defined by camera_device_ops structure.
-   * See hardware/libhardware/include/hardware/camera.h for information on
-   * each of these callbacks. Implemented in this class, these callbacks simply
-   * dispatch the call into an instance of EmulatedCamera class defined by the
-   * 'camera_device' parameter.
-   ***************************************************************************/
-
- private:
-  static int set_preview_window(struct camera_device* dev,
-                                struct preview_stream_ops* window);
-
-  static void set_callbacks(struct camera_device* dev,
-                            camera_notify_callback notify_cb,
-                            camera_data_callback data_cb,
-                            camera_data_timestamp_callback data_cb_timestamp,
-                            camera_request_memory get_memory, void* user);
-
-  static void enable_msg_type(struct camera_device* dev, int32_t msg_type);
-
-  static void disable_msg_type(struct camera_device* dev, int32_t msg_type);
-
-  static int msg_type_enabled(struct camera_device* dev, int32_t msg_type);
-
-  static int start_preview(struct camera_device* dev);
-
-  static void stop_preview(struct camera_device* dev);
-
-  static int preview_enabled(struct camera_device* dev);
-
-  static int store_meta_data_in_buffers(struct camera_device* dev, int enable);
-
-  static int start_recording(struct camera_device* dev);
-
-  static void stop_recording(struct camera_device* dev);
-
-  static int recording_enabled(struct camera_device* dev);
-
-  static void release_recording_frame(struct camera_device* dev,
-                                      const void* opaque);
-
-  static int auto_focus(struct camera_device* dev);
-
-  static int cancel_auto_focus(struct camera_device* dev);
-
-  static int take_picture(struct camera_device* dev);
-
-  static int cancel_picture(struct camera_device* dev);
-
-  static int set_parameters(struct camera_device* dev, const char* parms);
-
-  static char* get_parameters(struct camera_device* dev);
-
-  static void put_parameters(struct camera_device* dev, char* params);
-
-  static int send_command(struct camera_device* dev, int32_t cmd, int32_t arg1,
-                          int32_t arg2);
-
-  static void release(struct camera_device* dev);
-
-  static int dump(struct camera_device* dev, int fd);
-
-  static int close(struct hw_device_t* device);
-
-  /****************************************************************************
-   * Data members
-   ***************************************************************************/
-
- protected:
-  /* Locks this instance for parameters, state, etc. change. */
-  Mutex mObjectLock;
-
-  /* Camera parameters. */
-  CameraParameters mParameters;
-
-  /* Preview window. */
-  PreviewWindow mPreviewWindow;
-
-  /* Callback notifier. */
-  CallbackNotifier mCallbackNotifier;
-
- private:
-  /* Registered callbacks implementing camera API. */
-  static camera_device_ops_t mDeviceOps;
-
-  /****************************************************************************
-   * Common keys
-   ***************************************************************************/
-
- public:
-  static const char FACING_KEY[];
-  static const char ORIENTATION_KEY[];
-  static const char RECORDING_HINT_KEY[];
-
-  /****************************************************************************
-   * Common string values
-   ***************************************************************************/
-
-  /* Possible values for FACING_KEY */
-  static const char FACING_BACK[];
-  static const char FACING_FRONT[];
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_H */
diff --git a/guest/hals/camera/EmulatedCamera2.cpp b/guest/hals/camera/EmulatedCamera2.cpp
deleted file mode 100644
index ccb8006..0000000
--- a/guest/hals/camera/EmulatedCamera2.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/*
- * Contains implementation of a class EmulatedCamera that encapsulates
- * functionality common to all version 2.0 emulated camera devices.  Instances
- * of this class (for each emulated camera) are created during the construction
- * of the EmulatedCameraFactory instance.  This class serves as an entry point
- * for all camera API calls that defined by camera2_device_ops_t API.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera2_Camera"
-#include <log/log.h>
-
-#include "EmulatedCamera2.h"
-#include "system/camera_metadata.h"
-
-namespace android {
-
-/* Constructs EmulatedCamera2 instance.
- * Param:
- *  cameraId - Zero based camera identifier, which is an index of the camera
- *      instance in camera factory's array.
- *  module - Emulated camera HAL module descriptor.
- */
-EmulatedCamera2::EmulatedCamera2(int cameraId, struct hw_module_t *module)
-    : EmulatedBaseCamera(cameraId, CAMERA_DEVICE_API_VERSION_2_0, &common,
-                         module) {
-  common.close = EmulatedCamera2::close;
-  ops = &sDeviceOps;
-  priv = this;
-
-  mNotifyCb = NULL;
-
-  mRequestQueueSrc = NULL;
-  mFrameQueueDst = NULL;
-
-  mVendorTagOps.get_camera_vendor_section_name =
-      EmulatedCamera2::get_camera_vendor_section_name;
-  mVendorTagOps.get_camera_vendor_tag_name =
-      EmulatedCamera2::get_camera_vendor_tag_name;
-  mVendorTagOps.get_camera_vendor_tag_type =
-      EmulatedCamera2::get_camera_vendor_tag_type;
-  mVendorTagOps.parent = this;
-
-  mStatusPresent = true;
-}
-
-/* Destructs EmulatedCamera2 instance. */
-EmulatedCamera2::~EmulatedCamera2() {}
-
-/****************************************************************************
- * Abstract API
- ***************************************************************************/
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-status_t EmulatedCamera2::Initialize(const cvd::CameraDefinition & /*props*/) {
-  return NO_ERROR;
-}
-
-/****************************************************************************
- * Camera API implementation
- ***************************************************************************/
-
-status_t EmulatedCamera2::connectCamera(hw_device_t **device) {
-  *device = &common;
-  return NO_ERROR;
-}
-
-status_t EmulatedCamera2::closeCamera() { return NO_ERROR; }
-
-status_t EmulatedCamera2::getCameraInfo(struct camera_info *info) {
-  return EmulatedBaseCamera::getCameraInfo(info);
-}
-
-/****************************************************************************
- * Camera Device API implementation.
- * These methods are called from the camera API callback routines.
- ***************************************************************************/
-
-/** Request input queue */
-
-int EmulatedCamera2::requestQueueNotify() { return INVALID_OPERATION; }
-
-/** Count of requests in flight */
-int EmulatedCamera2::getInProgressCount() { return INVALID_OPERATION; }
-
-/** Cancel all captures in flight */
-int EmulatedCamera2::flushCapturesInProgress() { return INVALID_OPERATION; }
-
-/** Construct a default request for a given use case */
-int EmulatedCamera2::constructDefaultRequest(int /*request_template*/,
-                                             camera_metadata_t ** /*request*/) {
-  return INVALID_OPERATION;
-}
-
-/** Output stream creation and management */
-
-int EmulatedCamera2::allocateStream(uint32_t /*width*/, uint32_t /*height*/,
-                                    int /*format*/,
-                                    const camera2_stream_ops_t * /*stream_ops*/,
-                                    uint32_t * /*stream_id*/,
-                                    uint32_t * /*format_actual*/,
-                                    uint32_t * /*usage*/,
-                                    uint32_t * /*max_buffers*/) {
-  return INVALID_OPERATION;
-}
-
-int EmulatedCamera2::registerStreamBuffers(uint32_t /*stream_id*/,
-                                           int /*num_buffers*/,
-                                           buffer_handle_t * /*buffers*/) {
-  return INVALID_OPERATION;
-}
-
-int EmulatedCamera2::releaseStream(uint32_t /*stream_id*/) {
-  return INVALID_OPERATION;
-}
-
-/** Reprocessing input stream management */
-
-int EmulatedCamera2::allocateReprocessStream(
-    uint32_t /*width*/, uint32_t /*height*/, uint32_t /*format*/,
-    const camera2_stream_in_ops_t * /*reprocess_stream_ops*/,
-    uint32_t * /*stream_id*/, uint32_t * /*consumer_usage*/,
-    uint32_t * /*max_buffers*/) {
-  return INVALID_OPERATION;
-}
-
-int EmulatedCamera2::allocateReprocessStreamFromStream(
-    uint32_t /*output_stream_id*/,
-    const camera2_stream_in_ops_t * /*reprocess_stream_ops*/,
-    uint32_t * /*stream_id*/) {
-  return INVALID_OPERATION;
-}
-
-int EmulatedCamera2::releaseReprocessStream(uint32_t /*stream_id*/) {
-  return INVALID_OPERATION;
-}
-
-/** 3A triggering */
-
-int EmulatedCamera2::triggerAction(uint32_t /*trigger_id*/, int /*ext1*/,
-                                   int /*ext2*/) {
-  return INVALID_OPERATION;
-}
-
-/** Custom tag query methods */
-
-const char *EmulatedCamera2::getVendorSectionName(uint32_t /*tag*/) {
-  return NULL;
-}
-
-const char *EmulatedCamera2::getVendorTagName(uint32_t /*tag*/) { return NULL; }
-
-int EmulatedCamera2::getVendorTagType(uint32_t /*tag*/) { return -1; }
-
-/** Debug methods */
-
-int EmulatedCamera2::dump(int /*fd*/) { return INVALID_OPERATION; }
-
-/****************************************************************************
- * Private API.
- ***************************************************************************/
-
-/****************************************************************************
- * Camera API callbacks as defined by camera2_device_ops structure.  See
- * hardware/libhardware/include/hardware/camera2.h for information on each
- * of these callbacks. Implemented in this class, these callbacks simply
- * dispatch the call into an instance of EmulatedCamera2 class defined by the
- * 'camera_device2' parameter, or set a member value in the same.
- ***************************************************************************/
-
-EmulatedCamera2 *getInstance(const camera2_device_t *d) {
-  const EmulatedCamera2 *cec = static_cast<const EmulatedCamera2 *>(d);
-  return const_cast<EmulatedCamera2 *>(cec);
-}
-
-int EmulatedCamera2::set_request_queue_src_ops(
-    const camera2_device_t *d,
-    const camera2_request_queue_src_ops *queue_src_ops) {
-  EmulatedCamera2 *ec = getInstance(d);
-  ec->mRequestQueueSrc = queue_src_ops;
-  return NO_ERROR;
-}
-
-int EmulatedCamera2::notify_request_queue_not_empty(const camera2_device_t *d) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->requestQueueNotify();
-}
-
-int EmulatedCamera2::set_frame_queue_dst_ops(
-    const camera2_device_t *d,
-    const camera2_frame_queue_dst_ops *queue_dst_ops) {
-  EmulatedCamera2 *ec = getInstance(d);
-  ec->mFrameQueueDst = queue_dst_ops;
-  return NO_ERROR;
-}
-
-int EmulatedCamera2::get_in_progress_count(const camera2_device_t *d) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->getInProgressCount();
-}
-
-int EmulatedCamera2::flush_captures_in_progress(const camera2_device_t *d) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->flushCapturesInProgress();
-}
-
-int EmulatedCamera2::construct_default_request(const camera2_device_t *d,
-                                               int request_template,
-                                               camera_metadata_t **request) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->constructDefaultRequest(request_template, request);
-}
-
-int EmulatedCamera2::allocate_stream(const camera2_device_t *d, uint32_t width,
-                                     uint32_t height, int format,
-                                     const camera2_stream_ops_t *stream_ops,
-                                     uint32_t *stream_id,
-                                     uint32_t *format_actual, uint32_t *usage,
-                                     uint32_t *max_buffers) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->allocateStream(width, height, format, stream_ops, stream_id,
-                            format_actual, usage, max_buffers);
-}
-
-int EmulatedCamera2::register_stream_buffers(const camera2_device_t *d,
-                                             uint32_t stream_id,
-                                             int num_buffers,
-                                             buffer_handle_t *buffers) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->registerStreamBuffers(stream_id, num_buffers, buffers);
-}
-int EmulatedCamera2::release_stream(const camera2_device_t *d,
-                                    uint32_t stream_id) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->releaseStream(stream_id);
-}
-
-int EmulatedCamera2::allocate_reprocess_stream(
-    const camera2_device_t *d, uint32_t width, uint32_t height, uint32_t format,
-    const camera2_stream_in_ops_t *reprocess_stream_ops, uint32_t *stream_id,
-    uint32_t *consumer_usage, uint32_t *max_buffers) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->allocateReprocessStream(width, height, format,
-                                     reprocess_stream_ops, stream_id,
-                                     consumer_usage, max_buffers);
-}
-
-int EmulatedCamera2::allocate_reprocess_stream_from_stream(
-    const camera2_device_t *d, uint32_t output_stream_id,
-    const camera2_stream_in_ops_t *reprocess_stream_ops, uint32_t *stream_id) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->allocateReprocessStreamFromStream(output_stream_id,
-                                               reprocess_stream_ops, stream_id);
-}
-
-int EmulatedCamera2::release_reprocess_stream(const camera2_device_t *d,
-                                              uint32_t stream_id) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->releaseReprocessStream(stream_id);
-}
-
-int EmulatedCamera2::trigger_action(const camera2_device_t *d,
-                                    uint32_t trigger_id, int ext1, int ext2) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->triggerAction(trigger_id, ext1, ext2);
-}
-
-int EmulatedCamera2::set_notify_callback(const camera2_device_t *d,
-                                         camera2_notify_callback notify_cb,
-                                         void *user) {
-  EmulatedCamera2 *ec = getInstance(d);
-  Mutex::Autolock l(ec->mMutex);
-  ec->mNotifyCb = notify_cb;
-  ec->mNotifyUserPtr = user;
-  return NO_ERROR;
-}
-
-int EmulatedCamera2::get_instance_metadata(
-    const struct camera2_device *d, camera_metadata **instance_metadata) {
-  EmulatedCamera2 *ec = getInstance(d);
-  if (!ec) {
-    return INVALID_OPERATION;
-  }
-  *instance_metadata = ec->mCameraInfo;
-  return NO_ERROR;
-}
-
-int EmulatedCamera2::get_metadata_vendor_tag_ops(const camera2_device_t *d,
-                                                 vendor_tag_query_ops_t **ops) {
-  EmulatedCamera2 *ec = getInstance(d);
-  *ops = static_cast<vendor_tag_query_ops_t *>(&ec->mVendorTagOps);
-  return NO_ERROR;
-}
-
-const char *EmulatedCamera2::get_camera_vendor_section_name(
-    const vendor_tag_query_ops_t *v, uint32_t tag) {
-  EmulatedCamera2 *ec = static_cast<const TagOps *>(v)->parent;
-  return ec->getVendorSectionName(tag);
-}
-
-const char *EmulatedCamera2::get_camera_vendor_tag_name(
-    const vendor_tag_query_ops_t *v, uint32_t tag) {
-  EmulatedCamera2 *ec = static_cast<const TagOps *>(v)->parent;
-  return ec->getVendorTagName(tag);
-}
-
-int EmulatedCamera2::get_camera_vendor_tag_type(const vendor_tag_query_ops_t *v,
-                                                uint32_t tag) {
-  EmulatedCamera2 *ec = static_cast<const TagOps *>(v)->parent;
-  return ec->getVendorTagType(tag);
-}
-
-int EmulatedCamera2::dump(const camera2_device_t *d, int fd) {
-  EmulatedCamera2 *ec = getInstance(d);
-  return ec->dump(fd);
-}
-
-int EmulatedCamera2::close(struct hw_device_t *device) {
-  EmulatedCamera2 *ec = static_cast<EmulatedCamera2 *>(
-      reinterpret_cast<camera2_device_t *>(device));
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera2 device", __FUNCTION__);
-    return -EINVAL;
-  }
-  return ec->closeCamera();
-}
-
-void EmulatedCamera2::sendNotification(int32_t msgType, int32_t ext1,
-                                       int32_t ext2, int32_t ext3) {
-  camera2_notify_callback notifyCb;
-  {
-    Mutex::Autolock l(mMutex);
-    notifyCb = mNotifyCb;
-  }
-  if (notifyCb != NULL) {
-    notifyCb(msgType, ext1, ext2, ext3, mNotifyUserPtr);
-  }
-}
-
-camera2_device_ops_t EmulatedCamera2::sDeviceOps = {
-    EmulatedCamera2::set_request_queue_src_ops,
-    EmulatedCamera2::notify_request_queue_not_empty,
-    EmulatedCamera2::set_frame_queue_dst_ops,
-    EmulatedCamera2::get_in_progress_count,
-    EmulatedCamera2::flush_captures_in_progress,
-    EmulatedCamera2::construct_default_request,
-    EmulatedCamera2::allocate_stream,
-    EmulatedCamera2::register_stream_buffers,
-    EmulatedCamera2::release_stream,
-    EmulatedCamera2::allocate_reprocess_stream,
-    EmulatedCamera2::allocate_reprocess_stream_from_stream,
-    EmulatedCamera2::release_reprocess_stream,
-    EmulatedCamera2::trigger_action,
-    EmulatedCamera2::set_notify_callback,
-    EmulatedCamera2::get_metadata_vendor_tag_ops,
-    EmulatedCamera2::dump,
-#ifdef CAMERA_DEVICE_API_VERSION_2_1
-    EmulatedCamera2::get_instance_metadata,
-#endif
-};
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedCamera2.h b/guest/hals/camera/EmulatedCamera2.h
deleted file mode 100644
index ad8b113..0000000
--- a/guest/hals/camera/EmulatedCamera2.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA2_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA2_H
-
-/*
- * Contains declaration of a class EmulatedCamera that encapsulates
- * functionality common to all version 2.0 emulated camera devices.  Instances
- * of this class (for each emulated camera) are created during the construction
- * of the EmulatedCameraFactory instance.  This class serves as an entry point
- * for all camera API calls that defined by camera2_device_ops_t API.
- */
-
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
-#include "EmulatedBaseCamera.h"
-#include "hardware/camera2.h"
-#include "system/camera_metadata.h"
-
-namespace android {
-
-/* Encapsulates functionality common to all version 2.0 emulated camera devices
- *
- * Note that EmulatedCameraFactory instantiates object of this class just once,
- * when EmulatedCameraFactory instance gets constructed. Connection to /
- * disconnection from the actual camera device is handled by calls to
- * connectDevice(), and closeCamera() methods of this class that are invoked in
- * response to hw_module_methods_t::open, and camera_device::close callbacks.
- */
-class EmulatedCamera2 : public camera2_device, public EmulatedBaseCamera {
- public:
-  /* Constructs EmulatedCamera2 instance.
-   * Param:
-   *  cameraId - Zero based camera identifier, which is an index of the camera
-   *      instance in camera factory's array.
-   *  module - Emulated camera HAL module descriptor.
-   */
-  EmulatedCamera2(int cameraId, struct hw_module_t *module);
-
-  /* Destructs EmulatedCamera2 instance. */
-  virtual ~EmulatedCamera2();
-
-  /****************************************************************************
-   * Abstract API
-   ***************************************************************************/
-
- public:
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  virtual status_t Initialize(const cvd::CameraDefinition &props);
-
-  /****************************************************************************
-   * Camera module API and generic hardware device API implementation
-   ***************************************************************************/
-
- public:
-  virtual status_t connectCamera(hw_device_t **device);
-
-  virtual status_t closeCamera();
-
-  virtual status_t getCameraInfo(struct camera_info *info) = 0;
-
-  /****************************************************************************
-   * Camera API implementation.
-   * These methods are called from the camera API callback routines.
-   ***************************************************************************/
-
- protected:
-  /** Request input queue notification */
-  virtual int requestQueueNotify();
-
-  /** Count of requests in flight */
-  virtual int getInProgressCount();
-
-  /** Cancel all captures in flight */
-  virtual int flushCapturesInProgress();
-
-  virtual int constructDefaultRequest(int request_template,
-                                      camera_metadata_t **request);
-
-  /** Output stream creation and management */
-  virtual int allocateStream(uint32_t width, uint32_t height, int format,
-                             const camera2_stream_ops_t *stream_ops,
-                             uint32_t *stream_id, uint32_t *format_actual,
-                             uint32_t *usage, uint32_t *max_buffers);
-
-  virtual int registerStreamBuffers(uint32_t stream_id, int num_buffers,
-                                    buffer_handle_t *buffers);
-
-  virtual int releaseStream(uint32_t stream_id);
-
-  /** Input stream creation and management */
-  virtual int allocateReprocessStream(
-      uint32_t width, uint32_t height, uint32_t format,
-      const camera2_stream_in_ops_t *reprocess_stream_ops, uint32_t *stream_id,
-      uint32_t *consumer_usage, uint32_t *max_buffers);
-
-  virtual int allocateReprocessStreamFromStream(
-      uint32_t output_stream_id,
-      const camera2_stream_in_ops_t *reprocess_stream_ops, uint32_t *stream_id);
-
-  virtual int releaseReprocessStream(uint32_t stream_id);
-
-  /** 3A action triggering */
-  virtual int triggerAction(uint32_t trigger_id, int32_t ext1, int32_t ext2);
-
-  /** Custom tag definitions */
-  virtual const char *getVendorSectionName(uint32_t tag);
-  virtual const char *getVendorTagName(uint32_t tag);
-  virtual int getVendorTagType(uint32_t tag);
-
-  /** Debug methods */
-
-  virtual int dump(int fd);
-
-  /****************************************************************************
-   * Camera API callbacks as defined by camera2_device_ops structure.  See
-   * hardware/libhardware/include/hardware/camera2.h for information on each
-   * of these callbacks. Implemented in this class, these callbacks simply
-   * dispatch the call into an instance of EmulatedCamera2 class defined in
-   * the 'camera_device2' parameter.
-   ***************************************************************************/
-
- private:
-  /** Input request queue */
-  static int set_request_queue_src_ops(
-      const camera2_device_t *,
-      const camera2_request_queue_src_ops *queue_src_ops);
-  static int notify_request_queue_not_empty(const camera2_device_t *);
-
-  /** Output frame queue */
-  static int set_frame_queue_dst_ops(
-      const camera2_device_t *,
-      const camera2_frame_queue_dst_ops *queue_dst_ops);
-
-  /** In-progress request management */
-  static int get_in_progress_count(const camera2_device_t *);
-
-  static int get_instance_metadata(const struct camera2_device *,
-                                   camera_metadata **);
-
-  static int flush_captures_in_progress(const camera2_device_t *);
-
-  /** Request template creation */
-  static int construct_default_request(const camera2_device_t *,
-                                       int request_template,
-                                       camera_metadata_t **request);
-
-  /** Stream management */
-  static int allocate_stream(const camera2_device_t *, uint32_t width,
-                             uint32_t height, int format,
-                             const camera2_stream_ops_t *stream_ops,
-                             uint32_t *stream_id, uint32_t *format_actual,
-                             uint32_t *usage, uint32_t *max_buffers);
-
-  static int register_stream_buffers(const camera2_device_t *,
-                                     uint32_t stream_id, int num_buffers,
-                                     buffer_handle_t *buffers);
-
-  static int release_stream(const camera2_device_t *, uint32_t stream_id);
-
-  static int allocate_reprocess_stream(
-      const camera2_device_t *, uint32_t width, uint32_t height,
-      uint32_t format, const camera2_stream_in_ops_t *reprocess_stream_ops,
-      uint32_t *stream_id, uint32_t *consumer_usage, uint32_t *max_buffers);
-
-  static int allocate_reprocess_stream_from_stream(
-      const camera2_device_t *, uint32_t output_stream_id,
-      const camera2_stream_in_ops_t *reprocess_stream_ops, uint32_t *stream_id);
-
-  static int release_reprocess_stream(const camera2_device_t *,
-                                      uint32_t stream_id);
-
-  /** 3A triggers*/
-  static int trigger_action(const camera2_device_t *, uint32_t trigger_id,
-                            int ext1, int ext2);
-
-  /** Notifications to application */
-  static int set_notify_callback(const camera2_device_t *,
-                                 camera2_notify_callback notify_cb, void *user);
-
-  /** Vendor metadata registration */
-  static int get_metadata_vendor_tag_ops(const camera2_device_t *,
-                                         vendor_tag_query_ops_t **ops);
-  // for get_metadata_vendor_tag_ops
-  static const char *get_camera_vendor_section_name(
-      const vendor_tag_query_ops_t *, uint32_t tag);
-  static const char *get_camera_vendor_tag_name(const vendor_tag_query_ops_t *,
-                                                uint32_t tag);
-  static int get_camera_vendor_tag_type(const vendor_tag_query_ops_t *,
-                                        uint32_t tag);
-
-  static int dump(const camera2_device_t *, int fd);
-
-  /** For hw_device_t ops */
-  static int close(struct hw_device_t *device);
-
-  /****************************************************************************
-   * Data members shared with implementations
-   ***************************************************************************/
- protected:
-  /** Mutex for calls through camera2 device interface */
-  Mutex mMutex;
-
-  bool mStatusPresent;
-
-  const camera2_request_queue_src_ops *mRequestQueueSrc;
-  const camera2_frame_queue_dst_ops *mFrameQueueDst;
-
-  struct TagOps : public vendor_tag_query_ops {
-    EmulatedCamera2 *parent;
-  };
-  TagOps mVendorTagOps;
-
-  void sendNotification(int32_t msgType, int32_t ext1, int32_t ext2,
-                        int32_t ext3);
-
-  /****************************************************************************
-   * Data members
-   ***************************************************************************/
- private:
-  static camera2_device_ops_t sDeviceOps;
-  camera2_notify_callback mNotifyCb;
-  void *mNotifyUserPtr;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA2_H */
diff --git a/guest/hals/camera/EmulatedCamera3.cpp b/guest/hals/camera/EmulatedCamera3.cpp
deleted file mode 100644
index 8b8921a..0000000
--- a/guest/hals/camera/EmulatedCamera3.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-/**
- * Contains implementation of a class EmulatedCamera that encapsulates
- * functionality common to all version 3.0 emulated camera devices.  Instances
- * of this class (for each emulated camera) are created during the construction
- * of the EmulatedCameraFactory instance.  This class serves as an entry point
- * for all camera API calls that defined by camera3_device_ops_t API.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera3_Camera"
-#include <log/log.h>
-
-#include "EmulatedCamera3.h"
-#include "system/camera_metadata.h"
-
-namespace android {
-
-/**
- * Constructs EmulatedCamera3 instance.
- * Param:
- *  cameraId - Zero based camera identifier, which is an index of the camera
- *      instance in camera factory's array.
- *  module - Emulated camera HAL module descriptor.
- */
-EmulatedCamera3::EmulatedCamera3(int cameraId, struct hw_module_t* module)
-    : EmulatedBaseCamera(cameraId, CAMERA_DEVICE_API_VERSION_3_3, &common,
-                         module),
-      mStatus(STATUS_ERROR) {
-  common.close = EmulatedCamera3::close;
-  ops = &sDeviceOps;
-
-  mCallbackOps = NULL;
-}
-
-/* Destructs EmulatedCamera3 instance. */
-EmulatedCamera3::~EmulatedCamera3() {}
-
-/****************************************************************************
- * Abstract API
- ***************************************************************************/
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-status_t EmulatedCamera3::Initialize(const cvd::CameraDefinition& /*params*/) {
-  ALOGV("%s", __FUNCTION__);
-
-  mStatus = STATUS_CLOSED;
-  return NO_ERROR;
-}
-
-/****************************************************************************
- * Camera API implementation
- ***************************************************************************/
-
-status_t EmulatedCamera3::connectCamera(hw_device_t** device) {
-  ALOGV("%s", __FUNCTION__);
-  if (device == NULL) return BAD_VALUE;
-
-  if (mStatus != STATUS_CLOSED) {
-    ALOGE("%s: Trying to open a camera in state %d!", __FUNCTION__, mStatus);
-    return INVALID_OPERATION;
-  }
-
-  *device = &common;
-  mStatus = STATUS_OPEN;
-  return NO_ERROR;
-}
-
-status_t EmulatedCamera3::closeCamera() {
-  mStatus = STATUS_CLOSED;
-  return NO_ERROR;
-}
-
-status_t EmulatedCamera3::getCameraInfo(struct camera_info* info) {
-  return EmulatedBaseCamera::getCameraInfo(info);
-}
-
-/****************************************************************************
- * Camera Device API implementation.
- * These methods are called from the camera API callback routines.
- ***************************************************************************/
-
-status_t EmulatedCamera3::initializeDevice(
-    const camera3_callback_ops* callbackOps) {
-  if (callbackOps == NULL) {
-    ALOGE("%s: NULL callback ops provided to HAL!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  if (mStatus != STATUS_OPEN) {
-    ALOGE("%s: Trying to initialize a camera in state %d!", __FUNCTION__,
-          mStatus);
-    return INVALID_OPERATION;
-  }
-
-  mCallbackOps = callbackOps;
-  mStatus = STATUS_READY;
-
-  return NO_ERROR;
-}
-
-status_t EmulatedCamera3::configureStreams(
-    camera3_stream_configuration* /*streamList*/) {
-  ALOGE("%s: Not implemented", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-status_t EmulatedCamera3::registerStreamBuffers(
-    const camera3_stream_buffer_set* /*bufferSet*/) {
-  ALOGE("%s: Not implemented", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-const camera_metadata_t* EmulatedCamera3::constructDefaultRequestSettings(
-    int /*type*/) {
-  ALOGE("%s: Not implemented", __FUNCTION__);
-  return NULL;
-}
-
-status_t EmulatedCamera3::processCaptureRequest(
-    camera3_capture_request* /*request*/) {
-  ALOGE("%s: Not implemented", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-status_t EmulatedCamera3::flush() {
-  ALOGE("%s: Not implemented", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-/** Debug methods */
-
-void EmulatedCamera3::dump(int /*fd*/) {
-  ALOGE("%s: Not implemented", __FUNCTION__);
-  return;
-}
-
-/****************************************************************************
- * Protected API. Callbacks to the framework.
- ***************************************************************************/
-
-void EmulatedCamera3::sendCaptureResult(camera3_capture_result_t* result) {
-  mCallbackOps->process_capture_result(mCallbackOps, result);
-}
-
-void EmulatedCamera3::sendNotify(camera3_notify_msg_t* msg) {
-  mCallbackOps->notify(mCallbackOps, msg);
-}
-
-/****************************************************************************
- * Private API.
- ***************************************************************************/
-
-/****************************************************************************
- * Camera API callbacks as defined by camera3_device_ops structure.  See
- * hardware/libhardware/include/hardware/camera3.h for information on each
- * of these callbacks. Implemented in this class, these callbacks simply
- * dispatch the call into an instance of EmulatedCamera3 class defined by the
- * 'camera_device3' parameter, or set a member value in the same.
- ***************************************************************************/
-
-EmulatedCamera3* getInstance(const camera3_device_t* d) {
-  const EmulatedCamera3* cec = static_cast<const EmulatedCamera3*>(d);
-  return const_cast<EmulatedCamera3*>(cec);
-}
-
-int EmulatedCamera3::initialize(const struct camera3_device* d,
-                                const camera3_callback_ops_t* callback_ops) {
-  EmulatedCamera3* ec = getInstance(d);
-  return ec->initializeDevice(callback_ops);
-}
-
-int EmulatedCamera3::configure_streams(
-    const struct camera3_device* d,
-    camera3_stream_configuration_t* stream_list) {
-  EmulatedCamera3* ec = getInstance(d);
-  return ec->configureStreams(stream_list);
-}
-
-int EmulatedCamera3::register_stream_buffers(
-    const struct camera3_device* d,
-    const camera3_stream_buffer_set_t* buffer_set) {
-  EmulatedCamera3* ec = getInstance(d);
-  return ec->registerStreamBuffers(buffer_set);
-}
-
-int EmulatedCamera3::process_capture_request(
-    const struct camera3_device* d, camera3_capture_request_t* request) {
-  EmulatedCamera3* ec = getInstance(d);
-  return ec->processCaptureRequest(request);
-}
-
-const camera_metadata_t* EmulatedCamera3::construct_default_request_settings(
-    const camera3_device_t* d, int type) {
-  EmulatedCamera3* ec = getInstance(d);
-  return ec->constructDefaultRequestSettings(type);
-}
-
-void EmulatedCamera3::dump(const camera3_device_t* d, int fd) {
-  EmulatedCamera3* ec = getInstance(d);
-  ec->dump(fd);
-}
-
-int EmulatedCamera3::flush(const camera3_device_t* d) {
-  EmulatedCamera3* ec = getInstance(d);
-  return ec->flush();
-}
-
-int EmulatedCamera3::close(struct hw_device_t* device) {
-  EmulatedCamera3* ec = static_cast<EmulatedCamera3*>(
-      reinterpret_cast<camera3_device_t*>(device));
-  if (ec == NULL) {
-    ALOGE("%s: Unexpected NULL camera3 device", __FUNCTION__);
-    return BAD_VALUE;
-  }
-  return ec->closeCamera();
-}
-
-camera3_device_ops_t EmulatedCamera3::sDeviceOps = {
-    EmulatedCamera3::initialize,
-    EmulatedCamera3::configure_streams,
-    /* DEPRECATED: register_stream_buffers */ nullptr,
-    EmulatedCamera3::construct_default_request_settings,
-    EmulatedCamera3::process_capture_request,
-    /* DEPRECATED: get_metadata_vendor_tag_ops */ nullptr,
-    EmulatedCamera3::dump,
-    EmulatedCamera3::flush,
-#ifdef CAMERA_DEVICE_API_VERSION_3_6
-    /*UNUSED: signal_stream_flush*/nullptr,
-    /*UNUSED: is_reconfiguration_required*/nullptr,
-#endif
-    {0}};
-
-const char* EmulatedCamera3::sAvailableCapabilitiesStrings[NUM_CAPABILITIES] = {
-    "BACKWARD_COMPATIBLE",
-    "MANUAL_SENSOR",
-    "MANUAL_POST_PROCESSING",
-    "RAW",
-    "PRIVATE_REPROCESSING",
-    "READ_SENSOR_SETTINGS",
-    "BURST_CAPTURE",
-    "YUV_REPROCESSING",
-    "DEPTH_OUTPUT",
-    "CONSTRAINED_HIGH_SPEED_VIDEO",
-    "FULL_LEVEL"};
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedCamera3.h b/guest/hals/camera/EmulatedCamera3.h
deleted file mode 100644
index 92fbb4d..0000000
--- a/guest/hals/camera/EmulatedCamera3.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H
-
-/**
- * Contains declaration of a class EmulatedCamera that encapsulates
- * functionality common to all version 3.0 emulated camera devices.  Instances
- * of this class (for each emulated camera) are created during the construction
- * of the EmulatedCameraFactory instance.  This class serves as an entry point
- * for all camera API calls that defined by camera3_device_ops_t API.
- */
-
-#include "EmulatedBaseCamera.h"
-#include "hardware/camera3.h"
-#include "system/camera_metadata.h"
-
-namespace android {
-
-/**
- * Encapsulates functionality common to all version 3.0 emulated camera devices
- *
- * Note that EmulatedCameraFactory instantiates an object of this class just
- * once, when EmulatedCameraFactory instance gets constructed. Connection to /
- * disconnection from the actual camera device is handled by calls to
- * connectDevice(), and closeCamera() methods of this class that are invoked in
- * response to hw_module_methods_t::open, and camera_device::close callbacks.
- */
-class EmulatedCamera3 : public camera3_device, public EmulatedBaseCamera {
- public:
-  /* Constructs EmulatedCamera3 instance.
-   * Param:
-   *  cameraId - Zero based camera identifier, which is an index of the camera
-   *      instance in camera factory's array.
-   *  module - Emulated camera HAL module descriptor.
-   */
-  EmulatedCamera3(int cameraId, struct hw_module_t *module);
-
-  /* Destructs EmulatedCamera2 instance. */
-  virtual ~EmulatedCamera3();
-
-  /* List of all defined capabilities plus useful HW levels */
-  enum AvailableCapabilities {
-    BACKWARD_COMPATIBLE,
-    MANUAL_SENSOR,
-    MANUAL_POST_PROCESSING,
-    RAW,
-    PRIVATE_REPROCESSING,
-    READ_SENSOR_SETTINGS,
-    BURST_CAPTURE,
-    YUV_REPROCESSING,
-    DEPTH_OUTPUT,
-    CONSTRAINED_HIGH_SPEED_VIDEO,
-    // Levels
-    FULL_LEVEL,
-
-    NUM_CAPABILITIES
-  };
-
-  // Char strings for above enum, with size NUM_CAPABILITIES
-  static const char *sAvailableCapabilitiesStrings[];
-
-  /****************************************************************************
-   * Abstract API
-   ***************************************************************************/
-
- public:
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  virtual status_t Initialize(const cvd::CameraDefinition &params);
-
-  /****************************************************************************
-   * Camera module API and generic hardware device API implementation
-   ***************************************************************************/
-
- public:
-  virtual status_t connectCamera(hw_device_t **device);
-
-  virtual status_t closeCamera();
-
-  virtual status_t getCameraInfo(struct camera_info *info);
-
-  /****************************************************************************
-   * Camera API implementation.
-   * These methods are called from the camera API callback routines.
-   ***************************************************************************/
-
- protected:
-  virtual status_t initializeDevice(const camera3_callback_ops *callbackOps);
-
-  virtual status_t configureStreams(camera3_stream_configuration *streamList);
-
-  virtual status_t registerStreamBuffers(
-      const camera3_stream_buffer_set *bufferSet);
-
-  virtual const camera_metadata_t *constructDefaultRequestSettings(int type);
-
-  virtual status_t processCaptureRequest(camera3_capture_request *request);
-
-  virtual status_t flush();
-
-  /** Debug methods */
-
-  virtual void dump(int fd);
-
-  /****************************************************************************
-   * Camera API callbacks as defined by camera3_device_ops structure.  See
-   * hardware/libhardware/include/hardware/camera3.h for information on each
-   * of these callbacks. Implemented in this class, these callbacks simply
-   * dispatch the call into an instance of EmulatedCamera3 class defined in
-   * the 'camera_device3' parameter.
-   ***************************************************************************/
-
- private:
-  /** Startup */
-  static int initialize(const struct camera3_device *,
-                        const camera3_callback_ops_t *callback_ops);
-
-  /** Stream configuration and buffer registration */
-
-  static int configure_streams(const struct camera3_device *,
-                               camera3_stream_configuration_t *stream_list);
-
-  static int register_stream_buffers(
-      const struct camera3_device *,
-      const camera3_stream_buffer_set_t *buffer_set);
-
-  /** Template request settings provision */
-
-  static const camera_metadata_t *construct_default_request_settings(
-      const struct camera3_device *, int type);
-
-  /** Submission of capture requests to HAL */
-
-  static int process_capture_request(const struct camera3_device *,
-                                     camera3_capture_request_t *request);
-
-  static void dump(const camera3_device_t *, int fd);
-
-  static int flush(const camera3_device_t *);
-
-  /** For hw_device_t ops */
-  static int close(struct hw_device_t *device);
-
-  /****************************************************************************
-   * Data members shared with implementations
-   ***************************************************************************/
- protected:
-  enum {
-    // State at construction time, and after a device operation error
-    STATUS_ERROR = 0,
-    // State after startup-time init and after device instance close
-    STATUS_CLOSED,
-    // State after being opened, before device instance init
-    STATUS_OPEN,
-    // State after device instance initialization
-    STATUS_READY,
-    // State while actively capturing data
-    STATUS_ACTIVE
-  } mStatus;
-
-  /**
-   * Callbacks back to the framework
-   */
-
-  void sendCaptureResult(camera3_capture_result_t *result);
-  void sendNotify(camera3_notify_msg_t *msg);
-
-  /****************************************************************************
-   * Data members
-   ***************************************************************************/
- private:
-  static camera3_device_ops_t sDeviceOps;
-  const camera3_callback_ops_t *mCallbackOps;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H */
diff --git a/guest/hals/camera/EmulatedCameraCommon.h b/guest/hals/camera/EmulatedCameraCommon.h
deleted file mode 100644
index 0ec7501..0000000
--- a/guest/hals/camera/EmulatedCameraCommon.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_COMMON_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_COMMON_H
-
-/*
- * Contains common declarations that are used across the camera emulation.
- */
-
-#include <hardware/camera.h>
-#include <linux/videodev2.h>
-
-/* A helper class that tracks a routine execution.
- * Basically, it dumps an enry message in its constructor, and an exit message
- * in its destructor. Use LOGRE() macro (declared bellow) to create instances
- * of this class at the beginning of the tracked routines / methods.
- */
-class HWERoutineTracker {
- public:
-  /* Constructor that prints an "entry" trace message. */
-  explicit HWERoutineTracker(const char* name) : mName(name) {
-    ALOGV("Entering %s", mName);
-  }
-
-  /* Destructor that prints a "leave" trace message. */
-  ~HWERoutineTracker() { ALOGV("Leaving %s", mName); }
-
- private:
-  /* Stores the routine name. */
-  const char* mName;
-};
-
-/* Logs an execution of a routine / method. */
-#define LOGRE() HWERoutineTracker hwertracker_##__LINE__(__FUNCTION__)
-
-/*
- * min / max macros
- */
-
-#define min(a, b) (((a) < (b)) ? (a) : (b))
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_COMMON_H */
diff --git a/guest/hals/camera/EmulatedCameraDevice.cpp b/guest/hals/camera/EmulatedCameraDevice.cpp
deleted file mode 100644
index d741b73..0000000
--- a/guest/hals/camera/EmulatedCameraDevice.cpp
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of an abstract class EmulatedCameraDevice that
- * defines functionality expected from an emulated physical camera device:
- *  - Obtaining and setting camera parameters
- *  - Capturing frames
- *  - Streaming video
- *  - etc.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Device"
-#include "EmulatedCameraDevice.h"
-#include <log/log.h>
-#include <sys/select.h>
-#include <algorithm>
-#include <cmath>
-#include "EmulatedCamera.h"
-
-namespace android {
-
-const float GAMMA_CORRECTION = 2.2f;
-EmulatedCameraDevice::EmulatedCameraDevice(EmulatedCamera* camera_hal)
-    : mObjectLock(),
-      mCurFrameTimestamp(0),
-      mCameraHAL(camera_hal),
-      mCurrentFrame(NULL),
-      mExposureCompensation(1.0f),
-      mWhiteBalanceScale(NULL),
-      mIsFocusing(false),
-      mSupportedWhiteBalanceScale(),
-      mState(ECDS_CONSTRUCTED) {}
-
-EmulatedCameraDevice::~EmulatedCameraDevice() {
-  ALOGV("EmulatedCameraDevice destructor");
-  if (mCurrentFrame != NULL) {
-    delete[] mCurrentFrame;
-  }
-  for (size_t i = 0; i < mSupportedWhiteBalanceScale.size(); ++i) {
-    if (mSupportedWhiteBalanceScale.valueAt(i) != NULL) {
-      delete[] mSupportedWhiteBalanceScale.valueAt(i);
-    }
-  }
-}
-
-/****************************************************************************
- * Emulated camera device public API
- ***************************************************************************/
-
-status_t EmulatedCameraDevice::Initialize() {
-  if (isInitialized()) {
-    ALOGW("%s: Emulated camera device is already initialized: mState = %d",
-          __FUNCTION__, mState);
-    return NO_ERROR;
-  }
-
-  /* Instantiate worker thread object. */
-  mWorkerThread = new WorkerThread(this);
-  if (getWorkerThread() == NULL) {
-    ALOGE("%s: Unable to instantiate worker thread object", __FUNCTION__);
-    return ENOMEM;
-  }
-
-  mState = ECDS_INITIALIZED;
-
-  return NO_ERROR;
-}
-
-status_t EmulatedCameraDevice::startDeliveringFrames(bool one_burst) {
-  ALOGV("%s", __FUNCTION__);
-
-  if (!isStarted()) {
-    ALOGE("%s: Device is not started", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* Frames will be delivered from the thread routine. */
-  const status_t res = startWorkerThread(one_burst);
-  ALOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
-  return res;
-}
-
-status_t EmulatedCameraDevice::stopDeliveringFrames() {
-  ALOGV("%s", __FUNCTION__);
-
-  if (!isStarted()) {
-    ALOGW("%s: Device is not started", __FUNCTION__);
-    return NO_ERROR;
-  }
-
-  const status_t res = stopWorkerThread();
-  ALOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
-  return res;
-}
-
-void EmulatedCameraDevice::setExposureCompensation(const float ev) {
-  ALOGV("%s", __FUNCTION__);
-
-  if (!isStarted()) {
-    ALOGW("%s: Fake camera device is not started.", __FUNCTION__);
-  }
-
-  mExposureCompensation = std::pow(2.0f, ev / GAMMA_CORRECTION);
-  ALOGV("New exposure compensation is %f", mExposureCompensation);
-}
-
-void EmulatedCameraDevice::initializeWhiteBalanceModes(const char* mode,
-                                                       const float r_scale,
-                                                       const float b_scale) {
-  ALOGV("%s with %s, %f, %f", __FUNCTION__, mode, r_scale, b_scale);
-  float* value = new float[3];
-  value[0] = r_scale;
-  value[1] = 1.0f;
-  value[2] = b_scale;
-  mSupportedWhiteBalanceScale.add(String8(mode), value);
-}
-
-void EmulatedCameraDevice::setWhiteBalanceMode(const char* mode) {
-  ALOGV("%s with white balance %s", __FUNCTION__, mode);
-  mWhiteBalanceScale = mSupportedWhiteBalanceScale.valueFor(String8(mode));
-}
-
-void EmulatedCameraDevice::startAutoFocus() { mIsFocusing = true; }
-
-/* Computes the pixel value after adjusting the white balance to the current
- * one. The input the y, u, v channel of the pixel and the adjusted value will
- * be stored in place. The adjustment is done in RGB space.
- */
-void EmulatedCameraDevice::changeWhiteBalance(uint8_t& y, uint8_t& u,
-                                              uint8_t& v) const {
-  float r_scale = mWhiteBalanceScale[0];
-  float b_scale = mWhiteBalanceScale[2];
-  int r = static_cast<float>(YUV2R(y, u, v)) / r_scale;
-  int g = YUV2G(y, u, v);
-  int b = static_cast<float>(YUV2B(y, u, v)) / b_scale;
-
-  y = RGB2Y(r, g, b);
-  u = RGB2U(r, g, b);
-  v = RGB2V(r, g, b);
-}
-
-void EmulatedCameraDevice::simulateAutoFocus() {
-  if (mIsFocusing) {
-    ALOGV("%s: Simulating auto-focus", __FUNCTION__);
-    mCameraHAL->onCameraFocusAcquired();
-    mIsFocusing = false;
-  }
-}
-
-status_t EmulatedCameraDevice::getCurrentPreviewFrame(void* buffer) {
-  if (!isStarted()) {
-    ALOGE("%s: Device is not started", __FUNCTION__);
-    return EINVAL;
-  }
-  if (mCurrentFrame == NULL || buffer == NULL) {
-    ALOGE("%s: No framebuffer", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* In emulation the framebuffer is never RGB. */
-  switch (mPixelFormat) {
-    case V4L2_PIX_FMT_YVU420:
-      YV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
-      return NO_ERROR;
-    case V4L2_PIX_FMT_YUV420:
-      YU12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
-      return NO_ERROR;
-    case V4L2_PIX_FMT_NV21:
-      NV21ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
-      return NO_ERROR;
-    case V4L2_PIX_FMT_NV12:
-      NV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
-      return NO_ERROR;
-
-    default:
-      ALOGE("%s: Unknown pixel format %.4s", __FUNCTION__,
-            reinterpret_cast<const char*>(&mPixelFormat));
-      return EINVAL;
-  }
-}
-
-/****************************************************************************
- * Emulated camera device private API
- ***************************************************************************/
-
-status_t EmulatedCameraDevice::commonStartDevice(int width, int height,
-                                                 uint32_t pix_fmt, int fps) {
-  /* Validate pixel format, and calculate framebuffer size at the same time. */
-  switch (pix_fmt) {
-    case V4L2_PIX_FMT_YVU420:
-    case V4L2_PIX_FMT_YUV420:
-    case V4L2_PIX_FMT_NV21:
-    case V4L2_PIX_FMT_NV12:
-      mFrameBufferSize = (width * height * 12) / 8;
-      break;
-
-    default:
-      ALOGE("%s: Unknown pixel format %.4s", __FUNCTION__,
-            reinterpret_cast<const char*>(&pix_fmt));
-      return EINVAL;
-  }
-
-  /* Cache framebuffer info. */
-  mFrameWidth = width;
-  mFrameHeight = height;
-  mPixelFormat = pix_fmt;
-  mTotalPixels = width * height;
-  mTargetFps = fps;
-
-  /* Allocate framebuffer. */
-  mCurrentFrame = new uint8_t[mFrameBufferSize];
-  if (mCurrentFrame == NULL) {
-    ALOGE("%s: Unable to allocate framebuffer", __FUNCTION__);
-    return ENOMEM;
-  }
-  ALOGV("%s: Allocated %p %zu bytes for %d pixels in %.4s[%dx%d] frame",
-        __FUNCTION__, mCurrentFrame, mFrameBufferSize, mTotalPixels,
-        reinterpret_cast<const char*>(&mPixelFormat), mFrameWidth,
-        mFrameHeight);
-  return NO_ERROR;
-}
-
-void EmulatedCameraDevice::commonStopDevice() {
-  mFrameWidth = mFrameHeight = mTotalPixels = 0;
-  mPixelFormat = 0;
-  mTargetFps = 0;
-
-  if (mCurrentFrame != NULL) {
-    delete[] mCurrentFrame;
-    mCurrentFrame = NULL;
-  }
-}
-
-const CameraParameters* EmulatedCameraDevice::getCameraParameters() {
-  return mCameraHAL->getCameraParameters();
-}
-
-/****************************************************************************
- * Worker thread management.
- ***************************************************************************/
-
-status_t EmulatedCameraDevice::startWorkerThread(bool one_burst) {
-  ALOGV("%s", __FUNCTION__);
-
-  if (!isInitialized()) {
-    ALOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
-    return EINVAL;
-  }
-
-  const status_t res = getWorkerThread()->startThread(one_burst);
-  ALOGE_IF(res != NO_ERROR, "%s: Unable to start worker thread", __FUNCTION__);
-  return res;
-}
-
-status_t EmulatedCameraDevice::stopWorkerThread() {
-  ALOGV("%s", __FUNCTION__);
-
-  if (!isInitialized()) {
-    ALOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
-    return EINVAL;
-  }
-
-  const status_t res = getWorkerThread()->stopThread();
-  ALOGE_IF(res != NO_ERROR, "%s: Unable to stop worker thread", __FUNCTION__);
-  return res;
-}
-
-bool EmulatedCameraDevice::inWorkerThread() {
-  /* This will end the thread loop, and will terminate the thread. Derived
-   * classes must override this method. */
-  return false;
-}
-
-/****************************************************************************
- * Worker thread implementation.
- ***************************************************************************/
-
-status_t EmulatedCameraDevice::WorkerThread::readyToRun() {
-  ALOGV("Starting emulated camera device worker thread...");
-
-  ALOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
-           "%s: Thread control FDs are opened", __FUNCTION__);
-  /* Create a pair of FDs that would be used to control the thread. */
-  int thread_fds[2];
-  status_t ret;
-  Mutex::Autolock lock(mCameraDevice->mObjectLock);
-  if (pipe(thread_fds) == 0) {
-    mThreadControl = thread_fds[1];
-    mControlFD = thread_fds[0];
-    ALOGV("Emulated device's worker thread has been started.");
-    ret = NO_ERROR;
-  } else {
-    ALOGE("%s: Unable to create thread control FDs: %d -> %s", __FUNCTION__,
-          errno, strerror(errno));
-    ret = errno;
-  }
-
-  mSetup.signal();
-  return ret;
-}
-
-status_t EmulatedCameraDevice::WorkerThread::stopThread() {
-  ALOGV("Stopping emulated camera device's worker thread...");
-
-  status_t res = EINVAL;
-
-  // Limit the scope of the Autolock
-  {
-    // If thread is running and readyToRun() has not finished running,
-    //    then wait until it is done.
-    Mutex::Autolock lock(mCameraDevice->mObjectLock);
-    if (isRunning() && (mThreadControl < 0 || mControlFD < 0)) {
-      mSetup.wait(mCameraDevice->mObjectLock);
-    }
-  }
-
-  if (mThreadControl >= 0) {
-    /* Send "stop" message to the thread loop. */
-    const ControlMessage msg = THREAD_STOP;
-    const int wres =
-        TEMP_FAILURE_RETRY(write(mThreadControl, &msg, sizeof(msg)));
-    if (wres == sizeof(msg)) {
-      /* Stop the thread, and wait till it's terminated. */
-      res = requestExitAndWait();
-      if (res == NO_ERROR) {
-        /* Close control FDs. */
-        if (mThreadControl >= 0) {
-          close(mThreadControl);
-          mThreadControl = -1;
-        }
-        if (mControlFD >= 0) {
-          close(mControlFD);
-          mControlFD = -1;
-        }
-        ALOGV("Emulated camera device's worker thread has been stopped.");
-      } else {
-        ALOGE("%s: requestExitAndWait failed: %d -> %s", __FUNCTION__, res,
-              strerror(-res));
-      }
-    } else {
-      ALOGE("%s: Unable to send THREAD_STOP message: %d -> %s", __FUNCTION__,
-            errno, strerror(errno));
-      res = errno ? errno : EINVAL;
-    }
-  } else {
-    ALOGE("%s: Thread control FDs are not opened", __FUNCTION__);
-  }
-
-  return res;
-}
-
-EmulatedCameraDevice::WorkerThread::SelectRes
-EmulatedCameraDevice::WorkerThread::Select(int fd, int timeout) {
-  fd_set fds[1];
-  struct timeval tv, *tvp = NULL;
-
-  mCameraDevice->simulateAutoFocus();
-
-  const int fd_num = (fd >= 0) ? std::max(fd, mControlFD) + 1 : mControlFD + 1;
-  FD_ZERO(fds);
-  FD_SET(mControlFD, fds);
-  if (fd >= 0) {
-    FD_SET(fd, fds);
-  }
-  if (timeout) {
-    tv.tv_sec = timeout / 1000000;
-    tv.tv_usec = timeout % 1000000;
-    tvp = &tv;
-  }
-  int res = TEMP_FAILURE_RETRY(select(fd_num, fds, NULL, NULL, tvp));
-  if (res < 0) {
-    ALOGE("%s: select returned %d and failed: %d -> %s", __FUNCTION__, res,
-          errno, strerror(errno));
-    return ERROR;
-  } else if (res == 0) {
-    /* Timeout. */
-    return TIMEOUT;
-  } else if (FD_ISSET(mControlFD, fds)) {
-    /* A control event. Lets read the message. */
-    ControlMessage msg;
-    res = TEMP_FAILURE_RETRY(read(mControlFD, &msg, sizeof(msg)));
-    if (res != sizeof(msg)) {
-      ALOGE("%s: Unexpected message size %d, or an error %d -> %s",
-            __FUNCTION__, res, errno, strerror(errno));
-      return ERROR;
-    }
-    /* THREAD_STOP is the only message expected here. */
-    if (msg == THREAD_STOP) {
-      ALOGV("%s: THREAD_STOP message is received", __FUNCTION__);
-      return EXIT_THREAD;
-    } else {
-      ALOGE("Unknown worker thread message %d", msg);
-      return ERROR;
-    }
-  } else {
-    /* Must be an FD. */
-    ALOGW_IF(fd < 0 || !FD_ISSET(fd, fds), "%s: Undefined 'select' result",
-             __FUNCTION__);
-    return READY;
-  }
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedCameraDevice.h b/guest/hals/camera/EmulatedCameraDevice.h
deleted file mode 100644
index ab654eb..0000000
--- a/guest/hals/camera/EmulatedCameraDevice.h
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
-
-/*
- * Contains declaration of an abstract class EmulatedCameraDevice that defines
- * functionality expected from an emulated physical camera device:
- *  - Obtaining and setting camera device parameters
- *  - Capturing frames
- *  - Streaming video
- *  - etc.
- */
-
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-#include "Converters.h"
-#include "EmulatedCameraCommon.h"
-
-#include <CameraParameters.h>
-
-using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
-
-namespace android {
-
-class EmulatedCamera;
-
-/* Encapsulates an abstract class EmulatedCameraDevice that defines
- * functionality expected from an emulated physical camera device:
- *  - Obtaining and setting camera device parameters
- *  - Capturing frames
- *  - Streaming video
- *  - etc.
- */
-class EmulatedCameraDevice {
- public:
-  /* Constructs EmulatedCameraDevice instance.
-   * Param:
-   *  camera_hal - Emulated camera that implements the camera HAL API, and
-   *      manages (contains) this object.
-   */
-  explicit EmulatedCameraDevice(EmulatedCamera* camera_hal);
-
-  /* Destructs EmulatedCameraDevice instance. */
-  virtual ~EmulatedCameraDevice();
-
-  /***************************************************************************
-   * Emulated camera device abstract interface
-   **************************************************************************/
-
- public:
-  /* Connects to the camera device.
-   * This method must be called on an initialized instance of this class.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t connectDevice() = 0;
-
-  /* Disconnects from the camera device.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status. If this method is
-   *  called for already disconnected, or uninitialized instance of this class,
-   *  a successful status must be returned from this method. If this method is
-   *  called for an instance that is in the "started" state, this method must
-   *  return a failure.
-   */
-  virtual status_t disconnectDevice() = 0;
-
-  /* Starts the camera device.
-   * This method tells the camera device to start capturing frames of the given
-   * dimensions for the given pixel format. Note that this method doesn't start
-   * the delivery of the captured frames to the emulated camera. Call
-   * startDeliveringFrames method to start delivering frames. This method must
-   * be called on a connected instance of this class. If it is called on a
-   * disconnected instance, this method must return a failure.
-   * Param:
-   *  width, height - Frame dimensions to use when capturing video frames.
-   *  pix_fmt - Pixel format to use when capturing video frames.
-   *  fps - Target rate of frames per second.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t startDevice(int width, int height, uint32_t pix_fmt,
-                               int fps) = 0;
-
-  /* Stops the camera device.
-   * This method tells the camera device to stop capturing frames. Note that
-   * this method doesn't stop delivering frames to the emulated camera. Always
-   * call stopDeliveringFrames prior to calling this method.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status. If this method is
-   *  called for an object that is not capturing frames, or is disconnected,
-   *  or is uninitialized, a successful status must be returned from this
-   *  method.
-   */
-  virtual status_t stopDevice() = 0;
-
-  /***************************************************************************
-   * Emulated camera device public API
-   **************************************************************************/
-
- public:
-  /* Initializes EmulatedCameraDevice instance.
-   * Derived classes should override this method in order to cache static
-   * properties of the physical device (list of supported pixel formats, frame
-   * sizes, etc.) If this method is called on an already initialized instance,
-   * it must return a successful status.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t Initialize();
-
-  /* Initializes the white balance modes parameters.
-   * The parameters are passed by each individual derived camera API to
-   * represent that different camera manufacturers may have different
-   * preferences on the white balance parameters. Green channel in the RGB
-   * color space is fixed to keep the luminance to be reasonably constant.
-   *
-   * Param:
-   * mode the text describing the current white balance mode
-   * r_scale the scale factor for the R channel in RGB space
-   * b_scale the scale factor for the B channel in RGB space.
-   */
-  void initializeWhiteBalanceModes(const char* mode, const float r_scale,
-                                   const float b_scale);
-
-  /* Starts delivering frames captured from the camera device.
-   * This method will start the worker thread that would be pulling frames from
-   * the camera device, and will deliver the pulled frames back to the emulated
-   * camera via onNextFrameAvailable callback. This method must be called on a
-   * connected instance of this class with a started camera device. If it is
-   * called on a disconnected instance, or camera device has not been started,
-   * this method must return a failure.
-   * Param:
-   *  one_burst - Controls how many frames should be delivered. If this
-   *      parameter is 'true', only one captured frame will be delivered to the
-   *      emulated camera. If this parameter is 'false', frames will keep
-   *      coming until stopDeliveringFrames method is called. Typically, this
-   *      parameter is set to 'true' only in order to obtain a single frame
-   *      that will be used as a "picture" in takePicture method of the
-   *      emulated camera.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t startDeliveringFrames(bool one_burst);
-
-  /* Stops delivering frames captured from the camera device.
-   * This method will stop the worker thread started by startDeliveringFrames.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t stopDeliveringFrames();
-
-  /* Sets the exposure compensation for the camera device.
-   */
-  void setExposureCompensation(const float ev);
-
-  /* Sets the white balance mode for the device.
-   */
-  void setWhiteBalanceMode(const char* mode);
-
-  /* Initiates focus operation.
-   */
-  virtual void startAutoFocus();
-
-  /* Gets current framebuffer, converted into preview frame format.
-   * This method must be called on a connected instance of this class with a
-   * started camera device. If it is called on a disconnected instance, or
-   * camera device has not been started, this method must return a failure.
-   * Note that this method should be called only after at least one frame has
-   * been captured and delivered. Otherwise it will return garbage in the
-   * preview frame buffer. Typically, this method shuld be called from
-   * onNextFrameAvailable callback.
-   * Param:
-   *  buffer - Buffer, large enough to contain the entire preview frame.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t getCurrentPreviewFrame(void* buffer);
-
-  /* Gets width of the frame obtained from the physical device.
-   * Return:
-   *  Width of the frame obtained from the physical device. Note that value
-   *  returned from this method is valid only in case if camera device has been
-   *  started.
-   */
-  inline int getFrameWidth() const {
-    ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
-    return mFrameWidth;
-  }
-
-  /* Gets height of the frame obtained from the physical device.
-   * Return:
-   *  Height of the frame obtained from the physical device. Note that value
-   *  returned from this method is valid only in case if camera device has been
-   *  started.
-   */
-  inline int getFrameHeight() const {
-    ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
-    return mFrameHeight;
-  }
-
-  /* Gets byte size of the current frame buffer.
-   * Return:
-   *  Byte size of the frame buffer. Note that value returned from this method
-   *  is valid only in case if camera device has been started.
-   */
-  inline size_t getFrameBufferSize() const {
-    ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
-    return mFrameBufferSize;
-  }
-
-  /* Gets number of pixels in the current frame buffer.
-   * Return:
-   *  Number of pixels in the frame buffer. Note that value returned from this
-   *  method is valid only in case if camera device has been started.
-   */
-  inline int getPixelNum() const {
-    ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
-    return mTotalPixels;
-  }
-
-  /* Gets pixel format of the frame that camera device streams to this class.
-   * Throughout camera framework, there are three different forms of pixel
-   * format representation:
-   *  - Original format, as reported by the actual camera device. Values for
-   *    this format are declared in bionic/libc/kernel/common/linux/videodev2.h
-   *  - String representation as defined in CameraParameters::PIXEL_FORMAT_XXX
-   *    strings in frameworks/base/include/camera/CameraParameters.h
-   *  - HAL_PIXEL_FORMAT_XXX format, as defined in
-   * system/core/include/system/graphics.h Since emulated camera device gets its
-   * data from the actual device, it gets pixel format in the original form. And
-   * that's the pixel format representation that will be returned from this
-   * method. HAL components will need to translate value returned from this
-   * method to the appropriate form. This method must be called only on started
-   * instance of this class, since it's applicable only when camera device is
-   * ready to stream frames. Param: pix_fmt - Upon success contains the original
-   * pixel format. Return: Current framebuffer's pixel format. Note that value
-   * returned from this method is valid only in case if camera device has been
-   * started.
-   */
-  inline uint32_t getOriginalPixelFormat() const {
-    ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
-    return mPixelFormat;
-  }
-
-  /* Gets image metadata (from HAL).
-   * Return:
-   *  Filled in ImageMetadata structure (in/out parameter).
-   */
-  const CameraParameters* getCameraParameters();
-
-  /*
-   * State checkers.
-   */
-
-  inline bool isInitialized() const {
-    /* Instance is initialized when the worker thread has been successfuly
-     * created (but not necessarily started). */
-    return mWorkerThread.get() != NULL && mState != ECDS_CONSTRUCTED;
-  }
-  inline bool isConnected() const {
-    /* Instance is connected when its status is either"connected", or
-     * "started". */
-    return mState == ECDS_CONNECTED || mState == ECDS_STARTED;
-  }
-  inline bool isStarted() const { return mState == ECDS_STARTED; }
-
-  /****************************************************************************
-   * Emulated camera device private API
-   ***************************************************************************/
- protected:
-  /* Performs common validation and calculation of startDevice parameters.
-   * Param:
-   *  width, height, pix_fmt, fps - Parameters passed to startDevice method.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t commonStartDevice(int width, int height, uint32_t pix_fmt,
-                                     int fps);
-
-  /* Performs common cleanup on stopDevice.
-   * This method will undo what commonStartDevice had done.
-   */
-  virtual void commonStopDevice();
-
-  /** Computes a luminance value after taking the exposure compensation.
-   * value into account.
-   *
-   * Param:
-   * inputY - The input luminance value.
-   * Return:
-   * The luminance value after adjusting the exposure compensation.
-   */
-  inline uint8_t changeExposure(const uint8_t& inputY) const {
-    return static_cast<uint8_t>(
-        clamp(static_cast<float>(inputY) * mExposureCompensation));
-  }
-
-  /** Simulates focusing and reports completion to the client.
-   */
-  void simulateAutoFocus();
-
-  /** Computes the pixel value in YUV space after adjusting to the current
-   * white balance mode.
-   */
-  void changeWhiteBalance(uint8_t& y, uint8_t& u, uint8_t& v) const;
-
-  /****************************************************************************
-   * Worker thread management.
-   * Typicaly when emulated camera device starts capturing frames from the
-   * actual device, it does that in a worker thread created in StartCapturing,
-   * and terminated in StopCapturing. Since this is such a typical scenario,
-   * it makes sence to encapsulate worker thread management in the base class
-   * for all emulated camera devices.
-   ***************************************************************************/
-
- protected:
-  /* Starts the worker thread.
-   * Typically, worker thread is started from startDeliveringFrames method of
-   * this class.
-   * Param:
-   *  one_burst - Controls how many times thread loop should run. If this
-   *      parameter is 'true', thread routine will run only once If this
-   *      parameter is 'false', thread routine will run until stopWorkerThread
-   *      method is called. See startDeliveringFrames for more info.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t startWorkerThread(bool one_burst);
-
-  /* Stops the worker thread.
-   * Note that this method will always wait for the worker thread to terminate.
-   * Typically, worker thread is started from stopDeliveringFrames method of
-   * this class.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t stopWorkerThread();
-
-  /* Implementation of the worker thread routine.
-   * In the default implementation of the worker thread routine we simply
-   * return 'false' forcing the thread loop to exit, and the thread to
-   * terminate. Derived class should override that method to provide there the
-   * actual frame delivery.
-   * Return:
-   *  true To continue thread loop (this method will be called again), or false
-   *  to exit the thread loop and to terminate the thread.
-   */
-  virtual bool inWorkerThread();
-
-  /* Encapsulates a worker thread used by the emulated camera device.
-   */
-  friend class WorkerThread;
-  class WorkerThread : public Thread {
-    /****************************************************************************
-     * Public API
-     ***************************************************************************/
-
-   public:
-    inline explicit WorkerThread(EmulatedCameraDevice* camera_dev)
-        : Thread(true),  // Callbacks may involve Java calls.
-          mCameraDevice(camera_dev),
-          mThreadControl(-1),
-          mControlFD(-1) {}
-
-    inline ~WorkerThread() {
-      ALOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
-               "%s: Control FDs are opened in the destructor", __FUNCTION__);
-      if (mThreadControl >= 0) {
-        close(mThreadControl);
-      }
-      if (mControlFD >= 0) {
-        close(mControlFD);
-      }
-    }
-
-    /* Starts the thread
-     * Param:
-     *  one_burst - Controls how many times thread loop should run. If
-     *      this parameter is 'true', thread routine will run only once
-     *      If this parameter is 'false', thread routine will run until
-     *      stopThread method is called. See startWorkerThread for more
-     *      info.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    inline status_t startThread(bool one_burst) {
-      mOneBurst = one_burst;
-      return run("Camera_startThread", ANDROID_PRIORITY_URGENT_DISPLAY, 0);
-    }
-
-    /* Overriden base class method.
-     * It is overriden in order to provide one-time initialization just
-     * prior to starting the thread routine.
-     */
-    status_t readyToRun();
-
-    /* Stops the thread. */
-    status_t stopThread();
-
-    /* Values returned from the Select method of this class. */
-    enum SelectRes {
-      /* A timeout has occurred. */
-      TIMEOUT,
-      /* Data are available for read on the provided FD. */
-      READY,
-      /* Thread exit request has been received. */
-      EXIT_THREAD,
-      /* An error has occurred. */
-      ERROR
-    };
-
-    /* Select on an FD event, keeping in mind thread exit message.
-     * Param:
-     *  fd - File descriptor on which to wait for an event. This
-     *      parameter may be negative. If it is negative this method will
-     *      only wait on a control message to the thread.
-     *  timeout - Timeout in microseconds. 0 indicates no timeout (wait
-     *      forever).
-     * Return:
-     *  See SelectRes enum comments.
-     */
-    SelectRes Select(int fd, int timeout);
-
-    /****************************************************************************
-     * Private API
-     ***************************************************************************/
-
-   private:
-    /* Implements abstract method of the base Thread class. */
-    bool threadLoop() {
-      /* Simply dispatch the call to the containing camera device. */
-      if (mCameraDevice->inWorkerThread()) {
-        /* Respect "one burst" parameter (see startThread). */
-        return !mOneBurst;
-      } else {
-        return false;
-      }
-    }
-
-    /* Containing camera device object. */
-    EmulatedCameraDevice* mCameraDevice;
-
-    /* FD that is used to send control messages into the thread. */
-    int mThreadControl;
-
-    /* FD that thread uses to receive control messages. */
-    int mControlFD;
-
-    /* Controls number of times the thread loop runs.
-     * See startThread for more information. */
-    bool mOneBurst;
-
-    /* Enumerates control messages that can be sent into the thread. */
-    enum ControlMessage {
-      /* Stop the thread. */
-      THREAD_STOP
-    };
-
-    Condition mSetup;
-  };
-
-  /* Worker thread accessor. */
-  inline WorkerThread* getWorkerThread() const { return mWorkerThread.get(); }
-
-  /****************************************************************************
-   * Data members
-   ***************************************************************************/
-
- protected:
-  /* Locks this instance for parameters, state, etc. change. */
-  Mutex mObjectLock;
-
-  /* Worker thread that is used in frame capturing. */
-  sp<WorkerThread> mWorkerThread;
-
-  /* Timestamp of the current frame. */
-  nsecs_t mCurFrameTimestamp;
-
-  /* Emulated camera object containing this instance. */
-  EmulatedCamera* mCameraHAL;
-
-  /* Framebuffer containing the current frame. */
-  uint8_t* mCurrentFrame;
-
-  /*
-   * Framebuffer properties.
-   */
-
-  /* Byte size of the framebuffer. */
-  size_t mFrameBufferSize;
-
-  /* Original pixel format (one of the V4L2_PIX_FMT_XXX values, as defined in
-   * bionic/libc/kernel/common/linux/videodev2.h */
-  uint32_t mPixelFormat;
-
-  /* Frame width */
-  int mFrameWidth;
-
-  /* Frame height */
-  int mFrameHeight;
-
-  /* Total number of pixels */
-  int mTotalPixels;
-
-  /* Requested FPS rate */
-  int mTargetFps;
-
-  /* Exposure compensation value */
-  float mExposureCompensation;
-
-  float* mWhiteBalanceScale;
-
-  bool mIsFocusing;
-
-  DefaultKeyedVector<String8, float*> mSupportedWhiteBalanceScale;
-
-  /* Defines possible states of the emulated camera device object.
-   */
-  enum EmulatedCameraDeviceState {
-    /* Object has been constructed. */
-    ECDS_CONSTRUCTED,
-    /* Object has been initialized. */
-    ECDS_INITIALIZED,
-    /* Object has been connected to the physical device. */
-    ECDS_CONNECTED,
-    /* Camera device has been started. */
-    ECDS_STARTED,
-  };
-
-  /* Object state. */
-  EmulatedCameraDeviceState mState;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H */
diff --git a/guest/hals/camera/EmulatedCameraFactory.cpp b/guest/hals/camera/EmulatedCameraFactory.cpp
deleted file mode 100644
index 009e194..0000000
--- a/guest/hals/camera/EmulatedCameraFactory.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class EmulatedCameraFactory that manages cameras
- * available for emulation.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Factory"
-#include <log/log.h>
-#include <cutils/properties.h>
-#include "EmulatedFakeCamera.h"
-
-#include "EmulatedCameraHotplugThread.h"
-#include "EmulatedFakeCamera2.h"
-
-#include "EmulatedFakeCamera3.h"
-
-#include "EmulatedCameraFactory.h"
-
-extern camera_module_t HAL_MODULE_INFO_SYM;
-
-namespace android {
-EmulatedCameraFactory& EmulatedCameraFactory::Instance() {
-  static EmulatedCameraFactory* factory = new EmulatedCameraFactory;
-  return *factory;
-}
-
-EmulatedCameraFactory::EmulatedCameraFactory()
-    : mCallbacks(NULL)
-{
-  mCameraConfiguration.Init();
-  const std::vector<cvd::CameraDefinition>& cameras =
-      mCameraConfiguration.cameras();
-  for (size_t camera_index = 0; camera_index < cameras.size(); ++camera_index) {
-    mCameraDefinitions.push(cameras[camera_index]);
-    /* Reserve a spot for camera, but don't create just yet. */
-    mEmulatedCameras.push(NULL);
-  }
-
-  ALOGV("%zu cameras are being emulated.", getEmulatedCameraNum());
-
-  /* Create hotplug thread */
-  {
-    mHotplugThread = new EmulatedCameraHotplugThread(getEmulatedCameraNum());
-    mHotplugThread->run("EmulatedCameraHotplugThread");
-  }
-}
-
-EmulatedBaseCamera* EmulatedCameraFactory::getOrCreateFakeCamera(
-    size_t cameraId) {
-  std::lock_guard lock(mEmulatedCamerasMutex);
-
-  if (cameraId >= getEmulatedCameraNum()) {
-    ALOGE("%s: Invalid camera ID: %zu", __FUNCTION__, cameraId);
-    return NULL;
-  }
-
-  if (mEmulatedCameras[cameraId] != NULL) {
-    return mEmulatedCameras[cameraId];
-  }
-
-  const cvd::CameraDefinition& definition = mCameraDefinitions[cameraId];
-  bool is_back_facing =
-      (definition.orientation == cvd::CameraDefinition::kBack);
-
-  EmulatedBaseCamera* camera;
-  /* Create, and initialize the fake camera */
-  switch (definition.hal_version) {
-    case cvd::CameraDefinition::kHalV1:
-      camera = new EmulatedFakeCamera(cameraId, is_back_facing,
-                                      &HAL_MODULE_INFO_SYM.common);
-      break;
-    case cvd::CameraDefinition::kHalV2:
-      camera = new EmulatedFakeCamera2(cameraId, is_back_facing,
-                                       &HAL_MODULE_INFO_SYM.common);
-      break;
-    case cvd::CameraDefinition::kHalV3:
-      camera = new EmulatedFakeCamera3(cameraId, is_back_facing,
-                                       &HAL_MODULE_INFO_SYM.common);
-      break;
-    default:
-      ALOGE("%s: Unsupported camera hal version requested: %d", __FUNCTION__,
-            definition.hal_version);
-      return NULL;
-  }
-
-  ALOGI("%s: Camera device %zu hal version is %d", __FUNCTION__, cameraId,
-        definition.hal_version);
-  int res = camera->Initialize(definition);
-
-  if (res != NO_ERROR) {
-    ALOGE("%s: Unable to intialize camera %zu: %s (%d)", __FUNCTION__, cameraId,
-          strerror(-res), res);
-    delete camera;
-    return NULL;
-  }
-
-  ALOGI("%s: Inserting camera", __FUNCTION__);
-  mEmulatedCameras.replaceAt(camera, cameraId);
-  ALOGI("%s: Done", __FUNCTION__);
-  return camera;
-}
-
-EmulatedCameraFactory::~EmulatedCameraFactory() {
-  for (size_t n = 0; n < mEmulatedCameras.size(); n++) {
-    if (mEmulatedCameras[n] != NULL) {
-      delete mEmulatedCameras[n];
-    }
-  }
-
-  if (mHotplugThread != NULL) {
-    mHotplugThread->requestExit();
-    mHotplugThread->join();
-  }
-}
-
-/****************************************************************************
- * Camera HAL API handlers.
- *
- * Each handler simply verifies existence of an appropriate EmulatedBaseCamera
- * instance, and dispatches the call to that instance.
- *
- ***************************************************************************/
-
-int EmulatedCameraFactory::cameraDeviceOpen(int camera_id,
-                                            hw_device_t** device) {
-  ALOGV("%s: id = %d", __FUNCTION__, camera_id);
-
-  *device = NULL;
-
-  EmulatedBaseCamera* camera = getOrCreateFakeCamera(camera_id);
-  if (camera == NULL) return -EINVAL;
-
-  return camera->connectCamera(device);
-}
-
-int EmulatedCameraFactory::getCameraInfo(int camera_id,
-                                         struct camera_info* info) {
-  ALOGV("%s: id = %d", __FUNCTION__, camera_id);
-
-  EmulatedBaseCamera* camera = getOrCreateFakeCamera(camera_id);
-  if (camera == NULL) return -EINVAL;
-
-  return camera->getCameraInfo(info);
-}
-
-int EmulatedCameraFactory::setCallbacks(
-    const camera_module_callbacks_t* callbacks) {
-  ALOGV("%s: callbacks = %p", __FUNCTION__, callbacks);
-
-  mCallbacks = callbacks;
-
-  return OK;
-}
-
-void EmulatedCameraFactory::getVendorTagOps(vendor_tag_ops_t* ops) {
-  ALOGV("%s: ops = %p", __FUNCTION__, ops);
-
-  // No vendor tags defined for emulator yet, so not touching ops
-}
-
-int EmulatedCameraFactory::setTorchMode(const char* camera_id, bool enabled) {
-  ALOGV("%s: camera_id = %s, enabled =%d", __FUNCTION__, camera_id, enabled);
-
-  EmulatedBaseCamera* camera = getOrCreateFakeCamera(atoi(camera_id));
-  if (camera == NULL) return -EINVAL;
-
-  return camera->setTorchMode(enabled);
-}
-
-/****************************************************************************
- * Camera HAL API callbacks.
- ***************************************************************************/
-
-int EmulatedCameraFactory::device_open(const hw_module_t* module,
-                                       const char* name, hw_device_t** device) {
-  /*
-   * Simply verify the parameters, and dispatch the call inside the
-   * EmulatedCameraFactory instance.
-   */
-
-  if (module != &HAL_MODULE_INFO_SYM.common) {
-    ALOGE("%s: Invalid module %p expected %p", __FUNCTION__, module,
-          &HAL_MODULE_INFO_SYM.common);
-    return -EINVAL;
-  }
-  if (name == NULL) {
-    ALOGE("%s: NULL name is not expected here", __FUNCTION__);
-    return -EINVAL;
-  }
-
-  return EmulatedCameraFactory::Instance().cameraDeviceOpen(atoi(name), device);
-}
-
-int EmulatedCameraFactory::get_number_of_cameras(void) {
-  return EmulatedCameraFactory::Instance().getEmulatedCameraNum();
-}
-
-int EmulatedCameraFactory::get_camera_info(int camera_id,
-                                           struct camera_info* info) {
-  return EmulatedCameraFactory::Instance().getCameraInfo(camera_id, info);
-}
-
-int EmulatedCameraFactory::set_callbacks(
-    const camera_module_callbacks_t* callbacks) {
-  return EmulatedCameraFactory::Instance().setCallbacks(callbacks);
-}
-
-void EmulatedCameraFactory::get_vendor_tag_ops(vendor_tag_ops_t* ops) {
-  EmulatedCameraFactory::Instance().getVendorTagOps(ops);
-}
-
-int EmulatedCameraFactory::open_legacy(const struct hw_module_t* /*module*/,
-                                       const char* /*id*/,
-                                       uint32_t /*halVersion*/,
-                                       struct hw_device_t** /*device*/) {
-  // Not supporting legacy open
-  return -ENOSYS;
-}
-
-int EmulatedCameraFactory::set_torch_mode(const char* camera_id, bool enabled) {
-  return EmulatedCameraFactory::Instance().setTorchMode(camera_id, enabled);
-}
-
-/********************************************************************************
- * Internal API
- *******************************************************************************/
-
-void EmulatedCameraFactory::onStatusChanged(int cameraId, int newStatus) {
-  EmulatedBaseCamera* cam = getOrCreateFakeCamera(cameraId);
-  if (!cam) {
-    ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
-    return;
-  }
-
-  /**
-   * (Order is important)
-   * Send the callback first to framework, THEN close the camera.
-   */
-
-  if (newStatus == cam->getHotplugStatus()) {
-    ALOGW("%s: Ignoring transition to the same status", __FUNCTION__);
-    return;
-  }
-
-  const camera_module_callbacks_t* cb = mCallbacks;
-  if (cb != NULL && cb->camera_device_status_change != NULL) {
-    cb->camera_device_status_change(cb, cameraId, newStatus);
-  }
-
-  if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
-    cam->unplugCamera();
-  } else if (newStatus == CAMERA_DEVICE_STATUS_PRESENT) {
-    cam->plugCamera();
-  }
-}
-
-void EmulatedCameraFactory::onTorchModeStatusChanged(int cameraId,
-                                                     int newStatus) {
-  EmulatedBaseCamera* cam = getOrCreateFakeCamera(cameraId);
-  if (!cam) {
-    ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
-    return;
-  }
-
-  const camera_module_callbacks_t* cb = mCallbacks;
-  if (cb != NULL && cb->torch_mode_status_change != NULL) {
-    char id[10];
-    sprintf(id, "%d", cameraId);
-    cb->torch_mode_status_change(cb, id, newStatus);
-  }
-}
-
-/********************************************************************************
- * Initializer for the static member structure.
- *******************************************************************************/
-
-/* Entry point for camera HAL API. */
-struct hw_module_methods_t EmulatedCameraFactory::mCameraModuleMethods = {
-    .open = EmulatedCameraFactory::device_open};
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedCameraFactory.h b/guest/hals/camera/EmulatedCameraFactory.h
deleted file mode 100644
index f86ae1c..0000000
--- a/guest/hals/camera/EmulatedCameraFactory.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_FACTORY_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_FACTORY_H
-
-#include <mutex>
-
-#include <utils/RefBase.h>
-
-#include <utils/Vector.h>
-#include "CameraConfiguration.h"
-#include "EmulatedBaseCamera.h"
-#include "common/libs/threads/thread_annotations.h"
-
-namespace android {
-
-class EmulatedCameraHotplugThread;
-
-/*
- * Contains declaration of a class EmulatedCameraFactory that manages cameras
- * available for the emulation. A global instance of this class is statically
- * instantiated and initialized when camera emulation HAL is loaded.
- */
-
-/* Class EmulatedCameraFactoryManages cameras available for the emulation.
- *
- * When the global static instance of this class is created on the module load,
- * it enumerates cameras available for the emulation by connecting to the
- * emulator's 'camera' service. For every camera found out there it creates an
- * instance of an appropriate class, and stores it an in array of emulated
- * cameras. In addition to the cameras reported by the emulator, a fake camera
- * emulator is always created, so there is always at least one camera that is
- * available.
- *
- * Instance of this class is also used as the entry point for the camera HAL
- * API, including:
- *  - hw_module_methods_t::open entry point
- *  - camera_module_t::get_number_of_cameras entry point
- *  - camera_module_t::get_camera_info entry point
- *
- */
-class EmulatedCameraFactory {
- public:
-  /* Constructs EmulatedCameraFactory instance.
-   * In this constructor the factory will create and initialize a list of
-   * emulated cameras. All errors that occur on this constructor are reported
-   * via mConstructedOK data member of this class.
-   */
-  EmulatedCameraFactory();
-
-  /* Destructs EmulatedCameraFactory instance. */
-  ~EmulatedCameraFactory();
-
-  /****************************************************************************
-   * Camera HAL API handlers.
-   ***************************************************************************/
-
- public:
-  /* Returns a (singleton) instance of the EmulatedCameraFactory.
-   */
-  static EmulatedCameraFactory& Instance();
-
-  /* Opens (connects to) a camera device.
-   * This method is called in response to hw_module_methods_t::open callback.
-   */
-  int cameraDeviceOpen(int camera_id, hw_device_t** device);
-
-  /* Gets emulated camera information.
-   * This method is called in response to camera_module_t::get_camera_info
-   * callback.
-   */
-  int getCameraInfo(int camera_id, struct camera_info* info);
-
-  /* Sets emulated camera callbacks.
-   * This method is called in response to camera_module_t::set_callbacks
-   * callback.
-   */
-  int setCallbacks(const camera_module_callbacks_t* callbacks);
-
-  /* Fill in vendor tags for the module
-   * This method is called in response to camera_module_t::get_vendor_tag_ops
-   * callback.
-   */
-  void getVendorTagOps(vendor_tag_ops_t* ops);
-
-  int setTorchMode(const char* camera_id, bool enabled);
-
-  /****************************************************************************
-   * Camera HAL API callbacks.
-   ***************************************************************************/
-
- public:
-  /* camera_module_t::get_number_of_cameras callback entry point. */
-  static int get_number_of_cameras(void);
-
-  /* camera_module_t::get_camera_info callback entry point. */
-  static int get_camera_info(int camera_id, struct camera_info* info);
-
-  /* camera_module_t::set_callbacks callback entry point. */
-  static int set_callbacks(const camera_module_callbacks_t* callbacks);
-
-  /* camera_module_t::get_vendor_tag_ops callback entry point */
-  static void get_vendor_tag_ops(vendor_tag_ops_t* ops);
-
-  /* camera_module_t::open_legacy callback entry point */
-  static int open_legacy(const struct hw_module_t* module, const char* id,
-                         uint32_t halVersion, struct hw_device_t** device);
-
-  static int set_torch_mode(const char* camera_id, bool enabled);
-
- private:
-  /* hw_module_methods_t::open callback entry point. */
-  static int device_open(const hw_module_t* module, const char* name,
-                         hw_device_t** device);
-
-  /****************************************************************************
-   * Public API.
-   ***************************************************************************/
-
- public:
-  /* Gets fake camera orientation. */
-  int getFakeCameraOrientation() {
-    /* TODO: Have a boot property that controls that. */
-    return 90;
-  }
-
-  /* Gets number of emulated cameras.
-   */
-  inline size_t getEmulatedCameraNum() const {
-    return mCameraDefinitions.size();
-  }
-
-  void onStatusChanged(int cameraId, int newStatus);
-
-  void onTorchModeStatusChanged(int cameraId, int newStatus);
-
-  /****************************************************************************
-   * Private API
-   ***************************************************************************/
-
- private:
-  /* Create new or return existing fake camera based on camera definition
-   * found in mCameraDefinitions.
-   * Returns NULL if cameraId is not valid (= not a valid index of
-   * mCameraDefinitions)
-   */
-  EmulatedBaseCamera* getOrCreateFakeCamera(size_t cameraId);
-
-  /****************************************************************************
-   * Data members.
-   ***************************************************************************/
-
- private:
-  /* Array of cameras available for the emulation. */
-  Vector<EmulatedBaseCamera*> mEmulatedCameras;
-
-  /* Guards access to mEmulatedCameras. */
-  std::mutex mEmulatedCamerasMutex;
-
-  /* Camera callbacks (for status changing) */
-  const camera_module_callbacks_t* mCallbacks;
-
-  /* Hotplug thread (to call onStatusChanged) */
-  sp<EmulatedCameraHotplugThread> mHotplugThread;
-
-  /* Back- and front camera properties accessed from the vsoc device. */
-  cvd::CameraConfiguration mCameraConfiguration;
-  Vector<cvd::CameraDefinition> mCameraDefinitions;
-
- public:
-  /* Contains device open entry point, as required by HAL API. */
-  static struct hw_module_methods_t mCameraModuleMethods;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_FACTORY_H */
diff --git a/guest/hals/camera/EmulatedCameraHal.cpp b/guest/hals/camera/EmulatedCameraHal.cpp
deleted file mode 100644
index 2aba50a..0000000
--- a/guest/hals/camera/EmulatedCameraHal.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of the camera HAL layer in the system running
- * under the emulator.
- *
- * This file contains only required HAL header, which directs all the API calls
- * to the EmulatedCameraFactory class implementation, wich is responsible for
- * managing emulated cameras.
- */
-
-#include "EmulatedCameraFactory.h"
-
-/*
- * Required HAL header.
- */
-camera_module_t HAL_MODULE_INFO_SYM = {
-    .common = {
-        .tag = HARDWARE_MODULE_TAG,
-        .module_api_version =
-            CAMERA_MODULE_API_VERSION_2_4,
-        .hal_api_version = HARDWARE_HAL_API_VERSION,
-        .id = CAMERA_HARDWARE_MODULE_ID,
-        .name = "Emulated Camera Module",
-        .author = "The Android Open Source Project",
-        .methods = &
-            android::EmulatedCameraFactory::mCameraModuleMethods,
-        .dso = NULL,
-        .reserved = {0},
-    },
-    .get_number_of_cameras =
-        android::EmulatedCameraFactory::get_number_of_cameras,
-    .get_camera_info =
-        android::EmulatedCameraFactory::get_camera_info,
-    .set_callbacks =
-        android::EmulatedCameraFactory::set_callbacks,
-    .get_vendor_tag_ops =
-        android::EmulatedCameraFactory::get_vendor_tag_ops,
-    .open_legacy =
-        android::EmulatedCameraFactory::open_legacy,
-    .set_torch_mode =
-        android::EmulatedCameraFactory::set_torch_mode,
-};
diff --git a/guest/hals/camera/EmulatedCameraHotplugThread.cpp b/guest/hals/camera/EmulatedCameraHotplugThread.cpp
deleted file mode 100644
index 34a4c15..0000000
--- a/guest/hals/camera/EmulatedCameraHotplugThread.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_HotplugThread"
-#include <log/log.h>
-
-#include <fcntl.h>
-#include <sys/inotify.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "EmulatedCameraFactory.h"
-#include "EmulatedCameraHotplugThread.h"
-
-#define FAKE_HOTPLUG_FILE "/data/misc/media/emulator.camera.hotplug"
-
-#define EVENT_SIZE (sizeof(struct inotify_event))
-#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
-
-#define SubscriberInfo EmulatedCameraHotplugThread::SubscriberInfo
-
-namespace android {
-
-EmulatedCameraHotplugThread::EmulatedCameraHotplugThread(
-    size_t totalCameraCount)
-    : Thread(/*canCallJava*/ false) {
-  mRunning = true;
-  mInotifyFd = 0;
-
-  for (size_t id = 0; id < totalCameraCount; ++id) {
-    if (createFileIfNotExists(id)) {
-      mSubscribedCameraIds.push_back(id);
-    }
-  }
-}
-
-EmulatedCameraHotplugThread::~EmulatedCameraHotplugThread() {}
-
-status_t EmulatedCameraHotplugThread::requestExitAndWait() {
-  ALOGE("%s: Not implemented. Use requestExit + join instead", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-void EmulatedCameraHotplugThread::requestExit() {
-  Mutex::Autolock al(mMutex);
-
-  ALOGV("%s: Requesting thread exit", __FUNCTION__);
-  mRunning = false;
-
-  bool rmWatchFailed = false;
-  Vector<SubscriberInfo>::iterator it;
-  for (it = mSubscribers.begin(); it != mSubscribers.end(); ++it) {
-    if (inotify_rm_watch(mInotifyFd, it->WatchID) == -1) {
-      ALOGE(
-          "%s: Could not remove watch for camID '%d',"
-          " error: '%s' (%d)",
-          __FUNCTION__, it->CameraID, strerror(errno), errno);
-
-      rmWatchFailed = true;
-    } else {
-      ALOGV("%s: Removed watch for camID '%d'", __FUNCTION__, it->CameraID);
-    }
-  }
-
-  if (rmWatchFailed) {  // unlikely
-    // Give the thread a fighting chance to error out on the next
-    // read
-    if (close(mInotifyFd) == -1) {
-      ALOGE("%s: close failure error: '%s' (%d)", __FUNCTION__, strerror(errno),
-            errno);
-    }
-  }
-
-  ALOGV("%s: Request exit complete.", __FUNCTION__);
-}
-
-status_t EmulatedCameraHotplugThread::readyToRun() {
-  Mutex::Autolock al(mMutex);
-
-  mInotifyFd = -1;
-
-  do {
-    ALOGV("%s: Initializing inotify", __FUNCTION__);
-
-    mInotifyFd = inotify_init();
-    if (mInotifyFd == -1) {
-      ALOGE("%s: inotify_init failure error: '%s' (%d)", __FUNCTION__,
-            strerror(errno), errno);
-      mRunning = false;
-      break;
-    }
-
-    /**
-     * For each fake camera file, add a watch for when
-     * the file is closed (if it was written to)
-     */
-    Vector<int>::const_iterator it, end;
-    it = mSubscribedCameraIds.begin();
-    end = mSubscribedCameraIds.end();
-    for (; it != end; ++it) {
-      int cameraId = *it;
-      if (!addWatch(cameraId)) {
-        mRunning = false;
-        break;
-      }
-    }
-  } while (false);
-
-  if (!mRunning) {
-    status_t err = -errno;
-
-    if (mInotifyFd != -1) {
-      close(mInotifyFd);
-    }
-
-    return err;
-  }
-
-  return OK;
-}
-
-bool EmulatedCameraHotplugThread::threadLoop() {
-  // If requestExit was already called, mRunning will be false
-  while (mRunning) {
-    char buffer[EVENT_BUF_LEN];
-    int length = TEMP_FAILURE_RETRY(read(mInotifyFd, buffer, EVENT_BUF_LEN));
-
-    if (length < 0) {
-      ALOGE("%s: Error reading from inotify FD, error: '%s' (%d)", __FUNCTION__,
-            strerror(errno), errno);
-      mRunning = false;
-      break;
-    }
-
-    ALOGV("%s: Read %d bytes from inotify FD", __FUNCTION__, length);
-
-    int i = 0;
-    while (i < length) {
-      inotify_event* event = (inotify_event*)&buffer[i];
-
-      if (event->mask & IN_IGNORED) {
-        Mutex::Autolock al(mMutex);
-        if (!mRunning) {
-          ALOGV("%s: Shutting down thread", __FUNCTION__);
-          break;
-        } else {
-          ALOGE("%s: File was deleted, aborting", __FUNCTION__);
-          mRunning = false;
-          break;
-        }
-      } else if (event->mask & IN_CLOSE_WRITE) {
-        int cameraId = getCameraId(event->wd);
-
-        if (cameraId < 0) {
-          ALOGE("%s: Got bad camera ID from WD '%d", __FUNCTION__, event->wd);
-        } else {
-          // Check the file for the new hotplug event
-          String8 filePath = getFilePath(cameraId);
-          /**
-           * NOTE: we carefully avoid getting an inotify
-           * for the same exact file because it's opened for
-           * read-only, but our inotify is for write-only
-           */
-          int newStatus = readFile(filePath);
-
-          if (newStatus < 0) {
-            mRunning = false;
-            break;
-          }
-
-          int halStatus = newStatus ? CAMERA_DEVICE_STATUS_PRESENT
-                                    : CAMERA_DEVICE_STATUS_NOT_PRESENT;
-          EmulatedCameraFactory::Instance().onStatusChanged(cameraId,
-                                                            halStatus);
-        }
-
-      } else {
-        ALOGW("%s: Unknown mask 0x%x", __FUNCTION__, event->mask);
-      }
-
-      i += EVENT_SIZE + event->len;
-    }
-  }
-
-  if (!mRunning) {
-    close(mInotifyFd);
-    return false;
-  }
-
-  return true;
-}
-
-String8 EmulatedCameraHotplugThread::getFilePath(int cameraId) const {
-  return String8::format(FAKE_HOTPLUG_FILE ".%d", cameraId);
-}
-
-bool EmulatedCameraHotplugThread::createFileIfNotExists(int cameraId) const {
-  String8 filePath = getFilePath(cameraId);
-  // make sure this file exists and we have access to it
-  int fd =
-      TEMP_FAILURE_RETRY(open(filePath.string(), O_WRONLY | O_CREAT | O_TRUNC,
-                              /* mode = ug+rwx */ S_IRWXU | S_IRWXG));
-  if (fd == -1) {
-    ALOGE("%s: Could not create file '%s', error: '%s' (%d)", __FUNCTION__,
-          filePath.string(), strerror(errno), errno);
-    return false;
-  }
-
-  // File has '1' by default since we are plugged in by default
-  if (TEMP_FAILURE_RETRY(write(fd, "1\n", /*count*/ 2)) == -1) {
-    ALOGE("%s: Could not write '1' to file '%s', error: '%s' (%d)",
-          __FUNCTION__, filePath.string(), strerror(errno), errno);
-    return false;
-  }
-
-  close(fd);
-  return true;
-}
-
-int EmulatedCameraHotplugThread::getCameraId(String8 filePath) const {
-  Vector<int>::const_iterator it, end;
-  it = mSubscribedCameraIds.begin();
-  end = mSubscribedCameraIds.end();
-  for (; it != end; ++it) {
-    String8 camPath = getFilePath(*it);
-
-    if (camPath == filePath) {
-      return *it;
-    }
-  }
-
-  return NAME_NOT_FOUND;
-}
-
-int EmulatedCameraHotplugThread::getCameraId(int wd) const {
-  for (size_t i = 0; i < mSubscribers.size(); ++i) {
-    if (mSubscribers[i].WatchID == wd) {
-      return mSubscribers[i].CameraID;
-    }
-  }
-
-  return NAME_NOT_FOUND;
-}
-
-SubscriberInfo* EmulatedCameraHotplugThread::getSubscriberInfo(int cameraId) {
-  for (size_t i = 0; i < mSubscribers.size(); ++i) {
-    if (mSubscribers[i].CameraID == cameraId) {
-      return (SubscriberInfo*)&mSubscribers[i];
-    }
-  }
-
-  return NULL;
-}
-
-bool EmulatedCameraHotplugThread::addWatch(int cameraId) {
-  String8 camPath = getFilePath(cameraId);
-  int wd = inotify_add_watch(mInotifyFd, camPath.string(), IN_CLOSE_WRITE);
-
-  if (wd == -1) {
-    ALOGE("%s: Could not add watch for '%s', error: '%s' (%d)", __FUNCTION__,
-          camPath.string(), strerror(errno), errno);
-
-    mRunning = false;
-    return false;
-  }
-
-  ALOGV("%s: Watch added for camID='%d', wd='%d'", __FUNCTION__, cameraId, wd);
-
-  SubscriberInfo si = {cameraId, wd};
-  mSubscribers.push_back(si);
-
-  return true;
-}
-
-bool EmulatedCameraHotplugThread::removeWatch(int cameraId) {
-  SubscriberInfo* si = getSubscriberInfo(cameraId);
-
-  if (!si) return false;
-
-  if (inotify_rm_watch(mInotifyFd, si->WatchID) == -1) {
-    ALOGE("%s: Could not remove watch for camID '%d', error: '%s' (%d)",
-          __FUNCTION__, cameraId, strerror(errno), errno);
-
-    return false;
-  }
-
-  Vector<SubscriberInfo>::iterator it;
-  for (it = mSubscribers.begin(); it != mSubscribers.end(); ++it) {
-    if (it->CameraID == cameraId) {
-      break;
-    }
-  }
-
-  if (it != mSubscribers.end()) {
-    mSubscribers.erase(it);
-  }
-
-  return true;
-}
-
-int EmulatedCameraHotplugThread::readFile(String8 filePath) const {
-  int fd = TEMP_FAILURE_RETRY(open(filePath.string(), O_RDONLY, /*mode*/ 0));
-  if (fd == -1) {
-    ALOGE("%s: Could not open file '%s', error: '%s' (%d)", __FUNCTION__,
-          filePath.string(), strerror(errno), errno);
-    return -1;
-  }
-
-  char buffer[1];
-  int length;
-
-  length = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
-
-  int retval;
-
-  ALOGV("%s: Read file '%s', length='%d', buffer='%c'", __FUNCTION__,
-        filePath.string(), length, buffer[0]);
-
-  if (length == 0) {  // EOF
-    retval = 0;       // empty file is the same thing as 0
-  } else if (buffer[0] == '0') {
-    retval = 0;
-  } else {  // anything non-empty that's not beginning with '0'
-    retval = 1;
-  }
-
-  close(fd);
-
-  return retval;
-}
-
-}  // namespace android
diff --git a/guest/hals/camera/EmulatedCameraHotplugThread.h b/guest/hals/camera/EmulatedCameraHotplugThread.h
deleted file mode 100644
index bc28889..0000000
--- a/guest/hals/camera/EmulatedCameraHotplugThread.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_HOTPLUG_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_HOTPLUG_H
-
-/**
- * This class emulates hotplug events by inotifying on a file, specific
- * to a camera ID. When the file changes between 1/0 the hotplug
- * status goes between PRESENT and NOT_PRESENT.
- *
- * Refer to FAKE_HOTPLUG_FILE in EmulatedCameraHotplugThread.cpp
- */
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include "EmulatedCamera2.h"
-
-namespace android {
-class EmulatedCameraHotplugThread : public Thread {
- public:
-  EmulatedCameraHotplugThread(size_t totalCameraCount);
-  ~EmulatedCameraHotplugThread();
-
-  virtual void requestExit();
-  virtual status_t requestExitAndWait();
-
- private:
-  virtual status_t readyToRun();
-  virtual bool threadLoop();
-
-  struct SubscriberInfo {
-    int CameraID;
-    int WatchID;
-  };
-
-  bool addWatch(int cameraId);
-  bool removeWatch(int cameraId);
-  SubscriberInfo* getSubscriberInfo(int cameraId);
-
-  int getCameraId(String8 filePath) const;
-  int getCameraId(int wd) const;
-
-  String8 getFilePath(int cameraId) const;
-  int readFile(String8 filePath) const;
-
-  bool createFileIfNotExists(int cameraId) const;
-
-  Vector<int> mSubscribedCameraIds;
-  Vector<SubscriberInfo> mSubscribers;
-
-  // variables above are unguarded:
-  // -- accessed in thread loop or in constructor only
-
-  Mutex mMutex;
-
-  bool mRunning;  // guarding only when it's important
-};
-}  // namespace android
-
-#endif
diff --git a/guest/hals/camera/EmulatedFakeCamera.cpp b/guest/hals/camera/EmulatedFakeCamera.cpp
deleted file mode 100644
index 4153fd7..0000000
--- a/guest/hals/camera/EmulatedFakeCamera.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class EmulatedFakeCamera that encapsulates
- * functionality of a fake camera.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_FakeCamera"
-#include "EmulatedFakeCamera.h"
-#include <log/log.h>
-#include <cutils/properties.h>
-#undef min
-#undef max
-#include <algorithm>
-#include <sstream>
-#include <string>
-#include "EmulatedCameraFactory.h"
-
-namespace android {
-
-EmulatedFakeCamera::EmulatedFakeCamera(int cameraId, bool facingBack,
-                                       struct hw_module_t* module)
-    : EmulatedCamera(cameraId, module),
-      mFacingBack(facingBack),
-      mFakeCameraDevice(this) {}
-
-EmulatedFakeCamera::~EmulatedFakeCamera() {}
-
-/****************************************************************************
- * Public API overrides
- ***************************************************************************/
-
-status_t EmulatedFakeCamera::Initialize(const cvd::CameraDefinition& params) {
-  status_t res = mFakeCameraDevice.Initialize();
-  if (res != NO_ERROR) {
-    return res;
-  }
-
-  const char* facing =
-      mFacingBack ? EmulatedCamera::FACING_BACK : EmulatedCamera::FACING_FRONT;
-
-  mParameters.set(EmulatedCamera::FACING_KEY, facing);
-  ALOGD("%s: Fake camera is facing %s", __FUNCTION__, facing);
-
-  mParameters.set(EmulatedCamera::ORIENTATION_KEY,
-                  EmulatedCameraFactory::Instance().getFakeCameraOrientation());
-
-  res = EmulatedCamera::Initialize(params);
-  if (res != NO_ERROR) {
-    return res;
-  }
-
-  /*
-   * Parameters provided by the camera device.
-   */
-
-  /* 352x288 and 320x240 frame dimensions are required by the framework for
-   * video mode preview and video recording. */
-  std::ostringstream resolutions;
-  for (size_t index = 0; index < params.resolutions.size(); ++index) {
-    if (resolutions.str().size()) {
-      resolutions << ",";
-    }
-    resolutions << params.resolutions[index].width << "x"
-                << params.resolutions[index].height;
-  }
-
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
-                  resolutions.str().c_str());
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
-                  resolutions.str().c_str());
-  mParameters.setPreviewSize(640, 480);
-  mParameters.setPictureSize(640, 480);
-
-  mParameters.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
-                  CameraParameters::ANTIBANDING_AUTO);
-  mParameters.set(CameraParameters::KEY_ANTIBANDING,
-                  CameraParameters::ANTIBANDING_AUTO);
-  mParameters.set(CameraParameters::KEY_SUPPORTED_EFFECTS,
-                  CameraParameters::EFFECT_NONE);
-  mParameters.set(CameraParameters::KEY_EFFECT, CameraParameters::EFFECT_NONE);
-
-  return NO_ERROR;
-}
-
-EmulatedCameraDevice* EmulatedFakeCamera::getCameraDevice() {
-  return &mFakeCameraDevice;
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedFakeCamera.h b/guest/hals/camera/EmulatedFakeCamera.h
deleted file mode 100644
index 5afba3f..0000000
--- a/guest/hals/camera/EmulatedFakeCamera.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_H
-#define HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_H
-
-/*
- * Contains declaration of a class EmulatedFakeCamera that encapsulates
- * functionality of a fake camera. This class is nothing more than a placeholder
- * for EmulatedFakeCameraDevice instance.
- */
-
-#include "EmulatedCamera.h"
-#include "EmulatedFakeCameraDevice.h"
-
-namespace android {
-
-/* Encapsulates functionality of a fake camera.
- * This class is nothing more than a placeholder for EmulatedFakeCameraDevice
- * instance that emulates a fake camera device.
- */
-class EmulatedFakeCamera : public EmulatedCamera {
- public:
-  /* Constructs EmulatedFakeCamera instance. */
-  EmulatedFakeCamera(int cameraId, bool facingBack, struct hw_module_t* module);
-
-  /* Destructs EmulatedFakeCamera instance. */
-  ~EmulatedFakeCamera();
-
-  /****************************************************************************
-   * EmulatedCamera virtual overrides.
-   ***************************************************************************/
-
- public:
-  /* Initializes EmulatedFakeCamera instance. */
-  status_t Initialize(const cvd::CameraDefinition& params);
-
-  /****************************************************************************
-   * EmulatedCamera abstract API implementation.
-   ***************************************************************************/
-
- protected:
-  /* Gets emulated camera device ised by this instance of the emulated camera.
-   */
-  EmulatedCameraDevice* getCameraDevice();
-
-  /****************************************************************************
-   * Data memebers.
-   ***************************************************************************/
-
- protected:
-  /* Facing back (true) or front (false) switch. */
-  bool mFacingBack;
-
-  /* Contained fake camera device object. */
-  EmulatedFakeCameraDevice mFakeCameraDevice;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_H */
diff --git a/guest/hals/camera/EmulatedFakeCamera2.cpp b/guest/hals/camera/EmulatedFakeCamera2.cpp
deleted file mode 100644
index 393adf1..0000000
--- a/guest/hals/camera/EmulatedFakeCamera2.cpp
+++ /dev/null
@@ -1,2606 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/*
- * Contains implementation of a class EmulatedFakeCamera2 that encapsulates
- * functionality of an advanced fake camera.
- */
-
-#include <inttypes.h>
-
-#include <algorithm>
-#include <cstdint>
-#include <iterator>
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_FakeCamera2"
-#include <utils/Log.h>
-
-#include "EmulatedCameraFactory.h"
-#include "EmulatedFakeCamera2.h"
-#include "GrallocModule.h"
-
-#define ERROR_CAMERA_NOT_PRESENT -EPIPE
-
-#define CAMERA2_EXT_TRIGGER_TESTING_DISCONNECT 0xFFFFFFFF
-
-template <typename T, size_t N>
-char (&ArraySizeHelper(T (&array)[N]))[N];
-
-template <typename T, size_t N>
-char (&ArraySizeHelper(const T (&array)[N]))[N];
-
-#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-
-namespace android {
-
-const int64_t USEC = 1000LL;
-const int64_t MSEC = USEC * 1000LL;
-const int64_t SEC = MSEC * 1000LL;
-
-const uint32_t EmulatedFakeCamera2::kAvailableFormats[] = {
-    HAL_PIXEL_FORMAT_RAW16,
-    HAL_PIXEL_FORMAT_BLOB, HAL_PIXEL_FORMAT_RGBA_8888,
-    //        HAL_PIXEL_FORMAT_YV12,
-    HAL_PIXEL_FORMAT_YCrCb_420_SP};
-
-const uint32_t EmulatedFakeCamera2::kAvailableRawSizes[2] = {
-    640, 480
-    //    mSensorWidth, mSensorHeight
-};
-
-const uint64_t EmulatedFakeCamera2::kAvailableRawMinDurations[1] = {
-    static_cast<uint64_t>(Sensor::kFrameDurationRange[0])};
-
-const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizesBack[4] = {
-    640, 480, 320, 240
-    //    mSensorWidth, mSensorHeight
-};
-
-const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizesFront[4] = {
-    320, 240, 160, 120
-    //    mSensorWidth, mSensorHeight
-};
-
-const uint64_t EmulatedFakeCamera2::kAvailableProcessedMinDurations[1] = {
-    static_cast<uint64_t>(Sensor::kFrameDurationRange[0])};
-
-const uint32_t EmulatedFakeCamera2::kAvailableJpegSizesBack[2] = {
-    640, 480
-    //    mSensorWidth, mSensorHeight
-};
-
-const uint32_t EmulatedFakeCamera2::kAvailableJpegSizesFront[2] = {
-    320, 240
-    //    mSensorWidth, mSensorHeight
-};
-
-const uint64_t EmulatedFakeCamera2::kAvailableJpegMinDurations[1] = {
-    static_cast<uint64_t>(Sensor::kFrameDurationRange[0])};
-
-EmulatedFakeCamera2::EmulatedFakeCamera2(int cameraId, bool facingBack,
-                                         struct hw_module_t *module)
-    : EmulatedCamera2(cameraId, module),
-      mFacingBack(facingBack),
-      mIsConnected(false) {
-  ALOGD("Constructing emulated fake camera 2 facing %s",
-        facingBack ? "back" : "front");
-}
-
-EmulatedFakeCamera2::~EmulatedFakeCamera2() {
-  if (mCameraInfo != NULL) {
-    free_camera_metadata(mCameraInfo);
-  }
-}
-
-/****************************************************************************
- * Public API overrides
- ***************************************************************************/
-
-status_t EmulatedFakeCamera2::Initialize(const cvd::CameraDefinition &params) {
-  status_t res;
-
-  for (size_t index = 0; index < params.resolutions.size(); ++index) {
-    mAvailableRawSizes.push_back(params.resolutions[index].width);
-    mAvailableRawSizes.push_back(params.resolutions[index].height);
-    mAvailableProcessedSizes.push_back(params.resolutions[index].width);
-    mAvailableProcessedSizes.push_back(params.resolutions[index].height);
-    mAvailableJpegSizes.push_back(params.resolutions[index].width);
-    mAvailableJpegSizes.push_back(params.resolutions[index].height);
-  }
-
-  // Find max width/height
-  int32_t width = 0, height = 0;
-  for (size_t index = 0; index < params.resolutions.size(); ++index) {
-    if (width <= params.resolutions[index].width &&
-        height <= params.resolutions[index].height) {
-      width = params.resolutions[index].width;
-      height = params.resolutions[index].height;
-    }
-  }
-  if (width < 640 || height < 480) {
-    width = 640;
-    height = 480;
-  }
-  mSensorWidth = width;
-  mSensorHeight = height;
-
-  /* TODO(ender): probably should drop this. */
-  std::copy(kAvailableRawSizes,
-            kAvailableRawSizes + arraysize(kAvailableRawSizes),
-            std::back_inserter(mAvailableRawSizes));
-
-  if (params.orientation == cvd::CameraDefinition::kFront) {
-    std::copy(kAvailableProcessedSizesFront,
-              kAvailableProcessedSizesFront +
-                  arraysize(kAvailableProcessedSizesFront),
-              std::back_inserter(mAvailableProcessedSizes));
-    std::copy(kAvailableJpegSizesFront,
-              kAvailableJpegSizesFront + arraysize(kAvailableJpegSizesFront),
-              std::back_inserter(mAvailableJpegSizes));
-  } else {
-    std::copy(
-        kAvailableProcessedSizesBack,
-        kAvailableProcessedSizesBack + arraysize(kAvailableProcessedSizesBack),
-        mAvailableProcessedSizes.begin());
-    std::copy(kAvailableJpegSizesBack,
-              kAvailableJpegSizesBack + arraysize(kAvailableJpegSizesBack),
-              mAvailableJpegSizes.begin());
-  }
-
-  res = constructStaticInfo(&mCameraInfo, true);
-  if (res != OK) {
-    ALOGE("%s: Unable to allocate static info: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    return res;
-  }
-  res = constructStaticInfo(&mCameraInfo, false);
-  if (res != OK) {
-    ALOGE("%s: Unable to fill in static info: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    return res;
-  }
-  if (res != OK) return res;
-
-  mNextStreamId = 1;
-  mNextReprocessStreamId = 1;
-  mRawStreamCount = 0;
-  mProcessedStreamCount = 0;
-  mJpegStreamCount = 0;
-  mReprocessStreamCount = 0;
-
-  return NO_ERROR;
-}
-
-/****************************************************************************
- * Camera module API overrides
- ***************************************************************************/
-
-status_t EmulatedFakeCamera2::connectCamera(hw_device_t **device) {
-  status_t res;
-  ALOGV("%s", __FUNCTION__);
-
-  {
-    Mutex::Autolock l(mMutex);
-    if (!mStatusPresent) {
-      ALOGE("%s: Camera ID %d is unplugged", __FUNCTION__, mCameraID);
-      return -ENODEV;
-    }
-  }
-
-  mConfigureThread = new ConfigureThread(this);
-  mReadoutThread = new ReadoutThread(this);
-  mControlThread = new ControlThread(this);
-  mSensor = new Sensor(mSensorWidth, mSensorHeight);
-  mJpegCompressor = new JpegCompressor();
-
-  mNextStreamId = 1;
-  mNextReprocessStreamId = 1;
-
-  res = mSensor->startUp();
-  if (res != NO_ERROR) return res;
-
-  res = mConfigureThread->run("EmulatedFakeCamera2::configureThread");
-  if (res != NO_ERROR) return res;
-
-  res = mReadoutThread->run("EmulatedFakeCamera2::readoutThread");
-  if (res != NO_ERROR) return res;
-
-  res = mControlThread->run("EmulatedFakeCamera2::controlThread");
-  if (res != NO_ERROR) return res;
-
-  status_t ret = EmulatedCamera2::connectCamera(device);
-
-  if (ret >= 0) {
-    mIsConnected = true;
-  }
-
-  return ret;
-}
-
-status_t EmulatedFakeCamera2::plugCamera() {
-  {
-    Mutex::Autolock l(mMutex);
-
-    if (!mStatusPresent) {
-      ALOGI("%s: Plugged back in", __FUNCTION__);
-      mStatusPresent = true;
-    }
-  }
-
-  return NO_ERROR;
-}
-
-status_t EmulatedFakeCamera2::unplugCamera() {
-  {
-    Mutex::Autolock l(mMutex);
-
-    if (mStatusPresent) {
-      ALOGI("%s: Unplugged camera", __FUNCTION__);
-      mStatusPresent = false;
-    }
-  }
-
-  return closeCamera();
-}
-
-camera_device_status_t EmulatedFakeCamera2::getHotplugStatus() {
-  Mutex::Autolock l(mMutex);
-  return mStatusPresent ? CAMERA_DEVICE_STATUS_PRESENT
-                        : CAMERA_DEVICE_STATUS_NOT_PRESENT;
-}
-
-status_t EmulatedFakeCamera2::closeCamera() {
-  {
-    Mutex::Autolock l(mMutex);
-
-    status_t res;
-    ALOGV("%s", __FUNCTION__);
-
-    if (!mIsConnected) {
-      return NO_ERROR;
-    }
-
-    res = mSensor->shutDown();
-    if (res != NO_ERROR) {
-      ALOGE("%s: Unable to shut down sensor: %d", __FUNCTION__, res);
-      return res;
-    }
-
-    mConfigureThread->requestExit();
-    mReadoutThread->requestExit();
-    mControlThread->requestExit();
-    mJpegCompressor->cancel();
-  }
-
-  // give up the lock since we will now block and the threads
-  // can call back into this object
-  mConfigureThread->join();
-  mReadoutThread->join();
-  mControlThread->join();
-
-  ALOGV("%s exit", __FUNCTION__);
-
-  {
-    Mutex::Autolock l(mMutex);
-    mIsConnected = false;
-  }
-
-  return NO_ERROR;
-}
-
-status_t EmulatedFakeCamera2::getCameraInfo(struct camera_info *info) {
-  info->facing = mFacingBack ? CAMERA_FACING_BACK : CAMERA_FACING_FRONT;
-  info->orientation =
-      EmulatedCameraFactory::Instance().getFakeCameraOrientation();
-  return EmulatedCamera2::getCameraInfo(info);
-}
-
-/****************************************************************************
- * Camera device API overrides
- ***************************************************************************/
-
-/** Request input queue */
-
-int EmulatedFakeCamera2::requestQueueNotify() {
-  ALOGV("Request queue notification received");
-
-  ALOG_ASSERT(mRequestQueueSrc != NULL,
-              "%s: Request queue src not set, but received queue notification!",
-              __FUNCTION__);
-  ALOG_ASSERT(mFrameQueueDst != NULL,
-              "%s: Request queue src not set, but received queue notification!",
-              __FUNCTION__);
-  ALOG_ASSERT(mStreams.size() != 0,
-              "%s: No streams allocated, but received queue notification!",
-              __FUNCTION__);
-  return mConfigureThread->newRequestAvailable();
-}
-
-int EmulatedFakeCamera2::getInProgressCount() {
-  Mutex::Autolock l(mMutex);
-
-  if (!mStatusPresent) {
-    ALOGW("%s: Camera was physically disconnected", __FUNCTION__);
-    return ERROR_CAMERA_NOT_PRESENT;
-  }
-
-  int requestCount = 0;
-  requestCount += mConfigureThread->getInProgressCount();
-  requestCount += mReadoutThread->getInProgressCount();
-  requestCount += mJpegCompressor->isBusy() ? 1 : 0;
-
-  return requestCount;
-}
-
-int EmulatedFakeCamera2::constructDefaultRequest(int request_template,
-                                                 camera_metadata_t **request) {
-  if (request == NULL) return BAD_VALUE;
-  if (request_template < 0 || request_template >= CAMERA2_TEMPLATE_COUNT) {
-    return BAD_VALUE;
-  }
-
-  {
-    Mutex::Autolock l(mMutex);
-    if (!mStatusPresent) {
-      ALOGW("%s: Camera was physically disconnected", __FUNCTION__);
-      return ERROR_CAMERA_NOT_PRESENT;
-    }
-  }
-
-  status_t res;
-  // Pass 1, calculate size and allocate
-  res = constructDefaultRequest(request_template, request, true);
-  if (res != OK) {
-    return res;
-  }
-  // Pass 2, build request
-  res = constructDefaultRequest(request_template, request, false);
-  if (res != OK) {
-    ALOGE("Unable to populate new request for template %d", request_template);
-  }
-
-  return res;
-}
-
-int EmulatedFakeCamera2::allocateStream(
-    uint32_t width, uint32_t height, int format,
-    const camera2_stream_ops_t *stream_ops, uint32_t *stream_id,
-    uint32_t *format_actual, uint32_t *usage, uint32_t *max_buffers) {
-  Mutex::Autolock l(mMutex);
-
-  if (!mStatusPresent) {
-    ALOGW("%s: Camera was physically disconnected", __FUNCTION__);
-    return ERROR_CAMERA_NOT_PRESENT;
-  }
-
-  // Temporary shim until FORMAT_ZSL is removed
-  if (format == CAMERA2_HAL_PIXEL_FORMAT_ZSL) {
-    format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-  }
-
-  if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-    unsigned int numFormats = sizeof(kAvailableFormats) / sizeof(uint32_t);
-    unsigned int formatIdx = 0;
-    for (; formatIdx < numFormats; formatIdx++) {
-      if (format == (int)kAvailableFormats[formatIdx]) break;
-    }
-    if (formatIdx == numFormats) {
-      ALOGE("%s: Format 0x%x is not supported", __FUNCTION__, format);
-      return BAD_VALUE;
-    }
-  }
-
-  const uint32_t *availableSizes;
-  size_t availableSizeCount;
-  switch (format) {
-    case HAL_PIXEL_FORMAT_RAW16:
-      availableSizes = &mAvailableRawSizes.front();
-      availableSizeCount = mAvailableRawSizes.size();
-      break;
-    case HAL_PIXEL_FORMAT_BLOB:
-      availableSizes = &mAvailableJpegSizes.front();
-      availableSizeCount = mAvailableJpegSizes.size();
-      break;
-    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-    case HAL_PIXEL_FORMAT_YV12:
-    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-      availableSizes = &mAvailableProcessedSizes.front();
-      availableSizeCount = mAvailableProcessedSizes.size();
-      break;
-    default:
-      ALOGE("%s: Unknown format 0x%x", __FUNCTION__, format);
-      return BAD_VALUE;
-  }
-
-  unsigned int resIdx = 0;
-  for (; resIdx < availableSizeCount; resIdx++) {
-    if (availableSizes[resIdx * 2] == width &&
-        availableSizes[resIdx * 2 + 1] == height)
-      break;
-  }
-  if (resIdx == availableSizeCount) {
-    ALOGE("%s: Format 0x%x does not support resolution %d, %d", __FUNCTION__,
-          format, width, height);
-    return BAD_VALUE;
-  }
-
-  switch (format) {
-    case HAL_PIXEL_FORMAT_RAW16:
-      if (mRawStreamCount >= kMaxRawStreamCount) {
-        ALOGE("%s: Cannot allocate another raw stream (%d already allocated)",
-              __FUNCTION__, mRawStreamCount);
-        return INVALID_OPERATION;
-      }
-      mRawStreamCount++;
-      break;
-    case HAL_PIXEL_FORMAT_BLOB:
-      if (mJpegStreamCount >= kMaxJpegStreamCount) {
-        ALOGE("%s: Cannot allocate another JPEG stream (%d already allocated)",
-              __FUNCTION__, mJpegStreamCount);
-        return INVALID_OPERATION;
-      }
-      mJpegStreamCount++;
-      break;
-    default:
-      if (mProcessedStreamCount >= kMaxProcessedStreamCount) {
-        ALOGE(
-            "%s: Cannot allocate another processed stream (%d already "
-            "allocated)",
-            __FUNCTION__, mProcessedStreamCount);
-        return INVALID_OPERATION;
-      }
-      mProcessedStreamCount++;
-  }
-
-  Stream newStream;
-  newStream.ops = stream_ops;
-  newStream.width = width;
-  newStream.height = height;
-  newStream.format = format;
-  // TODO: Query stride from gralloc
-  newStream.stride = width;
-
-  mStreams.add(mNextStreamId, newStream);
-
-  *stream_id = mNextStreamId;
-  if (format_actual) *format_actual = format;
-  *usage = GRALLOC_USAGE_HW_CAMERA_WRITE;
-  *max_buffers = kMaxBufferCount;
-
-  ALOGV("Stream allocated: %d, %d x %d, 0x%x. U: %x, B: %d", *stream_id, width,
-        height, format, *usage, *max_buffers);
-
-  mNextStreamId++;
-  return NO_ERROR;
-}
-
-int EmulatedFakeCamera2::registerStreamBuffers(uint32_t stream_id,
-                                               int num_buffers,
-                                               buffer_handle_t * /*buffers*/) {
-  Mutex::Autolock l(mMutex);
-
-  if (!mStatusPresent) {
-    ALOGW("%s: Camera was physically disconnected", __FUNCTION__);
-    return ERROR_CAMERA_NOT_PRESENT;
-  }
-
-  ALOGV("%s: Stream %d registering %d buffers", __FUNCTION__, stream_id,
-        num_buffers);
-  // Need to find out what the final concrete pixel format for our stream is
-  // Assumes that all buffers have the same format.
-  if (num_buffers < 1) {
-    ALOGE("%s: Stream %d only has %d buffers!", __FUNCTION__, stream_id,
-          num_buffers);
-    return BAD_VALUE;
-  }
-
-  ssize_t streamIndex = mStreams.indexOfKey(stream_id);
-  if (streamIndex < 0) {
-    ALOGE("%s: Unknown stream id %d!", __FUNCTION__, stream_id);
-    return BAD_VALUE;
-  }
-
-  Stream &stream = mStreams.editValueAt(streamIndex);
-
-  int finalFormat = stream.format;
-
-  if (finalFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-    finalFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-  }
-
-  ALOGV("%s: Stream %d format set to %x, previously %x", __FUNCTION__,
-        stream_id, finalFormat, stream.format);
-
-  stream.format = finalFormat;
-
-  return NO_ERROR;
-}
-
-int EmulatedFakeCamera2::releaseStream(uint32_t stream_id) {
-  Mutex::Autolock l(mMutex);
-
-  ssize_t streamIndex = mStreams.indexOfKey(stream_id);
-  if (streamIndex < 0) {
-    ALOGE("%s: Unknown stream id %d!", __FUNCTION__, stream_id);
-    return BAD_VALUE;
-  }
-
-  if (isStreamInUse(stream_id)) {
-    ALOGE("%s: Cannot release stream %d; in use!", __FUNCTION__, stream_id);
-    return BAD_VALUE;
-  }
-
-  switch (mStreams.valueAt(streamIndex).format) {
-    case HAL_PIXEL_FORMAT_RAW16:
-      mRawStreamCount--;
-      break;
-    case HAL_PIXEL_FORMAT_BLOB:
-      mJpegStreamCount--;
-      break;
-    default:
-      mProcessedStreamCount--;
-      break;
-  }
-
-  mStreams.removeItemsAt(streamIndex);
-
-  return NO_ERROR;
-}
-
-int EmulatedFakeCamera2::allocateReprocessStreamFromStream(
-    uint32_t output_stream_id, const camera2_stream_in_ops_t *stream_ops,
-    uint32_t *stream_id) {
-  Mutex::Autolock l(mMutex);
-
-  if (!mStatusPresent) {
-    ALOGW("%s: Camera was physically disconnected", __FUNCTION__);
-    return ERROR_CAMERA_NOT_PRESENT;
-  }
-
-  ssize_t baseStreamIndex = mStreams.indexOfKey(output_stream_id);
-  if (baseStreamIndex < 0) {
-    ALOGE("%s: Unknown output stream id %d!", __FUNCTION__, output_stream_id);
-    return BAD_VALUE;
-  }
-
-  const Stream &baseStream = mStreams[baseStreamIndex];
-
-  // We'll reprocess anything we produced
-
-  if (mReprocessStreamCount >= kMaxReprocessStreamCount) {
-    ALOGE("%s: Cannot allocate another reprocess stream (%d already allocated)",
-          __FUNCTION__, mReprocessStreamCount);
-    return INVALID_OPERATION;
-  }
-  mReprocessStreamCount++;
-
-  ReprocessStream newStream;
-  newStream.ops = stream_ops;
-  newStream.width = baseStream.width;
-  newStream.height = baseStream.height;
-  newStream.format = baseStream.format;
-  newStream.stride = baseStream.stride;
-  newStream.sourceStreamId = output_stream_id;
-
-  *stream_id = mNextReprocessStreamId;
-  mReprocessStreams.add(mNextReprocessStreamId, newStream);
-
-  ALOGV("Reprocess stream allocated: %d: %d, %d, 0x%x. Parent stream: %d",
-        *stream_id, newStream.width, newStream.height, newStream.format,
-        output_stream_id);
-
-  mNextReprocessStreamId++;
-  return NO_ERROR;
-}
-
-int EmulatedFakeCamera2::releaseReprocessStream(uint32_t stream_id) {
-  Mutex::Autolock l(mMutex);
-
-  ssize_t streamIndex = mReprocessStreams.indexOfKey(stream_id);
-  if (streamIndex < 0) {
-    ALOGE("%s: Unknown reprocess stream id %d!", __FUNCTION__, stream_id);
-    return BAD_VALUE;
-  }
-
-  if (isReprocessStreamInUse(stream_id)) {
-    ALOGE("%s: Cannot release reprocessing stream %d; in use!", __FUNCTION__,
-          stream_id);
-    return BAD_VALUE;
-  }
-
-  mReprocessStreamCount--;
-  mReprocessStreams.removeItemsAt(streamIndex);
-
-  return NO_ERROR;
-}
-
-int EmulatedFakeCamera2::triggerAction(uint32_t trigger_id, int32_t ext1,
-                                       int32_t ext2) {
-  Mutex::Autolock l(mMutex);
-
-  if (trigger_id == CAMERA2_EXT_TRIGGER_TESTING_DISCONNECT) {
-    ALOGI("%s: Disconnect trigger - camera must be closed", __FUNCTION__);
-    mStatusPresent = false;
-
-    EmulatedCameraFactory::Instance().onStatusChanged(
-        mCameraID, CAMERA_DEVICE_STATUS_NOT_PRESENT);
-  }
-
-  if (!mStatusPresent) {
-    ALOGW("%s: Camera was physically disconnected", __FUNCTION__);
-    return ERROR_CAMERA_NOT_PRESENT;
-  }
-
-  return mControlThread->triggerAction(trigger_id, ext1, ext2);
-}
-
-/** Shutdown and debug methods */
-
-int EmulatedFakeCamera2::dump(int fd) {
-  String8 result;
-
-  result.appendFormat("    Camera HAL device: EmulatedFakeCamera2\n");
-  result.appendFormat("      Streams:\n");
-  for (size_t i = 0; i < mStreams.size(); i++) {
-    int id = mStreams.keyAt(i);
-    const Stream &s = mStreams.valueAt(i);
-    result.appendFormat("         Stream %d: %d x %d, format 0x%x, stride %d\n",
-                        id, s.width, s.height, s.format, s.stride);
-  }
-
-  write(fd, result.string(), result.size());
-
-  return NO_ERROR;
-}
-
-void EmulatedFakeCamera2::signalError() {
-  // TODO: Let parent know so we can shut down cleanly
-  ALOGE("Worker thread is signaling a serious error");
-}
-
-/** Pipeline control worker thread methods */
-
-EmulatedFakeCamera2::ConfigureThread::ConfigureThread(
-    EmulatedFakeCamera2 *parent)
-    : Thread(false), mParent(parent), mRequestCount(0), mNextBuffers(NULL) {
-  mRunning = false;
-}
-
-EmulatedFakeCamera2::ConfigureThread::~ConfigureThread() {}
-
-status_t EmulatedFakeCamera2::ConfigureThread::readyToRun() {
-  Mutex::Autolock lock(mInputMutex);
-
-  ALOGV("Starting up ConfigureThread");
-  mRequest = NULL;
-  mActive = false;
-  mRunning = true;
-
-  mInputSignal.signal();
-  return NO_ERROR;
-}
-
-status_t EmulatedFakeCamera2::ConfigureThread::waitUntilRunning() {
-  Mutex::Autolock lock(mInputMutex);
-  if (!mRunning) {
-    ALOGV("Waiting for configure thread to start");
-    mInputSignal.wait(mInputMutex);
-  }
-  return OK;
-}
-
-status_t EmulatedFakeCamera2::ConfigureThread::newRequestAvailable() {
-  waitUntilRunning();
-
-  Mutex::Autolock lock(mInputMutex);
-
-  mActive = true;
-  mInputSignal.signal();
-
-  return OK;
-}
-
-bool EmulatedFakeCamera2::ConfigureThread::isStreamInUse(uint32_t id) {
-  Mutex::Autolock lock(mInternalsMutex);
-
-  if (mNextBuffers == NULL) return false;
-  for (size_t i = 0; i < mNextBuffers->size(); i++) {
-    if ((*mNextBuffers)[i].streamId == (int)id) return true;
-  }
-  return false;
-}
-
-int EmulatedFakeCamera2::ConfigureThread::getInProgressCount() {
-  Mutex::Autolock lock(mInputMutex);
-  return mRequestCount;
-}
-
-bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
-  status_t res;
-
-  // Check if we're currently processing or just waiting
-  {
-    Mutex::Autolock lock(mInputMutex);
-    if (!mActive) {
-      // Inactive, keep waiting until we've been signaled
-      status_t res;
-      res = mInputSignal.waitRelative(mInputMutex, kWaitPerLoop);
-      if (res != NO_ERROR && res != TIMED_OUT) {
-        ALOGE("%s: Error waiting for input requests: %d", __FUNCTION__, res);
-        return false;
-      }
-      if (!mActive) return true;
-      ALOGV("New request available");
-    }
-    // Active
-  }
-
-  if (mRequest == NULL) {
-    Mutex::Autolock il(mInternalsMutex);
-
-    ALOGV("Configure: Getting next request");
-    res = mParent->mRequestQueueSrc->dequeue_request(mParent->mRequestQueueSrc,
-                                                     &mRequest);
-    if (res != NO_ERROR) {
-      ALOGE("%s: Error dequeuing next request: %d", __FUNCTION__, res);
-      mParent->signalError();
-      return false;
-    }
-    if (mRequest == NULL) {
-      ALOGV("Configure: Request queue empty, going inactive");
-      // No requests available, go into inactive mode
-      Mutex::Autolock lock(mInputMutex);
-      mActive = false;
-      return true;
-    } else {
-      Mutex::Autolock lock(mInputMutex);
-      mRequestCount++;
-    }
-
-    camera_metadata_entry_t type;
-    res = find_camera_metadata_entry(mRequest, ANDROID_REQUEST_TYPE, &type);
-    if (res != NO_ERROR) {
-      ALOGE("%s: error reading request type", __FUNCTION__);
-      mParent->signalError();
-      return false;
-    }
-    bool success = false;
-    ;
-    switch (type.data.u8[0]) {
-      case ANDROID_REQUEST_TYPE_CAPTURE:
-        success = setupCapture();
-        break;
-      case ANDROID_REQUEST_TYPE_REPROCESS:
-        success = setupReprocess();
-        break;
-      default:
-        ALOGE("%s: Unexpected request type %d", __FUNCTION__, type.data.u8[0]);
-        mParent->signalError();
-        break;
-    }
-    if (!success) return false;
-  }
-
-  if (mWaitingForReadout) {
-    bool readoutDone;
-    readoutDone = mParent->mReadoutThread->waitForReady(kWaitPerLoop);
-    if (!readoutDone) return true;
-
-    if (mNextNeedsJpeg) {
-      ALOGV("Configure: Waiting for JPEG compressor");
-    } else {
-      ALOGV("Configure: Waiting for sensor");
-    }
-    mWaitingForReadout = false;
-  }
-
-  if (mNextNeedsJpeg) {
-    bool jpegDone;
-    jpegDone = mParent->mJpegCompressor->waitForDone(kWaitPerLoop);
-    if (!jpegDone) return true;
-
-    ALOGV("Configure: Waiting for sensor");
-    mNextNeedsJpeg = false;
-  }
-
-  if (mNextIsCapture) {
-    return configureNextCapture();
-  } else {
-    return configureNextReprocess();
-  }
-}
-
-bool EmulatedFakeCamera2::ConfigureThread::setupCapture() {
-  status_t res;
-
-  mNextIsCapture = true;
-  // Get necessary parameters for sensor config
-  mParent->mControlThread->processRequest(mRequest);
-
-  camera_metadata_entry_t streams;
-  res = find_camera_metadata_entry(mRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
-                                   &streams);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading output stream tag", __FUNCTION__);
-    mParent->signalError();
-    return false;
-  }
-
-  mNextBuffers = new Buffers;
-  mNextNeedsJpeg = false;
-  ALOGV("Configure: Setting up buffers for capture");
-  for (size_t i = 0; i < streams.count; i++) {
-    int streamId = streams.data.i32[i];
-    const Stream &s = mParent->getStreamInfo(streamId);
-    if (s.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-      ALOGE(
-          "%s: Stream %d does not have a concrete pixel format, but "
-          "is included in a request!",
-          __FUNCTION__, streamId);
-      mParent->signalError();
-      return false;
-    }
-    StreamBuffer b;
-    b.streamId = streamId;  // streams.data.u8[i];
-    b.width = s.width;
-    b.height = s.height;
-    b.format = s.format;
-    b.stride = s.stride;
-    mNextBuffers->push_back(b);
-    ALOGV(
-        "Configure:    Buffer %zu: Stream %d, %d x %d, format 0x%x, "
-        "stride %d",
-        i, b.streamId, b.width, b.height, b.format, b.stride);
-    if (b.format == HAL_PIXEL_FORMAT_BLOB) {
-      mNextNeedsJpeg = true;
-    }
-  }
-
-  camera_metadata_entry_t e;
-  res = find_camera_metadata_entry(mRequest, ANDROID_REQUEST_FRAME_COUNT, &e);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading frame count tag: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    mParent->signalError();
-    return false;
-  }
-  mNextFrameNumber = *e.data.i32;
-
-  res = find_camera_metadata_entry(mRequest, ANDROID_SENSOR_EXPOSURE_TIME, &e);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading exposure time tag: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    mParent->signalError();
-    return false;
-  }
-  mNextExposureTime = *e.data.i64;
-
-  res = find_camera_metadata_entry(mRequest, ANDROID_SENSOR_FRAME_DURATION, &e);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading frame duration tag", __FUNCTION__);
-    mParent->signalError();
-    return false;
-  }
-  mNextFrameDuration = *e.data.i64;
-
-  if (mNextFrameDuration < mNextExposureTime + Sensor::kMinVerticalBlank) {
-    mNextFrameDuration = mNextExposureTime + Sensor::kMinVerticalBlank;
-  }
-  res = find_camera_metadata_entry(mRequest, ANDROID_SENSOR_SENSITIVITY, &e);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading sensitivity tag", __FUNCTION__);
-    mParent->signalError();
-    return false;
-  }
-  mNextSensitivity = *e.data.i32;
-
-  // Start waiting on readout thread
-  mWaitingForReadout = true;
-  ALOGV("Configure: Waiting for readout thread");
-
-  return true;
-}
-
-bool EmulatedFakeCamera2::ConfigureThread::configureNextCapture() {
-  bool vsync = mParent->mSensor->waitForVSync(kWaitPerLoop);
-  if (!vsync) return true;
-
-  Mutex::Autolock il(mInternalsMutex);
-  ALOGV("Configure: Configuring sensor for capture %d", mNextFrameNumber);
-  mParent->mSensor->setExposureTime(mNextExposureTime);
-  mParent->mSensor->setFrameDuration(mNextFrameDuration);
-  mParent->mSensor->setSensitivity(mNextSensitivity);
-
-  getBuffers();
-
-  ALOGV("Configure: Done configure for capture %d", mNextFrameNumber);
-  mParent->mReadoutThread->setNextOperation(true, mRequest, mNextBuffers);
-  mParent->mSensor->setDestinationBuffers(mNextBuffers);
-
-  mRequest = NULL;
-  mNextBuffers = NULL;
-
-  Mutex::Autolock lock(mInputMutex);
-  mRequestCount--;
-
-  return true;
-}
-
-bool EmulatedFakeCamera2::ConfigureThread::setupReprocess() {
-  status_t res;
-
-  mNextNeedsJpeg = true;
-  mNextIsCapture = false;
-
-  camera_metadata_entry_t reprocessStreams;
-  res = find_camera_metadata_entry(mRequest, ANDROID_REQUEST_INPUT_STREAMS,
-                                   &reprocessStreams);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading output stream tag", __FUNCTION__);
-    mParent->signalError();
-    return false;
-  }
-
-  mNextBuffers = new Buffers;
-
-  ALOGV("Configure: Setting up input buffers for reprocess");
-  for (size_t i = 0; i < reprocessStreams.count; i++) {
-    int streamId = reprocessStreams.data.i32[i];
-    const ReprocessStream &s = mParent->getReprocessStreamInfo(streamId);
-    if (s.format != HAL_PIXEL_FORMAT_RGB_888) {
-      ALOGE("%s: Only ZSL reprocessing supported!", __FUNCTION__);
-      mParent->signalError();
-      return false;
-    }
-    StreamBuffer b;
-    b.streamId = -streamId;
-    b.width = s.width;
-    b.height = s.height;
-    b.format = s.format;
-    b.stride = s.stride;
-    mNextBuffers->push_back(b);
-  }
-
-  camera_metadata_entry_t streams;
-  res = find_camera_metadata_entry(mRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
-                                   &streams);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading output stream tag", __FUNCTION__);
-    mParent->signalError();
-    return false;
-  }
-
-  ALOGV("Configure: Setting up output buffers for reprocess");
-  for (size_t i = 0; i < streams.count; i++) {
-    int streamId = streams.data.i32[i];
-    const Stream &s = mParent->getStreamInfo(streamId);
-    if (s.format != HAL_PIXEL_FORMAT_BLOB) {
-      // TODO: Support reprocess to YUV
-      ALOGE("%s: Non-JPEG output stream %d for reprocess not supported",
-            __FUNCTION__, streamId);
-      mParent->signalError();
-      return false;
-    }
-    StreamBuffer b;
-    b.streamId = streams.data.u8[i];
-    b.width = s.width;
-    b.height = s.height;
-    b.format = s.format;
-    b.stride = s.stride;
-    mNextBuffers->push_back(b);
-    ALOGV(
-        "Configure:    Buffer %zu: Stream %d, %d x %d, format 0x%x, "
-        "stride %d",
-        i, b.streamId, b.width, b.height, b.format, b.stride);
-  }
-
-  camera_metadata_entry_t e;
-  res = find_camera_metadata_entry(mRequest, ANDROID_REQUEST_FRAME_COUNT, &e);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading frame count tag: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    mParent->signalError();
-    return false;
-  }
-  mNextFrameNumber = *e.data.i32;
-
-  return true;
-}
-
-bool EmulatedFakeCamera2::ConfigureThread::configureNextReprocess() {
-  Mutex::Autolock il(mInternalsMutex);
-
-  getBuffers();
-
-  ALOGV("Configure: Done configure for reprocess %d", mNextFrameNumber);
-  mParent->mReadoutThread->setNextOperation(false, mRequest, mNextBuffers);
-
-  mRequest = NULL;
-  mNextBuffers = NULL;
-
-  Mutex::Autolock lock(mInputMutex);
-  mRequestCount--;
-
-  return true;
-}
-
-bool EmulatedFakeCamera2::ConfigureThread::getBuffers() {
-  status_t res;
-  /** Get buffers to fill for this frame */
-  for (size_t i = 0; i < mNextBuffers->size(); i++) {
-    StreamBuffer &b = mNextBuffers->editItemAt(i);
-
-    if (b.streamId > 0) {
-      ALOGV("Configure: Dequeing buffer from stream %d", b.streamId);
-      Stream s = mParent->getStreamInfo(b.streamId);
-      res = s.ops->dequeue_buffer(s.ops, &(b.buffer));
-      if (res != NO_ERROR || b.buffer == NULL) {
-        ALOGE("%s: Unable to dequeue buffer from stream %d: %s (%d)",
-              __FUNCTION__, b.streamId, strerror(-res), res);
-        mParent->signalError();
-        return false;
-      }
-
-      /* Lock the buffer from the perspective of the graphics mapper */
-      res = GrallocModule::getInstance().lock(
-          *(b.buffer), GRALLOC_USAGE_HW_CAMERA_WRITE, 0, 0, s.width, s.height,
-          (void **)&(b.img));
-
-      if (res != NO_ERROR) {
-        ALOGE("%s: grbuffer_mapper.lock failure: %s (%d)", __FUNCTION__,
-              strerror(-res), res);
-        s.ops->cancel_buffer(s.ops, b.buffer);
-        mParent->signalError();
-        return false;
-      }
-    } else {
-      ALOGV("Configure: Acquiring buffer from reprocess stream %d",
-            -b.streamId);
-      ReprocessStream s = mParent->getReprocessStreamInfo(-b.streamId);
-      res = s.ops->acquire_buffer(s.ops, &(b.buffer));
-      if (res != NO_ERROR || b.buffer == NULL) {
-        ALOGE(
-            "%s: Unable to acquire buffer from reprocess stream %d: "
-            "%s (%d)",
-            __FUNCTION__, -b.streamId, strerror(-res), res);
-        mParent->signalError();
-        return false;
-      }
-
-      /* Lock the buffer from the perspective of the graphics mapper */
-      res = GrallocModule::getInstance().lock(
-          *(b.buffer), GRALLOC_USAGE_HW_CAMERA_READ, 0, 0, s.width, s.height,
-          (void **)&(b.img));
-      if (res != NO_ERROR) {
-        ALOGE("%s: grbuffer_mapper.lock failure: %s (%d)", __FUNCTION__,
-              strerror(-res), res);
-        s.ops->release_buffer(s.ops, b.buffer);
-        mParent->signalError();
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-EmulatedFakeCamera2::ReadoutThread::ReadoutThread(EmulatedFakeCamera2 *parent)
-    : Thread(false),
-      mParent(parent),
-      mRunning(false),
-      mActive(false),
-      mRequestCount(0),
-      mRequest(NULL),
-      mBuffers(NULL) {
-  mInFlightQueue = new InFlightQueue[kInFlightQueueSize];
-  mInFlightHead = 0;
-  mInFlightTail = 0;
-}
-
-EmulatedFakeCamera2::ReadoutThread::~ReadoutThread() {
-  delete[] mInFlightQueue;
-}
-
-status_t EmulatedFakeCamera2::ReadoutThread::readyToRun() {
-  Mutex::Autolock lock(mInputMutex);
-  ALOGV("Starting up ReadoutThread");
-  mRunning = true;
-  mInputSignal.signal();
-  return NO_ERROR;
-}
-
-status_t EmulatedFakeCamera2::ReadoutThread::waitUntilRunning() {
-  Mutex::Autolock lock(mInputMutex);
-  if (!mRunning) {
-    ALOGV("Waiting for readout thread to start");
-    mInputSignal.wait(mInputMutex);
-  }
-  return OK;
-}
-
-bool EmulatedFakeCamera2::ReadoutThread::waitForReady(nsecs_t timeout) {
-  status_t res;
-  Mutex::Autolock lock(mInputMutex);
-  while (!readyForNextCapture()) {
-    res = mReadySignal.waitRelative(mInputMutex, timeout);
-    if (res == TIMED_OUT) return false;
-    if (res != OK) {
-      ALOGE("%s: Error waiting for ready: %s (%d)", __FUNCTION__,
-            strerror(-res), res);
-      return false;
-    }
-  }
-  return true;
-}
-
-bool EmulatedFakeCamera2::ReadoutThread::readyForNextCapture() {
-  return (mInFlightTail + 1) % kInFlightQueueSize != mInFlightHead;
-}
-
-void EmulatedFakeCamera2::ReadoutThread::setNextOperation(
-    bool isCapture, camera_metadata_t *request, Buffers *buffers) {
-  Mutex::Autolock lock(mInputMutex);
-  if (!readyForNextCapture()) {
-    ALOGE("In flight queue full, dropping captures");
-    mParent->signalError();
-    return;
-  }
-  mInFlightQueue[mInFlightTail].isCapture = isCapture;
-  mInFlightQueue[mInFlightTail].request = request;
-  mInFlightQueue[mInFlightTail].buffers = buffers;
-  mInFlightTail = (mInFlightTail + 1) % kInFlightQueueSize;
-  mRequestCount++;
-
-  if (!mActive) {
-    mActive = true;
-    mInputSignal.signal();
-  }
-}
-
-bool EmulatedFakeCamera2::ReadoutThread::isStreamInUse(uint32_t id) {
-  // acquire in same order as threadLoop
-  Mutex::Autolock iLock(mInternalsMutex);
-  Mutex::Autolock lock(mInputMutex);
-
-  size_t i = mInFlightHead;
-  while (i != mInFlightTail) {
-    for (size_t j = 0; j < mInFlightQueue[i].buffers->size(); j++) {
-      if ((*(mInFlightQueue[i].buffers))[j].streamId == (int)id) return true;
-    }
-    i = (i + 1) % kInFlightQueueSize;
-  }
-
-  if (mBuffers != NULL) {
-    for (i = 0; i < mBuffers->size(); i++) {
-      if ((*mBuffers)[i].streamId == (int)id) return true;
-    }
-  }
-
-  return false;
-}
-
-int EmulatedFakeCamera2::ReadoutThread::getInProgressCount() {
-  Mutex::Autolock lock(mInputMutex);
-
-  return mRequestCount;
-}
-
-bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
-  static const nsecs_t kWaitPerLoop = 10000000L;  // 10 ms
-  status_t res;
-  int32_t frameNumber;
-
-  // Check if we're currently processing or just waiting
-  {
-    Mutex::Autolock lock(mInputMutex);
-    if (!mActive) {
-      // Inactive, keep waiting until we've been signaled
-      res = mInputSignal.waitRelative(mInputMutex, kWaitPerLoop);
-      if (res != NO_ERROR && res != TIMED_OUT) {
-        ALOGE("%s: Error waiting for capture requests: %d", __FUNCTION__, res);
-        mParent->signalError();
-        return false;
-      }
-      if (!mActive) return true;
-    }
-    // Active, see if we need a new request
-    if (mRequest == NULL) {
-      if (mInFlightHead == mInFlightTail) {
-        // Go inactive
-        ALOGV("Waiting for sensor data");
-        mActive = false;
-        return true;
-      } else {
-        Mutex::Autolock iLock(mInternalsMutex);
-        mReadySignal.signal();
-        mIsCapture = mInFlightQueue[mInFlightHead].isCapture;
-        mRequest = mInFlightQueue[mInFlightHead].request;
-        mBuffers = mInFlightQueue[mInFlightHead].buffers;
-        mInFlightQueue[mInFlightHead].request = NULL;
-        mInFlightQueue[mInFlightHead].buffers = NULL;
-        mInFlightHead = (mInFlightHead + 1) % kInFlightQueueSize;
-        ALOGV("Ready to read out request %p, %zu buffers", mRequest,
-              mBuffers->size());
-      }
-    }
-  }
-
-  // Active with request, wait on sensor to complete
-
-  nsecs_t captureTime;
-
-  if (mIsCapture) {
-    bool gotFrame;
-    gotFrame = mParent->mSensor->waitForNewFrame(kWaitPerLoop, &captureTime);
-
-    if (!gotFrame) return true;
-  }
-
-  Mutex::Autolock iLock(mInternalsMutex);
-
-  camera_metadata_entry_t entry;
-  if (!mIsCapture) {
-    res =
-        find_camera_metadata_entry(mRequest, ANDROID_SENSOR_TIMESTAMP, &entry);
-    if (res != NO_ERROR) {
-      ALOGE("%s: error reading reprocessing timestamp: %s (%d)", __FUNCTION__,
-            strerror(-res), res);
-      mParent->signalError();
-      return false;
-    }
-    captureTime = entry.data.i64[0];
-  }
-
-  res =
-      find_camera_metadata_entry(mRequest, ANDROID_REQUEST_FRAME_COUNT, &entry);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading frame count tag: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    mParent->signalError();
-    return false;
-  }
-  frameNumber = *entry.data.i32;
-
-  res = find_camera_metadata_entry(mRequest, ANDROID_REQUEST_METADATA_MODE,
-                                   &entry);
-  if (res != NO_ERROR) {
-    ALOGE("%s: error reading metadata mode tag: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    mParent->signalError();
-    return false;
-  }
-
-  // Got sensor data and request, construct frame and send it out
-  ALOGV("Readout: Constructing metadata and frames for request %d",
-        frameNumber);
-
-  if (*entry.data.u8 == ANDROID_REQUEST_METADATA_MODE_FULL) {
-    ALOGV("Readout: Metadata requested, constructing");
-
-    camera_metadata_t *frame = NULL;
-
-    size_t frame_entries = get_camera_metadata_entry_count(mRequest);
-    size_t frame_data = get_camera_metadata_data_count(mRequest);
-
-    // TODO: Dynamically calculate based on enabled statistics, etc
-    frame_entries += 10;
-    frame_data += 100;
-
-    res = mParent->mFrameQueueDst->dequeue_frame(
-        mParent->mFrameQueueDst, frame_entries, frame_data, &frame);
-
-    if (res != NO_ERROR || frame == NULL) {
-      ALOGE("%s: Unable to dequeue frame metadata buffer", __FUNCTION__);
-      mParent->signalError();
-      return false;
-    }
-
-    res = append_camera_metadata(frame, mRequest);
-    if (res != NO_ERROR) {
-      ALOGE("Unable to append request metadata");
-    }
-
-    if (mIsCapture) {
-      add_camera_metadata_entry(frame, ANDROID_SENSOR_TIMESTAMP, &captureTime,
-                                1);
-
-      collectStatisticsMetadata(frame);
-      // TODO: Collect all final values used from sensor in addition to
-      // timestamp
-    }
-
-    ALOGV("Readout: Enqueue frame %d", frameNumber);
-    mParent->mFrameQueueDst->enqueue_frame(mParent->mFrameQueueDst, frame);
-  }
-  ALOGV("Readout: Free request");
-  res = mParent->mRequestQueueSrc->free_request(mParent->mRequestQueueSrc,
-                                                mRequest);
-  if (res != NO_ERROR) {
-    ALOGE("%s: Unable to return request buffer to queue: %d", __FUNCTION__,
-          res);
-    mParent->signalError();
-    return false;
-  }
-  mRequest = NULL;
-
-  int compressedBufferIndex = -1;
-  ALOGV("Readout: Processing %zu buffers", mBuffers->size());
-  for (size_t i = 0; i < mBuffers->size(); i++) {
-    const StreamBuffer &b = (*mBuffers)[i];
-    ALOGV("Readout:    Buffer %zu: Stream %d, %d x %d, format 0x%x, stride %d",
-          i, b.streamId, b.width, b.height, b.format, b.stride);
-    if (b.streamId > 0) {
-      if (b.format == HAL_PIXEL_FORMAT_BLOB) {
-        // Assumes only one BLOB buffer type per capture
-        compressedBufferIndex = i;
-      } else {
-        ALOGV("Readout:    Sending image buffer %zu (%p) to output stream %d",
-              i, (void *)*(b.buffer), b.streamId);
-        GrallocModule::getInstance().unlock(*(b.buffer));
-        const Stream &s = mParent->getStreamInfo(b.streamId);
-        res = s.ops->enqueue_buffer(s.ops, captureTime, b.buffer);
-        if (res != OK) {
-          ALOGE("Error enqueuing image buffer %p: %s (%d)", b.buffer,
-                strerror(-res), res);
-          mParent->signalError();
-        }
-      }
-    }
-  }
-
-  if (compressedBufferIndex == -1) {
-    delete mBuffers;
-  } else {
-    ALOGV("Readout:  Starting JPEG compression for buffer %d, stream %d",
-          compressedBufferIndex, (*mBuffers)[compressedBufferIndex].streamId);
-    mJpegTimestamp = captureTime;
-    // Takes ownership of mBuffers
-    mParent->mJpegCompressor->start(mBuffers, this);
-  }
-  mBuffers = NULL;
-
-  Mutex::Autolock l(mInputMutex);
-  mRequestCount--;
-  ALOGV("Readout: Done with request %d", frameNumber);
-  return true;
-}
-
-void EmulatedFakeCamera2::ReadoutThread::onJpegDone(
-    const StreamBuffer &jpegBuffer, bool success) {
-  if (!success) {
-    ALOGE("%s: Error queueing compressed image buffer %p", __FUNCTION__,
-          jpegBuffer.buffer);
-    mParent->signalError();
-    return;
-  }
-
-  // Write to JPEG output stream
-  ALOGV("%s: Compression complete, pushing to stream %d", __FUNCTION__,
-        jpegBuffer.streamId);
-
-  GrallocModule::getInstance().unlock(*(jpegBuffer.buffer));
-  const Stream &s = mParent->getStreamInfo(jpegBuffer.streamId);
-  s.ops->enqueue_buffer(s.ops, mJpegTimestamp, jpegBuffer.buffer);
-}
-
-void EmulatedFakeCamera2::ReadoutThread::onJpegInputDone(
-    const StreamBuffer &inputBuffer) {
-  status_t res;
-  GrallocModule::getInstance().unlock(*(inputBuffer.buffer));
-  const ReprocessStream &s =
-      mParent->getReprocessStreamInfo(-inputBuffer.streamId);
-  res = s.ops->release_buffer(s.ops, inputBuffer.buffer);
-  if (res != OK) {
-    ALOGE("Error releasing reprocess buffer %p: %s (%d)", inputBuffer.buffer,
-          strerror(-res), res);
-    mParent->signalError();
-  }
-}
-
-status_t EmulatedFakeCamera2::ReadoutThread::collectStatisticsMetadata(
-    camera_metadata_t *frame) {
-  // Completely fake face rectangles, don't correspond to real faces in scene
-  ALOGV("Readout:    Collecting statistics metadata");
-
-  status_t res;
-  camera_metadata_entry_t entry;
-  res = find_camera_metadata_entry(frame, ANDROID_STATISTICS_FACE_DETECT_MODE,
-                                   &entry);
-  if (res != OK) {
-    ALOGE("%s: Unable to find face detect mode!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  if (entry.data.u8[0] == ANDROID_STATISTICS_FACE_DETECT_MODE_OFF) return OK;
-
-  // The coordinate system for the face regions is the raw sensor pixel
-  // coordinates. Here, we map from the scene coordinates (0-19 in both axis)
-  // to raw pixels, for the scene defined in fake-pipeline2/Scene.cpp. We
-  // approximately place two faces on top of the windows of the house. No
-  // actual faces exist there, but might one day. Note that this doesn't
-  // account for the offsets used to account for aspect ratio differences, so
-  // the rectangles don't line up quite right.
-  const size_t numFaces = 2;
-  int32_t rects[numFaces * 4] = {
-      static_cast<int32_t>(mParent->mSensorWidth * 10 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 15 / 20),
-      static_cast<int32_t>(mParent->mSensorWidth * 12 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 17 / 20),
-
-      static_cast<int32_t>(mParent->mSensorWidth * 16 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 15 / 20),
-      static_cast<int32_t>(mParent->mSensorWidth * 18 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 17 / 20)};
-  // To simulate some kind of real detection going on, we jitter the rectangles
-  // on each frame by a few pixels in each dimension.
-  for (size_t i = 0; i < numFaces * 4; i++) {
-    rects[i] += (int32_t)(((float)rand() / (float)RAND_MAX) * 6 - 3);
-  }
-  // The confidence scores (0-100) are similarly jittered.
-  uint8_t scores[numFaces] = {85, 95};
-  for (size_t i = 0; i < numFaces; i++) {
-    scores[i] += (int32_t)(((float)rand() / (float)RAND_MAX) * 10 - 5);
-  }
-
-  res = add_camera_metadata_entry(frame, ANDROID_STATISTICS_FACE_RECTANGLES,
-                                  rects, numFaces * 4);
-  if (res != OK) {
-    ALOGE("%s: Unable to add face rectangles!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  res = add_camera_metadata_entry(frame, ANDROID_STATISTICS_FACE_SCORES, scores,
-                                  numFaces);
-  if (res != OK) {
-    ALOGE("%s: Unable to add face scores!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  if (entry.data.u8[0] == ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE) return OK;
-
-  // Advanced face detection options - add eye/mouth coordinates.  The
-  // coordinates in order are (leftEyeX, leftEyeY, rightEyeX, rightEyeY,
-  // mouthX, mouthY). The mapping is the same as the face rectangles.
-  int32_t features[numFaces * 6] = {
-      static_cast<int32_t>(mParent->mSensorWidth * 10.5 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 16 / 20),
-      static_cast<int32_t>(mParent->mSensorWidth * 11.5 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 16 / 20),
-      static_cast<int32_t>(mParent->mSensorWidth * 11 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 16.5 / 20),
-
-      static_cast<int32_t>(mParent->mSensorWidth * 16.5 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 16 / 20),
-      static_cast<int32_t>(mParent->mSensorWidth * 17.5 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 16 / 20),
-      static_cast<int32_t>(mParent->mSensorWidth * 17 / 20),
-      static_cast<int32_t>(mParent->mSensorHeight * 16.5 / 20),
-  };
-  // Jitter these a bit less than the rects
-  for (size_t i = 0; i < numFaces * 6; i++) {
-    features[i] += (int32_t)(((float)rand() / (float)RAND_MAX) * 4 - 2);
-  }
-  // These are unique IDs that are used to identify each face while it's
-  // visible to the detector (if a face went away and came back, it'd get a
-  // new ID).
-  int32_t ids[numFaces] = {100, 200};
-
-  res = add_camera_metadata_entry(frame, ANDROID_STATISTICS_FACE_LANDMARKS,
-                                  features, numFaces * 6);
-  if (res != OK) {
-    ALOGE("%s: Unable to add face landmarks!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  res = add_camera_metadata_entry(frame, ANDROID_STATISTICS_FACE_IDS, ids,
-                                  numFaces);
-  if (res != OK) {
-    ALOGE("%s: Unable to add face scores!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  return OK;
-}
-
-EmulatedFakeCamera2::ControlThread::ControlThread(EmulatedFakeCamera2 *parent)
-    : Thread(false), mParent(parent) {
-  mRunning = false;
-}
-
-EmulatedFakeCamera2::ControlThread::~ControlThread() {}
-
-status_t EmulatedFakeCamera2::ControlThread::readyToRun() {
-  Mutex::Autolock lock(mInputMutex);
-
-  ALOGV("Starting up ControlThread");
-  mRunning = true;
-  mStartAf = false;
-  mCancelAf = false;
-  mStartPrecapture = false;
-
-  mControlMode = ANDROID_CONTROL_MODE_AUTO;
-
-  mEffectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
-  mSceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
-
-  mAfMode = ANDROID_CONTROL_AF_MODE_AUTO;
-  mAfModeChange = false;
-
-  mAeMode = ANDROID_CONTROL_AE_MODE_ON;
-  mAwbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
-
-  mAfTriggerId = 0;
-  mPrecaptureTriggerId = 0;
-
-  mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
-  mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
-  mAwbState = ANDROID_CONTROL_AWB_STATE_INACTIVE;
-
-  mExposureTime = kNormalExposureTime;
-
-  mInputSignal.signal();
-  return NO_ERROR;
-}
-
-status_t EmulatedFakeCamera2::ControlThread::waitUntilRunning() {
-  Mutex::Autolock lock(mInputMutex);
-  if (!mRunning) {
-    ALOGV("Waiting for control thread to start");
-    mInputSignal.wait(mInputMutex);
-  }
-  return OK;
-}
-
-// Override android.control.* fields with 3A values before sending request to
-// sensor
-status_t EmulatedFakeCamera2::ControlThread::processRequest(
-    camera_metadata_t *request) {
-  Mutex::Autolock lock(mInputMutex);
-  // TODO: Add handling for all android.control.* fields here
-  camera_metadata_entry_t mode;
-  status_t res;
-
-#define READ_IF_OK(res, what, def) (((res) == OK) ? (what) : (uint8_t)(def))
-
-  res = find_camera_metadata_entry(request, ANDROID_CONTROL_MODE, &mode);
-  mControlMode = READ_IF_OK(res, mode.data.u8[0], ANDROID_CONTROL_MODE_OFF);
-
-  // disable all 3A
-  if (mControlMode == ANDROID_CONTROL_MODE_OFF) {
-    mEffectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
-    mSceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
-    mAfMode = ANDROID_CONTROL_AF_MODE_OFF;
-    mAeLock = ANDROID_CONTROL_AE_LOCK_ON;
-    mAeMode = ANDROID_CONTROL_AE_MODE_OFF;
-    mAfModeChange = true;
-    mStartAf = false;
-    mCancelAf = true;
-    mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
-    mAwbMode = ANDROID_CONTROL_AWB_MODE_OFF;
-    return res;
-  }
-
-  res = find_camera_metadata_entry(request, ANDROID_CONTROL_EFFECT_MODE, &mode);
-  mEffectMode =
-      READ_IF_OK(res, mode.data.u8[0], ANDROID_CONTROL_EFFECT_MODE_OFF);
-
-  res = find_camera_metadata_entry(request, ANDROID_CONTROL_SCENE_MODE, &mode);
-  mSceneMode =
-      READ_IF_OK(res, mode.data.u8[0], ANDROID_CONTROL_SCENE_MODE_DISABLED);
-
-  res = find_camera_metadata_entry(request, ANDROID_CONTROL_AF_MODE, &mode);
-  if (mAfMode != mode.data.u8[0]) {
-    ALOGV("AF new mode: %d, old mode %d", mode.data.u8[0], mAfMode);
-    mAfMode = mode.data.u8[0];
-    mAfModeChange = true;
-    mStartAf = false;
-    mCancelAf = false;
-  }
-
-  res = find_camera_metadata_entry(request, ANDROID_CONTROL_AE_MODE, &mode);
-  mAeMode = READ_IF_OK(res, mode.data.u8[0], ANDROID_CONTROL_AE_MODE_OFF);
-
-  res = find_camera_metadata_entry(request, ANDROID_CONTROL_AE_LOCK, &mode);
-  uint8_t aeLockVal =
-      READ_IF_OK(res, mode.data.u8[0], ANDROID_CONTROL_AE_LOCK_ON);
-  bool aeLock = (aeLockVal == ANDROID_CONTROL_AE_LOCK_ON);
-  if (mAeLock && !aeLock) {
-    mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
-  }
-  mAeLock = aeLock;
-
-  res = find_camera_metadata_entry(request, ANDROID_CONTROL_AWB_MODE, &mode);
-  mAwbMode = READ_IF_OK(res, mode.data.u8[0], ANDROID_CONTROL_AWB_MODE_OFF);
-
-  // TODO: Override more control fields
-
-  if (mAeMode != ANDROID_CONTROL_AE_MODE_OFF) {
-    camera_metadata_entry_t exposureTime;
-    res = find_camera_metadata_entry(request, ANDROID_SENSOR_EXPOSURE_TIME,
-                                     &exposureTime);
-    if (res == OK) {
-      exposureTime.data.i64[0] = mExposureTime;
-    }
-  }
-
-#undef READ_IF_OK
-
-  return OK;
-}
-
-status_t EmulatedFakeCamera2::ControlThread::triggerAction(uint32_t msgType,
-                                                           int32_t ext1,
-                                                           int32_t ext2) {
-  ALOGV("%s: Triggering %d (%d, %d)", __FUNCTION__, msgType, ext1, ext2);
-  Mutex::Autolock lock(mInputMutex);
-  switch (msgType) {
-    case CAMERA2_TRIGGER_AUTOFOCUS:
-      mAfTriggerId = ext1;
-      mStartAf = true;
-      mCancelAf = false;
-      break;
-    case CAMERA2_TRIGGER_CANCEL_AUTOFOCUS:
-      mAfTriggerId = ext1;
-      mStartAf = false;
-      mCancelAf = true;
-      break;
-    case CAMERA2_TRIGGER_PRECAPTURE_METERING:
-      mPrecaptureTriggerId = ext1;
-      mStartPrecapture = true;
-      break;
-    default:
-      ALOGE("%s: Unknown action triggered: %d (arguments %d %d)", __FUNCTION__,
-            msgType, ext1, ext2);
-      return BAD_VALUE;
-  }
-  return OK;
-}
-
-const nsecs_t EmulatedFakeCamera2::ControlThread::kControlCycleDelay =
-    100 * MSEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kMinAfDuration = 500 * MSEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kMaxAfDuration = 900 * MSEC;
-const float EmulatedFakeCamera2::ControlThread::kAfSuccessRate = 0.9;
-// Once every 5 seconds
-const float EmulatedFakeCamera2::ControlThread::kContinuousAfStartRate =
-    kControlCycleDelay / 5.0 * SEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kMinAeDuration = 500 * MSEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kMaxAeDuration = 2 * SEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kMinPrecaptureAeDuration =
-    100 * MSEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kMaxPrecaptureAeDuration =
-    400 * MSEC;
-// Once every 3 seconds
-const float EmulatedFakeCamera2::ControlThread::kAeScanStartRate =
-    kControlCycleDelay / 3000000000.0;
-
-const nsecs_t EmulatedFakeCamera2::ControlThread::kNormalExposureTime =
-    10 * MSEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kExposureJump = 2 * MSEC;
-const nsecs_t EmulatedFakeCamera2::ControlThread::kMinExposureTime = 1 * MSEC;
-
-bool EmulatedFakeCamera2::ControlThread::threadLoop() {
-  bool afModeChange = false;
-  bool afTriggered = false;
-  bool afCancelled = false;
-  uint8_t afState;
-  uint8_t afMode;
-  int32_t afTriggerId;
-  bool precaptureTriggered = false;
-  uint8_t aeState;
-  uint8_t aeMode;
-  bool aeLock;
-  int32_t precaptureTriggerId;
-  nsecs_t nextSleep = kControlCycleDelay;
-
-  {
-    Mutex::Autolock lock(mInputMutex);
-    if (mStartAf) {
-      ALOGD("Starting AF trigger processing");
-      afTriggered = true;
-      mStartAf = false;
-    } else if (mCancelAf) {
-      ALOGD("Starting cancel AF trigger processing");
-      afCancelled = true;
-      mCancelAf = false;
-    }
-    afState = mAfState;
-    afMode = mAfMode;
-    afModeChange = mAfModeChange;
-    mAfModeChange = false;
-
-    afTriggerId = mAfTriggerId;
-
-    if (mStartPrecapture) {
-      ALOGD("Starting precapture trigger processing");
-      precaptureTriggered = true;
-      mStartPrecapture = false;
-    }
-    aeState = mAeState;
-    aeMode = mAeMode;
-    aeLock = mAeLock;
-    precaptureTriggerId = mPrecaptureTriggerId;
-  }
-
-  if (afCancelled || afModeChange) {
-    ALOGV("Resetting AF state due to cancel/mode change");
-    afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
-    updateAfState(afState, afTriggerId);
-    mAfScanDuration = 0;
-    mLockAfterPassiveScan = false;
-  }
-
-  if (afTriggered) {
-    afState = processAfTrigger(afMode, afState);
-  }
-
-  afState = maybeStartAfScan(afMode, afState);
-  afState = updateAfScan(afMode, afState, &nextSleep);
-  updateAfState(afState, afTriggerId);
-
-  if (precaptureTriggered) {
-    aeState = processPrecaptureTrigger(aeMode, aeState);
-  }
-
-  aeState = maybeStartAeScan(aeMode, aeLock, aeState);
-  aeState = updateAeScan(aeMode, aeLock, aeState, &nextSleep);
-  updateAeState(aeState, precaptureTriggerId);
-
-  int ret;
-  timespec t;
-  t.tv_sec = 0;
-  t.tv_nsec = nextSleep;
-  do {
-    ret = nanosleep(&t, &t);
-  } while (ret != 0);
-
-  if (mAfScanDuration > 0) {
-    mAfScanDuration -= nextSleep;
-  }
-  if (mAeScanDuration > 0) {
-    mAeScanDuration -= nextSleep;
-  }
-
-  return true;
-}
-
-int EmulatedFakeCamera2::ControlThread::processAfTrigger(uint8_t afMode,
-                                                         uint8_t afState) {
-  switch (afMode) {
-    case ANDROID_CONTROL_AF_MODE_OFF:
-    case ANDROID_CONTROL_AF_MODE_EDOF:
-      // Do nothing
-      break;
-    case ANDROID_CONTROL_AF_MODE_MACRO:
-    case ANDROID_CONTROL_AF_MODE_AUTO:
-      switch (afState) {
-        case ANDROID_CONTROL_AF_STATE_INACTIVE:
-        case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
-        case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
-          // Start new focusing cycle
-          mAfScanDuration =
-              ((double)rand() / RAND_MAX) * (kMaxAfDuration - kMinAfDuration) +
-              kMinAfDuration;
-          afState = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
-          ALOGV("%s: AF scan start, duration %" PRId64 " ms", __FUNCTION__,
-                mAfScanDuration / 1000000);
-          break;
-        case ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN:
-          // Ignore new request, already scanning
-          break;
-        default:
-          ALOGE("Unexpected AF state in AUTO/MACRO AF mode: %d", afState);
-      }
-      break;
-    case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-      switch (afState) {
-        // Picture mode waits for passive scan to complete
-        case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
-          mLockAfterPassiveScan = true;
-          break;
-        case ANDROID_CONTROL_AF_STATE_INACTIVE:
-          afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-          break;
-        case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
-          afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
-          break;
-        case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
-        case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
-          // Must cancel to get out of these states
-          break;
-        default:
-          ALOGE("Unexpected AF state in CONTINUOUS_PICTURE AF mode: %d",
-                afState);
-      }
-      break;
-    case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-      switch (afState) {
-        // Video mode does not wait for passive scan to complete
-        case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
-        case ANDROID_CONTROL_AF_STATE_INACTIVE:
-          afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-          break;
-        case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
-          afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
-          break;
-        case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
-        case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
-          // Must cancel to get out of these states
-          break;
-        default:
-          ALOGE("Unexpected AF state in CONTINUOUS_VIDEO AF mode: %d", afState);
-      }
-      break;
-    default:
-      break;
-  }
-  return afState;
-}
-
-int EmulatedFakeCamera2::ControlThread::maybeStartAfScan(uint8_t afMode,
-                                                         uint8_t afState) {
-  if ((afMode == ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO ||
-       afMode == ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE) &&
-      (afState == ANDROID_CONTROL_AF_STATE_INACTIVE ||
-       afState == ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED)) {
-    bool startScan = ((double)rand() / RAND_MAX) < kContinuousAfStartRate;
-    if (startScan) {
-      // Start new passive focusing cycle
-      mAfScanDuration =
-          ((double)rand() / RAND_MAX) * (kMaxAfDuration - kMinAfDuration) +
-          kMinAfDuration;
-      afState = ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN;
-      ALOGV("%s: AF passive scan start, duration %" PRId64 " ms", __FUNCTION__,
-            mAfScanDuration / 1000000);
-    }
-  }
-  return afState;
-}
-
-int EmulatedFakeCamera2::ControlThread::updateAfScan(uint8_t afMode,
-                                                     uint8_t afState,
-                                                     nsecs_t *maxSleep) {
-  if (!(afState == ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN ||
-        afState == ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN)) {
-    return afState;
-  }
-
-  if (mAfScanDuration <= 0) {
-    ALOGV("%s: AF scan done", __FUNCTION__);
-    switch (afMode) {
-      case ANDROID_CONTROL_AF_MODE_MACRO:
-      case ANDROID_CONTROL_AF_MODE_AUTO: {
-        bool success = ((double)rand() / RAND_MAX) < kAfSuccessRate;
-        if (success) {
-          afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
-        } else {
-          afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-        }
-        break;
-      }
-      case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-        if (mLockAfterPassiveScan) {
-          afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
-          mLockAfterPassiveScan = false;
-        } else {
-          afState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
-        }
-        break;
-      case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-        afState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
-        break;
-      default:
-        ALOGE("Unexpected AF mode in scan state");
-    }
-  } else {
-    if (mAfScanDuration <= *maxSleep) {
-      *maxSleep = mAfScanDuration;
-    }
-  }
-  return afState;
-}
-
-void EmulatedFakeCamera2::ControlThread::updateAfState(uint8_t newState,
-                                                       int32_t triggerId) {
-  Mutex::Autolock lock(mInputMutex);
-  if (mAfState != newState) {
-    ALOGV("%s: Autofocus state now %d, id %d", __FUNCTION__, newState,
-          triggerId);
-    mAfState = newState;
-    mParent->sendNotification(CAMERA2_MSG_AUTOFOCUS, newState, triggerId, 0);
-  }
-}
-
-int EmulatedFakeCamera2::ControlThread::processPrecaptureTrigger(
-    uint8_t aeMode, uint8_t aeState) {
-  switch (aeMode) {
-    case ANDROID_CONTROL_AE_MODE_OFF:
-      // Don't do anything for these
-      return aeState;
-    case ANDROID_CONTROL_AE_MODE_ON:
-    case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH:
-    case ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH:
-    case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE:
-      // Trigger a precapture cycle
-      aeState = ANDROID_CONTROL_AE_STATE_PRECAPTURE;
-      mAeScanDuration =
-          ((double)rand() / RAND_MAX) *
-              (kMaxPrecaptureAeDuration - kMinPrecaptureAeDuration) +
-          kMinPrecaptureAeDuration;
-      ALOGD("%s: AE precapture scan start, duration %" PRId64 " ms",
-            __FUNCTION__, mAeScanDuration / 1000000);
-  }
-  return aeState;
-}
-
-int EmulatedFakeCamera2::ControlThread::maybeStartAeScan(uint8_t aeMode,
-                                                         bool aeLocked,
-                                                         uint8_t aeState) {
-  if (aeLocked) return aeState;
-  switch (aeMode) {
-    case ANDROID_CONTROL_AE_MODE_OFF:
-      break;
-    case ANDROID_CONTROL_AE_MODE_ON:
-    case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH:
-    case ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH:
-    case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE: {
-      if (aeState != ANDROID_CONTROL_AE_STATE_INACTIVE &&
-          aeState != ANDROID_CONTROL_AE_STATE_CONVERGED)
-        break;
-
-      bool startScan = ((double)rand() / RAND_MAX) < kAeScanStartRate;
-      if (startScan) {
-        mAeScanDuration =
-            ((double)rand() / RAND_MAX) * (kMaxAeDuration - kMinAeDuration) +
-            kMinAeDuration;
-        aeState = ANDROID_CONTROL_AE_STATE_SEARCHING;
-        ALOGV("%s: AE scan start, duration %" PRId64 " ms", __FUNCTION__,
-              mAeScanDuration / 1000000);
-      }
-    }
-  }
-
-  return aeState;
-}
-
-int EmulatedFakeCamera2::ControlThread::updateAeScan(uint8_t /*aeMode*/,
-                                                     bool aeLock,
-                                                     uint8_t aeState,
-                                                     nsecs_t *maxSleep) {
-  if (aeLock && aeState != ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
-    mAeScanDuration = 0;
-    aeState = ANDROID_CONTROL_AE_STATE_LOCKED;
-  } else if ((aeState == ANDROID_CONTROL_AE_STATE_SEARCHING) ||
-             (aeState == ANDROID_CONTROL_AE_STATE_PRECAPTURE)) {
-    if (mAeScanDuration <= 0) {
-      ALOGV("%s: AE scan done", __FUNCTION__);
-      aeState = aeLock ? ANDROID_CONTROL_AE_STATE_LOCKED
-                       : ANDROID_CONTROL_AE_STATE_CONVERGED;
-
-      Mutex::Autolock lock(mInputMutex);
-      mExposureTime = kNormalExposureTime;
-    } else {
-      if (mAeScanDuration <= *maxSleep) {
-        *maxSleep = mAeScanDuration;
-      }
-
-      int64_t exposureDelta =
-          ((double)rand() / RAND_MAX) * 2 * kExposureJump - kExposureJump;
-      Mutex::Autolock lock(mInputMutex);
-      mExposureTime = mExposureTime + exposureDelta;
-      if (mExposureTime < kMinExposureTime) mExposureTime = kMinExposureTime;
-    }
-  }
-
-  return aeState;
-}
-
-void EmulatedFakeCamera2::ControlThread::updateAeState(uint8_t newState,
-                                                       int32_t triggerId) {
-  Mutex::Autolock lock(mInputMutex);
-  if (mAeState != newState) {
-    ALOGV("%s: Autoexposure state now %d, id %d", __FUNCTION__, newState,
-          triggerId);
-    mAeState = newState;
-    mParent->sendNotification(CAMERA2_MSG_AUTOEXPOSURE, newState, triggerId, 0);
-  }
-}
-
-/** Private methods */
-
-status_t EmulatedFakeCamera2::constructStaticInfo(camera_metadata_t **info,
-                                                  bool sizeRequest) const {
-  size_t entryCount = 0;
-  size_t dataCount = 0;
-  status_t ret;
-
-#define ADD_OR_SIZE(tag, data, count)                                          \
-  if ((ret = addOrSize(*info, sizeRequest, &entryCount, &dataCount, tag, data, \
-                       count)) != OK)                                          \
-  return ret
-
-  // android.lens
-
-  // 5 cm min focus distance for back camera, infinity (fixed focus) for front
-  const float minFocusDistance = mFacingBack ? 1.0 / 0.05 : 0.0;
-  ADD_OR_SIZE(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, &minFocusDistance, 1);
-  // 5 m hyperfocal distance for back camera, infinity (fixed focus) for front
-  // const float hyperFocalDistance = mFacingBack ? 1.0 / 5.0 : 0.0;
-  ADD_OR_SIZE(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, &minFocusDistance, 1);
-
-  static const float focalLength = 3.30f;  // mm
-  ADD_OR_SIZE(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &focalLength, 1);
-  static const float aperture = 2.8f;
-  ADD_OR_SIZE(ANDROID_LENS_INFO_AVAILABLE_APERTURES, &aperture, 1);
-  static const float filterDensity = 0;
-  ADD_OR_SIZE(ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES, &filterDensity, 1);
-  static const uint8_t availableOpticalStabilization =
-      ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
-              &availableOpticalStabilization, 1);
-
-  static const int32_t lensShadingMapSize[] = {1, 1};
-  ADD_OR_SIZE(ANDROID_LENS_INFO_SHADING_MAP_SIZE, lensShadingMapSize,
-              sizeof(lensShadingMapSize) / sizeof(int32_t));
-
-  int32_t lensFacing =
-      mFacingBack ? ANDROID_LENS_FACING_BACK : ANDROID_LENS_FACING_FRONT;
-  ADD_OR_SIZE(ANDROID_LENS_FACING, &lensFacing, 1);
-
-  // android.sensor
-
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
-              Sensor::kExposureTimeRange, 2);
-
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
-              &Sensor::kFrameDurationRange[1], 1);
-
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE, Sensor::kSensitivityRange,
-              sizeof(Sensor::kSensitivityRange) / sizeof(int32_t));
-
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
-              &Sensor::kColorFilterArrangement, 1);
-
-  static const float sensorPhysicalSize[2] = {3.20f, 2.40f};  // mm
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, sensorPhysicalSize, 2);
-
-  const int32_t pixelArray[] = {mSensorWidth, mSensorHeight};
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArray, 2);
-
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, pixelArray, 2);
-
-  ADD_OR_SIZE(ANDROID_SENSOR_INFO_WHITE_LEVEL, &Sensor::kMaxRawValue, 1);
-
-  static const int32_t blackLevelPattern[4] = {
-      static_cast<int32_t>(Sensor::kBlackLevel),
-      static_cast<int32_t>(Sensor::kBlackLevel),
-      static_cast<int32_t>(Sensor::kBlackLevel),
-      static_cast<int32_t>(Sensor::kBlackLevel)};
-  ADD_OR_SIZE(ANDROID_SENSOR_BLACK_LEVEL_PATTERN, blackLevelPattern,
-              sizeof(blackLevelPattern) / sizeof(int32_t));
-
-  // TODO: sensor color calibration fields
-
-  // android.flash
-  static const uint8_t flashAvailable = 0;
-  ADD_OR_SIZE(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1);
-
-  static const int64_t flashChargeDuration = 0;
-  ADD_OR_SIZE(ANDROID_FLASH_INFO_CHARGE_DURATION, &flashChargeDuration, 1);
-
-  // android.tonemap
-
-  static const int32_t tonemapCurvePoints = 128;
-  ADD_OR_SIZE(ANDROID_TONEMAP_MAX_CURVE_POINTS, &tonemapCurvePoints, 1);
-
-  // android.scaler
-
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_FORMATS, kAvailableFormats,
-              sizeof(kAvailableFormats) / sizeof(uint32_t));
-
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_RAW_SIZES, &mAvailableRawSizes.front(),
-              mAvailableRawSizes.size());
-
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
-              kAvailableRawMinDurations,
-              sizeof(kAvailableRawMinDurations) / sizeof(uint64_t));
-
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
-              &mAvailableProcessedSizes.front(),
-              mAvailableProcessedSizes.size());
-
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
-              kAvailableProcessedMinDurations,
-              sizeof(kAvailableProcessedMinDurations) / sizeof(uint64_t));
-
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, &mAvailableJpegSizes.front(),
-              mAvailableJpegSizes.size());
-
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
-              kAvailableJpegMinDurations,
-              sizeof(kAvailableJpegMinDurations) / sizeof(uint64_t));
-
-  static const float maxZoom = 10;
-  ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &maxZoom, 1);
-
-  // android.jpeg
-
-  static const int32_t jpegThumbnailSizes[] = {0, 0, 160, 120, 320, 240};
-  ADD_OR_SIZE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegThumbnailSizes,
-              sizeof(jpegThumbnailSizes) / sizeof(int32_t));
-
-  static const int32_t jpegMaxSize = JpegCompressor::kMaxJpegSize;
-  ADD_OR_SIZE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
-
-  // android.stats
-
-  static const uint8_t availableFaceDetectModes[] = {
-      ANDROID_STATISTICS_FACE_DETECT_MODE_OFF,
-      ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE,
-      ANDROID_STATISTICS_FACE_DETECT_MODE_FULL};
-
-  ADD_OR_SIZE(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
-              availableFaceDetectModes, sizeof(availableFaceDetectModes));
-
-  static const int32_t maxFaceCount = 8;
-  ADD_OR_SIZE(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1);
-
-  static const int32_t histogramSize = 64;
-  ADD_OR_SIZE(ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT, &histogramSize,
-              1);
-
-  static const int32_t maxHistogramCount = 1000;
-  ADD_OR_SIZE(ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT, &maxHistogramCount,
-              1);
-
-  static const int32_t sharpnessMapSize[2] = {64, 64};
-  ADD_OR_SIZE(ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE, sharpnessMapSize,
-              sizeof(sharpnessMapSize) / sizeof(int32_t));
-
-  static const int32_t maxSharpnessMapValue = 1000;
-  ADD_OR_SIZE(ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
-              &maxSharpnessMapValue, 1);
-
-  // android.control
-
-  static const uint8_t availableSceneModes[] = {
-    ANDROID_CONTROL_SCENE_MODE_DISABLED
-  };
-  ADD_OR_SIZE(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, availableSceneModes,
-              sizeof(availableSceneModes));
-
-  static const uint8_t availableEffects[] = {ANDROID_CONTROL_EFFECT_MODE_OFF};
-  ADD_OR_SIZE(ANDROID_CONTROL_AVAILABLE_EFFECTS, availableEffects,
-              sizeof(availableEffects));
-
-  static const int32_t max3aRegions[] = {/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0};
-  ADD_OR_SIZE(ANDROID_CONTROL_MAX_REGIONS, max3aRegions,
-              sizeof(max3aRegions) / sizeof(max3aRegions[0]));
-
-  static const uint8_t availableAeModes[] = {ANDROID_CONTROL_AE_MODE_OFF,
-                                             ANDROID_CONTROL_AE_MODE_ON};
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_MODES, availableAeModes,
-              sizeof(availableAeModes));
-
-  static const camera_metadata_rational exposureCompensationStep = {1, 3};
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_COMPENSATION_STEP, &exposureCompensationStep,
-              1);
-
-  int32_t exposureCompensationRange[] = {-9, 9};
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_COMPENSATION_RANGE, exposureCompensationRange,
-              sizeof(exposureCompensationRange) / sizeof(int32_t));
-
-  static const int32_t availableTargetFpsRanges[] = {5, 30, 15, 30};
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
-              availableTargetFpsRanges,
-              sizeof(availableTargetFpsRanges) / sizeof(int32_t));
-
-  static const uint8_t availableAntibandingModes[] = {
-      ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
-      ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO};
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
-              availableAntibandingModes, sizeof(availableAntibandingModes));
-
-  static const uint8_t availableAwbModes[] = {
-      ANDROID_CONTROL_AWB_MODE_OFF,
-      ANDROID_CONTROL_AWB_MODE_AUTO,
-      ANDROID_CONTROL_AWB_MODE_INCANDESCENT,
-      ANDROID_CONTROL_AWB_MODE_FLUORESCENT,
-      ANDROID_CONTROL_AWB_MODE_DAYLIGHT,
-      ANDROID_CONTROL_AWB_MODE_SHADE};
-  ADD_OR_SIZE(ANDROID_CONTROL_AWB_AVAILABLE_MODES, availableAwbModes,
-              sizeof(availableAwbModes));
-
-  static const uint8_t availableAfModesBack[] = {
-      ANDROID_CONTROL_AF_MODE_OFF, ANDROID_CONTROL_AF_MODE_AUTO,
-      ANDROID_CONTROL_AF_MODE_MACRO, ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
-      ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE};
-
-  static const uint8_t availableAfModesFront[] = {ANDROID_CONTROL_AF_MODE_OFF};
-
-  if (mFacingBack) {
-    ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModesBack,
-                sizeof(availableAfModesBack));
-  } else {
-    ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModesFront,
-                sizeof(availableAfModesFront));
-  }
-
-  static const uint8_t availableVstabModes[] = {
-      ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF};
-  ADD_OR_SIZE(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
-              availableVstabModes, sizeof(availableVstabModes));
-
-#undef ADD_OR_SIZE
-  /** Allocate metadata if sizing */
-  if (sizeRequest) {
-    ALOGV(
-        "Allocating %zu entries, %zu extra bytes for "
-        "static camera info",
-        entryCount, dataCount);
-    *info = allocate_camera_metadata(entryCount, dataCount);
-    if (*info == NULL) {
-      ALOGE(
-          "Unable to allocate camera static info"
-          "(%zu entries, %zu bytes extra data)",
-          entryCount, dataCount);
-      return NO_MEMORY;
-    }
-  }
-  return OK;
-}
-
-status_t EmulatedFakeCamera2::constructDefaultRequest(
-    int request_template, camera_metadata_t **request, bool sizeRequest) const {
-  size_t entryCount = 0;
-  size_t dataCount = 0;
-  status_t ret;
-
-#define ADD_OR_SIZE(tag, data, count)                                       \
-  if ((ret = addOrSize(*request, sizeRequest, &entryCount, &dataCount, tag, \
-                       data, count)) != OK)                                 \
-  return ret
-
-  /** android.request */
-
-  static const uint8_t requestType = ANDROID_REQUEST_TYPE_CAPTURE;
-  ADD_OR_SIZE(ANDROID_REQUEST_TYPE, &requestType, 1);
-
-  static const uint8_t metadataMode = ANDROID_REQUEST_METADATA_MODE_FULL;
-  ADD_OR_SIZE(ANDROID_REQUEST_METADATA_MODE, &metadataMode, 1);
-
-  static const int32_t id = 0;
-  ADD_OR_SIZE(ANDROID_REQUEST_ID, &id, 1);
-
-  static const int32_t frameCount = 0;
-  ADD_OR_SIZE(ANDROID_REQUEST_FRAME_COUNT, &frameCount, 1);
-
-  // OUTPUT_STREAMS set by user
-  entryCount += 1;
-  dataCount += 5;  // TODO: Should be maximum stream number
-
-  /** android.lens */
-
-  static const float focusDistance = 0;
-  ADD_OR_SIZE(ANDROID_LENS_FOCUS_DISTANCE, &focusDistance, 1);
-
-  static const float aperture = 2.8f;
-  ADD_OR_SIZE(ANDROID_LENS_APERTURE, &aperture, 1);
-
-  static const float focalLength = 5.0f;
-  ADD_OR_SIZE(ANDROID_LENS_FOCAL_LENGTH, &focalLength, 1);
-
-  static const float filterDensity = 0;
-  ADD_OR_SIZE(ANDROID_LENS_FILTER_DENSITY, &filterDensity, 1);
-
-  static const uint8_t opticalStabilizationMode =
-      ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
-              &opticalStabilizationMode, 1);
-
-  // FOCUS_RANGE set only in frame
-
-  /** android.sensor */
-
-  static const int64_t exposureTime = 10 * MSEC;
-  ADD_OR_SIZE(ANDROID_SENSOR_EXPOSURE_TIME, &exposureTime, 1);
-
-  static const int64_t frameDuration = 33333333L;  // 1/30 s
-  ADD_OR_SIZE(ANDROID_SENSOR_FRAME_DURATION, &frameDuration, 1);
-
-  static const int32_t sensitivity = 100;
-  ADD_OR_SIZE(ANDROID_SENSOR_SENSITIVITY, &sensitivity, 1);
-
-  // TIMESTAMP set only in frame
-
-  /** android.flash */
-
-  static const uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_FLASH_MODE, &flashMode, 1);
-
-  static const uint8_t flashPower = 10;
-  ADD_OR_SIZE(ANDROID_FLASH_FIRING_POWER, &flashPower, 1);
-
-  static const int64_t firingTime = 0;
-  ADD_OR_SIZE(ANDROID_FLASH_FIRING_TIME, &firingTime, 1);
-
-  /** Processing block modes */
-  uint8_t hotPixelMode = 0;
-  uint8_t demosaicMode = 0;
-  uint8_t noiseMode = 0;
-  uint8_t shadingMode = 0;
-  uint8_t colorMode = 0;
-  uint8_t tonemapMode = 0;
-  uint8_t edgeMode = 0;
-  switch (request_template) {
-    case CAMERA2_TEMPLATE_STILL_CAPTURE:
-      // fall-through
-    case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
-      // fall-through
-    case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
-      hotPixelMode = ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY;
-      demosaicMode = ANDROID_DEMOSAIC_MODE_HIGH_QUALITY;
-      noiseMode = ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY;
-      shadingMode = ANDROID_SHADING_MODE_HIGH_QUALITY;
-      colorMode = ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY;
-      tonemapMode = ANDROID_TONEMAP_MODE_HIGH_QUALITY;
-      edgeMode = ANDROID_EDGE_MODE_HIGH_QUALITY;
-      break;
-    case CAMERA2_TEMPLATE_PREVIEW:
-      // fall-through
-    case CAMERA2_TEMPLATE_VIDEO_RECORD:
-      // fall-through
-    default:
-      hotPixelMode = ANDROID_HOT_PIXEL_MODE_FAST;
-      demosaicMode = ANDROID_DEMOSAIC_MODE_FAST;
-      noiseMode = ANDROID_NOISE_REDUCTION_MODE_FAST;
-      shadingMode = ANDROID_SHADING_MODE_FAST;
-      colorMode = ANDROID_COLOR_CORRECTION_MODE_FAST;
-      tonemapMode = ANDROID_TONEMAP_MODE_FAST;
-      edgeMode = ANDROID_EDGE_MODE_FAST;
-      break;
-  }
-  ADD_OR_SIZE(ANDROID_HOT_PIXEL_MODE, &hotPixelMode, 1);
-  ADD_OR_SIZE(ANDROID_DEMOSAIC_MODE, &demosaicMode, 1);
-  ADD_OR_SIZE(ANDROID_NOISE_REDUCTION_MODE, &noiseMode, 1);
-  ADD_OR_SIZE(ANDROID_SHADING_MODE, &shadingMode, 1);
-  ADD_OR_SIZE(ANDROID_COLOR_CORRECTION_MODE, &colorMode, 1);
-  ADD_OR_SIZE(ANDROID_TONEMAP_MODE, &tonemapMode, 1);
-  ADD_OR_SIZE(ANDROID_EDGE_MODE, &edgeMode, 1);
-
-  /** android.noise */
-  static const uint8_t noiseStrength = 5;
-  ADD_OR_SIZE(ANDROID_NOISE_REDUCTION_STRENGTH, &noiseStrength, 1);
-
-  /** android.color */
-  static const float colorTransform[9] = {1.0f, 0.f, 0.f, 0.f, 1.f,
-                                          0.f,  0.f, 0.f, 1.f};
-  ADD_OR_SIZE(ANDROID_COLOR_CORRECTION_TRANSFORM, colorTransform, 9);
-
-  /** android.tonemap */
-  static const float tonemapCurve[4] = {0.f, 0.f, 1.f, 1.f};
-  ADD_OR_SIZE(ANDROID_TONEMAP_CURVE_RED, tonemapCurve, 4);
-  ADD_OR_SIZE(ANDROID_TONEMAP_CURVE_GREEN, tonemapCurve, 4);
-  ADD_OR_SIZE(ANDROID_TONEMAP_CURVE_BLUE, tonemapCurve, 4);
-
-  /** android.edge */
-  static const uint8_t edgeStrength = 5;
-  ADD_OR_SIZE(ANDROID_EDGE_STRENGTH, &edgeStrength, 1);
-
-  /** android.scaler */
-  static const int32_t cropRegion[3] = {0, 0,
-                                        static_cast<int32_t>(mSensorWidth)};
-  ADD_OR_SIZE(ANDROID_SCALER_CROP_REGION, cropRegion, 3);
-
-  /** android.jpeg */
-  static const int32_t jpegQuality = 80;
-  ADD_OR_SIZE(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
-
-  static const int32_t thumbnailSize[2] = {640, 480};
-  ADD_OR_SIZE(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
-
-  static const int32_t thumbnailQuality = 80;
-  ADD_OR_SIZE(ANDROID_JPEG_THUMBNAIL_QUALITY, &thumbnailQuality, 1);
-
-  static const double gpsCoordinates[2] = {0, 0};
-  ADD_OR_SIZE(ANDROID_JPEG_GPS_COORDINATES, gpsCoordinates, 2);
-
-  static const uint8_t gpsProcessingMethod[32] = "None";
-  ADD_OR_SIZE(ANDROID_JPEG_GPS_PROCESSING_METHOD, gpsProcessingMethod, 32);
-
-  static const int64_t gpsTimestamp = 0;
-  ADD_OR_SIZE(ANDROID_JPEG_GPS_TIMESTAMP, &gpsTimestamp, 1);
-
-  static const int32_t jpegOrientation = 0;
-  ADD_OR_SIZE(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
-
-  /** android.stats */
-
-  static const uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_STATISTICS_FACE_DETECT_MODE, &faceDetectMode, 1);
-
-  static const uint8_t histogramMode = ANDROID_STATISTICS_HISTOGRAM_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_STATISTICS_HISTOGRAM_MODE, &histogramMode, 1);
-
-  static const uint8_t sharpnessMapMode =
-      ANDROID_STATISTICS_SHARPNESS_MAP_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_STATISTICS_SHARPNESS_MAP_MODE, &sharpnessMapMode, 1);
-
-  // faceRectangles, faceScores, faceLandmarks, faceIds, histogram,
-  // sharpnessMap only in frames
-
-  /** android.control */
-
-  uint8_t controlIntent = 0;
-  switch (request_template) {
-    case CAMERA2_TEMPLATE_PREVIEW:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
-      break;
-    case CAMERA2_TEMPLATE_STILL_CAPTURE:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
-      break;
-    case CAMERA2_TEMPLATE_VIDEO_RECORD:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
-      break;
-    case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
-      break;
-    case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
-      break;
-    default:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM;
-      break;
-  }
-  ADD_OR_SIZE(ANDROID_CONTROL_CAPTURE_INTENT, &controlIntent, 1);
-
-  static const uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;
-  ADD_OR_SIZE(ANDROID_CONTROL_MODE, &controlMode, 1);
-
-  static const uint8_t effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1);
-
-  static const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
-  ADD_OR_SIZE(ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1);
-
-  static const uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH;
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
-
-  static const uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_LOCK, &aeLock, 1);
-
-  static const int32_t controlRegions[5] = {
-      0, 0, static_cast<int32_t>(mSensorWidth),
-      static_cast<int32_t>(mSensorHeight), 1000};
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_REGIONS, controlRegions, 5);
-
-  static const int32_t aeExpCompensation = 0;
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &aeExpCompensation, 1);
-
-  static const int32_t aeTargetFpsRange[2] = {10, 30};
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, aeTargetFpsRange, 2);
-
-  static const uint8_t aeAntibandingMode =
-      ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
-  ADD_OR_SIZE(ANDROID_CONTROL_AE_ANTIBANDING_MODE, &aeAntibandingMode, 1);
-
-  static const uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
-  ADD_OR_SIZE(ANDROID_CONTROL_AWB_MODE, &awbMode, 1);
-
-  static const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
-  ADD_OR_SIZE(ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
-  ADD_OR_SIZE(ANDROID_CONTROL_AWB_REGIONS, controlRegions, 5);
-
-  uint8_t afMode = 0;
-  switch (request_template) {
-    case CAMERA2_TEMPLATE_PREVIEW:
-      afMode = ANDROID_CONTROL_AF_MODE_AUTO;
-      break;
-    case CAMERA2_TEMPLATE_STILL_CAPTURE:
-      afMode = ANDROID_CONTROL_AF_MODE_AUTO;
-      break;
-    case CAMERA2_TEMPLATE_VIDEO_RECORD:
-      afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
-      break;
-    case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
-      afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
-      break;
-    case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
-      afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
-      break;
-    default:
-      afMode = ANDROID_CONTROL_AF_MODE_AUTO;
-      break;
-  }
-  ADD_OR_SIZE(ANDROID_CONTROL_AF_MODE, &afMode, 1);
-
-  ADD_OR_SIZE(ANDROID_CONTROL_AF_REGIONS, controlRegions, 5);
-
-  static const uint8_t vstabMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
-  ADD_OR_SIZE(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &vstabMode, 1);
-
-  // aeState, awbState, afState only in frame
-
-  /** Allocate metadata if sizing */
-  if (sizeRequest) {
-    ALOGV(
-        "Allocating %zu entries, %zu extra bytes for "
-        "request template type %d",
-        entryCount, dataCount, request_template);
-    *request = allocate_camera_metadata(entryCount, dataCount);
-    if (*request == NULL) {
-      ALOGE(
-          "Unable to allocate new request template type %d "
-          "(%zu entries, %zu bytes extra data)",
-          request_template, entryCount, dataCount);
-      return NO_MEMORY;
-    }
-  }
-  return OK;
-#undef ADD_OR_SIZE
-}
-
-status_t EmulatedFakeCamera2::addOrSize(camera_metadata_t *request,
-                                        bool sizeRequest, size_t *entryCount,
-                                        size_t *dataCount, uint32_t tag,
-                                        const void *entryData,
-                                        size_t entryDataCount) {
-  if (!sizeRequest) {
-    return add_camera_metadata_entry(request, tag, entryData, entryDataCount);
-  } else {
-    int type = get_camera_metadata_tag_type(tag);
-    if (type < 0) return BAD_VALUE;
-    (*entryCount)++;
-    (*dataCount) +=
-        calculate_camera_metadata_entry_data_size(type, entryDataCount);
-    return OK;
-  }
-}
-
-bool EmulatedFakeCamera2::isStreamInUse(uint32_t id) {
-  // Assumes mMutex is locked; otherwise new requests could enter
-  // configureThread while readoutThread is being checked
-
-  // Order of isStreamInUse calls matters
-  if (mConfigureThread->isStreamInUse(id) ||
-      mReadoutThread->isStreamInUse(id) || mJpegCompressor->isStreamInUse(id)) {
-    ALOGE("%s: Stream %d is in use in active requests!", __FUNCTION__, id);
-    return true;
-  }
-  return false;
-}
-
-bool EmulatedFakeCamera2::isReprocessStreamInUse(uint32_t /*id*/) {
-  // TODO: implement
-  return false;
-}
-
-const Stream &EmulatedFakeCamera2::getStreamInfo(uint32_t streamId) {
-  Mutex::Autolock lock(mMutex);
-
-  return mStreams.valueFor(streamId);
-}
-
-const ReprocessStream &EmulatedFakeCamera2::getReprocessStreamInfo(
-    uint32_t streamId) {
-  Mutex::Autolock lock(mMutex);
-
-  return mReprocessStreams.valueFor(streamId);
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedFakeCamera2.h b/guest/hals/camera/EmulatedFakeCamera2.h
deleted file mode 100644
index b55d012..0000000
--- a/guest/hals/camera/EmulatedFakeCamera2.h
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA2_H
-#define HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA2_H
-
-/*
- * Contains declaration of a class EmulatedFakeCamera2 that encapsulates
- * functionality of a fake camera that implements version 2 of the camera device
- * interface.
- */
-
-#include <vector>
-
-#include <utils/Condition.h>
-#include <utils/KeyedVector.h>
-#include <utils/String16.h>
-#include <utils/String8.h>
-#include "EmulatedCamera2.h"
-#include "fake-pipeline2/Base.h"
-#include "fake-pipeline2/JpegCompressor.h"
-#include "fake-pipeline2/Sensor.h"
-
-namespace android {
-
-/* Encapsulates functionality of an advanced fake camera.  This camera contains
- * a simple simulation of a scene, sensor, and image processing pipeline.
- */
-class EmulatedFakeCamera2 : public EmulatedCamera2 {
- public:
-  /* Constructs EmulatedFakeCamera instance. */
-  EmulatedFakeCamera2(int cameraId, bool facingBack,
-                      struct hw_module_t *module);
-
-  /* Destructs EmulatedFakeCamera instance. */
-  ~EmulatedFakeCamera2();
-
-  /****************************************************************************
-   * EmulatedCamera2 virtual overrides.
-   ***************************************************************************/
-
- public:
-  /* Initializes EmulatedFakeCamera2 instance. */
-  status_t Initialize(const cvd::CameraDefinition &props);
-
-  /****************************************************************************
-   * Camera Module API and generic hardware device API implementation
-   ***************************************************************************/
- public:
-  virtual status_t connectCamera(hw_device_t **device);
-
-  virtual status_t plugCamera();
-  virtual status_t unplugCamera();
-  virtual camera_device_status_t getHotplugStatus();
-
-  virtual status_t closeCamera();
-
-  virtual status_t getCameraInfo(struct camera_info *info);
-
-  /****************************************************************************
-   * EmulatedCamera2 abstract API implementation.
-   ***************************************************************************/
- protected:
-  /** Request input queue */
-
-  virtual int requestQueueNotify();
-
-  /** Count of requests in flight */
-  virtual int getInProgressCount();
-
-  /** Cancel all captures in flight */
-  // virtual int flushCapturesInProgress();
-
-  /** Construct default request */
-  virtual int constructDefaultRequest(int request_template,
-                                      camera_metadata_t **request);
-
-  virtual int allocateStream(uint32_t width, uint32_t height, int format,
-                             const camera2_stream_ops_t *stream_ops,
-                             uint32_t *stream_id, uint32_t *format_actual,
-                             uint32_t *usage, uint32_t *max_buffers);
-
-  virtual int registerStreamBuffers(uint32_t stream_id, int num_buffers,
-                                    buffer_handle_t *buffers);
-
-  virtual int releaseStream(uint32_t stream_id);
-
-  // virtual int allocateReprocessStream(
-  //         uint32_t width,
-  //         uint32_t height,
-  //         uint32_t format,
-  //         const camera2_stream_ops_t *stream_ops,
-  //         uint32_t *stream_id,
-  //         uint32_t *format_actual,
-  //         uint32_t *usage,
-  //         uint32_t *max_buffers);
-
-  virtual int allocateReprocessStreamFromStream(
-      uint32_t output_stream_id, const camera2_stream_in_ops_t *stream_ops,
-      uint32_t *stream_id);
-
-  virtual int releaseReprocessStream(uint32_t stream_id);
-
-  virtual int triggerAction(uint32_t trigger_id, int32_t ext1, int32_t ext2);
-
-  /** Debug methods */
-
-  virtual int dump(int fd);
-
- public:
-  /****************************************************************************
-   * Utility methods called by configure/readout threads and pipeline
-   ***************************************************************************/
-
-  // Get information about a given stream. Will lock mMutex
-  const Stream &getStreamInfo(uint32_t streamId);
-  const ReprocessStream &getReprocessStreamInfo(uint32_t streamId);
-
-  // Notifies rest of camera subsystem of serious error
-  void signalError();
-
- private:
-  /****************************************************************************
-   * Utility methods
-   ***************************************************************************/
-  /** Construct static camera metadata, two-pass */
-  status_t constructStaticInfo(camera_metadata_t **info,
-                               bool sizeRequest) const;
-
-  /** Two-pass implementation of constructDefaultRequest */
-  status_t constructDefaultRequest(int request_template,
-                                   camera_metadata_t **request,
-                                   bool sizeRequest) const;
-  /** Helper function for constructDefaultRequest */
-  static status_t addOrSize(camera_metadata_t *request, bool sizeRequest,
-                            size_t *entryCount, size_t *dataCount, uint32_t tag,
-                            const void *entry_data, size_t entry_count);
-
-  /** Determine if the stream id is listed in any currently-in-flight
-   * requests. Assumes mMutex is locked */
-  bool isStreamInUse(uint32_t streamId);
-
-  /** Determine if the reprocess stream id is listed in any
-   * currently-in-flight requests. Assumes mMutex is locked */
-  bool isReprocessStreamInUse(uint32_t streamId);
-
-  /****************************************************************************
-   * Pipeline controller threads
-   ***************************************************************************/
-
-  class ConfigureThread : public Thread {
-   public:
-    ConfigureThread(EmulatedFakeCamera2 *parent);
-    ~ConfigureThread();
-
-    status_t waitUntilRunning();
-    status_t newRequestAvailable();
-    status_t readyToRun();
-
-    bool isStreamInUse(uint32_t id);
-    int getInProgressCount();
-
-   private:
-    EmulatedFakeCamera2 *mParent;
-    static const nsecs_t kWaitPerLoop = 10000000L;  // 10 ms
-
-    bool mRunning;
-    bool threadLoop();
-
-    bool setupCapture();
-    bool setupReprocess();
-
-    bool configureNextCapture();
-    bool configureNextReprocess();
-
-    bool getBuffers();
-
-    Mutex mInputMutex;  // Protects mActive, mRequestCount
-    Condition mInputSignal;
-    bool mActive;  // Whether we're waiting for input requests or actively
-                   // working on them
-    size_t mRequestCount;
-
-    camera_metadata_t *mRequest;
-
-    Mutex mInternalsMutex;  // Lock before accessing below members.
-    bool mWaitingForReadout;
-    bool mNextNeedsJpeg;
-    bool mNextIsCapture;
-    int32_t mNextFrameNumber;
-    int64_t mNextExposureTime;
-    int64_t mNextFrameDuration;
-    int32_t mNextSensitivity;
-    Buffers *mNextBuffers;
-  };
-
-  class ReadoutThread : public Thread, private JpegCompressor::JpegListener {
-   public:
-    ReadoutThread(EmulatedFakeCamera2 *parent);
-    ~ReadoutThread();
-
-    status_t readyToRun();
-
-    // Input
-    status_t waitUntilRunning();
-    bool waitForReady(nsecs_t timeout);
-    void setNextOperation(bool isCapture, camera_metadata_t *request,
-                          Buffers *buffers);
-    bool isStreamInUse(uint32_t id);
-    int getInProgressCount();
-
-   private:
-    EmulatedFakeCamera2 *mParent;
-
-    bool mRunning;
-    bool threadLoop();
-
-    bool readyForNextCapture();
-    status_t collectStatisticsMetadata(camera_metadata_t *frame);
-
-    // Inputs
-    Mutex mInputMutex;  // Protects mActive, mInFlightQueue, mRequestCount
-    Condition mInputSignal;
-    Condition mReadySignal;
-
-    bool mActive;
-
-    static const int kInFlightQueueSize = 4;
-    struct InFlightQueue {
-      bool isCapture;
-      camera_metadata_t *request;
-      Buffers *buffers;
-    } * mInFlightQueue;
-
-    size_t mInFlightHead;
-    size_t mInFlightTail;
-
-    size_t mRequestCount;
-
-    // Internals
-    Mutex mInternalsMutex;
-
-    bool mIsCapture;
-    camera_metadata_t *mRequest;
-    Buffers *mBuffers;
-
-    // Jpeg completion listeners
-    void onJpegDone(const StreamBuffer &jpegBuffer, bool success);
-    void onJpegInputDone(const StreamBuffer &inputBuffer);
-    nsecs_t mJpegTimestamp;
-  };
-
-  // 3A management thread (auto-exposure, focus, white balance)
-  class ControlThread : public Thread {
-   public:
-    ControlThread(EmulatedFakeCamera2 *parent);
-    ~ControlThread();
-
-    status_t readyToRun();
-
-    status_t waitUntilRunning();
-
-    // Interpret request's control parameters and override
-    // capture settings as needed
-    status_t processRequest(camera_metadata_t *request);
-
-    status_t triggerAction(uint32_t msgType, int32_t ext1, int32_t ext2);
-
-   private:
-    ControlThread(const ControlThread &t);
-    ControlThread &operator=(const ControlThread &t);
-
-    // Constants controlling fake 3A behavior
-    static const nsecs_t kControlCycleDelay;
-    static const nsecs_t kMinAfDuration;
-    static const nsecs_t kMaxAfDuration;
-    static const float kAfSuccessRate;
-    static const float kContinuousAfStartRate;
-
-    static const float kAeScanStartRate;
-    static const nsecs_t kMinAeDuration;
-    static const nsecs_t kMaxAeDuration;
-    static const nsecs_t kMinPrecaptureAeDuration;
-    static const nsecs_t kMaxPrecaptureAeDuration;
-
-    static const nsecs_t kNormalExposureTime;
-    static const nsecs_t kExposureJump;
-    static const nsecs_t kMinExposureTime;
-
-    EmulatedFakeCamera2 *mParent;
-
-    bool mRunning;
-    bool threadLoop();
-
-    Mutex mInputMutex;  // Protects input methods
-    Condition mInputSignal;
-
-    // Trigger notifications
-    bool mStartAf;
-    bool mCancelAf;
-    bool mStartPrecapture;
-
-    // Latest state for 3A request fields
-    uint8_t mControlMode;
-
-    uint8_t mEffectMode;
-    uint8_t mSceneMode;
-
-    uint8_t mAfMode;
-    bool mAfModeChange;
-
-    uint8_t mAwbMode;
-    uint8_t mAeMode;
-
-    // Latest trigger IDs
-    int32_t mAfTriggerId;
-    int32_t mPrecaptureTriggerId;
-
-    // Current state for 3A algorithms
-    uint8_t mAfState;
-    uint8_t mAeState;
-    uint8_t mAwbState;
-    bool mAeLock;
-
-    // Current control parameters
-    nsecs_t mExposureTime;
-
-    // Private to threadLoop and its utility methods
-
-    nsecs_t mAfScanDuration;
-    nsecs_t mAeScanDuration;
-    bool mLockAfterPassiveScan;
-
-    // Utility methods for AF
-    int processAfTrigger(uint8_t afMode, uint8_t afState);
-    int maybeStartAfScan(uint8_t afMode, uint8_t afState);
-    int updateAfScan(uint8_t afMode, uint8_t afState, nsecs_t *maxSleep);
-    void updateAfState(uint8_t newState, int32_t triggerId);
-
-    // Utility methods for precapture trigger
-    int processPrecaptureTrigger(uint8_t aeMode, uint8_t aeState);
-    int maybeStartAeScan(uint8_t aeMode, bool aeLock, uint8_t aeState);
-    int updateAeScan(uint8_t aeMode, bool aeLock, uint8_t aeState,
-                     nsecs_t *maxSleep);
-    void updateAeState(uint8_t newState, int32_t triggerId);
-  };
-
-  /****************************************************************************
-   * Static configuration information
-   ***************************************************************************/
- private:
-  static const uint32_t kMaxRawStreamCount = 1;
-  static const uint32_t kMaxProcessedStreamCount = 3;
-  static const uint32_t kMaxJpegStreamCount = 1;
-  static const uint32_t kMaxReprocessStreamCount = 2;
-  static const uint32_t kMaxBufferCount = 4;
-  static const uint32_t kAvailableFormats[];
-  static const uint32_t kAvailableRawSizes[];
-  static const uint64_t kAvailableRawMinDurations[];
-  static const uint32_t kAvailableProcessedSizesBack[];
-  static const uint32_t kAvailableProcessedSizesFront[];
-  static const uint64_t kAvailableProcessedMinDurations[];
-  static const uint32_t kAvailableJpegSizesBack[];
-  static const uint32_t kAvailableJpegSizesFront[];
-  static const uint64_t kAvailableJpegMinDurations[];
-
-  /****************************************************************************
-   * Data members.
-   ***************************************************************************/
-
- protected:
-  /* Facing back (true) or front (false) switch. */
-  bool mFacingBack;
-
- private:
-  bool mIsConnected;
-
-  int32_t mSensorWidth, mSensorHeight;
-
-  /** Stream manipulation */
-  uint32_t mNextStreamId;
-  uint32_t mRawStreamCount;
-  uint32_t mProcessedStreamCount;
-  uint32_t mJpegStreamCount;
-
-  std::vector<uint32_t> mAvailableRawSizes;
-  std::vector<uint32_t> mAvailableProcessedSizes;
-  std::vector<uint32_t> mAvailableJpegSizes;
-
-  uint32_t mNextReprocessStreamId;
-  uint32_t mReprocessStreamCount;
-
-  KeyedVector<uint32_t, Stream> mStreams;
-  KeyedVector<uint32_t, ReprocessStream> mReprocessStreams;
-
-  /** Simulated hardware interfaces */
-  sp<Sensor> mSensor;
-  sp<JpegCompressor> mJpegCompressor;
-
-  /** Pipeline control threads */
-  sp<ConfigureThread> mConfigureThread;
-  sp<ReadoutThread> mReadoutThread;
-  sp<ControlThread> mControlThread;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA2_H */
diff --git a/guest/hals/camera/EmulatedFakeCamera3.cpp b/guest/hals/camera/EmulatedFakeCamera3.cpp
deleted file mode 100644
index f9d9628..0000000
--- a/guest/hals/camera/EmulatedFakeCamera3.cpp
+++ /dev/null
@@ -1,2661 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-/*
- * Contains implementation of a class EmulatedFakeCamera3 that encapsulates
- * functionality of an advanced fake camera.
- */
-
-#include <cstdint>
-#include <inttypes.h>
-
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0
-#define LOG_TAG "EmulatedCamera_FakeCamera3"
-#include <cutils/properties.h>
-#include <utils/Log.h>
-
-#include <ui/Fence.h>
-#include "EmulatedCameraFactory.h"
-#include "EmulatedFakeCamera3.h"
-#include "GrallocModule.h"
-
-#include <cmath>
-#include "fake-pipeline2/JpegCompressor.h"
-#include "fake-pipeline2/Sensor.h"
-
-#include <vector>
-
-#if defined(LOG_NNDEBUG) && LOG_NNDEBUG == 0
-#define ALOGVV ALOGV
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-namespace android {
-
-/**
- * Constants for camera capabilities
- */
-
-const int64_t USEC = 1000LL;
-const int64_t MSEC = USEC * 1000LL;
-// const int64_t SEC = MSEC * 1000LL;
-
-const int32_t EmulatedFakeCamera3::kAvailableFormats[] = {
-    HAL_PIXEL_FORMAT_RAW16, HAL_PIXEL_FORMAT_BLOB, HAL_PIXEL_FORMAT_RGBA_8888,
-    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-    // These are handled by YCbCr_420_888
-    //        HAL_PIXEL_FORMAT_YV12,
-    //        HAL_PIXEL_FORMAT_YCrCb_420_SP,
-    HAL_PIXEL_FORMAT_YCbCr_420_888, HAL_PIXEL_FORMAT_Y16};
-
-/**
- * 3A constants
- */
-
-// Default exposure and gain targets for different scenarios
-const nsecs_t EmulatedFakeCamera3::kNormalExposureTime = 10 * MSEC;
-const nsecs_t EmulatedFakeCamera3::kFacePriorityExposureTime = 30 * MSEC;
-const int EmulatedFakeCamera3::kNormalSensitivity = 100;
-const int EmulatedFakeCamera3::kFacePrioritySensitivity = 400;
-const float EmulatedFakeCamera3::kExposureTrackRate = 0.1;
-const int EmulatedFakeCamera3::kPrecaptureMinFrames = 10;
-const int EmulatedFakeCamera3::kStableAeMaxFrames = 100;
-const float EmulatedFakeCamera3::kExposureWanderMin = -2;
-const float EmulatedFakeCamera3::kExposureWanderMax = 1;
-
-/**
- * Camera device lifecycle methods
- */
-
-EmulatedFakeCamera3::EmulatedFakeCamera3(int cameraId, bool facingBack,
-                                         struct hw_module_t *module)
-    : EmulatedCamera3(cameraId, module), mFacingBack(facingBack) {
-  ALOGI("Constructing emulated fake camera 3: ID %d, facing %s", mCameraID,
-        facingBack ? "back" : "front");
-
-  for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++) {
-    mDefaultTemplates[i] = NULL;
-  }
-}
-
-EmulatedFakeCamera3::~EmulatedFakeCamera3() {
-  for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++) {
-    if (mDefaultTemplates[i] != NULL) {
-      free_camera_metadata(mDefaultTemplates[i]);
-    }
-  }
-}
-
-status_t EmulatedFakeCamera3::Initialize(const cvd::CameraDefinition &params) {
-  ALOGV("%s: E", __FUNCTION__);
-  status_t res;
-
-  if (mStatus != STATUS_ERROR) {
-    ALOGE("%s: Already initialized!", __FUNCTION__);
-    return INVALID_OPERATION;
-  }
-
-  res = getCameraCapabilities();
-  if (res != OK) {
-    ALOGE("%s: Unable to get camera capabilities: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    return res;
-  }
-
-  res = constructStaticInfo(params);
-  if (res != OK) {
-    ALOGE("%s: Unable to allocate static info: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    return res;
-  }
-
-  return EmulatedCamera3::Initialize(params);
-}
-
-status_t EmulatedFakeCamera3::connectCamera(hw_device_t **device) {
-  ALOGV("%s: E", __FUNCTION__);
-  Mutex::Autolock l(mLock);
-  status_t res;
-
-  if (mStatus != STATUS_CLOSED) {
-    ALOGE("%s: Can't connect in state %d", __FUNCTION__, mStatus);
-    return INVALID_OPERATION;
-  }
-
-  mSensor = new Sensor(mSensorWidth, mSensorHeight);
-  mSensor->setSensorListener(this);
-
-  res = mSensor->startUp();
-  if (res != NO_ERROR) return res;
-
-  mReadoutThread = new ReadoutThread(this);
-  mJpegCompressor = new JpegCompressor();
-
-  res = mReadoutThread->run("EmuCam3::readoutThread");
-  if (res != NO_ERROR) return res;
-
-  // Initialize fake 3A
-
-  mControlMode = ANDROID_CONTROL_MODE_AUTO;
-  mFacePriority = false;
-  mAeMode = ANDROID_CONTROL_AE_MODE_ON;
-  mAfMode = ANDROID_CONTROL_AF_MODE_AUTO;
-  mAwbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
-  mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
-  mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
-  mAwbState = ANDROID_CONTROL_AWB_STATE_INACTIVE;
-  mAeCounter = 0;
-  mAeTargetExposureTime = kNormalExposureTime;
-  mAeCurrentExposureTime = kNormalExposureTime;
-  mAeCurrentSensitivity = kNormalSensitivity;
-
-  return EmulatedCamera3::connectCamera(device);
-}
-
-status_t EmulatedFakeCamera3::closeCamera() {
-  ALOGV("%s: E", __FUNCTION__);
-  status_t res;
-  {
-    Mutex::Autolock l(mLock);
-    if (mStatus == STATUS_CLOSED) return OK;
-
-    res = mSensor->shutDown();
-    if (res != NO_ERROR) {
-      ALOGE("%s: Unable to shut down sensor: %d", __FUNCTION__, res);
-      return res;
-    }
-    mSensor.clear();
-
-    mReadoutThread->requestExit();
-  }
-
-  mReadoutThread->join();
-
-  {
-    Mutex::Autolock l(mLock);
-    // Clear out private stream information
-    for (StreamIterator s = mStreams.begin(); s != mStreams.end(); s++) {
-      PrivateStreamInfo *privStream =
-          static_cast<PrivateStreamInfo *>((*s)->priv);
-      delete privStream;
-      (*s)->priv = NULL;
-    }
-    mStreams.clear();
-    mReadoutThread.clear();
-  }
-
-  return EmulatedCamera3::closeCamera();
-}
-
-status_t EmulatedFakeCamera3::getCameraInfo(struct camera_info *info) {
-  info->facing = mFacingBack ? CAMERA_FACING_BACK : CAMERA_FACING_FRONT;
-  info->orientation =
-      EmulatedCameraFactory::Instance().getFakeCameraOrientation();
-  info->resource_cost = 100;
-  info->conflicting_devices = NULL;
-  info->conflicting_devices_length = 0;
-  return EmulatedCamera3::getCameraInfo(info);
-}
-
-status_t EmulatedFakeCamera3::setTorchMode(bool enabled) {
-  if (!mFacingBack) {
-    ALOGE("%s: Front camera does not have flash unit", __FUNCTION__);
-    return INVALID_OPERATION;
-  }
-  EmulatedCameraFactory::Instance().onTorchModeStatusChanged(
-      mCameraID, enabled ? TORCH_MODE_STATUS_AVAILABLE_ON
-                         : TORCH_MODE_STATUS_AVAILABLE_OFF);
-  return NO_ERROR;
-}
-
-/**
- * Camera3 interface methods
- */
-
-status_t EmulatedFakeCamera3::configureStreams(
-    camera3_stream_configuration *streamList) {
-  Mutex::Autolock l(mLock);
-  ALOGV("%s: %d streams", __FUNCTION__, streamList->num_streams);
-
-  if (mStatus != STATUS_OPEN && mStatus != STATUS_READY) {
-    ALOGE("%s: Cannot configure streams in state %d", __FUNCTION__, mStatus);
-    return NO_INIT;
-  }
-
-  /**
-   * Sanity-check input list.
-   */
-  if (streamList == NULL) {
-    ALOGE("%s: NULL stream configuration", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  if (streamList->streams == NULL) {
-    ALOGE("%s: NULL stream list", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  if (streamList->num_streams < 1) {
-    ALOGE("%s: Bad number of streams requested: %d", __FUNCTION__,
-          streamList->num_streams);
-    return BAD_VALUE;
-  }
-
-  camera3_stream_t *inputStream = NULL;
-  for (size_t i = 0; i < streamList->num_streams; i++) {
-    camera3_stream_t *newStream = streamList->streams[i];
-
-    if (newStream == NULL) {
-      ALOGE("%s: Stream index %zu was NULL", __FUNCTION__, i);
-      return BAD_VALUE;
-    }
-
-    ALOGV("%s: Stream %p (id %zu), type %d, usage 0x%x, format 0x%x",
-          __FUNCTION__, newStream, i, newStream->stream_type, newStream->usage,
-          newStream->format);
-
-    if (newStream->stream_type == CAMERA3_STREAM_INPUT ||
-        newStream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL) {
-      if (inputStream != NULL) {
-        ALOGE("%s: Multiple input streams requested!", __FUNCTION__);
-        return BAD_VALUE;
-      }
-      inputStream = newStream;
-    }
-
-    bool validFormat = false;
-    for (size_t f = 0;
-         f < sizeof(kAvailableFormats) / sizeof(kAvailableFormats[0]); f++) {
-      if (newStream->format == kAvailableFormats[f]) {
-        validFormat = true;
-        break;
-      }
-    }
-    if (!validFormat) {
-      ALOGE("%s: Unsupported stream format 0x%x requested", __FUNCTION__,
-            newStream->format);
-      return BAD_VALUE;
-    }
-  }
-  mInputStream = inputStream;
-
-  /**
-   * Initially mark all existing streams as not alive
-   */
-  for (StreamIterator s = mStreams.begin(); s != mStreams.end(); ++s) {
-    PrivateStreamInfo *privStream =
-        static_cast<PrivateStreamInfo *>((*s)->priv);
-    privStream->alive = false;
-  }
-
-  /**
-   * Find new streams and mark still-alive ones
-   */
-  for (size_t i = 0; i < streamList->num_streams; i++) {
-    camera3_stream_t *newStream = streamList->streams[i];
-    if (newStream->priv == NULL) {
-      // New stream, construct info
-      PrivateStreamInfo *privStream = new PrivateStreamInfo();
-      privStream->alive = true;
-
-      newStream->max_buffers = kMaxBufferCount;
-      newStream->priv = privStream;
-      mStreams.push_back(newStream);
-    } else {
-      // Existing stream, mark as still alive.
-      PrivateStreamInfo *privStream =
-          static_cast<PrivateStreamInfo *>(newStream->priv);
-      privStream->alive = true;
-    }
-    // Always update usage and max buffers
-    newStream->max_buffers = kMaxBufferCount;
-    switch (newStream->stream_type) {
-      case CAMERA3_STREAM_OUTPUT:
-        newStream->usage = GRALLOC_USAGE_HW_CAMERA_WRITE;
-        break;
-      case CAMERA3_STREAM_INPUT:
-        newStream->usage = GRALLOC_USAGE_HW_CAMERA_READ;
-        break;
-      case CAMERA3_STREAM_BIDIRECTIONAL:
-        newStream->usage =
-            GRALLOC_USAGE_HW_CAMERA_READ | GRALLOC_USAGE_HW_CAMERA_WRITE;
-        break;
-    }
-  }
-
-  /**
-   * Reap the dead streams
-   */
-  for (StreamIterator s = mStreams.begin(); s != mStreams.end();) {
-    PrivateStreamInfo *privStream =
-        static_cast<PrivateStreamInfo *>((*s)->priv);
-    if (!privStream->alive) {
-      (*s)->priv = NULL;
-      delete privStream;
-      s = mStreams.erase(s);
-    } else {
-      ++s;
-    }
-  }
-
-  /**
-   * Can't reuse settings across configure call
-   */
-  mPrevSettings.clear();
-
-  return OK;
-}
-
-status_t EmulatedFakeCamera3::registerStreamBuffers(
-    const camera3_stream_buffer_set * /*bufferSet*/) {
-  ALOGV("%s: E", __FUNCTION__);
-  Mutex::Autolock l(mLock);
-
-  // Should not be called in HAL versions >= 3.2
-
-  ALOGE("%s: Should not be invoked on new HALs!", __FUNCTION__);
-  return NO_INIT;
-}
-
-const camera_metadata_t *EmulatedFakeCamera3::constructDefaultRequestSettings(
-    int type) {
-  ALOGV("%s: E", __FUNCTION__);
-  Mutex::Autolock l(mLock);
-
-  if (type < 0 || type >= CAMERA3_TEMPLATE_COUNT) {
-    ALOGE("%s: Unknown request settings template: %d", __FUNCTION__, type);
-    return NULL;
-  }
-
-  if (!hasCapability(BACKWARD_COMPATIBLE) && type != CAMERA3_TEMPLATE_PREVIEW) {
-    ALOGE("%s: Template %d not supported w/o BACKWARD_COMPATIBLE capability",
-          __FUNCTION__, type);
-    return NULL;
-  }
-
-  /**
-   * Cache is not just an optimization - pointer returned has to live at
-   * least as long as the camera device instance does.
-   */
-  if (mDefaultTemplates[type] != NULL) {
-    return mDefaultTemplates[type];
-  }
-
-  CameraMetadata settings;
-
-  /** android.request */
-
-  static const uint8_t metadataMode = ANDROID_REQUEST_METADATA_MODE_FULL;
-  settings.update(ANDROID_REQUEST_METADATA_MODE, &metadataMode, 1);
-
-  static const int32_t id = 0;
-  settings.update(ANDROID_REQUEST_ID, &id, 1);
-
-  static const int32_t frameCount = 0;
-  settings.update(ANDROID_REQUEST_FRAME_COUNT, &frameCount, 1);
-
-  /** android.lens */
-
-  static const float focalLength = 5.0f;
-  settings.update(ANDROID_LENS_FOCAL_LENGTH, &focalLength, 1);
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const float focusDistance = 0;
-    settings.update(ANDROID_LENS_FOCUS_DISTANCE, &focusDistance, 1);
-
-    static const float aperture = 2.8f;
-    settings.update(ANDROID_LENS_APERTURE, &aperture, 1);
-
-    static const float filterDensity = 0;
-    settings.update(ANDROID_LENS_FILTER_DENSITY, &filterDensity, 1);
-
-    static const uint8_t opticalStabilizationMode =
-        ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
-    settings.update(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
-                    &opticalStabilizationMode, 1);
-
-    // FOCUS_RANGE set only in frame
-  }
-
-  /** android.sensor */
-
-  if (hasCapability(MANUAL_SENSOR)) {
-    static const int64_t exposureTime = 10 * MSEC;
-    settings.update(ANDROID_SENSOR_EXPOSURE_TIME, &exposureTime, 1);
-
-    static const int64_t frameDuration = 33333333L;  // 1/30 s
-    settings.update(ANDROID_SENSOR_FRAME_DURATION, &frameDuration, 1);
-
-    static const int32_t sensitivity = 100;
-    settings.update(ANDROID_SENSOR_SENSITIVITY, &sensitivity, 1);
-  }
-
-  // TIMESTAMP set only in frame
-
-  /** android.flash */
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
-    settings.update(ANDROID_FLASH_MODE, &flashMode, 1);
-
-    static const uint8_t flashPower = 10;
-    settings.update(ANDROID_FLASH_FIRING_POWER, &flashPower, 1);
-
-    static const int64_t firingTime = 0;
-    settings.update(ANDROID_FLASH_FIRING_TIME, &firingTime, 1);
-  }
-
-  /** Processing block modes */
-  if (hasCapability(MANUAL_POST_PROCESSING)) {
-    uint8_t hotPixelMode = 0;
-    uint8_t demosaicMode = 0;
-    uint8_t noiseMode = 0;
-    uint8_t shadingMode = 0;
-    uint8_t colorMode = 0;
-    uint8_t tonemapMode = 0;
-    uint8_t edgeMode = 0;
-    switch (type) {
-      case CAMERA3_TEMPLATE_STILL_CAPTURE:
-        // fall-through
-      case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
-        // fall-through
-      case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
-        hotPixelMode = ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY;
-        demosaicMode = ANDROID_DEMOSAIC_MODE_HIGH_QUALITY;
-        noiseMode = ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY;
-        shadingMode = ANDROID_SHADING_MODE_HIGH_QUALITY;
-        colorMode = ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY;
-        tonemapMode = ANDROID_TONEMAP_MODE_HIGH_QUALITY;
-        edgeMode = ANDROID_EDGE_MODE_HIGH_QUALITY;
-        break;
-      case CAMERA3_TEMPLATE_PREVIEW:
-        // fall-through
-      case CAMERA3_TEMPLATE_VIDEO_RECORD:
-        // fall-through
-      default:
-        hotPixelMode = ANDROID_HOT_PIXEL_MODE_FAST;
-        demosaicMode = ANDROID_DEMOSAIC_MODE_FAST;
-        noiseMode = ANDROID_NOISE_REDUCTION_MODE_FAST;
-        shadingMode = ANDROID_SHADING_MODE_FAST;
-        colorMode = ANDROID_COLOR_CORRECTION_MODE_FAST;
-        tonemapMode = ANDROID_TONEMAP_MODE_FAST;
-        edgeMode = ANDROID_EDGE_MODE_FAST;
-        break;
-    }
-    settings.update(ANDROID_HOT_PIXEL_MODE, &hotPixelMode, 1);
-    settings.update(ANDROID_DEMOSAIC_MODE, &demosaicMode, 1);
-    settings.update(ANDROID_NOISE_REDUCTION_MODE, &noiseMode, 1);
-    settings.update(ANDROID_SHADING_MODE, &shadingMode, 1);
-    settings.update(ANDROID_COLOR_CORRECTION_MODE, &colorMode, 1);
-    settings.update(ANDROID_TONEMAP_MODE, &tonemapMode, 1);
-    settings.update(ANDROID_EDGE_MODE, &edgeMode, 1);
-  }
-
-  /** android.colorCorrection */
-
-  if (hasCapability(MANUAL_POST_PROCESSING)) {
-    static const camera_metadata_rational colorTransform[9] = {
-        {1, 1}, {0, 1}, {0, 1}, {0, 1}, {1, 1}, {0, 1}, {0, 1}, {0, 1}, {1, 1}};
-    settings.update(ANDROID_COLOR_CORRECTION_TRANSFORM, colorTransform, 9);
-
-    static const float colorGains[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-    settings.update(ANDROID_COLOR_CORRECTION_GAINS, colorGains, 4);
-  }
-
-  /** android.tonemap */
-
-  if (hasCapability(MANUAL_POST_PROCESSING)) {
-    static const float tonemapCurve[4] = {0.f, 0.f, 1.f, 1.f};
-    settings.update(ANDROID_TONEMAP_CURVE_RED, tonemapCurve, 4);
-    settings.update(ANDROID_TONEMAP_CURVE_GREEN, tonemapCurve, 4);
-    settings.update(ANDROID_TONEMAP_CURVE_BLUE, tonemapCurve, 4);
-  }
-
-  /** android.scaler */
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const int32_t cropRegion[4] = {0, 0, mSensorWidth, mSensorHeight};
-    settings.update(ANDROID_SCALER_CROP_REGION, cropRegion, 4);
-  }
-
-  /** android.jpeg */
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t jpegQuality = 80;
-    settings.update(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
-
-    static const int32_t thumbnailSize[2] = {640, 480};
-    settings.update(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
-
-    static const uint8_t thumbnailQuality = 80;
-    settings.update(ANDROID_JPEG_THUMBNAIL_QUALITY, &thumbnailQuality, 1);
-
-    static const double gpsCoordinates[2] = {0, 0};
-    settings.update(ANDROID_JPEG_GPS_COORDINATES, gpsCoordinates, 2);
-
-    static const uint8_t gpsProcessingMethod[32] = "None";
-    settings.update(ANDROID_JPEG_GPS_PROCESSING_METHOD, gpsProcessingMethod,
-                    32);
-
-    static const int64_t gpsTimestamp = 0;
-    settings.update(ANDROID_JPEG_GPS_TIMESTAMP, &gpsTimestamp, 1);
-
-    static const int32_t jpegOrientation = 0;
-    settings.update(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
-  }
-
-  /** android.stats */
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t faceDetectMode =
-        ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
-    settings.update(ANDROID_STATISTICS_FACE_DETECT_MODE, &faceDetectMode, 1);
-
-    static const uint8_t hotPixelMapMode =
-        ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
-    settings.update(ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, &hotPixelMapMode, 1);
-  }
-
-  // faceRectangles, faceScores, faceLandmarks, faceIds, histogram,
-  // sharpnessMap only in frames
-
-  /** android.control */
-
-  uint8_t controlIntent = 0;
-  switch (type) {
-    case CAMERA3_TEMPLATE_PREVIEW:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
-      break;
-    case CAMERA3_TEMPLATE_STILL_CAPTURE:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
-      break;
-    case CAMERA3_TEMPLATE_VIDEO_RECORD:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
-      break;
-    case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
-      break;
-    case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
-      break;
-    case CAMERA3_TEMPLATE_MANUAL:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;
-      break;
-    default:
-      controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM;
-      break;
-  }
-  settings.update(ANDROID_CONTROL_CAPTURE_INTENT, &controlIntent, 1);
-
-  const uint8_t controlMode = (type == CAMERA3_TEMPLATE_MANUAL)
-                                  ? ANDROID_CONTROL_MODE_OFF
-                                  : ANDROID_CONTROL_MODE_AUTO;
-  settings.update(ANDROID_CONTROL_MODE, &controlMode, 1);
-
-  int32_t aeTargetFpsRange[2] = {5, 30};
-  if (type == CAMERA3_TEMPLATE_VIDEO_RECORD ||
-      type == CAMERA3_TEMPLATE_VIDEO_SNAPSHOT) {
-    aeTargetFpsRange[0] = 30;
-  }
-  settings.update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, aeTargetFpsRange, 2);
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
-    settings.update(ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1);
-
-    static const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
-    settings.update(ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1);
-
-    const uint8_t aeMode = (type == CAMERA3_TEMPLATE_MANUAL)
-                               ? ANDROID_CONTROL_AE_MODE_OFF
-                               : ANDROID_CONTROL_AE_MODE_ON;
-    settings.update(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
-
-    static const uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;
-    settings.update(ANDROID_CONTROL_AE_LOCK, &aeLock, 1);
-
-    static const int32_t controlRegions[5] = {0, 0, 0, 0, 0};
-    settings.update(ANDROID_CONTROL_AE_REGIONS, controlRegions, 5);
-
-    static const int32_t aeExpCompensation = 0;
-    settings.update(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
-                    &aeExpCompensation, 1);
-
-    static const uint8_t aeAntibandingMode =
-        ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
-    settings.update(ANDROID_CONTROL_AE_ANTIBANDING_MODE, &aeAntibandingMode, 1);
-
-    static const uint8_t aePrecaptureTrigger =
-        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
-    settings.update(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &aePrecaptureTrigger,
-                    1);
-
-    const uint8_t awbMode = (type == CAMERA3_TEMPLATE_MANUAL)
-                                ? ANDROID_CONTROL_AWB_MODE_OFF
-                                : ANDROID_CONTROL_AWB_MODE_AUTO;
-    settings.update(ANDROID_CONTROL_AWB_MODE, &awbMode, 1);
-
-    static const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
-    settings.update(ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
-    uint8_t afMode = 0;
-
-    if (mFacingBack) {
-      switch (type) {
-        case CAMERA3_TEMPLATE_PREVIEW:
-          afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
-          break;
-        case CAMERA3_TEMPLATE_STILL_CAPTURE:
-          afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
-          break;
-        case CAMERA3_TEMPLATE_VIDEO_RECORD:
-          afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
-          break;
-        case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
-          afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
-          break;
-        case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
-          afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE;
-          break;
-        case CAMERA3_TEMPLATE_MANUAL:
-          afMode = ANDROID_CONTROL_AF_MODE_OFF;
-          break;
-        default:
-          afMode = ANDROID_CONTROL_AF_MODE_AUTO;
-          break;
-      }
-    } else {
-      afMode = ANDROID_CONTROL_AF_MODE_OFF;
-    }
-    settings.update(ANDROID_CONTROL_AF_MODE, &afMode, 1);
-
-    settings.update(ANDROID_CONTROL_AF_REGIONS, controlRegions, 5);
-
-    static const uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
-    settings.update(ANDROID_CONTROL_AF_TRIGGER, &afTrigger, 1);
-
-    static const uint8_t vstabMode =
-        ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
-    settings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &vstabMode, 1);
-
-    static const uint8_t blackLevelLock = ANDROID_BLACK_LEVEL_LOCK_OFF;
-    settings.update(ANDROID_BLACK_LEVEL_LOCK, &blackLevelLock, 1);
-
-    static const uint8_t lensShadingMapMode =
-        ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
-    settings.update(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
-                    &lensShadingMapMode, 1);
-
-    static const uint8_t aberrationMode =
-        ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST;
-    settings.update(ANDROID_COLOR_CORRECTION_ABERRATION_MODE, &aberrationMode,
-                    1);
-
-    static const int32_t testPatternMode = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
-    settings.update(ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternMode, 1);
-  }
-
-  mDefaultTemplates[type] = settings.release();
-
-  return mDefaultTemplates[type];
-}
-
-status_t EmulatedFakeCamera3::processCaptureRequest(
-    camera3_capture_request *request) {
-  Mutex::Autolock l(mLock);
-  status_t res;
-
-  /** Validation */
-
-  if (mStatus < STATUS_READY) {
-    ALOGE("%s: Can't submit capture requests in state %d", __FUNCTION__,
-          mStatus);
-    return INVALID_OPERATION;
-  }
-
-  if (request == NULL) {
-    ALOGE("%s: NULL request!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  uint32_t frameNumber = request->frame_number;
-
-  if (request->settings == NULL && mPrevSettings.isEmpty()) {
-    ALOGE(
-        "%s: Request %d: NULL settings for first request after"
-        "configureStreams()",
-        __FUNCTION__, frameNumber);
-    return BAD_VALUE;
-  }
-
-  if (request->input_buffer != NULL &&
-      request->input_buffer->stream != mInputStream) {
-    ALOGE("%s: Request %d: Input buffer not from input stream!", __FUNCTION__,
-          frameNumber);
-    ALOGV("%s: Bad stream %p, expected: %p", __FUNCTION__,
-          request->input_buffer->stream, mInputStream);
-    ALOGV("%s: Bad stream type %d, expected stream type %d", __FUNCTION__,
-          request->input_buffer->stream->stream_type,
-          mInputStream ? mInputStream->stream_type : -1);
-
-    return BAD_VALUE;
-  }
-
-  if (request->num_output_buffers < 1 || request->output_buffers == NULL) {
-    ALOGE("%s: Request %d: No output buffers provided!", __FUNCTION__,
-          frameNumber);
-    return BAD_VALUE;
-  }
-
-  // Validate all buffers, starting with input buffer if it's given
-
-  ssize_t idx;
-  const camera3_stream_buffer_t *b;
-  if (request->input_buffer != NULL) {
-    idx = -1;
-    b = request->input_buffer;
-  } else {
-    idx = 0;
-    b = request->output_buffers;
-  }
-  do {
-    PrivateStreamInfo *priv = static_cast<PrivateStreamInfo *>(b->stream->priv);
-    if (priv == NULL) {
-      ALOGE("%s: Request %d: Buffer %zu: Unconfigured stream!", __FUNCTION__,
-            frameNumber, idx);
-      return BAD_VALUE;
-    }
-    if (!priv->alive) {
-      ALOGE("%s: Request %d: Buffer %zu: Dead stream!", __FUNCTION__,
-            frameNumber, idx);
-      return BAD_VALUE;
-    }
-    if (b->status != CAMERA3_BUFFER_STATUS_OK) {
-      ALOGE("%s: Request %d: Buffer %zu: Status not OK!", __FUNCTION__,
-            frameNumber, idx);
-      return BAD_VALUE;
-    }
-    if (b->release_fence != -1) {
-      ALOGE("%s: Request %d: Buffer %zu: Has a release fence!", __FUNCTION__,
-            frameNumber, idx);
-      return BAD_VALUE;
-    }
-    if (b->buffer == NULL) {
-      ALOGE("%s: Request %d: Buffer %zu: NULL buffer handle!", __FUNCTION__,
-            frameNumber, idx);
-      return BAD_VALUE;
-    }
-    idx++;
-    b = &(request->output_buffers[idx]);
-  } while (idx < (ssize_t)request->num_output_buffers);
-
-  // TODO: Validate settings parameters
-
-  /**
-   * Start processing this request
-   */
-
-  mStatus = STATUS_ACTIVE;
-
-  CameraMetadata settings;
-
-  if (request->settings == NULL) {
-    settings.acquire(mPrevSettings);
-  } else {
-    settings = request->settings;
-  }
-
-  res = process3A(settings);
-  if (res != OK) {
-    return res;
-  }
-
-  // TODO: Handle reprocessing
-
-  /**
-   * Get ready for sensor config
-   */
-
-  nsecs_t exposureTime;
-  nsecs_t frameDuration;
-  uint32_t sensitivity;
-  bool needJpeg = false;
-  camera_metadata_entry_t entry;
-
-  entry = settings.find(ANDROID_SENSOR_EXPOSURE_TIME);
-  exposureTime =
-      (entry.count > 0) ? entry.data.i64[0] : Sensor::kExposureTimeRange[0];
-  entry = settings.find(ANDROID_SENSOR_FRAME_DURATION);
-  frameDuration =
-      (entry.count > 0) ? entry.data.i64[0] : Sensor::kFrameDurationRange[0];
-  entry = settings.find(ANDROID_SENSOR_SENSITIVITY);
-  sensitivity =
-      (entry.count > 0) ? entry.data.i32[0] : Sensor::kSensitivityRange[0];
-
-  if (exposureTime > frameDuration) {
-    frameDuration = exposureTime + Sensor::kMinVerticalBlank;
-    settings.update(ANDROID_SENSOR_FRAME_DURATION, &frameDuration, 1);
-  }
-
-  Buffers *sensorBuffers = new Buffers();
-  HalBufferVector *buffers = new HalBufferVector();
-
-  sensorBuffers->setCapacity(request->num_output_buffers);
-  buffers->setCapacity(request->num_output_buffers);
-
-  // Process all the buffers we got for output, constructing internal buffer
-  // structures for them, and lock them for writing.
-  for (size_t i = 0; i < request->num_output_buffers; i++) {
-    const camera3_stream_buffer &srcBuf = request->output_buffers[i];
-    StreamBuffer destBuf;
-    destBuf.streamId = kGenericStreamId;
-    destBuf.width = srcBuf.stream->width;
-    destBuf.height = srcBuf.stream->height;
-    // For GCE, IMPLEMENTATION_DEFINED is always RGBx_8888
-    destBuf.format =
-        (srcBuf.stream->format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)
-            ? HAL_PIXEL_FORMAT_RGBA_8888
-            : srcBuf.stream->format;
-    destBuf.stride = srcBuf.stream->width;
-    destBuf.dataSpace = srcBuf.stream->data_space;
-    destBuf.buffer = srcBuf.buffer;
-
-    if (destBuf.format == HAL_PIXEL_FORMAT_BLOB) {
-      needJpeg = true;
-    }
-
-    // Wait on fence
-    sp<Fence> bufferAcquireFence = new Fence(srcBuf.acquire_fence);
-    res = bufferAcquireFence->wait(kFenceTimeoutMs);
-    if (res == TIMED_OUT) {
-      ALOGE("%s: Request %d: Buffer %zu: Fence timed out after %d ms",
-            __FUNCTION__, frameNumber, i, kFenceTimeoutMs);
-    }
-    if (res == OK) {
-      // Lock buffer for writing
-      if (srcBuf.stream->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-        if (destBuf.format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-          android_ycbcr ycbcr = android_ycbcr();
-          res = GrallocModule::getInstance().lock_ycbcr(
-              *(destBuf.buffer), GRALLOC_USAGE_HW_CAMERA_WRITE, 0, 0,
-              destBuf.width, destBuf.height, &ycbcr);
-          // This is only valid because we know that emulator's
-          // YCbCr_420_888 is really contiguous NV21 under the hood
-          destBuf.img = static_cast<uint8_t *>(ycbcr.y);
-        } else {
-          ALOGE("Unexpected private format for flexible YUV: 0x%x",
-                destBuf.format);
-          res = INVALID_OPERATION;
-        }
-      } else {
-        res = GrallocModule::getInstance().lock(
-            *(destBuf.buffer), GRALLOC_USAGE_HW_CAMERA_WRITE, 0, 0,
-            destBuf.width, destBuf.height, (void **)&(destBuf.img));
-      }
-      if (res != OK) {
-        ALOGE("%s: Request %d: Buffer %zu: Unable to lock buffer", __FUNCTION__,
-              frameNumber, i);
-      }
-    }
-
-    if (res != OK) {
-      // Either waiting or locking failed. Unlock locked buffers and bail
-      // out.
-      for (size_t j = 0; j < i; j++) {
-        GrallocModule::getInstance().unlock(
-            *(request->output_buffers[i].buffer));
-      }
-      delete sensorBuffers;
-      delete buffers;
-      return NO_INIT;
-    }
-
-    sensorBuffers->push_back(destBuf);
-    buffers->push_back(srcBuf);
-  }
-
-  /**
-   * Wait for JPEG compressor to not be busy, if needed
-   */
-  if (needJpeg) {
-    bool ready = mJpegCompressor->waitForDone(kJpegTimeoutNs);
-    if (!ready) {
-      ALOGE("%s: Timeout waiting for JPEG compression to complete!",
-            __FUNCTION__);
-      return NO_INIT;
-    }
-    res = mJpegCompressor->reserve();
-    if (res != OK) {
-      ALOGE("%s: Error managing JPEG compressor resources, can't reserve it!",
-            __FUNCTION__);
-      return NO_INIT;
-    }
-  }
-
-  /**
-   * Wait until the in-flight queue has room
-   */
-  res = mReadoutThread->waitForReadout();
-  if (res != OK) {
-    ALOGE("%s: Timeout waiting for previous requests to complete!",
-          __FUNCTION__);
-    return NO_INIT;
-  }
-
-  /**
-   * Wait until sensor's ready. This waits for lengthy amounts of time with
-   * mLock held, but the interface spec is that no other calls may by done to
-   * the HAL by the framework while process_capture_request is happening.
-   */
-  int syncTimeoutCount = 0;
-  while (!mSensor->waitForVSync(kSyncWaitTimeout)) {
-    if (mStatus == STATUS_ERROR) {
-      return NO_INIT;
-    }
-    if (syncTimeoutCount == kMaxSyncTimeoutCount) {
-      ALOGE("%s: Request %d: Sensor sync timed out after %" PRId64 " ms",
-            __FUNCTION__, frameNumber,
-            kSyncWaitTimeout * kMaxSyncTimeoutCount / 1000000);
-      return NO_INIT;
-    }
-    syncTimeoutCount++;
-  }
-
-  /**
-   * Configure sensor and queue up the request to the readout thread
-   */
-  mSensor->setExposureTime(exposureTime);
-  mSensor->setFrameDuration(frameDuration);
-  mSensor->setSensitivity(sensitivity);
-  mSensor->setDestinationBuffers(sensorBuffers);
-  mSensor->setFrameNumber(request->frame_number);
-
-  ReadoutThread::Request r;
-  r.frameNumber = request->frame_number;
-  r.settings = settings;
-  r.sensorBuffers = sensorBuffers;
-  r.buffers = buffers;
-
-  mReadoutThread->queueCaptureRequest(r);
-  ALOGVV("%s: Queued frame %d", __FUNCTION__, request->frame_number);
-
-  // Cache the settings for next time
-  mPrevSettings.acquire(settings);
-
-  return OK;
-}
-
-status_t EmulatedFakeCamera3::flush() {
-  ALOGW("%s: Not implemented; ignored", __FUNCTION__);
-  return OK;
-}
-
-/** Debug methods */
-
-void EmulatedFakeCamera3::dump(int /*fd*/) {}
-
-/**
- * Private methods
- */
-
-status_t EmulatedFakeCamera3::getCameraCapabilities() {
-  const char *key =
-      mFacingBack ? "qemu.sf.back_camera_caps" : "qemu.sf.front_camera_caps";
-
-  /* Defined by 'qemu.sf.*_camera_caps' boot property: if the
-   * property doesn't exist, it is assumed to list FULL. */
-  char prop[PROPERTY_VALUE_MAX];
-  if (property_get(key, prop, NULL) > 0) {
-    char *saveptr = nullptr;
-    char *cap = strtok_r(prop, " ,", &saveptr);
-    while (cap != NULL) {
-      for (int i = 0; i < NUM_CAPABILITIES; i++) {
-        if (!strcasecmp(cap, sAvailableCapabilitiesStrings[i])) {
-          mCapabilities.add(static_cast<AvailableCapabilities>(i));
-          break;
-        }
-      }
-      cap = strtok_r(NULL, " ,", &saveptr);
-    }
-    if (mCapabilities.size() == 0) {
-      ALOGE("qemu.sf.back_camera_caps had no valid capabilities: %s", prop);
-    }
-  }
-  // Default to FULL_LEVEL plus RAW if nothing is defined
-  if (mCapabilities.size() == 0) {
-    mCapabilities.add(FULL_LEVEL);
-    mCapabilities.add(RAW);
-  }
-
-  // Add level-based caps
-  if (hasCapability(FULL_LEVEL)) {
-    mCapabilities.add(BURST_CAPTURE);
-    mCapabilities.add(READ_SENSOR_SETTINGS);
-    mCapabilities.add(MANUAL_SENSOR);
-    mCapabilities.add(MANUAL_POST_PROCESSING);
-  };
-
-  // Backwards-compatible is required for most other caps
-  // Not required for DEPTH_OUTPUT, though.
-  if (hasCapability(BURST_CAPTURE) || hasCapability(READ_SENSOR_SETTINGS) ||
-      hasCapability(RAW) || hasCapability(MANUAL_SENSOR) ||
-      hasCapability(MANUAL_POST_PROCESSING) ||
-      hasCapability(PRIVATE_REPROCESSING) || hasCapability(YUV_REPROCESSING) ||
-      hasCapability(CONSTRAINED_HIGH_SPEED_VIDEO)) {
-    mCapabilities.add(BACKWARD_COMPATIBLE);
-  }
-
-  ALOGI("Camera %d capabilities:", mCameraID);
-  for (size_t i = 0; i < mCapabilities.size(); i++) {
-    ALOGI("  %s", sAvailableCapabilitiesStrings[mCapabilities[i]]);
-  }
-
-  return OK;
-}
-
-bool EmulatedFakeCamera3::hasCapability(AvailableCapabilities cap) {
-  ssize_t idx = mCapabilities.indexOf(cap);
-  return idx >= 0;
-}
-
-status_t EmulatedFakeCamera3::constructStaticInfo(
-    const cvd::CameraDefinition &params) {
-  CameraMetadata info;
-  Vector<int32_t> availableCharacteristicsKeys;
-  status_t res;
-
-  int32_t width = 0, height = 0;
-
-  /* TODO(ender): this currently supports only maximum resolution. */
-  for (size_t index = 0; index < params.resolutions.size(); ++index) {
-    if (width <= params.resolutions[index].width &&
-        height <= params.resolutions[index].height) {
-      width = params.resolutions[index].width;
-      height = params.resolutions[index].height;
-    }
-  }
-
-  if (width < 640 || height < 480) {
-    width = 640;
-    height = 480;
-  }
-
-  mSensorWidth = width;
-  mSensorHeight = height;
-
-#define ADD_STATIC_ENTRY(name, varptr, count) \
-  availableCharacteristicsKeys.add(name);     \
-  res = info.update(name, varptr, count);     \
-  if (res != OK) return res
-
-  // android.sensor
-
-  if (hasCapability(MANUAL_SENSOR)) {
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
-                     Sensor::kExposureTimeRange, 2);
-
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
-                     &Sensor::kFrameDurationRange[1], 1);
-
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
-                     Sensor::kSensitivityRange,
-                     sizeof(Sensor::kSensitivityRange) / sizeof(int32_t));
-
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY,
-                     &Sensor::kSensitivityRange[1], 1);
-  }
-
-  static const float sensorPhysicalSize[2] = {3.20f, 2.40f};  // mm
-  ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, sensorPhysicalSize, 2);
-
-  const int32_t pixelArray[] = {mSensorWidth, mSensorHeight};
-  ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArray, 2);
-  const int32_t activeArray[] = {0, 0, mSensorWidth, mSensorHeight};
-  ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArray, 4);
-
-  static const int32_t orientation = 90;  // Aligned with 'long edge'
-  ADD_STATIC_ENTRY(ANDROID_SENSOR_ORIENTATION, &orientation, 1);
-
-  static const uint8_t timestampSource =
-      ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
-  ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &timestampSource, 1);
-
-  if (hasCapability(RAW)) {
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
-                     &Sensor::kColorFilterArrangement, 1);
-
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_WHITE_LEVEL,
-                     (int32_t *)&Sensor::kMaxRawValue, 1);
-
-    static const int32_t blackLevelPattern[4] = {
-        (int32_t)Sensor::kBlackLevel, (int32_t)Sensor::kBlackLevel,
-        (int32_t)Sensor::kBlackLevel, (int32_t)Sensor::kBlackLevel};
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_BLACK_LEVEL_PATTERN, blackLevelPattern,
-                     sizeof(blackLevelPattern) / sizeof(int32_t));
-  }
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const int32_t availableTestPatternModes[] = {
-        ANDROID_SENSOR_TEST_PATTERN_MODE_OFF};
-    ADD_STATIC_ENTRY(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
-                     availableTestPatternModes,
-                     sizeof(availableTestPatternModes) / sizeof(int32_t));
-  }
-
-  // android.lens
-
-  static const float focalLength = 3.30f;  // mm
-  ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &focalLength, 1);
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    // 5 cm min focus distance for back camera, infinity (fixed focus) for front
-    const float minFocusDistance = mFacingBack ? 1.0 / 0.05 : 0.0;
-    ADD_STATIC_ENTRY(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
-                     &minFocusDistance, 1);
-
-    // 5 m hyperfocal distance for back camera, infinity (fixed focus) for front
-    const float hyperFocalDistance = mFacingBack ? 1.0 / 5.0 : 0.0;
-    ADD_STATIC_ENTRY(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, &hyperFocalDistance,
-                     1);
-
-    static const float aperture = 2.8f;
-    ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_APERTURES, &aperture, 1);
-    static const float filterDensity = 0;
-    ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
-                     &filterDensity, 1);
-    static const uint8_t availableOpticalStabilization =
-        ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
-    ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
-                     &availableOpticalStabilization, 1);
-
-    static const int32_t lensShadingMapSize[] = {1, 1};
-    ADD_STATIC_ENTRY(ANDROID_LENS_INFO_SHADING_MAP_SIZE, lensShadingMapSize,
-                     sizeof(lensShadingMapSize) / sizeof(int32_t));
-
-    static const uint8_t lensFocusCalibration =
-        ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE;
-    ADD_STATIC_ENTRY(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
-                     &lensFocusCalibration, 1);
-  }
-
-  if (hasCapability(DEPTH_OUTPUT)) {
-    // These could be included for non-DEPTH capability as well, but making this
-    // variable for testing coverage
-
-    // 90 degree rotation to align with long edge of a phone device that's by
-    // default portrait
-    static const float qO[] = {0.707107f, 0.f, 0.f, 0.707107f};
-
-    // Either a 180-degree rotation for back-facing, or no rotation for
-    // front-facing
-    const float qF[] = {0, (mFacingBack ? 1.f : 0.f), 0,
-                        (mFacingBack ? 0.f : 1.f)};
-
-    // Quarternion product, orientation change then facing
-    const float lensPoseRotation[] = {
-        qO[0] * qF[0] - qO[1] * qF[1] - qO[2] * qF[2] - qO[3] * qF[3],
-        qO[0] * qF[1] + qO[1] * qF[0] + qO[2] * qF[3] - qO[3] * qF[2],
-        qO[0] * qF[2] + qO[2] * qF[0] + qO[1] * qF[3] - qO[3] * qF[1],
-        qO[0] * qF[3] + qO[3] * qF[0] + qO[1] * qF[2] - qO[2] * qF[1]};
-
-    ADD_STATIC_ENTRY(ANDROID_LENS_POSE_ROTATION, lensPoseRotation,
-                     sizeof(lensPoseRotation) / sizeof(float));
-
-    // Only one camera facing each way, so 0 translation needed to the center of
-    // the 'main' camera
-    static const float lensPoseTranslation[] = {0.f, 0.f, 0.f};
-
-    ADD_STATIC_ENTRY(ANDROID_LENS_POSE_TRANSLATION, lensPoseTranslation,
-                     sizeof(lensPoseTranslation) / sizeof(float));
-
-    // Intrinsics are 'ideal' (f_x, f_y, c_x, c_y, s) match focal length and
-    // active array size
-    float f_x = focalLength * mSensorWidth / sensorPhysicalSize[0];
-    float f_y = focalLength * mSensorHeight / sensorPhysicalSize[1];
-    float c_x = mSensorWidth / 2.f;
-    float c_y = mSensorHeight / 2.f;
-    float s = 0.f;
-    const float lensIntrinsics[] = {f_x, f_y, c_x, c_y, s};
-
-    ADD_STATIC_ENTRY(ANDROID_LENS_INTRINSIC_CALIBRATION, lensIntrinsics,
-                     sizeof(lensIntrinsics) / sizeof(float));
-
-    // No radial or tangential distortion
-
-    float lensRadialDistortion[] = {1.0f, 0.f, 0.f, 0.f, 0.f, 0.f};
-
-    ADD_STATIC_ENTRY(ANDROID_LENS_RADIAL_DISTORTION, lensRadialDistortion,
-                     sizeof(lensRadialDistortion) / sizeof(float));
-  }
-
-  const uint8_t lensFacing =
-      mFacingBack ? ANDROID_LENS_FACING_BACK : ANDROID_LENS_FACING_FRONT;
-  ADD_STATIC_ENTRY(ANDROID_LENS_FACING, &lensFacing, 1);
-
-  // android.flash
-
-  const uint8_t flashAvailable = mFacingBack;
-  ADD_STATIC_ENTRY(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1);
-
-  // android.tonemap
-
-  if (hasCapability(MANUAL_POST_PROCESSING)) {
-    static const int32_t tonemapCurvePoints = 128;
-    ADD_STATIC_ENTRY(ANDROID_TONEMAP_MAX_CURVE_POINTS, &tonemapCurvePoints, 1);
-
-    static const uint8_t availableToneMapModes[] = {
-        ANDROID_TONEMAP_MODE_CONTRAST_CURVE, ANDROID_TONEMAP_MODE_FAST,
-        ANDROID_TONEMAP_MODE_HIGH_QUALITY};
-    ADD_STATIC_ENTRY(ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES,
-                     availableToneMapModes, sizeof(availableToneMapModes));
-  }
-
-  // android.scaler
-
-  const std::vector<int32_t> availableStreamConfigurationsBasic = {
-      HAL_PIXEL_FORMAT_BLOB,
-      width,
-      height,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      320,
-      240,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      320,
-      240,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-      HAL_PIXEL_FORMAT_BLOB,
-      320,
-      240,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-  };
-
-  // Always need to include 640x480 in basic formats
-  const std::vector<int32_t> availableStreamConfigurationsBasic640 = {
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      640,
-      480,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      640,
-      480,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-      HAL_PIXEL_FORMAT_BLOB,
-      640,
-      480,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT};
-
-  const std::vector<int32_t> availableStreamConfigurationsRaw = {
-      HAL_PIXEL_FORMAT_RAW16,
-      width,
-      height,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-  };
-
-  const std::vector<int32_t> availableStreamConfigurationsBurst = {
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      width,
-      height,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      width,
-      height,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-      HAL_PIXEL_FORMAT_RGBA_8888,
-      width,
-      height,
-      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-  };
-
-  std::vector<int32_t> availableStreamConfigurations;
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    availableStreamConfigurations.insert(
-        availableStreamConfigurations.end(),
-        availableStreamConfigurationsBasic.begin(),
-        availableStreamConfigurationsBasic.end());
-    if (width > 640) {
-      availableStreamConfigurations.insert(
-          availableStreamConfigurations.end(),
-          availableStreamConfigurationsBasic640.begin(),
-          availableStreamConfigurationsBasic640.end());
-    }
-  }
-  if (hasCapability(RAW)) {
-    availableStreamConfigurations.insert(
-        availableStreamConfigurations.end(),
-        availableStreamConfigurationsRaw.begin(),
-        availableStreamConfigurationsRaw.end());
-  }
-  if (hasCapability(BURST_CAPTURE)) {
-    availableStreamConfigurations.insert(
-        availableStreamConfigurations.end(),
-        availableStreamConfigurationsBurst.begin(),
-        availableStreamConfigurationsBurst.end());
-  }
-
-  if (availableStreamConfigurations.size() > 0) {
-    ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-                     &availableStreamConfigurations[0],
-                     availableStreamConfigurations.size());
-  }
-
-  const std::vector<int64_t> availableMinFrameDurationsBasic = {
-      HAL_PIXEL_FORMAT_BLOB,
-      width,
-      height,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      320,
-      240,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      320,
-      240,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_BLOB,
-      320,
-      240,
-      Sensor::kFrameDurationRange[0],
-  };
-
-  // Always need to include 640x480 in basic formats
-  const std::vector<int64_t> availableMinFrameDurationsBasic640 = {
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      640,
-      480,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      640,
-      480,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_BLOB,
-      640,
-      480,
-      Sensor::kFrameDurationRange[0]};
-
-  const std::vector<int64_t> availableMinFrameDurationsRaw = {
-      HAL_PIXEL_FORMAT_RAW16,
-      width,
-      height,
-      Sensor::kFrameDurationRange[0],
-  };
-
-  const std::vector<int64_t> availableMinFrameDurationsBurst = {
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      width,
-      height,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      width,
-      height,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_RGBA_8888,
-      width,
-      height,
-      Sensor::kFrameDurationRange[0],
-  };
-
-  std::vector<int64_t> availableMinFrameDurations;
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    availableMinFrameDurations.insert(availableMinFrameDurations.end(),
-                                      availableMinFrameDurationsBasic.begin(),
-                                      availableMinFrameDurationsBasic.end());
-    if (width > 640) {
-      availableMinFrameDurations.insert(
-          availableMinFrameDurations.end(),
-          availableMinFrameDurationsBasic640.begin(),
-          availableMinFrameDurationsBasic640.end());
-    }
-  }
-  if (hasCapability(RAW)) {
-    availableMinFrameDurations.insert(availableMinFrameDurations.end(),
-                                      availableMinFrameDurationsRaw.begin(),
-                                      availableMinFrameDurationsRaw.end());
-  }
-  if (hasCapability(BURST_CAPTURE)) {
-    availableMinFrameDurations.insert(availableMinFrameDurations.end(),
-                                      availableMinFrameDurationsBurst.begin(),
-                                      availableMinFrameDurationsBurst.end());
-  }
-
-  if (availableMinFrameDurations.size() > 0) {
-    ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
-                     &availableMinFrameDurations[0],
-                     availableMinFrameDurations.size());
-  }
-
-  const std::vector<int64_t> availableStallDurationsBasic = {
-      HAL_PIXEL_FORMAT_BLOB,
-      width,
-      height,
-      Sensor::kFrameDurationRange[0],
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      320,
-      240,
-      0,
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      320,
-      240,
-      0,
-      HAL_PIXEL_FORMAT_RGBA_8888,
-      320,
-      240,
-      0,
-  };
-
-  // Always need to include 640x480 in basic formats
-  const std::vector<int64_t> availableStallDurationsBasic640 = {
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      640,
-      480,
-      0,
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      640,
-      480,
-      0,
-      HAL_PIXEL_FORMAT_BLOB,
-      640,
-      480,
-      Sensor::kFrameDurationRange[0]};
-
-  const std::vector<int64_t> availableStallDurationsRaw = {
-      HAL_PIXEL_FORMAT_RAW16, width, height, Sensor::kFrameDurationRange[0]};
-  const std::vector<int64_t> availableStallDurationsBurst = {
-      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-      width,
-      height,
-      0,
-      HAL_PIXEL_FORMAT_YCbCr_420_888,
-      width,
-      height,
-      0,
-      HAL_PIXEL_FORMAT_RGBA_8888,
-      width,
-      height,
-      0};
-
-  std::vector<int64_t> availableStallDurations;
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    availableStallDurations.insert(availableStallDurations.end(),
-                                   availableStallDurationsBasic.begin(),
-                                   availableStallDurationsBasic.end());
-    if (width > 640) {
-      availableStallDurations.insert(availableStallDurations.end(),
-                                     availableStallDurationsBasic640.begin(),
-                                     availableStallDurationsBasic640.end());
-    }
-  }
-  if (hasCapability(RAW)) {
-    availableStallDurations.insert(availableStallDurations.end(),
-                                   availableStallDurationsRaw.begin(),
-                                   availableStallDurationsRaw.end());
-  }
-  if (hasCapability(BURST_CAPTURE)) {
-    availableStallDurations.insert(availableStallDurations.end(),
-                                   availableStallDurationsBurst.begin(),
-                                   availableStallDurationsBurst.end());
-  }
-
-  if (availableStallDurations.size() > 0) {
-    ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
-                     &availableStallDurations[0],
-                     availableStallDurations.size());
-  }
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_FREEFORM;
-    ADD_STATIC_ENTRY(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
-
-    static const float maxZoom = 10;
-    ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &maxZoom, 1);
-  }
-
-  // android.jpeg
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const int32_t jpegThumbnailSizes[] = {0, 0, 160, 120, 320, 240};
-    ADD_STATIC_ENTRY(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegThumbnailSizes,
-                     sizeof(jpegThumbnailSizes) / sizeof(int32_t));
-
-    static const int32_t jpegMaxSize = JpegCompressor::kMaxJpegSize;
-    ADD_STATIC_ENTRY(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
-  }
-
-  // android.stats
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableFaceDetectModes[] = {
-        ANDROID_STATISTICS_FACE_DETECT_MODE_OFF,
-        ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE,
-        ANDROID_STATISTICS_FACE_DETECT_MODE_FULL};
-    ADD_STATIC_ENTRY(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
-                     availableFaceDetectModes,
-                     sizeof(availableFaceDetectModes));
-
-    static const int32_t maxFaceCount = 8;
-    ADD_STATIC_ENTRY(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1);
-
-    static const uint8_t availableShadingMapModes[] = {
-        ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF};
-    ADD_STATIC_ENTRY(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
-                     availableShadingMapModes,
-                     sizeof(availableShadingMapModes));
-  }
-
-  // android.sync
-
-  static const int32_t maxLatency =
-      hasCapability(FULL_LEVEL) ? ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL
-                                : 3;
-  ADD_STATIC_ENTRY(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
-
-  // android.control
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableControlModes[] = {
-        ANDROID_CONTROL_MODE_OFF, ANDROID_CONTROL_MODE_AUTO,
-        ANDROID_CONTROL_MODE_USE_SCENE_MODE};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_MODES, availableControlModes,
-                     sizeof(availableControlModes));
-  } else {
-    static const uint8_t availableControlModes[] = {ANDROID_CONTROL_MODE_AUTO};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_MODES, availableControlModes,
-                     sizeof(availableControlModes));
-  }
-
-  static const uint8_t availableSceneModes[] = {
-    static_cast<uint8_t>(hasCapability(BACKWARD_COMPATIBLE)
-                         ? ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY
-                         : ANDROID_CONTROL_SCENE_MODE_DISABLED)};
-  ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, availableSceneModes,
-                   sizeof(availableSceneModes));
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableEffects[] = {ANDROID_CONTROL_EFFECT_MODE_OFF};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_EFFECTS, availableEffects,
-                     sizeof(availableEffects));
-  }
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const int32_t max3aRegions[] = {/*AE*/ 1, /*AWB*/ 0, /*AF*/ 1};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_MAX_REGIONS, max3aRegions,
-                     sizeof(max3aRegions) / sizeof(max3aRegions[0]));
-
-    static const uint8_t availableAeModes[] = {ANDROID_CONTROL_AE_MODE_OFF,
-                                               ANDROID_CONTROL_AE_MODE_ON};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_MODES, availableAeModes,
-                     sizeof(availableAeModes));
-
-    static const camera_metadata_rational exposureCompensationStep = {1, 3};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_COMPENSATION_STEP,
-                     &exposureCompensationStep, 1);
-
-    int32_t exposureCompensationRange[] = {-9, 9};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
-                     exposureCompensationRange,
-                     sizeof(exposureCompensationRange) / sizeof(int32_t));
-  }
-
-  static const int32_t availableTargetFpsRanges[] = {5,  30, 15, 30,
-                                                     15, 15, 30, 30};
-  ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
-                   availableTargetFpsRanges,
-                   sizeof(availableTargetFpsRanges) / sizeof(int32_t));
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableAntibandingModes[] = {
-        ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
-        ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
-                     availableAntibandingModes,
-                     sizeof(availableAntibandingModes));
-  }
-
-  static const uint8_t aeLockAvailable =
-      hasCapability(BACKWARD_COMPATIBLE)
-          ? ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE
-          : ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
-
-  ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1);
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableAwbModes[] = {
-        ANDROID_CONTROL_AWB_MODE_OFF,
-        ANDROID_CONTROL_AWB_MODE_AUTO,
-        ANDROID_CONTROL_AWB_MODE_INCANDESCENT,
-        ANDROID_CONTROL_AWB_MODE_FLUORESCENT,
-        ANDROID_CONTROL_AWB_MODE_DAYLIGHT,
-        ANDROID_CONTROL_AWB_MODE_SHADE};
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AWB_AVAILABLE_MODES, availableAwbModes,
-                     sizeof(availableAwbModes));
-  }
-
-  static const uint8_t awbLockAvailable =
-      hasCapability(BACKWARD_COMPATIBLE)
-          ? ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE
-          : ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
-
-  ADD_STATIC_ENTRY(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1);
-
-  static const uint8_t availableAfModesBack[] = {
-      ANDROID_CONTROL_AF_MODE_OFF, ANDROID_CONTROL_AF_MODE_AUTO,
-      ANDROID_CONTROL_AF_MODE_MACRO, ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
-      ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE};
-
-  static const uint8_t availableAfModesFront[] = {ANDROID_CONTROL_AF_MODE_OFF};
-
-  if (mFacingBack && hasCapability(BACKWARD_COMPATIBLE)) {
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModesBack,
-                     sizeof(availableAfModesBack));
-  } else {
-    ADD_STATIC_ENTRY(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModesFront,
-                     sizeof(availableAfModesFront));
-  }
-
-  static const uint8_t availableVstabModes[] = {
-      ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF};
-  ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
-                   availableVstabModes, sizeof(availableVstabModes));
-
-  // android.colorCorrection
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableAberrationModes[] = {
-        ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF,
-        ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
-        ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY};
-    ADD_STATIC_ENTRY(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
-                     availableAberrationModes,
-                     sizeof(availableAberrationModes));
-  } else {
-    static const uint8_t availableAberrationModes[] = {
-        ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF,
-    };
-    ADD_STATIC_ENTRY(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
-                     availableAberrationModes,
-                     sizeof(availableAberrationModes));
-  }
-  // android.edge
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableEdgeModes[] = {
-        ANDROID_EDGE_MODE_OFF, ANDROID_EDGE_MODE_FAST,
-        ANDROID_EDGE_MODE_HIGH_QUALITY};
-    ADD_STATIC_ENTRY(ANDROID_EDGE_AVAILABLE_EDGE_MODES, availableEdgeModes,
-                     sizeof(availableEdgeModes));
-  } else {
-    static const uint8_t availableEdgeModes[] = {ANDROID_EDGE_MODE_OFF};
-    ADD_STATIC_ENTRY(ANDROID_EDGE_AVAILABLE_EDGE_MODES, availableEdgeModes,
-                     sizeof(availableEdgeModes));
-  }
-
-  // android.info
-
-  static const uint8_t supportedHardwareLevel =
-      hasCapability(FULL_LEVEL) ? ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL
-                                : ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
-  ADD_STATIC_ENTRY(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
-                   &supportedHardwareLevel,
-                   /*count*/ 1);
-
-  // android.noiseReduction
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableNoiseReductionModes[] = {
-        ANDROID_NOISE_REDUCTION_MODE_OFF, ANDROID_NOISE_REDUCTION_MODE_FAST,
-        ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY};
-    ADD_STATIC_ENTRY(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
-                     availableNoiseReductionModes,
-                     sizeof(availableNoiseReductionModes));
-  } else {
-    static const uint8_t availableNoiseReductionModes[] = {
-        ANDROID_NOISE_REDUCTION_MODE_OFF,
-    };
-    ADD_STATIC_ENTRY(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
-                     availableNoiseReductionModes,
-                     sizeof(availableNoiseReductionModes));
-  }
-
-  // android.depth
-
-  if (hasCapability(DEPTH_OUTPUT)) {
-    static const int32_t maxDepthSamples = 100;
-    ADD_STATIC_ENTRY(ANDROID_DEPTH_MAX_DEPTH_SAMPLES, &maxDepthSamples, 1);
-
-    static const int32_t availableDepthStreamConfigurations[] = {
-        HAL_PIXEL_FORMAT_Y16,
-        160,
-        120,
-        ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
-        HAL_PIXEL_FORMAT_BLOB,
-        maxDepthSamples,
-        1,
-        ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT};
-    ADD_STATIC_ENTRY(
-        ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
-        availableDepthStreamConfigurations,
-        sizeof(availableDepthStreamConfigurations) / sizeof(int32_t));
-
-    static const int64_t availableDepthMinFrameDurations[] = {
-        HAL_PIXEL_FORMAT_Y16,
-        160,
-        120,
-        Sensor::kFrameDurationRange[0],
-        HAL_PIXEL_FORMAT_BLOB,
-        maxDepthSamples,
-        1,
-        Sensor::kFrameDurationRange[0]};
-    ADD_STATIC_ENTRY(ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
-                     availableDepthMinFrameDurations,
-                     sizeof(availableDepthMinFrameDurations) / sizeof(int64_t));
-
-    static const int64_t availableDepthStallDurations[] = {
-        HAL_PIXEL_FORMAT_Y16,
-        160,
-        120,
-        Sensor::kFrameDurationRange[0],
-        HAL_PIXEL_FORMAT_BLOB,
-        maxDepthSamples,
-        1,
-        Sensor::kFrameDurationRange[0]};
-    ADD_STATIC_ENTRY(ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS,
-                     availableDepthStallDurations,
-                     sizeof(availableDepthStallDurations) / sizeof(int64_t));
-
-    uint8_t depthIsExclusive = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE;
-    ADD_STATIC_ENTRY(ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE, &depthIsExclusive, 1);
-  }
-
-  // android.shading
-
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t availableShadingModes[] = {
-        ANDROID_SHADING_MODE_OFF, ANDROID_SHADING_MODE_FAST,
-        ANDROID_SHADING_MODE_HIGH_QUALITY};
-    ADD_STATIC_ENTRY(ANDROID_SHADING_AVAILABLE_MODES, availableShadingModes,
-                     sizeof(availableShadingModes));
-  } else {
-    static const uint8_t availableShadingModes[] = {ANDROID_SHADING_MODE_OFF};
-    ADD_STATIC_ENTRY(ANDROID_SHADING_AVAILABLE_MODES, availableShadingModes,
-                     sizeof(availableShadingModes));
-  }
-
-  // android.request
-
-  static const int32_t maxNumOutputStreams[] = {
-      kMaxRawStreamCount, kMaxProcessedStreamCount, kMaxJpegStreamCount};
-  ADD_STATIC_ENTRY(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, maxNumOutputStreams,
-                   3);
-
-  static const uint8_t maxPipelineDepth = kMaxBufferCount;
-  ADD_STATIC_ENTRY(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &maxPipelineDepth, 1);
-
-  static const int32_t partialResultCount = 1;
-  ADD_STATIC_ENTRY(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount,
-                   /*count*/ 1);
-
-  SortedVector<uint8_t> caps;
-  for (size_t i = 0; i < mCapabilities.size(); i++) {
-    switch (mCapabilities[i]) {
-      case BACKWARD_COMPATIBLE:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
-        break;
-      case MANUAL_SENSOR:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
-        break;
-      case MANUAL_POST_PROCESSING:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);
-        break;
-      case RAW:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
-        break;
-      case PRIVATE_REPROCESSING:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
-        break;
-      case READ_SENSOR_SETTINGS:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS);
-        break;
-      case BURST_CAPTURE:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
-        break;
-      case YUV_REPROCESSING:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
-        break;
-      case DEPTH_OUTPUT:
-        caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
-        break;
-      case CONSTRAINED_HIGH_SPEED_VIDEO:
-        caps.add(
-            ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO);
-        break;
-      default:
-        // Ignore LEVELs
-        break;
-    }
-  }
-  ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, caps.array(),
-                   caps.size());
-
-  // Scan a default request template for included request keys
-  Vector<int32_t> availableRequestKeys;
-  const camera_metadata_t *previewRequest =
-      constructDefaultRequestSettings(CAMERA3_TEMPLATE_PREVIEW);
-  for (size_t i = 0; i < get_camera_metadata_entry_count(previewRequest); i++) {
-    camera_metadata_ro_entry_t entry;
-    get_camera_metadata_ro_entry(previewRequest, i, &entry);
-    availableRequestKeys.add(entry.tag);
-  }
-  ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
-                   availableRequestKeys.array(), availableRequestKeys.size());
-
-  // Add a few more result keys. Must be kept up to date with the various places
-  // that add these
-
-  Vector<int32_t> availableResultKeys(availableRequestKeys);
-  if (hasCapability(BACKWARD_COMPATIBLE)) {
-    availableResultKeys.add(ANDROID_CONTROL_AE_STATE);
-    availableResultKeys.add(ANDROID_CONTROL_AF_STATE);
-    availableResultKeys.add(ANDROID_CONTROL_AWB_STATE);
-    availableResultKeys.add(ANDROID_FLASH_STATE);
-    availableResultKeys.add(ANDROID_LENS_STATE);
-    availableResultKeys.add(ANDROID_LENS_FOCUS_RANGE);
-    availableResultKeys.add(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW);
-    availableResultKeys.add(ANDROID_STATISTICS_SCENE_FLICKER);
-  }
-
-  if (hasCapability(DEPTH_OUTPUT)) {
-    availableResultKeys.add(ANDROID_LENS_POSE_ROTATION);
-    availableResultKeys.add(ANDROID_LENS_POSE_TRANSLATION);
-    availableResultKeys.add(ANDROID_LENS_INTRINSIC_CALIBRATION);
-    availableResultKeys.add(ANDROID_LENS_RADIAL_DISTORTION);
-  }
-
-  availableResultKeys.add(ANDROID_REQUEST_PIPELINE_DEPTH);
-  availableResultKeys.add(ANDROID_SENSOR_TIMESTAMP);
-
-  ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
-                   availableResultKeys.array(), availableResultKeys.size());
-
-  // Needs to be last, to collect all the keys set
-
-  availableCharacteristicsKeys.add(
-      ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
-  info.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
-              availableCharacteristicsKeys);
-
-  mCameraInfo = info.release();
-
-#undef ADD_STATIC_ENTRY
-  return OK;
-}
-
-status_t EmulatedFakeCamera3::process3A(CameraMetadata &settings) {
-  /**
-   * Extract top-level 3A controls
-   */
-  status_t res;
-
-  camera_metadata_entry e;
-
-  e = settings.find(ANDROID_CONTROL_MODE);
-  if (e.count == 0) {
-    ALOGE("%s: No control mode entry!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-  uint8_t controlMode = e.data.u8[0];
-
-  if (controlMode == ANDROID_CONTROL_MODE_OFF) {
-    mAeMode = ANDROID_CONTROL_AE_MODE_OFF;
-    mAfMode = ANDROID_CONTROL_AF_MODE_OFF;
-    mAwbMode = ANDROID_CONTROL_AWB_MODE_OFF;
-    mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
-    mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
-    mAwbState = ANDROID_CONTROL_AWB_STATE_INACTIVE;
-    update3A(settings);
-    return OK;
-  } else if (controlMode == ANDROID_CONTROL_MODE_USE_SCENE_MODE) {
-    if (!hasCapability(BACKWARD_COMPATIBLE)) {
-      ALOGE("%s: Can't use scene mode when BACKWARD_COMPATIBLE not supported!",
-            __FUNCTION__);
-      return BAD_VALUE;
-    }
-
-    e = settings.find(ANDROID_CONTROL_SCENE_MODE);
-    if (e.count == 0) {
-      ALOGE("%s: No scene mode entry!", __FUNCTION__);
-      return BAD_VALUE;
-    }
-    uint8_t sceneMode = e.data.u8[0];
-
-    switch (sceneMode) {
-      case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY:
-        mFacePriority = true;
-        break;
-      default:
-        ALOGE("%s: Emulator doesn't support scene mode %d", __FUNCTION__,
-              sceneMode);
-        return BAD_VALUE;
-    }
-  } else {
-    mFacePriority = false;
-  }
-
-  // controlMode == AUTO or sceneMode = FACE_PRIORITY
-  // Process individual 3A controls
-
-  res = doFakeAE(settings);
-  if (res != OK) return res;
-
-  res = doFakeAF(settings);
-  if (res != OK) return res;
-
-  res = doFakeAWB(settings);
-  if (res != OK) return res;
-
-  update3A(settings);
-  return OK;
-}
-
-status_t EmulatedFakeCamera3::doFakeAE(CameraMetadata &settings) {
-  camera_metadata_entry e;
-
-  e = settings.find(ANDROID_CONTROL_AE_MODE);
-  if (e.count == 0 && hasCapability(BACKWARD_COMPATIBLE)) {
-    ALOGE("%s: No AE mode entry!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-  uint8_t aeMode =
-      (e.count > 0) ? e.data.u8[0] : (uint8_t)ANDROID_CONTROL_AE_MODE_ON;
-  mAeMode = aeMode;
-
-  switch (aeMode) {
-    case ANDROID_CONTROL_AE_MODE_OFF:
-      // AE is OFF
-      mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
-      return OK;
-    case ANDROID_CONTROL_AE_MODE_ON:
-      // OK for AUTO modes
-      break;
-    default:
-      // Mostly silently ignore unsupported modes
-      ALOGV("%s: Emulator doesn't support AE mode %d, assuming ON",
-            __FUNCTION__, aeMode);
-      break;
-  }
-
-  e = settings.find(ANDROID_CONTROL_AE_LOCK);
-  bool aeLocked =
-      (e.count > 0) ? (e.data.u8[0] == ANDROID_CONTROL_AE_LOCK_ON) : false;
-
-  e = settings.find(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER);
-  bool precaptureTrigger = false;
-  if (e.count != 0) {
-    precaptureTrigger =
-        (e.data.u8[0] == ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START);
-  }
-
-  if (precaptureTrigger) {
-    ALOGV("%s: Pre capture trigger = %d", __FUNCTION__, precaptureTrigger);
-  } else if (e.count > 0) {
-    ALOGV("%s: Pre capture trigger was present? %zu", __FUNCTION__, e.count);
-  }
-
-  if (precaptureTrigger || mAeState == ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
-    // Run precapture sequence
-    if (mAeState != ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
-      mAeCounter = 0;
-    }
-
-    if (mFacePriority) {
-      mAeTargetExposureTime = kFacePriorityExposureTime;
-    } else {
-      mAeTargetExposureTime = kNormalExposureTime;
-    }
-
-    if (mAeCounter > kPrecaptureMinFrames &&
-        (mAeTargetExposureTime - mAeCurrentExposureTime) <
-            mAeTargetExposureTime / 10) {
-      // Done with precapture
-      mAeCounter = 0;
-      mAeState = aeLocked ? ANDROID_CONTROL_AE_STATE_LOCKED
-                          : ANDROID_CONTROL_AE_STATE_CONVERGED;
-    } else {
-      // Converge some more
-      mAeCurrentExposureTime +=
-          (mAeTargetExposureTime - mAeCurrentExposureTime) * kExposureTrackRate;
-      mAeCounter++;
-      mAeState = ANDROID_CONTROL_AE_STATE_PRECAPTURE;
-    }
-
-  } else if (!aeLocked) {
-    // Run standard occasional AE scan
-    switch (mAeState) {
-      case ANDROID_CONTROL_AE_STATE_CONVERGED:
-      case ANDROID_CONTROL_AE_STATE_INACTIVE:
-        mAeCounter++;
-        if (mAeCounter > kStableAeMaxFrames) {
-          mAeTargetExposureTime =
-              mFacePriority ? kFacePriorityExposureTime : kNormalExposureTime;
-          float exposureStep = ((double)rand() / RAND_MAX) *
-                                   (kExposureWanderMax - kExposureWanderMin) +
-                               kExposureWanderMin;
-          mAeTargetExposureTime *= std::pow(2, exposureStep);
-          mAeState = ANDROID_CONTROL_AE_STATE_SEARCHING;
-        }
-        break;
-      case ANDROID_CONTROL_AE_STATE_SEARCHING:
-        mAeCurrentExposureTime +=
-            (mAeTargetExposureTime - mAeCurrentExposureTime) *
-            kExposureTrackRate;
-        if (llabs(mAeTargetExposureTime - mAeCurrentExposureTime) <
-            mAeTargetExposureTime / 10) {
-          // Close enough
-          mAeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
-          mAeCounter = 0;
-        }
-        break;
-      case ANDROID_CONTROL_AE_STATE_LOCKED:
-        mAeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
-        mAeCounter = 0;
-        break;
-      default:
-        ALOGE("%s: Emulator in unexpected AE state %d", __FUNCTION__, mAeState);
-        return INVALID_OPERATION;
-    }
-  } else {
-    // AE is locked
-    mAeState = ANDROID_CONTROL_AE_STATE_LOCKED;
-  }
-
-  return OK;
-}
-
-status_t EmulatedFakeCamera3::doFakeAF(CameraMetadata &settings) {
-  camera_metadata_entry e;
-
-  e = settings.find(ANDROID_CONTROL_AF_MODE);
-  if (e.count == 0 && hasCapability(BACKWARD_COMPATIBLE)) {
-    ALOGE("%s: No AF mode entry!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-  uint8_t afMode =
-      (e.count > 0) ? e.data.u8[0] : (uint8_t)ANDROID_CONTROL_AF_MODE_OFF;
-
-  e = settings.find(ANDROID_CONTROL_AF_TRIGGER);
-  typedef camera_metadata_enum_android_control_af_trigger af_trigger_t;
-  af_trigger_t afTrigger;
-  if (e.count != 0) {
-    afTrigger = static_cast<af_trigger_t>(e.data.u8[0]);
-
-    ALOGV("%s: AF trigger set to 0x%x", __FUNCTION__, afTrigger);
-    ALOGV("%s: AF mode is 0x%x", __FUNCTION__, afMode);
-  } else {
-    afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
-  }
-
-  switch (afMode) {
-    case ANDROID_CONTROL_AF_MODE_OFF:
-      mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
-      return OK;
-    case ANDROID_CONTROL_AF_MODE_AUTO:
-    case ANDROID_CONTROL_AF_MODE_MACRO:
-    case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-    case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-      if (!mFacingBack) {
-        ALOGE("%s: Front camera doesn't support AF mode %d", __FUNCTION__,
-              afMode);
-        return BAD_VALUE;
-      }
-      // OK, handle transitions lower on
-      break;
-    default:
-      ALOGE("%s: Emulator doesn't support AF mode %d", __FUNCTION__, afMode);
-      return BAD_VALUE;
-  }
-
-  bool afModeChanged = mAfMode != afMode;
-  mAfMode = afMode;
-
-  /**
-   * Simulate AF triggers. Transition at most 1 state per frame.
-   * - Focusing always succeeds (goes into locked, or PASSIVE_SCAN).
-   */
-
-  bool afTriggerStart = false;
-  bool afTriggerCancel = false;
-  switch (afTrigger) {
-    case ANDROID_CONTROL_AF_TRIGGER_IDLE:
-      break;
-    case ANDROID_CONTROL_AF_TRIGGER_START:
-      afTriggerStart = true;
-      break;
-    case ANDROID_CONTROL_AF_TRIGGER_CANCEL:
-      afTriggerCancel = true;
-      // Cancel trigger always transitions into INACTIVE
-      mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
-
-      ALOGV("%s: AF State transition to STATE_INACTIVE", __FUNCTION__);
-
-      // Stay in 'inactive' until at least next frame
-      return OK;
-    default:
-      ALOGE("%s: Unknown af trigger value %d", __FUNCTION__, afTrigger);
-      return BAD_VALUE;
-  }
-
-  // If we get down here, we're either in an autofocus mode
-  //  or in a continuous focus mode (and no other modes)
-
-  int oldAfState = mAfState;
-  switch (mAfState) {
-    case ANDROID_CONTROL_AF_STATE_INACTIVE:
-      if (afTriggerStart) {
-        switch (afMode) {
-          case ANDROID_CONTROL_AF_MODE_AUTO:
-            // fall-through
-          case ANDROID_CONTROL_AF_MODE_MACRO:
-            mAfState = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
-            break;
-          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-            // fall-through
-          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-            mAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-            break;
-        }
-      } else {
-        // At least one frame stays in INACTIVE
-        if (!afModeChanged) {
-          switch (afMode) {
-            case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-              // fall-through
-            case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-              mAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN;
-              break;
-          }
-        }
-      }
-      break;
-    case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
-      /**
-       * When the AF trigger is activated, the algorithm should finish
-       * its PASSIVE_SCAN if active, and then transition into AF_FOCUSED
-       * or AF_NOT_FOCUSED as appropriate
-       */
-      if (afTriggerStart) {
-        // Randomly transition to focused or not focused
-        if (rand() % 3) {
-          mAfState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
-        } else {
-          mAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-        }
-      }
-      /**
-       * When the AF trigger is not involved, the AF algorithm should
-       * start in INACTIVE state, and then transition into PASSIVE_SCAN
-       * and PASSIVE_FOCUSED states
-       */
-      else if (!afTriggerCancel) {
-        // Randomly transition to passive focus
-        if (rand() % 3 == 0) {
-          mAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
-        }
-      }
-
-      break;
-    case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
-      if (afTriggerStart) {
-        // Randomly transition to focused or not focused
-        if (rand() % 3) {
-          mAfState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
-        } else {
-          mAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-        }
-      }
-      // TODO: initiate passive scan (PASSIVE_SCAN)
-      break;
-    case ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN:
-      // Simulate AF sweep completing instantaneously
-
-      // Randomly transition to focused or not focused
-      if (rand() % 3) {
-        mAfState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
-      } else {
-        mAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-      }
-      break;
-    case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
-      if (afTriggerStart) {
-        switch (afMode) {
-          case ANDROID_CONTROL_AF_MODE_AUTO:
-            // fall-through
-          case ANDROID_CONTROL_AF_MODE_MACRO:
-            mAfState = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
-            break;
-          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-            // fall-through
-          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-            // continuous autofocus => trigger start has no effect
-            break;
-        }
-      }
-      break;
-    case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
-      if (afTriggerStart) {
-        switch (afMode) {
-          case ANDROID_CONTROL_AF_MODE_AUTO:
-            // fall-through
-          case ANDROID_CONTROL_AF_MODE_MACRO:
-            mAfState = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
-            break;
-          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-            // fall-through
-          case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-            // continuous autofocus => trigger start has no effect
-            break;
-        }
-      }
-      break;
-    default:
-      ALOGE("%s: Bad af state %d", __FUNCTION__, mAfState);
-  }
-
-  {
-    char afStateString[100] = {
-        0,
-    };
-    camera_metadata_enum_snprint(ANDROID_CONTROL_AF_STATE, oldAfState,
-                                 afStateString, sizeof(afStateString));
-
-    char afNewStateString[100] = {
-        0,
-    };
-    camera_metadata_enum_snprint(ANDROID_CONTROL_AF_STATE, mAfState,
-                                 afNewStateString, sizeof(afNewStateString));
-    ALOGVV("%s: AF state transitioned from %s to %s", __FUNCTION__,
-           afStateString, afNewStateString);
-  }
-
-  return OK;
-}
-
-status_t EmulatedFakeCamera3::doFakeAWB(CameraMetadata &settings) {
-  camera_metadata_entry e;
-
-  e = settings.find(ANDROID_CONTROL_AWB_MODE);
-  if (e.count == 0 && hasCapability(BACKWARD_COMPATIBLE)) {
-    ALOGE("%s: No AWB mode entry!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-  uint8_t awbMode =
-      (e.count > 0) ? e.data.u8[0] : (uint8_t)ANDROID_CONTROL_AWB_MODE_AUTO;
-
-  // TODO: Add white balance simulation
-
-  e = settings.find(ANDROID_CONTROL_AWB_LOCK);
-  bool awbLocked =
-      (e.count > 0) ? (e.data.u8[0] == ANDROID_CONTROL_AWB_LOCK_ON) : false;
-
-  switch (awbMode) {
-    case ANDROID_CONTROL_AWB_MODE_OFF:
-      mAwbState = ANDROID_CONTROL_AWB_STATE_INACTIVE;
-      break;
-    case ANDROID_CONTROL_AWB_MODE_AUTO:
-    case ANDROID_CONTROL_AWB_MODE_INCANDESCENT:
-    case ANDROID_CONTROL_AWB_MODE_FLUORESCENT:
-    case ANDROID_CONTROL_AWB_MODE_DAYLIGHT:
-    case ANDROID_CONTROL_AWB_MODE_SHADE:
-      // Always magically right, or locked
-      mAwbState = awbLocked ? ANDROID_CONTROL_AWB_STATE_LOCKED
-                            : ANDROID_CONTROL_AWB_STATE_CONVERGED;
-      break;
-    default:
-      ALOGE("%s: Emulator doesn't support AWB mode %d", __FUNCTION__, awbMode);
-      return BAD_VALUE;
-  }
-
-  return OK;
-}
-
-void EmulatedFakeCamera3::update3A(CameraMetadata &settings) {
-  if (mAeMode != ANDROID_CONTROL_AE_MODE_OFF) {
-    settings.update(ANDROID_SENSOR_EXPOSURE_TIME, &mAeCurrentExposureTime, 1);
-    settings.update(ANDROID_SENSOR_SENSITIVITY, &mAeCurrentSensitivity, 1);
-  }
-
-  settings.update(ANDROID_CONTROL_AE_STATE, &mAeState, 1);
-  settings.update(ANDROID_CONTROL_AF_STATE, &mAfState, 1);
-  settings.update(ANDROID_CONTROL_AWB_STATE, &mAwbState, 1);
-
-  uint8_t lensState;
-  switch (mAfState) {
-    case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
-    case ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN:
-      lensState = ANDROID_LENS_STATE_MOVING;
-      break;
-    case ANDROID_CONTROL_AF_STATE_INACTIVE:
-    case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
-    case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
-    case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
-    case ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
-    default:
-      lensState = ANDROID_LENS_STATE_STATIONARY;
-      break;
-  }
-  settings.update(ANDROID_LENS_STATE, &lensState, 1);
-}
-
-void EmulatedFakeCamera3::signalReadoutIdle() {
-  Mutex::Autolock l(mLock);
-  // Need to chek isIdle again because waiting on mLock may have allowed
-  // something to be placed in the in-flight queue.
-  if (mStatus == STATUS_ACTIVE && mReadoutThread->isIdle()) {
-    ALOGV("Now idle");
-    mStatus = STATUS_READY;
-  }
-}
-
-void EmulatedFakeCamera3::onSensorEvent(uint32_t frameNumber, Event e,
-                                        nsecs_t timestamp) {
-  switch (e) {
-    case Sensor::SensorListener::EXPOSURE_START: {
-      ALOGVV("%s: Frame %d: Sensor started exposure at %lld", __FUNCTION__,
-             frameNumber, timestamp);
-      // Trigger shutter notify to framework
-      camera3_notify_msg_t msg;
-      msg.type = CAMERA3_MSG_SHUTTER;
-      msg.message.shutter.frame_number = frameNumber;
-      msg.message.shutter.timestamp = timestamp;
-      sendNotify(&msg);
-      break;
-    }
-    default:
-      ALOGW("%s: Unexpected sensor event %d at %" PRId64, __FUNCTION__, e,
-            timestamp);
-      break;
-  }
-}
-
-EmulatedFakeCamera3::ReadoutThread::ReadoutThread(EmulatedFakeCamera3 *parent)
-    : mParent(parent), mJpegWaiting(false) {}
-
-EmulatedFakeCamera3::ReadoutThread::~ReadoutThread() {
-  for (List<Request>::iterator i = mInFlightQueue.begin();
-       i != mInFlightQueue.end(); i++) {
-    delete i->buffers;
-    delete i->sensorBuffers;
-  }
-}
-
-void EmulatedFakeCamera3::ReadoutThread::queueCaptureRequest(const Request &r) {
-  Mutex::Autolock l(mLock);
-
-  mInFlightQueue.push_back(r);
-  mInFlightSignal.signal();
-}
-
-bool EmulatedFakeCamera3::ReadoutThread::isIdle() {
-  Mutex::Autolock l(mLock);
-  return mInFlightQueue.empty() && !mThreadActive;
-}
-
-status_t EmulatedFakeCamera3::ReadoutThread::waitForReadout() {
-  status_t res;
-  Mutex::Autolock l(mLock);
-  int loopCount = 0;
-  while (mInFlightQueue.size() >= kMaxQueueSize) {
-    res = mInFlightSignal.waitRelative(mLock, kWaitPerLoop);
-    if (res != OK && res != TIMED_OUT) {
-      ALOGE("%s: Error waiting for in-flight queue to shrink", __FUNCTION__);
-      return INVALID_OPERATION;
-    }
-    if (loopCount == kMaxWaitLoops) {
-      ALOGE("%s: Timed out waiting for in-flight queue to shrink",
-            __FUNCTION__);
-      return TIMED_OUT;
-    }
-    loopCount++;
-  }
-  return OK;
-}
-
-bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
-  status_t res;
-
-  ALOGVV("%s: ReadoutThread waiting for request", __FUNCTION__);
-
-  // First wait for a request from the in-flight queue
-
-  if (mCurrentRequest.settings.isEmpty()) {
-    Mutex::Autolock l(mLock);
-    if (mInFlightQueue.empty()) {
-      res = mInFlightSignal.waitRelative(mLock, kWaitPerLoop);
-      if (res == TIMED_OUT) {
-        ALOGVV("%s: ReadoutThread: Timed out waiting for request",
-               __FUNCTION__);
-        return true;
-      } else if (res != NO_ERROR) {
-        ALOGE("%s: Error waiting for capture requests: %d", __FUNCTION__, res);
-        return false;
-      }
-    }
-    mCurrentRequest.frameNumber = mInFlightQueue.begin()->frameNumber;
-    mCurrentRequest.settings.acquire(mInFlightQueue.begin()->settings);
-    mCurrentRequest.buffers = mInFlightQueue.begin()->buffers;
-    mCurrentRequest.sensorBuffers = mInFlightQueue.begin()->sensorBuffers;
-    mInFlightQueue.erase(mInFlightQueue.begin());
-    mInFlightSignal.signal();
-    mThreadActive = true;
-    ALOGVV("%s: Beginning readout of frame %d", __FUNCTION__,
-           mCurrentRequest.frameNumber);
-  }
-
-  // Then wait for it to be delivered from the sensor
-  ALOGVV("%s: ReadoutThread: Wait for frame to be delivered from sensor",
-         __FUNCTION__);
-
-  nsecs_t captureTime;
-  bool gotFrame = mParent->mSensor->waitForNewFrame(kWaitPerLoop, &captureTime);
-  if (!gotFrame) {
-    ALOGVV("%s: ReadoutThread: Timed out waiting for sensor frame",
-           __FUNCTION__);
-    return true;
-  }
-
-  ALOGVV("Sensor done with readout for frame %d, captured at %lld ",
-         mCurrentRequest.frameNumber, captureTime);
-
-  // Check if we need to JPEG encode a buffer, and send it for async
-  // compression if so. Otherwise prepare the buffer for return.
-  bool needJpeg = false;
-  HalBufferVector::iterator buf = mCurrentRequest.buffers->begin();
-  while (buf != mCurrentRequest.buffers->end()) {
-    bool goodBuffer = true;
-    if (buf->stream->format == HAL_PIXEL_FORMAT_BLOB &&
-        buf->stream->data_space != HAL_DATASPACE_DEPTH) {
-      Mutex::Autolock jl(mJpegLock);
-      if (mJpegWaiting) {
-        // This shouldn't happen, because processCaptureRequest should
-        // be stalling until JPEG compressor is free.
-        ALOGE("%s: Already processing a JPEG!", __FUNCTION__);
-        goodBuffer = false;
-      }
-      if (goodBuffer) {
-        // Compressor takes ownership of sensorBuffers here
-        res = mParent->mJpegCompressor->start(mCurrentRequest.sensorBuffers,
-                                              this);
-        goodBuffer = (res == OK);
-      }
-      if (goodBuffer) {
-        needJpeg = true;
-
-        mJpegHalBuffer = *buf;
-        mJpegFrameNumber = mCurrentRequest.frameNumber;
-        mJpegWaiting = true;
-
-        mCurrentRequest.sensorBuffers = NULL;
-        buf = mCurrentRequest.buffers->erase(buf);
-
-        continue;
-      }
-      ALOGE("%s: Error compressing output buffer: %s (%d)", __FUNCTION__,
-            strerror(-res), res);
-      // fallthrough for cleanup
-    }
-    GrallocModule::getInstance().unlock(*(buf->buffer));
-
-    buf->status =
-        goodBuffer ? CAMERA3_BUFFER_STATUS_OK : CAMERA3_BUFFER_STATUS_ERROR;
-    buf->acquire_fence = -1;
-    buf->release_fence = -1;
-
-    ++buf;
-  }  // end while
-
-  // Construct result for all completed buffers and results
-
-  camera3_capture_result result;
-
-  if (mParent->hasCapability(BACKWARD_COMPATIBLE)) {
-    static const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
-    mCurrentRequest.settings.update(ANDROID_STATISTICS_SCENE_FLICKER,
-                                    &sceneFlicker, 1);
-
-    static const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
-    mCurrentRequest.settings.update(ANDROID_FLASH_STATE, &flashState, 1);
-
-    nsecs_t rollingShutterSkew = Sensor::kFrameDurationRange[0];
-    mCurrentRequest.settings.update(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
-                                    &rollingShutterSkew, 1);
-
-    float focusRange[] = {1.0f / 5.0f, 0};  // 5 m to infinity in focus
-    mCurrentRequest.settings.update(ANDROID_LENS_FOCUS_RANGE, focusRange,
-                                    sizeof(focusRange) / sizeof(float));
-  }
-
-  if (mParent->hasCapability(DEPTH_OUTPUT)) {
-    camera_metadata_entry_t entry;
-
-    find_camera_metadata_entry(mParent->mCameraInfo,
-                               ANDROID_LENS_POSE_TRANSLATION, &entry);
-    mCurrentRequest.settings.update(ANDROID_LENS_POSE_TRANSLATION, entry.data.f,
-                                    entry.count);
-
-    find_camera_metadata_entry(mParent->mCameraInfo, ANDROID_LENS_POSE_ROTATION,
-                               &entry);
-    mCurrentRequest.settings.update(ANDROID_LENS_POSE_ROTATION, entry.data.f,
-                                    entry.count);
-
-    find_camera_metadata_entry(mParent->mCameraInfo,
-                               ANDROID_LENS_INTRINSIC_CALIBRATION, &entry);
-    mCurrentRequest.settings.update(ANDROID_LENS_INTRINSIC_CALIBRATION,
-                                    entry.data.f, entry.count);
-
-    find_camera_metadata_entry(mParent->mCameraInfo,
-                               ANDROID_LENS_RADIAL_DISTORTION, &entry);
-    mCurrentRequest.settings.update(ANDROID_LENS_RADIAL_DISTORTION,
-                                    entry.data.f, entry.count);
-  }
-
-  mCurrentRequest.settings.update(ANDROID_SENSOR_TIMESTAMP, &captureTime, 1);
-
-  // JPEGs take a stage longer
-  const uint8_t pipelineDepth =
-      needJpeg ? kMaxBufferCount : kMaxBufferCount - 1;
-  mCurrentRequest.settings.update(ANDROID_REQUEST_PIPELINE_DEPTH,
-                                  &pipelineDepth, 1);
-
-  result.frame_number = mCurrentRequest.frameNumber;
-  result.result = mCurrentRequest.settings.getAndLock();
-  result.num_output_buffers = mCurrentRequest.buffers->size();
-  result.output_buffers = mCurrentRequest.buffers->array();
-  result.input_buffer = nullptr;
-  result.partial_result = 1;
-
-  // Go idle if queue is empty, before sending result
-  bool signalIdle = false;
-  {
-    Mutex::Autolock l(mLock);
-    if (mInFlightQueue.empty()) {
-      mThreadActive = false;
-      signalIdle = true;
-    }
-  }
-  if (signalIdle) mParent->signalReadoutIdle();
-
-  // Send it off to the framework
-  ALOGVV("%s: ReadoutThread: Send result to framework", __FUNCTION__);
-  mParent->sendCaptureResult(&result);
-
-  // Clean up
-  mCurrentRequest.settings.unlock(result.result);
-
-  delete mCurrentRequest.buffers;
-  mCurrentRequest.buffers = NULL;
-  if (!needJpeg) {
-    delete mCurrentRequest.sensorBuffers;
-    mCurrentRequest.sensorBuffers = NULL;
-  }
-  mCurrentRequest.settings.clear();
-
-  return true;
-}
-
-void EmulatedFakeCamera3::ReadoutThread::onJpegDone(
-    const StreamBuffer &jpegBuffer, bool success) {
-  Mutex::Autolock jl(mJpegLock);
-
-  GrallocModule::getInstance().unlock(*(jpegBuffer.buffer));
-
-  mJpegHalBuffer.status =
-      success ? CAMERA3_BUFFER_STATUS_OK : CAMERA3_BUFFER_STATUS_ERROR;
-  mJpegHalBuffer.acquire_fence = -1;
-  mJpegHalBuffer.release_fence = -1;
-  mJpegWaiting = false;
-
-  camera3_capture_result result;
-
-  result.frame_number = mJpegFrameNumber;
-  result.result = NULL;
-  result.num_output_buffers = 1;
-  result.output_buffers = &mJpegHalBuffer;
-  result.input_buffer = nullptr;
-  result.partial_result = 0;
-
-  if (!success) {
-    ALOGE(
-        "%s: Compression failure, returning error state buffer to"
-        " framework",
-        __FUNCTION__);
-  } else {
-    ALOGV("%s: Compression complete, returning buffer to framework",
-          __FUNCTION__);
-  }
-
-  mParent->sendCaptureResult(&result);
-}
-
-void EmulatedFakeCamera3::ReadoutThread::onJpegInputDone(
-    const StreamBuffer & /*inputBuffer*/) {
-  // Should never get here, since the input buffer has to be returned
-  // by end of processCaptureRequest
-  ALOGE("%s: Unexpected input buffer from JPEG compressor!", __FUNCTION__);
-}
-
-};  // namespace android
diff --git a/guest/hals/camera/EmulatedFakeCamera3.h b/guest/hals/camera/EmulatedFakeCamera3.h
deleted file mode 100644
index d67662a..0000000
--- a/guest/hals/camera/EmulatedFakeCamera3.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA3_H
-#define HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA3_H
-
-/**
- * Contains declaration of a class EmulatedCamera that encapsulates
- * functionality of a fake camera that implements version 3 of the camera device
- * interace.
- */
-
-#include <CameraMetadata.h>
-using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
-
-#include <utils/List.h>
-#include <utils/Mutex.h>
-#include <utils/SortedVector.h>
-#include "EmulatedCamera3.h"
-#include "fake-pipeline2/Base.h"
-#include "fake-pipeline2/JpegCompressor.h"
-#include "fake-pipeline2/Sensor.h"
-
-namespace android {
-
-/**
- * Encapsulates functionality for a v3 HAL camera which produces synthetic data.
- *
- * Note that EmulatedCameraFactory instantiates an object of this class just
- * once, when EmulatedCameraFactory instance gets constructed. Connection to /
- * disconnection from the actual camera device is handled by calls to
- * connectDevice(), and closeCamera() methods of this class that are invoked in
- * response to hw_module_methods_t::open, and camera_device::close callbacks.
- */
-class EmulatedFakeCamera3 : public EmulatedCamera3,
-                            private Sensor::SensorListener {
- public:
-  EmulatedFakeCamera3(int cameraId, bool facingBack,
-                      struct hw_module_t *module);
-
-  virtual ~EmulatedFakeCamera3();
-
-  /****************************************************************************
-   * EmulatedCamera3 virtual overrides
-   ***************************************************************************/
-
- public:
-  virtual status_t Initialize(const cvd::CameraDefinition &params);
-
-  /****************************************************************************
-   * Camera module API and generic hardware device API implementation
-   ***************************************************************************/
-
- public:
-  virtual status_t connectCamera(hw_device_t **device);
-
-  virtual status_t closeCamera();
-
-  virtual status_t getCameraInfo(struct camera_info *info);
-
-  virtual status_t setTorchMode(bool enabled);
-
-  /****************************************************************************
-   * EmulatedCamera3 abstract API implementation
-   ***************************************************************************/
-
- protected:
-  virtual status_t configureStreams(camera3_stream_configuration *streamList);
-
-  virtual status_t registerStreamBuffers(
-      const camera3_stream_buffer_set *bufferSet);
-
-  virtual const camera_metadata_t *constructDefaultRequestSettings(int type);
-
-  virtual status_t processCaptureRequest(camera3_capture_request *request);
-
-  virtual status_t flush();
-
-  /** Debug methods */
-
-  virtual void dump(int fd);
-
- private:
-  /**
-   * Get the requested capability set for this camera
-   */
-  status_t getCameraCapabilities();
-
-  bool hasCapability(AvailableCapabilities cap);
-
-  /**
-   * Build the static info metadata buffer for this device
-   */
-  status_t constructStaticInfo(const cvd::CameraDefinition &params);
-
-  /**
-   * Run the fake 3A algorithms as needed. May override/modify settings
-   * values.
-   */
-  status_t process3A(CameraMetadata &settings);
-
-  status_t doFakeAE(CameraMetadata &settings);
-  status_t doFakeAF(CameraMetadata &settings);
-  status_t doFakeAWB(CameraMetadata &settings);
-  void update3A(CameraMetadata &settings);
-
-  /** Signal from readout thread that it doesn't have anything to do */
-  void signalReadoutIdle();
-
-  /** Handle interrupt events from the sensor */
-  void onSensorEvent(uint32_t frameNumber, Event e, nsecs_t timestamp);
-
-  /****************************************************************************
-   * Static configuration information
-   ***************************************************************************/
- private:
-  static const uint32_t kMaxRawStreamCount = 1;
-  static const uint32_t kMaxProcessedStreamCount = 3;
-  static const uint32_t kMaxJpegStreamCount = 1;
-  static const uint32_t kMaxReprocessStreamCount = 2;
-  static const uint32_t kMaxBufferCount = 4;
-  // We need a positive stream ID to distinguish external buffers from
-  // sensor-generated buffers which use a nonpositive ID. Otherwise, HAL3 has
-  // no concept of a stream id.
-  static const uint32_t kGenericStreamId = 1;
-  static const int32_t kAvailableFormats[];
-
-  static const int64_t kSyncWaitTimeout = 10000000;   // 10 ms
-  static const int32_t kMaxSyncTimeoutCount = 1000;   // 1000 kSyncWaitTimeouts
-  static const uint32_t kFenceTimeoutMs = 2000;       // 2 s
-  static const nsecs_t kJpegTimeoutNs = 5000000000l;  // 5 s
-
-  /****************************************************************************
-   * Data members.
-   ***************************************************************************/
-
-  /* HAL interface serialization lock. */
-  Mutex mLock;
-
-  /* Facing back (true) or front (false) switch. */
-  bool mFacingBack;
-  int32_t mSensorWidth;
-  int32_t mSensorHeight;
-
-  SortedVector<AvailableCapabilities> mCapabilities;
-
-  /**
-   * Cache for default templates. Once one is requested, the pointer must be
-   * valid at least until close() is called on the device
-   */
-  camera_metadata_t *mDefaultTemplates[CAMERA3_TEMPLATE_COUNT];
-
-  /**
-   * Private stream information, stored in camera3_stream_t->priv.
-   */
-  struct PrivateStreamInfo {
-    bool alive;
-  };
-
-  // Shortcut to the input stream
-  camera3_stream_t *mInputStream;
-
-  typedef List<camera3_stream_t *> StreamList;
-  typedef List<camera3_stream_t *>::iterator StreamIterator;
-  typedef Vector<camera3_stream_buffer> HalBufferVector;
-
-  // All streams, including input stream
-  StreamList mStreams;
-
-  // Cached settings from latest submitted request
-  CameraMetadata mPrevSettings;
-
-  /** Fake hardware interfaces */
-  sp<Sensor> mSensor;
-  sp<JpegCompressor> mJpegCompressor;
-  friend class JpegCompressor;
-
-  /** Processing thread for sending out results */
-
-  class ReadoutThread : public Thread, private JpegCompressor::JpegListener {
-   public:
-    ReadoutThread(EmulatedFakeCamera3 *parent);
-    ~ReadoutThread();
-
-    struct Request {
-      uint32_t frameNumber;
-      CameraMetadata settings;
-      HalBufferVector *buffers;
-      Buffers *sensorBuffers;
-    };
-
-    /**
-     * Interface to parent class
-     */
-
-    // Place request in the in-flight queue to wait for sensor capture
-    void queueCaptureRequest(const Request &r);
-
-    // Test if the readout thread is idle (no in-flight requests, not
-    // currently reading out anything
-    bool isIdle();
-
-    // Wait until isIdle is true
-    status_t waitForReadout();
-
-   private:
-    static const nsecs_t kWaitPerLoop = 10000000L;  // 10 ms
-    static const nsecs_t kMaxWaitLoops = 1000;
-    static const size_t kMaxQueueSize = 2;
-
-    EmulatedFakeCamera3 *mParent;
-    Mutex mLock;
-
-    List<Request> mInFlightQueue;
-    Condition mInFlightSignal;
-    bool mThreadActive;
-
-    virtual bool threadLoop();
-
-    // Only accessed by threadLoop
-
-    Request mCurrentRequest;
-
-    // Jpeg completion callbacks
-
-    Mutex mJpegLock;
-    bool mJpegWaiting;
-    camera3_stream_buffer mJpegHalBuffer;
-    uint32_t mJpegFrameNumber;
-    virtual void onJpegDone(const StreamBuffer &jpegBuffer, bool success);
-    virtual void onJpegInputDone(const StreamBuffer &inputBuffer);
-  };
-
-  sp<ReadoutThread> mReadoutThread;
-
-  /** Fake 3A constants */
-
-  static const nsecs_t kNormalExposureTime;
-  static const nsecs_t kFacePriorityExposureTime;
-  static const int kNormalSensitivity;
-  static const int kFacePrioritySensitivity;
-  // Rate of converging AE to new target value, as fraction of difference
-  // between current and target value.
-  static const float kExposureTrackRate;
-  // Minimum duration for precapture state. May be longer if slow to converge
-  // to target exposure
-  static const int kPrecaptureMinFrames;
-  // How often to restart AE 'scanning'
-  static const int kStableAeMaxFrames;
-  // Maximum stop below 'normal' exposure time that we'll wander to while
-  // pretending to converge AE. In powers of 2. (-2 == 1/4 as bright)
-  static const float kExposureWanderMin;
-  // Maximum stop above 'normal' exposure time that we'll wander to while
-  // pretending to converge AE. In powers of 2. (2 == 4x as bright)
-  static const float kExposureWanderMax;
-
-  /** Fake 3A state */
-
-  uint8_t mControlMode;
-  bool mFacePriority;
-  uint8_t mAeState;
-  uint8_t mAfState;
-  uint8_t mAwbState;
-  uint8_t mAeMode;
-  uint8_t mAfMode;
-  uint8_t mAwbMode;
-
-  int mAeCounter;
-  nsecs_t mAeCurrentExposureTime;
-  nsecs_t mAeTargetExposureTime;
-  int mAeCurrentSensitivity;
-};
-
-}  // namespace android
-
-#endif  // HW_EMULATOR_CAMERA_EMULATED_CAMERA3_H
diff --git a/guest/hals/camera/EmulatedFakeCameraDevice.cpp b/guest/hals/camera/EmulatedFakeCameraDevice.cpp
deleted file mode 100644
index a354e69..0000000
--- a/guest/hals/camera/EmulatedFakeCameraDevice.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class EmulatedFakeCameraDevice that encapsulates
- * fake camera device.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_FakeDevice"
-#include "EmulatedFakeCameraDevice.h"
-#include <log/log.h>
-#include "EmulatedFakeCamera.h"
-
-namespace android {
-
-EmulatedFakeCameraDevice::EmulatedFakeCameraDevice(
-    EmulatedFakeCamera* camera_hal)
-    : EmulatedCameraDevice(camera_hal),
-      mBlackYUV(kBlack32),
-      mWhiteYUV(kWhite32),
-      mRedYUV(kRed8),
-      mGreenYUV(kGreen8),
-      mBlueYUV(kBlue8),
-      mLastRedrawn(0),
-      mCheckX(0),
-      mCheckY(0),
-      mCcounter(0)
-#if EFCD_ROTATE_FRAME
-      ,
-      mLastRotatedAt(0),
-      mCurrentFrameType(0),
-      mCurrentColor(&mWhiteYUV)
-#endif  // EFCD_ROTATE_FRAME
-{
-  // Makes the image with the original exposure compensation darker.
-  // So the effects of changing the exposure compensation can be seen.
-  mBlackYUV.Y = mBlackYUV.Y / 2;
-  mWhiteYUV.Y = mWhiteYUV.Y / 2;
-  mRedYUV.Y = mRedYUV.Y / 2;
-  mGreenYUV.Y = mGreenYUV.Y / 2;
-  mBlueYUV.Y = mBlueYUV.Y / 2;
-}
-
-EmulatedFakeCameraDevice::~EmulatedFakeCameraDevice() {}
-
-/****************************************************************************
- * Emulated camera device abstract interface implementation.
- ***************************************************************************/
-
-status_t EmulatedFakeCameraDevice::connectDevice() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isInitialized()) {
-    ALOGE("%s: Fake camera device is not initialized.", __FUNCTION__);
-    return EINVAL;
-  }
-  if (isConnected()) {
-    ALOGW("%s: Fake camera device is already connected.", __FUNCTION__);
-    return NO_ERROR;
-  }
-
-  /* There is no device to connect to. */
-  mState = ECDS_CONNECTED;
-
-  return NO_ERROR;
-}
-
-status_t EmulatedFakeCameraDevice::disconnectDevice() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isConnected()) {
-    ALOGW("%s: Fake camera device is already disconnected.", __FUNCTION__);
-    return NO_ERROR;
-  }
-  if (isStarted()) {
-    ALOGE("%s: Cannot disconnect from the started device.", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* There is no device to disconnect from. */
-  mState = ECDS_INITIALIZED;
-
-  return NO_ERROR;
-}
-
-status_t EmulatedFakeCameraDevice::startDevice(int width, int height,
-                                               uint32_t pix_fmt, int fps) {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isConnected()) {
-    ALOGE("%s: Fake camera device is not connected.", __FUNCTION__);
-    return EINVAL;
-  }
-  if (isStarted()) {
-    ALOGE("%s: Fake camera device is already started.", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* Initialize the base class. */
-  const status_t res =
-      EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt, fps);
-  if (res == NO_ERROR) {
-    /* Calculate U/V panes inside the framebuffer. */
-    switch (mPixelFormat) {
-      case V4L2_PIX_FMT_YVU420:
-        mFrameV = mCurrentFrame + mTotalPixels;
-        mFrameU = mFrameU + mTotalPixels / 4;
-        mUVStep = 1;
-        mUVTotalNum = mTotalPixels / 4;
-        break;
-
-      case V4L2_PIX_FMT_YUV420:
-        mFrameU = mCurrentFrame + mTotalPixels;
-        mFrameV = mFrameU + mTotalPixels / 4;
-        mUVStep = 1;
-        mUVTotalNum = mTotalPixels / 4;
-        break;
-
-      case V4L2_PIX_FMT_NV21:
-        /* Interleaved UV pane, V first. */
-        mFrameV = mCurrentFrame + mTotalPixels;
-        mFrameU = mFrameV + 1;
-        mUVStep = 2;
-        mUVTotalNum = mTotalPixels / 4;
-        break;
-
-      case V4L2_PIX_FMT_NV12:
-        /* Interleaved UV pane, U first. */
-        mFrameU = mCurrentFrame + mTotalPixels;
-        mFrameV = mFrameU + 1;
-        mUVStep = 2;
-        mUVTotalNum = mTotalPixels / 4;
-        break;
-
-      default:
-        ALOGE("%s: Unknown pixel format %.4s", __FUNCTION__,
-              reinterpret_cast<const char*>(&mPixelFormat));
-        return EINVAL;
-    }
-    /* Number of items in a single row inside U/V panes. */
-    mUVInRow = (width / 2) * mUVStep;
-    mState = ECDS_STARTED;
-    mCurFrameTimestamp = 0;
-  } else {
-    ALOGE("%s: commonStartDevice failed", __FUNCTION__);
-  }
-
-  return res;
-}
-
-status_t EmulatedFakeCameraDevice::stopDevice() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isStarted()) {
-    ALOGW("%s: Fake camera device is not started.", __FUNCTION__);
-    return NO_ERROR;
-  }
-
-  mFrameU = mFrameV = NULL;
-  EmulatedCameraDevice::commonStopDevice();
-  mState = ECDS_CONNECTED;
-
-  return NO_ERROR;
-}
-
-/****************************************************************************
- * Worker thread management overrides.
- ***************************************************************************/
-
-bool EmulatedFakeCameraDevice::inWorkerThread() {
-  /* Wait till FPS timeout expires, or thread exit message is received. */
-  WorkerThread::SelectRes res =
-      getWorkerThread()->Select(-1, 1000000 / (mTargetFps / 1000));
-  if (res == WorkerThread::EXIT_THREAD) {
-    ALOGV("%s: Worker thread has been terminated.", __FUNCTION__);
-    return false;
-  }
-
-  /* Lets see if we need to generate a new frame. */
-  if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRedrawn) >= mRedrawAfter) {
-    /*
-     * Time to generate a new frame.
-     */
-
-#if EFCD_ROTATE_FRAME
-    const int frame_type = rotateFrame();
-    switch (frame_type) {
-      case 0:
-        drawCheckerboard();
-        break;
-      case 1:
-        drawStripes();
-        break;
-      case 2:
-        drawSolid(mCurrentColor);
-        break;
-    }
-#else
-    /* Draw the checker board. */
-    drawCheckerboard();
-
-#endif  // EFCD_ROTATE_FRAME
-
-    // mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-    mCurFrameTimestamp += (1000000000 / (mTargetFps / 1000));
-    /* Timestamp the current frame, and notify the camera HAL about new frame.
-     */
-    mLastRedrawn = systemTime(SYSTEM_TIME_MONOTONIC);
-    mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this);
-  }
-
-  return true;
-}
-
-/****************************************************************************
- * Fake camera device private API
- ***************************************************************************/
-
-void EmulatedFakeCameraDevice::drawCheckerboard() {
-  const int size = mFrameWidth / 10;
-  bool black = true;
-
-  if (size == 0) {
-    // When this happens, it happens at a very high rate,
-    //     so don't log any messages and just return.
-    return;
-  }
-
-  if ((mCheckX / size) & 1) black = false;
-  if ((mCheckY / size) & 1) black = !black;
-
-  int county = mCheckY % size;
-  int checkxremainder = mCheckX % size;
-  uint8_t* Y = mCurrentFrame;
-  uint8_t* U_pos = mFrameU;
-  uint8_t* V_pos = mFrameV;
-  uint8_t* U = U_pos;
-  uint8_t* V = V_pos;
-
-  YUVPixel adjustedWhite = YUVPixel(mWhiteYUV);
-  changeWhiteBalance(adjustedWhite.Y, adjustedWhite.U, adjustedWhite.V);
-
-  for (int y = 0; y < mFrameHeight; y++) {
-    int countx = checkxremainder;
-    bool current = black;
-    for (int x = 0; x < mFrameWidth; x += 2) {
-      if (current) {
-        mBlackYUV.get(Y, U, V);
-      } else {
-        adjustedWhite.get(Y, U, V);
-      }
-      *Y = changeExposure(*Y);
-      Y[1] = *Y;
-      Y += 2;
-      U += mUVStep;
-      V += mUVStep;
-      countx += 2;
-      if (countx >= size) {
-        countx = 0;
-        current = !current;
-      }
-    }
-    if (y & 0x1) {
-      U_pos = U;
-      V_pos = V;
-    } else {
-      U = U_pos;
-      V = V_pos;
-    }
-    if (county++ >= size) {
-      county = 0;
-      black = !black;
-    }
-  }
-  mCheckX += 3;
-  mCheckY++;
-
-  /* Run the square. */
-  int sqx = ((mCcounter * 3) & 255);
-  if (sqx > 128) sqx = 255 - sqx;
-  int sqy = ((mCcounter * 5) & 255);
-  if (sqy > 128) sqy = 255 - sqy;
-  const int sqsize = mFrameWidth / 10;
-  drawSquare(sqx * sqsize / 32, sqy * sqsize / 32, (sqsize * 5) >> 1,
-             (mCcounter & 0x100) ? &mRedYUV : &mGreenYUV);
-  mCcounter++;
-}
-
-void EmulatedFakeCameraDevice::drawSquare(int x, int y, int size,
-                                          const YUVPixel* color) {
-  const int square_xstop = std::min(mFrameWidth, x + size);
-  const int square_ystop = std::min(mFrameHeight, y + size);
-  uint8_t* Y_pos = mCurrentFrame + y * mFrameWidth + x;
-
-  YUVPixel adjustedColor = *color;
-  changeWhiteBalance(adjustedColor.Y, adjustedColor.U, adjustedColor.V);
-
-  // Draw the square.
-  for (; y < square_ystop; y++) {
-    const int iUV = (y / 2) * mUVInRow + (x / 2) * mUVStep;
-    uint8_t* sqU = mFrameU + iUV;
-    uint8_t* sqV = mFrameV + iUV;
-    uint8_t* sqY = Y_pos;
-    for (int i = x; i < square_xstop; i += 2) {
-      adjustedColor.get(sqY, sqU, sqV);
-      *sqY = changeExposure(*sqY);
-      sqY[1] = *sqY;
-      sqY += 2;
-      sqU += mUVStep;
-      sqV += mUVStep;
-    }
-    Y_pos += mFrameWidth;
-  }
-}
-
-#if EFCD_ROTATE_FRAME
-
-void EmulatedFakeCameraDevice::drawSolid(YUVPixel* color) {
-  YUVPixel adjustedColor = *color;
-  changeWhiteBalance(adjustedColor.Y, adjustedColor.U, adjustedColor.V);
-
-  /* All Ys are the same. */
-  memset(mCurrentFrame, changeExposure(adjustedColor.Y), mTotalPixels);
-
-  /* Fill U, and V panes. */
-  uint8_t* U = mFrameU;
-  uint8_t* V = mFrameV;
-  for (int k = 0; k < mUVTotalNum; k++, U += mUVStep, V += mUVStep) {
-    *U = color->U;
-    *V = color->V;
-  }
-}
-
-void EmulatedFakeCameraDevice::drawStripes() {
-  /* Divide frame into 4 stripes. */
-  const int change_color_at = mFrameHeight / 4;
-  const int each_in_row = mUVInRow / mUVStep;
-  uint8_t* pY = mCurrentFrame;
-  for (int y = 0; y < mFrameHeight; y++, pY += mFrameWidth) {
-    /* Select the color. */
-    YUVPixel* color;
-    const int color_index = y / change_color_at;
-    if (color_index == 0) {
-      /* White stripe on top. */
-      color = &mWhiteYUV;
-    } else if (color_index == 1) {
-      /* Then the red stripe. */
-      color = &mRedYUV;
-    } else if (color_index == 2) {
-      /* Then the green stripe. */
-      color = &mGreenYUV;
-    } else {
-      /* And the blue stripe at the bottom. */
-      color = &mBlueYUV;
-    }
-    changeWhiteBalance(color->Y, color->U, color->V);
-
-    /* All Ys at the row are the same. */
-    memset(pY, changeExposure(color->Y), mFrameWidth);
-
-    /* Offset of the current row inside U/V panes. */
-    const int uv_off = (y / 2) * mUVInRow;
-    /* Fill U, and V panes. */
-    uint8_t* U = mFrameU + uv_off;
-    uint8_t* V = mFrameV + uv_off;
-    for (int k = 0; k < each_in_row; k++, U += mUVStep, V += mUVStep) {
-      *U = color->U;
-      *V = color->V;
-    }
-  }
-}
-
-int EmulatedFakeCameraDevice::rotateFrame() {
-  if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRotatedAt) >= mRotateFreq) {
-    mLastRotatedAt = systemTime(SYSTEM_TIME_MONOTONIC);
-    mCurrentFrameType++;
-    if (mCurrentFrameType > 2) {
-      mCurrentFrameType = 0;
-    }
-    if (mCurrentFrameType == 2) {
-      ALOGD("********** Rotated to the SOLID COLOR frame **********");
-      /* Solid color: lets rotate color too. */
-      if (mCurrentColor == &mWhiteYUV) {
-        ALOGD("----- Painting a solid RED frame -----");
-        mCurrentColor = &mRedYUV;
-      } else if (mCurrentColor == &mRedYUV) {
-        ALOGD("----- Painting a solid GREEN frame -----");
-        mCurrentColor = &mGreenYUV;
-      } else if (mCurrentColor == &mGreenYUV) {
-        ALOGD("----- Painting a solid BLUE frame -----");
-        mCurrentColor = &mBlueYUV;
-      } else {
-        /* Back to white. */
-        ALOGD("----- Painting a solid WHITE frame -----");
-        mCurrentColor = &mWhiteYUV;
-      }
-    } else if (mCurrentFrameType == 0) {
-      ALOGD("********** Rotated to the CHECKERBOARD frame **********");
-    } else if (mCurrentFrameType == 1) {
-      ALOGD("********** Rotated to the STRIPED frame **********");
-    }
-  }
-
-  return mCurrentFrameType;
-}
-
-#endif  // EFCD_ROTATE_FRAME
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedFakeCameraDevice.h b/guest/hals/camera/EmulatedFakeCameraDevice.h
deleted file mode 100644
index 096d1bc..0000000
--- a/guest/hals/camera/EmulatedFakeCameraDevice.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H
-#define HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H
-
-/*
- * Contains declaration of a class EmulatedFakeCameraDevice that encapsulates
- * a fake camera device.
- */
-
-#include "Converters.h"
-#include "EmulatedCameraDevice.h"
-
-/* This is used for debugging format / conversion issues. If EFCD_ROTATE_FRAME
- * is set to 0, the frame content will be always the "checkerboard". Otherwise,
- * if EFCD_ROTATE_FRAME is set to a non-zero value, the frame content will
- * "rotate" from a "checkerboard" frame to a "white/red/green/blue stripes"
- * frame, to a "white/red/green/blue" frame. Frame content rotation helps
- * finding bugs in format conversions.
- */
-#define EFCD_ROTATE_FRAME 0
-
-namespace android {
-
-class EmulatedFakeCamera;
-
-/* Encapsulates a fake camera device.
- * Fake camera device emulates a camera device by providing frames containing
- * a black and white checker board, moving diagonally towards the 0,0 corner.
- * There is also a green, or red square that bounces inside the frame, changing
- * its color when bouncing off the 0,0 corner.
- */
-class EmulatedFakeCameraDevice : public EmulatedCameraDevice {
- public:
-  /* Constructs EmulatedFakeCameraDevice instance. */
-  explicit EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_hal);
-
-  /* Destructs EmulatedFakeCameraDevice instance. */
-  ~EmulatedFakeCameraDevice();
-
-  /***************************************************************************
-   * Emulated camera device abstract interface implementation.
-   * See declarations of these methods in EmulatedCameraDevice class for
-   * information on each of these methods.
-   **************************************************************************/
-
- public:
-  /* Connects to the camera device.
-   * Since there is no real device to connect to, this method does nothing,
-   * but changes the state.
-   */
-  status_t connectDevice();
-
-  /* Disconnects from the camera device.
-   * Since there is no real device to disconnect from, this method does
-   * nothing, but changes the state.
-   */
-  status_t disconnectDevice();
-
-  /* Starts the camera device. */
-  status_t startDevice(int width, int height, uint32_t pix_fmt, int fps);
-
-  /* Stops the camera device. */
-  status_t stopDevice();
-
-  /* Gets current preview fame into provided buffer. */
-  status_t getPreviewFrame(void* /*buffer*/) { return OK; }
-
-  /***************************************************************************
-   * Worker thread management overrides.
-   * See declarations of these methods in EmulatedCameraDevice class for
-   * information on each of these methods.
-   **************************************************************************/
-
- protected:
-  /* Implementation of the worker thread routine.
-   * This method simply sleeps for a period of time defined by the FPS property
-   * of the fake camera (simulating frame frequency), and then calls emulated
-   * camera's onNextFrameAvailable method.
-   */
-  bool inWorkerThread();
-
-  /****************************************************************************
-   * Fake camera device private API
-   ***************************************************************************/
-
- private:
-  /* Draws a black and white checker board in the current frame buffer. */
-  void drawCheckerboard();
-
-  /* Draws a square of the given color in the current frame buffer.
-   * Param:
-   *  x, y - Coordinates of the top left corner of the square in the buffer.
-   *  size - Size of the square's side.
-   *  color - Square's color.
-   */
-  void drawSquare(int x, int y, int size, const YUVPixel* color);
-
-#if EFCD_ROTATE_FRAME
-  void drawSolid(YUVPixel* color);
-  void drawStripes();
-  int rotateFrame();
-#endif  // EFCD_ROTATE_FRAME
-
-  /****************************************************************************
-   * Fake camera device data members
-   ***************************************************************************/
-
- private:
-  /*
-   * Pixel colors in YUV format used when drawing the checker board.
-   */
-
-  YUVPixel mBlackYUV;
-  YUVPixel mWhiteYUV;
-  YUVPixel mRedYUV;
-  YUVPixel mGreenYUV;
-  YUVPixel mBlueYUV;
-
-  /* Last time the frame has been redrawn. */
-  nsecs_t mLastRedrawn;
-
-  /*
-   * Precalculated values related to U/V panes.
-   */
-
-  /* U pane inside the framebuffer. */
-  uint8_t* mFrameU;
-
-  /* V pane inside the framebuffer. */
-  uint8_t* mFrameV;
-
-  /* Defines byte distance between adjacent U, and V values. */
-  int mUVStep;
-
-  /* Defines number of Us and Vs in a row inside the U/V panes.
-   * Note that if U/V panes are interleaved, this value reflects the total
-   * number of both, Us and Vs in a single row in the interleaved UV pane. */
-  int mUVInRow;
-
-  /* Total number of each, U, and V elements in the framebuffer. */
-  int mUVTotalNum;
-
-  /*
-   * Checkerboard drawing related stuff
-   */
-
-  int mCheckX;
-  int mCheckY;
-  int mCcounter;
-
-  /* Defines time (in nanoseconds) between redrawing the checker board.
-   * We will redraw the checker board every 15 milliseconds. */
-  static const nsecs_t mRedrawAfter = 15000000LL;
-
-#if EFCD_ROTATE_FRAME
-  /* Frame rotation frequency in nanosec (currently - 3 sec) */
-  static const nsecs_t mRotateFreq = 3000000000LL;
-
-  /* Last time the frame has rotated. */
-  nsecs_t mLastRotatedAt;
-
-  /* Type of the frame to display in the current rotation:
-   *  0 - Checkerboard.
-   *  1 - White/Red/Green/Blue horisontal stripes
-   *  2 - Solid color. */
-  int mCurrentFrameType;
-
-  /* Color to use to paint the solid color frame. Colors will rotate between
-   * white, red, gree, and blue each time rotation comes to the solid color
-   * frame. */
-  YUVPixel* mCurrentColor;
-#endif  // EFCD_ROTATE_FRAME
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H */
diff --git a/guest/hals/camera/EmulatedQemuCamera.cpp b/guest/hals/camera/EmulatedQemuCamera.cpp
deleted file mode 100644
index 99c4797..0000000
--- a/guest/hals/camera/EmulatedQemuCamera.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class EmulatedQemuCamera that encapsulates
- * functionality of an emulated camera connected to the host.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_QemuCamera"
-#include "EmulatedQemuCamera.h"
-#include <log/log.h>
-#include "EmulatedCameraFactory.h"
-
-namespace android {
-
-EmulatedQemuCamera::EmulatedQemuCamera(int cameraId, struct hw_module_t* module)
-    : EmulatedCamera(cameraId, module), mQemuCameraDevice(this) {}
-
-EmulatedQemuCamera::~EmulatedQemuCamera() {}
-
-/****************************************************************************
- * EmulatedCamera virtual overrides.
- ***************************************************************************/
-
-status_t EmulatedQemuCamera::Initialize(const char* device_name,
-                                        const char* frame_dims,
-                                        const char* facing_dir) {
-  ALOGV("%s:\n   Name=%s\n   Facing '%s'\n   Dimensions=%s", __FUNCTION__,
-        device_name, facing_dir, frame_dims);
-  /* Save dimensions. */
-  mFrameDims = frame_dims;
-
-  /* Initialize camera device. */
-  status_t res = mQemuCameraDevice.Initialize(device_name);
-  if (res != NO_ERROR) {
-    return res;
-  }
-
-  /* Initialize base class. */
-  res = EmulatedCamera::Initialize();
-  if (res != NO_ERROR) {
-    return res;
-  }
-
-  /*
-   * Set customizable parameters.
-   */
-
-  mParameters.set(EmulatedCamera::FACING_KEY, facing_dir);
-  mParameters.set(EmulatedCamera::ORIENTATION_KEY,
-                  gEmulatedCameraFactory.getQemuCameraOrientation());
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, frame_dims);
-  mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, frame_dims);
-
-  /*
-   * Use first dimension reported by the device to set current preview and
-   * picture sizes.
-   */
-
-  char first_dim[128];
-  /* Dimensions are separated with ',' */
-  const char* c = strchr(frame_dims, ',');
-  if (c == NULL) {
-    strncpy(first_dim, frame_dims, sizeof(first_dim));
-    first_dim[sizeof(first_dim) - 1] = '\0';
-  } else if (static_cast<size_t>(c - frame_dims) < sizeof(first_dim)) {
-    memcpy(first_dim, frame_dims, c - frame_dims);
-    first_dim[c - frame_dims] = '\0';
-  } else {
-    memcpy(first_dim, frame_dims, sizeof(first_dim));
-    first_dim[sizeof(first_dim) - 1] = '\0';
-  }
-
-  /* Width and height are separated with 'x' */
-  char* sep = strchr(first_dim, 'x');
-  if (sep == NULL) {
-    ALOGE("%s: Invalid first dimension format in %s", __FUNCTION__, frame_dims);
-    return EINVAL;
-  }
-
-  *sep = '\0';
-  const int x = atoi(first_dim);
-  const int y = atoi(sep + 1);
-  mParameters.setPreviewSize(x, y);
-  mParameters.setPictureSize(x, y);
-
-  ALOGV("%s: Qemu camera %s is initialized. Current frame is %dx%d",
-        __FUNCTION__, device_name, x, y);
-
-  return NO_ERROR;
-}
-
-EmulatedCameraDevice* EmulatedQemuCamera::getCameraDevice() {
-  return &mQemuCameraDevice;
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedQemuCamera.h b/guest/hals/camera/EmulatedQemuCamera.h
deleted file mode 100644
index fe063bf..0000000
--- a/guest/hals/camera/EmulatedQemuCamera.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_H
-#define HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_H
-
-/*
- * Contains declaration of a class EmulatedQemuCamera that encapsulates
- * functionality of an emulated camera connected to the host.
- */
-
-#include "EmulatedCamera.h"
-#include "EmulatedQemuCameraDevice.h"
-
-namespace android {
-
-/* Encapsulates functionality of an emulated camera connected to the host.
- */
-class EmulatedQemuCamera : public EmulatedCamera {
- public:
-  /* Constructs EmulatedQemuCamera instance. */
-  EmulatedQemuCamera(int cameraId, struct hw_module_t* module);
-
-  /* Destructs EmulatedQemuCamera instance. */
-  ~EmulatedQemuCamera();
-
-  /***************************************************************************
-   * EmulatedCamera virtual overrides.
-   **************************************************************************/
-
- public:
-  /* Initializes EmulatedQemuCamera instance. */
-  status_t Initialize(const char* device_name, const char* frame_dims,
-                      const char* facing_dir);
-
-  /***************************************************************************
-   * EmulatedCamera abstract API implementation.
-   **************************************************************************/
-
- protected:
-  /* Gets emulated camera device ised by this instance of the emulated camera.
-   */
-  EmulatedCameraDevice* getCameraDevice();
-
-  /***************************************************************************
-   * Data memebers.
-   **************************************************************************/
-
- protected:
-  /* Contained qemu camera device object. */
-  EmulatedQemuCameraDevice mQemuCameraDevice;
-
-  /* Supported frame dimensions reported by the camera device. */
-  String8 mFrameDims;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_H */
diff --git a/guest/hals/camera/EmulatedQemuCamera2.cpp b/guest/hals/camera/EmulatedQemuCamera2.cpp
deleted file mode 100644
index cf894fd..0000000
--- a/guest/hals/camera/EmulatedQemuCamera2.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/*
- * Contains implementation of a class EmulatedQemuCamera2 that encapsulates
- * functionality of a host webcam with further processing to simulate the
- * capabilities of a v2 camera device.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_QemuCamera2"
-#include "EmulatedQemuCamera2.h"
-#include <log/log.h>
-#include <cutils/properties.h>
-#include "EmulatedCameraFactory.h"
-
-namespace android {
-
-EmulatedQemuCamera2::EmulatedQemuCamera2(int cameraId, bool facingBack,
-                                         struct hw_module_t* module)
-    : EmulatedCamera2(cameraId, module), mFacingBack(facingBack) {
-  ALOGD("Constructing emulated qemu camera 2 facing %s",
-        facingBack ? "back" : "front");
-}
-
-EmulatedQemuCamera2::~EmulatedQemuCamera2() {}
-
-/****************************************************************************
- * Public API overrides
- ***************************************************************************/
-
-status_t EmulatedQemuCamera2::Initialize() { return NO_ERROR; }
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedQemuCamera2.h b/guest/hals/camera/EmulatedQemuCamera2.h
deleted file mode 100644
index 7697c0e..0000000
--- a/guest/hals/camera/EmulatedQemuCamera2.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA2_H
-#define HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA2_H
-
-/*
- * Contains declaration of a class EmulatedQemuCamera2 that encapsulates
- * functionality of a host webcam with added processing to implement version 2
- * of the camera device interface.
- */
-
-#include "EmulatedCamera2.h"
-
-namespace android {
-
-/* Encapsulates functionality of an advanced fake camera based on real host
- * camera data.
- */
-class EmulatedQemuCamera2 : public EmulatedCamera2 {
- public:
-  /* Constructs EmulatedFakeCamera instance. */
-  EmulatedQemuCamera2(int cameraId, bool facingBack,
-                      struct hw_module_t* module);
-
-  /* Destructs EmulatedFakeCamera instance. */
-  ~EmulatedQemuCamera2();
-
-  /****************************************************************************
-   * EmulatedCamera2 virtual overrides.
-   ***************************************************************************/
-
- public:
-  /* Initializes EmulatedQemuCamera2 instance. */
-  status_t Initialize();
-
-  /****************************************************************************
-   * EmulatedCamera abstract API implementation.
-   ***************************************************************************/
-
- protected:
-  /****************************************************************************
-   * Data memebers.
-   ***************************************************************************/
-
- protected:
-  /* Facing back (true) or front (false) switch. */
-  bool mFacingBack;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA2_H */
diff --git a/guest/hals/camera/EmulatedQemuCameraDevice.cpp b/guest/hals/camera/EmulatedQemuCameraDevice.cpp
deleted file mode 100644
index 61291e8..0000000
--- a/guest/hals/camera/EmulatedQemuCameraDevice.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class EmulatedQemuCameraDevice that encapsulates
- * an emulated camera device connected to the host.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_QemuDevice"
-#include "EmulatedQemuCameraDevice.h"
-#include <log/log.h>
-#include "EmulatedQemuCamera.h"
-
-namespace android {
-
-EmulatedQemuCameraDevice::EmulatedQemuCameraDevice(
-    EmulatedQemuCamera* camera_hal)
-    : EmulatedCameraDevice(camera_hal), mQemuClient(), mPreviewFrame(NULL) {}
-
-EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice() {
-  if (mPreviewFrame != NULL) {
-    delete[] mPreviewFrame;
-  }
-}
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-status_t EmulatedQemuCameraDevice::Initialize(const char* device_name) {
-  /* Connect to the service. */
-  char connect_str[256];
-  snprintf(connect_str, sizeof(connect_str), "name=%s", device_name);
-  status_t res = mQemuClient.connectClient(connect_str);
-  if (res != NO_ERROR) {
-    return res;
-  }
-
-  /* Initialize base class. */
-  res = EmulatedCameraDevice::Initialize();
-  if (res == NO_ERROR) {
-    ALOGV("%s: Connected to the emulated camera service '%s'", __FUNCTION__,
-          device_name);
-    mDeviceName = device_name;
-  } else {
-    mQemuClient.queryDisconnect();
-  }
-
-  return res;
-}
-
-/****************************************************************************
- * Emulated camera device abstract interface implementation.
- ***************************************************************************/
-
-status_t EmulatedQemuCameraDevice::connectDevice() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isInitialized()) {
-    ALOGE("%s: Qemu camera device is not initialized.", __FUNCTION__);
-    return EINVAL;
-  }
-  if (isConnected()) {
-    ALOGW("%s: Qemu camera device '%s' is already connected.", __FUNCTION__,
-          (const char*)mDeviceName);
-    return NO_ERROR;
-  }
-
-  /* Connect to the camera device via emulator. */
-  const status_t res = mQemuClient.queryConnect();
-  if (res == NO_ERROR) {
-    ALOGV("%s: Connected to device '%s'", __FUNCTION__,
-          (const char*)mDeviceName);
-    mState = ECDS_CONNECTED;
-  } else {
-    ALOGE("%s: Connection to device '%s' failed", __FUNCTION__,
-          (const char*)mDeviceName);
-  }
-
-  return res;
-}
-
-status_t EmulatedQemuCameraDevice::disconnectDevice() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isConnected()) {
-    ALOGW("%s: Qemu camera device '%s' is already disconnected.", __FUNCTION__,
-          (const char*)mDeviceName);
-    return NO_ERROR;
-  }
-  if (isStarted()) {
-    ALOGE("%s: Cannot disconnect from the started device '%s.", __FUNCTION__,
-          (const char*)mDeviceName);
-    return EINVAL;
-  }
-
-  /* Disconnect from the camera device via emulator. */
-  const status_t res = mQemuClient.queryDisconnect();
-  if (res == NO_ERROR) {
-    ALOGV("%s: Disonnected from device '%s'", __FUNCTION__,
-          (const char*)mDeviceName);
-    mState = ECDS_INITIALIZED;
-  } else {
-    ALOGE("%s: Disconnection from device '%s' failed", __FUNCTION__,
-          (const char*)mDeviceName);
-  }
-
-  return res;
-}
-
-status_t EmulatedQemuCameraDevice::startDevice(int width, int height,
-                                               uint32_t pix_fmt, int fps) {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isConnected()) {
-    ALOGE("%s: Qemu camera device '%s' is not connected.", __FUNCTION__,
-          (const char*)mDeviceName);
-    return EINVAL;
-  }
-  if (isStarted()) {
-    ALOGW("%s: Qemu camera device '%s' is already started.", __FUNCTION__,
-          (const char*)mDeviceName);
-    return NO_ERROR;
-  }
-
-  status_t res =
-      EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt, fps);
-  if (res != NO_ERROR) {
-    ALOGE("%s: commonStartDevice failed", __FUNCTION__);
-    return res;
-  }
-
-  /* Allocate preview frame buffer. */
-  /* TODO: Watch out for preview format changes! At this point we implement
-   * RGB32 only.*/
-  mPreviewFrame = new uint32_t[mTotalPixels];
-  if (mPreviewFrame == NULL) {
-    ALOGE("%s: Unable to allocate %d bytes for preview frame", __FUNCTION__,
-          mTotalPixels);
-    return ENOMEM;
-  }
-
-  /* Start the actual camera device. */
-  res = mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight);
-  if (res == NO_ERROR) {
-    ALOGV("%s: Qemu camera device '%s' is started for %.4s[%dx%d] frames",
-          __FUNCTION__, (const char*)mDeviceName,
-          reinterpret_cast<const char*>(&mPixelFormat), mFrameWidth,
-          mFrameHeight);
-    mState = ECDS_STARTED;
-  } else {
-    ALOGE("%s: Unable to start device '%s' for %.4s[%dx%d] frames",
-          __FUNCTION__, (const char*)mDeviceName,
-          reinterpret_cast<const char*>(&pix_fmt), width, height);
-  }
-
-  return res;
-}
-
-status_t EmulatedQemuCameraDevice::stopDevice() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  if (!isStarted()) {
-    ALOGW("%s: Qemu camera device '%s' is not started.", __FUNCTION__,
-          (const char*)mDeviceName);
-    return NO_ERROR;
-  }
-
-  /* Stop the actual camera device. */
-  status_t res = mQemuClient.queryStop();
-  if (res == NO_ERROR) {
-    if (mPreviewFrame == NULL) {
-      delete[] mPreviewFrame;
-      mPreviewFrame = NULL;
-    }
-    EmulatedCameraDevice::commonStopDevice();
-    mState = ECDS_CONNECTED;
-    ALOGV("%s: Qemu camera device '%s' is stopped", __FUNCTION__,
-          (const char*)mDeviceName);
-  } else {
-    ALOGE("%s: Unable to stop device '%s'", __FUNCTION__,
-          (const char*)mDeviceName);
-  }
-
-  return res;
-}
-
-/****************************************************************************
- * EmulatedCameraDevice virtual overrides
- ***************************************************************************/
-
-status_t EmulatedQemuCameraDevice::getCurrentPreviewFrame(void* buffer) {
-  ALOGW_IF(mPreviewFrame == NULL, "%s: No preview frame", __FUNCTION__);
-  if (mPreviewFrame != NULL) {
-    memcpy(buffer, mPreviewFrame, mTotalPixels * 4);
-    return 0;
-  } else {
-    return EmulatedCameraDevice::getCurrentPreviewFrame(buffer);
-  }
-}
-
-/****************************************************************************
- * Worker thread management overrides.
- ***************************************************************************/
-
-bool EmulatedQemuCameraDevice::inWorkerThread() {
-  /* Wait till FPS timeout expires, or thread exit message is received. */
-  WorkerThread::SelectRes res =
-      getWorkerThread()->Select(-1, 1000000 / mEmulatedFPS);
-  if (res == WorkerThread::EXIT_THREAD) {
-    ALOGV("%s: Worker thread has been terminated.", __FUNCTION__);
-    return false;
-  }
-
-  /* Query frames from the service. */
-  status_t query_res = mQemuClient.queryFrame(
-      mCurrentFrame, mPreviewFrame, mFrameBufferSize, mTotalPixels * 4,
-      mWhiteBalanceScale[0], mWhiteBalanceScale[1], mWhiteBalanceScale[2],
-      mExposureCompensation);
-  if (query_res == NO_ERROR) {
-    /* Timestamp the current frame, and notify the camera HAL. */
-    mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-    mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this);
-    return true;
-  } else {
-    ALOGE("%s: Unable to get current video frame: %s", __FUNCTION__,
-          strerror(query_res));
-    mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
-    return false;
-  }
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/EmulatedQemuCameraDevice.h b/guest/hals/camera/EmulatedQemuCameraDevice.h
deleted file mode 100644
index 2e4770b..0000000
--- a/guest/hals/camera/EmulatedQemuCameraDevice.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_DEVICE_H
-#define HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_DEVICE_H
-
-/*
- * Contains declaration of a class EmulatedQemuCameraDevice that encapsulates
- * an emulated camera device connected to the host.
- */
-
-#include "EmulatedCameraDevice.h"
-#include "QemuClient.h"
-
-namespace android {
-
-class EmulatedQemuCamera;
-
-/* Encapsulates an emulated camera device connected to the host.
- */
-class EmulatedQemuCameraDevice : public EmulatedCameraDevice {
- public:
-  /* Constructs EmulatedQemuCameraDevice instance. */
-  explicit EmulatedQemuCameraDevice(EmulatedQemuCamera* camera_hal);
-
-  /* Destructs EmulatedQemuCameraDevice instance. */
-  ~EmulatedQemuCameraDevice();
-
-  /***************************************************************************
-   * Public API
-   **************************************************************************/
-
- public:
-  /* Initializes EmulatedQemuCameraDevice instance.
-   * Param:
-   *  device_name - Name of the camera device connected to the host. The name
-   *      that is used here must have been reported by the 'factory' camera
-   *      service when it listed camera devices connected to the host.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  status_t Initialize(const char* device_name);
-
-  /***************************************************************************
-   * Emulated camera device abstract interface implementation.
-   * See declarations of these methods in EmulatedCameraDevice class for
-   * information on each of these methods.
-   **************************************************************************/
-
- public:
-  /* Connects to the camera device. */
-  status_t connectDevice();
-
-  /* Disconnects from the camera device. */
-  status_t disconnectDevice();
-
-  /* Starts capturing frames from the camera device. */
-  status_t startDevice(int width, int height, uint32_t pix_fmt, int fps);
-
-  /* Stops capturing frames from the camera device. */
-  status_t stopDevice();
-
-  /***************************************************************************
-   * EmulatedCameraDevice virtual overrides
-   * See declarations of these methods in EmulatedCameraDevice class for
-   * information on each of these methods.
-   **************************************************************************/
-
- public:
-  /* Gets current preview fame into provided buffer.
-   * We override this method in order to provide preview frames cached in this
-   * object.
-   */
-  status_t getCurrentPreviewFrame(void* buffer);
-
-  /***************************************************************************
-   * Worker thread management overrides.
-   * See declarations of these methods in EmulatedCameraDevice class for
-   * information on each of these methods.
-   **************************************************************************/
-
- protected:
-  /* Implementation of the worker thread routine. */
-  bool inWorkerThread();
-
-  /***************************************************************************
-   * Qemu camera device data members
-   **************************************************************************/
-
- private:
-  /* Qemu client that is used to communicate with the 'emulated camera'
-   * service, created for this instance in the emulator. */
-  CameraQemuClient mQemuClient;
-
-  /* Name of the camera device connected to the host. */
-  String8 mDeviceName;
-
-  /* Current preview framebuffer. */
-  uint32_t* mPreviewFrame;
-
-  /* Emulated FPS (frames per second).
-   * We will emulate 50 FPS. */
-  static const int mEmulatedFPS = 50;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_DEVICE_H */
diff --git a/guest/hals/camera/Exif.cpp b/guest/hals/camera/Exif.cpp
deleted file mode 100644
index e57bb8c..0000000
--- a/guest/hals/camera/Exif.cpp
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Exif"
-#include <log/log.h>
-
-#include <inttypes.h>
-#include <math.h>
-#include <stdint.h>
-
-#include <CameraParameters.h>
-
-using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
-using ::android::hardware::camera::common::V1_0::helper::Size;
-
-#include "Exif.h"
-
-#include <libexif/exif-data.h>
-#include <libexif/exif-entry.h>
-#include <libexif/exif-ifd.h>
-#include <libexif/exif-tag.h>
-
-#include <string>
-#include <vector>
-
-// For GPS timestamping we want to ensure we use a 64-bit time_t, 32-bit
-// platforms have time64_t but 64-bit platforms do not.
-#if defined(__LP64__)
-#include <time.h>
-using Timestamp = time_t;
-#define TIMESTAMP_TO_TM(timestamp, tm) gmtime_r(timestamp, tm)
-#else
-#include <time64.h>
-using Timestamp = time64_t;
-#define TIMESTAMP_TO_TM(timestamp, tm) gmtime64_r(timestamp, tm)
-#endif
-
-namespace android {
-
-// A prefix that is used for tags with the "undefined" format to indicate that
-// the contents are ASCII encoded. See the user comment section of the EXIF spec
-// for more details http://www.exif.org/Exif2-2.PDF
-static const unsigned char kAsciiPrefix[] = {
-    0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00 // "ASCII\0\0\0"
-};
-
-// Remove an existing EXIF entry from |exifData| if it exists. This is useful
-// when replacing existing data, it's easier to just remove the data and
-// re-allocate it than to adjust the amount of allocated data.
-static void removeExistingEntry(ExifData* exifData, ExifIfd ifd, int tag) {
-    ExifEntry* entry = exif_content_get_entry(exifData->ifd[ifd],
-                                              static_cast<ExifTag>(tag));
-    if (entry) {
-        exif_content_remove_entry(exifData->ifd[ifd], entry);
-    }
-}
-
-static ExifEntry* allocateEntry(int tag,
-                                ExifFormat format,
-                                unsigned int numComponents) {
-    ExifMem* mem = exif_mem_new_default();
-    ExifEntry* entry = exif_entry_new_mem(mem);
-
-    unsigned int size = numComponents * exif_format_get_size(format);
-    entry->data = reinterpret_cast<unsigned char*>(exif_mem_alloc(mem, size));
-    entry->size = size;
-    entry->tag = static_cast<ExifTag>(tag);
-    entry->components = numComponents;
-    entry->format = format;
-
-    exif_mem_unref(mem);
-    return entry;
-}
-
-// Create an entry and place it in |exifData|, the entry is initialized with an
-// array of floats from |values|
-template<size_t N>
-static bool createEntry(ExifData* exifData,
-                        ExifIfd ifd,
-                        int tag,
-                        const float (&values)[N],
-                        float denominator = 1000.0) {
-    removeExistingEntry(exifData, ifd, tag);
-    ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
-    ExifEntry* entry = allocateEntry(tag, EXIF_FORMAT_RATIONAL, N);
-    exif_content_add_entry(exifData->ifd[ifd], entry);
-    unsigned int rationalSize = exif_format_get_size(EXIF_FORMAT_RATIONAL);
-    for (size_t i = 0; i < N; ++i) {
-        ExifRational rational = {
-            static_cast<uint32_t>(values[i] * denominator),
-            static_cast<uint32_t>(denominator)
-        };
-
-        exif_set_rational(&entry->data[i * rationalSize], byteOrder, rational);
-    }
-
-    // Unref entry after changing owner to the ExifData struct
-    exif_entry_unref(entry);
-    return true;
-}
-
-// Create an entry with a single float |value| in it and place it in |exifData|
-static bool createEntry(ExifData* exifData,
-                        ExifIfd ifd,
-                        int tag,
-                        const float value,
-                        float denominator = 1000.0) {
-    float values[1] = { value };
-    // Recycling functions is good for the environment
-    return createEntry(exifData, ifd, tag, values, denominator);
-}
-
-// Create an entry and place it in |exifData|, the entry contains the raw data
-// pointed to by |data| of length |size|.
-static bool createEntry(ExifData* exifData,
-                        ExifIfd ifd,
-                        int tag,
-                        const unsigned char* data,
-                        size_t size,
-                        ExifFormat format = EXIF_FORMAT_UNDEFINED) {
-    removeExistingEntry(exifData, ifd, tag);
-    ExifEntry* entry = allocateEntry(tag, format, size);
-    memcpy(entry->data, data, size);
-    exif_content_add_entry(exifData->ifd[ifd], entry);
-    // Unref entry after changing owner to the ExifData struct
-    exif_entry_unref(entry);
-    return true;
-}
-
-// Create an entry and place it in |exifData|, the entry is initialized with
-// the string provided in |value|
-static bool createEntry(ExifData* exifData,
-                        ExifIfd ifd,
-                        int tag,
-                        const char* value) {
-    unsigned int length = strlen(value) + 1;
-    const unsigned char* data = reinterpret_cast<const unsigned char*>(value);
-    return createEntry(exifData, ifd, tag, data, length, EXIF_FORMAT_ASCII);
-}
-
-// Create an entry and place it in |exifData|, the entry is initialized with a
-// single byte in |value|
-static bool createEntry(ExifData* exifData,
-                        ExifIfd ifd,
-                        int tag,
-                        uint8_t value) {
-    return createEntry(exifData, ifd, tag, &value, 1, EXIF_FORMAT_BYTE);
-}
-
-// Create an entry and place it in |exifData|, the entry is default initialized
-// by the exif library based on |tag|
-static bool createEntry(ExifData* exifData,
-                        ExifIfd ifd,
-                        int tag) {
-    removeExistingEntry(exifData, ifd, tag);
-    ExifEntry* entry = exif_entry_new();
-    exif_content_add_entry(exifData->ifd[ifd], entry);
-    exif_entry_initialize(entry, static_cast<ExifTag>(tag));
-    // Unref entry after changing owner to the ExifData struct
-    exif_entry_unref(entry);
-    return true;
-}
-
-// Create an entry with a single EXIF LONG (32-bit value) and place it in
-// |exifData|.
-static bool createEntry(ExifData* exifData,
-                        ExifIfd ifd,
-                        int tag,
-                        int value) {
-    removeExistingEntry(exifData, ifd, tag);
-    ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
-    ExifEntry* entry = allocateEntry(tag, EXIF_FORMAT_LONG, 1);
-    exif_content_add_entry(exifData->ifd[ifd], entry);
-    exif_set_long(entry->data, byteOrder, value);
-
-    // Unref entry after changing owner to the ExifData struct
-    exif_entry_unref(entry);
-    return true;
-}
-
-static bool getCameraParam(const CameraParameters& parameters,
-                           const char* parameterKey,
-                           const char** outValue) {
-    const char* value = parameters.get(parameterKey);
-    if (value) {
-        *outValue = value;
-        return true;
-    }
-    return false;
-}
-
-static bool getCameraParam(const CameraParameters& parameters,
-                           const char* parameterKey,
-                           float* outValue) {
-    const char* value = parameters.get(parameterKey);
-    if (value) {
-        *outValue = parameters.getFloat(parameterKey);
-        return true;
-    }
-    return false;
-}
-
-static bool getCameraParam(const CameraParameters& parameters,
-                           const char* parameterKey,
-                           int64_t* outValue) {
-    const char* value = parameters.get(parameterKey);
-    if (value) {
-        char dummy = 0;
-        // Attempt to scan an extra character and then make sure it was not
-        // scanned by checking that the return value indicates only one item.
-        // This way we fail on any trailing characters
-        if (sscanf(value, "%" SCNd64 "%c", outValue, &dummy) == 1) {
-            return true;
-        }
-    }
-    return false;
-}
-
-// Convert a GPS coordinate represented as a decimal degree value to sexagesimal
-// GPS coordinates comprised of <degrees> <minutes>' <seconds>"
-static void convertGpsCoordinate(float degrees, float (*result)[3]) {
-    float absDegrees = fabs(degrees);
-    // First value is degrees without any decimal digits
-    (*result)[0] = floor(absDegrees);
-
-    // Subtract degrees so we only have the fraction left, then multiply by
-    // 60 to get the minutes
-    float minutes = (absDegrees - (*result)[0]) * 60.0f;
-    (*result)[1] = floor(minutes);
-
-    // Same thing for seconds but here we store seconds with the fraction
-    float seconds = (minutes - (*result)[1]) * 60.0f;
-    (*result)[2] = seconds;
-}
-
-// Convert a UNIX epoch timestamp to a timestamp comprised of three floats for
-// hour, minute and second, and a date part that is represented as a string.
-static bool convertTimestampToTimeAndDate(int64_t timestamp,
-                                          float (*timeValues)[3],
-                                          std::string* date) {
-    Timestamp time = timestamp;
-    struct tm utcTime;
-    if (TIMESTAMP_TO_TM(&time, &utcTime) == nullptr) {
-        ALOGE("Could not decompose timestamp into components");
-        return false;
-    }
-    (*timeValues)[0] = utcTime.tm_hour;
-    (*timeValues)[1] = utcTime.tm_min;
-    (*timeValues)[2] = utcTime.tm_sec;
-
-    char buffer[64] = {};
-    if (strftime(buffer, sizeof(buffer), "%Y:%m:%d", &utcTime) == 0) {
-        ALOGE("Could not construct date string from timestamp");
-        return false;
-    }
-    *date = buffer;
-    return true;
-}
-
-ExifData* createExifData(const CameraParameters& params) {
-    ExifData* exifData = exif_data_new();
-
-    exif_data_set_option(exifData, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
-    exif_data_set_data_type(exifData, EXIF_DATA_TYPE_COMPRESSED);
-    exif_data_set_byte_order(exifData, EXIF_BYTE_ORDER_INTEL);
-
-    // Create mandatory exif fields and set their default values
-    exif_data_fix(exifData);
-
-    float triplet[3];
-    float floatValue = 0.0f;
-    const char* stringValue;
-    int64_t degrees;
-
-    // Datetime, creating and initializing a datetime tag will automatically
-    // set the current date and time in the tag so just do that.
-    createEntry(exifData, EXIF_IFD_0, EXIF_TAG_DATE_TIME);
-
-    // Make and model
-    createEntry(exifData, EXIF_IFD_0, EXIF_TAG_MAKE, "Emulator-Cuttlefish");
-    createEntry(exifData, EXIF_IFD_0, EXIF_TAG_MODEL, "Emulator-Cuttlefish");
-
-    // Picture size
-    int width = -1, height = -1;
-    params.getPictureSize(&width, &height);
-    if (width >= 0 && height >= 0) {
-        createEntry(exifData, EXIF_IFD_EXIF,
-                    EXIF_TAG_PIXEL_X_DIMENSION, width);
-        createEntry(exifData, EXIF_IFD_EXIF,
-                    EXIF_TAG_PIXEL_Y_DIMENSION, height);
-    }
-    // Orientation
-    if (getCameraParam(params,
-                       CameraParameters::KEY_ROTATION,
-                       &degrees)) {
-        // Exif orientation values, please refer to
-        // http://www.exif.org/Exif2-2.PDF, Section 4.6.4-A-Orientation
-        // Or these websites:
-        // http://sylvana.net/jpegcrop/exif_orientation.html
-        // http://www.impulseadventure.com/photo/exif-orientation.html
-        enum {
-            EXIF_ROTATE_CAMERA_CW0 = 1,
-            EXIF_ROTATE_CAMERA_CW90 = 6,
-            EXIF_ROTATE_CAMERA_CW180 = 3,
-            EXIF_ROTATE_CAMERA_CW270 = 8,
-        };
-        uint16_t exifOrien = 1;
-        switch (degrees) {
-            case 0:
-                exifOrien = EXIF_ROTATE_CAMERA_CW0;
-                break;
-            case 90:
-                exifOrien = EXIF_ROTATE_CAMERA_CW90;
-                break;
-            case 180:
-                exifOrien = EXIF_ROTATE_CAMERA_CW180;
-                break;
-            case 270:
-                exifOrien = EXIF_ROTATE_CAMERA_CW270;
-                break;
-        }
-        createEntry(exifData, EXIF_IFD_0, EXIF_TAG_ORIENTATION, exifOrien);
-    }
-    // Focal length
-    if (getCameraParam(params,
-                       CameraParameters::KEY_FOCAL_LENGTH,
-                       &floatValue)) {
-        createEntry(exifData, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, floatValue);
-    }
-    // GPS latitude and reference, reference indicates sign, store unsigned
-    if (getCameraParam(params,
-                       CameraParameters::KEY_GPS_LATITUDE,
-                       &floatValue)) {
-        convertGpsCoordinate(floatValue, &triplet);
-        createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, triplet);
-
-        const char* ref = floatValue < 0.0f ? "S" : "N";
-        createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, ref);
-    }
-    // GPS longitude and reference, reference indicates sign, store unsigned
-    if (getCameraParam(params,
-                       CameraParameters::KEY_GPS_LONGITUDE,
-                       &floatValue)) {
-        convertGpsCoordinate(floatValue, &triplet);
-        createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, triplet);
-
-        const char* ref = floatValue < 0.0f ? "W" : "E";
-        createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, ref);
-    }
-    // GPS altitude and reference, reference indicates sign, store unsigned
-    if (getCameraParam(params,
-                       CameraParameters::KEY_GPS_ALTITUDE,
-                       &floatValue)) {
-        createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE,
-                    static_cast<float>(fabs(floatValue)));
-
-        // 1 indicated below sea level, 0 indicates above sea level
-        uint8_t ref = floatValue < 0.0f ? 1 : 0;
-        createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE_REF, ref);
-    }
-    // GPS timestamp and datestamp
-    int64_t timestamp = 0;
-    if (getCameraParam(params,
-                       CameraParameters::KEY_GPS_TIMESTAMP,
-                       &timestamp)) {
-        std::string date;
-        if (convertTimestampToTimeAndDate(timestamp, &triplet, &date)) {
-            createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_TIME_STAMP,
-                        triplet, 1.0f);
-            createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_DATE_STAMP,
-                        date.c_str());
-        }
-    }
-
-    // GPS processing method
-    if (getCameraParam(params,
-                       CameraParameters::KEY_GPS_PROCESSING_METHOD,
-                       &stringValue)) {
-        std::vector<unsigned char> data;
-        // Because this is a tag with an undefined format it has to be prefixed
-        // with the encoding type. Insert an ASCII prefix first, then the
-        // actual string. Undefined tags do not have to be null terminated.
-        data.insert(data.end(),
-                    std::begin(kAsciiPrefix),
-                    std::end(kAsciiPrefix));
-        data.insert(data.end(), stringValue, stringValue + strlen(stringValue));
-        createEntry(exifData, EXIF_IFD_GPS, EXIF_TAG_GPS_PROCESSING_METHOD,
-                    &data[0], data.size());
-    }
-
-    return exifData;
-}
-
-void freeExifData(ExifData* exifData) {
-    exif_data_free(exifData);
-}
-
-}  // namespace android
-
diff --git a/guest/hals/camera/Exif.h b/guest/hals/camera/Exif.h
deleted file mode 100644
index 4ea06e1..0000000
--- a/guest/hals/camera/Exif.h
+++ /dev/null
@@ -1,41 +0,0 @@
-
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef CUTTLEFISH_CAMERA_EXIF_H
-#define CUTTLEFISH_CAMERA_EXIF_H
-
-#include <CameraParameters.h>
-
-using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
-
-struct _ExifData;
-typedef struct _ExifData ExifData;
-
-namespace android {
-
-/* Create an EXIF data structure based on camera parameters. This includes
- * things like GPS information that has been set by the camera client.
- */
-ExifData* createExifData(const CameraParameters& parameters);
-
-/* Free EXIF data created in the createExifData call */
-void freeExifData(ExifData* exifData);
-
-}  // namespace android
-
-#endif  // CUTTLEFISH_CAMERA_EXIF_H
-
diff --git a/guest/hals/camera/GrallocModule.h b/guest/hals/camera/GrallocModule.h
deleted file mode 100644
index 2033e8d..0000000
--- a/guest/hals/camera/GrallocModule.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#ifndef GUEST_HALS_CAMERA_GRALLOCMODULE_H_
-#define GUEST_HALS_CAMERA_GRALLOCMODULE_H_
-
-#include <hardware/gralloc.h>
-
-class GrallocModule {
- public:
-  static GrallocModule &getInstance() {
-    static GrallocModule instance;
-    return instance;
-  }
-
-  int lock(buffer_handle_t handle, int usage, int l, int t, int w, int h,
-           void **vaddr) {
-    return mModule->lock(mModule, handle, usage, l, t, w, h, vaddr);
-  }
-
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-  int lock_ycbcr(buffer_handle_t handle, int usage, int l, int t, int w, int h,
-                 struct android_ycbcr *ycbcr) {
-    return mModule->lock_ycbcr(mModule, handle, usage, l, t, w, h, ycbcr);
-  }
-#endif
-
-  int unlock(buffer_handle_t handle) {
-    return mModule->unlock(mModule, handle);
-  }
-
- private:
-  GrallocModule() {
-    const hw_module_t *module = NULL;
-    int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    if (ret) {
-      ALOGE("%s: Failed to get gralloc module: %d", __FUNCTION__, ret);
-    }
-    mModule = reinterpret_cast<const gralloc_module_t *>(module);
-  }
-  const gralloc_module_t *mModule;
-};
-
-#endif  // GUEST_HALS_CAMERA_GRALLOCMODULE_H_
diff --git a/guest/hals/camera/JpegCompressor.cpp b/guest/hals/camera/JpegCompressor.cpp
deleted file mode 100644
index 99164c9..0000000
--- a/guest/hals/camera/JpegCompressor.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class NV21JpegCompressor that encapsulates a
- * converter between NV21, and JPEG formats.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_JPEG"
-#include "JpegCompressor.h"
-#include <assert.h>
-#include <log/log.h>
-#include <dlfcn.h>
-
-namespace android {
-
-void* NV21JpegCompressor::mDl = NULL;
-
-static void* getSymbol(void* dl, const char* signature) {
-  void* res = dlsym(dl, signature);
-  assert(res != NULL);
-
-  return res;
-}
-
-typedef void (*InitFunc)(JpegStub* stub);
-typedef void (*CleanupFunc)(JpegStub* stub);
-typedef int (*CompressFunc)(JpegStub* stub, const void* image, int width,
-                            int height, int quality, ExifData* exifData);
-typedef void (*GetCompressedImageFunc)(JpegStub* stub, void* buff);
-typedef size_t (*GetCompressedSizeFunc)(JpegStub* stub);
-
-NV21JpegCompressor::NV21JpegCompressor() {
-  if (mDl == NULL) {
-    mDl = dlopen("/vendor/lib/hw/camera.cutf.jpeg.so", RTLD_NOW);
-  }
-  if (mDl == NULL) {
-    mDl = dlopen("/system/lib/hw/camera.cutf.jpeg.so", RTLD_NOW);
-  }
-  assert(mDl != NULL);
-
-  InitFunc f = (InitFunc)getSymbol(mDl, "JpegStub_init");
-  (*f)(&mStub);
-}
-
-NV21JpegCompressor::~NV21JpegCompressor() {
-  CleanupFunc f = (CleanupFunc)getSymbol(mDl, "JpegStub_cleanup");
-  (*f)(&mStub);
-}
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-status_t NV21JpegCompressor::compressRawImage(const void* image,
-                                              ExifData* exifData,
-                                              int quality,
-                                              int width,
-                                              int height) {
-  mStrides[0] = width;
-  mStrides[1] = width;
-  CompressFunc f = (CompressFunc)getSymbol(mDl, "JpegStub_compress");
-  return (status_t)(*f)(&mStub, image, width, height, quality, exifData);
-}
-
-size_t NV21JpegCompressor::getCompressedSize() {
-  GetCompressedSizeFunc f =
-      (GetCompressedSizeFunc)getSymbol(mDl, "JpegStub_getCompressedSize");
-  return (*f)(&mStub);
-}
-
-void NV21JpegCompressor::getCompressedImage(void* buff) {
-  GetCompressedImageFunc f =
-      (GetCompressedImageFunc)getSymbol(mDl, "JpegStub_getCompressedImage");
-  (*f)(&mStub, buff);
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/JpegCompressor.h b/guest/hals/camera/JpegCompressor.h
deleted file mode 100644
index 6d93c46..0000000
--- a/guest/hals/camera/JpegCompressor.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H
-#define HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H
-
-/*
- * Contains declaration of a class NV21JpegCompressor that encapsulates a
- * converter between YV21, and JPEG formats.
- */
-
-#include <utils/threads.h>
-#include "JpegStub.h"
-
-namespace android {
-
-/* Encapsulates a converter between YV12, and JPEG formats.
- */
-class NV21JpegCompressor {
- public:
-  /* Constructs JpegCompressor instance. */
-  NV21JpegCompressor();
-  /* Destructs JpegCompressor instance. */
-  ~NV21JpegCompressor();
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  /* Compresses raw NV21 image into a JPEG.
-   * The compressed image will be saved in mStream member of this class. Use
-   * getCompressedSize method to obtain buffer size of the compressed image,
-   * and getCompressedImage to copy out the compressed image.
-   * Param:
-   *  image - Raw NV21 image.
-   *  metadata - Image metadata (dimensions, location etc).
-   *  quality - JPEG quality.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   *
-   */
-  status_t compressRawImage(const void* image, ExifData* exifData,
-                            int quality, int width, int height);
-
-  /* Get size of the compressed JPEG buffer.
-   * This method must be called only after a successful completion of
-   * compressRawImage call.
-   * Return:
-   *  Size of the compressed JPEG buffer.
-   */
-  size_t getCompressedSize();
-
-  /* Copies out compressed JPEG buffer.
-   * This method must be called only after a successful completion of
-   * compressRawImage call.
-   * Param:
-   *  buff - Buffer where to copy the JPEG. Must be large enough to contain the
-   *      entire image.
-   */
-  void getCompressedImage(void* buff);
-
-  /****************************************************************************
-   * Class data
-   ***************************************************************************/
-
- protected:
-  /* Strides for Y (the first element), and UV (the second one) panes. */
-  int mStrides[2];
-
- private:
-  // library handle to dlopen
-  static void* mDl;
-  JpegStub mStub;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H */
diff --git a/guest/hals/camera/JpegStub.cpp b/guest/hals/camera/JpegStub.cpp
deleted file mode 100644
index 3e02de0..0000000
--- a/guest/hals/camera/JpegStub.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#include "JpegStub.h"
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_JPEGStub"
-#include <errno.h>
-#include <log/log.h>
-#include <stdlib.h>
-
-#include "Compressor.h"
-
-extern "C" void JpegStub_init(JpegStub* stub) {
-    stub->mCompressor = static_cast<void*>(new Compressor());
-}
-
-extern "C" void JpegStub_cleanup(JpegStub* stub) {
-    delete reinterpret_cast<Compressor*>(stub->mCompressor);
-    stub->mCompressor = nullptr;
-}
-
-extern "C" int JpegStub_compress(JpegStub* stub,
-                                 const void* buffer,
-                                 int width,
-                                 int height,
-                                 int quality,
-                                 ExifData* exifData)
-{
-    Compressor* compressor = reinterpret_cast<Compressor*>(stub->mCompressor);
-
-    if (compressor->compress(reinterpret_cast<const unsigned char*>(buffer),
-                              width, height, quality, exifData)) {
-        ALOGV("%s: Compressed JPEG: %d[%dx%d] -> %zu bytes",
-              __FUNCTION__, (width * height * 12) / 8,
-              width, height, compressor->getCompressedData().size());
-        return 0;
-    }
-    ALOGE("%s: JPEG compression failed", __FUNCTION__);
-    return errno ? errno : EINVAL;
-}
-
-extern "C" void JpegStub_getCompressedImage(JpegStub* stub, void* buff) {
-    Compressor* compressor = reinterpret_cast<Compressor*>(stub->mCompressor);
-
-    const std::vector<unsigned char>& data = compressor->getCompressedData();
-    memcpy(buff, &data[0], data.size());
-}
-
-extern "C" size_t JpegStub_getCompressedSize(JpegStub* stub) {
-    Compressor* compressor = reinterpret_cast<Compressor*>(stub->mCompressor);
-
-    return compressor->getCompressedData().size();
-}
diff --git a/guest/hals/camera/JpegStub.h b/guest/hals/camera/JpegStub.h
deleted file mode 100644
index 2e62182..0000000
--- a/guest/hals/camera/JpegStub.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef JPEGSTUB_H_
-#define JPEGSTUB_H_
-
-#include <stddef.h>
-
-struct _ExifData;
-typedef _ExifData ExifData;
-
-extern "C" {
-
-struct JpegStub {
-    void* mCompressor;
-};
-
-void JpegStub_init(JpegStub* stub);
-void JpegStub_cleanup(JpegStub* stub);
-int JpegStub_compress(JpegStub* stub,
-                      const void* image,
-                      int width,
-                      int height,
-                      int quality,
-                      ExifData* exifData);
-void JpegStub_getCompressedImage(JpegStub* stub, void* buff);
-size_t JpegStub_getCompressedSize(JpegStub* stub);
-
-};
-#endif // JPEGSTUB_H_
diff --git a/guest/hals/camera/PreviewWindow.cpp b/guest/hals/camera/PreviewWindow.cpp
deleted file mode 100644
index e498435..0000000
--- a/guest/hals/camera/PreviewWindow.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of a class PreviewWindow that encapsulates
- * functionality of a preview window set via set_preview_window camera HAL API.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Preview"
-#include "PreviewWindow.h"
-#include <log/log.h>
-#include <hardware/camera.h>
-#include "EmulatedCameraDevice.h"
-#include "GrallocModule.h"
-
-namespace android {
-
-PreviewWindow::PreviewWindow()
-    : mPreviewWindow(NULL),
-      mLastPreviewed(0),
-      mPreviewFrameWidth(0),
-      mPreviewFrameHeight(0),
-      mPreviewEnabled(false) {}
-
-PreviewWindow::~PreviewWindow() {}
-
-/****************************************************************************
- * Camera API
- ***************************************************************************/
-
-status_t PreviewWindow::setPreviewWindow(struct preview_stream_ops* window,
-                                         int preview_fps) {
-  ALOGV("%s: current: %p -> new: %p", __FUNCTION__, mPreviewWindow, window);
-
-  status_t res = NO_ERROR;
-  Mutex::Autolock locker(&mObjectLock);
-
-  /* Reset preview info. */
-  mPreviewFrameWidth = mPreviewFrameHeight = 0;
-  mPreviewAfter = 0;
-  mLastPreviewed = 0;
-
-  if (window != NULL) {
-    /* The CPU will write each frame to the preview window buffer.
-     * Note that we delay setting preview window buffer geometry until
-     * frames start to come in. */
-    res = window->set_usage(window, GRALLOC_USAGE_SW_WRITE_OFTEN);
-    if (res == NO_ERROR) {
-      /* Set preview frequency. */
-      mPreviewAfter = 1000000 / preview_fps;
-    } else {
-      window = NULL;
-      res = -res;  // set_usage returns a negative errno.
-      ALOGE("%s: Error setting preview window usage %d -> %s", __FUNCTION__,
-            res, strerror(res));
-    }
-  }
-  mPreviewWindow = window;
-
-  return res;
-}
-
-status_t PreviewWindow::startPreview() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  mPreviewEnabled = true;
-
-  return NO_ERROR;
-}
-
-void PreviewWindow::stopPreview() {
-  ALOGV("%s", __FUNCTION__);
-
-  Mutex::Autolock locker(&mObjectLock);
-  mPreviewEnabled = false;
-}
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-void PreviewWindow::onNextFrameAvailable(const void* /*frame*/,
-                                         nsecs_t timestamp,
-                                         EmulatedCameraDevice* camera_dev) {
-  int res;
-  Mutex::Autolock locker(&mObjectLock);
-
-  if (!isPreviewEnabled() || mPreviewWindow == NULL || !isPreviewTime()) {
-    return;
-  }
-
-  /* Make sure that preview window dimensions are OK with the camera device */
-  if (adjustPreviewDimensions(camera_dev)) {
-    /* Need to set / adjust buffer geometry for the preview window.
-     * Note that in the emulator preview window uses only RGB for pixel
-     * formats. */
-    ALOGV("%s: Adjusting preview windows %p geometry to %dx%d", __FUNCTION__,
-          mPreviewWindow, mPreviewFrameWidth, mPreviewFrameHeight);
-    res = mPreviewWindow->set_buffers_geometry(
-        mPreviewWindow, mPreviewFrameWidth, mPreviewFrameHeight,
-        HAL_PIXEL_FORMAT_RGBA_8888);
-    if (res != NO_ERROR) {
-      ALOGE("%s: Error in set_buffers_geometry %d -> %s", __FUNCTION__, -res,
-            strerror(-res));
-      return;
-    }
-  }
-
-  /*
-   * Push new frame to the preview window.
-   */
-
-  /* Dequeue preview window buffer for the frame. */
-  buffer_handle_t* buffer = NULL;
-  int stride = 0;
-  res = mPreviewWindow->dequeue_buffer(mPreviewWindow, &buffer, &stride);
-  if (res != NO_ERROR || buffer == NULL) {
-    ALOGE("%s: Unable to dequeue preview window buffer: %d -> %s", __FUNCTION__,
-          -res, strerror(-res));
-    return;
-  }
-
-  /* Let the preview window to lock the buffer. */
-  res = mPreviewWindow->lock_buffer(mPreviewWindow, buffer);
-  if (res != NO_ERROR) {
-    ALOGE("%s: Unable to lock preview window buffer: %d -> %s", __FUNCTION__,
-          -res, strerror(-res));
-    mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
-    return;
-  }
-
-  /* Now let the graphics framework to lock the buffer, and provide
-   * us with the framebuffer data address. */
-  void* img = NULL;
-  res = GrallocModule::getInstance().lock(*buffer, GRALLOC_USAGE_SW_WRITE_OFTEN,
-                                          0, 0, mPreviewFrameWidth,
-                                          mPreviewFrameHeight, &img);
-  if (res != NO_ERROR) {
-    ALOGE("%s: gralloc.lock failure: %d -> %s", __FUNCTION__, res,
-          strerror(res));
-    mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
-    return;
-  }
-
-  /* Frames come in in YV12/NV12/NV21 format. Since preview window doesn't
-   * supports those formats, we need to obtain the frame in RGB565. */
-  res = camera_dev->getCurrentPreviewFrame(img);
-  if (res == NO_ERROR) {
-    /* Show it. */
-    mPreviewWindow->set_timestamp(mPreviewWindow, timestamp);
-    mPreviewWindow->enqueue_buffer(mPreviewWindow, buffer);
-  } else {
-    ALOGE("%s: Unable to obtain preview frame: %d", __FUNCTION__, res);
-    mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
-  }
-  GrallocModule::getInstance().unlock(*buffer);
-}
-
-/***************************************************************************
- * Private API
- **************************************************************************/
-
-bool PreviewWindow::adjustPreviewDimensions(EmulatedCameraDevice* camera_dev) {
-  /* Match the cached frame dimensions against the actual ones. */
-  if (mPreviewFrameWidth == camera_dev->getFrameWidth() &&
-      mPreviewFrameHeight == camera_dev->getFrameHeight()) {
-    /* They match. */
-    return false;
-  }
-
-  /* They don't match: adjust the cache. */
-  mPreviewFrameWidth = camera_dev->getFrameWidth();
-  mPreviewFrameHeight = camera_dev->getFrameHeight();
-
-  return true;
-}
-
-bool PreviewWindow::isPreviewTime() {
-  timeval cur_time;
-  gettimeofday(&cur_time, NULL);
-  const uint64_t cur_mks = cur_time.tv_sec * 1000000LL + cur_time.tv_usec;
-  if ((cur_mks - mLastPreviewed) >= mPreviewAfter) {
-    mLastPreviewed = cur_mks;
-    return true;
-  }
-  return false;
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/PreviewWindow.h b/guest/hals/camera/PreviewWindow.h
deleted file mode 100644
index 0041c55..0000000
--- a/guest/hals/camera/PreviewWindow.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_PREVIEW_WINDOW_H
-#define HW_EMULATOR_CAMERA_PREVIEW_WINDOW_H
-
-#include <hardware/camera.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/Timers.h>
-
-/*
- * Contains declaration of a class PreviewWindow that encapsulates functionality
- * of a preview window set via set_preview_window camera HAL API.
- */
-
-namespace android {
-
-class EmulatedCameraDevice;
-
-/* Encapsulates functionality of a preview window set via set_preview_window
- * camera HAL API.
- *
- * Objects of this class are contained in EmulatedCamera objects, and handle
- * relevant camera API callbacks.
- */
-class PreviewWindow {
- public:
-  /* Constructs PreviewWindow instance. */
-  PreviewWindow();
-
-  /* Destructs PreviewWindow instance. */
-  ~PreviewWindow();
-
-  /***************************************************************************
-   * Camera API
-   **************************************************************************/
-
- public:
-  /* Actual handler for camera_device_ops_t::set_preview_window callback.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::set_preview_window callback.
-   * Param:
-   *  window - Preview window to set. This parameter might be NULL, which
-   *      indicates preview window reset.
-   *  preview_fps - Preview's frame frequency. This parameter determins when
-   *      a frame received via onNextFrameAvailable call will be pushed to
-   *      the preview window. If 'window' parameter passed to this method is
-   *      NULL, this parameter is ignored.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  status_t setPreviewWindow(struct preview_stream_ops* window, int preview_fps);
-
-  /* Starts the preview.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::start_preview callback.
-   */
-  status_t startPreview();
-
-  /* Stops the preview.
-   * This method is called by the containing emulated camera object when it is
-   * handing the camera_device_ops_t::start_preview callback.
-   */
-  void stopPreview();
-
-  /* Checks if preview is enabled. */
-  inline bool isPreviewEnabled() { return mPreviewEnabled; }
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  /* Next frame is available in the camera device.
-   * This is a notification callback that is invoked by the camera device when
-   * a new frame is available.
-   * Note that most likely this method is called in context of a worker thread
-   * that camera device has created for frame capturing.
-   * Param:
-   *  frame - Captured frame, or NULL if camera device didn't pull the frame
-   *      yet. If NULL is passed in this parameter use GetCurrentFrame method
-   *      of the camera device class to obtain the next frame. Also note that
-   *      the size of the frame that is passed here (as well as the frame
-   *      returned from the GetCurrentFrame method) is defined by the current
-   *      frame settings (width + height + pixel format) for the camera device.
-   * timestamp - Frame's timestamp.
-   * camera_dev - Camera device instance that delivered the frame.
-   */
-  void onNextFrameAvailable(const void* frame, nsecs_t timestamp,
-                            EmulatedCameraDevice* camera_dev);
-
-  /***************************************************************************
-   * Private API
-   **************************************************************************/
-
- protected:
-  /* Adjusts cached dimensions of the preview window frame according to the
-   * frame dimensions used by the camera device.
-   *
-   * When preview is started, it's not known (hard to define) what are going
-   * to be the dimensions of the frames that are going to be displayed. Plus,
-   * it might be possible, that such dimensions can be changed on the fly. So,
-   * in order to be always in sync with frame dimensions, this method is
-   * called for each frame passed to onNextFrameAvailable method, in order to
-   * properly adjust frame dimensions, used by the preview window.
-   * Note that this method must be called while object is locked.
-   * Param:
-   *  camera_dev - Camera device, prpviding frames displayed in the preview
-   *      window.
-   * Return:
-   *  true if cached dimensions have been adjusted, or false if cached
-   *  dimensions match device's frame dimensions.
-   */
-  bool adjustPreviewDimensions(EmulatedCameraDevice* camera_dev);
-
-  /* Checks if it's the time to push new frame to the preview window.
-   * Note that this method must be called while object is locked. */
-  bool isPreviewTime();
-
-  /***************************************************************************
-   * Data members
-   **************************************************************************/
-
- protected:
-  /* Locks this instance for data changes. */
-  Mutex mObjectLock;
-
-  /* Preview window instance. */
-  preview_stream_ops* mPreviewWindow;
-
-  /* Timestamp (abs. microseconds) when last frame has been pushed to the
-   * preview window. */
-  uint64_t mLastPreviewed;
-
-  /* Preview frequency in microseconds. */
-  uint32_t mPreviewAfter;
-
-  /*
-   * Cached preview window frame dimensions.
-   */
-
-  int mPreviewFrameWidth;
-  int mPreviewFrameHeight;
-
-  /* Preview status. */
-  bool mPreviewEnabled;
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_PREVIEW_WINDOW_H */
diff --git a/guest/hals/camera/QemuClient.cpp b/guest/hals/camera/QemuClient.cpp
deleted file mode 100644
index eb89702..0000000
--- a/guest/hals/camera/QemuClient.cpp
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Contains implementation of classes that encapsulate connection to camera
- * services in the emulator via qemu pipe.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_QemuClient"
-#include "QemuClient.h"
-#include <log/log.h>
-#include "EmulatedCamera.h"
-
-#define LOG_QUERIES 0
-#if LOG_QUERIES
-#define LOGQ(...) ALOGD(__VA_ARGS__)
-#else
-#define LOGQ(...) (void(0))
-
-#endif  // LOG_QUERIES
-namespace android {
-
-/****************************************************************************
- * Qemu query
- ***************************************************************************/
-
-QemuQuery::QemuQuery()
-    : mQuery(mQueryPrealloc),
-      mQueryDeliveryStatus(NO_ERROR),
-      mReplyBuffer(NULL),
-      mReplyData(NULL),
-      mReplySize(0),
-      mReplyDataSize(0),
-      mReplyStatus(0) {
-  *mQuery = '\0';
-}
-
-QemuQuery::QemuQuery(const char* query_string)
-    : mQuery(mQueryPrealloc),
-      mQueryDeliveryStatus(NO_ERROR),
-      mReplyBuffer(NULL),
-      mReplyData(NULL),
-      mReplySize(0),
-      mReplyDataSize(0),
-      mReplyStatus(0) {
-  mQueryDeliveryStatus = QemuQuery::createQuery(query_string, NULL);
-}
-
-QemuQuery::QemuQuery(const char* query_name, const char* query_param)
-    : mQuery(mQueryPrealloc),
-      mQueryDeliveryStatus(NO_ERROR),
-      mReplyBuffer(NULL),
-      mReplyData(NULL),
-      mReplySize(0),
-      mReplyDataSize(0),
-      mReplyStatus(0) {
-  mQueryDeliveryStatus = QemuQuery::createQuery(query_name, query_param);
-}
-
-QemuQuery::~QemuQuery() { QemuQuery::resetQuery(); }
-
-status_t QemuQuery::createQuery(const char* name, const char* param) {
-  /* Reset from the previous use. */
-  resetQuery();
-
-  /* Query name cannot be NULL or an empty string. */
-  if (name == NULL || *name == '\0') {
-    ALOGE("%s: NULL or an empty string is passed as query name.", __FUNCTION__);
-    mQueryDeliveryStatus = EINVAL;
-    return EINVAL;
-  }
-
-  const size_t name_len = strlen(name);
-  const size_t param_len = (param != NULL) ? strlen(param) : 0;
-  const size_t required = strlen(name) + (param_len ? (param_len + 2) : 1);
-
-  if (required > sizeof(mQueryPrealloc)) {
-    /* Preallocated buffer was too small. Allocate a bigger query buffer. */
-    mQuery = new char[required];
-    if (mQuery == NULL) {
-      ALOGE("%s: Unable to allocate %zu bytes for query buffer", __FUNCTION__,
-            required);
-      mQueryDeliveryStatus = ENOMEM;
-      return ENOMEM;
-    }
-  }
-
-  /* At this point mQuery buffer is big enough for the query. */
-  if (param_len) {
-    sprintf(mQuery, "%s %s", name, param);
-  } else {
-    memcpy(mQuery, name, name_len + 1);
-  }
-
-  return NO_ERROR;
-}
-
-status_t QemuQuery::completeQuery(status_t status) {
-  /* Save query completion status. */
-  mQueryDeliveryStatus = status;
-  if (mQueryDeliveryStatus != NO_ERROR) {
-    return mQueryDeliveryStatus;
-  }
-
-  /* Make sure reply buffer contains at least 'ok', or 'ko'.
-   * Note that 'ok', or 'ko' prefixes are always 3 characters long: in case
-   * there are more data in the reply, that data will be separated from
-   * 'ok'/'ko' with a ':'. If there is no more data in the reply, the prefix
-   * will be
-   * zero-terminated, and the terminator will be inculded in the reply. */
-  if (mReplyBuffer == NULL || mReplySize < 3) {
-    ALOGE("%s: Invalid reply to the query", __FUNCTION__);
-    mQueryDeliveryStatus = EINVAL;
-    return EINVAL;
-  }
-
-  /* Lets see the reply status. */
-  if (!memcmp(mReplyBuffer, "ok", 2)) {
-    mReplyStatus = 1;
-  } else if (!memcmp(mReplyBuffer, "ko", 2)) {
-    mReplyStatus = 0;
-  } else {
-    ALOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
-    mQueryDeliveryStatus = EINVAL;
-    return EINVAL;
-  }
-
-  /* Lets see if there are reply data that follow. */
-  if (mReplySize > 3) {
-    /* There are extra data. Make sure they are separated from the status
-     * with a ':' */
-    if (mReplyBuffer[2] != ':') {
-      ALOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
-      mQueryDeliveryStatus = EINVAL;
-      return EINVAL;
-    }
-    mReplyData = mReplyBuffer + 3;
-    mReplyDataSize = mReplySize - 3;
-  } else {
-    /* Make sure reply buffer containing just 'ok'/'ko' ends with
-     * zero-terminator. */
-    if (mReplyBuffer[2] != '\0') {
-      ALOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
-      mQueryDeliveryStatus = EINVAL;
-      return EINVAL;
-    }
-  }
-
-  return NO_ERROR;
-}
-
-void QemuQuery::resetQuery() {
-  if (mQuery != NULL && mQuery != mQueryPrealloc) {
-    delete[] mQuery;
-  }
-  mQuery = mQueryPrealloc;
-  mQueryDeliveryStatus = NO_ERROR;
-  if (mReplyBuffer != NULL) {
-    free(mReplyBuffer);
-    mReplyBuffer = NULL;
-  }
-  mReplyData = NULL;
-  mReplySize = mReplyDataSize = 0;
-  mReplyStatus = 0;
-}
-
-/****************************************************************************
- * Qemu client base
- ***************************************************************************/
-
-/* Camera service name. */
-const char QemuClient::mCameraServiceName[] = "camera";
-
-QemuClient::QemuClient() : mPipeFD(-1) {}
-
-QemuClient::~QemuClient() {
-  if (mPipeFD >= 0) {
-    close(mPipeFD);
-  }
-}
-
-/****************************************************************************
- * Qemu client API
- ***************************************************************************/
-
-status_t QemuClient::connectClient(const char* param) {
-  ALOGV("%s: '%s'", __FUNCTION__, param ? param : "");
-
-  /* Make sure that client is not connected already. */
-  if (mPipeFD >= 0) {
-    ALOGE("%s: Qemu client is already connected", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* Select one of the two: 'factory', or 'emulated camera' service */
-  if (param == NULL || *param == '\0') {
-    /* No parameters: connect to the factory service. */
-    char pipe_name[512];
-    snprintf(pipe_name, sizeof(pipe_name), "qemud:%s", mCameraServiceName);
-    mPipeFD = qemu_pipe_open(pipe_name);
-  } else {
-    /* One extra char ':' that separates service name and parameters + six
-     * characters for 'qemud:'. This is required by qemu pipe protocol. */
-    char* connection_str =
-        new char[strlen(mCameraServiceName) + strlen(param) + 8];
-    sprintf(connection_str, "qemud:%s:%s", mCameraServiceName, param);
-
-    mPipeFD = qemu_pipe_open(connection_str);
-    delete[] connection_str;
-  }
-  if (mPipeFD < 0) {
-    ALOGE("%s: Unable to connect to the camera service '%s': %s", __FUNCTION__,
-          param ? param : "Factory", strerror(errno));
-    return errno ? errno : EINVAL;
-  }
-
-  return NO_ERROR;
-}
-
-void QemuClient::disconnectClient() {
-  ALOGV("%s", __FUNCTION__);
-
-  if (mPipeFD >= 0) {
-    close(mPipeFD);
-    mPipeFD = -1;
-  }
-}
-
-status_t QemuClient::sendMessage(const void* data, size_t data_size) {
-  if (mPipeFD < 0) {
-    ALOGE("%s: Qemu client is not connected", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* Note that we don't use here qemud_client_send, since with qemu pipes we
-   * don't need to provide payload size prior to payload when we're writing to
-   * the pipe. So, we can use simple write, and qemu pipe will take care of the
-   * rest, calling the receiving end with the number of bytes transferred. */
-  const size_t written = qemud_fd_write(mPipeFD, data, data_size);
-  if (written == data_size) {
-    return NO_ERROR;
-  } else {
-    ALOGE("%s: Error sending data via qemu pipe: '%s'", __FUNCTION__,
-          strerror(errno));
-    return errno ? errno : EIO;
-  }
-}
-
-status_t QemuClient::receiveMessage(void** data, size_t* data_size) {
-  *data = NULL;
-  *data_size = 0;
-
-  if (mPipeFD < 0) {
-    ALOGE("%s: Qemu client is not connected", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* The way the service replies to a query, it sends payload size first, and
-   * then it sends the payload itself. Note that payload size is sent as a
-   * string, containing 8 characters representing a hexadecimal payload size
-   * value. Note also, that the string doesn't contain zero-terminator. */
-  size_t payload_size;
-  char payload_size_str[9];
-  int rd_res = qemud_fd_read(mPipeFD, payload_size_str, 8);
-  if (rd_res != 8) {
-    ALOGE("%s: Unable to obtain payload size: %s", __FUNCTION__,
-          strerror(errno));
-    return errno ? errno : EIO;
-  }
-
-  /* Convert payload size. */
-  errno = 0;
-  payload_size_str[8] = '\0';
-  payload_size = strtol(payload_size_str, NULL, 16);
-  if (errno) {
-    ALOGE("%s: Invalid payload size '%s'", __FUNCTION__, payload_size_str);
-    return EIO;
-  }
-
-  /* Allocate payload data buffer, and read the payload there. */
-  *data = malloc(payload_size);
-  if (*data == NULL) {
-    ALOGE("%s: Unable to allocate %zu bytes payload buffer", __FUNCTION__,
-          payload_size);
-    return ENOMEM;
-  }
-  rd_res = qemud_fd_read(mPipeFD, *data, payload_size);
-  if (static_cast<size_t>(rd_res) == payload_size) {
-    *data_size = payload_size;
-    return NO_ERROR;
-  } else {
-    ALOGE("%s: Read size %d doesnt match expected payload size %zu: %s",
-          __FUNCTION__, rd_res, payload_size, strerror(errno));
-    free(*data);
-    *data = NULL;
-    return errno ? errno : EIO;
-  }
-}
-
-status_t QemuClient::doQuery(QemuQuery* query) {
-  /* Make sure that query has been successfuly constructed. */
-  if (query->mQueryDeliveryStatus != NO_ERROR) {
-    ALOGE("%s: Query is invalid", __FUNCTION__);
-    return query->mQueryDeliveryStatus;
-  }
-
-  LOGQ("Send query '%s'", query->mQuery);
-
-  /* Send the query. */
-  status_t res = sendMessage(query->mQuery, strlen(query->mQuery) + 1);
-  if (res == NO_ERROR) {
-    /* Read the response. */
-    res = receiveMessage(reinterpret_cast<void**>(&query->mReplyBuffer),
-                         &query->mReplySize);
-    if (res == NO_ERROR) {
-      LOGQ("Response to query '%s': Status = '%.2s', %d bytes in response",
-           query->mQuery, query->mReplyBuffer, query->mReplySize);
-    } else {
-      ALOGE("%s Response to query '%s' has failed: %s", __FUNCTION__,
-            query->mQuery, strerror(res));
-    }
-  } else {
-    ALOGE("%s: Send query '%s' failed: %s", __FUNCTION__, query->mQuery,
-          strerror(res));
-  }
-
-  /* Complete the query, and return its completion handling status. */
-  const status_t res1 = query->completeQuery(res);
-  ALOGE_IF(res1 != NO_ERROR && res1 != res,
-           "%s: Error %d in query '%s' completion", __FUNCTION__, res1,
-           query->mQuery);
-  return res1;
-}
-
-/****************************************************************************
- * Qemu client for the 'factory' service.
- ***************************************************************************/
-
-/*
- * Factory service queries.
- */
-
-/* Queries list of cameras connected to the host. */
-const char FactoryQemuClient::mQueryList[] = "list";
-
-FactoryQemuClient::FactoryQemuClient() : QemuClient() {}
-
-FactoryQemuClient::~FactoryQemuClient() {}
-
-status_t FactoryQemuClient::listCameras(char** list) {
-  ALOGV("%s", __FUNCTION__);
-
-  QemuQuery query(mQueryList);
-  if (doQuery(&query) || !query.isQuerySucceeded()) {
-    ALOGE("%s: List cameras query failed: %s", __FUNCTION__,
-          query.mReplyData ? query.mReplyData : "No error message");
-    return query.getCompletionStatus();
-  }
-
-  /* Make sure there is a list returned. */
-  if (query.mReplyDataSize == 0) {
-    ALOGE("%s: No camera list is returned.", __FUNCTION__);
-    return EINVAL;
-  }
-
-  /* Copy the list over. */
-  *list = (char*)malloc(query.mReplyDataSize);
-  if (*list != NULL) {
-    memcpy(*list, query.mReplyData, query.mReplyDataSize);
-    ALOGD("Emulated camera list: %s", *list);
-    return NO_ERROR;
-  } else {
-    ALOGE("%s: Unable to allocate %zu bytes", __FUNCTION__,
-          query.mReplyDataSize);
-    return ENOMEM;
-  }
-}
-
-/****************************************************************************
- * Qemu client for an 'emulated camera' service.
- ***************************************************************************/
-
-/*
- * Emulated camera queries
- */
-
-/* Connect to the camera device. */
-const char CameraQemuClient::mQueryConnect[] = "connect";
-/* Disconect from the camera device. */
-const char CameraQemuClient::mQueryDisconnect[] = "disconnect";
-/* Start capturing video from the camera device. */
-const char CameraQemuClient::mQueryStart[] = "start";
-/* Stop capturing video from the camera device. */
-const char CameraQemuClient::mQueryStop[] = "stop";
-/* Get next video frame from the camera device. */
-const char CameraQemuClient::mQueryFrame[] = "frame";
-
-CameraQemuClient::CameraQemuClient() : QemuClient() {}
-
-CameraQemuClient::~CameraQemuClient() {}
-
-status_t CameraQemuClient::queryConnect() {
-  ALOGV("%s", __FUNCTION__);
-
-  QemuQuery query(mQueryConnect);
-  doQuery(&query);
-  const status_t res = query.getCompletionStatus();
-  ALOGE_IF(res != NO_ERROR, "%s: Query failed: %s", __FUNCTION__,
-           query.mReplyData ? query.mReplyData : "No error message");
-  return res;
-}
-
-status_t CameraQemuClient::queryDisconnect() {
-  ALOGV("%s", __FUNCTION__);
-
-  QemuQuery query(mQueryDisconnect);
-  doQuery(&query);
-  const status_t res = query.getCompletionStatus();
-  ALOGE_IF(res != NO_ERROR, "%s: Query failed: %s", __FUNCTION__,
-           query.mReplyData ? query.mReplyData : "No error message");
-  return res;
-}
-
-status_t CameraQemuClient::queryStart(uint32_t pixel_format, int width,
-                                      int height) {
-  ALOGV("%s", __FUNCTION__);
-
-  char query_str[256];
-  snprintf(query_str, sizeof(query_str), "%s dim=%dx%d pix=%d", mQueryStart,
-           width, height, pixel_format);
-  QemuQuery query(query_str);
-  doQuery(&query);
-  const status_t res = query.getCompletionStatus();
-  ALOGE_IF(res != NO_ERROR, "%s: Query failed: %s", __FUNCTION__,
-           query.mReplyData ? query.mReplyData : "No error message");
-  return res;
-}
-
-status_t CameraQemuClient::queryStop() {
-  ALOGV("%s", __FUNCTION__);
-
-  QemuQuery query(mQueryStop);
-  doQuery(&query);
-  const status_t res = query.getCompletionStatus();
-  ALOGE_IF(res != NO_ERROR, "%s: Query failed: %s", __FUNCTION__,
-           query.mReplyData ? query.mReplyData : "No error message");
-  return res;
-}
-
-status_t CameraQemuClient::queryFrame(void* vframe, void* pframe,
-                                      size_t vframe_size, size_t pframe_size,
-                                      float r_scale, float g_scale,
-                                      float b_scale, float exposure_comp) {
-  ALOGV("%s", __FUNCTION__);
-
-  char query_str[256];
-  snprintf(query_str, sizeof(query_str),
-           "%s video=%zu preview=%zu whiteb=%g,%g,%g expcomp=%g", mQueryFrame,
-           (vframe && vframe_size) ? vframe_size : 0,
-           (pframe && pframe_size) ? pframe_size : 0, r_scale, g_scale, b_scale,
-           exposure_comp);
-  QemuQuery query(query_str);
-  doQuery(&query);
-  const status_t res = query.getCompletionStatus();
-  if (res != NO_ERROR) {
-    ALOGE("%s: Query failed: %s", __FUNCTION__,
-          query.mReplyData ? query.mReplyData : "No error message");
-    return res;
-  }
-
-  /* Copy requested frames. */
-  size_t cur_offset = 0;
-  const uint8_t* frame = reinterpret_cast<const uint8_t*>(query.mReplyData);
-  /* Video frame is always first. */
-  if (vframe != NULL && vframe_size != 0) {
-    /* Make sure that video frame is in. */
-    if ((query.mReplyDataSize - cur_offset) >= vframe_size) {
-      memcpy(vframe, frame, vframe_size);
-      cur_offset += vframe_size;
-    } else {
-      ALOGE("%s: Reply %zu bytes is to small to contain %zu bytes video frame",
-            __FUNCTION__, query.mReplyDataSize - cur_offset, vframe_size);
-      return EINVAL;
-    }
-  }
-  if (pframe != NULL && pframe_size != 0) {
-    /* Make sure that preview frame is in. */
-    if ((query.mReplyDataSize - cur_offset) >= pframe_size) {
-      memcpy(pframe, frame + cur_offset, pframe_size);
-      cur_offset += pframe_size;
-    } else {
-      ALOGE(
-          "%s: Reply %zu bytes is to small to contain %zu bytes preview frame",
-          __FUNCTION__, query.mReplyDataSize - cur_offset, pframe_size);
-      return EINVAL;
-    }
-  }
-
-  return NO_ERROR;
-}
-
-}; /* namespace android */
diff --git a/guest/hals/camera/QemuClient.h b/guest/hals/camera/QemuClient.h
deleted file mode 100644
index 290ab41..0000000
--- a/guest/hals/camera/QemuClient.h
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef HW_EMULATOR_CAMERA_QEMU_CLIENT_H
-#define HW_EMULATOR_CAMERA_QEMU_CLIENT_H
-
-/*
- * Contains declaration of classes that encapsulate connection to camera
- * services in the emulator via qemu pipe.
- */
-
-#include <hardware/qemud.h>
-
-namespace android {
-
-/****************************************************************************
- * Qemu query
- ***************************************************************************/
-
-/* Encapsulates a query to the emulator.
- * Guest exchanges data with the emulator via queries sent over the qemu pipe.
- * The queries as well as replies to the queries are all strings (except for the
- * 'frame' query where reply is a framebuffer).
- * Each query is formatted as such:
- *
- *      "<query name>[ <parameters>]",
- *
- * where <query name> is a string representing query name, and <parameters> are
- * optional parameters for the query. If parameters are present, they must be
- * separated from the query name with a single space, and they must be formatted
- * as such:
- *
- *      "<name1>=<value1> <name2>=<value2> ... <nameN>=<valueN>"
- *
- * I.e.:
- *  - Every parameter must have a name, and a value.
- *  - Name and value must be separated with '='.
- *  - No spaces are allowed around '=' separating name and value.
- *  - Parameters must be separated with a single space character.
- *  - No '=' character is allowed in name and in value.
- *
- * There are certain restrictions on strings used in the query:
- *  - Spaces are allowed only as separators.
- *  - '=' are allowed only to divide parameter names from parameter values.
- *
- * Emulator replies to each query in two chunks:
- * - 8 bytes encoding the payload size as a string containing hexadecimal
- *   representation of the payload size value. This is done in order to simplify
- *   dealing with different endianness on the host, and on the guest.
- * - Payload, whose size is defined by the first chunk.
- *
- * Every payload always begins with two characters, encoding the result of the
- * query:
- *  - 'ok' Encoding the success
- *  - 'ko' Encoding a failure.
- * After that payload may have optional data. If payload has more data following
- * the query result, there is a ':' character separating them. If payload
- * carries only the result, it always ends with a zero-terminator. So, payload
- * 'ok'/'ko' prefix is always 3 bytes long: it either includes a
- * zero-terminator, if there is no data, or a ':' separator.
- */
-class QemuQuery {
- public:
-  /* Constructs an uninitialized QemuQuery instance. */
-  QemuQuery();
-
-  /* Constructs and initializes QemuQuery instance for a query.
-   * Param:
-   *  query_string - Query string. This constructor can also be used to
-   *      construct a query that doesn't have parameters. In this case query
-   *      name can be passed as a parameter here.
-   */
-  explicit QemuQuery(const char* query_string);
-
-  /* Constructs and initializes QemuQuery instance for a query with parameters.
-   * Param:
-   *  query_name - Query name.
-   *  query_param - Query parameters. Can be NULL.
-   */
-  QemuQuery(const char* query_name, const char* query_param);
-
-  /* Destructs QemuQuery instance. */
-  ~QemuQuery();
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
-  /* Creates new query.
-   * Note: this method will reset this instance prior to creating a new query
-   * in order to discard possible "leftovers" from the previous query.
-   * Param:
-   *  query_name - Query name.
-   *  query_param - Query parameters. Can be NULL.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  status_t createQuery(const char* name, const char* param);
-
-  /* Completes the query after a reply from the emulator.
-   * This method will parse the reply buffer, and calculate the final query
-   * status, which depends not only on the transport success / failure, but
-   * also on 'ok' / 'ko' in the reply buffer.
-   * Param:
-   *  status - Query delivery status. This status doesn't necessarily reflects
-   *      the final query status (which is defined by 'ok'/'ko' prefix in the
-   *      reply buffer). This status simply states whether or not the query has
-   *      been sent, and a reply has been received successfuly. However, if
-   *      this status indicates a failure, it means that the entire query has
-   *      failed.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure. Note that
-   *  status returned here just signals whether or not the method has succeeded.
-   *  Use isQuerySucceeded() / getCompletionStatus() methods of this class to
-   *  check the final query status.
-   */
-  status_t completeQuery(status_t status);
-
-  /* Resets the query from a previous use. */
-  void resetQuery();
-
-  /* Checks if query has succeeded.
-   * Note that this method must be called after completeQuery() method of this
-   * class has been executed.
-   */
-  inline bool isQuerySucceeded() const {
-    return mQueryDeliveryStatus == NO_ERROR && mReplyStatus != 0;
-  }
-
-  /* Gets final completion status of the query.
-   * Note that this method must be called after completeQuery() method of this
-   * class has been executed.
-   * Return:
-   *  NO_ERROR if query has succeeded, or an appropriate error status on query
-   *  failure.
-   */
-  inline status_t getCompletionStatus() const {
-    if (mQueryDeliveryStatus == NO_ERROR) {
-      if (mReplyStatus) {
-        return NO_ERROR;
-      } else {
-        return EINVAL;
-      }
-    } else {
-      return mQueryDeliveryStatus;
-    }
-  }
-
-  /****************************************************************************
-   * Public data memebers
-   ***************************************************************************/
-
- public:
-  /* Query string. */
-  char* mQuery;
-  /* Query delivery status. */
-  status_t mQueryDeliveryStatus;
-  /* Reply buffer */
-  char* mReplyBuffer;
-  /* Reply data (past 'ok'/'ko'). If NULL, there were no data in reply. */
-  char* mReplyData;
-  /* Reply buffer size. */
-  size_t mReplySize;
-  /* Reply data size. */
-  size_t mReplyDataSize;
-  /* Reply status: 1 - ok, 0 - ko. */
-  int mReplyStatus;
-
-  /****************************************************************************
-   * Private data memebers
-   ***************************************************************************/
-
- protected:
-  /* Preallocated buffer for small queries. */
-  char mQueryPrealloc[256];
-};
-
-/****************************************************************************
- * Qemu client base
- ***************************************************************************/
-
-/* Encapsulates a connection to the 'camera' service in the emulator via qemu
- * pipe.
- */
-class QemuClient {
- public:
-  /* Constructs QemuClient instance. */
-  QemuClient();
-
-  /* Destructs QemuClient instance. */
-  virtual ~QemuClient();
-
-  /****************************************************************************
-   * Qemu client API
-   ***************************************************************************/
-
- public:
-  /* Connects to the 'camera' service in the emulator via qemu pipe.
-   * Param:
-   *  param - Parameters to pass to the camera service. There are two types of
-   *      camera services implemented by the emulator. The first one is a
-   *      'camera factory' type of service that provides list of cameras
-   *      connected to the host. Another one is an 'emulated camera' type of
-   *      service that provides interface to a camera connected to the host. At
-   *      the connection time emulator makes distinction between the two by
-   *      looking at connection parameters: no parameters means connection to
-   *      the 'factory' service, while connection with parameters means
-   *      connection to an 'emulated camera' service, where camera is identified
-   *      by one of the connection parameters. So, passing NULL, or an empty
-   *      string to this method will establish a connection with the 'factory'
-   *      service, while not empty string passed here will establish connection
-   *      with an 'emulated camera' service. Parameters defining the emulated
-   *      camera must be formatted as such:
-   *
-   *          "name=<device name> [inp_channel=<input channel #>]",
-   *
-   *      where 'device name' is a required parameter defining name of the
-   *      camera device, and 'input channel' is an optional parameter (positive
-   *      integer), defining the input channel to use on the camera device.
-   *      Note that device name passed here must have been previously obtained
-   *      from the factory service using 'list' query.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status.
-   */
-  virtual status_t connectClient(const char* param);
-
-  /* Disconnects from the service. */
-  virtual void disconnectClient();
-
-  /* Sends data to the service.
-   * Param:
-   *  data, data_size - Data to send.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  virtual status_t sendMessage(const void* data, size_t data_size);
-
-  /* Receives data from the service.
-   * This method assumes that data to receive will come in two chunks: 8
-   * characters encoding the payload size in hexadecimal string, followed by
-   * the paylod (if any).
-   * This method will allocate data buffer where to receive the response.
-   * Param:
-   *  data - Upon success contains address of the allocated data buffer with
-   *      the data received from the service. The caller is responsible for
-   *      freeing allocated data buffer.
-   *  data_size - Upon success contains size of the data received from the
-   *      service.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  virtual status_t receiveMessage(void** data, size_t* data_size);
-
-  /* Sends a query, and receives a response from the service.
-   * Param:
-   *  query - Query to send to the service. When this method returns, the query
-   *  is completed, and all its relevant data members are properly initialized.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure. Note that
-   *  status returned here is not the final query status. Use
-   * isQuerySucceeded(), or getCompletionStatus() method on the query object to
-   * see if it has succeeded. However, if this method returns a failure, it
-   * means that the query has failed, and there is no guarantee that its data
-   * members are properly initialized (except for the 'mQueryDeliveryStatus',
-   * which is always in the proper state).
-   */
-  virtual status_t doQuery(QemuQuery* query);
-
-  /****************************************************************************
-   * Data members
-   ***************************************************************************/
-
- protected:
-  /* Qemu pipe handle. */
-  int mPipeFD;
-
- private:
-  /* Camera service name. */
-  static const char mCameraServiceName[];
-};
-
-/****************************************************************************
- * Qemu client for the 'factory' service.
- ***************************************************************************/
-
-/* Encapsulates QemuClient for the 'factory' service. */
-class FactoryQemuClient : public QemuClient {
- public:
-  /* Constructs FactoryQemuClient instance. */
-  FactoryQemuClient();
-
-  /* Destructs FactoryQemuClient instance. */
-  ~FactoryQemuClient();
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  /* Lists camera devices connected to the host.
-   * Param:
-   *  list - Upon success contains a list of cameras connected to the host. The
-   *      list returned here is represented as a string, containing multiple
-   *      lines separated with '\n', where each line represents a camera. Each
-   *      camera line is formatted as such:
-   *
-   *          "name=<device name> channel=<num> pix=<num>
-   * framedims=<dimensions>\n"
-   *
-   *      Where:
-   *      - 'name' is the name of the camera device attached to the host. This
-   *        name must be used for subsequent connection to the 'emulated camera'
-   *        service for that camera.
-   *      - 'channel' - input channel number (positive int) to use to
-   * communicate with the camera.
-   *      - 'pix' - pixel format (a "fourcc" uint), chosen for the video frames
-   *        by the camera service.
-   *      - 'framedims' contains a list of frame dimensions supported by the
-   *        camera for the chosen pixel format. Each etry in the list is in form
-   *        '<width>x<height>', where 'width' and 'height' are numeric values
-   *        for width and height of a supported frame dimension. Entries in
-   *        this list are separated with ',' with no spaces between the entries.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  status_t listCameras(char** list);
-
-  /****************************************************************************
-   * Names of the queries available for the emulated camera factory.
-   ***************************************************************************/
-
- private:
-  /* List cameras connected to the host. */
-  static const char mQueryList[];
-};
-
-/****************************************************************************
- * Qemu client for an 'emulated camera' service.
- ***************************************************************************/
-
-/* Encapsulates QemuClient for an 'emulated camera' service.
- */
-class CameraQemuClient : public QemuClient {
- public:
-  /* Constructs CameraQemuClient instance. */
-  CameraQemuClient();
-
-  /* Destructs CameraQemuClient instance. */
-  ~CameraQemuClient();
-
-  /****************************************************************************
-   * Public API
-   ***************************************************************************/
-
- public:
-  /* Queries camera connection.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  status_t queryConnect();
-
-  /* Queries camera disconnection.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  status_t queryDisconnect();
-
-  /* Queries camera to start capturing video.
-   * Param:
-   *  pixel_format - Pixel format that is used by the client to push video
-   *      frames to the camera framework.
-   *  width, height - Frame dimensions, requested by the framework.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  status_t queryStart(uint32_t pixel_format, int width, int height);
-
-  /* Queries camera to stop capturing video.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  status_t queryStop();
-
-  /* Queries camera for the next video frame.
-   * Param:
-   *  vframe, vframe_size - Define buffer, allocated to receive a video frame.
-   *      Any of these parameters can be 0, indicating that the caller is
-   *      interested only in preview frame.
-   *  pframe, pframe_size - Define buffer, allocated to receive a preview frame.
-   *      Any of these parameters can be 0, indicating that the caller is
-   *      interested only in video frame.
-   *  r_scale, g_scale, b_scale - White balance scale.
-   *  exposure_comp - Expsoure compensation.
-   * Return:
-   *  NO_ERROR on success, or an appropriate error status on failure.
-   */
-  status_t queryFrame(void* vframe, void* pframe, size_t vframe_size,
-                      size_t pframe_size, float r_scale, float g_scale,
-                      float b_scale, float exposure_comp);
-
-  /****************************************************************************
-   * Names of the queries available for the emulated camera.
-   ***************************************************************************/
-
- private:
-  /* Connect to the camera. */
-  static const char mQueryConnect[];
-  /* Disconnect from the camera. */
-  static const char mQueryDisconnect[];
-  /* Start video capturing. */
-  static const char mQueryStart[];
-  /* Stop video capturing. */
-  static const char mQueryStop[];
-  /* Query frame(s). */
-  static const char mQueryFrame[];
-};
-
-}; /* namespace android */
-
-#endif /* HW_EMULATOR_CAMERA_QEMU_CLIENT_H */
diff --git a/guest/hals/camera/Thumbnail.cpp b/guest/hals/camera/Thumbnail.cpp
deleted file mode 100644
index e8f8126..0000000
--- a/guest/hals/camera/Thumbnail.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-* Copyright (C) 2016 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.
- */
-
-#include "Thumbnail.h"
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Thumbnail"
-#include <log/log.h>
-#include <libexif/exif-data.h>
-#include <libyuv.h>
-
-#include "JpegCompressor.h"
-
-#include <vector>
-
-/*
- * The NV21 format is a YUV format with an 8-bit Y-component and the U and V
- * components are stored as 8 bits each but they are shared between a block of
- * 2x2 pixels. So when calculating bits per pixel the 16 bits of U and V are
- * shared between 4 pixels leading to 4 bits of U and V per pixel. Together
- * with the 8 bits of Y this gives us 12 bits per pixel..
- *
- * The components are not grouped by pixels but separated into one Y-plane and
- * one interleaved U and V-plane. The first half of the byte sequence is all of
- * the Y data laid out in a linear fashion. After that the interleaved U and V-
- * plane starts with one byte of V followed by one byte of U followed by one
- * byte of V and so on. Each byte of U or V is associated with a 2x2 pixel block
- * in a linear fashion.
- *
- * For an 8 by 4 pixel image the layout would be:
- *
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | Y0  | Y1  | Y2  | Y3  | Y4  | Y5  | Y6  | Y7  |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | Y8  | Y9  | Y10 | Y11 | Y12 | Y13 | Y14 | Y15 |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | Y16 | Y17 | Y18 | Y19 | Y20 | Y21 | Y22 | Y23 |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | Y24 | Y25 | Y26 | Y27 | Y28 | Y29 | Y30 | Y31 |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | V0  | U0  | V1  | U1  | V2  | U2  | V3  | U3  |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | V4  | U4  | V5  | U5  | V6  | U6  | V7  | U7  |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- *
- * In this image V0 and U0 are the V and U components for the 2x2 block of
- * pixels whose Y components are Y0, Y1, Y8 and Y9. V1 and U1 are matched with
- * the Y components Y2, Y3, Y10, Y11, and so on for that row. For the next row
- * of V and U the V4 and U4 components would be paired with Y16, Y17, Y24 and
- * Y25.
- */
-
-namespace android {
-
-static bool createRawThumbnail(const unsigned char* sourceImage,
-                               int sourceWidth, int sourceHeight,
-                               int thumbnailWidth, int thumbnailHeight,
-                               std::vector<unsigned char>* thumbnail) {
-    // Deinterleave the U and V planes into separate planes, this is because
-    // libyuv requires the planes to be separate when scaling
-    const size_t sourceUVPlaneSize = (sourceWidth * sourceHeight) / 4;
-    // Put both U and V planes in one buffer, one after the other, to reduce
-    // memory fragmentation and number of allocations
-    std::vector<unsigned char> sourcePlanes(sourceUVPlaneSize * 2);
-    const unsigned char* ySourcePlane = sourceImage;
-    unsigned char* uSourcePlane = &sourcePlanes[0];
-    unsigned char* vSourcePlane = &sourcePlanes[sourceUVPlaneSize];
-
-    for (size_t i = 0; i < sourceUVPlaneSize; ++i) {
-        vSourcePlane[i] = sourceImage[sourceWidth * sourceHeight + i * 2 + 0];
-        uSourcePlane[i] = sourceImage[sourceWidth * sourceHeight + i * 2 + 1];
-    }
-
-    // Create enough space in the output vector for the result
-    thumbnail->resize((thumbnailWidth * thumbnailHeight * 12) / 8);
-
-    // The downscaled U and V planes will also be linear instead of interleaved,
-    // allocate space for them here
-    const size_t destUVPlaneSize = (thumbnailWidth * thumbnailHeight) / 4;
-    std::vector<unsigned char> destPlanes(destUVPlaneSize * 2);
-    unsigned char* yDestPlane = &(*thumbnail)[0];
-    unsigned char* uDestPlane = &destPlanes[0];
-    unsigned char* vDestPlane = &destPlanes[destUVPlaneSize];
-
-    // The strides for the U and V planes are half the width because the U and V
-    // components are common to 2x2 pixel blocks
-    int result = libyuv::I420Scale(ySourcePlane, sourceWidth,
-                                   uSourcePlane, sourceWidth / 2,
-                                   vSourcePlane, sourceWidth / 2,
-                                   sourceWidth, sourceHeight,
-                                   yDestPlane, thumbnailWidth,
-                                   uDestPlane, thumbnailWidth / 2,
-                                   vDestPlane, thumbnailWidth / 2,
-                                   thumbnailWidth, thumbnailHeight,
-                                   libyuv::kFilterBilinear);
-    if (result != 0) {
-        ALOGE("Unable to create thumbnail, downscaling failed with error: %d",
-              result);
-        return false;
-    }
-
-    // Now we need to interleave the downscaled U and V planes into the
-    // output buffer to make it NV21 encoded
-    const size_t uvPlanesOffset = thumbnailWidth * thumbnailHeight;
-    for (size_t i = 0; i < destUVPlaneSize; ++i) {
-        (*thumbnail)[uvPlanesOffset + i * 2 + 0] = vDestPlane[i];
-        (*thumbnail)[uvPlanesOffset + i * 2 + 1] = uDestPlane[i];
-    }
-
-    return true;
-}
-
-bool createThumbnail(const unsigned char* sourceImage,
-                     int sourceWidth, int sourceHeight,
-                     int thumbWidth, int thumbHeight, int quality,
-                     ExifData* exifData) {
-    if (thumbWidth <= 0 || thumbHeight <= 0) {
-        ALOGE("%s: Invalid thumbnail width=%d or height=%d, must be > 0",
-              __FUNCTION__, thumbWidth, thumbHeight);
-        return false;
-    }
-
-    // First downscale the source image into a thumbnail-sized raw image
-    std::vector<unsigned char> rawThumbnail;
-    if (!createRawThumbnail(sourceImage, sourceWidth, sourceHeight,
-                            thumbWidth, thumbHeight, &rawThumbnail)) {
-        // The thumbnail function will log an appropriate error if needed
-        return false;
-    }
-
-    // And then compress it into JPEG format without any EXIF data
-    NV21JpegCompressor compressor;
-    status_t result = compressor.compressRawImage(&rawThumbnail[0],
-                                                  nullptr /* EXIF */,
-                                                  quality, thumbWidth, thumbHeight);
-    if (result != NO_ERROR) {
-        ALOGE("%s: Unable to compress thumbnail", __FUNCTION__);
-        return false;
-    }
-
-    // And finally put it in the EXIF data. This transfers ownership of the
-    // malloc'd memory to the EXIF data structure. As long as the EXIF data
-    // structure is free'd using the EXIF library this memory will be free'd.
-    exifData->size = compressor.getCompressedSize();
-    exifData->data = reinterpret_cast<unsigned char*>(malloc(exifData->size));
-    if (exifData->data == nullptr) {
-        ALOGE("%s: Unable to allocate %u bytes of memory for thumbnail",
-              __FUNCTION__, exifData->size);
-        exifData->size = 0;
-        return false;
-    }
-    compressor.getCompressedImage(exifData->data);
-    return true;
-}
-
-}  // namespace android
-
diff --git a/guest/hals/camera/Thumbnail.h b/guest/hals/camera/Thumbnail.h
deleted file mode 100644
index b27636c..0000000
--- a/guest/hals/camera/Thumbnail.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-* Copyright (C) 2016 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.
- */
-
-#ifndef GOLDFISH_CAMERA_THUMBNAIL_H
-#define GOLDFISH_CAMERA_THUMBNAIL_H
-
-struct _ExifData;
-typedef struct _ExifData ExifData;
-
-namespace android {
-
-/* Create a thumbnail from NV21 source data in |sourceImage| with the given
- * dimensions. The resulting thumbnail is JPEG compressed and a pointer and size
- * is placed in |exifData| which takes ownership of the allocated memory.
- */
-bool createThumbnail(const unsigned char* sourceImage,
-                     int sourceWidth, int sourceHeight,
-                     int thumbnailWidth, int thumbnailHeight, int quality,
-                     ExifData* exifData);
-
-}  // namespace android
-
-#endif  // GOLDFISH_CAMERA_THUMBNAIL_H
-
diff --git a/guest/hals/camera/VSoCEmulatedCameraHotplugThread.cpp b/guest/hals/camera/VSoCEmulatedCameraHotplugThread.cpp
deleted file mode 100644
index 2378dc0..0000000
--- a/guest/hals/camera/VSoCEmulatedCameraHotplugThread.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_HotplugThread"
-#include <log/log.h>
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "EmulatedCameraFactory.h"
-#include "EmulatedCameraHotplugThread.h"
-
-#define SubscriberInfo EmulatedCameraHotplugThread::SubscriberInfo
-
-namespace android {
-
-EmulatedCameraHotplugThread::EmulatedCameraHotplugThread(
-    size_t /*totalCameraCount*/)
-    : Thread(/*canCallJava*/ false) {}
-
-EmulatedCameraHotplugThread::~EmulatedCameraHotplugThread() {}
-
-status_t EmulatedCameraHotplugThread::requestExitAndWait() {
-  ALOGE("%s: Not implemented. Use requestExit + join instead", __FUNCTION__);
-  return INVALID_OPERATION;
-}
-
-void EmulatedCameraHotplugThread::requestExit() {
-  ALOGV("%s: Requesting thread exit", __FUNCTION__);
-  mRunning = false;
-}
-
-status_t EmulatedCameraHotplugThread::readyToRun() { return OK; }
-
-bool EmulatedCameraHotplugThread::threadLoop() {
-  // Thread is irrelevant right now; hoplug is not supported.
-  return false;
-}
-
-String8 EmulatedCameraHotplugThread::getFilePath(int /*cameraId*/) const {
-  return String8();
-}
-
-bool EmulatedCameraHotplugThread::createFileIfNotExists(
-    int /*cameraId*/) const {
-  return true;
-}
-
-int EmulatedCameraHotplugThread::getCameraId(String8 /*filePath*/) const {
-  // Not used anywhere.
-  return NAME_NOT_FOUND;
-}
-
-int EmulatedCameraHotplugThread::getCameraId(int /*wd*/) const {
-  // Not used anywhere.
-  return NAME_NOT_FOUND;
-}
-
-SubscriberInfo* EmulatedCameraHotplugThread::getSubscriberInfo(
-    int /*cameraId*/) {
-  // Not used anywhere.
-  return NULL;
-}
-
-bool EmulatedCameraHotplugThread::addWatch(int /*cameraId*/) { return true; }
-
-bool EmulatedCameraHotplugThread::removeWatch(int /*cameraId*/) { return true; }
-
-int EmulatedCameraHotplugThread::readFile(String8 /*filePath*/) const {
-  return 1;
-}
-
-}  // namespace android
diff --git a/guest/hals/camera/fake-pipeline2/Base.h b/guest/hals/camera/fake-pipeline2/Base.h
deleted file mode 100644
index 3cd1e15..0000000
--- a/guest/hals/camera/fake-pipeline2/Base.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/**
- * This file includes various basic structures that are needed by multiple parts
- * of the fake camera 2 implementation.
- */
-
-#ifndef HW_EMULATOR_CAMERA2_BASE_H
-#define HW_EMULATOR_CAMERA2_BASE_H
-
-#include <hardware/camera2.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-/* Internal structure for passing buffers across threads */
-struct StreamBuffer {
-  // Positive numbers are output streams
-  // Negative numbers are input reprocess streams
-  // Zero is an auxillary buffer
-  int streamId;
-  uint32_t width, height;
-  uint32_t format;
-  uint32_t dataSpace;
-  uint32_t stride;
-  buffer_handle_t *buffer;
-  uint8_t *img;
-};
-typedef Vector<StreamBuffer> Buffers;
-
-struct Stream {
-  const camera2_stream_ops_t *ops;
-  uint32_t width, height;
-  int32_t format;
-  uint32_t stride;
-};
-
-struct ReprocessStream {
-  const camera2_stream_in_ops_t *ops;
-  uint32_t width, height;
-  int32_t format;
-  uint32_t stride;
-  // -1 if the reprocessing stream is independent
-  int32_t sourceStreamId;
-};
-
-}  // namespace android
-
-#endif
diff --git a/guest/hals/camera/fake-pipeline2/JpegCompressor.cpp b/guest/hals/camera/fake-pipeline2/JpegCompressor.cpp
deleted file mode 100644
index 22c5d3a..0000000
--- a/guest/hals/camera/fake-pipeline2/JpegCompressor.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera2_JpegCompressor"
-
-#include <utils/Log.h>
-
-#include "../EmulatedFakeCamera2.h"
-#include "../EmulatedFakeCamera3.h"
-#include "JpegCompressor.h"
-
-namespace android {
-
-JpegCompressor::JpegCompressor()
-    : Thread(false),
-      mIsBusy(false),
-      mSynchronous(false),
-      mBuffers(NULL),
-      mListener(NULL),
-      mFoundAux(false) {}
-
-JpegCompressor::~JpegCompressor() { Mutex::Autolock lock(mMutex); }
-
-status_t JpegCompressor::reserve() {
-  Mutex::Autolock busyLock(mBusyMutex);
-  if (mIsBusy) {
-    ALOGE("%s: Already processing a buffer!", __FUNCTION__);
-    return INVALID_OPERATION;
-  }
-  mIsBusy = true;
-  return OK;
-}
-
-status_t JpegCompressor::start(Buffers *buffers, JpegListener *listener) {
-  if (listener == NULL) {
-    ALOGE("%s: NULL listener not allowed!", __FUNCTION__);
-    return BAD_VALUE;
-  }
-  ALOGV("%s: Starting JPEG compression thread", __FUNCTION__);
-  Mutex::Autolock lock(mMutex);
-  {
-    Mutex::Autolock busyLock(mBusyMutex);
-
-    if (!mIsBusy) {
-      ALOGE("Called start without reserve() first!");
-      return INVALID_OPERATION;
-    }
-    mSynchronous = false;
-    mBuffers = buffers;
-    mListener = listener;
-  }
-
-  status_t res;
-  res = run("EmulatedFakeCamera2::JpegCompressor");
-  if (res != OK) {
-    ALOGE("%s: Unable to start up compression thread: %s (%d)", __FUNCTION__,
-          strerror(-res), res);
-    delete mBuffers;
-  }
-  return res;
-}
-
-status_t JpegCompressor::compressSynchronous(Buffers *buffers) {
-  status_t res;
-
-  Mutex::Autolock lock(mMutex);
-  {
-    Mutex::Autolock busyLock(mBusyMutex);
-
-    if (mIsBusy) {
-      ALOGE("%s: Already processing a buffer!", __FUNCTION__);
-      return INVALID_OPERATION;
-    }
-
-    mIsBusy = true;
-    mSynchronous = true;
-    mBuffers = buffers;
-  }
-
-  res = compress();
-
-  cleanUp();
-
-  return res;
-}
-
-status_t JpegCompressor::cancel() {
-  requestExitAndWait();
-  return OK;
-}
-
-status_t JpegCompressor::readyToRun() { return OK; }
-
-bool JpegCompressor::threadLoop() {
-  status_t res;
-  ALOGV("%s: Starting compression thread", __FUNCTION__);
-
-  res = compress();
-
-  mListener->onJpegDone(mJpegBuffer, res == OK);
-
-  cleanUp();
-
-  return false;
-}
-
-status_t JpegCompressor::compress() {
-  // Find source and target buffers. Assumes only one buffer matches
-  // each condition!
-  ALOGV("%s: Compressing start", __FUNCTION__);
-  for (size_t i = 0; i < mBuffers->size(); i++) {
-    const StreamBuffer &b = (*mBuffers)[i];
-    if (b.format == HAL_PIXEL_FORMAT_BLOB) {
-      mJpegBuffer = b;
-      mFoundJpeg = true;
-    } else if (b.streamId <= 0) {
-      mAuxBuffer = b;
-      mFoundAux = true;
-    }
-    if (mFoundJpeg && mFoundAux) break;
-  }
-  if (!mFoundJpeg || !mFoundAux) {
-    ALOGE("%s: Unable to find buffers for JPEG source/destination",
-          __FUNCTION__);
-    return BAD_VALUE;
-  }
-
-  // Set up error management
-
-  mJpegErrorInfo = NULL;
-  JpegError error;
-  error.parent = this;
-
-  mCInfo.err = jpeg_std_error(&error);
-  mCInfo.err->error_exit = jpegErrorHandler;
-
-  jpeg_create_compress(&mCInfo);
-  if (checkError("Error initializing compression")) return NO_INIT;
-
-  // Route compressed data straight to output stream buffer
-
-  JpegDestination jpegDestMgr;
-  jpegDestMgr.parent = this;
-  jpegDestMgr.init_destination = jpegInitDestination;
-  jpegDestMgr.empty_output_buffer = jpegEmptyOutputBuffer;
-  jpegDestMgr.term_destination = jpegTermDestination;
-
-  mCInfo.dest = &jpegDestMgr;
-
-  // Set up compression parameters
-
-  mCInfo.image_width = mAuxBuffer.width;
-  mCInfo.image_height = mAuxBuffer.height;
-  mCInfo.input_components = 3;
-  mCInfo.in_color_space = JCS_RGB;
-
-  jpeg_set_defaults(&mCInfo);
-  if (checkError("Error configuring defaults")) return NO_INIT;
-
-  // Do compression
-
-  jpeg_start_compress(&mCInfo, TRUE);
-  if (checkError("Error starting compression")) return NO_INIT;
-
-  size_t rowStride = mAuxBuffer.stride * 3;
-  const size_t kChunkSize = 32;
-  while (mCInfo.next_scanline < mCInfo.image_height) {
-    JSAMPROW chunk[kChunkSize];
-    for (size_t i = 0; i < kChunkSize; i++) {
-      chunk[i] =
-          (JSAMPROW)(mAuxBuffer.img + (i + mCInfo.next_scanline) * rowStride);
-    }
-    jpeg_write_scanlines(&mCInfo, chunk, kChunkSize);
-    if (checkError("Error while compressing")) return NO_INIT;
-    if (exitPending()) {
-      ALOGV("%s: Cancel called, exiting early", __FUNCTION__);
-      return TIMED_OUT;
-    }
-  }
-
-  jpeg_finish_compress(&mCInfo);
-  if (checkError("Error while finishing compression")) return NO_INIT;
-
-  // All done
-  ALOGV("%s: Compressing done", __FUNCTION__);
-
-  return OK;
-}
-
-bool JpegCompressor::isBusy() {
-  Mutex::Autolock busyLock(mBusyMutex);
-  return mIsBusy;
-}
-
-bool JpegCompressor::isStreamInUse(uint32_t id) {
-  Mutex::Autolock lock(mBusyMutex);
-
-  if (mBuffers && mIsBusy) {
-    for (size_t i = 0; i < mBuffers->size(); i++) {
-      if ((*mBuffers)[i].streamId == (int)id) return true;
-    }
-  }
-  return false;
-}
-
-bool JpegCompressor::waitForDone(nsecs_t timeout) {
-  Mutex::Autolock lock(mBusyMutex);
-  while (mIsBusy) {
-    status_t res = mDone.waitRelative(mBusyMutex, timeout);
-    if (res != OK) return false;
-  }
-  return true;
-}
-
-bool JpegCompressor::checkError(const char *msg) {
-  if (mJpegErrorInfo) {
-    char errBuffer[JMSG_LENGTH_MAX];
-    mJpegErrorInfo->err->format_message(mJpegErrorInfo, errBuffer);
-    ALOGE("%s: %s: %s", __FUNCTION__, msg, errBuffer);
-    mJpegErrorInfo = NULL;
-    return true;
-  }
-  return false;
-}
-
-void JpegCompressor::cleanUp() {
-  jpeg_destroy_compress(&mCInfo);
-  Mutex::Autolock lock(mBusyMutex);
-
-  if (mFoundAux) {
-    if (mAuxBuffer.streamId == 0) {
-      delete[] mAuxBuffer.img;
-    } else if (!mSynchronous) {
-      mListener->onJpegInputDone(mAuxBuffer);
-    }
-  }
-  if (!mSynchronous) {
-    delete mBuffers;
-  }
-
-  mBuffers = NULL;
-
-  mIsBusy = false;
-  mDone.signal();
-}
-
-void JpegCompressor::jpegErrorHandler(j_common_ptr cinfo) {
-  JpegError *error = static_cast<JpegError *>(cinfo->err);
-  error->parent->mJpegErrorInfo = cinfo;
-}
-
-void JpegCompressor::jpegInitDestination(j_compress_ptr cinfo) {
-  JpegDestination *dest = static_cast<JpegDestination *>(cinfo->dest);
-  ALOGV("%s: Setting destination to %p, size %zu", __FUNCTION__,
-        dest->parent->mJpegBuffer.img, kMaxJpegSize);
-  dest->next_output_byte = (JOCTET *)(dest->parent->mJpegBuffer.img);
-  dest->free_in_buffer = kMaxJpegSize;
-}
-
-boolean JpegCompressor::jpegEmptyOutputBuffer(j_compress_ptr /*cinfo*/) {
-  ALOGE("%s: JPEG destination buffer overflow!", __FUNCTION__);
-  return true;
-}
-
-void JpegCompressor::jpegTermDestination(j_compress_ptr cinfo) {
-  ALOGV("%s: Done writing JPEG data. %zu bytes left in buffer", __FUNCTION__,
-        cinfo->dest->free_in_buffer);
-}
-
-JpegCompressor::JpegListener::~JpegListener() {}
-
-}  // namespace android
diff --git a/guest/hals/camera/fake-pipeline2/JpegCompressor.h b/guest/hals/camera/fake-pipeline2/JpegCompressor.h
deleted file mode 100644
index bdbc772..0000000
--- a/guest/hals/camera/fake-pipeline2/JpegCompressor.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/**
- * This class simulates a hardware JPEG compressor.  It receives image buffers
- * in RGBA_8888 format, processes them in a worker thread, and then pushes them
- * out to their destination stream.
- */
-
-#ifndef HW_EMULATOR_CAMERA2_JPEG_H
-#define HW_EMULATOR_CAMERA2_JPEG_H
-
-#include "utils/Mutex.h"
-#include "utils/Thread.h"
-#include "utils/Timers.h"
-
-#include "Base.h"
-
-#include <stdio.h>
-
-extern "C" {
-#include <jpeglib.h>
-}
-
-namespace android {
-
-class JpegCompressor : private Thread, public virtual RefBase {
- public:
-  JpegCompressor();
-  ~JpegCompressor();
-
-  struct JpegListener {
-    // Called when JPEG compression has finished, or encountered an error
-    virtual void onJpegDone(const StreamBuffer &jpegBuffer, bool success) = 0;
-    // Called when the input buffer for JPEG is not needed any more,
-    // if the buffer came from the framework.
-    virtual void onJpegInputDone(const StreamBuffer &inputBuffer) = 0;
-    virtual ~JpegListener();
-  };
-
-  // Start compressing COMPRESSED format buffers; JpegCompressor takes
-  // ownership of the Buffers vector.
-  // Reserve() must be called first.
-  status_t start(Buffers *buffers, JpegListener *listener);
-
-  // Compress and block until buffer is complete.
-  status_t compressSynchronous(Buffers *buffers);
-
-  status_t cancel();
-
-  bool isBusy();
-  bool isStreamInUse(uint32_t id);
-
-  bool waitForDone(nsecs_t timeout);
-
-  // Reserve the compressor for a later start() call.
-  status_t reserve();
-
-  // TODO: Measure this
-  static const size_t kMaxJpegSize = 300000;
-
- private:
-  Mutex mBusyMutex;
-  bool mIsBusy;
-  Condition mDone;
-  bool mSynchronous;
-
-  Mutex mMutex;
-
-  Buffers *mBuffers;
-  JpegListener *mListener;
-
-  StreamBuffer mJpegBuffer, mAuxBuffer;
-  bool mFoundJpeg, mFoundAux;
-
-  jpeg_compress_struct mCInfo;
-
-  struct JpegError : public jpeg_error_mgr {
-    JpegCompressor *parent;
-  };
-  j_common_ptr mJpegErrorInfo;
-
-  struct JpegDestination : public jpeg_destination_mgr {
-    JpegCompressor *parent;
-  };
-
-  static void jpegErrorHandler(j_common_ptr cinfo);
-
-  static void jpegInitDestination(j_compress_ptr cinfo);
-  static boolean jpegEmptyOutputBuffer(j_compress_ptr cinfo);
-  static void jpegTermDestination(j_compress_ptr cinfo);
-
-  bool checkError(const char *msg);
-  status_t compress();
-
-  void cleanUp();
-
-  /**
-   * Inherited Thread virtual overrides
-   */
- private:
-  virtual status_t readyToRun();
-  virtual bool threadLoop();
-};
-
-}  // namespace android
-
-#endif
diff --git a/guest/hals/camera/fake-pipeline2/Scene.cpp b/guest/hals/camera/fake-pipeline2/Scene.cpp
deleted file mode 100644
index c70dc4c..0000000
--- a/guest/hals/camera/fake-pipeline2/Scene.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Scene"
-#include "Scene.h"
-#include <stdlib.h>
-#include <utils/Log.h>
-#include <cmath>
-
-// TODO: This should probably be done host-side in OpenGL for speed and better
-// quality
-
-namespace android {
-
-// Define single-letter shortcuts for scene definition, for directly indexing
-// mCurrentColors
-#define G (Scene::GRASS * Scene::NUM_CHANNELS)
-#define S (Scene::GRASS_SHADOW * Scene::NUM_CHANNELS)
-#define H (Scene::HILL * Scene::NUM_CHANNELS)
-#define W (Scene::WALL * Scene::NUM_CHANNELS)
-#define R (Scene::ROOF * Scene::NUM_CHANNELS)
-#define D (Scene::DOOR * Scene::NUM_CHANNELS)
-#define C (Scene::CHIMNEY * Scene::NUM_CHANNELS)
-#define I (Scene::WINDOW * Scene::NUM_CHANNELS)
-#define U (Scene::SUN * Scene::NUM_CHANNELS)
-#define K (Scene::SKY * Scene::NUM_CHANNELS)
-#define M (Scene::MOON * Scene::NUM_CHANNELS)
-
-const int Scene::kSceneWidth = 20;
-const int Scene::kSceneHeight = 20;
-
-const uint8_t Scene::kScene[Scene::kSceneWidth * Scene::kSceneHeight] = {
-    //      5         10        15        20
-    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
-    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
-    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
-    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
-    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,  // 5
-    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
-    K, K, K, K, K, K, K, K, H, H, H, H, H, H, H, H, H, H, H, H,
-    K, K, K, K, K, K, K, K, H, H, H, H, H, H, H, C, C, H, H, H,
-    K, K, K, K, K, K, H, H, H, H, H, H, H, H, H, C, C, H, H, H,
-    H, K, K, K, K, K, H, R, R, R, R, R, R, R, R, R, R, R, R, H,  // 10
-    H, K, K, K, K, H, H, R, R, R, R, R, R, R, R, R, R, R, R, H,
-    H, H, H, K, K, H, H, R, R, R, R, R, R, R, R, R, R, R, R, H,
-    H, H, H, K, K, H, H, H, W, W, W, W, W, W, W, W, W, W, H, H,
-    S, S, S, G, G, S, S, S, W, W, W, W, W, W, W, W, W, W, S, S,
-    S, G, G, G, G, S, S, S, W, I, I, W, D, D, W, I, I, W, S, S,  // 15
-    G, G, G, G, G, G, S, S, W, I, I, W, D, D, W, I, I, W, S, S,
-    G, G, G, G, G, G, G, G, W, W, W, W, D, D, W, W, W, W, G, G,
-    G, G, G, G, G, G, G, G, W, W, W, W, D, D, W, W, W, W, G, G,
-    G, G, G, G, G, G, G, G, S, S, S, S, S, S, S, S, S, S, G, G,
-    G, G, G, G, G, G, G, G, S, S, S, S, S, S, S, S, S, S, G, G,  // 20
-    //      5         10        15        20
-};
-
-#undef G
-#undef S
-#undef H
-#undef W
-#undef R
-#undef D
-#undef C
-#undef I
-#undef U
-#undef K
-#undef M
-
-Scene::Scene(int sensorWidthPx, int sensorHeightPx, float sensorSensitivity)
-    : mSensorWidth(sensorWidthPx),
-      mSensorHeight(sensorHeightPx),
-      mHour(12),
-      mExposureDuration(0.033f),
-      mSensorSensitivity(sensorSensitivity) {
-  // Map scene to sensor pixels
-  if (mSensorWidth > mSensorHeight) {
-    mMapDiv = (mSensorWidth / (kSceneWidth + 1)) + 1;
-  } else {
-    mMapDiv = (mSensorHeight / (kSceneHeight + 1)) + 1;
-  }
-  mOffsetX = (kSceneWidth * mMapDiv - mSensorWidth) / 2;
-  mOffsetY = (kSceneHeight * mMapDiv - mSensorHeight) / 2;
-
-  // Assume that sensor filters are sRGB primaries to start
-  mFilterR[0] = 3.2406f;
-  mFilterR[1] = -1.5372f;
-  mFilterR[2] = -0.4986f;
-  mFilterGr[0] = -0.9689f;
-  mFilterGr[1] = 1.8758f;
-  mFilterGr[2] = 0.0415f;
-  mFilterGb[0] = -0.9689f;
-  mFilterGb[1] = 1.8758f;
-  mFilterGb[2] = 0.0415f;
-  mFilterB[0] = 0.0557f;
-  mFilterB[1] = -0.2040f;
-  mFilterB[2] = 1.0570f;
-}
-
-Scene::~Scene() {}
-
-void Scene::setColorFilterXYZ(float rX, float rY, float rZ, float grX,
-                              float grY, float grZ, float gbX, float gbY,
-                              float gbZ, float bX, float bY, float bZ) {
-  mFilterR[0] = rX;
-  mFilterR[1] = rY;
-  mFilterR[2] = rZ;
-  mFilterGr[0] = grX;
-  mFilterGr[1] = grY;
-  mFilterGr[2] = grZ;
-  mFilterGb[0] = gbX;
-  mFilterGb[1] = gbY;
-  mFilterGb[2] = gbZ;
-  mFilterB[0] = bX;
-  mFilterB[1] = bY;
-  mFilterB[2] = bZ;
-}
-
-void Scene::setHour(int hour) {
-  ALOGV("Hour set to: %d", hour);
-  mHour = hour % 24;
-}
-
-int Scene::getHour() { return mHour; }
-
-void Scene::setExposureDuration(float seconds) { mExposureDuration = seconds; }
-
-void Scene::calculateScene(nsecs_t time) {
-  // Calculate time fractions for interpolation
-  int timeIdx = mHour / kTimeStep;
-  int nextTimeIdx = (timeIdx + 1) % (24 / kTimeStep);
-  const nsecs_t kOneHourInNsec = 1e9 * 60 * 60;
-  nsecs_t timeSinceIdx = (mHour - timeIdx * kTimeStep) * kOneHourInNsec + time;
-  float timeFrac = timeSinceIdx / (float)(kOneHourInNsec * kTimeStep);
-
-  // Determine overall sunlight levels
-  float sunLux =
-      kSunlight[timeIdx] * (1 - timeFrac) + kSunlight[nextTimeIdx] * timeFrac;
-  ALOGV("Sun lux: %f", sunLux);
-
-  float sunShadeLux = sunLux * (kDaylightShadeIllum / kDirectSunIllum);
-
-  // Determine sun/shade illumination chromaticity
-  float currentSunXY[2];
-  float currentShadeXY[2];
-
-  const float *prevSunXY, *nextSunXY;
-  const float *prevShadeXY, *nextShadeXY;
-  if (kSunlight[timeIdx] == kSunsetIllum ||
-      kSunlight[timeIdx] == kTwilightIllum) {
-    prevSunXY = kSunsetXY;
-    prevShadeXY = kSunsetXY;
-  } else {
-    prevSunXY = kDirectSunlightXY;
-    prevShadeXY = kDaylightXY;
-  }
-  if (kSunlight[nextTimeIdx] == kSunsetIllum ||
-      kSunlight[nextTimeIdx] == kTwilightIllum) {
-    nextSunXY = kSunsetXY;
-    nextShadeXY = kSunsetXY;
-  } else {
-    nextSunXY = kDirectSunlightXY;
-    nextShadeXY = kDaylightXY;
-  }
-  currentSunXY[0] = prevSunXY[0] * (1 - timeFrac) + nextSunXY[0] * timeFrac;
-  currentSunXY[1] = prevSunXY[1] * (1 - timeFrac) + nextSunXY[1] * timeFrac;
-
-  currentShadeXY[0] =
-      prevShadeXY[0] * (1 - timeFrac) + nextShadeXY[0] * timeFrac;
-  currentShadeXY[1] =
-      prevShadeXY[1] * (1 - timeFrac) + nextShadeXY[1] * timeFrac;
-
-  ALOGV("Sun XY: %f, %f, Shade XY: %f, %f", currentSunXY[0], currentSunXY[1],
-        currentShadeXY[0], currentShadeXY[1]);
-
-  // Converting for xyY to XYZ:
-  // X = Y / y * x
-  // Y = Y
-  // Z = Y / y * (1 - x - y);
-  float sunXYZ[3] = {
-      sunLux / currentSunXY[1] * currentSunXY[0], sunLux,
-      sunLux / currentSunXY[1] * (1 - currentSunXY[0] - currentSunXY[1])};
-  float sunShadeXYZ[3] = {sunShadeLux / currentShadeXY[1] * currentShadeXY[0],
-                          sunShadeLux,
-                          sunShadeLux / currentShadeXY[1] *
-                              (1 - currentShadeXY[0] - currentShadeXY[1])};
-  ALOGV("Sun XYZ: %f, %f, %f", sunXYZ[0], sunXYZ[1], sunXYZ[2]);
-  ALOGV("Sun shade XYZ: %f, %f, %f", sunShadeXYZ[0], sunShadeXYZ[1],
-        sunShadeXYZ[2]);
-
-  // Determine moonlight levels
-  float moonLux =
-      kMoonlight[timeIdx] * (1 - timeFrac) + kMoonlight[nextTimeIdx] * timeFrac;
-  float moonShadeLux = moonLux * (kDaylightShadeIllum / kDirectSunIllum);
-
-  float moonXYZ[3] = {
-      moonLux / kMoonlightXY[1] * kMoonlightXY[0], moonLux,
-      moonLux / kMoonlightXY[1] * (1 - kMoonlightXY[0] - kMoonlightXY[1])};
-  float moonShadeXYZ[3] = {
-      moonShadeLux / kMoonlightXY[1] * kMoonlightXY[0], moonShadeLux,
-      moonShadeLux / kMoonlightXY[1] * (1 - kMoonlightXY[0] - kMoonlightXY[1])};
-
-  // Determine starlight level
-  const float kClearNightXYZ[3] = {
-      kClearNightIllum / kMoonlightXY[1] * kMoonlightXY[0], kClearNightIllum,
-      kClearNightIllum / kMoonlightXY[1] *
-          (1 - kMoonlightXY[0] - kMoonlightXY[1])};
-
-  // Calculate direct and shaded light
-  float directIllumXYZ[3] = {
-      sunXYZ[0] + moonXYZ[0] + kClearNightXYZ[0],
-      sunXYZ[1] + moonXYZ[1] + kClearNightXYZ[1],
-      sunXYZ[2] + moonXYZ[2] + kClearNightXYZ[2],
-  };
-
-  float shadeIllumXYZ[3] = {kClearNightXYZ[0], kClearNightXYZ[1],
-                            kClearNightXYZ[2]};
-
-  shadeIllumXYZ[0] += (mHour < kSunOverhead) ? sunXYZ[0] : sunShadeXYZ[0];
-  shadeIllumXYZ[1] += (mHour < kSunOverhead) ? sunXYZ[1] : sunShadeXYZ[1];
-  shadeIllumXYZ[2] += (mHour < kSunOverhead) ? sunXYZ[2] : sunShadeXYZ[2];
-
-  // Moon up period covers 23->0 transition, shift for simplicity
-  int adjHour = (mHour + 12) % 24;
-  int adjMoonOverhead = (kMoonOverhead + 12) % 24;
-  shadeIllumXYZ[0] +=
-      (adjHour < adjMoonOverhead) ? moonXYZ[0] : moonShadeXYZ[0];
-  shadeIllumXYZ[1] +=
-      (adjHour < adjMoonOverhead) ? moonXYZ[1] : moonShadeXYZ[1];
-  shadeIllumXYZ[2] +=
-      (adjHour < adjMoonOverhead) ? moonXYZ[2] : moonShadeXYZ[2];
-
-  ALOGV("Direct XYZ: %f, %f, %f", directIllumXYZ[0], directIllumXYZ[1],
-        directIllumXYZ[2]);
-  ALOGV("Shade XYZ: %f, %f, %f", shadeIllumXYZ[0], shadeIllumXYZ[1],
-        shadeIllumXYZ[2]);
-
-  for (int i = 0; i < NUM_MATERIALS; i++) {
-    // Converting for xyY to XYZ:
-    // X = Y / y * x
-    // Y = Y
-    // Z = Y / y * (1 - x - y);
-    float matXYZ[3] = {
-        kMaterials_xyY[i][2] / kMaterials_xyY[i][1] * kMaterials_xyY[i][0],
-        kMaterials_xyY[i][2],
-        kMaterials_xyY[i][2] / kMaterials_xyY[i][1] *
-            (1 - kMaterials_xyY[i][0] - kMaterials_xyY[i][1])};
-
-    if (kMaterialsFlags[i] == 0 || kMaterialsFlags[i] & kSky) {
-      matXYZ[0] *= directIllumXYZ[0];
-      matXYZ[1] *= directIllumXYZ[1];
-      matXYZ[2] *= directIllumXYZ[2];
-    } else if (kMaterialsFlags[i] & kShadowed) {
-      matXYZ[0] *= shadeIllumXYZ[0];
-      matXYZ[1] *= shadeIllumXYZ[1];
-      matXYZ[2] *= shadeIllumXYZ[2];
-    }  // else if (kMaterialsFlags[i] * kSelfLit), do nothing
-
-    ALOGV("Mat %d XYZ: %f, %f, %f", i, matXYZ[0], matXYZ[1], matXYZ[2]);
-    float luxToElectrons =
-        mSensorSensitivity * mExposureDuration / (kAperture * kAperture);
-    mCurrentColors[i * NUM_CHANNELS + 0] =
-        (mFilterR[0] * matXYZ[0] + mFilterR[1] * matXYZ[1] +
-         mFilterR[2] * matXYZ[2]) *
-        luxToElectrons;
-    mCurrentColors[i * NUM_CHANNELS + 1] =
-        (mFilterGr[0] * matXYZ[0] + mFilterGr[1] * matXYZ[1] +
-         mFilterGr[2] * matXYZ[2]) *
-        luxToElectrons;
-    mCurrentColors[i * NUM_CHANNELS + 2] =
-        (mFilterGb[0] * matXYZ[0] + mFilterGb[1] * matXYZ[1] +
-         mFilterGb[2] * matXYZ[2]) *
-        luxToElectrons;
-    mCurrentColors[i * NUM_CHANNELS + 3] =
-        (mFilterB[0] * matXYZ[0] + mFilterB[1] * matXYZ[1] +
-         mFilterB[2] * matXYZ[2]) *
-        luxToElectrons;
-
-    ALOGV("Color %d RGGB: %d, %d, %d, %d", i,
-          mCurrentColors[i * NUM_CHANNELS + 0],
-          mCurrentColors[i * NUM_CHANNELS + 1],
-          mCurrentColors[i * NUM_CHANNELS + 2],
-          mCurrentColors[i * NUM_CHANNELS + 3]);
-  }
-  // Shake viewpoint; horizontal and vertical sinusoids at roughly
-  // human handshake frequencies
-  mHandshakeX = (kFreq1Magnitude * std::sin(kHorizShakeFreq1 * timeSinceIdx) +
-                 kFreq2Magnitude * std::sin(kHorizShakeFreq2 * timeSinceIdx)) *
-                mMapDiv * kShakeFraction;
-
-  mHandshakeY = (kFreq1Magnitude * std::sin(kVertShakeFreq1 * timeSinceIdx) +
-                 kFreq2Magnitude * std::sin(kVertShakeFreq2 * timeSinceIdx)) *
-                mMapDiv * kShakeFraction;
-
-  // Set starting pixel
-  setReadoutPixel(0, 0);
-}
-
-void Scene::setReadoutPixel(int x, int y) {
-  mCurrentX = x;
-  mCurrentY = y;
-  mSubX = (x + mOffsetX + mHandshakeX) % mMapDiv;
-  mSubY = (y + mOffsetY + mHandshakeY) % mMapDiv;
-  mSceneX = (x + mOffsetX + mHandshakeX) / mMapDiv;
-  mSceneY = (y + mOffsetY + mHandshakeY) / mMapDiv;
-  mSceneIdx = mSceneY * kSceneWidth + mSceneX;
-  mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]);
-}
-
-const uint32_t *Scene::getPixelElectrons() {
-  const uint32_t *pixel = mCurrentSceneMaterial;
-  mCurrentX++;
-  mSubX++;
-  if (mCurrentX >= mSensorWidth) {
-    mCurrentX = 0;
-    mCurrentY++;
-    if (mCurrentY >= mSensorHeight) mCurrentY = 0;
-    setReadoutPixel(mCurrentX, mCurrentY);
-  } else if (mSubX > mMapDiv) {
-    mSceneIdx++;
-    mSceneX++;
-    mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]);
-    mSubX = 0;
-  }
-  return pixel;
-}
-
-// Handshake model constants.
-// Frequencies measured in a nanosecond timebase
-const float Scene::kHorizShakeFreq1 = 2 * M_PI * 2 / 1e9;   // 2 Hz
-const float Scene::kHorizShakeFreq2 = 2 * M_PI * 13 / 1e9;  // 13 Hz
-const float Scene::kVertShakeFreq1 = 2 * M_PI * 3 / 1e9;    // 3 Hz
-const float Scene::kVertShakeFreq2 = 2 * M_PI * 11 / 1e9;   // 1 Hz
-const float Scene::kFreq1Magnitude = 5;
-const float Scene::kFreq2Magnitude = 1;
-const float Scene::kShakeFraction = 0.03;  // As a fraction of a scene tile
-
-// RGB->YUV, Jpeg standard
-const float Scene::kRgb2Yuv[12] = {
-    0.299f, 0.587f, 0.114f, 0.f,       -0.16874f, -0.33126f,
-    0.5f,   -128.f, 0.5f,   -0.41869f, -0.08131f, -128.f,
-};
-
-// Aperture of imaging lens
-const float Scene::kAperture = 2.8;
-
-// Sun illumination levels through the day
-const float Scene::kSunlight[24 / kTimeStep] = {0,  // 00:00
-                                                0,
-                                                0,
-                                                kTwilightIllum,  // 06:00
-                                                kDirectSunIllum,
-                                                kDirectSunIllum,
-                                                kDirectSunIllum,  // 12:00
-                                                kDirectSunIllum,
-                                                kDirectSunIllum,
-                                                kSunsetIllum,  // 18:00
-                                                kTwilightIllum,
-                                                0};
-
-// Moon illumination levels through the day
-const float Scene::kMoonlight[24 / kTimeStep] = {kFullMoonIllum,  // 00:00
-                                                 kFullMoonIllum,
-                                                 0,
-                                                 0,  // 06:00
-                                                 0,
-                                                 0,
-                                                 0,  // 12:00
-                                                 0,
-                                                 0,
-                                                 0,  // 18:00
-                                                 0,
-                                                 kFullMoonIllum};
-
-const int Scene::kSunOverhead = 12;
-const int Scene::kMoonOverhead = 0;
-
-// Used for sun illumination levels
-const float Scene::kDirectSunIllum = 100000;
-const float Scene::kSunsetIllum = 400;
-const float Scene::kTwilightIllum = 4;
-// Used for moon illumination levels
-const float Scene::kFullMoonIllum = 1;
-// Other illumination levels
-const float Scene::kDaylightShadeIllum = 20000;
-const float Scene::kClearNightIllum = 2e-3;
-const float Scene::kStarIllum = 2e-6;
-const float Scene::kLivingRoomIllum = 50;
-
-const float Scene::kIncandescentXY[2] = {0.44757f, 0.40745f};
-const float Scene::kDirectSunlightXY[2] = {0.34842f, 0.35161f};
-const float Scene::kDaylightXY[2] = {0.31271f, 0.32902f};
-const float Scene::kNoonSkyXY[2] = {0.346f, 0.359f};
-const float Scene::kMoonlightXY[2] = {0.34842f, 0.35161f};
-const float Scene::kSunsetXY[2] = {0.527f, 0.413f};
-
-const uint8_t Scene::kSelfLit = 0x01;
-const uint8_t Scene::kShadowed = 0x02;
-const uint8_t Scene::kSky = 0x04;
-
-// For non-self-lit materials, the Y component is normalized with 1=full
-// reflectance; for self-lit materials, it's the constant illuminance in lux.
-const float Scene::kMaterials_xyY[Scene::NUM_MATERIALS][3] = {
-    {0.3688f, 0.4501f, .1329f},                                  // GRASS
-    {0.3688f, 0.4501f, .1329f},                                  // GRASS_SHADOW
-    {0.3986f, 0.5002f, .4440f},                                  // HILL
-    {0.3262f, 0.5040f, .2297f},                                  // WALL
-    {0.4336f, 0.3787f, .1029f},                                  // ROOF
-    {0.3316f, 0.2544f, .0639f},                                  // DOOR
-    {0.3425f, 0.3577f, .0887f},                                  // CHIMNEY
-    {kIncandescentXY[0], kIncandescentXY[1], kLivingRoomIllum},  // WINDOW
-    {kDirectSunlightXY[0], kDirectSunlightXY[1], kDirectSunIllum},  // SUN
-    {kNoonSkyXY[0], kNoonSkyXY[1],
-     kDaylightShadeIllum / kDirectSunIllum},            // SKY
-    {kMoonlightXY[0], kMoonlightXY[1], kFullMoonIllum}  // MOON
-};
-
-const uint8_t Scene::kMaterialsFlags[Scene::NUM_MATERIALS] = {
-    0,         kShadowed, kShadowed, kShadowed, kShadowed, kShadowed,
-    kShadowed, kSelfLit,  kSelfLit,  kSky,      kSelfLit,
-};
-
-}  // namespace android
diff --git a/guest/hals/camera/fake-pipeline2/Scene.h b/guest/hals/camera/fake-pipeline2/Scene.h
deleted file mode 100644
index 5e86861..0000000
--- a/guest/hals/camera/fake-pipeline2/Scene.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/**
- * The Scene class implements a simple physical simulation of a scene, using the
- * CIE 1931 colorspace to represent light in physical units (lux).
- *
- * It's fairly approximate, but does provide a scene with realistic widely
- * variable illumination levels and colors over time.
- *
- */
-
-#ifndef HW_EMULATOR_CAMERA2_SCENE_H
-#define HW_EMULATOR_CAMERA2_SCENE_H
-
-#include "utils/Timers.h"
-
-namespace android {
-
-class Scene {
- public:
-  Scene(int sensorWidthPx, int sensorHeightPx, float sensorSensitivity);
-  ~Scene();
-
-  // Set the filter coefficients for the red, green, and blue filters on the
-  // sensor. Used as an optimization to pre-calculate various illuminance
-  // values. Two different green filters can be provided, to account for
-  // possible cross-talk on a Bayer sensor. Must be called before
-  // calculateScene.
-  void setColorFilterXYZ(float rX, float rY, float rZ, float grX, float grY,
-                         float grZ, float gbX, float gbY, float gbZ, float bX,
-                         float bY, float bZ);
-
-  // Set time of day (24-hour clock). This controls the general light levels
-  // in the scene. Must be called before calculateScene
-  void setHour(int hour);
-  // Get current hour
-  int getHour();
-
-  // Set the duration of exposure for determining luminous exposure.
-  // Must be called before calculateScene
-  void setExposureDuration(float seconds);
-
-  // Calculate scene information for current hour and the time offset since
-  // the hour. Must be called at least once before calling getLuminousExposure.
-  // Resets pixel readout location to 0,0
-  void calculateScene(nsecs_t time);
-
-  // Set sensor pixel readout location.
-  void setReadoutPixel(int x, int y);
-
-  // Get sensor response in physical units (electrons) for light hitting the
-  // current readout pixel, after passing through color filters. The readout
-  // pixel will be auto-incremented. The returned array can be indexed with
-  // ColorChannels.
-  const uint32_t* getPixelElectrons();
-
-  enum ColorChannels { R = 0, Gr, Gb, B, Y, Cb, Cr, NUM_CHANNELS };
-
- private:
-  // Sensor color filtering coefficients in XYZ
-  float mFilterR[3];
-  float mFilterGr[3];
-  float mFilterGb[3];
-  float mFilterB[3];
-
-  int mOffsetX, mOffsetY;
-  int mMapDiv;
-
-  int mHandshakeX, mHandshakeY;
-
-  int mSensorWidth;
-  int mSensorHeight;
-  int mCurrentX;
-  int mCurrentY;
-  int mSubX;
-  int mSubY;
-  int mSceneX;
-  int mSceneY;
-  int mSceneIdx;
-  uint32_t* mCurrentSceneMaterial;
-
-  int mHour;
-  float mExposureDuration;
-  float mSensorSensitivity;
-
-  enum Materials {
-    GRASS = 0,
-    GRASS_SHADOW,
-    HILL,
-    WALL,
-    ROOF,
-    DOOR,
-    CHIMNEY,
-    WINDOW,
-    SUN,
-    SKY,
-    MOON,
-    NUM_MATERIALS
-  };
-
-  uint32_t mCurrentColors[NUM_MATERIALS * NUM_CHANNELS];
-
-  /**
-   * Constants for scene definition. These are various degrees of approximate.
-   */
-
-  // Fake handshake parameters. Two shake frequencies per axis, plus magnitude
-  // as a fraction of a scene tile, and relative magnitudes for the frequencies
-  static const float kHorizShakeFreq1;
-  static const float kHorizShakeFreq2;
-  static const float kVertShakeFreq1;
-  static const float kVertShakeFreq2;
-  static const float kFreq1Magnitude;
-  static const float kFreq2Magnitude;
-
-  static const float kShakeFraction;
-
-  // RGB->YUV conversion
-  static const float kRgb2Yuv[12];
-
-  // Aperture of imaging lens
-  static const float kAperture;
-
-  // Sun, moon illuminance levels in 2-hour increments. These don't match any
-  // real day anywhere.
-  static const uint32_t kTimeStep = 2;
-  static const float kSunlight[];
-  static const float kMoonlight[];
-  static const int kSunOverhead;
-  static const int kMoonOverhead;
-
-  // Illumination levels for various conditions, in lux
-  static const float kDirectSunIllum;
-  static const float kDaylightShadeIllum;
-  static const float kSunsetIllum;
-  static const float kTwilightIllum;
-  static const float kFullMoonIllum;
-  static const float kClearNightIllum;
-  static const float kStarIllum;
-  static const float kLivingRoomIllum;
-
-  // Chromaticity of various illumination sources
-  static const float kIncandescentXY[2];
-  static const float kDirectSunlightXY[2];
-  static const float kDaylightXY[2];
-  static const float kNoonSkyXY[2];
-  static const float kMoonlightXY[2];
-  static const float kSunsetXY[2];
-
-  static const uint8_t kSelfLit;
-  static const uint8_t kShadowed;
-  static const uint8_t kSky;
-
-  static const float kMaterials_xyY[NUM_MATERIALS][3];
-  static const uint8_t kMaterialsFlags[NUM_MATERIALS];
-
-  static const int kSceneWidth;
-  static const int kSceneHeight;
-  static const uint8_t kScene[];
-};
-
-}  // namespace android
-
-#endif  // HW_EMULATOR_CAMERA2_SCENE_H
diff --git a/guest/hals/camera/fake-pipeline2/Sensor.cpp b/guest/hals/camera/fake-pipeline2/Sensor.cpp
deleted file mode 100644
index f39bbbd..0000000
--- a/guest/hals/camera/fake-pipeline2/Sensor.cpp
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0
-#define LOG_TAG "EmulatedCamera2_Sensor"
-
-#ifdef LOG_NNDEBUG
-#define ALOGVV(...) ALOGV(__VA_ARGS__)
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-#include <utils/Log.h>
-
-#include <cmath>
-#include <cstdlib>
-#include "../EmulatedFakeCamera2.h"
-#include "Sensor.h"
-#include "system/camera_metadata.h"
-
-namespace android {
-
-// const nsecs_t Sensor::kExposureTimeRange[2] =
-//    {1000L, 30000000000L} ; // 1 us - 30 sec
-// const nsecs_t Sensor::kFrameDurationRange[2] =
-//    {33331760L, 30000000000L}; // ~1/30 s - 30 sec
-const nsecs_t Sensor::kExposureTimeRange[2] = {1000L,
-                                               300000000L};  // 1 us - 0.3 sec
-const nsecs_t Sensor::kFrameDurationRange[2] = {
-    33331760L, 300000000L};  // ~1/30 s - 0.3 sec
-
-const nsecs_t Sensor::kMinVerticalBlank = 10000L;
-
-const uint8_t Sensor::kColorFilterArrangement =
-    ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB;
-
-// Output image data characteristics
-const uint32_t Sensor::kMaxRawValue = 4000;
-const uint32_t Sensor::kBlackLevel = 1000;
-
-// Sensor sensitivity
-const float Sensor::kSaturationVoltage = 0.520f;
-const uint32_t Sensor::kSaturationElectrons = 2000;
-const float Sensor::kVoltsPerLuxSecond = 0.100f;
-
-const float Sensor::kElectronsPerLuxSecond = Sensor::kSaturationElectrons /
-                                             Sensor::kSaturationVoltage *
-                                             Sensor::kVoltsPerLuxSecond;
-
-const float Sensor::kBaseGainFactor =
-    (float)Sensor::kMaxRawValue / Sensor::kSaturationElectrons;
-
-const float Sensor::kReadNoiseStddevBeforeGain = 1.177;  // in electrons
-const float Sensor::kReadNoiseStddevAfterGain = 2.100;   // in digital counts
-const float Sensor::kReadNoiseVarBeforeGain =
-    Sensor::kReadNoiseStddevBeforeGain * Sensor::kReadNoiseStddevBeforeGain;
-const float Sensor::kReadNoiseVarAfterGain =
-    Sensor::kReadNoiseStddevAfterGain * Sensor::kReadNoiseStddevAfterGain;
-
-const int32_t Sensor::kSensitivityRange[2] = {100, 1600};
-const uint32_t Sensor::kDefaultSensitivity = 100;
-
-/** A few utility functions for math, normal distributions */
-
-// Take advantage of IEEE floating-point format to calculate an approximate
-// square root. Accurate to within +-3.6%
-float sqrtf_approx(float r) {
-  // Modifier is based on IEEE floating-point representation; the
-  // manipulations boil down to finding approximate log2, dividing by two, and
-  // then inverting the log2. A bias is added to make the relative error
-  // symmetric about the real answer.
-  const int32_t modifier = 0x1FBB4000;
-
-  int32_t r_i = *(int32_t *)(&r);
-  r_i = (r_i >> 1) + modifier;
-
-  return *(float *)(&r_i);
-}
-
-Sensor::Sensor(uint32_t width, uint32_t height)
-    : Thread(false),
-      mResolution{width, height},
-      mActiveArray{0, 0, width, height},
-      mRowReadoutTime(kFrameDurationRange[0] / height),
-      mGotVSync(false),
-      mExposureTime(kFrameDurationRange[0] - kMinVerticalBlank),
-      mFrameDuration(kFrameDurationRange[0]),
-      mGainFactor(kDefaultSensitivity),
-      mNextBuffers(NULL),
-      mFrameNumber(0),
-      mCapturedBuffers(NULL),
-      mListener(NULL),
-      mScene(width, height, kElectronsPerLuxSecond) {
-  ALOGV("Sensor created with pixel array %d x %d", width, height);
-}
-
-Sensor::~Sensor() { shutDown(); }
-
-status_t Sensor::startUp() {
-  ALOGV("%s: E", __FUNCTION__);
-
-  int res;
-  mCapturedBuffers = NULL;
-  res = run("EmulatedFakeCamera2::Sensor", ANDROID_PRIORITY_URGENT_DISPLAY);
-
-  if (res != OK) {
-    ALOGE("Unable to start up sensor capture thread: %d", res);
-  }
-  return res;
-}
-
-status_t Sensor::shutDown() {
-  ALOGV("%s: E", __FUNCTION__);
-
-  int res;
-  res = requestExitAndWait();
-  if (res != OK) {
-    ALOGE("Unable to shut down sensor capture thread: %d", res);
-  }
-  return res;
-}
-
-Scene &Sensor::getScene() { return mScene; }
-
-void Sensor::setExposureTime(uint64_t ns) {
-  Mutex::Autolock lock(mControlMutex);
-  ALOGVV("Exposure set to %f", ns / 1000000.f);
-  mExposureTime = ns;
-}
-
-void Sensor::setFrameDuration(uint64_t ns) {
-  Mutex::Autolock lock(mControlMutex);
-  ALOGVV("Frame duration set to %f", ns / 1000000.f);
-  mFrameDuration = ns;
-}
-
-void Sensor::setSensitivity(uint32_t gain) {
-  Mutex::Autolock lock(mControlMutex);
-  ALOGVV("Gain set to %d", gain);
-  mGainFactor = gain;
-}
-
-void Sensor::setDestinationBuffers(Buffers *buffers) {
-  Mutex::Autolock lock(mControlMutex);
-  mNextBuffers = buffers;
-}
-
-void Sensor::setFrameNumber(uint32_t frameNumber) {
-  Mutex::Autolock lock(mControlMutex);
-  mFrameNumber = frameNumber;
-}
-
-bool Sensor::waitForVSync(nsecs_t reltime) {
-  int res;
-  Mutex::Autolock lock(mControlMutex);
-
-  mGotVSync = false;
-  res = mVSync.waitRelative(mControlMutex, reltime);
-  if (res != OK && res != TIMED_OUT) {
-    ALOGE("%s: Error waiting for VSync signal: %d", __FUNCTION__, res);
-    return false;
-  }
-  return mGotVSync;
-}
-
-bool Sensor::waitForNewFrame(nsecs_t reltime, nsecs_t *captureTime) {
-  Mutex::Autolock lock(mReadoutMutex);
-
-  if (mCapturedBuffers == NULL) {
-    int res;
-    res = mReadoutAvailable.waitRelative(mReadoutMutex, reltime);
-    if (res == TIMED_OUT) {
-      return false;
-    } else if (res != OK || mCapturedBuffers == NULL) {
-      ALOGE("Error waiting for sensor readout signal: %d", res);
-      return false;
-    }
-  }
-  mReadoutComplete.signal();
-
-  *captureTime = mCaptureTime;
-  mCapturedBuffers = NULL;
-  return true;
-}
-
-Sensor::SensorListener::~SensorListener() {}
-
-void Sensor::setSensorListener(SensorListener *listener) {
-  Mutex::Autolock lock(mControlMutex);
-  mListener = listener;
-}
-
-status_t Sensor::readyToRun() {
-  ALOGV("Starting up sensor thread");
-  mStartupTime = systemTime();
-  mNextCaptureTime = 0;
-  mNextCapturedBuffers = NULL;
-  return OK;
-}
-
-bool Sensor::threadLoop() {
-  /**
-   * Sensor capture operation main loop.
-   *
-   * Stages are out-of-order relative to a single frame's processing, but
-   * in-order in time.
-   */
-
-  /**
-   * Stage 1: Read in latest control parameters
-   */
-  uint64_t exposureDuration;
-  uint64_t frameDuration;
-  uint32_t gain;
-  Buffers *nextBuffers;
-  uint32_t frameNumber;
-  SensorListener *listener = NULL;
-  {
-    Mutex::Autolock lock(mControlMutex);
-    exposureDuration = mExposureTime;
-    frameDuration = mFrameDuration;
-    gain = mGainFactor;
-    nextBuffers = mNextBuffers;
-    frameNumber = mFrameNumber;
-    listener = mListener;
-    // Don't reuse a buffer set
-    mNextBuffers = NULL;
-
-    // Signal VSync for start of readout
-    ALOGVV("Sensor VSync");
-    mGotVSync = true;
-    mVSync.signal();
-  }
-
-  /**
-   * Stage 3: Read out latest captured image
-   */
-
-  Buffers *capturedBuffers = NULL;
-  nsecs_t captureTime = 0;
-
-  nsecs_t startRealTime = systemTime();
-  // Stagefright cares about system time for timestamps, so base simulated
-  // time on that.
-  nsecs_t simulatedTime = startRealTime;
-  nsecs_t frameEndRealTime = startRealTime + frameDuration;
-
-  if (mNextCapturedBuffers != NULL) {
-    ALOGVV("Sensor starting readout");
-    // Pretend we're doing readout now; will signal once enough time has elapsed
-    capturedBuffers = mNextCapturedBuffers;
-    captureTime = mNextCaptureTime;
-  }
-  simulatedTime += mRowReadoutTime + kMinVerticalBlank;
-
-  // TODO: Move this signal to another thread to simulate readout
-  // time properly
-  if (capturedBuffers != NULL) {
-    ALOGVV("Sensor readout complete");
-    Mutex::Autolock lock(mReadoutMutex);
-    if (mCapturedBuffers != NULL) {
-      ALOGV("Waiting for readout thread to catch up!");
-      mReadoutComplete.wait(mReadoutMutex);
-    }
-
-    mCapturedBuffers = capturedBuffers;
-    mCaptureTime = captureTime;
-    mReadoutAvailable.signal();
-    capturedBuffers = NULL;
-  }
-
-  /**
-   * Stage 2: Capture new image
-   */
-  mNextCaptureTime = simulatedTime;
-  mNextCapturedBuffers = nextBuffers;
-
-  if (mNextCapturedBuffers != NULL) {
-    if (listener != NULL) {
-      listener->onSensorEvent(frameNumber, SensorListener::EXPOSURE_START,
-                              mNextCaptureTime);
-    }
-    ALOGVV("Starting next capture: Exposure: %f ms, gain: %d",
-           (float)exposureDuration / 1e6, gain);
-    mScene.setExposureDuration((float)exposureDuration / 1e9);
-    mScene.calculateScene(mNextCaptureTime);
-
-    // Might be adding more buffers, so size isn't constant
-    for (size_t i = 0; i < mNextCapturedBuffers->size(); i++) {
-      const StreamBuffer &b = (*mNextCapturedBuffers)[i];
-      ALOGVV(
-          "Sensor capturing buffer %d: stream %d,"
-          " %d x %d, format %x, stride %d, buf %p, img %p",
-          i, b.streamId, b.width, b.height, b.format, b.stride, b.buffer,
-          b.img);
-      switch (b.format) {
-        case HAL_PIXEL_FORMAT_RAW16:
-          captureRaw(b.img, gain, b.stride);
-          break;
-        case HAL_PIXEL_FORMAT_RGB_888:
-          captureRGB(b.img, gain, b.stride);
-          break;
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-          captureRGBA(b.img, gain, b.stride);
-          break;
-        case HAL_PIXEL_FORMAT_BLOB:
-#if defined HAL_DATASPACE_DEPTH
-          if (b.dataSpace != HAL_DATASPACE_DEPTH) {
-#endif
-            // Add auxillary buffer of the right size
-            // Assumes only one BLOB (JPEG) buffer in
-            // mNextCapturedBuffers
-            StreamBuffer bAux;
-            bAux.streamId = 0;
-            bAux.width = b.width;
-            bAux.height = b.height;
-            bAux.format = HAL_PIXEL_FORMAT_RGB_888;
-            bAux.stride = b.width;
-            bAux.buffer = NULL;
-            // TODO: Reuse these
-            bAux.img = new uint8_t[b.width * b.height * 3];
-            mNextCapturedBuffers->push_back(bAux);
-#if defined HAL_DATASPACE_DEPTH
-          } else {
-            captureDepthCloud(b.img);
-          }
-#endif
-          break;
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_420_888:
-          captureNV21(b.img, gain, b.stride);
-          break;
-        case HAL_PIXEL_FORMAT_YV12:
-          // TODO:
-          ALOGE("%s: Format %x is TODO", __FUNCTION__, b.format);
-          break;
-        case HAL_PIXEL_FORMAT_Y16:
-          captureDepth(b.img, gain, b.stride);
-          break;
-        default:
-          ALOGE("%s: Unknown format %x, no output", __FUNCTION__, b.format);
-          break;
-      }
-    }
-  }
-
-  ALOGVV("Sensor vertical blanking interval");
-  nsecs_t workDoneRealTime = systemTime();
-  const nsecs_t timeAccuracy = 2e6;  // 2 ms of imprecision is ok
-  if (workDoneRealTime < frameEndRealTime - timeAccuracy) {
-    timespec t;
-    t.tv_sec = (frameEndRealTime - workDoneRealTime) / 1000000000L;
-    t.tv_nsec = (frameEndRealTime - workDoneRealTime) % 1000000000L;
-
-    int ret;
-    do {
-      ret = nanosleep(&t, &t);
-    } while (ret != 0);
-  }
-  nsecs_t endRealTime __unused = systemTime();
-  ALOGVV("Frame cycle took %d ms, target %d ms",
-         (int)((endRealTime - startRealTime) / 1000000),
-         (int)(frameDuration / 1000000));
-  return true;
-};
-
-void Sensor::captureRaw(uint8_t *img, uint32_t gain, uint32_t stride) {
-  float totalGain = gain / 100.0 * kBaseGainFactor;
-  float noiseVarGain = totalGain * totalGain;
-  float readNoiseVar =
-      kReadNoiseVarBeforeGain * noiseVarGain + kReadNoiseVarAfterGain;
-
-  int bayerSelect[4] = {Scene::R, Scene::Gr, Scene::Gb, Scene::B};  // RGGB
-  mScene.setReadoutPixel(0, 0);
-  for (unsigned int y = 0; y < mResolution[1]; y++) {
-    int *bayerRow = bayerSelect + (y & 0x1) * 2;
-    uint16_t *px = (uint16_t *)img + y * stride;
-    for (unsigned int x = 0; x < mResolution[0]; x++) {
-      uint32_t electronCount;
-      electronCount = mScene.getPixelElectrons()[bayerRow[x & 0x1]];
-
-      // TODO: Better pixel saturation curve?
-      electronCount = (electronCount < kSaturationElectrons)
-                          ? electronCount
-                          : kSaturationElectrons;
-
-      // TODO: Better A/D saturation curve?
-      uint16_t rawCount = electronCount * totalGain;
-      rawCount = (rawCount < kMaxRawValue) ? rawCount : kMaxRawValue;
-
-      // Calculate noise value
-      // TODO: Use more-correct Gaussian instead of uniform noise
-      float photonNoiseVar = electronCount * noiseVarGain;
-      float noiseStddev = sqrtf_approx(readNoiseVar + photonNoiseVar);
-      // Scaled to roughly match gaussian/uniform noise stddev
-      float noiseSample = std::rand() * (2.5 / (1.0 + RAND_MAX)) - 1.25;
-
-      rawCount += kBlackLevel;
-      rawCount += noiseStddev * noiseSample;
-
-      *px++ = rawCount;
-    }
-    // TODO: Handle this better
-    // simulatedTime += mRowReadoutTime;
-  }
-  ALOGVV("Raw sensor image captured");
-}
-
-void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) {
-  float totalGain = gain / 100.0 * kBaseGainFactor;
-  // In fixed-point math, calculate total scaling from electrons to 8bpp
-  int scale64x = 64 * totalGain * 255 / kMaxRawValue;
-  uint32_t inc = ceil((float)mResolution[0] / stride);
-
-  for (unsigned int y = 0, outY = 0; y < mResolution[1]; y += inc, outY++) {
-    uint8_t *px = img + outY * stride * 4;
-    mScene.setReadoutPixel(0, y);
-    for (unsigned int x = 0; x < mResolution[0]; x += inc) {
-      uint32_t rCount, gCount, bCount;
-      // TODO: Perfect demosaicing is a cheat
-      const uint32_t *pixel = mScene.getPixelElectrons();
-      rCount = pixel[Scene::R] * scale64x;
-      gCount = pixel[Scene::Gr] * scale64x;
-      bCount = pixel[Scene::B] * scale64x;
-
-      *px++ = rCount < 255 * 64 ? rCount / 64 : 255;
-      *px++ = gCount < 255 * 64 ? gCount / 64 : 255;
-      *px++ = bCount < 255 * 64 ? bCount / 64 : 255;
-      *px++ = 255;
-      for (unsigned int j = 1; j < inc; j++) mScene.getPixelElectrons();
-    }
-    // TODO: Handle this better
-    // simulatedTime += mRowReadoutTime;
-  }
-  ALOGVV("RGBA sensor image captured");
-}
-
-void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) {
-  float totalGain = gain / 100.0 * kBaseGainFactor;
-  // In fixed-point math, calculate total scaling from electrons to 8bpp
-  int scale64x = 64 * totalGain * 255 / kMaxRawValue;
-  uint32_t inc = ceil((float)mResolution[0] / stride);
-
-  for (unsigned int y = 0, outY = 0; y < mResolution[1]; y += inc, outY++) {
-    mScene.setReadoutPixel(0, y);
-    uint8_t *px = img + outY * stride * 3;
-    for (unsigned int x = 0; x < mResolution[0]; x += inc) {
-      uint32_t rCount, gCount, bCount;
-      // TODO: Perfect demosaicing is a cheat
-      const uint32_t *pixel = mScene.getPixelElectrons();
-      rCount = pixel[Scene::R] * scale64x;
-      gCount = pixel[Scene::Gr] * scale64x;
-      bCount = pixel[Scene::B] * scale64x;
-
-      *px++ = rCount < 255 * 64 ? rCount / 64 : 255;
-      *px++ = gCount < 255 * 64 ? gCount / 64 : 255;
-      *px++ = bCount < 255 * 64 ? bCount / 64 : 255;
-      for (unsigned int j = 1; j < inc; j++) mScene.getPixelElectrons();
-    }
-    // TODO: Handle this better
-    // simulatedTime += mRowReadoutTime;
-  }
-  ALOGVV("RGB sensor image captured");
-}
-
-void Sensor::captureNV21(uint8_t *img, uint32_t gain, uint32_t stride) {
-  float totalGain = gain / 100.0 * kBaseGainFactor;
-  // Using fixed-point math with 6 bits of fractional precision.
-  // In fixed-point math, calculate total scaling from electrons to 8bpp
-  const int scale64x = 64 * totalGain * 255 / kMaxRawValue;
-  // In fixed-point math, saturation point of sensor after gain
-  const int saturationPoint = 64 * 255;
-  // Fixed-point coefficients for RGB-YUV transform
-  // Based on JFIF RGB->YUV transform.
-  // Cb/Cr offset scaled by 64x twice since they're applied post-multiply
-  const int rgbToY[] = {19, 37, 7};
-  const int rgbToCb[] = {-10, -21, 32, 524288};
-  const int rgbToCr[] = {32, -26, -5, 524288};
-  // Scale back to 8bpp non-fixed-point
-  const int scaleOut = 64;
-  const int scaleOutSq = scaleOut * scaleOut;  // after multiplies
-
-  // inc = how many pixels to skip while reading every next pixel
-  // horizontally.
-  uint32_t inc = ceil((float)mResolution[0] / stride);
-  // outH = projected vertical resolution based on stride.
-  uint32_t outH = mResolution[1] / inc;
-  for (unsigned int y = 0, outY = 0; y < mResolution[1]; y += inc, outY++) {
-    uint8_t *pxY = img + outY * stride;
-    uint8_t *pxVU = img + (outH + outY / 2) * stride;
-    mScene.setReadoutPixel(0, y);
-    for (unsigned int outX = 0; outX < stride; outX++) {
-      int32_t rCount, gCount, bCount;
-      // TODO: Perfect demosaicing is a cheat
-      const uint32_t *pixel = mScene.getPixelElectrons();
-      rCount = pixel[Scene::R] * scale64x;
-      rCount = rCount < saturationPoint ? rCount : saturationPoint;
-      gCount = pixel[Scene::Gr] * scale64x;
-      gCount = gCount < saturationPoint ? gCount : saturationPoint;
-      bCount = pixel[Scene::B] * scale64x;
-      bCount = bCount < saturationPoint ? bCount : saturationPoint;
-
-      *pxY++ = (rgbToY[0] * rCount + rgbToY[1] * gCount + rgbToY[2] * bCount) /
-               scaleOutSq;
-      if (outY % 2 == 0 && outX % 2 == 0) {
-        *pxVU++ = (rgbToCb[0] * rCount + rgbToCb[1] * gCount +
-                   rgbToCb[2] * bCount + rgbToCb[3]) /
-                  scaleOutSq;
-        *pxVU++ = (rgbToCr[0] * rCount + rgbToCr[1] * gCount +
-                   rgbToCr[2] * bCount + rgbToCr[3]) /
-                  scaleOutSq;
-      }
-
-      // Skip unprocessed pixels from sensor.
-      for (unsigned int j = 1; j < inc; j++) mScene.getPixelElectrons();
-    }
-  }
-  ALOGVV("NV21 sensor image captured");
-}
-
-void Sensor::captureDepth(uint8_t *img, uint32_t gain, uint32_t stride) {
-  float totalGain = gain / 100.0 * kBaseGainFactor;
-  // In fixed-point math, calculate scaling factor to 13bpp millimeters
-  int scale64x = 64 * totalGain * 8191 / kMaxRawValue;
-  uint32_t inc = ceil((float)mResolution[0] / stride);
-
-  for (unsigned int y = 0, outY = 0; y < mResolution[1]; y += inc, outY++) {
-    mScene.setReadoutPixel(0, y);
-    uint16_t *px = ((uint16_t *)img) + outY * stride;
-    for (unsigned int x = 0; x < mResolution[0]; x += inc) {
-      uint32_t depthCount;
-      // TODO: Make up real depth scene instead of using green channel
-      // as depth
-      const uint32_t *pixel = mScene.getPixelElectrons();
-      depthCount = pixel[Scene::Gr] * scale64x;
-
-      *px++ = depthCount < 8191 * 64 ? depthCount / 64 : 0;
-      for (unsigned int j = 1; j < inc; j++) mScene.getPixelElectrons();
-    }
-    // TODO: Handle this better
-    // simulatedTime += mRowReadoutTime;
-  }
-  ALOGVV("Depth sensor image captured");
-}
-
-void Sensor::captureDepthCloud(uint8_t * /*img*/) {
-#if defined HAL_DATASPACE_DEPTH
-  android_depth_points *cloud = reinterpret_cast<android_depth_points *>(img);
-
-  cloud->num_points = 16;
-
-  // TODO: Create point cloud values that match RGB scene
-  const int FLOATS_PER_POINT = 4;
-  const float JITTER_STDDEV = 0.1f;
-  for (size_t y = 0, i = 0; y < 4; y++) {
-    for (size_t x = 0; x < 4; x++, i++) {
-      float randSampleX = std::rand() * (2.5f / (1.0f + RAND_MAX)) - 1.25f;
-      randSampleX *= JITTER_STDDEV;
-
-      float randSampleY = std::rand() * (2.5f / (1.0f + RAND_MAX)) - 1.25f;
-      randSampleY *= JITTER_STDDEV;
-
-      float randSampleZ = std::rand() * (2.5f / (1.0f + RAND_MAX)) - 1.25f;
-      randSampleZ *= JITTER_STDDEV;
-
-      cloud->xyzc_points[i * FLOATS_PER_POINT + 0] = x - 1.5f + randSampleX;
-      cloud->xyzc_points[i * FLOATS_PER_POINT + 1] = y - 1.5f + randSampleY;
-      cloud->xyzc_points[i * FLOATS_PER_POINT + 2] = 3.f + randSampleZ;
-      cloud->xyzc_points[i * FLOATS_PER_POINT + 3] = 0.8f;
-    }
-  }
-
-  ALOGVV("Depth point cloud captured");
-#endif
-}
-
-}  // namespace android
diff --git a/guest/hals/camera/fake-pipeline2/Sensor.h b/guest/hals/camera/fake-pipeline2/Sensor.h
deleted file mode 100644
index 326af29..0000000
--- a/guest/hals/camera/fake-pipeline2/Sensor.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/**
- * This class is a simple simulation of a typical CMOS cellphone imager chip,
- * which outputs 12-bit Bayer-mosaic raw images.
- *
- * Unlike most real image sensors, this one's native color space is linear sRGB.
- *
- * The sensor is abstracted as operating as a pipeline 3 stages deep;
- * conceptually, each frame to be captured goes through these three stages. The
- * processing step for the sensor is marked off by vertical sync signals, which
- * indicate the start of readout of the oldest frame. The interval between
- * processing steps depends on the frame duration of the frame currently being
- * captured. The stages are 1) configure, 2) capture, and 3) readout. During
- * configuration, the sensor's registers for settings such as exposure time,
- * frame duration, and gain are set for the next frame to be captured. In stage
- * 2, the image data for the frame is actually captured by the sensor. Finally,
- * in stage 3, the just-captured data is read out and sent to the rest of the
- * system.
- *
- * The sensor is assumed to be rolling-shutter, so low-numbered rows of the
- * sensor are exposed earlier in time than larger-numbered rows, with the time
- * offset between each row being equal to the row readout time.
- *
- * The characteristics of this sensor don't correspond to any actual sensor,
- * but are not far off typical sensors.
- *
- * Example timing diagram, with three frames:
- *  Frame 0-1: Frame duration 50 ms, exposure time 20 ms.
- *  Frame   2: Frame duration 75 ms, exposure time 65 ms.
- * Legend:
- *   C = update sensor registers for frame
- *   v = row in reset (vertical blanking interval)
- *   E = row capturing image data
- *   R = row being read out
- *   | = vertical sync signal
- *time(ms)|   0          55        105       155            230     270
- * Frame 0|   :configure : capture : readout :              :       :
- *  Row # | ..|CCCC______|_________|_________|              :       :
- *      0 |   :\          \vvvvvEEEER         \             :       :
- *    500 |   : \          \vvvvvEEEER         \            :       :
- *   1000 |   :  \          \vvvvvEEEER         \           :       :
- *   1500 |   :   \          \vvvvvEEEER         \          :       :
- *   2000 |   :    \__________\vvvvvEEEER_________\         :       :
- * Frame 1|   :           configure  capture      readout   :       :
- *  Row # |   :          |CCCC_____|_________|______________|       :
- *      0 |   :          :\         \vvvvvEEEER              \      :
- *    500 |   :          : \         \vvvvvEEEER              \     :
- *   1000 |   :          :  \         \vvvvvEEEER              \    :
- *   1500 |   :          :   \         \vvvvvEEEER              \   :
- *   2000 |   :          :    \_________\vvvvvEEEER______________\  :
- * Frame 2|   :          :          configure     capture    readout:
- *  Row # |   :          :         |CCCC_____|______________|_______|...
- *      0 |   :          :         :\         \vEEEEEEEEEEEEER       \
- *    500 |   :          :         : \         \vEEEEEEEEEEEEER       \
- *   1000 |   :          :         :  \         \vEEEEEEEEEEEEER       \
- *   1500 |   :          :         :   \         \vEEEEEEEEEEEEER       \
- *   2000 |   :          :         :    \_________\vEEEEEEEEEEEEER_______\
- */
-
-#ifndef HW_EMULATOR_CAMERA2_SENSOR_H
-#define HW_EMULATOR_CAMERA2_SENSOR_H
-
-#include "utils/Mutex.h"
-#include "utils/Thread.h"
-#include "utils/Timers.h"
-
-#include "Base.h"
-#include "Scene.h"
-
-namespace android {
-
-class EmulatedFakeCamera2;
-
-class Sensor : private Thread, public virtual RefBase {
- public:
-  // width: Width of pixel array
-  // height: Height of pixel array
-  Sensor(uint32_t width, uint32_t height);
-  ~Sensor();
-
-  /*
-   * Power control
-   */
-
-  status_t startUp();
-  status_t shutDown();
-
-  /*
-   * Access to scene
-   */
-  Scene &getScene();
-
-  /*
-   * Controls that can be updated every frame
-   */
-
-  void setExposureTime(uint64_t ns);
-  void setFrameDuration(uint64_t ns);
-  void setSensitivity(uint32_t gain);
-  // Buffer must be at least stride*height*2 bytes in size
-  void setDestinationBuffers(Buffers *buffers);
-  // To simplify tracking sensor's current frame
-  void setFrameNumber(uint32_t frameNumber);
-
-  /*
-   * Controls that cause reconfiguration delay
-   */
-
-  void setBinning(int horizontalFactor, int verticalFactor);
-
-  /*
-   * Synchronizing with sensor operation (vertical sync)
-   */
-
-  // Wait until the sensor outputs its next vertical sync signal, meaning it
-  // is starting readout of its latest frame of data. Returns true if vertical
-  // sync is signaled, false if the wait timed out.
-  bool waitForVSync(nsecs_t reltime);
-
-  // Wait until a new frame has been read out, and then return the time
-  // capture started.  May return immediately if a new frame has been pushed
-  // since the last wait for a new frame. Returns true if new frame is
-  // returned, false if timed out.
-  bool waitForNewFrame(nsecs_t reltime, nsecs_t *captureTime);
-
-  /*
-   * Interrupt event servicing from the sensor. Only triggers for sensor
-   * cycles that have valid buffers to write to.
-   */
-  struct SensorListener {
-    enum Event {
-      EXPOSURE_START,  // Start of exposure
-    };
-
-    virtual void onSensorEvent(uint32_t frameNumber, Event e,
-                               nsecs_t timestamp) = 0;
-    virtual ~SensorListener();
-  };
-
-  void setSensorListener(SensorListener *listener);
-
-  /**
-   * Static sensor characteristics
-   */
-  const uint32_t mResolution[2];
-  const uint32_t mActiveArray[4];
-
-  static const nsecs_t kExposureTimeRange[2];
-  static const nsecs_t kFrameDurationRange[2];
-  static const nsecs_t kMinVerticalBlank;
-
-  static const uint8_t kColorFilterArrangement;
-
-  // Output image data characteristics
-  static const uint32_t kMaxRawValue;
-  static const uint32_t kBlackLevel;
-  // Sensor sensitivity, approximate
-
-  static const float kSaturationVoltage;
-  static const uint32_t kSaturationElectrons;
-  static const float kVoltsPerLuxSecond;
-  static const float kElectronsPerLuxSecond;
-
-  static const float kBaseGainFactor;
-
-  static const float kReadNoiseStddevBeforeGain;  // In electrons
-  static const float kReadNoiseStddevAfterGain;   // In raw digital units
-  static const float kReadNoiseVarBeforeGain;
-  static const float kReadNoiseVarAfterGain;
-
-  // While each row has to read out, reset, and then expose, the (reset +
-  // expose) sequence can be overlapped by other row readouts, so the final
-  // minimum frame duration is purely a function of row readout time, at least
-  // if there's a reasonable number of rows.
-  const nsecs_t mRowReadoutTime;
-
-  static const int32_t kSensitivityRange[2];
-  static const uint32_t kDefaultSensitivity;
-
- private:
-  Mutex mControlMutex;  // Lock before accessing control parameters
-  // Start of control parameters
-  Condition mVSync;
-  bool mGotVSync;
-  uint64_t mExposureTime;
-  uint64_t mFrameDuration;
-  uint32_t mGainFactor;
-  Buffers *mNextBuffers;
-  uint32_t mFrameNumber;
-
-  // End of control parameters
-
-  Mutex mReadoutMutex;  // Lock before accessing readout variables
-  // Start of readout variables
-  Condition mReadoutAvailable;
-  Condition mReadoutComplete;
-  Buffers *mCapturedBuffers;
-  nsecs_t mCaptureTime;
-  SensorListener *mListener;
-  // End of readout variables
-
-  // Time of sensor startup, used for simulation zero-time point
-  nsecs_t mStartupTime;
-
-  /**
-   * Inherited Thread virtual overrides, and members only used by the
-   * processing thread
-   */
- private:
-  virtual status_t readyToRun();
-
-  virtual bool threadLoop();
-
-  nsecs_t mNextCaptureTime;
-  Buffers *mNextCapturedBuffers;
-
-  Scene mScene;
-
-  void captureRaw(uint8_t *img, uint32_t gain, uint32_t stride);
-  void captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride);
-  void captureRGB(uint8_t *img, uint32_t gain, uint32_t stride);
-  void captureNV21(uint8_t *img, uint32_t gain, uint32_t stride);
-  void captureDepth(uint8_t *img, uint32_t gain, uint32_t stride);
-  void captureDepthCloud(uint8_t *img);
-};
-
-}  // namespace android
-
-#endif  // HW_EMULATOR_CAMERA2_SENSOR_H
diff --git a/guest/hals/gatekeeper/OWNERS b/guest/hals/gatekeeper/OWNERS
new file mode 100644
index 0000000..f3bae39
--- /dev/null
+++ b/guest/hals/gatekeeper/OWNERS
@@ -0,0 +1 @@
+include platform/system/gatekeeper:/OWNERS
diff --git a/guest/hals/gatekeeper/remote/Android.bp b/guest/hals/gatekeeper/remote/Android.bp
new file mode 100644
index 0000000..d20ad9f
--- /dev/null
+++ b/guest/hals/gatekeeper/remote/Android.bp
@@ -0,0 +1,55 @@
+// Copyright (C) 2015 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.gatekeeper@1.0-service.remote",
+    defaults: ["cuttlefish_guest_only", "hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.gatekeeper@1.0-service.remote.rc"],
+
+    srcs: [
+        "remote_gatekeeper.cpp",
+        "service.cpp",
+    ],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+    ],
+
+    static_libs: [
+        "libgflags",
+    ],
+
+    shared_libs: [
+        "android.hardware.gatekeeper@1.0",
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_security",
+        "libhidlbase",
+        "libgatekeeper",
+        "libutils",
+        "liblog",
+        "libcutils",
+        "libtrusty",
+    ],
+
+    vintf_fragments: ["android.hardware.gatekeeper@1.0-service.remote.xml"],
+}
diff --git a/guest/hals/gatekeeper/remote/android.hardware.gatekeeper@1.0-service.remote.rc b/guest/hals/gatekeeper/remote/android.hardware.gatekeeper@1.0-service.remote.rc
new file mode 100644
index 0000000..45bf268
--- /dev/null
+++ b/guest/hals/gatekeeper/remote/android.hardware.gatekeeper@1.0-service.remote.rc
@@ -0,0 +1,4 @@
+service vendor.gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service.remote
+    class hal
+    user system
+    group system
diff --git a/guest/hals/gatekeeper/remote/android.hardware.gatekeeper@1.0-service.remote.xml b/guest/hals/gatekeeper/remote/android.hardware.gatekeeper@1.0-service.remote.xml
new file mode 100644
index 0000000..19714a8
--- /dev/null
+++ b/guest/hals/gatekeeper/remote/android.hardware.gatekeeper@1.0-service.remote.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gatekeeper</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+        <name>IGatekeeper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/guest/hals/gatekeeper/remote/remote_gatekeeper.cpp b/guest/hals/gatekeeper/remote/remote_gatekeeper.cpp
new file mode 100644
index 0000000..5cca879
--- /dev/null
+++ b/guest/hals/gatekeeper/remote/remote_gatekeeper.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "RemoteGateKeeper"
+
+#include "remote_gatekeeper.h"
+
+#include <limits>
+
+#include <android-base/logging.h>
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using ::gatekeeper::EnrollRequest;
+using ::gatekeeper::EnrollResponse;
+using ::gatekeeper::ERROR_INVALID;
+using ::gatekeeper::ERROR_MEMORY_ALLOCATION_FAILED;
+using ::gatekeeper::ERROR_NONE;
+using ::gatekeeper::ERROR_RETRY;
+using ::gatekeeper::SizedBuffer;
+using ::gatekeeper::VerifyRequest;
+using ::gatekeeper::VerifyResponse;
+
+namespace gatekeeper {
+
+RemoteGateKeeperDevice::RemoteGateKeeperDevice(cuttlefish::GatekeeperChannel* channel)
+    : gatekeeper_channel_(channel), error_(0) {
+}
+
+RemoteGateKeeperDevice::~RemoteGateKeeperDevice() {
+}
+
+SizedBuffer hidl_vec2sized_buffer(const hidl_vec<uint8_t>& vec) {
+    if (vec.size() == 0 || vec.size() > std::numeric_limits<uint32_t>::max()) return {};
+    auto unused = new uint8_t[vec.size()];
+    std::copy(vec.begin(), vec.end(), unused);
+    return {unused, static_cast<uint32_t>(vec.size())};
+}
+
+Return<void> RemoteGateKeeperDevice::enroll(uint32_t uid,
+                                            const hidl_vec<uint8_t>& currentPasswordHandle,
+                                            const hidl_vec<uint8_t>& currentPassword,
+                                            const hidl_vec<uint8_t>& desiredPassword,
+                                            enroll_cb _hidl_cb) {
+    if (error_ != 0) {
+        LOG(ERROR) << "Gatekeeper in invalid state";
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+        return {};
+    }
+
+    if (desiredPassword.size() == 0) {
+        LOG(ERROR) << "Desired password size is 0";
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+        return {};
+    }
+
+    EnrollRequest request(uid, hidl_vec2sized_buffer(currentPasswordHandle),
+                          hidl_vec2sized_buffer(desiredPassword),
+                          hidl_vec2sized_buffer(currentPassword));
+    EnrollResponse response;
+    auto error = Send(request, &response);
+    if (error != ERROR_NONE) {
+        LOG(ERROR) << "Enroll request gave error: " << error;
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+    } else if (response.error == ERROR_RETRY) {
+        LOG(ERROR) << "Enroll response has a retry error";
+        _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}});
+    } else if (response.error != ERROR_NONE) {
+        LOG(ERROR) << "Enroll response has an error: " << response.error;
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+    } else {
+        hidl_vec<uint8_t> new_handle(response.enrolled_password_handle.Data<uint8_t>(),
+                                     response.enrolled_password_handle.Data<uint8_t>() +
+                                             response.enrolled_password_handle.size());
+        _hidl_cb({GatekeeperStatusCode::STATUS_OK, response.retry_timeout, new_handle});
+    }
+    return {};
+}
+
+Return<void> RemoteGateKeeperDevice::verify(
+        uint32_t uid, uint64_t challenge,
+        const ::android::hardware::hidl_vec<uint8_t>& enrolledPasswordHandle,
+        const ::android::hardware::hidl_vec<uint8_t>& providedPassword, verify_cb _hidl_cb) {
+    if (error_ != 0) {
+        LOG(ERROR) << "Gatekeeper in invalid state";
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+        return {};
+    }
+
+    if (enrolledPasswordHandle.size() == 0) {
+        LOG(ERROR) << "Enrolled password size is 0";
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+        return {};
+    }
+
+    VerifyRequest request(uid, challenge, hidl_vec2sized_buffer(enrolledPasswordHandle),
+                          hidl_vec2sized_buffer(providedPassword));
+    VerifyResponse response;
+
+    auto error = Send(request, &response);
+    if (error != ERROR_NONE) {
+        LOG(ERROR) << "Verify request gave error: " << error;
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+    } else if (response.error == ERROR_RETRY) {
+        LOG(ERROR) << "Verify request response gave retry error";
+        _hidl_cb({GatekeeperStatusCode::ERROR_RETRY_TIMEOUT, response.retry_timeout, {}});
+    } else if (response.error != ERROR_NONE) {
+        LOG(ERROR) << "Verify request response gave error: " << response.error;
+        _hidl_cb({GatekeeperStatusCode::ERROR_GENERAL_FAILURE, 0, {}});
+    } else {
+        hidl_vec<uint8_t> auth_token(
+                response.auth_token.Data<uint8_t>(),
+                response.auth_token.Data<uint8_t>() + response.auth_token.size());
+
+        _hidl_cb({response.request_reenroll ? GatekeeperStatusCode::STATUS_REENROLL
+                                            : GatekeeperStatusCode::STATUS_OK,
+                  response.retry_timeout, auth_token});
+    }
+    return {};
+}
+
+Return<void> RemoteGateKeeperDevice::deleteUser(uint32_t /*uid*/, deleteUser_cb _hidl_cb) {
+    LOG(ERROR) << "deleteUser is unimplemented";
+    _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}});
+    return {};
+}
+
+Return<void> RemoteGateKeeperDevice::deleteAllUsers(deleteAllUsers_cb _hidl_cb) {
+    LOG(ERROR) << "deleteAllUsers is unimplemented";
+    _hidl_cb({GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED, 0, {}});
+    return {};
+}
+
+gatekeeper_error_t RemoteGateKeeperDevice::Send(uint32_t command, const GateKeeperMessage& request,
+        GateKeeperMessage *response) {
+    if (!gatekeeper_channel_->SendRequest(command, request)) {
+      LOG(ERROR) << "Failed to send request";
+      return ERROR_UNKNOWN;
+    }
+    auto remote_response = gatekeeper_channel_->ReceiveMessage();
+    if (!remote_response) {
+      LOG(ERROR) << "Failed to receive response";
+      return ERROR_UNKNOWN;
+    }
+    const uint8_t* buffer = remote_response->payload;
+    const uint8_t* buffer_end = remote_response->payload + remote_response->payload_size;
+    auto rc = response->Deserialize(buffer, buffer_end);
+    if (rc != ERROR_NONE) {
+        LOG(ERROR) << "Failed to deserialize keymaster response: " << command;
+        return ERROR_UNKNOWN;
+    }
+    return rc;
+}
+
+};
diff --git a/guest/hals/gatekeeper/remote/remote_gatekeeper.h b/guest/hals/gatekeeper/remote/remote_gatekeeper.h
new file mode 100644
index 0000000..5575052
--- /dev/null
+++ b/guest/hals/gatekeeper/remote/remote_gatekeeper.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef TRUSTY_GATEKEEPER_H
+#define TRUSTY_GATEKEEPER_H
+
+#include <memory>
+
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <hidl/Status.h>
+#include <gatekeeper/gatekeeper_messages.h>
+
+#include "common/libs/security/gatekeeper_channel.h"
+
+namespace gatekeeper {
+
+class RemoteGateKeeperDevice : public ::android::hardware::gatekeeper::V1_0::IGatekeeper {
+  public:
+    explicit RemoteGateKeeperDevice(cuttlefish::GatekeeperChannel* gatekeeper_channel);
+    ~RemoteGateKeeperDevice();
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    ::android::hardware::Return<void> enroll(
+            uint32_t uid, const ::android::hardware::hidl_vec<uint8_t>& currentPasswordHandle,
+            const ::android::hardware::hidl_vec<uint8_t>& currentPassword,
+            const ::android::hardware::hidl_vec<uint8_t>& desiredPassword,
+            enroll_cb _hidl_cb) override;
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    ::android::hardware::Return<void> verify(
+            uint32_t uid, uint64_t challenge,
+            const ::android::hardware::hidl_vec<uint8_t>& enrolledPasswordHandle,
+            const ::android::hardware::hidl_vec<uint8_t>& providedPassword,
+            verify_cb _hidl_cb) override;
+
+    ::android::hardware::Return<void> deleteUser(uint32_t uid, deleteUser_cb _hidl_cb) override;
+
+    ::android::hardware::Return<void> deleteAllUsers(deleteAllUsers_cb _hidl_cb) override;
+
+  private:
+    cuttlefish::GatekeeperChannel* gatekeeper_channel_;
+
+    gatekeeper_error_t Send(uint32_t command, const GateKeeperMessage& request,
+                           GateKeeperMessage* response);
+
+    gatekeeper_error_t Send(const EnrollRequest& request, EnrollResponse *response) {
+        return Send(ENROLL, request, response);
+    }
+
+    gatekeeper_error_t Send(const VerifyRequest& request, VerifyResponse *response) {
+        return Send(VERIFY, request, response);
+    }
+
+    int error_;
+};
+
+}  // namespace gatekeeper
+
+#endif
diff --git a/guest/hals/gatekeeper/remote/service.cpp b/guest/hals/gatekeeper/remote/service.cpp
new file mode 100644
index 0000000..9a230f5
--- /dev/null
+++ b/guest/hals/gatekeeper/remote/service.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#define LOG_TAG "android.hardware.gatekeeper@1.0-service.remote"
+
+#include <android-base/logging.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <cutils/properties.h>
+#include <gflags/gflags.h>
+
+#include <hidl/LegacySupport.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/gatekeeper_channel.h"
+#include "guest/hals/gatekeeper/remote/remote_gatekeeper.h"
+
+// Generated HIDL files
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+using gatekeeper::RemoteGateKeeperDevice;
+
+const char device[] = "/dev/hvc4";
+
+int main(int argc, char** argv) {
+  ::android::base::InitLogging(argv, ::android::base::KernelLogger);
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
+  ::android::hardware::configureRpcThreadpool(1, true /* willJoinThreadpool */);
+
+  auto fd = cuttlefish::SharedFD::Open(device, O_RDWR);
+  if (!fd->IsOpen()) {
+    LOG(FATAL) << "Could not connect to gatekeeper: " << fd->StrError();
+  }
+
+  if (fd->SetTerminalRaw() < 0) {
+    LOG(FATAL) << "Could not make " << device << " a raw terminal: "
+                << fd->StrError();
+  }
+
+  cuttlefish::GatekeeperChannel gatekeeperChannel(fd, fd);
+
+  android::sp<RemoteGateKeeperDevice> gatekeeper(
+    new RemoteGateKeeperDevice(&gatekeeperChannel));
+  auto status = gatekeeper->registerAsService();
+  if (status != android::OK) {
+    LOG(FATAL) << "Could not register service for Gatekeeper 1.0 (remote) (" << status << ")";
+  }
+
+  android::hardware::joinRpcThreadpool();
+  return -1;  // Should never get here.
+}
diff --git a/guest/hals/gps/Android.bp b/guest/hals/gps/Android.bp
deleted file mode 100644
index 22c5998..0000000
--- a/guest/hals/gps/Android.bp
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2017 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.
-
-// HAL module implemenation, not prelinked and stored in
-// hw/<LIGHTS_HARDWARE_MODULE_ID>.<ro.hardware>.so
-cc_library_shared {
-    name: "gps.cutf",
-    relative_install_path: "hw",
-    srcs: [
-        "gps_vsoc.cpp",
-        "gps_thread.cpp",
-    ],
-    shared_libs: [
-        "liblog",
-        "libcutils",
-    ],
-    header_libs: ["libhardware_headers"],
-    cflags: [
-        "-Wno-missing-field-initializers",
-        "-DLOG_TAG=\"VSoCGPS\"",
-    ],
-    defaults: ["cuttlefish_guest_only"],
-}
diff --git a/guest/hals/gps/gps_thread.cpp b/guest/hals/gps/gps_thread.cpp
deleted file mode 100644
index cea830c..0000000
--- a/guest/hals/gps/gps_thread.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#include "guest/hals/gps/gps_thread.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <pthread.h>
-#include <sys/epoll.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <log/log.h>
-#include <cutils/sockets.h>
-#include <hardware/gps.h>
-
-// Calls an callback function to pass received and parsed GPS data to Android.
-static void reader_call_callback(GpsDataReader* r) {
-  if (!r) {
-    ALOGW("%s: called with r=NULL", __FUNCTION__);
-    return;
-  }
-  if (!r->callback) {
-    ALOGW("%s: no callback registered; keeping the data to send later",
-          __FUNCTION__);
-    return;
-  }
-  if (!r->fix.flags) {
-    ALOGW("%s: no GPS fix", __FUNCTION__);
-    return;
-  }
-  // Always uses current time converted to UTC time in milliseconds.
-  time_t secs = time(NULL);  // seconds from 01/01/1970.
-  r->fix.timestamp = (long long)secs * 1000;
-
-#if GPS_DEBUG
-  D("* Parsed GPS Data");
-  if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
-    D(" - latitude = %g", r->fix.latitude);
-    D(" - longitude = %g", r->fix.longitude);
-  }
-  if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE)
-    D(" - altitude = %g", r->fix.altitude);
-  if (r->fix.flags & GPS_LOCATION_HAS_SPEED) D(" - speed = %g", r->fix.speed);
-  if (r->fix.flags & GPS_LOCATION_HAS_BEARING)
-    D(" - bearing = %g", r->fix.bearing);
-  if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY)
-    D(" - accuracy = %g", r->fix.accuracy);
-  long long utc_secs = r->fix.timestamp / 1000;
-  struct tm utc;
-  gmtime_r((time_t*)&utc_secs, &utc);
-  D(" - time = %s", asctime(&utc));
-#endif
-
-  D("Sending fix to callback %p", r->callback);
-  r->callback(&r->fix);
-}
-
-// Parses data received so far and calls reader_call_callback().
-static void reader_parse_message(GpsDataReader* r) {
-  D("Received: '%s'", r->buffer);
-
-  int num_read = sscanf(r->buffer, "%lf,%lf,%lf,%f,%f,%f", &r->fix.longitude,
-                        &r->fix.latitude, &r->fix.altitude, &r->fix.bearing,
-                        &r->fix.speed, &r->fix.accuracy);
-  if (num_read != 6) {
-    ALOGE("Couldn't find 6 values from the received message %s.", r->buffer);
-    return;
-  }
-  r->fix.flags = DEFAULT_GPS_LOCATION_FLAG;
-  reader_call_callback(r);
-}
-
-// Accepts a newly received string & calls reader_parse_message if '\n' is seen.
-static void reader_accept_string(GpsDataReader* r, char* const str,
-                                 const int len) {
-  int index;
-  for (index = 0; index < len; index++) {
-    if (r->index >= (int)sizeof(r->buffer) - 1) {
-      if (str[index] == '\n') {
-        ALOGW("Message longer than buffer; new byte (%d) skipped.", str[index]);
-        r->index = 0;
-      }
-    } else {
-      r->buffer[r->index++] = str[index];
-      if (str[index] == '\n') {
-        r->buffer[r->index] = '\0';
-        reader_parse_message(r);
-        r->index = 0;
-      }
-    }
-  }
-}
-
-// GPS state threads which communicates with control and data sockets.
-void gps_state_thread(void* arg) {
-  GpsState* state = (GpsState*)arg;
-  GpsDataReader reader;
-  int epoll_fd = epoll_create(2);
-  int started = -1;
-  int gps_fd = state->fd;
-  int control_fd = state->control[1];
-
-  memset(&reader, 0, sizeof(reader));
-  reader.fix.size = sizeof(reader.fix);
-
-  epoll_register(epoll_fd, control_fd);
-  epoll_register(epoll_fd, gps_fd);
-
-  while (1) {
-    struct epoll_event events[2];
-    int nevents, event_index;
-
-    nevents = epoll_wait(epoll_fd, events, 2, 500);
-    D("Thread received %d events", nevents);
-    if (nevents < 0) {
-      if (errno != EINTR)
-        ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
-      continue;
-    } else if (nevents == 0) {
-      if (started == 1) {
-        reader_call_callback(&reader);
-      }
-      continue;
-    }
-
-    for (event_index = 0; event_index < nevents; event_index++) {
-      if ((events[event_index].events & (EPOLLERR | EPOLLHUP)) != 0) {
-        ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
-        goto Exit;
-      }
-
-      if ((events[event_index].events & EPOLLIN) != 0) {
-        int fd = events[event_index].data.fd;
-        if (fd == control_fd) {
-          unsigned char cmd = 255;
-          int ret;
-          do {
-            ret = read(fd, &cmd, 1);
-          } while (ret < 0 && errno == EINTR);
-
-          if (cmd == CMD_STOP || cmd == CMD_QUIT) {
-            if (started == 1) {
-              D("Thread stopping");
-              started = 0;
-              reader.callback = NULL;
-            }
-            if (cmd == CMD_QUIT) {
-              D("Thread quitting");
-              goto Exit;
-            }
-          } else if (cmd == CMD_START) {
-            if (started != 1) {
-              reader.callback = state->callbacks.location_cb;
-              D("Thread starting callback=%p", reader.callback);
-              reader_call_callback(&reader);
-              started = 1;
-            }
-          } else {
-            ALOGE("unknown control command %d", cmd);
-          }
-        } else if (fd == gps_fd) {
-          char buff[256];
-          int ret;
-          for (;;) {
-            ret = read(fd, buff, sizeof(buff));
-            if (ret < 0) {
-              if (errno == EINTR) continue;
-              if (errno != EWOULDBLOCK)
-                ALOGE("error while reading from gps daemon socket: %s:",
-                      strerror(errno));
-              break;
-            }
-            D("Thread received %d bytes: %.*s", ret, ret, buff);
-            reader_accept_string(&reader, buff, ret);
-          }
-        } else {
-          ALOGE("epoll_wait() returned unknown fd %d.", fd);
-        }
-      }
-    }
-  }
-
-Exit:
-  epoll_deregister(epoll_fd, control_fd);
-  epoll_deregister(epoll_fd, gps_fd);
-}
diff --git a/guest/hals/gps/gps_thread.h b/guest/hals/gps/gps_thread.h
deleted file mode 100644
index 7cd3c9e..0000000
--- a/guest/hals/gps/gps_thread.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2017 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 <errno.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-
-#include <hardware/gps.h>
-
-#define GPS_DEBUG 0
-#define GPS_DATA_BUFFER_MAX_SIZE 256
-
-#define DEFAULT_GPS_LOCATION_FLAG                          \
-  (GPS_LOCATION_HAS_LAT_LONG | GPS_LOCATION_HAS_ALTITUDE | \
-   GPS_LOCATION_HAS_BEARING | GPS_LOCATION_HAS_SPEED |     \
-   GPS_LOCATION_HAS_ACCURACY)
-
-#if GPS_DEBUG
-#define D(...) ALOGD(__VA_ARGS__)
-#else
-#define D(...) ((void)0)
-#endif
-
-// Control commands to GPS thread
-enum { CMD_QUIT = 0, CMD_START = 1, CMD_STOP = 2 };
-
-// GPS HAL's state
-typedef struct {
-  int init;
-  int fd;
-  int control[2];
-  pthread_t thread;
-  GpsCallbacks callbacks;
-} GpsState;
-
-typedef struct {
-  GpsLocation fix;
-  gps_location_callback callback;
-  char buffer[GPS_DATA_BUFFER_MAX_SIZE + 1];
-  int index;
-} GpsDataReader;
-
-void gps_state_thread(void* arg);
-
-static inline int epoll_register(int epoll_fd, int fd) {
-  fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
-
-  struct epoll_event ev;
-  ev.events = EPOLLIN;
-  ev.data.fd = fd;
-
-  int ret;
-  do {
-    ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
-  } while (ret < 0 && errno == EINTR);
-  return ret;
-}
-
-static inline int epoll_deregister(int epoll_fd, int fd) {
-  int ret;
-  do {
-    ret = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
-  } while (ret < 0 && errno == EINTR);
-  return ret;
-}
diff --git a/guest/hals/gps/gps_vsoc.cpp b/guest/hals/gps/gps_vsoc.cpp
deleted file mode 100644
index 94bfce4..0000000
--- a/guest/hals/gps/gps_vsoc.cpp
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-/* This implements a GPS hardware HAL library for cuttlefish.
- * A produced shared library is placed in /system/lib/hw/gps.gce.so, and
- * loaded by hardware/libhardware/hardware.c code which is called from
- * android_location_GpsLocationProvider.cpp
- */
-
-#include <errno.h>
-#include <pthread.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#include <log/log.h>
-#include <cutils/sockets.h>
-#include <hardware/gps.h>
-
-#include "guest/hals/gps/gps_thread.h"
-
-static GpsState _gps_state;
-
-// Cleans up GpsState data structure.
-static void gps_state_cleanup(GpsState* s) {
-  char cmd = CMD_QUIT;
-
-  write(s->control[0], &cmd, 1);
-  if (s->thread > 0) {
-    pthread_join(s->thread, NULL);
-  }
-
-  close(s->control[0]);
-  close(s->control[1]);
-  close(s->fd);
-
-  s->thread = 0;
-  s->control[0] = -1;
-  s->control[1] = -1;
-  s->fd = -1;
-  s->init = 0;
-}
-
-static int gce_gps_init(GpsCallbacks* callbacks) {
-  D("%s: called", __FUNCTION__);
-  // Stop if the framework does not fulfill its interface contract.
-  // We don't want to return an error and continue to ensure that we
-  // catch framework breaks ASAP and to give a tombstone to track down the
-  // offending code.
-  LOG_ALWAYS_FATAL_IF(!callbacks->location_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->status_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->sv_status_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->nmea_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->set_capabilities_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->acquire_wakelock_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->release_wakelock_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->create_thread_cb);
-  LOG_ALWAYS_FATAL_IF(!callbacks->request_utc_time_cb);
-  if (!_gps_state.init) {
-    _gps_state.init = 1;
-    _gps_state.control[0] = -1;
-    _gps_state.control[1] = -1;
-    _gps_state.thread = 0;
-
-    _gps_state.fd = socket_local_client(
-        "gps_broadcasts", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    if (_gps_state.fd < 0) {
-      ALOGE("no GPS emulation detected.");
-      goto Fail;
-    }
-    D("GPS HAL will receive data from remoter via gps_broadcasts channel.");
-
-    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, _gps_state.control) < 0) {
-      ALOGE("could not create thread control socket pair: %s", strerror(errno));
-      goto Fail;
-    }
-
-    _gps_state.callbacks = *callbacks;
-    ALOGE("Starting thread callback=%p", callbacks->location_cb);
-    _gps_state.thread = callbacks->create_thread_cb(
-        "gps_state_thread", gps_state_thread, &_gps_state);
-    if (!_gps_state.thread) {
-      ALOGE("could not create GPS thread: %s", strerror(errno));
-      goto Fail;
-    }
-  }
-
-  if (_gps_state.fd < 0) return -1;
-  return 0;
-
-Fail:
-  gps_state_cleanup(&_gps_state);
-  return -1;
-}
-
-static void gce_gps_cleanup() {
-  D("%s: called", __FUNCTION__);
-  if (_gps_state.init) gps_state_cleanup(&_gps_state);
-}
-
-static int gce_gps_start() {
-  if (!_gps_state.init) {
-    ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
-    return -1;
-  }
-
-  char cmd = CMD_START;
-  int ret;
-  do {
-    ret = write(_gps_state.control[0], &cmd, 1);
-  } while (ret < 0 && errno == EINTR);
-
-  if (ret != 1) {
-    D("%s: could not send CMD_START command: ret=%d: %s", __FUNCTION__, ret,
-      strerror(errno));
-    return -1;
-  }
-
-  return 0;
-}
-
-static int gce_gps_stop() {
-  D("%s: called", __FUNCTION__);
-  if (!_gps_state.init) {
-    ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
-    return -1;
-  }
-
-  char cmd = CMD_STOP;
-  int ret;
-
-  do {
-    ret = write(_gps_state.control[0], &cmd, 1);
-  } while (ret < 0 && errno == EINTR);
-
-  if (ret != 1) {
-    ALOGE("%s: could not send CMD_STOP command: ret=%d: %s", __FUNCTION__, ret,
-          strerror(errno));
-    return -1;
-  }
-  return 0;
-}
-
-static int gce_gps_inject_time(GpsUtcTime /*time*/, int64_t /*time_ref*/,
-                               int /*uncertainty*/) {
-  D("%s: called", __FUNCTION__);
-  if (!_gps_state.init) {
-    ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
-    return -1;
-  }
-
-  return 0;
-}
-
-static int gce_gps_inject_location(double /*latitude*/, double /*longitude*/,
-                                   float /*accuracy*/) {
-  D("%s: called", __FUNCTION__);
-  if (!_gps_state.init) {
-    ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
-    return -1;
-  }
-
-  return 0;
-}
-
-static void gce_gps_delete_aiding_data(GpsAidingData /*flags*/) {
-  D("%s: called", __FUNCTION__);
-  if (!_gps_state.init) {
-    ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
-    return;
-  }
-}
-
-static int gce_gps_set_position_mode(GpsPositionMode mode,
-                                     GpsPositionRecurrence recurrence,
-                                     uint32_t min_interval,
-                                     uint32_t preferred_accuracy,
-                                     uint32_t preferred_time) {
-  D("%s: called", __FUNCTION__);
-  if (!_gps_state.init) {
-    ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
-    return -1;
-  }
-  ALOGE("%s(mode=%d, recurrence=%d, min_interval=%" PRIu32
-        ", "
-        "preferred_accuracy=%" PRIu32 ", preferred_time=%" PRIu32
-        ") unimplemented",
-        __FUNCTION__, mode, recurrence, min_interval, preferred_accuracy,
-        preferred_time);
-  return 0;
-}
-
-static const void* gce_gps_get_extension(const char* name) {
-  D("%s: called", __FUNCTION__);
-  // It is normal for this to be called before init.
-  ALOGE("%s(%s): called but not implemented.", __FUNCTION__,
-        name ? name : "NULL");
-  return NULL;
-}
-
-static const GpsInterface gceGpsInterface = {
-    sizeof(GpsInterface),
-    gce_gps_init,
-    gce_gps_start,
-    gce_gps_stop,
-    gce_gps_cleanup,
-    gce_gps_inject_time,
-    gce_gps_inject_location,
-    gce_gps_delete_aiding_data,
-    gce_gps_set_position_mode,
-    gce_gps_get_extension,
-};
-
-const GpsInterface* gps_get_gps_interface(struct gps_device_t* /*dev*/) {
-  return &gceGpsInterface;
-}
-
-static int open_gps(const struct hw_module_t* module, char const* /*name*/,
-                    struct hw_device_t** device) {
-  struct gps_device_t* dev =
-      (struct gps_device_t*)malloc(sizeof(struct gps_device_t));
-  LOG_FATAL_IF(!dev, "%s: malloc returned NULL.", __FUNCTION__);
-  memset(dev, 0, sizeof(*dev));
-
-  dev->common.tag = HARDWARE_DEVICE_TAG;
-  dev->common.version = 0;
-  dev->common.module = (struct hw_module_t*)module;
-  dev->get_gps_interface = gps_get_gps_interface;
-
-  *device = (struct hw_device_t*)dev;
-  return 0;
-}
-
-static struct hw_module_methods_t gps_module_methods = {
-    .open = open_gps};
-
-struct hw_module_t HAL_MODULE_INFO_SYM = {
-    .tag = HARDWARE_MODULE_TAG,
-    .version_major = 1,
-    .version_minor = 0,
-    .id = GPS_HARDWARE_MODULE_ID,
-    .name = "GCE GPS Module",
-    .author = "The Android Open Source Project",
-    .methods = & gps_module_methods,
-};
diff --git a/guest/hals/gralloc/legacy/Android.mk b/guest/hals/gralloc/legacy/Android.mk
deleted file mode 100644
index 257605e..0000000
--- a/guest/hals/gralloc/legacy/Android.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2016 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.
-
-# Temporary, should be removed once vsoc hals are in usable state
-
-LOCAL_PATH := $(call my-dir)
-
-VSOC_GRALLOC_COMMON_SRC_FILES := \
-    gralloc.cpp \
-    mapper.cpp \
-    region_registry.cpp
-
-VSOC_GRALLOC_COMMON_CFLAGS:= \
-    -DLOG_TAG=\"gralloc_vsoc_legacy\" \
-    -Wno-missing-field-initializers \
-    -Wall -Werror \
-    $(VSOC_VERSION_CFLAGS)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := gralloc.cutf_ashmem
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(VSOC_GRALLOC_COMMON_SRC_FILES)
-
-LOCAL_CFLAGS := $(VSOC_GRALLOC_COMMON_CFLAGS)
-LOCAL_C_INCLUDES := \
-    device/google/cuttlefish
-
-LOCAL_HEADER_LIBRARIES := \
-    libhardware_headers
-
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    liblog \
-    libutils \
-    libcutils
-
-LOCAL_VENDOR_MODULE := true
-
-# See b/67109557
-ifeq (true, $(TARGET_TRANSLATE_2ND_ARCH))
-LOCAL_MULTILIB := first
-endif
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/guest/hals/gralloc/legacy/gralloc.cpp b/guest/hals/gralloc/legacy/gralloc.cpp
deleted file mode 100644
index 28e71eb..0000000
--- a/guest/hals/gralloc/legacy/gralloc.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-#include <atomic>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-
-#include <cutils/ashmem.h>
-#include <log/log.h>
-#include <cutils/atomic.h>
-#include <utils/String8.h>
-
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-
-#include "gralloc_vsoc_priv.h"
-#include "region_registry.h"
-
-using vsoc::screen::ScreenRegionView;
-
-/*****************************************************************************/
-
-static inline size_t roundUpToPageSize(size_t x) {
-  return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
-}
-
-static int gralloc_alloc_buffer(
-    alloc_device_t* /*dev*/, int format, int w, int h,
-    buffer_handle_t* pHandle, int* pStrideInPixels) {
-  int err = 0;
-  int fd = -1;
-  static std::atomic<int> sequence;
-
-  int bytes_per_pixel = formatToBytesPerPixel(format);
-  int bytes_per_line;
-  int stride_in_pixels;
-  int size = 0;
-  // SwiftShader can't handle RGB_888, so fail fast and hard if we try to create
-  // a gralloc buffer in this format.
-  ALOG_ASSERT(format != HAL_PIXEL_FORMAT_RGB_888);
-  if (format == HAL_PIXEL_FORMAT_YV12) {
-    bytes_per_line = ScreenRegionView::align(bytes_per_pixel * w);
-  } else {
-    bytes_per_line = ScreenRegionView::align(bytes_per_pixel * w);
-  }
-  size = roundUpToPageSize(size + formatToBytesPerFrame(format, w, h));
-  size += PAGE_SIZE;
-  fd = ashmem_create_region(
-      android::String8::format(
-          "gralloc-%d.%d", getpid(), sequence++).string(),
-      size);
-  if (fd < 0) {
-    ALOGE("couldn't create ashmem (%s)", strerror(-errno));
-    err = -errno;
-  }
-
-  if (err == 0) {
-    stride_in_pixels = bytes_per_line / bytes_per_pixel;
-    private_handle_t* hnd =
-        new private_handle_t(fd, size, format, w, h, stride_in_pixels, 0);
-    void* base = reference_region(__FUNCTION__, hnd);
-    if (base) {
-      *pHandle = hnd;
-      *pStrideInPixels = stride_in_pixels;
-    } else {
-      err = -EIO;
-    }
-  }
-
-  ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
-
-  return err;
-}
-
-/*****************************************************************************/
-
-static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
-                         int /*usage*/, buffer_handle_t* pHandle,
-                         int* pStrideInPixels) {
-  if (!pHandle || !pStrideInPixels)
-    return -EINVAL;
-
-  int err = gralloc_alloc_buffer(dev, format, w, h, pHandle, pStrideInPixels);
-
-  if (err < 0) {
-    return err;
-  }
-  return 0;
-}
-
-static int gralloc_free(alloc_device_t* /*dev*/, buffer_handle_t handle) {
-  if (private_handle_t::validate(handle) < 0) {
-    return -EINVAL;
-  }
-
-  private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(
-    handle);
-  int retval = unreference_region(__FUNCTION__, hnd);
-
-  close(hnd->fd);
-  delete hnd;
-  return retval;
-}
-
-/*****************************************************************************/
-
-static int gralloc_close(struct hw_device_t *dev) {
-  priv_alloc_device_t* ctx = reinterpret_cast<priv_alloc_device_t*>(dev);
-  if (ctx) {
-    /* TODO: keep a list of all buffer_handle_t created, and free them
-     * all here.
-     */
-    free(ctx);
-  }
-  return 0;
-}
-
-static int gralloc_device_open(
-    const hw_module_t* module, const char* name, hw_device_t** device) {
-  int status = -EINVAL;
-  if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
-    priv_alloc_device_t *dev;
-    dev = (priv_alloc_device_t*) malloc(sizeof(*dev));
-    LOG_FATAL_IF(!dev, "%s: malloc returned NULL.", __FUNCTION__);
-
-    /* initialize our state here */
-    memset(dev, 0, sizeof(*dev));
-
-    /* initialize the procs */
-    dev->device.common.tag = HARDWARE_DEVICE_TAG;
-    dev->device.common.version = 0;
-    dev->device.common.module = const_cast<hw_module_t*>(module);
-    dev->device.common.close = gralloc_close;
-
-    dev->device.alloc   = gralloc_alloc;
-    dev->device.free    = gralloc_free;
-
-    *device = &dev->device.common;
-    status = 0;
-  } else {
-    ALOGE("Need to create framebuffer, but it is unsupported");
-  }
-  return status;
-}
-
-/*****************************************************************************/
-
-static struct hw_module_methods_t gralloc_module_methods = {
-  .open = gralloc_device_open
-};
-
-struct private_module_t HAL_MODULE_INFO_SYM = {
-  .base = {
-    .common = {
-      .tag = HARDWARE_MODULE_TAG,
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-      .version_major = GRALLOC_MODULE_API_VERSION_0_2,
-#else
-      .version_major = 1,
-#endif
-      .version_minor = 0,
-      .id = GRALLOC_HARDWARE_MODULE_ID,
-      .name = "VSOC X86 Graphics Memory Allocator Module",
-      .author = "The Android Open Source Project",
-      .methods = &gralloc_module_methods,
-      .dso = NULL,
-      .reserved = {0},
-    },
-    .registerBuffer = gralloc_register_buffer,
-    .unregisterBuffer = gralloc_unregister_buffer,
-    .lock = gralloc_lock,
-    .unlock = gralloc_unlock,
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-    .perform = NULL,
-    .lock_ycbcr = gralloc_lock_ycbcr,
-#endif
-    .getTransportSize = gralloc_get_transport_size,
-    .validateBufferSize = gralloc_validate_buffer_size,
-  },
-};
diff --git a/guest/hals/gralloc/legacy/gralloc_vsoc_priv.h b/guest/hals/gralloc/legacy/gralloc_vsoc_priv.h
deleted file mode 100644
index 390c654..0000000
--- a/guest/hals/gralloc/legacy/gralloc_vsoc_priv.h
+++ /dev/null
@@ -1,340 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-#include <stdint.h>
-#include <limits.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/mman.h>
-#include <hardware/gralloc.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <cutils/native_handle.h>
-#include <log/log.h>
-
-#include <linux/fb.h>
-
-#ifndef GRALLOC_MODULE_API_VERSION_0_2
-// This structure will be defined in later releases of Android. Declare it
-// here to allow us to structure the code well.
-struct android_ycbcr {
-  void* y;
-  void* cb;
-  void* cr;
-  size_t ystride;
-  size_t cstride;
-  size_t chroma_step;
-  uint32_t reserved[8];
-};
-#endif
-
-namespace vsoc {
-namespace screen {
-
-struct ScreenRegionView {
-  static int align(int input) {
-    auto constexpr alignment = 16;
-    return (input + alignment - 1) & -alignment;
-  }
-  static constexpr int kSwiftShaderPadding = 4;
-};
-
-}
-}
-
-/*****************************************************************************/
-
-struct private_handle_t;
-
-struct private_module_t {
-  gralloc_module_t base;
-};
-
-/*****************************************************************************/
-
-struct priv_alloc_device_t {
-  alloc_device_t  device;
-};
-
-/*****************************************************************************/
-
-struct private_handle_t : public native_handle {
-  // file-descriptors
-  int     fd;
-  // ints
-  int     magic;
-  int     flags;
-  int     format;
-  int     x_res;
-  int     y_res;
-  int     stride_in_pixels;
-  // Use to indicate which frame we're using.
-  int     frame_offset;
-  int     total_size;
-  int     lock_level;
-
-  static inline int sNumInts() {
-    return (((sizeof(private_handle_t) - sizeof(native_handle_t))/sizeof(int)) - sNumFds);
-  }
-  static const int sNumFds = 1;
-  static const int sMagic = 0x3141592;
-
-  private_handle_t(int fd, int size, int format, int x_res, int y_res,
-                   int stride_in_pixels, int flags, int frame_offset = 0)
-      : fd(fd),
-        magic(sMagic),
-        flags(flags),
-        format(format),
-        x_res(x_res),
-        y_res(y_res),
-        stride_in_pixels(stride_in_pixels),
-        frame_offset(frame_offset),
-        total_size(size),
-        lock_level(0) {
-    version = sizeof(native_handle);
-    numInts = sNumInts();
-    numFds = sNumFds;
-  }
-
-  ~private_handle_t() {
-    magic = 0;
-  }
-
-  static int validate(const native_handle* h) {
-    const private_handle_t* hnd = (const private_handle_t*)h;
-    if (!h) {
-      ALOGE("invalid gralloc handle (at %p): NULL pointer", h);
-      return -EINVAL;
-    }
-    if (h->version != sizeof(native_handle)) {
-      ALOGE(
-          "invalid gralloc handle (at %p): Wrong version(observed: %d, "
-          "expected: %zu)",
-          h,
-          h->version,
-          sizeof(native_handle));
-      return -EINVAL;
-    }
-    if (h->numInts != sNumInts()) {
-      ALOGE(
-          "invalid gralloc handle (at %p): Wrong number of ints(observed: %d, "
-          "expected: %d)",
-          h,
-          h->numInts,
-          sNumInts());
-      return -EINVAL;
-    }
-    if (h->numFds != sNumFds) {
-      ALOGE(
-          "invalid gralloc handle (at %p): Wrong number of file "
-          "descriptors(observed: %d, expected: %d)",
-          h,
-          h->numFds,
-          sNumFds);
-      return -EINVAL;
-    }
-    if (hnd->magic != sMagic) {
-      ALOGE(
-          "invalid gralloc handle (at %p): Wrong magic number(observed: %d, "
-          "expected: %d)",
-          h,
-          hnd->magic,
-          sMagic);
-      return -EINVAL;
-    }
-    return 0;
-  }
-};
-
-
-static inline int formatToBytesPerPixel(int format) {
-  switch (format) {
-    case HAL_PIXEL_FORMAT_RGBA_FP16:
-      return 8;
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-    case HAL_PIXEL_FORMAT_BGRA_8888:
-    // The camera 3.0 implementation assumes that IMPLEMENTATION_DEFINED
-    // means HAL_PIXEL_FORMAT_RGBA_8888
-    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-      return 4;
-    case HAL_PIXEL_FORMAT_RGB_888:
-      return 3;
-    case HAL_PIXEL_FORMAT_RGB_565:
-    case HAL_PIXEL_FORMAT_YV12:
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-    case HAL_PIXEL_FORMAT_YCbCr_420_888:
-#endif
-      return 2;
-    case HAL_PIXEL_FORMAT_BLOB:
-      return 1;
-    default:
-      ALOGE("%s: unknown format=%d", __FUNCTION__, format);
-      return 8;
-  }
-}
-
-inline const char* pixel_format_to_string(int format) {
-  switch (format) {
-    // Formats that are universal across versions
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-      return "RGBA_8888";
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-      return "RGBX_8888";
-    case HAL_PIXEL_FORMAT_BGRA_8888:
-      return "BGRA_8888";
-    case HAL_PIXEL_FORMAT_RGB_888:
-      return "RGB_888";
-    case HAL_PIXEL_FORMAT_RGB_565:
-      return "RGB_565";
-    case HAL_PIXEL_FORMAT_YV12:
-      return "YV12";
-    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-      return "YCrCb_420_SP";
-    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-      return "YCbCr_422_SP";
-    case HAL_PIXEL_FORMAT_YCbCr_422_I:
-      return "YCbCr_422_I";
-
-    // First supported on JBMR1 (API 17)
-    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-      return "IMPLEMENTATION_DEFINED";
-    case HAL_PIXEL_FORMAT_BLOB:
-      return "BLOB";
-    // First supported on JBMR2 (API 18)
-    case HAL_PIXEL_FORMAT_YCbCr_420_888:
-      return "YCbCr_420_888";
-    case HAL_PIXEL_FORMAT_Y8:
-      return "Y8";
-    case HAL_PIXEL_FORMAT_Y16:
-      return "Y16";
-    // Support was added in L (API 21)
-    case HAL_PIXEL_FORMAT_RAW_OPAQUE:
-      return "RAW_OPAQUE";
-    // This is an alias for RAW_SENSOR in L and replaces it in M.
-    case HAL_PIXEL_FORMAT_RAW16:
-      return "RAW16";
-    case HAL_PIXEL_FORMAT_RAW10:
-      return "RAW10";
-    case HAL_PIXEL_FORMAT_YCbCr_444_888:
-      return "YCbCr_444_888";
-    case HAL_PIXEL_FORMAT_YCbCr_422_888:
-      return "YCbCr_422_888";
-    case HAL_PIXEL_FORMAT_RAW12:
-      return "RAW12";
-    case HAL_PIXEL_FORMAT_FLEX_RGBA_8888:
-      return "FLEX_RGBA_8888";
-    case HAL_PIXEL_FORMAT_FLEX_RGB_888:
-      return "FLEX_RGB_888";
-    case HAL_PIXEL_FORMAT_RGBA_FP16:
-      return "RGBA_FP16";
-  }
-  return "UNKNOWN";
-}
-
-
-static inline void formatToYcbcr(
-    int format, int width, int height, void* base_v, android_ycbcr* out) {
-  char* it = static_cast<char*>(base_v);
-  // Clear reserved fields;
-  memset(out, 0, sizeof(*out));
-  switch (format) {
-    case HAL_PIXEL_FORMAT_YV12:
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-    case HAL_PIXEL_FORMAT_YCbCr_420_888:
-#endif
-      out->ystride = vsoc::screen::ScreenRegionView::align(width);
-      out->cstride =
-          vsoc::screen::ScreenRegionView::align(out->ystride / 2);
-      out->chroma_step = 1;
-      out->y = it;
-      it += out->ystride * height;
-      out->cr = it;
-      it += out->cstride * height / 2;
-      out->cb = it;
-      break;
-    default:
-      ALOGE("%s: can't deal with format=0x%x (%s)",
-            __FUNCTION__, format, pixel_format_to_string(format));
-  }
-}
-
-static inline int formatToBytesPerFrame(int format, int w, int h) {
-  int bytes_per_pixel = formatToBytesPerPixel(format);
-  int w16, h16;
-  int y_size, c_size;
-
-  switch (format) {
-    // BLOB is used to allocate buffers for JPEG formatted data. Bytes per pixel
-    // is 1, the desired buffer size is in w, and h should be 1. We refrain from
-    // adding additional padding, although the caller is likely to round
-    // up to a page size.
-    case HAL_PIXEL_FORMAT_BLOB:
-      return bytes_per_pixel * w * h;
-    case HAL_PIXEL_FORMAT_YV12:
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-    case HAL_PIXEL_FORMAT_YCbCr_420_888:
-#endif
-      android_ycbcr strides;
-      formatToYcbcr(format, w, h, NULL, &strides);
-      y_size = strides.ystride * h;
-      c_size = strides.cstride * h / 2;
-      return (y_size + 2 * c_size +
-              vsoc::screen::ScreenRegionView::kSwiftShaderPadding);
-    /*case HAL_PIXEL_FORMAT_RGBA_8888:
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-    case HAL_PIXEL_FORMAT_BGRA_8888:
-    case HAL_PIXEL_FORMAT_RGB_888:
-    case HAL_PIXEL_FORMAT_RGB_565:*/
-    default:
-      w16 = vsoc::screen::ScreenRegionView::align(w);
-      h16 = vsoc::screen::ScreenRegionView::align(h);
-      return bytes_per_pixel * w16 * h16 +
-             vsoc::screen::ScreenRegionView::kSwiftShaderPadding;
-  }
-}
-
-int gralloc_lock(
-    gralloc_module_t const* module,
-    buffer_handle_t handle, int usage,
-    int l, int t, int w, int h,
-    void** vaddr);
-
-int gralloc_unlock(
-    gralloc_module_t const* module, buffer_handle_t handle);
-
-int gralloc_register_buffer(
-    gralloc_module_t const* module, buffer_handle_t handle);
-
-int gralloc_unregister_buffer(
-    gralloc_module_t const* module, buffer_handle_t handle);
-
-int gralloc_lock_ycbcr(
-    struct gralloc_module_t const* module,
-    buffer_handle_t handle, int usage,
-    int l, int t, int w, int h,
-    struct android_ycbcr *ycbcr);
-
-int32_t gralloc_get_transport_size(
-    struct gralloc_module_t const* module, buffer_handle_t handle,
-    uint32_t *outNumFds, uint32_t *outNumInts);
-
-int32_t gralloc_validate_buffer_size(
-    struct gralloc_module_t const* device, buffer_handle_t handle,
-    uint32_t w, uint32_t h, int32_t format, int usage,
-    uint32_t stride);
diff --git a/guest/hals/gralloc/legacy/mapper.cpp b/guest/hals/gralloc/legacy/mapper.cpp
deleted file mode 100644
index eb0facc..0000000
--- a/guest/hals/gralloc/legacy/mapper.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-#include <limits.h>
-#include <errno.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <cutils/hashmap.h>
-#include <log/log.h>
-#include <cutils/atomic.h>
-
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-#include <system/graphics.h>
-
-#include "gralloc_vsoc_priv.h"
-#include "region_registry.h"
-
-#define DEBUG_REFERENCES 1
-#define DEBUG_MAX_LOCK_LEVEL 20
-
-/*****************************************************************************/
-
-int gralloc_register_buffer(gralloc_module_t const* /*module*/,
-                            buffer_handle_t handle) {
-  if (private_handle_t::validate(handle) < 0) {
-    return -EINVAL;
-  }
-
-  private_handle_t* hnd = (private_handle_t*)handle;
-  if (reference_region(__FUNCTION__, hnd)) {
-    return 0;
-  } else {
-    return -EIO;
-  }
-}
-
-int gralloc_unregister_buffer(gralloc_module_t const* /*module*/,
-                              buffer_handle_t handle) {
-  if (private_handle_t::validate(handle) < 0) {
-    return -EINVAL;
-  }
-  private_handle_t* hnd = (private_handle_t*)handle;
-  return unreference_region("gralloc_unregister_buffer", hnd);
-}
-
-int gralloc_lock(
-    gralloc_module_t const* /*module*/, buffer_handle_t handle, int /*usage*/,
-    int /*l*/, int /*t*/, int /*w*/, int /*h*/,
-    void** vaddr) {
-  if (private_handle_t::validate(handle) < 0) {
-    return -EINVAL;
-  }
-  if (!vaddr) {
-    return -EINVAL;
-  }
-  private_handle_t* hnd = (private_handle_t*)handle;
-#if DEBUG_REFERENCES
-  if (hnd->lock_level > DEBUG_MAX_LOCK_LEVEL) {
-    LOG_FATAL("%s: unbalanced lock detected. lock level = %d",
-              __FUNCTION__, hnd->lock_level);
-  }
-  ++hnd->lock_level;
-#endif
-  void* base = reference_region("gralloc_lock", hnd);
-  *vaddr = reinterpret_cast<unsigned char*>(base)
-      + hnd->frame_offset;
-  return 0;
-}
-
-int gralloc_unlock(
-    gralloc_module_t const* /*module*/, buffer_handle_t handle) {
-  if (private_handle_t::validate(handle) < 0) {
-    return -EINVAL;
-  }
-  private_handle_t* hnd = (private_handle_t*) handle;
-#if DEBUG_REFERENCES
-  if (hnd->lock_level <= 0) {
-    LOG_FATAL("%s unbalanced unlock detected. lock level = %d",
-              __FUNCTION__, hnd->lock_level);
-  }
-  --hnd->lock_level;
-#endif
-  unreference_region("gralloc_unlock", hnd);
-  return 0;
-}
-
-int gralloc_lock_ycbcr(
-    gralloc_module_t const* /*module*/, buffer_handle_t handle, int /*usage*/,
-    int /*l*/, int /*t*/, int /*w*/, int /*h*/,
-    struct android_ycbcr* ycbcr) {
-  if (private_handle_t::validate(handle) < 0) {
-    return -EINVAL;
-  }
-  private_handle_t* hnd = (private_handle_t*)handle;
-#if DEBUG_REFERENCES
-  if (hnd->lock_level > DEBUG_MAX_LOCK_LEVEL) {
-    LOG_FATAL("%s: unbalanced lock detected. lock level = %d",
-              __FUNCTION__, hnd->lock_level);
-  }
-  ++hnd->lock_level;
-#endif
-  void* base = reference_region("gralloc_lock_ycbcr", hnd);
-  formatToYcbcr(hnd->format, hnd->x_res, hnd->y_res, base, ycbcr);
-  return 0;
-}
-
-int32_t gralloc_get_transport_size(struct gralloc_module_t const* /*module*/,
-                                   buffer_handle_t handle,
-                                   uint32_t *outNumFds,
-                                   uint32_t *outNumInts) {
-  if (private_handle_t::validate(handle) < 0) {
-    return 2; // GRALLOC1_ERROR_BAD_HANDLE
-  }
-  private_handle_t* hnd = (private_handle_t*)handle;
-  *outNumFds = hnd->numFds;
-  *outNumInts = hnd->numInts;
-  return 0;
-}
-
-int32_t gralloc_validate_buffer_size(struct gralloc_module_t const* /*device*/,
-                                     buffer_handle_t handle,
-                                     uint32_t w,
-                                     uint32_t h,
-                                     int32_t format,
-                                     int /*usage*/,
-                                     uint32_t stride) {
-  if (private_handle_t::validate(handle) < 0) {
-    return 2; // GRALLOC1_ERROR_BAD_HANDLE
-  }
-  private_handle_t* hnd = (private_handle_t*)handle;
-  if (format != hnd->format ||
-      w > hnd->x_res ||
-      h > hnd->y_res ||
-      stride > hnd->stride_in_pixels) {
-    return 3; // GRALLOC1_ERROR_BAD_VALUE
-  }
-  return 0;
-}
diff --git a/guest/hals/gralloc/legacy/region_registry.cpp b/guest/hals/gralloc/legacy/region_registry.cpp
deleted file mode 100644
index 9829d46..0000000
--- a/guest/hals/gralloc/legacy/region_registry.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "VSoCGrallocRegionRegistry"
-// Ensure verbose messages appear even on release builds
-#define LOG_NDEBUG 0
-
-#include <limits.h>
-#include <errno.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <cutils/hashmap.h>
-#include <log/log.h>
-#include <cutils/atomic.h>
-
-#include <linux/ashmem.h>
-
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-#include <system/graphics.h>
-
-#include "gralloc_vsoc_priv.h"
-
-#include <deque>
-#include <map>
-#include <mutex>
-
-static const bool g_log_maps = false;
-static const bool g_log_refs = false;
-
-struct GrallocRegion {
-  void* base_;
-  int   num_references_;
-
-  GrallocRegion() : base_(0), num_references_(0) { }
-  // Copy constructors are ok.
-};
-
-
-static const char* get_buffer_name(
-    const private_handle_t* hnd, char output[ASHMEM_NAME_LEN]) {
-  output[0] = '\0';
-  if (!hnd) {
-    ALOGE("Attempted to log gralloc name hnd=NULL");
-    return output;
-  }
-  if (hnd->fd == -1) {
-    ALOGE("Attempted to log gralloc name hnd=%p with fd == -1", hnd);
-    return output;
-  }
-  int rval = ioctl(hnd->fd, ASHMEM_GET_NAME, output);
-  if (rval == -1) {
-    output[0] = '\0';
-  }
-  return output;
-}
-
-
-static int str_hash(void* str) {
-  return hashmapHash(str, strlen(reinterpret_cast<const char*>(str)));
-}
-
-
-static bool str_equal(void* a, void* b) {
-  return strcmp(
-      reinterpret_cast<const char*>(a),
-      reinterpret_cast<const char*>(b)) == 0;
-}
-
-
-static Hashmap* get_regions() {
-  static Hashmap* regionMap = hashmapCreate(19, str_hash, str_equal);
-  return regionMap;
-}
-
-
-static GrallocRegion* lock_region_for_handle(
-    const private_handle_t* hnd, char region_name[ASHMEM_NAME_LEN]) {
-  region_name[0] = '\0';
-  get_buffer_name(hnd, region_name);
-  Hashmap* hash = get_regions();
-  hashmapLock(hash);
-  GrallocRegion* region = reinterpret_cast<GrallocRegion*>(
-      hashmapGet(hash, region_name));
-  if (!region) {
-    region = new GrallocRegion;
-    hashmapPut(hash, strdup(region_name), region);
-  }
-  return region;
-}
-
-
-/* The current implementation uses only a single lock for all regions.
- * This method takes a region to simplfy the refactoring if we go to
- * finer-grained locks.
- */
-static inline void unlock_region(GrallocRegion* ) {
-  hashmapUnlock(get_regions());
-}
-
-
-/*
- * surface_flinger can drop its last reference to a gralloc buffer (from the
- * gralloc HAL's point of view) even though it also has work in flight to the
- * GPU for that target. This causes segfaults in the swiftshader code.
- *
- * We create a compromise solution. On unmap we release the pages by mmaping
- * anonymous memory over the range, but we don't release the address space.
- * Instead we mark the address space for recycling into a new gralloc buffer.
- * This means that the shaders can still write, that the writes won't land in
- * the gralloc buffer, and the gralloc buffer memory can be released.
- *
- * When we're preparing to mmap a new gralloc buffer we see if we can recycle
- * address space from a prior gralloc buffer.
- *
- * The protects the application layer from stray memory writes and pointer
- * references to freed memory. It does mean that bad pixel data can land in
- * a buffer in the case of a fast map-unmap-map sequence. However, that
- * could also happen on a physical GPU.
- *
- * The alternative to this would be to create an elaborate reference counting
- * mechanism below both gralloc and SwiftShader. However, we want to keep the
- * SwiftShader code clean, so that seems undesirable.
- *
- * This problem also comes up for physical GPUs b/62267886. Background fo rthis
- * solution is in b/118777601
- */
-
-static std::map<size_t, std::deque<void*>> g_recycled_addrs;
-std::mutex g_recycled_addrs_mutex;
-
-
-
-static void* recycle_mmap(void *addr, size_t length, int prot, int flags,
-                          int fd, off_t offset) {
-  if (!addr) {
-    std::lock_guard<std::mutex> guard(g_recycled_addrs_mutex);
-    auto it = g_recycled_addrs.find(length);
-    if (it != g_recycled_addrs.end()) {
-      if (it->second.size()) {
-        addr = it->second.front();
-        flags |= MAP_FIXED;
-        it->second.pop_front();
-      }
-    }
-  }
-  return mmap(addr, length, prot, flags, fd, offset);
-}
-
-
-static int recycle_munmap(void *addr, size_t length) {
-  // Do this first so we don't hold the mutex during the syscall
-  if (addr != mmap(addr, length, PROT_READ|PROT_WRITE,
-                   MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0)) {
-    // Be conservative. Don't recycle here.
-    return -1;
-  }
-  std::lock_guard<std::mutex> guard(g_recycled_addrs_mutex);
-  g_recycled_addrs[length].push_back(addr);
-  return 0;
-}
-
-
-void* reference_region(const char* op, const private_handle_t* hnd) {
-  char name_buf[ASHMEM_NAME_LEN];
-  GrallocRegion* region = lock_region_for_handle(hnd, name_buf);
-  if (!region->base_) {
-    void* mappedAddress = recycle_mmap(
-        0, hnd->total_size, PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
-    if (mappedAddress == MAP_FAILED) {
-      ALOGE("Could not mmap %s", strerror(errno));
-      unlock_region(region);
-      return NULL;
-    }
-    // Set up the guard pages. The last page is always a guard
-    uintptr_t base = uintptr_t(mappedAddress);
-    uintptr_t addr = base + hnd->total_size - PAGE_SIZE;
-    if (mprotect((void*)addr, PAGE_SIZE, PROT_NONE) == -1) {
-      ALOGE("mprotect base=%p, pg=%p failed (%s)", (void*)base, (void*)addr,
-            strerror(errno));
-    }
-    region->base_ = mappedAddress;
-    ALOGV_IF(g_log_maps, "Mapped %s hnd=%p fd=%d base=%p format=%s(0x%x) "
-              "width=%d height=%d stride_in_pixels=%d total_size=%d",
-          name_buf, hnd, hnd->fd, region->base_,
-          pixel_format_to_string(hnd->format), hnd->format,
-          hnd->x_res, hnd->y_res, hnd->stride_in_pixels, hnd->total_size);
-  }
-
-  void* rval = region->base_;
-  ++region->num_references_;
-  ALOGV_IF(g_log_refs, "Referencing name=%s op=%s addr=%p new numRefs=%d",
-           name_buf, op, region->base_, region->num_references_);
-  unlock_region(region);
-  return rval;
-}
-
-
-int unreference_region(const char* op, const private_handle_t* hnd) {
-  char name_buf[ASHMEM_NAME_LEN];
-
-  GrallocRegion* region = lock_region_for_handle(hnd, name_buf);
-  if (!region->base_) {
-    ALOGE("Unmapping region with no map hnd=%p", hnd);
-    unlock_region(region);
-    return -1;
-  }
-  if (region->num_references_ < 1) {
-    ALOGE(
-        "unmap with hnd=%p, numReferences=%d", hnd, region->num_references_);
-    unlock_region(region);
-    return -1;
-  }
-  --region->num_references_;
-  if (!region->num_references_) {
-    ALOGV_IF(g_log_maps, "Unmapped %s hnd=%p fd=%d base=%p", name_buf, hnd,
-             hnd->fd, region->base_);
-    if (recycle_munmap(region->base_, hnd->total_size) < 0) {
-      ALOGE("Could not unmap %s", strerror(errno));
-    }
-    region->base_ = 0;
-  }
-  ALOGV_IF(g_log_refs, "Unreferencing name=%s op=%s addr=%p new numRefs=%d",
-           name_buf, op, region->base_, region->num_references_);
-  unlock_region(region);
-  return 0;
-}
diff --git a/guest/hals/gralloc/legacy/region_registry.h b/guest/hals/gralloc/legacy/region_registry.h
deleted file mode 100644
index 210ba9a..0000000
--- a/guest/hals/gralloc/legacy/region_registry.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-struct private_handle_t;
-
-/**
- * Map the memory associated with hnd->fd or, if already mapped, increment
- * its reference count.
- */
-void* reference_region(
-    const char* op, const private_handle_t* hnd);
-
-/**
- * Decrement the reference count associated with hnd->fd, unmapping its
- * memory iff the reference count reaches 0.
- */
-int unreference_region(const char* op, const private_handle_t* hnd);
diff --git a/guest/hals/health/Android.bp b/guest/hals/health/Android.bp
index 3f21425..81d19a3 100644
--- a/guest/hals/health/Android.bp
+++ b/guest/hals/health/Android.bp
@@ -13,6 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library_shared {
     name: "android.hardware.health@2.1-impl-cuttlefish",
     stem: "android.hardware.health@2.0-impl-2.1-cuttlefish",
diff --git a/guest/hals/health/storage/Android.bp b/guest/hals/health/storage/Android.bp
index 74b36ad..dc57d0f 100644
--- a/guest/hals/health/storage/Android.bp
+++ b/guest/hals/health/storage/Android.bp
@@ -14,12 +14,19 @@
  * limitations under the License.
  */
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary {
-    name: "android.hardware.health.storage@1.0-service.cuttlefish",
+    name: "android.hardware.health.storage-service.cuttlefish",
     vendor: true,
     defaults: ["hidl_defaults", "cuttlefish_health_storage"],
     relative_install_path: "hw",
-    init_rc: ["android.hardware.health.storage@1.0-service.cuttlefish.rc"],
+    init_rc: ["android.hardware.health.storage-service.cuttlefish.rc"],
+    vintf_fragments: [
+        "manifest_android.hardware.health.storage.cuttlefish.xml",
+    ],
     srcs: [
         "Storage.cpp",
         "service.cpp",
@@ -31,9 +38,9 @@
     ],
 
     shared_libs: [
-        "android.hardware.health.storage@1.0",
+        "android.hardware.health.storage-V1-ndk_platform",
         "libbase",
-        "libhidlbase",
+        "libbinder_ndk",
         "libutils",
     ],
 }
diff --git a/guest/hals/health/storage/Storage.cpp b/guest/hals/health/storage/Storage.cpp
index 6b7671a..afaf947 100644
--- a/guest/hals/health/storage/Storage.cpp
+++ b/guest/hals/health/storage/Storage.cpp
@@ -18,29 +18,20 @@
 
 #include <android-base/logging.h>
 
-namespace android {
-namespace hardware {
-namespace health {
-namespace storage {
-namespace V1_0 {
-namespace implementation {
+namespace aidl::android::hardware::health::storage {
 
-Return<void> Storage::garbageCollect(uint64_t /*timeoutSeconds*/,
-                                     const sp<IGarbageCollectCallback>& cb) {
-    LOG(INFO) << "IStorage::garbageCollect() is called. Nothing to do.";
-    if (cb != nullptr) {
-        auto ret = cb->onFinish(Result::SUCCESS);
-        if (!ret.isOk()) {
-            LOG(WARNING) << "Cannot return result to callback: " << ret.description();
-        }
+ndk::ScopedAStatus
+Storage::garbageCollect(int64_t /*timeout_seconds*/,
+                        const std::shared_ptr<IGarbageCollectCallback> &cb) {
+  LOG(INFO) << "IStorage::garbageCollect() is called. Nothing to do.";
+  if (cb != nullptr) {
+    auto ret = cb->onFinish(Result::SUCCESS);
+    if (!ret.isOk()) {
+      LOG(WARNING) << "Cannot return result to callback: "
+                   << ret.getDescription();
     }
-    return Void();
+  }
+  return ndk::ScopedAStatus::ok();
 }
 
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace storage
-}  // namespace health
-}  // namespace hardware
-}  // namespace android
+} // namespace aidl::android::hardware::health::storage
diff --git a/guest/hals/health/storage/Storage.h b/guest/hals/health/storage/Storage.h
index 08ff3f2..3949623 100644
--- a/guest/hals/health/storage/Storage.h
+++ b/guest/hals/health/storage/Storage.h
@@ -14,35 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_HEALTH_FILESYSTEM_V1_0_FILESYSTEM_H
-#define ANDROID_HARDWARE_HEALTH_FILESYSTEM_V1_0_FILESYSTEM_H
+#pragma once
 
-#include <android/hardware/health/storage/1.0/IStorage.h>
-#include <hidl/Status.h>
+#include <aidl/android/hardware/health/storage/BnStorage.h>
 
-namespace android {
-namespace hardware {
-namespace health {
-namespace storage {
-namespace V1_0 {
-namespace implementation {
+namespace aidl::android::hardware::health::storage {
 
-using ::android::sp;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-
-struct Storage : public IStorage {
-    Return<void> garbageCollect(uint64_t timeoutSeconds,
-                                const sp<IGarbageCollectCallback>& cb) override;
+class Storage : public BnStorage {
+  ndk::ScopedAStatus
+  garbageCollect(int64_t timeout_seconds,
+                 const std::shared_ptr<IGarbageCollectCallback> &cb) override;
 };
 
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace storage
-}  // namespace health
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_HEALTH_FILESYSTEM_V1_0_FILESYSTEM_H
+} // namespace aidl::android::hardware::health::storage
diff --git a/guest/hals/health/storage/android.hardware.health.storage-service.cuttlefish.rc b/guest/hals/health/storage/android.hardware.health.storage-service.cuttlefish.rc
new file mode 100644
index 0000000..a94d265
--- /dev/null
+++ b/guest/hals/health/storage/android.hardware.health.storage-service.cuttlefish.rc
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2019 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.
+#
+
+service vendor.health-storage-default /vendor/bin/hw/android.hardware.health.storage-service.cuttlefish
+    interface aidl android.hardware.health.storage.IStorage/default
+    oneshot
+    disabled
+    class hal
+    user system
+    group system
diff --git a/guest/hals/health/storage/android.hardware.health.storage@1.0-service.cuttlefish.rc b/guest/hals/health/storage/android.hardware.health.storage@1.0-service.cuttlefish.rc
deleted file mode 100644
index 44eccf3..0000000
--- a/guest/hals/health/storage/android.hardware.health.storage@1.0-service.cuttlefish.rc
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Copyright (C) 2019 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.
-#
-
-service vendor.health-storage-hal-1-0 /vendor/bin/hw/android.hardware.health.storage@1.0-service.cuttlefish
-    interface android.hardware.health.storage@1.0::IStorage default
-    oneshot
-    disabled
-    class hal
-    user system
-    group system
diff --git a/guest/hals/health/storage/manifest_android.hardware.health.storage.cuttlefish.xml b/guest/hals/health/storage/manifest_android.hardware.health.storage.cuttlefish.xml
new file mode 100644
index 0000000..d044e8a
--- /dev/null
+++ b/guest/hals/health/storage/manifest_android.hardware.health.storage.cuttlefish.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.health.storage</name>
+        <version>1</version>
+        <fqname>IStorage/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/health/storage/manifest_android.hardware.health.storage@1.0.cuttlefish.xml b/guest/hals/health/storage/manifest_android.hardware.health.storage@1.0.cuttlefish.xml
deleted file mode 100644
index 62b23e0..0000000
--- a/guest/hals/health/storage/manifest_android.hardware.health.storage@1.0.cuttlefish.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-<manifest version="1.0" type="device">
-    <hal>
-        <name>android.hardware.health.storage</name>
-        <transport>hwbinder</transport>
-        <version>1.0</version>
-        <interface>
-            <name>IStorage</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/guest/hals/health/storage/service.cpp b/guest/hals/health/storage/service.cpp
index 39ff08b..87adf3e 100644
--- a/guest/hals/health/storage/service.cpp
+++ b/guest/hals/health/storage/service.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,31 +14,24 @@
  * limitations under the License.
  */
 
-#include <hidl/HidlLazyUtils.h>
-#include <hidl/HidlTransportSupport.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
 #include "Storage.h"
 
-using android::OK;
-using android::sp;
-using android::status_t;
-using android::UNKNOWN_ERROR;
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::LazyServiceRegistrar;
-using android::hardware::health::storage::V1_0::IStorage;
-using android::hardware::health::storage::V1_0::implementation::Storage;
+using aidl::android::hardware::health::storage::Storage;
+using std::string_literals::operator""s;
 
 int main() {
-    configureRpcThreadpool(1, true);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
 
-    sp<IStorage> service = new Storage();
-    auto serviceRegistrar = LazyServiceRegistrar::getInstance();
-    status_t result = serviceRegistrar.registerService(service);
+    // make a default storage service
+    auto storage = ndk::SharedRefBase::make<Storage>();
+    const std::string name = Storage::descriptor + "/default"s;
+    CHECK_EQ(STATUS_OK, AServiceManager_registerLazyService(
+                            storage->asBinder().get(), name.c_str()));
 
-    if (result != OK) {
-        return result;
-    }
-
-    joinRpcThreadpool();
-    return UNKNOWN_ERROR;
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
 }
diff --git a/guest/hals/hwcomposer/common/Android.bp b/guest/hals/hwcomposer/common/Android.bp
deleted file mode 100644
index fa023f1..0000000
--- a/guest/hals/hwcomposer/common/Android.bp
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2019 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.
-
-
-cc_library_static {
-    name: "hwcomposer_common",
-    defaults: ["cuttlefish_guest_only"],
-    vendor: true,
-    srcs: [
-        "base_composer.cpp",
-        "cpu_composer.cpp",
-        "drm_utils.cpp",
-        "geometry_utils.cpp",
-        "gralloc_utils.cpp",
-        "hwcomposer.cpp",
-        "screen_view.cpp",
-        "stats_keeper.cpp",
-    ],
-    static_libs: [
-        "libyuv_static",
-    ],
-    header_libs: ["libhardware_headers"],
-    shared_libs: [
-        "android.hardware.graphics.mapper@4.0",
-        "libbase",
-        "libcutils",
-        "libcuttlefish_utils",
-        "libcuttlefish_fs",
-        "libdrm",
-        "libgralloctypes",
-        "libhidlbase",
-        "libjpeg",
-        "liblog",
-        "libsync",
-        "libutils",
-    ],
-}
diff --git a/guest/hals/hwcomposer/common/base_composer.cpp b/guest/hals/hwcomposer/common/base_composer.cpp
deleted file mode 100644
index cd3ac65..0000000
--- a/guest/hals/hwcomposer/common/base_composer.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "guest/hals/hwcomposer/common/base_composer.h"
-
-#include <string.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-
-namespace cvd {
-
-BaseComposer::BaseComposer(std::unique_ptr<ScreenView> screen_view)
-    : screen_view_(std::move(screen_view)), gralloc_() {}
-
-void BaseComposer::Dump(char* buff __unused, int buff_len __unused) {}
-
-int BaseComposer::PostFrameBufferTarget(buffer_handle_t buffer_handle) {
-  auto buffer_id = screen_view_->NextBuffer();
-  void* frame_buffer = screen_view_->GetBuffer(buffer_id);
-
-  auto imported_buffer_opt = gralloc_.Import(buffer_handle);
-  if (!imported_buffer_opt) {
-    ALOGE("Failed to Import() framebuffer for post.");
-    return -1;
-  }
-  GrallocBuffer& imported_buffer = *imported_buffer_opt;
-
-  auto buffer_opt = imported_buffer.Lock();
-  if (!buffer_opt) {
-    ALOGE("Failed to Lock() framebuffer for post.");
-    return -1;
-  }
-
-  void* buffer = *buffer_opt;
-  memcpy(frame_buffer, buffer, screen_view_->buffer_size());
-
-  imported_buffer.Unlock();
-
-  screen_view_->Broadcast(buffer_id);
-  return 0;
-}  // namespace cvd
-
-bool BaseComposer::IsValidLayer(const hwc_layer_1_t& layer) {
-  auto buffer_opt = gralloc_.Import(layer.handle);
-  if (!buffer_opt) {
-    ALOGE("Failed to import and validate layer buffer handle.");
-    return false;
-  }
-  GrallocBuffer& buffer = *buffer_opt;
-
-  auto buffer_width_opt = buffer.GetWidth();
-  if (!buffer_width_opt) {
-    ALOGE("Failed to get layer buffer width.");
-    return false;
-  }
-  uint32_t buffer_width = *buffer_width_opt;
-
-  auto buffer_height_opt = buffer.GetHeight();
-  if (!buffer_height_opt) {
-    ALOGE("Failed to get layer buffer height.");
-    return false;
-  }
-  uint32_t buffer_height = *buffer_height_opt;
-
-  if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
-      layer.sourceCrop.right > buffer_width ||
-      layer.sourceCrop.bottom > buffer_height) {
-    ALOGE(
-        "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
-        "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
-        "%d]",
-        __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
-        layer.sourceCrop.top, layer.sourceCrop.bottom, buffer_width,
-        buffer_height);
-    return false;
-  }
-  return true;
-}
-
-int BaseComposer::PrepareLayers(size_t num_layers, hwc_layer_1_t* layers) {
-  // find unsupported overlays
-  for (size_t i = 0; i < num_layers; i++) {
-    if (IS_TARGET_FRAMEBUFFER(layers[i].compositionType)) {
-      continue;
-    }
-    layers[i].compositionType = HWC_FRAMEBUFFER;
-  }
-  return 0;
-}
-
-int BaseComposer::SetLayers(size_t num_layers, hwc_layer_1_t* layers) {
-  for (size_t idx = 0; idx < num_layers; idx++) {
-    if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
-      return PostFrameBufferTarget(layers[idx].handle);
-    }
-  }
-  return -1;
-}
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/base_composer.h b/guest/hals/hwcomposer/common/base_composer.h
deleted file mode 100644
index c1ffbfe..0000000
--- a/guest/hals/hwcomposer/common/base_composer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2016 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 <memory>
-
-#include "guest/hals/hwcomposer/common/gralloc_utils.h"
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-#include "guest/hals/hwcomposer/common/screen_view.h"
-
-namespace cvd {
-
-class BaseComposer {
- public:
-  BaseComposer(std::unique_ptr<ScreenView> screen_view);
-  virtual ~BaseComposer() = default;
-
-  virtual bool IsValidLayer(const hwc_layer_1_t& layer);
-  // Sets the composition type of each layer and returns the number of layers
-  // to be composited by the hwcomposer.
-  virtual int PrepareLayers(size_t num_layers, hwc_layer_1_t* layers);
-  // Returns 0 if successful.
-  virtual int SetLayers(size_t num_layers, hwc_layer_1_t* layers);
-  virtual void Dump(char* buff, int buff_len);
-
-  int32_t x_res() { return screen_view_->x_res(); }
-  int32_t y_res() { return screen_view_->y_res(); }
-  int32_t dpi() { return screen_view_->dpi(); }
-  int32_t refresh_rate() { return screen_view_->refresh_rate(); }
-
- protected:
-  std::unique_ptr<ScreenView> screen_view_;
-  Gralloc gralloc_;
-
- private:
-  // Returns buffer offset or negative on error.
-  int PostFrameBufferTarget(buffer_handle_t handle);
-};
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/cpu_composer.cpp b/guest/hals/hwcomposer/common/cpu_composer.cpp
deleted file mode 100644
index 966aabf..0000000
--- a/guest/hals/hwcomposer/common/cpu_composer.cpp
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "guest/hals/hwcomposer/common/cpu_composer.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <utility>
-#include <vector>
-
-#include <drm_fourcc.h>
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer_defs.h>
-#include <libyuv.h>
-#include <log/log.h>
-
-#include "common/libs/utils/size_utils.h"
-#include "guest/hals/hwcomposer/common/drm_utils.h"
-#include "guest/hals/hwcomposer/common/geometry_utils.h"
-
-namespace cvd {
-
-namespace {
-
-bool LayerNeedsScaling(const hwc_layer_1_t& layer) {
-  int from_w = layer.sourceCrop.right - layer.sourceCrop.left;
-  int from_h = layer.sourceCrop.bottom - layer.sourceCrop.top;
-  int to_w = layer.displayFrame.right - layer.displayFrame.left;
-  int to_h = layer.displayFrame.bottom - layer.displayFrame.top;
-
-  bool not_rot_scale = from_w != to_w || from_h != to_h;
-  bool rot_scale = from_w != to_h || from_h != to_w;
-
-  bool needs_rot = layer.transform & HAL_TRANSFORM_ROT_90;
-
-  return needs_rot ? rot_scale : not_rot_scale;
-}
-
-bool LayerNeedsBlending(const hwc_layer_1_t& layer) {
-  return layer.blending != HWC_BLENDING_NONE;
-}
-
-bool LayerNeedsAttenuation(const hwc_layer_1_t& layer) {
-  return layer.blending == HWC_BLENDING_COVERAGE;
-}
-
-struct BufferSpec;
-typedef int (*ConverterFunction)(const BufferSpec& src, const BufferSpec& dst,
-                                 bool v_flip);
-int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
-int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
-
-ConverterFunction GetConverterForDrmFormat(uint32_t drm_format) {
-  switch (drm_format) {
-    case DRM_FORMAT_ABGR8888:
-    case DRM_FORMAT_XBGR8888:
-      return &DoCopy;
-    case DRM_FORMAT_YVU420:
-      return &ConvertFromYV12;
-  }
-  ALOGW("Unsupported format: %d(%s), returning null converter",
-        drm_format, GetDrmFormatString(drm_format));
-  return nullptr;
-}
-
-bool IsDrmFormatSupported(uint32_t drm_format) {
-  return GetConverterForDrmFormat(drm_format) != nullptr;
-}
-
-/*******************************************************************************
-Libyuv's convert functions only allow the combination of any rotation (multiple
-of 90 degrees) and a vertical flip, but not horizontal flips.
-Surfaceflinger's transformations are expressed in terms of a vertical flip, a
-horizontal flip and/or a single 90 degrees clockwise rotation (see
-NATIVE_WINDOW_TRANSFORM_HINT documentation on system/window.h for more insight).
-The following code allows to turn a horizontal flip into a 180 degrees rotation
-and a vertical flip.
-*******************************************************************************/
-libyuv::RotationMode GetRotationFromTransform(uint32_t transform) {
-  uint32_t rotation =
-      (transform & HAL_TRANSFORM_ROT_90) ? 1 : 0;          // 1 * ROT90 bit
-  rotation += (transform & HAL_TRANSFORM_FLIP_H) ? 2 : 0;  // 2 * VFLIP bit
-  return static_cast<libyuv::RotationMode>(90 * rotation);
-}
-
-bool GetVFlipFromTransform(uint32_t transform) {
-  // vertical flip xor horizontal flip
-  return ((transform & HAL_TRANSFORM_FLIP_V) >> 1) ^
-         (transform & HAL_TRANSFORM_FLIP_H);
-}
-
-struct BufferSpec {
-  uint8_t* buffer;
-  std::optional<android_ycbcr> buffer_ycbcr;
-  int width;
-  int height;
-  int crop_x;
-  int crop_y;
-  int crop_width;
-  int crop_height;
-  uint32_t drm_format;
-  int stride_bytes;
-  int sample_bytes;
-
-  BufferSpec(uint8_t* buffer,
-             std::optional<android_ycbcr> buffer_ycbcr,
-             int width,
-             int height,
-             int crop_x,
-             int crop_y,
-             int crop_width,
-             int crop_height,
-             uint32_t drm_format,
-             int stride_bytes,
-             int sample_bytes)
-      : buffer(buffer),
-        buffer_ycbcr(buffer_ycbcr),
-        width(width),
-        height(height),
-        crop_x(crop_x),
-        crop_y(crop_y),
-        crop_width(crop_width),
-        crop_height(crop_height),
-        drm_format(drm_format),
-        stride_bytes(stride_bytes),
-        sample_bytes(sample_bytes) {}
-
-  BufferSpec(uint8_t* buffer,
-             int width,
-             int height,
-             int stride_bytes)
-      : BufferSpec(buffer,
-                   /*buffer_ycbcr=*/std::nullopt,
-                   width,
-                   height,
-                   /*crop_x=*/0,
-                   /*crop_y=*/0,
-                   /*crop_width=*/width,
-                   /*crop_height=*/height,
-                   /*drm_format=*/DRM_FORMAT_ABGR8888,
-                   stride_bytes,
-                   /*sample_bytes=*/4) {}
-
-};
-
-int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  // The following calculation of plane offsets and alignments are based on
-  // swiftshader's Sampler::setTextureLevel() implementation
-  // (Renderer/Sampler.cpp:225)
-
-  auto& src_buffer_ycbcr_opt = src.buffer_ycbcr;
-  if (!src_buffer_ycbcr_opt) {
-    ALOGE("%s called on non ycbcr buffer", __FUNCTION__);
-    return -1;
-  }
-  auto& src_buffer_ycbcr = *src_buffer_ycbcr_opt;
-
-  // The libyuv::I420ToARGB() function is for tri-planar.
-  if (src_buffer_ycbcr.chroma_step != 1) {
-    ALOGE("%s called with bad chroma step", __FUNCTION__);
-    return -1;
-  }
-
-  uint8_t* src_y = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.y);
-  int stride_y = src_buffer_ycbcr.ystride;
-  uint8_t* src_u = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.cb);
-  int stride_u = src_buffer_ycbcr.cstride;
-  uint8_t* src_v = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.cr);
-  int stride_v = src_buffer_ycbcr.cstride;
-
-  // Adjust for crop
-  src_y += src.crop_y * stride_y + src.crop_x;
-  src_v += (src.crop_y / 2) * stride_v + (src.crop_x / 2);
-  src_u += (src.crop_y / 2) * stride_u + (src.crop_x / 2);
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
-                        dst.crop_x * dst.sample_bytes;
-
-  // YV12 is the same as I420, with the U and V planes swapped
-  return libyuv::I420ToARGB(src_y, stride_y,
-                            src_v, stride_v,
-                            src_u, stride_u,
-                            dst_buffer, dst.stride_bytes,
-                            dst.crop_width,
-                            v_flip ? -dst.crop_height : dst.crop_height);
-}
-
-int DoConversion(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  return (*GetConverterForDrmFormat(src.drm_format))(src, dst, v_flip);
-}
-
-int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  // Point to the upper left corner of the crop rectangle
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
-                        src.crop_x * src.sample_bytes;
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
-                        dst.crop_x * dst.sample_bytes;
-  int width = src.crop_width;
-  int height = src.crop_height;
-
-  if (v_flip) {
-    height = -height;
-  }
-
-  // HAL formats are named based on the order of the pixel componets on the
-  // byte stream, while libyuv formats are named based on the order of those
-  // pixel components in an integer written from left to right. So
-  // libyuv::FOURCC_ARGB is equivalent to HAL_PIXEL_FORMAT_BGRA_8888.
-  auto ret = libyuv::ARGBCopy(src_buffer, src.stride_bytes,
-                              dst_buffer, dst.stride_bytes,
-                              width, height);
-  return ret;
-}
-
-int DoRotation(const BufferSpec& src, const BufferSpec& dst,
-               libyuv::RotationMode rotation, bool v_flip) {
-  // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
-                        src.crop_x * src.sample_bytes;
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
-                        dst.crop_x * dst.sample_bytes;
-  int width = src.crop_width;
-  int height = src.crop_height;
-
-  if (v_flip) {
-    height = -height;
-  }
-
-  return libyuv::ARGBRotate(src_buffer, src.stride_bytes,
-                            dst_buffer, dst.stride_bytes,
-                            width, height, rotation);
-}
-
-int DoScaling(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
-                        src.crop_x * src.sample_bytes;
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
-                        dst.crop_x * dst.sample_bytes;
-  int src_width = src.crop_width;
-  int src_height = src.crop_height;
-  int dst_width = dst.crop_width;
-  int dst_height = dst.crop_height;
-
-  if (v_flip) {
-    src_height = -src_height;
-  }
-
-  return libyuv::ARGBScale(src_buffer, src.stride_bytes, src_width, src_height,
-                           dst_buffer, dst.stride_bytes, dst_width, dst_height,
-                           libyuv::kFilterBilinear);
-}
-
-int DoAttenuation(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
-                        src.crop_x * src.sample_bytes;
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
-                        dst.crop_x * dst.sample_bytes;
-  int width = dst.crop_width;
-  int height = dst.crop_height;
-
-  if (v_flip) {
-    height = -height;
-  }
-
-  return libyuv::ARGBAttenuate(src_buffer, src.stride_bytes,
-                               dst_buffer, dst.stride_bytes,
-                               width, height);
-}
-
-int DoBlending(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
-                        src.crop_x * src.sample_bytes;
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
-                        dst.crop_x * dst.sample_bytes;
-  int width = dst.crop_width;
-  int height = dst.crop_height;
-
-  if (v_flip) {
-    height = -height;
-  }
-
-  // libyuv's ARGB format is hwcomposer's BGRA format, since blending only cares
-  // for the position of alpha in the pixel and not the position of the colors
-  // this function is perfectly usable.
-  return libyuv::ARGBBlend(src_buffer, src.stride_bytes,
-                           dst_buffer, dst.stride_bytes,
-                           dst_buffer, dst.stride_bytes,
-                           width, height);
-}
-
-std::optional<BufferSpec> GetBufferSpec(GrallocBuffer& buffer,
-                                        const hwc_rect_t& buffer_crop) {
-  auto buffer_format_opt = buffer.GetDrmFormat();
-  if (!buffer_format_opt) {
-    ALOGE("Failed to get gralloc buffer format.");
-    return std::nullopt;
-  }
-  uint32_t buffer_format = *buffer_format_opt;
-
-  auto buffer_width_opt = buffer.GetWidth();
-  if (!buffer_width_opt) {
-    ALOGE("Failed to get gralloc buffer width.");
-    return std::nullopt;
-  }
-  uint32_t buffer_width = *buffer_width_opt;
-
-  auto buffer_height_opt = buffer.GetHeight();
-  if (!buffer_height_opt) {
-    ALOGE("Failed to get gralloc buffer height.");
-    return std::nullopt;
-  }
-  uint32_t buffer_height = *buffer_height_opt;
-
-  uint8_t* buffer_data = nullptr;
-  uint32_t buffer_stride_bytes = 0;
-  std::optional<android_ycbcr> buffer_ycbcr_data;
-
-  if (buffer_format == DRM_FORMAT_NV12 ||
-      buffer_format == DRM_FORMAT_NV21 ||
-      buffer_format == DRM_FORMAT_YVU420) {
-    buffer_ycbcr_data = buffer.LockYCbCr();
-    if (!buffer_ycbcr_data) {
-      ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
-      return std::nullopt;
-    }
-  } else {
-    auto buffer_data_opt = buffer.Lock();
-    if (!buffer_data_opt) {
-      ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
-      return std::nullopt;
-    }
-    buffer_data = reinterpret_cast<uint8_t*>(*buffer_data_opt);
-
-    auto buffer_stride_bytes_opt = buffer.GetMonoPlanarStrideBytes();
-    if (!buffer_stride_bytes_opt) {
-      ALOGE("%s failed to get plane stride.", __FUNCTION__);
-      return std::nullopt;
-    }
-    buffer_stride_bytes = *buffer_stride_bytes_opt;
-  }
-
-  return BufferSpec(
-      buffer_data,
-      buffer_ycbcr_data,
-      buffer_width,
-      buffer_height,
-      buffer_crop.left,
-      buffer_crop.top,
-      buffer_crop.right - buffer_crop.left,
-      buffer_crop.bottom - buffer_crop.top,
-      buffer_format,
-      buffer_stride_bytes,
-      GetDrmFormatBytesPerPixel(buffer_format));
-}
-
-}  // namespace
-
-bool CpuComposer::CanCompositeLayer(const hwc_layer_1_t& layer) {
-  buffer_handle_t buffer_handle = layer.handle;
-  if (buffer_handle == nullptr) {
-    ALOGW("%s received a layer with a null handle", __FUNCTION__);
-    return false;
-  }
-
-  auto buffer_opt = gralloc_.Import(buffer_handle);
-  if (!buffer_opt) {
-    ALOGE("Failed to import layer buffer.");
-    return false;
-  }
-  GrallocBuffer& buffer = *buffer_opt;
-
-  auto buffer_format_opt = buffer.GetDrmFormat();
-  if (!buffer_format_opt) {
-    ALOGE("Failed to get layer buffer format.");
-    return false;
-  }
-  uint32_t buffer_format = *buffer_format_opt;
-
-  if (!IsDrmFormatSupported(buffer_format)) {
-    ALOGD("Unsupported pixel format: 0x%x, doing software composition instead",
-          buffer_format);
-    return false;
-  }
-  return true;
-}
-
-void CpuComposer::CompositeLayer(hwc_layer_1_t* src_layer, int buffer_idx) {
-  libyuv::RotationMode rotation =
-      GetRotationFromTransform(src_layer->transform);
-
-  auto src_imported_buffer_opt = gralloc_.Import(src_layer->handle);
-  if (!src_imported_buffer_opt) {
-    ALOGE("Failed to import layer buffer.");
-    return;
-  }
-  GrallocBuffer& src_imported_buffer = *src_imported_buffer_opt;
-
-  auto src_layer_spec_opt = GetBufferSpec(src_imported_buffer, src_layer->sourceCrop);
-  if (!src_layer_spec_opt) {
-    return;
-  }
-  BufferSpec src_layer_spec = *src_layer_spec_opt;
-
-  // TODO(jemoreira): Remove the hardcoded fomat.
-  bool needs_conversion = src_layer_spec.drm_format != DRM_FORMAT_XBGR8888;
-  bool needs_scaling = LayerNeedsScaling(*src_layer);
-  bool needs_rotation = rotation != libyuv::kRotate0;
-  bool needs_transpose = needs_rotation && rotation != libyuv::kRotate180;
-  bool needs_vflip = GetVFlipFromTransform(src_layer->transform);
-  bool needs_attenuation = LayerNeedsAttenuation(*src_layer);
-  bool needs_blending = LayerNeedsBlending(*src_layer);
-  bool needs_copy = !(needs_conversion || needs_scaling || needs_rotation ||
-                      needs_vflip || needs_attenuation || needs_blending);
-
-  uint8_t* dst_buffer =
-    reinterpret_cast<uint8_t*>(screen_view_->GetBuffer(buffer_idx));
-
-  BufferSpec dst_layer_spec(
-      dst_buffer,
-      /*buffer_ycbcr=*/std::nullopt,
-      screen_view_->x_res(),
-      screen_view_->y_res(),
-      src_layer->displayFrame.left,
-      src_layer->displayFrame.top,
-      src_layer->displayFrame.right - src_layer->displayFrame.left,
-      src_layer->displayFrame.bottom - src_layer->displayFrame.top,
-      DRM_FORMAT_XBGR8888,
-      screen_view_->line_length(),
-      4);
-
-  // Add the destination layer to the bottom of the buffer stack
-  std::vector<BufferSpec> dest_buffer_stack(1, dst_layer_spec);
-
-  // If more than operation is to be performed, a temporary buffer is needed for
-  // each additional operation
-
-  // N operations need N destination buffers, the destination layer (the
-  // framebuffer) is one of them, so only N-1 temporary buffers are needed.
-  // Vertical flip is not taken into account because it can be done together
-  // with any other operation.
-  int needed_tmp_buffers = (needs_conversion ? 1 : 0) +
-                           (needs_scaling ? 1 : 0) + (needs_rotation ? 1 : 0) +
-                           (needs_attenuation ? 1 : 0) +
-                           (needs_blending ? 1 : 0) + (needs_copy ? 1 : 0) - 1;
-
-  int tmp_buffer_width =
-      src_layer->displayFrame.right - src_layer->displayFrame.left;
-  int tmp_buffer_height =
-      src_layer->displayFrame.bottom - src_layer->displayFrame.top;
-  int tmp_buffer_stride_bytes =
-      cvd::AlignToPowerOf2(tmp_buffer_width * screen_view_->bytes_per_pixel(), 4);
-
-  for (int i = 0; i < needed_tmp_buffers; i++) {
-    BufferSpec tmp_buffer_spec(
-        RotateTmpBuffer(i),
-        tmp_buffer_width,
-        tmp_buffer_height,
-        tmp_buffer_stride_bytes);
-    dest_buffer_stack.push_back(tmp_buffer_spec);
-  }
-
-  // Conversion and scaling should always be the first operations, so that every
-  // other operation works on equally sized frames (garanteed to fit in the tmp
-  // buffers)
-
-  // TODO(jemoreira): We are converting to ARGB as the first step under the
-  // assumption that scaling ARGB is faster than scaling I420 (the most common).
-  // This should be confirmed with testing.
-  if (needs_conversion) {
-    BufferSpec& dst_buffer_spec = dest_buffer_stack.back();
-    if (needs_scaling || needs_transpose) {
-      // If a rotation or a scaling operation are needed the dimensions at the
-      // top of the buffer stack are wrong (wrong sizes for scaling, swapped
-      // width and height for 90 and 270 rotations).
-      // Make width and height match the crop sizes on the source
-      int src_width = src_layer_spec.crop_width;
-      int src_height = src_layer_spec.crop_height;
-      int dst_stride_bytes =
-          cvd::AlignToPowerOf2(src_width * screen_view_->bytes_per_pixel(), 4);
-      size_t needed_size = dst_stride_bytes * src_height;
-      dst_buffer_spec.width = src_width;
-      dst_buffer_spec.height = src_height;
-      // Adjust the stride accordingly
-      dst_buffer_spec.stride_bytes = dst_stride_bytes;
-      // Crop sizes also need to be adjusted
-      dst_buffer_spec.crop_width = src_width;
-      dst_buffer_spec.crop_height = src_height;
-      // crop_x and y are fine at 0, format is already set to match destination
-
-      // In case of a scale, the source frame may be bigger than the default tmp
-      // buffer size
-      if (needed_size > tmp_buffer_.size() / kNumTmpBufferPieces) {
-        dst_buffer_spec.buffer = GetSpecialTmpBuffer(needed_size);
-      }
-    }
-
-    int retval = DoConversion(src_layer_spec, dst_buffer_spec, needs_vflip);
-    if (retval) {
-      ALOGE("Got error code %d from DoConversion function", retval);
-    }
-    needs_vflip = false;
-    src_layer_spec = dst_buffer_spec;
-    dest_buffer_stack.pop_back();
-  }
-
-  if (needs_scaling) {
-    BufferSpec& dst_buffer_spec = dest_buffer_stack.back();
-    if (needs_transpose) {
-      // If a rotation is needed, the temporary buffer has the correct size but
-      // needs to be transposed and have its stride updated accordingly. The
-      // crop sizes also needs to be transposed, but not the x and y since they
-      // are both zero in a temporary buffer (and it is a temporary buffer
-      // because a rotation will be performed next).
-      std::swap(dst_buffer_spec.width, dst_buffer_spec.height);
-      std::swap(dst_buffer_spec.crop_width, dst_buffer_spec.crop_height);
-      // TODO (jemoreira): Aligment (To align here may cause the needed size to
-      // be bigger than the buffer, so care should be taken)
-      dst_buffer_spec.stride_bytes =
-          dst_buffer_spec.width * screen_view_->bytes_per_pixel();
-    }
-    int retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
-    needs_vflip = false;
-    if (retval) {
-      ALOGE("Got error code %d from DoScaling function", retval);
-    }
-    src_layer_spec = dst_buffer_spec;
-    dest_buffer_stack.pop_back();
-  }
-
-  if (needs_rotation) {
-    int retval = DoRotation(src_layer_spec, dest_buffer_stack.back(), rotation,
-                            needs_vflip);
-    needs_vflip = false;
-    if (retval) {
-      ALOGE("Got error code %d from DoTransform function", retval);
-    }
-    src_layer_spec = dest_buffer_stack.back();
-    dest_buffer_stack.pop_back();
-  }
-
-  if (needs_attenuation) {
-    int retval = DoAttenuation(src_layer_spec, dest_buffer_stack.back(),
-                               needs_vflip);
-    needs_vflip = false;
-    if (retval) {
-      ALOGE("Got error code %d from DoBlending function", retval);
-    }
-    src_layer_spec = dest_buffer_stack.back();
-    dest_buffer_stack.pop_back();
-  }
-
-  if (needs_copy) {
-    int retval = DoCopy(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
-    needs_vflip = false;
-    if (retval) {
-      ALOGE("Got error code %d from DoBlending function", retval);
-    }
-    src_layer_spec = dest_buffer_stack.back();
-    dest_buffer_stack.pop_back();
-  }
-
-  // Blending (if needed) should always be the last operation, so that it reads
-  // and writes in the destination layer and not some temporary buffer.
-  if (needs_blending) {
-    int retval = DoBlending(src_layer_spec, dest_buffer_stack.back(),
-                            needs_vflip);
-    needs_vflip = false;
-    if (retval) {
-      ALOGE("Got error code %d from DoBlending function", retval);
-    }
-    // Don't need to assign destination to source in the last one
-    dest_buffer_stack.pop_back();
-  }
-
-  src_imported_buffer.Unlock();
-}
-
-/* static */ const int CpuComposer::kNumTmpBufferPieces = 2;
-
-CpuComposer::CpuComposer(std::unique_ptr<ScreenView> screen_view)
-    : BaseComposer(std::move(screen_view)),
-      tmp_buffer_(kNumTmpBufferPieces * screen_view_->buffer_size()) {}
-
-int CpuComposer::PrepareLayers(size_t num_layers, hwc_layer_1_t* layers) {
-  int composited_layers_count = 0;
-
-  // Loop over layers in inverse order of z-index
-  for (size_t layer_index = num_layers; layer_index > 0;) {
-    // Decrement here to be able to compare unsigned integer with 0 in the
-    // loop condition
-    --layer_index;
-    if (IS_TARGET_FRAMEBUFFER(layers[layer_index].compositionType)) {
-      continue;
-    }
-    if (layers[layer_index].flags & HWC_SKIP_LAYER) {
-      continue;
-    }
-    if (layers[layer_index].compositionType == HWC_BACKGROUND) {
-      layers[layer_index].compositionType = HWC_FRAMEBUFFER;
-      continue;
-    }
-    layers[layer_index].compositionType = HWC_OVERLAY;
-    // Hwcomposer cannot draw below software-composed layers, so we need
-    // to mark those HWC_FRAMEBUFFER as well.
-    for (size_t top_idx = layer_index + 1; top_idx < num_layers; ++top_idx) {
-      // layers marked as skip are in a state that makes them unreliable to
-      // read, so it's best to assume they cover the whole screen
-      if (layers[top_idx].flags & HWC_SKIP_LAYER ||
-          (layers[top_idx].compositionType == HWC_FRAMEBUFFER &&
-           LayersOverlap(layers[layer_index], layers[top_idx]))) {
-        layers[layer_index].compositionType = HWC_FRAMEBUFFER;
-        break;
-      }
-    }
-    if (layers[layer_index].compositionType == HWC_OVERLAY &&
-        !CanCompositeLayer(layers[layer_index])) {
-      layers[layer_index].compositionType = HWC_FRAMEBUFFER;
-    }
-    if (layers[layer_index].compositionType == HWC_OVERLAY) {
-      ++composited_layers_count;
-    }
-  }
-  return composited_layers_count;
-}
-
-int CpuComposer::SetLayers(size_t num_layers, hwc_layer_1_t* layers) {
-  int targetFbs = 0;
-  int buffer_idx = screen_view_->NextBuffer();
-
-  // The framebuffer target layer should be composed if at least one layers was
-  // marked HWC_FRAMEBUFFER or if it's the only layer in the composition
-  // (unlikely)
-  bool fb_target = true;
-  for (size_t idx = 0; idx < num_layers; idx++) {
-    if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
-      // At least one was found
-      fb_target = true;
-      break;
-    }
-    if (layers[idx].compositionType == HWC_OVERLAY) {
-      // Not the only layer in the composition
-      fb_target = false;
-    }
-  }
-
-  // When the framebuffer target needs to be composed, it has to go first.
-  if (fb_target) {
-    for (size_t idx = 0; idx < num_layers; idx++) {
-      if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
-        CompositeLayer(&layers[idx], buffer_idx);
-        break;
-      }
-    }
-  }
-
-  for (size_t idx = 0; idx < num_layers; idx++) {
-    if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
-      ++targetFbs;
-    }
-    if (layers[idx].compositionType == HWC_OVERLAY &&
-        !(layers[idx].flags & HWC_SKIP_LAYER)) {
-      CompositeLayer(&layers[idx], buffer_idx);
-    }
-  }
-  if (targetFbs != 1) {
-    ALOGW("Saw %zu layers, posted=%d", num_layers, targetFbs);
-  }
-  screen_view_->Broadcast(buffer_idx);
-  return 0;
-}
-
-uint8_t* CpuComposer::RotateTmpBuffer(unsigned int order) {
-  return &tmp_buffer_[(order % kNumTmpBufferPieces) * tmp_buffer_.size() /
-                      kNumTmpBufferPieces];
-}
-
-uint8_t* CpuComposer::GetSpecialTmpBuffer(size_t needed_size) {
-  special_tmp_buffer_.resize(needed_size);
-  return &special_tmp_buffer_[0];
-}
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/cpu_composer.h b/guest/hals/hwcomposer/common/cpu_composer.h
deleted file mode 100644
index f331e2d..0000000
--- a/guest/hals/hwcomposer/common/cpu_composer.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 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 <vector>
-
-#include <hardware/gralloc.h>
-
-#include "guest/hals/hwcomposer/common/base_composer.h"
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-
-namespace cvd {
-
-class CpuComposer : public BaseComposer {
- public:
-  CpuComposer(std::unique_ptr<ScreenView> screen_view);
-  virtual ~CpuComposer() = default;
-
-  // override
-  int PrepareLayers(size_t num_layers, hwc_layer_1_t* layers) override;
-  // override
-  int SetLayers(size_t num_layers, hwc_layer_1_t* layers) override;
-
- protected:
-  static const int kNumTmpBufferPieces;
-  uint8_t* RotateTmpBuffer(unsigned int order);
-  uint8_t* GetSpecialTmpBuffer(size_t needed_size);
-  bool CanCompositeLayer(const hwc_layer_1_t& layer);
-  void CompositeLayer(hwc_layer_1_t* src_layer, int32_t fb_offset);
-  std::vector<uint8_t> tmp_buffer_;
-  std::vector<uint8_t> special_tmp_buffer_;
-};
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/drm_utils.cpp b/guest/hals/hwcomposer/common/drm_utils.cpp
deleted file mode 100644
index d4c864e..0000000
--- a/guest/hals/hwcomposer/common/drm_utils.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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.
- */
-
-#include "guest/hals/hwcomposer/common/drm_utils.h"
-
-#include <drm_fourcc.h>
-#include <log/log.h>
-#include <system/graphics.h>
-
-namespace cvd {
-
-const char* GetDrmFormatString(uint32_t drm_format) {
-  switch (drm_format) {
-    case DRM_FORMAT_ABGR1555:
-      return "DRM_FORMAT_ABGR1555";
-    case DRM_FORMAT_ABGR2101010:
-      return "DRM_FORMAT_ABGR2101010";
-    case DRM_FORMAT_ABGR4444:
-      return "DRM_FORMAT_ABGR4444";
-    case DRM_FORMAT_ABGR8888:
-      return "DRM_FORMAT_ABGR8888";
-    case DRM_FORMAT_ARGB1555:
-      return "DRM_FORMAT_ARGB1555";
-    case DRM_FORMAT_ARGB2101010:
-      return "DRM_FORMAT_ARGB2101010";
-    case DRM_FORMAT_ARGB4444:
-      return "DRM_FORMAT_ARGB4444";
-    case DRM_FORMAT_ARGB8888:
-      return "DRM_FORMAT_ARGB8888";
-    case DRM_FORMAT_AYUV:
-      return "DRM_FORMAT_AYUV";
-    case DRM_FORMAT_BGR233:
-      return "DRM_FORMAT_BGR233";
-    case DRM_FORMAT_BGR565:
-      return "DRM_FORMAT_BGR565";
-    case DRM_FORMAT_BGR888:
-      return "DRM_FORMAT_BGR888";
-    case DRM_FORMAT_BGRA1010102:
-      return "DRM_FORMAT_BGRA1010102";
-    case DRM_FORMAT_BGRA4444:
-      return "DRM_FORMAT_BGRA4444";
-    case DRM_FORMAT_BGRA5551:
-      return "DRM_FORMAT_BGRA5551";
-    case DRM_FORMAT_BGRA8888:
-      return "DRM_FORMAT_BGRA8888";
-    case DRM_FORMAT_BGRX1010102:
-      return "DRM_FORMAT_BGRX1010102";
-    case DRM_FORMAT_BGRX4444:
-      return "DRM_FORMAT_BGRX4444";
-    case DRM_FORMAT_BGRX5551:
-      return "DRM_FORMAT_BGRX5551";
-    case DRM_FORMAT_BGRX8888:
-      return "DRM_FORMAT_BGRX8888";
-    case DRM_FORMAT_C8:
-      return "DRM_FORMAT_C8";
-    case DRM_FORMAT_GR88:
-      return "DRM_FORMAT_GR88";
-    case DRM_FORMAT_NV12:
-      return "DRM_FORMAT_NV12";
-    case DRM_FORMAT_NV21:
-      return "DRM_FORMAT_NV21";
-    case DRM_FORMAT_R8:
-      return "DRM_FORMAT_R8";
-    case DRM_FORMAT_RG88:
-      return "DRM_FORMAT_RG88";
-    case DRM_FORMAT_RGB332:
-      return "DRM_FORMAT_RGB332";
-    case DRM_FORMAT_RGB565:
-      return "DRM_FORMAT_RGB565";
-    case DRM_FORMAT_RGB888:
-      return "DRM_FORMAT_RGB888";
-    case DRM_FORMAT_RGBA1010102:
-      return "DRM_FORMAT_RGBA1010102";
-    case DRM_FORMAT_RGBA4444:
-      return "DRM_FORMAT_RGBA4444";
-    case DRM_FORMAT_RGBA5551:
-      return "DRM_FORMAT_RGBA5551";
-    case DRM_FORMAT_RGBA8888:
-      return "DRM_FORMAT_RGBA8888";
-    case DRM_FORMAT_RGBX1010102:
-      return "DRM_FORMAT_RGBX1010102";
-    case DRM_FORMAT_RGBX4444:
-      return "DRM_FORMAT_RGBX4444";
-    case DRM_FORMAT_RGBX5551:
-      return "DRM_FORMAT_RGBX5551";
-    case DRM_FORMAT_RGBX8888:
-      return "DRM_FORMAT_RGBX8888";
-    case DRM_FORMAT_UYVY:
-      return "DRM_FORMAT_UYVY";
-    case DRM_FORMAT_VYUY:
-      return "DRM_FORMAT_VYUY";
-    case DRM_FORMAT_XBGR1555:
-      return "DRM_FORMAT_XBGR1555";
-    case DRM_FORMAT_XBGR2101010:
-      return "DRM_FORMAT_XBGR2101010";
-    case DRM_FORMAT_XBGR4444:
-      return "DRM_FORMAT_XBGR4444";
-    case DRM_FORMAT_XBGR8888:
-      return "DRM_FORMAT_XBGR8888";
-    case DRM_FORMAT_XRGB1555:
-      return "DRM_FORMAT_XRGB1555";
-    case DRM_FORMAT_XRGB2101010:
-      return "DRM_FORMAT_XRGB2101010";
-    case DRM_FORMAT_XRGB4444:
-      return "DRM_FORMAT_XRGB4444";
-    case DRM_FORMAT_XRGB8888:
-      return "DRM_FORMAT_XRGB8888";
-    case DRM_FORMAT_YUYV:
-      return "DRM_FORMAT_YUYV";
-    case DRM_FORMAT_YVU420:
-      return "DRM_FORMAT_YVU420";
-    case DRM_FORMAT_YVYU:
-      return "DRM_FORMAT_YVYU";
-  }
-  return "Unknown";
-}
-
-int GetDrmFormatBytesPerPixel(uint32_t drm_format) {
-  switch (drm_format) {
-    case DRM_FORMAT_ABGR8888:
-    case DRM_FORMAT_ARGB8888:
-    case DRM_FORMAT_XBGR8888:
-      return 4;
-    case DRM_FORMAT_BGR888:
-      return 3;
-    case DRM_FORMAT_RGB565:
-    case DRM_FORMAT_YVU420:
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-    case DRM_FORMAT_FLEX_YCbCr_420_888:
-#endif
-      return 2;
-    case DRM_FORMAT_R8:
-      return 1;
-  }
-  ALOGE("%s: format size unknown %d(%s)", __FUNCTION__, drm_format,
-        GetDrmFormatString(drm_format));
-  return 8;
-}
-
-int GetDrmFormatFromHalFormat(int hal_format) {
-  switch (hal_format) {
-    case HAL_PIXEL_FORMAT_RGBA_FP16:
-      return DRM_FORMAT_ABGR16161616F;
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-      return DRM_FORMAT_ABGR8888;
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-      return DRM_FORMAT_XBGR8888;
-    case HAL_PIXEL_FORMAT_BGRA_8888:
-      return DRM_FORMAT_ARGB8888;
-    case HAL_PIXEL_FORMAT_RGB_888:
-      return DRM_FORMAT_BGR888;
-    case HAL_PIXEL_FORMAT_RGB_565:
-      return DRM_FORMAT_BGR565;
-    case HAL_PIXEL_FORMAT_YV12:
-      return DRM_FORMAT_YVU420;
-    case HAL_PIXEL_FORMAT_YCbCr_420_888:
-      return DRM_FORMAT_YVU420;
-    case HAL_PIXEL_FORMAT_BLOB:
-      return DRM_FORMAT_R8;
-    default:
-      break;
-  }
-  ALOGE("%s unhandled hal format: %d", __FUNCTION__, hal_format);
-  return 0;
-}
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/drm_utils.h b/guest/hals/hwcomposer/common/drm_utils.h
deleted file mode 100644
index 15f788d..0000000
--- a/guest/hals/hwcomposer/common/drm_utils.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 <cstdlib>
-
-namespace cvd {
-
-const char* GetDrmFormatString(uint32_t drm_format);
-
-int GetDrmFormatBytesPerPixel(uint32_t drm_format);
-
-int GetDrmFormatFromHalFormat(int hal_format);
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/geometry_utils.cpp b/guest/hals/hwcomposer/common/geometry_utils.cpp
deleted file mode 100644
index ade2d78..0000000
--- a/guest/hals/hwcomposer/common/geometry_utils.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "guest/hals/hwcomposer/common/geometry_utils.h"
-
-#include <algorithm>
-#include <utility>
-
-namespace cvd {
-
-bool LayersOverlap(const hwc_layer_1_t& layer1, const hwc_layer_1_t& layer2) {
-  int left1 = layer1.displayFrame.left;
-  int right1 = layer1.displayFrame.right;
-  int top1 = layer1.displayFrame.top;
-  int bottom1 = layer1.displayFrame.bottom;
-
-  int left2 = layer2.displayFrame.left;
-  int right2 = layer2.displayFrame.right;
-  int top2 = layer2.displayFrame.top;
-  int bottom2 = layer2.displayFrame.bottom;
-
-  bool overlap_x = left1 < right2 && left2 < right1;
-  bool overlap_y = top1 < bottom2 && top2 < bottom1;
-
-  return overlap_x && overlap_y;
-}
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/geometry_utils.h b/guest/hals/hwcomposer/common/geometry_utils.h
deleted file mode 100644
index 5563fa7..0000000
--- a/guest/hals/hwcomposer/common/geometry_utils.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-
-namespace cvd {
-
-bool LayersOverlap(const hwc_layer_1_t& layer1, const hwc_layer_1_t& layer2);
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/gralloc_utils.cpp b/guest/hals/hwcomposer/common/gralloc_utils.cpp
deleted file mode 100644
index bb2350f..0000000
--- a/guest/hals/hwcomposer/common/gralloc_utils.cpp
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * 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.
- */
-
-#include "guest/hals/hwcomposer/common/gralloc_utils.h"
-
-#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
-#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
-#include <drm_fourcc.h>
-#include <gralloctypes/Gralloc4.h>
-#include <hidl/ServiceManagement.h>
-#include <log/log.h>
-
-// TODO(b/146515640): remove this.
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-#include "guest/hals/hwcomposer/common/drm_utils.h"
-
-using aidl::android::hardware::graphics::common::PlaneLayout;
-using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
-using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
-using android::hardware::graphics::common::V1_2::BufferUsage;
-using android::hardware::graphics::mapper::V4_0::Error;
-using android::hardware::graphics::mapper::V4_0::IMapper;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_vec;
-using MetadataType =
-  android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
-
-// TODO(b/146515640): remove this.
-using cuttlefish_gralloc0_buffer_handle_t = private_handle_t;
-
-namespace cvd {
-
-Gralloc::Gralloc() {
-  android::hardware::preloadPassthroughService<IMapper>();
-
-  gralloc4_ = IMapper::getService();
-  if (gralloc4_ != nullptr) {
-    ALOGE("%s using Gralloc4.", __FUNCTION__);
-    return;
-  }
-  ALOGE("%s Gralloc4 not available.", __FUNCTION__);
-
-
-  hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                reinterpret_cast<const hw_module_t**>(&gralloc0_));
-  if (gralloc0_ != nullptr) {
-    ALOGE("%s using Gralloc0.", __FUNCTION__);
-    return;
-  }
-  ALOGE("%s Gralloc0 not available.", __FUNCTION__);
-
-  ALOGE("%s No Grallocs available!", __FUNCTION__);
-}
-
-Error Gralloc::GetMetadata(buffer_handle_t buffer, MetadataType type,
-                           hidl_vec<uint8_t>* metadata) {
-  if (gralloc4_ == nullptr) {
-    ALOGE("%s Gralloc4 not available.", __FUNCTION__);
-    return Error::NO_RESOURCES;
-  }
-
-  if (metadata == nullptr) {
-    return Error::BAD_VALUE;
-  }
-
-  Error error = Error::NONE;
-
-  auto native_handle = const_cast<native_handle_t*>(buffer);
-
-  auto ret = gralloc4_->get(native_handle, type,
-                            [&](const auto& get_error, const auto& get_metadata) {
-                              error = get_error;
-                              *metadata = get_metadata;
-                            });
-
-  if (!ret.isOk()) {
-    error = Error::NO_RESOURCES;
-  }
-
-  if (error != Error::NONE) {
-    ALOGE("%s failed to get metadata %s", __FUNCTION__, type.name.c_str());
-  }
-  return error;
-}
-
-std::optional<uint32_t> Gralloc::GetWidth(buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    hidl_vec<uint8_t> encoded_width;
-
-    Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Width,
-                              &encoded_width);
-    if (error != Error::NONE) {
-      return std::nullopt;
-    }
-
-    uint64_t width = 0;
-    android::gralloc4::decodeWidth(encoded_width, &width);
-    return static_cast<uint32_t>(width);
-  }
-  if (gralloc0_ != nullptr) {
-    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
-      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
-
-    return gralloc0_buffer->x_res;
-  }
-  return std::nullopt;
-}
-
-std::optional<uint32_t> Gralloc::GetHeight(buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    hidl_vec<uint8_t> encoded_height;
-
-    Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Height,
-                              &encoded_height);
-    if (error != Error::NONE) {
-      return std::nullopt;
-    }
-
-    uint64_t height = 0;
-    android::gralloc4::decodeHeight(encoded_height, &height);
-    return static_cast<uint32_t>(height);
-  }
-  if (gralloc0_ != nullptr) {
-    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
-      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
-
-    return gralloc0_buffer->y_res;
-  }
-  return std::nullopt;
-}
-
-std::optional<uint32_t> Gralloc::GetDrmFormat(buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    hidl_vec<uint8_t> encoded_format;
-
-    Error error = GetMetadata(buffer,
-                              android::gralloc4::MetadataType_PixelFormatFourCC,
-                              &encoded_format);
-    if (error != Error::NONE) {
-      return std::nullopt;
-    }
-
-    uint32_t format = 0;
-    android::gralloc4::decodePixelFormatFourCC(encoded_format, &format);
-    return static_cast<uint32_t>(format);
-  }
-  if (gralloc0_ != nullptr) {
-    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
-      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
-
-    return GetDrmFormatFromHalFormat(gralloc0_buffer->format);
-  }
-  return std::nullopt;
-}
-
-std::optional<std::vector<PlaneLayout>> Gralloc::GetPlaneLayouts(
-    buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    hidl_vec<uint8_t> encoded_layouts;
-
-    Error error = GetMetadata(buffer,
-                              android::gralloc4::MetadataType_PlaneLayouts,
-                              &encoded_layouts);
-    if (error != Error::NONE) {
-      return std::nullopt;
-    }
-
-    std::vector<PlaneLayout> plane_layouts;
-    android::gralloc4::decodePlaneLayouts(encoded_layouts, &plane_layouts);
-    return plane_layouts;
-  }
-  return std::nullopt;
-}
-
-std::optional<uint32_t> Gralloc::GetMonoPlanarStrideBytes(
-    buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    auto plane_layouts_opt = GetPlaneLayouts(buffer);
-    if (!plane_layouts_opt) {
-      return std::nullopt;
-    }
-
-    std::vector<PlaneLayout>& plane_layouts = *plane_layouts_opt;
-    if (plane_layouts.size() != 1) {
-      return std::nullopt;
-    }
-
-    return static_cast<uint32_t>(plane_layouts[0].strideInBytes);
-  }
-  if (gralloc0_ != nullptr) {
-    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
-      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
-
-    int bytes_per_pixel = formatToBytesPerPixel(gralloc0_buffer->format);
-    return gralloc0_buffer->stride_in_pixels * bytes_per_pixel;
-  }
-  return std::nullopt;
-}
-
-std::optional<GrallocBuffer> Gralloc::Import(buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    buffer_handle_t imported_buffer;
-
-    Error error;
-    auto ret = gralloc4_->importBuffer(buffer,
-                                       [&](const auto& err, const auto& buf) {
-                                         error = err;
-                                         if (err == Error::NONE) {
-                                           imported_buffer =
-                                             static_cast<buffer_handle_t>(buf);
-                                         }
-                                        });
-
-    if (!ret.isOk() || error != Error::NONE) {
-      ALOGE("%s failed to import buffer", __FUNCTION__);
-      return std::nullopt;
-    }
-    return GrallocBuffer(this, imported_buffer);
-  }
-  if (gralloc0_ != nullptr) {
-    return GrallocBuffer(this, buffer);
-  }
-  return std::nullopt;
-}
-
-void Gralloc::Release(buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    auto native_buffer = const_cast<native_handle_t*>(buffer);
-    auto ret = gralloc4_->freeBuffer(native_buffer);
-
-    if (!ret.isOk()) {
-      ALOGE("%s failed to release buffer", __FUNCTION__);
-    }
-    return;
-  }
-  if (gralloc0_) {
-    // no-opt
-  }
-}
-
-std::optional<void*> Gralloc::Lock(buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    auto native_buffer = const_cast<native_handle_t*>(buffer);
-
-    const auto buffer_usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN);
-
-    auto width_opt = GetWidth(buffer);
-    if (!width_opt) {
-      return std::nullopt;
-    }
-
-    auto height_opt = GetHeight(buffer);
-    if (!height_opt) {
-      return std::nullopt;
-    }
-
-    IMapper::Rect buffer_region;
-    buffer_region.left = 0;
-    buffer_region.top = 0;
-    buffer_region.width = *width_opt;
-    buffer_region.height = *height_opt;
-
-    // Empty fence, lock immedietly.
-    hidl_handle fence;
-
-    Error error = Error::NONE;
-    void* data = nullptr;
-
-    auto ret = gralloc4_->lock(native_buffer, buffer_usage, buffer_region,
-                               fence,
-                               [&](const auto& lock_error,
-                                   const auto& lock_data) {
-                                 error = lock_error;
-                                 if (lock_error == Error::NONE) {
-                                  data = lock_data;
-                                }
-                               });
-
-    if (!ret.isOk()) {
-      error = Error::NO_RESOURCES;
-    }
-
-    if (error != Error::NONE) {
-      ALOGE("%s failed to lock buffer", __FUNCTION__);
-      return std::nullopt;
-    }
-
-    return data;
-  }
-  if (gralloc0_ != nullptr) {
-    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
-      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
-
-    void* data = nullptr;
-    int ret = gralloc0_->lock(gralloc0_,
-                              gralloc0_buffer,
-                              GRALLOC_USAGE_SW_READ_OFTEN,
-                              0,
-                              0,
-                              gralloc0_buffer->x_res,
-                              gralloc0_buffer->y_res,
-                              &data);
-
-    if (ret) {
-      ALOGE("%s failed to lock buffer", __FUNCTION__);
-      return std::nullopt;
-    }
-    return data;
-  }
-  return std::nullopt;
-}
-
-std::optional<android_ycbcr> Gralloc::LockYCbCr(buffer_handle_t buffer) {
-  auto format_opt = GetDrmFormat(buffer);
-  if (!format_opt) {
-    ALOGE("%s failed to check format of buffer", __FUNCTION__);
-    return std::nullopt;
-  }
-
-  if (*format_opt != DRM_FORMAT_NV12 &&
-      *format_opt != DRM_FORMAT_NV21 &&
-      *format_opt != DRM_FORMAT_YVU420) {
-    ALOGE("%s called on non-ycbcr buffer", __FUNCTION__);
-    return std::nullopt;
-  }
-
-  if (gralloc4_ != nullptr) {
-    auto lock_opt = Lock(buffer);
-    if (!lock_opt) {
-      ALOGE("%s failed to lock buffer", __FUNCTION__);
-      return std::nullopt;
-    }
-
-    auto plane_layouts_opt = GetPlaneLayouts(buffer);
-    if (!plane_layouts_opt) {
-      ALOGE("%s failed to get plane layouts", __FUNCTION__);
-      return std::nullopt;
-    }
-
-    android_ycbcr buffer_ycbcr;
-    buffer_ycbcr.y = nullptr;
-    buffer_ycbcr.cb = nullptr;
-    buffer_ycbcr.cr = nullptr;
-    buffer_ycbcr.ystride = 0;
-    buffer_ycbcr.cstride = 0;
-    buffer_ycbcr.chroma_step = 0;
-
-    for (const auto& plane_layout : *plane_layouts_opt) {
-      for (const auto& plane_layout_component : plane_layout.components) {
-        const auto& type = plane_layout_component.type;
-
-        if (!android::gralloc4::isStandardPlaneLayoutComponentType(type)) {
-          continue;
-        }
-
-        auto* component_data =
-          reinterpret_cast<uint8_t*>(*lock_opt) +
-          plane_layout.offsetInBytes +
-          plane_layout_component.offsetInBits / 8;
-
-        switch (static_cast<PlaneLayoutComponentType>(type.value)) {
-          case PlaneLayoutComponentType::Y:
-            buffer_ycbcr.y = component_data;
-            buffer_ycbcr.ystride = plane_layout.strideInBytes;
-            break;
-          case PlaneLayoutComponentType::CB:
-            buffer_ycbcr.cb = component_data;
-            buffer_ycbcr.cstride = plane_layout.strideInBytes;
-            buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
-            break;
-          case PlaneLayoutComponentType::CR:
-            buffer_ycbcr.cr = component_data;
-            buffer_ycbcr.cstride = plane_layout.strideInBytes;
-            buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
-            break;
-          default:
-            break;
-        }
-      }
-    }
-
-    return buffer_ycbcr;
-  }
-  if (gralloc0_ != nullptr) {
-    auto lock_opt = Lock(buffer);
-    if (!lock_opt) {
-      ALOGE("%s failed to lock buffer", __FUNCTION__);
-      return std::nullopt;
-    }
-    void* data = *lock_opt;
-
-    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
-      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
-
-    android_ycbcr buffer_ycbcr;
-    formatToYcbcr(gralloc0_buffer->format,
-                  gralloc0_buffer->x_res,
-                  gralloc0_buffer->y_res,
-                  data,
-                  &buffer_ycbcr);
-    return buffer_ycbcr;
-  }
-  return std::nullopt;
-}
-
-void Gralloc::Unlock(buffer_handle_t buffer) {
-  if (gralloc4_ != nullptr) {
-    auto native_handle = const_cast<native_handle_t*>(buffer);
-
-    Error error = Error::NONE;
-    auto ret = gralloc4_->unlock(native_handle,
-                               [&](const auto& unlock_error, const auto&) {
-                                 error = unlock_error;
-                               });
-
-    if (!ret.isOk()) {
-      error = Error::NO_RESOURCES;
-    }
-
-    if (error != Error::NONE) {
-      ALOGE("%s failed to unlock buffer", __FUNCTION__);
-    }
-    return;
-  }
-  if (gralloc0_ != nullptr) {
-    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
-      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
-
-    gralloc0_->unlock(gralloc0_, gralloc0_buffer);
-    return;
-  }
-}
-
-
-GrallocBuffer::GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer) :
-  gralloc_(gralloc), buffer_(buffer) {}
-
-GrallocBuffer::~GrallocBuffer() {  Release(); }
-
-GrallocBuffer::GrallocBuffer(GrallocBuffer&& rhs) {
-  *this = std::move(rhs);
-}
-
-GrallocBuffer& GrallocBuffer::operator=(GrallocBuffer&& rhs) {
-  gralloc_ = rhs.gralloc_;
-  buffer_ = rhs.buffer_;
-  rhs.gralloc_ = nullptr;
-  rhs.buffer_ = nullptr;
-  return *this;
-}
-
-void GrallocBuffer::Release() {
-  if (gralloc_ && buffer_) {
-    gralloc_->Release(buffer_);
-    gralloc_ = nullptr;
-    buffer_ = nullptr;
-  }
-}
-
-std::optional<void*> GrallocBuffer::Lock() {
-  if (gralloc_ && buffer_) {
-    return gralloc_->Lock(buffer_);
-  }
-  return std::nullopt;
-}
-
- std::optional<android_ycbcr> GrallocBuffer::LockYCbCr() {
-  if (gralloc_ && buffer_) {
-    return gralloc_->LockYCbCr(buffer_);
-  }
-  return std::nullopt;
- }
-
-void GrallocBuffer::Unlock() {
-  if (gralloc_ && buffer_) {
-    gralloc_->Unlock(buffer_);
-  }
-}
-
-std::optional<uint32_t> GrallocBuffer::GetWidth() {
-  if (gralloc_ && buffer_) {
-    return gralloc_->GetWidth(buffer_);
-  }
-  return std::nullopt;
-}
-
-std::optional<uint32_t> GrallocBuffer::GetHeight() {
-  if (gralloc_ && buffer_) {
-    return gralloc_->GetHeight(buffer_);
-  }
-  return std::nullopt;
-}
-
-std::optional<uint32_t> GrallocBuffer::GetDrmFormat() {
-  if (gralloc_ && buffer_) {
-    return gralloc_->GetDrmFormat(buffer_);
-  }
-  return std::nullopt;
-}
-
-std::optional<std::vector<PlaneLayout>>
-GrallocBuffer::GetPlaneLayouts() {
-  if (gralloc_ && buffer_) {
-    return gralloc_->GetPlaneLayouts(buffer_);
-  }
-  return std::nullopt;
-}
-
-std::optional<uint32_t> GrallocBuffer::GetMonoPlanarStrideBytes() {
-  if (gralloc_ && buffer_) {
-    return gralloc_->GetMonoPlanarStrideBytes(buffer_);
-  }
-  return std::nullopt;
-}
-
-}  // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/common/gralloc_utils.h b/guest/hals/hwcomposer/common/gralloc_utils.h
deleted file mode 100644
index 370f2bb..0000000
--- a/guest/hals/hwcomposer/common/gralloc_utils.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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 <memory>
-#include <optional>
-#include <vector>
-
-#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
-#include <hardware/gralloc.h>
-#include <system/graphics.h>
-#include <utils/StrongPointer.h>
-
-namespace cvd {
-
-class Gralloc;
-
-// A gralloc 4.0 buffer that has been imported in the current process and
-// that will be released upon destruction. Users must ensure that the Gralloc
-// instance that this buffer is created with out lives this buffer.
-class GrallocBuffer {
- public:
-  GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer);
-  virtual ~GrallocBuffer();
-
-  GrallocBuffer(const GrallocBuffer& rhs) = delete;
-  GrallocBuffer& operator=(const GrallocBuffer& rhs) = delete;
-
-  GrallocBuffer(GrallocBuffer&& rhs);
-  GrallocBuffer& operator=(GrallocBuffer&& rhs);
-
-  // Locks the buffer for reading and returns the mapped address if successful.
-  // Fails and returns nullopt if the underlying buffer is a YCbCr buffer.
-  std::optional<void*> Lock();
-
-  // Locks the buffer for reading and returns the mapped addresses and strides
-  // of each plane if successful. Fails and returns nullopt if the underlying
-  // buffer is not a YCbCr buffer.
-  std::optional<android_ycbcr> LockYCbCr();
-
-  // Unlocks the buffer from reading.
-  void Unlock();
-
-  std::optional<uint32_t> GetWidth();
-  std::optional<uint32_t> GetHeight();
-  std::optional<uint32_t> GetDrmFormat();
-
-  // Returns the stride of the buffer if it is a single plane buffer or fails
-  // and returns nullopt if the buffer is for a multi plane buffer.
-  std::optional<uint32_t> GetMonoPlanarStrideBytes();
-
- private:
-  std::optional<
-    std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
-  GetPlaneLayouts();
-
-  void Release();
-
-  Gralloc* gralloc_ = nullptr;
-  buffer_handle_t buffer_ = nullptr;
-};
-
-class Gralloc {
- public:
-  Gralloc();
-  virtual ~Gralloc() = default;
-
-  // Imports the given buffer handle into the current process and returns an
-  // imported buffer which can be used for reading. Users must ensure that the
-  // Gralloc instance outlives any GrallocBuffers.
-  std::optional<GrallocBuffer> Import(buffer_handle_t buffer);
-
- private:
-  // The below functions are made avaialble only to GrallocBuffer so that
-  // users only call gralloc functions on *imported* buffers.
-  friend class GrallocBuffer;
-
-  // See GrallocBuffer::Release.
-  void Release(buffer_handle_t buffer);
-
-  // See GrallocBuffer::Lock.
-  std::optional<void*> Lock(buffer_handle_t buffer);
-
-  // See GrallocBuffer::LockYCbCr.
-  std::optional<android_ycbcr> LockYCbCr(buffer_handle_t buffer);
-
-  // See GrallocBuffer::Unlock.
-  void Unlock(buffer_handle_t buffer);
-
-  // See GrallocBuffer::GetWidth.
-  std::optional<uint32_t> GetWidth(buffer_handle_t buffer);
-
-  // See GrallocBuffer::GetHeight.
-  std::optional<uint32_t> GetHeight(buffer_handle_t buffer);
-
-  // See GrallocBuffer::GetDrmFormat.
-  std::optional<uint32_t> GetDrmFormat(buffer_handle_t buffer);
-
-  // See GrallocBuffer::GetPlaneLayouts.
-  std::optional<
-    std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
-  GetPlaneLayouts(buffer_handle_t buffer);
-
-  // Returns the stride of the buffer if it is a single plane buffer or fails
-  // and returns nullopt if the buffer is for a multi plane buffer.
-  std::optional<uint32_t> GetMonoPlanarStrideBytes(buffer_handle_t);
-
-  // See GrallocBuffer::GetMetadata.
-  android::hardware::graphics::mapper::V4_0::Error GetMetadata(
-    buffer_handle_t buffer,
-    android::hardware::graphics::mapper::V4_0::IMapper::MetadataType type,
-    android::hardware::hidl_vec<uint8_t>* metadata);
-
-  const gralloc_module_t* gralloc0_ = nullptr;
-
-  android::sp<android::hardware::graphics::mapper::V4_0::IMapper> gralloc4_;
-};
-
-}  // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/common/hwcomposer.cpp b/guest/hals/hwcomposer/common/hwcomposer.cpp
deleted file mode 100644
index 4b51202..0000000
--- a/guest/hals/hwcomposer/common/hwcomposer.cpp
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Versions of hwcomposer we implement:
-// JB: 0.3
-// JB-MR1 to N : 1.1
-// N-MR1 to ... : We report 1.1 but SurfaceFlinger has the option to use an
-// adapter to treat our 1.1 hwcomposer as a 2.0. If SF stops using that adapter
-// to support 1.1 implementations it can be copied into cuttlefish from
-// frameworks/native/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.*
-
-#define LOG_TAG "hwc.cf_x86"
-#define HWC_REMOVE_DEPRECATED_VERSIONS 1
-
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <poll.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sync/sync.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <cutils/compiler.h>
-#include <cutils/properties.h>
-#include <hardware/gralloc.h>
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer_defs.h>
-#include <log/log.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-#include "guest/hals/hwcomposer/common/base_composer.h"
-#include "guest/hals/hwcomposer/common/cpu_composer.h"
-#include "guest/hals/hwcomposer/common/geometry_utils.h"
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-
-#ifdef USE_OLD_HWCOMPOSER
-typedef cvd::BaseComposer ComposerType;
-#else
-typedef cvd::CpuComposer ComposerType;
-#endif
-
-struct hwc_composer_device_data_t {
-  const hwc_procs_t* procs;
-  pthread_t vsync_thread;
-  int64_t vsync_base_timestamp;
-  int32_t vsync_period_ns;
-};
-
-struct cvd_hwc_composer_device_1_t {
-  hwc_composer_device_1_t base;
-  hwc_composer_device_data_t vsync_data;
-  cvd::BaseComposer* composer;
-};
-
-struct external_display_config_t {
-  uint64_t physicalId;
-  uint32_t width;
-  uint32_t height;
-  uint32_t dpi;
-  uint32_t flags;
-};
-
-namespace {
-
-void* hwc_vsync_thread(void* data) {
-  struct hwc_composer_device_data_t* pdev =
-      (struct hwc_composer_device_data_t*)data;
-  setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
-
-  int64_t base_timestamp = pdev->vsync_base_timestamp;
-  int64_t last_logged = base_timestamp / 1e9;
-  int sent = 0;
-  int last_sent = 0;
-  static const int log_interval = 60;
-  void (*vsync_proc)(const struct hwc_procs*, int, int64_t) = nullptr;
-  bool log_no_procs = true, log_no_vsync = true;
-  while (true) {
-    struct timespec rt;
-    if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
-      LOG_ALWAYS_FATAL("%s:%d error in vsync thread clock_gettime: %s",
-                       __FILE__, __LINE__, strerror(errno));
-    }
-
-    int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
-    // Given now's timestamp calculate the time of the next timestamp.
-    timestamp += pdev->vsync_period_ns -
-                 (timestamp - base_timestamp) % pdev->vsync_period_ns;
-
-    rt.tv_sec = timestamp / 1e9;
-    rt.tv_nsec = timestamp % static_cast<int32_t>(1e9);
-    int err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &rt, NULL);
-    if (err == -1) {
-      ALOGE("error in vsync thread: %s", strerror(errno));
-      if (errno == EINTR) {
-        continue;
-      }
-    }
-
-    // The vsync thread is started on device open, it may run before the
-    // registerProcs callback has a chance to be called, so we need to make sure
-    // procs is not NULL before dereferencing it.
-    if (pdev && pdev->procs) {
-      vsync_proc = pdev->procs->vsync;
-    } else if (log_no_procs) {
-      log_no_procs = false;
-      ALOGI("procs is not set yet, unable to deliver vsync event");
-    }
-    if (vsync_proc) {
-      vsync_proc(const_cast<hwc_procs_t*>(pdev->procs), 0, timestamp);
-      ++sent;
-    } else if (log_no_vsync) {
-      log_no_vsync = false;
-      ALOGE("vsync callback is null (but procs was already set)");
-    }
-    if (rt.tv_sec - last_logged > log_interval) {
-      ALOGI("Sent %d syncs in %ds", sent - last_sent, log_interval);
-      last_logged = rt.tv_sec;
-      last_sent = sent;
-    }
-  }
-
-  return NULL;
-}
-
-std::string CompositionString(int type) {
-  switch (type) {
-    case HWC_FRAMEBUFFER:
-      return "Framebuffer";
-    case HWC_OVERLAY:
-      return "Overlay";
-    case HWC_BACKGROUND:
-      return "Background";
-    case HWC_FRAMEBUFFER_TARGET:
-      return "FramebufferTarget";
-    case HWC_SIDEBAND:
-      return "Sideband";
-    case HWC_CURSOR_OVERLAY:
-      return "CursorOverlay";
-    default:
-      return std::string("Unknown (") + std::to_string(type) + ")";
-  }
-}
-
-void LogLayers(int num_layers, hwc_layer_1_t* layers, int invalid) {
-  ALOGE("Layers:");
-  for (int idx = 0; idx < num_layers; ++idx) {
-    std::string log_line;
-    if (idx == invalid) {
-      log_line = "Invalid layer: ";
-    }
-    log_line +=
-        "Composition Type: " + CompositionString(layers[idx].compositionType);
-    ALOGE("%s", log_line.c_str());
-  }
-}
-
-// Ensures that the layer does not include any inconsistencies
-bool IsValidLayer(hwc_composer_device_1_t* dev, const hwc_layer_1_t& layer) {
-  if (layer.flags & HWC_SKIP_LAYER) {
-    // A layer we are asked to skip validate should not be marked as skip
-    ALOGE("%s: Layer is marked as skip", __FUNCTION__);
-    return false;
-  }
-  // Check displayFrame
-  if (layer.displayFrame.left > layer.displayFrame.right ||
-      layer.displayFrame.top > layer.displayFrame.bottom) {
-    ALOGE(
-        "%s: Malformed rectangle (displayFrame): [left = %d, right = %d, top = "
-        "%d, bottom = %d]",
-        __FUNCTION__, layer.displayFrame.left, layer.displayFrame.right,
-        layer.displayFrame.top, layer.displayFrame.bottom);
-    return false;
-  }
-  // Check sourceCrop
-  if (layer.sourceCrop.left > layer.sourceCrop.right ||
-      layer.sourceCrop.top > layer.sourceCrop.bottom) {
-    ALOGE(
-        "%s: Malformed rectangle (sourceCrop): [left = %d, right = %d, top = "
-        "%d, bottom = %d]",
-        __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
-        layer.sourceCrop.top, layer.sourceCrop.bottom);
-    return false;
-  }
-
-  auto* cvd_hwc_dev = reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev);
-  return cvd_hwc_dev->composer->IsValidLayer(layer);
-}
-
-bool IsValidComposition(hwc_composer_device_1_t* dev, int num_layers,
-                        hwc_layer_1_t* layers, bool on_set) {
-  if (num_layers == 0) {
-    ALOGE("Composition requested with 0 layers");
-    return false;
-  }
-  // Sometimes the hwcomposer receives a prepare and set calls with no other
-  // layer than the FRAMEBUFFER_TARGET with a null handler. We treat this case
-  // independently as a valid composition, but issue a warning about it.
-  if (num_layers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET &&
-      layers[0].handle == NULL) {
-    ALOGW("Received request for empty composition, treating as valid noop");
-    return true;
-  }
-  // The FRAMEBUFFER_TARGET layer needs to be sane only if
-  // there is at least one layer marked HWC_FRAMEBUFFER or if there is no layer
-  // marked HWC_OVERLAY (i.e some layers where composed with OpenGL, no layer
-  // marked overlay or framebuffer means that surfaceflinger decided to go for
-  // OpenGL without asking the hwcomposer first)
-  bool check_fb_target = true;
-  for (int idx = 0; idx < num_layers; ++idx) {
-    if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
-      // There is at least one, so it needs to be checked.
-      // It may have been set to false before, so ensure it's set to true.
-      check_fb_target = true;
-      break;
-    }
-    if (layers[idx].compositionType == HWC_OVERLAY) {
-      // At least one overlay, we may not need to.
-      check_fb_target = false;
-    }
-  }
-
-  for (int idx = 0; idx < num_layers; ++idx) {
-    switch (layers[idx].compositionType) {
-      case HWC_FRAMEBUFFER_TARGET:
-        // In the call to prepare() the framebuffer target does not have a valid
-        // buffer_handle, so we don't validate it yet.
-        if (on_set && check_fb_target && !IsValidLayer(dev, layers[idx])) {
-          ALOGE("%s: Invalid layer found", __FUNCTION__);
-          LogLayers(num_layers, layers, idx);
-          return false;
-        }
-        break;
-      case HWC_OVERLAY:
-        if (!(layers[idx].flags & HWC_SKIP_LAYER) &&
-            !IsValidLayer(dev, layers[idx])) {
-          ALOGE("%s: Invalid layer found", __FUNCTION__);
-          LogLayers(num_layers, layers, idx);
-          return false;
-        }
-        break;
-    }
-  }
-  return true;
-}
-
-// Note predefined "hwservicemanager." is used to avoid adding new selinux rules
-#define EXTERANL_DISPLAY_PROP "hwservicemanager.external.displays"
-
-// return 0 for successful
-// return < 0 if failed
-int GetExternalDisplayConfigs(std::vector<struct external_display_config_t>* configs) {
-  // this guest property, hwservicemanager.external.displays,
-  // specifies multi-display info, with comma (,) as separator
-  // each display has the following info:
-  //   physicalId,width,height,dpi,flags
-  // several displays can be provided, e.g., following has 2 displays:
-  // setprop hwservicemanager.external.displays 1,1200,800,120,0,2,1200,800,120,0
-  std::vector<uint64_t> values;
-  char displays_value[PROPERTY_VALUE_MAX] = "";
-  property_get(EXTERANL_DISPLAY_PROP, displays_value, "");
-  bool valid = displays_value[0] != '\0';
-  if (valid) {
-      char *p = displays_value;
-      while (*p) {
-          if (!isdigit(*p) && *p != ',' && *p != ' ') {
-              valid = false;
-              break;
-          }
-          p++;
-      }
-  }
-  if (!valid) {
-      // no external displays are specified
-      ALOGE("%s: Invalid syntax for the value of system prop: %s, value: %s",
-          __FUNCTION__, EXTERANL_DISPLAY_PROP, displays_value);
-      return 0;
-  }
-  // parse all int values to a vector
-  std::istringstream stream(displays_value);
-  for (uint64_t id; stream >> id;) {
-      values.push_back(id);
-      if (stream.peek() == ',')
-          stream.ignore();
-  }
-  // each display has 5 values
-  if ((values.size() % 5) != 0) {
-      ALOGE("%s: Invalid value for system property: %s", __FUNCTION__, EXTERANL_DISPLAY_PROP);
-      return -1;
-  }
-  while (!values.empty()) {
-      struct external_display_config_t config;
-      config.physicalId = values[0];
-      config.width = values[1];
-      config.height = values[2];
-      config.dpi = values[3];
-      config.flags = values[4];
-      values.erase(values.begin(), values.begin() + 5);
-      configs->push_back(config);
-  }
-  return 0;
-}
-
-}  // namespace
-
-static int cvd_hwc_prepare(hwc_composer_device_1_t* dev, size_t numDisplays,
-                           hwc_display_contents_1_t** displays) {
-  if (!numDisplays || !displays) return 0;
-
-  for (int disp = 0; disp < numDisplays; ++disp) {
-    hwc_display_contents_1_t* list = displays[disp];
-
-    if (!list) return 0;
-    if (!IsValidComposition(dev, list->numHwLayers, &list->hwLayers[0], false)) {
-      LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
-      return -1;
-    }
-    reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev)->composer->PrepareLayers(
-      list->numHwLayers, &list->hwLayers[0]);
-  }
-  return 0;
-}
-
-static int cvd_hwc_set(hwc_composer_device_1_t* dev, size_t numDisplays,
-                       hwc_display_contents_1_t** displays) {
-  if (!numDisplays || !displays) return 0;
-
-  int retval = -1;
-  for (int disp = 0; disp < numDisplays; ++disp) {
-    hwc_display_contents_1_t* contents = displays[disp];
-    if (!contents) return 0;
-
-    hwc_layer_1_t* layers = &contents->hwLayers[0];
-    if (contents->numHwLayers == 1 &&
-      layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
-      ALOGW("Received request for empty composition, treating as valid noop");
-      return 0;
-    }
-    if (!IsValidComposition(dev, contents->numHwLayers, layers, true)) {
-      LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
-      return -1;
-    }
-    retval =
-        reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev)->composer->SetLayers(
-            contents->numHwLayers, layers);
-    if (retval != 0) break;
-
-    int closedFds = 0;
-    for (size_t index = 0; index < contents->numHwLayers; ++index) {
-      if (layers[index].acquireFenceFd != -1) {
-        close(layers[index].acquireFenceFd);
-        layers[index].acquireFenceFd = -1;
-        ++closedFds;
-      }
-    }
-    if (closedFds) {
-      ALOGI("Saw %zu layers, closed=%d", contents->numHwLayers, closedFds);
-    }
-
-    // TODO(ghartman): This should be set before returning. On the next set it
-    // should be signalled when we load the new frame.
-    contents->retireFenceFd = -1;
-  }
-
-  return retval;
-}
-
-static void cvd_hwc_register_procs(hwc_composer_device_1_t* dev,
-                                   const hwc_procs_t* procs) {
-  struct cvd_hwc_composer_device_1_t* pdev =
-      (struct cvd_hwc_composer_device_1_t*)dev;
-  pdev->vsync_data.procs = procs;
-  if (procs) {
-      std::vector<struct external_display_config_t> configs;
-      int res = GetExternalDisplayConfigs(&configs);
-      if (res == 0 && !configs.empty()) {
-          // configs will be used in the future
-          procs->hotplug(procs, HWC_DISPLAY_EXTERNAL, 1);
-      }
-  }
-}
-
-static int cvd_hwc_query(hwc_composer_device_1_t* dev, int what, int* value) {
-  struct cvd_hwc_composer_device_1_t* pdev =
-      (struct cvd_hwc_composer_device_1_t*)dev;
-
-  switch (what) {
-    case HWC_BACKGROUND_LAYER_SUPPORTED:
-      // we support the background layer
-      value[0] = 0;
-      break;
-    case HWC_VSYNC_PERIOD:
-      value[0] = pdev->vsync_data.vsync_period_ns;
-      break;
-    default:
-      // unsupported query
-      ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
-      return -EINVAL;
-  }
-  return 0;
-}
-
-static int cvd_hwc_event_control(hwc_composer_device_1_t* /*dev*/, int /*dpy*/,
-                                 int event, int /*enabled*/) {
-  if (event == HWC_EVENT_VSYNC) {
-    return 0;
-  }
-  return -EINVAL;
-}
-
-static int cvd_hwc_blank(hwc_composer_device_1_t* /*dev*/, int disp, int /*blank*/) {
-  if (!IS_PRIMARY_DISPLAY(disp) && !IS_EXTERNAL_DISPLAY(disp)) return -EINVAL;
-  return 0;
-}
-
-static void cvd_hwc_dump(hwc_composer_device_1_t* dev, char* buff, int buff_len) {
-  reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev)->composer->Dump(buff,
-                                                                      buff_len);
-}
-
-static int cvd_hwc_get_display_configs(hwc_composer_device_1_t* /*dev*/, int disp,
-                                       uint32_t* configs, size_t* numConfigs) {
-  if (*numConfigs == 0) return 0;
-
-  if (IS_PRIMARY_DISPLAY(disp) || IS_EXTERNAL_DISPLAY(disp)) {
-    configs[0] = 0;
-    *numConfigs = 1;
-    return 0;
-  }
-
-  return -EINVAL;
-}
-
-static int32_t cvd_hwc_attribute(struct cvd_hwc_composer_device_1_t* pdev,
-                                 const uint32_t attribute) {
-  switch (attribute) {
-    case HWC_DISPLAY_VSYNC_PERIOD:
-      return pdev->vsync_data.vsync_period_ns;
-    case HWC_DISPLAY_WIDTH:
-      return pdev->composer->x_res();
-    case HWC_DISPLAY_HEIGHT:
-      return pdev->composer->y_res();
-    case HWC_DISPLAY_DPI_X:
-      ALOGI("Reporting DPI_X of %d", pdev->composer->dpi());
-      // The number of pixels per thousand inches
-      return pdev->composer->dpi() * 1000;
-    case HWC_DISPLAY_DPI_Y:
-      ALOGI("Reporting DPI_Y of %d", pdev->composer->dpi());
-      // The number of pixels per thousand inches
-      return pdev->composer->dpi() * 1000;
-    default:
-      ALOGE("unknown display attribute %u", attribute);
-      return -EINVAL;
-  }
-}
-
-static int cvd_hwc_get_display_attributes(hwc_composer_device_1_t* dev, int disp,
-                                          uint32_t config __unused,
-                                          const uint32_t* attributes,
-                                          int32_t* values) {
-  struct cvd_hwc_composer_device_1_t* pdev =
-      (struct cvd_hwc_composer_device_1_t*)dev;
-  if (!IS_PRIMARY_DISPLAY(disp) && !IS_EXTERNAL_DISPLAY(disp)) {
-    ALOGE("unknown display type %u", disp);
-    return -EINVAL;
-  }
-
-  for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
-    values[i] = cvd_hwc_attribute(pdev, attributes[i]);
-  }
-
-  return 0;
-}
-
-static int cvd_hwc_close(hw_device_t* device) {
-  struct cvd_hwc_composer_device_1_t* dev =
-      (struct cvd_hwc_composer_device_1_t*)device;
-  ALOGE("cvd_hwc_close");
-  pthread_kill(dev->vsync_data.vsync_thread, SIGTERM);
-  pthread_join(dev->vsync_data.vsync_thread, NULL);
-  delete dev->composer;
-  delete dev;
-  return 0;
-}
-
-namespace cvd {
-
-int cvd_hwc_open(std::unique_ptr<ScreenView> screen_view,
-                 const struct hw_module_t* module, const char* name,
-                 struct hw_device_t** device) {
-  ALOGI("%s", __FUNCTION__);
-  if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
-    ALOGE("%s called with bad name %s", __FUNCTION__, name);
-    return -EINVAL;
-  }
-
-  cvd_hwc_composer_device_1_t* dev = new cvd_hwc_composer_device_1_t();
-  if (!dev) {
-    ALOGE("%s failed to allocate dev", __FUNCTION__);
-    return -ENOMEM;
-  }
-
-  struct timespec rt;
-  if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
-    ALOGE("%s:%d error in vsync thread clock_gettime: %s", __FILE__, __LINE__,
-          strerror(errno));
-  }
-  dev->vsync_data.vsync_base_timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
-  dev->vsync_data.vsync_period_ns = 1e9 / screen_view->refresh_rate();
-
-  dev->base.common.tag = HARDWARE_DEVICE_TAG;
-  dev->base.common.version = HWC_DEVICE_API_VERSION_1_1;
-  dev->base.common.module = const_cast<hw_module_t*>(module);
-  dev->base.common.close = cvd_hwc_close;
-
-  dev->base.prepare = cvd_hwc_prepare;
-  dev->base.set = cvd_hwc_set;
-  dev->base.query = cvd_hwc_query;
-  dev->base.registerProcs = cvd_hwc_register_procs;
-  dev->base.dump = cvd_hwc_dump;
-  dev->base.blank = cvd_hwc_blank;
-  dev->base.eventControl = cvd_hwc_event_control;
-  dev->base.getDisplayConfigs = cvd_hwc_get_display_configs;
-  dev->base.getDisplayAttributes = cvd_hwc_get_display_attributes;
-#ifdef GATHER_STATS
-  dev->composer = new cvd::StatsKeepingComposer<ComposerType>(
-      dev->vsync_data.vsync_base_timestamp, std::move(screen_view));
-#else
-  dev->composer = new ComposerType(std::move(screen_view));
-#endif
-
-  if (!dev->composer) {
-    ALOGE("Failed to instantiate the composer object");
-    delete dev;
-    return -1;
-  }
-  int ret = pthread_create(&dev->vsync_data.vsync_thread, NULL,
-                           hwc_vsync_thread, &dev->vsync_data);
-  if (ret) {
-    ALOGE("failed to start vsync thread: %s", strerror(ret));
-    ret = -ret;
-    delete dev->composer;
-    delete dev;
-  } else {
-    *device = &dev->base.common;
-  }
-
-  return ret;
-}
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/hwcomposer.h b/guest/hals/hwcomposer/common/hwcomposer.h
deleted file mode 100644
index 60a786c..0000000
--- a/guest/hals/hwcomposer/common/hwcomposer.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2019 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 <memory>
-
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer_defs.h>
-
-#include "guest/hals/hwcomposer/common/screen_view.h"
-
-#define IS_TARGET_FRAMEBUFFER(x) ((x) == HWC_FRAMEBUFFER_TARGET)
-#define IS_PRIMARY_DISPLAY(x) ((x) == HWC_DISPLAY_PRIMARY)
-#define IS_EXTERNAL_DISPLAY(x) ((x) == HWC_DISPLAY_EXTERNAL)
-
-namespace cvd {
-int cvd_hwc_open(std::unique_ptr<ScreenView> screen_view,
-                 const struct hw_module_t* module, const char* name,
-                 struct hw_device_t** device);
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/screen_view.cpp b/guest/hals/hwcomposer/common/screen_view.cpp
deleted file mode 100644
index 48f9fa6..0000000
--- a/guest/hals/hwcomposer/common/screen_view.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include "guest/hals/hwcomposer/common/screen_view.h"
-
-#include "common/libs/utils/size_utils.h"
-
-namespace cvd {
-
-int ScreenView::NextBuffer() {
-  int num_buffers = this->num_buffers();
-  last_buffer_ = num_buffers > 0 ? (last_buffer_ + 1) % num_buffers : -1;
-  return last_buffer_;
-}
-
-size_t ScreenView::buffer_size() const {
-  return line_length() * y_res() + 4 /* swiftshader padding */;
-}
-
-size_t ScreenView::line_length() const {
-  return cvd::AlignToPowerOf2(x_res() * bytes_per_pixel(), 4);
-}
-
-int ScreenView::bytes_per_pixel() const { return 4; }
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/screen_view.h b/guest/hals/hwcomposer/common/screen_view.h
deleted file mode 100644
index b985f8f..0000000
--- a/guest/hals/hwcomposer/common/screen_view.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2019 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 <stdint.h>
-#include <sys/time.h>
-
-namespace cvd {
-
-struct CompositionStats {
-  uint32_t num_prepare_calls;
-  uint16_t num_layers;
-  uint16_t num_hwcomposited_layers;
-  timespec last_vsync;
-  timespec prepare_start;
-  timespec prepare_end;
-  timespec set_start;
-  timespec set_end;
-};
-
-class ScreenView {
- public:
-  ScreenView() = default;
-  ScreenView(const ScreenView&) = delete;
-  virtual ~ScreenView() = default;
-
-  ScreenView& operator=(const ScreenView&) = delete;
-
-  virtual void Broadcast(int buffer_id,
-                         const CompositionStats* stats = nullptr) = 0;
-  virtual int NextBuffer();
-  virtual void* GetBuffer(int buffer_id) = 0;
-
-  virtual int32_t x_res() const = 0;
-  virtual int32_t y_res() const = 0;
-  virtual int32_t dpi() const = 0;
-  virtual int32_t refresh_rate() const = 0;
-
-  size_t buffer_size() const;
-  size_t line_length() const;
-  int bytes_per_pixel() const;
-
-  virtual int num_buffers() const = 0;
-
- private:
-  int last_buffer_ = 0;
-};
-}  // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/common/stats_keeper.cpp b/guest/hals/hwcomposer/common/stats_keeper.cpp
deleted file mode 100644
index 9e0d0d2..0000000
--- a/guest/hals/hwcomposer/common/stats_keeper.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "guest/hals/hwcomposer/common/stats_keeper.h"
-
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <algorithm>
-#include <mutex>
-#include <utility>
-#include <vector>
-
-#include <log/log.h>
-
-#include "guest/hals/hwcomposer/common/geometry_utils.h"
-
-using cvd::time::Microseconds;
-using cvd::time::MonotonicTimePoint;
-using cvd::time::Nanoseconds;
-using cvd::time::Seconds;
-using cvd::time::TimeDifference;
-
-namespace cvd {
-
-namespace {
-
-// These functions assume that there is at least one suitable element inside
-// the multiset.
-template <class T>
-void MultisetDeleteOne(std::multiset<T>* mset, const T& key) {
-  mset->erase(mset->find(key));
-}
-template <class T>
-const T& MultisetMin(const std::multiset<T>& mset) {
-  return *mset.begin();
-}
-template <class T>
-const T& MultisetMax(const std::multiset<T>& mset) {
-  return *mset.rbegin();
-}
-
-void TimeDifferenceToTimeSpec(const TimeDifference& td, timespec* ts) {
-  ts->tv_sec = td.seconds();
-  ts->tv_nsec = td.subseconds_in_ns();
-}
-
-}  // namespace
-
-void StatsKeeper::GetLastCompositionStats(CompositionStats* stats_p) {
-  if (stats_p) {
-    TimeDifferenceToTimeSpec(last_composition_stats_.prepare_start.SinceEpoch(),
-                             &stats_p->prepare_start);
-    TimeDifferenceToTimeSpec(last_composition_stats_.prepare_end.SinceEpoch(),
-                             &stats_p->prepare_end);
-    TimeDifferenceToTimeSpec(last_composition_stats_.set_start.SinceEpoch(),
-                             &stats_p->set_start);
-    TimeDifferenceToTimeSpec(last_composition_stats_.set_end.SinceEpoch(),
-                             &stats_p->set_end);
-    TimeDifferenceToTimeSpec(last_composition_stats_.last_vsync.SinceEpoch(),
-                             &stats_p->last_vsync);
-
-    stats_p->num_prepare_calls = last_composition_stats_.num_prepare_calls;
-    stats_p->num_layers = last_composition_stats_.num_layers;
-    stats_p->num_hwcomposited_layers = last_composition_stats_.num_hwc_layers;
-  }
-}
-
-StatsKeeper::StatsKeeper(TimeDifference timespan, int64_t vsync_base,
-                         int32_t vsync_period)
-    : period_length_(timespan, 1),
-      vsync_base_(vsync_base),
-      vsync_period_(vsync_period),
-      num_layers_(0),
-      num_hwcomposited_layers_(0),
-      num_prepare_calls_(0),
-      num_set_calls_(0),
-      prepare_call_total_time_(0),
-      set_call_total_time_(0),
-      total_layers_area(0),
-      total_invisible_area(0) {
-  last_composition_stats_.num_prepare_calls = 0;
-}
-
-StatsKeeper::~StatsKeeper() {}
-
-void StatsKeeper::RecordPrepareStart(int num_layers) {
-  last_composition_stats_.num_layers = num_layers;
-  last_composition_stats_.num_prepare_calls++;
-  num_prepare_calls_++;
-  last_composition_stats_.prepare_start = MonotonicTimePoint::Now();
-  // Calculate the (expected) time of last VSYNC event. We can only make a guess
-  // about it because the vsync thread could run late or surfaceflinger could
-  // run late and call prepare from a previous vsync cycle.
-  int64_t last_vsync =
-      Nanoseconds(last_composition_stats_.set_start.SinceEpoch()).count();
-  last_vsync -= (last_vsync - vsync_base_) % vsync_period_;
-  last_composition_stats_.last_vsync =
-      MonotonicTimePoint() + Nanoseconds(last_vsync);
-}
-
-void StatsKeeper::RecordPrepareEnd(int num_hwcomposited_layers) {
-  last_composition_stats_.prepare_end = MonotonicTimePoint::Now();
-  last_composition_stats_.num_hwc_layers = num_hwcomposited_layers;
-}
-
-void StatsKeeper::RecordSetStart() {
-  last_composition_stats_.set_start = MonotonicTimePoint::Now();
-}
-
-void StatsKeeper::RecordSetEnd() {
-  last_composition_stats_.set_end = MonotonicTimePoint::Now();
-  std::lock_guard lock(mutex_);
-  num_set_calls_++;
-  while (!raw_composition_data_.empty() &&
-         period_length_ < last_composition_stats_.set_end -
-                              raw_composition_data_.front().time_point()) {
-    const CompositionData& front = raw_composition_data_.front();
-
-    num_prepare_calls_ -= front.num_prepare_calls();
-    --num_set_calls_;
-    num_layers_ -= front.num_layers();
-    num_hwcomposited_layers_ -= front.num_hwcomposited_layers();
-    prepare_call_total_time_ =
-        Nanoseconds(prepare_call_total_time_ - front.prepare_time());
-    set_call_total_time_ =
-        Nanoseconds(set_call_total_time_ - front.set_calls_time());
-
-    MultisetDeleteOne(&prepare_calls_per_set_calls_, front.num_prepare_calls());
-    MultisetDeleteOne(&layers_per_compositions_, front.num_layers());
-    MultisetDeleteOne(&prepare_call_times_, front.prepare_time());
-    MultisetDeleteOne(&set_call_times_, front.set_calls_time());
-    if (front.num_hwcomposited_layers() != 0) {
-      MultisetDeleteOne(
-          &set_call_times_per_hwcomposited_layer_ns_,
-          front.set_calls_time().count() / front.num_hwcomposited_layers());
-    }
-
-    raw_composition_data_.pop_front();
-  }
-  Nanoseconds last_prepare_call_time_(last_composition_stats_.prepare_end -
-                                      last_composition_stats_.prepare_start);
-  Nanoseconds last_set_call_total_time_(last_composition_stats_.set_end -
-                                        last_composition_stats_.set_start);
-  raw_composition_data_.push_back(
-      CompositionData(last_composition_stats_.set_end,
-                      last_composition_stats_.num_prepare_calls,
-                      last_composition_stats_.num_layers,
-                      last_composition_stats_.num_hwc_layers,
-                      last_prepare_call_time_, last_set_call_total_time_));
-
-  // There may be several calls to prepare before a call to set, but the only
-  // valid call is the last one, so we need to compute these here:
-  num_layers_ += last_composition_stats_.num_layers;
-  num_hwcomposited_layers_ += last_composition_stats_.num_hwc_layers;
-  prepare_call_total_time_ =
-      Nanoseconds(prepare_call_total_time_ + last_prepare_call_time_);
-  set_call_total_time_ =
-      Nanoseconds(set_call_total_time_ + last_set_call_total_time_);
-  prepare_calls_per_set_calls_.insert(
-      last_composition_stats_.num_prepare_calls);
-  layers_per_compositions_.insert(last_composition_stats_.num_layers);
-  prepare_call_times_.insert(last_prepare_call_time_);
-  set_call_times_.insert(last_set_call_total_time_);
-  if (last_composition_stats_.num_hwc_layers != 0) {
-    set_call_times_per_hwcomposited_layer_ns_.insert(
-        last_set_call_total_time_.count() /
-        last_composition_stats_.num_hwc_layers);
-  }
-
-  // Reset the counter
-  last_composition_stats_.num_prepare_calls = 0;
-}
-
-void StatsKeeper::SynchronizedDump(char* buffer, int buffer_size) const {
-  std::lock_guard lock(mutex_);
-  int chars_written = 0;
-// Make sure there is enough space to write the next line
-#define bprintf(...)                                                           \
-  (chars_written += (chars_written < buffer_size)                              \
-                        ? (snprintf(&buffer[chars_written],                    \
-                                    buffer_size - chars_written, __VA_ARGS__)) \
-                        : 0)
-
-  bprintf("HWComposer stats from the %" PRId64
-          " seconds just before the last call to "
-          "set() (which happended %" PRId64 " seconds ago):\n",
-          Seconds(period_length_).count(),
-          Seconds(MonotonicTimePoint::Now() - last_composition_stats_.set_end)
-              .count());
-  bprintf("  Layer count: %d\n", num_layers_);
-
-  if (num_layers_ == 0 || num_prepare_calls_ == 0 || num_set_calls_ == 0) {
-    return;
-  }
-
-  bprintf("  Layers composited by hwcomposer: %d (%d%%)\n",
-          num_hwcomposited_layers_,
-          100 * num_hwcomposited_layers_ / num_layers_);
-  bprintf("  Number of calls to prepare(): %d\n", num_prepare_calls_);
-  bprintf("  Number of calls to set(): %d\n", num_set_calls_);
-  if (num_set_calls_ > 0) {
-    bprintf(
-        "  Maximum number of calls to prepare() before a single call to set(): "
-        "%d\n",
-        MultisetMax(prepare_calls_per_set_calls_));
-  }
-  bprintf("  Time spent on prepare() (in microseconds):\n    max: %" PRId64
-          "\n    "
-          "average: %" PRId64 "\n    min: %" PRId64 "\n    total: %" PRId64
-          "\n",
-          Microseconds(MultisetMax(prepare_call_times_)).count(),
-          Microseconds(prepare_call_total_time_).count() / num_prepare_calls_,
-          Microseconds(MultisetMin(prepare_call_times_)).count(),
-          Microseconds(prepare_call_total_time_).count());
-  bprintf("  Time spent on set() (in microseconds):\n    max: %" PRId64
-          "\n    average: "
-          "%" PRId64 "\n    min: %" PRId64 "\n    total: %" PRId64 "\n",
-          Microseconds(MultisetMax(set_call_times_)).count(),
-          Microseconds(set_call_total_time_).count() / num_set_calls_,
-          Microseconds(MultisetMin(set_call_times_)).count(),
-          Microseconds(set_call_total_time_).count());
-  if (num_hwcomposited_layers_ > 0) {
-    bprintf(
-        "  Per layer compostition time:\n    max: %" PRId64
-        "\n    average: %" PRId64
-        "\n    "
-        "min: %" PRId64 "\n",
-        Microseconds(MultisetMax(set_call_times_per_hwcomposited_layer_ns_))
-            .count(),
-        Microseconds(set_call_total_time_).count() / num_hwcomposited_layers_,
-        Microseconds(MultisetMin(set_call_times_per_hwcomposited_layer_ns_))
-            .count());
-  }
-  bprintf("Statistics from last 100 compositions:\n");
-  bprintf("  Total area: %" PRId64 " square pixels\n", total_layers_area);
-  if (total_layers_area != 0) {
-    bprintf(
-        "  Total invisible area: %" PRId64 " square pixels, %" PRId64 "%%\n",
-        total_invisible_area, 100 * total_invisible_area / total_layers_area);
-  }
-#undef bprintf
-}
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/stats_keeper.h b/guest/hals/hwcomposer/common/stats_keeper.h
deleted file mode 100644
index 3a123f7..0000000
--- a/guest/hals/hwcomposer/common/stats_keeper.h
+++ /dev/null
@@ -1,224 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <deque>
-#include <mutex>
-#include <set>
-
-#include <android-base/thread_annotations.h>
-
-#include "common/libs/time/monotonic_time.h"
-
-#include "guest/hals/hwcomposer/common/base_composer.h"
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-
-namespace cvd {
-
-class CompositionData {
- public:
-  CompositionData(cvd::time::MonotonicTimePoint time_point, int num_prepares,
-                  int num_layers, int num_hwcomposited_layers,
-                  cvd::time::Nanoseconds prepare_time,
-                  cvd::time::Nanoseconds set_calls_time)
-      : time_point_(time_point),
-        num_prepare_calls_(num_prepares),
-        num_layers_(num_layers),
-        num_hwcomposited_layers_(num_hwcomposited_layers),
-        prepare_time_(prepare_time),
-        set_calls_time_(set_calls_time) {}
-
-  cvd::time::MonotonicTimePoint time_point() const { return time_point_; }
-
-  int num_prepare_calls() const { return num_prepare_calls_; }
-
-  int num_layers() const { return num_layers_; }
-
-  int num_hwcomposited_layers() const { return num_hwcomposited_layers_; }
-
-  cvd::time::Nanoseconds prepare_time() const { return prepare_time_; }
-
-  cvd::time::Nanoseconds set_calls_time() const { return set_calls_time_; }
-
- private:
-  cvd::time::MonotonicTimePoint time_point_;
-  int num_prepare_calls_;
-  int num_layers_;
-  int num_hwcomposited_layers_;
-  cvd::time::Nanoseconds prepare_time_;
-  cvd::time::Nanoseconds set_calls_time_;
-};
-
-struct HWCCompositionStats {
-  cvd::time::MonotonicTimePoint prepare_start;
-  cvd::time::MonotonicTimePoint prepare_end;
-  cvd::time::MonotonicTimePoint set_start;
-  cvd::time::MonotonicTimePoint set_end;
-  cvd::time::MonotonicTimePoint last_vsync;
-  // There may be more than one call to prepare, the timestamps are with regards
-  // to the last one (the one that precedes the set call)
-  int num_prepare_calls;
-  int num_layers;
-  // The number of layers composed by the hwcomposer
-  int num_hwc_layers;
-};
-
-class StatsKeeper {
- public:
-  // The timespan parameter indicates for how long we keep stats about the past
-  // compositions.
-  StatsKeeper(cvd::time::TimeDifference timespan, int64_t vsync_base,
-              int32_t vsync_period);
-  StatsKeeper();
-  ~StatsKeeper();
-
-  // Record the time at which a call to prepare was made, takes the number of
-  // layers received (excluding the framebuffer) as a parameter.
-  void RecordPrepareStart(int num_layers);
-  // Record the time at which a call to prepare (was about to) returned, takes
-  // the number of layers marked for hardware composition as a parameter.
-  void RecordPrepareEnd(int num_hwcomposited_layers);
-  void RecordSetStart();
-  void RecordSetEnd() EXCLUDES(mutex_);
-
-  void GetLastCompositionStats(CompositionStats* stats_p);
-
-  // Calls to this function are synchronized with calls to 'RecordSetEnd' with a
-  // mutex. The other Record* functions do not need such synchronization because
-  // they access last_* variables only, which are not read by 'Dump'.
-  void SynchronizedDump(char* buffer, int buffer_size) const EXCLUDES(mutex_);
-
- private:
-  cvd::time::TimeDifference period_length_;
-
-  // Base and period of the VSYNC signal, allows to accurately calculate the
-  // time of the last vsync broadcast.
-  int64_t vsync_base_;
-  int32_t vsync_period_;
-  // Data collected about ongoing composition. These variables are not accessed
-  // from Dump(), so they don't need to be guarded by a mutex.
-  HWCCompositionStats last_composition_stats_;
-
-  // Aggregated performance data collected from past compositions. These
-  // variables are modified when a composition is completed and when old
-  // compositions need to be discarded in RecordSetEnd(), and is accessed from
-  // Dump(). Non-aggregated data is kept in the raw_composition_data_ deque to
-  // be able to discard old values from the aggregated data.
-  int num_layers_ GUARDED_BY(mutex_);
-  int num_hwcomposited_layers_ GUARDED_BY(mutex_);
-  int num_prepare_calls_ GUARDED_BY(mutex_);
-  int num_set_calls_ GUARDED_BY(mutex_);
-  cvd::time::Nanoseconds prepare_call_total_time_ GUARDED_BY(mutex_);
-  cvd::time::Nanoseconds set_call_total_time_ GUARDED_BY(mutex_);
-  // These are kept in multisets to be able to calculate mins and maxs of
-  // changing sets of (not necessarily different) values.
-  std::multiset<int> prepare_calls_per_set_calls_ GUARDED_BY(mutex_);
-  std::multiset<int> layers_per_compositions_ GUARDED_BY(mutex_);
-  std::multiset<cvd::time::Nanoseconds> prepare_call_times_ GUARDED_BY(mutex_);
-  std::multiset<cvd::time::Nanoseconds> set_call_times_ GUARDED_BY(mutex_);
-  std::multiset<int64_t> set_call_times_per_hwcomposited_layer_ns_
-      GUARDED_BY(mutex_);
-
-  // Time-ordered list of compositions, used to update the global aggregated
-  // performance data when old compositions fall out of the period of interest.
-  std::deque<CompositionData> raw_composition_data_ GUARDED_BY(mutex_);
-
-  // TODO(jemoreira): Add min/max/average composition times per layer area units
-
-  std::deque<std::pair<int64_t, int64_t> > composition_areas GUARDED_BY(mutex_);
-  int64_t total_layers_area GUARDED_BY(mutex_);
-  int64_t total_invisible_area GUARDED_BY(mutex_);
-
-  // Controls access to data from past compositions.
-  mutable std::mutex mutex_;
-};
-
-class WrappedScreenView : public ScreenView {
- public:
-  WrappedScreenView(std::unique_ptr<ScreenView> screen_view,
-                    std::function<void(CompositionStats*)> stats_getter)
-      : screen_view_(std::move(screen_view)), stats_getter_(stats_getter) {}
-  virtual ~WrappedScreenView() = default;
-
-  void Broadcast(int buffer_id, const CompositionStats*) override {
-    // The composer object in stats_keeper produces null stats, use the ones
-    // provided by the stats_keeper instead.
-    CompositionStats stats;
-    stats_getter_(&stats);
-    return screen_view_->Broadcast(buffer_id, &stats);
-  }
-
-  void* GetBuffer(int buffer_id) override {
-    return screen_view_->GetBuffer(buffer_id);
-  }
-
-  int32_t x_res() const override { return screen_view_->x_res(); }
-
-  int32_t y_res() const override { return screen_view_->y_res(); }
-
-  int32_t dpi() const override { return screen_view_->dpi(); }
-
-  int32_t refresh_rate() const override { return screen_view_->refresh_rate(); }
-
-  int num_buffers() const override { return screen_view_->num_buffers(); }
-
- private:
-  std::unique_ptr<ScreenView> screen_view_;
-  std::function<void(CompositionStats*)> stats_getter_;
-};
-
-template <class Composer>
-class StatsKeepingComposer : public BaseComposer {
- public:
-  // Keep stats from the last 10 seconds.
-  StatsKeepingComposer(int64_t vsync_base_timestamp,
-                       std::unique_ptr<ScreenView> screen_view)
-      : composer_(std::unique_ptr<ScreenView>(
-                      new WrappedScreenView(std::move(screen_view),
-                                            [this](CompositionStats* stats) {
-                                              FinalizeStatsAndGet(stats);
-                                            }))),
-        stats_keeper_(cvd::time::TimeDifference(cvd::time::Seconds(10), 1),
-                      vsync_base_timestamp, 1e9 / composer_.refresh_rate()) {}
-  virtual ~StatsKeepingComposer() = default;
-
-  int PrepareLayers(size_t num_layers, hwc_layer_1_t* layers) override {
-    stats_keeper_.RecordPrepareStart(num_layers);
-    int num_hwc_layers = composer_.PrepareLayers(num_layers, layers);
-    stats_keeper_.RecordPrepareEnd(num_hwc_layers);
-    return num_hwc_layers;
-  }
-
-  int SetLayers(size_t num_layers, hwc_layer_1_t* layers) override {
-    stats_keeper_.RecordSetStart();
-    return composer_.SetLayers(num_layers, layers);
-  }
-
-  void Dump(char* buff, int buff_len) override {
-    stats_keeper_.SynchronizedDump(buff, buff_len);
-  }
-
-  void FinalizeStatsAndGet(CompositionStats* stats) {
-    stats_keeper_.RecordSetEnd();
-    stats_keeper_.GetLastCompositionStats(stats);
-  }
-
- private:
-  Composer composer_;
-  StatsKeeper stats_keeper_;
-};
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/Android.bp b/guest/hals/hwcomposer/cutf_cvm/Android.bp
deleted file mode 100644
index d622077..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/Android.bp
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (C) 2019 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.
-
-
-cc_library_shared {
-    name: "hwcomposer.cutf_cvm_ashmem",
-    relative_install_path: "hw",
-    defaults: ["cuttlefish_guest_only"],
-    vendor: true,
-    srcs: [
-        "hwcomposer.cpp",
-        "vsocket_screen_view.cpp",
-    ],
-    include_dirs: [
-        "device/google/cuttlefish",
-    ],
-    export_include_dirs: ["."],
-    static_libs: [
-        "hwcomposer_common",
-        "libyuv_static",
-    ],
-    shared_libs: [
-        "android.hardware.graphics.mapper@4.0",
-        "libbase",
-        "libcutils",
-        "libcuttlefish_device_config",
-        "libcuttlefish_utils",
-        "libcuttlefish_fs",
-        "libdrm",
-        "libgralloctypes",
-        "libhardware",
-        "libhidlbase",
-        "libjpeg",
-        "liblog",
-        "libsync",
-        "libutils",
-    ],
-}
-
-cc_library_shared {
-    name: "hwcomposer.cutf_hwc2",
-    relative_install_path: "hw",
-    defaults: ["cuttlefish_guest_only"],
-    vendor: true,
-
-    clang: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    cppflags: [
-        "-Wextra",
-        "-Wunused",
-        "-Wunreachable-code",
-
-        // Disabling warning specific to hwc2on1adapter code
-        "-Wno-sign-compare",
-    ],
-
-    srcs: [
-        "HWC2.cpp",
-        "MiniFence.cpp",
-        "vsocket_screen_view.cpp",
-    ],
-
-    include_dirs: [
-        "device/google/cuttlefish",
-    ],
-
-    export_include_dirs: ["."],
-
-    static_libs: [
-        "hwcomposer_common",
-        "libyuv_static",
-    ],
-
-    shared_libs: [
-        "android.hardware.graphics.mapper@4.0",
-        "libcutils",
-        "libcuttlefish_device_config",
-        "libcuttlefish_utils",
-        "libcuttlefish_fs",
-        "libgralloctypes",
-        "libhardware",
-        "libhidlbase",
-        "liblog",
-        "libutils",
-    ],
-}
diff --git a/guest/hals/hwcomposer/cutf_cvm/HWC2.cpp b/guest/hals/hwcomposer/cutf_cvm/HWC2.cpp
deleted file mode 100644
index e366b2f..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/HWC2.cpp
+++ /dev/null
@@ -1,2845 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-#include "HWC2.h"
-
-//#define LOG_NDEBUG 0
-
-#undef LOG_TAG
-#define LOG_TAG "CfHWC2"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <inttypes.h>
-
-#include <chrono>
-#include <cstdlib>
-#include <sstream>
-
-#include <hardware/hwcomposer.h>
-#include <log/log.h>
-#include <utils/Trace.h>
-
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-#include "guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h"
-
-using namespace std::chrono_literals;
-
-static uint8_t getMinorVersion(struct hwc_composer_device_1* device)
-{
-    auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
-    return (version >> 16) & 0xF;
-}
-
-template <typename PFN, typename T>
-static hwc2_function_pointer_t asFP(T function)
-{
-    static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
-    return reinterpret_cast<hwc2_function_pointer_t>(function);
-}
-
-using namespace HWC2;
-
-static constexpr Attribute ColorMode = static_cast<Attribute>(6);
-
-namespace android {
-
-class CfHWC2::Callbacks : public hwc_procs_t {
-    public:
-        explicit Callbacks(CfHWC2& adapter) : mAdapter(adapter) {
-            invalidate = &invalidateHook;
-            vsync = &vsyncHook;
-            hotplug = &hotplugHook;
-        }
-
-        static void invalidateHook(const hwc_procs_t* procs) {
-            auto callbacks = static_cast<const Callbacks*>(procs);
-            callbacks->mAdapter.hwc1Invalidate();
-        }
-
-        static void vsyncHook(const hwc_procs_t* procs, int display,
-                int64_t timestamp) {
-            auto callbacks = static_cast<const Callbacks*>(procs);
-            callbacks->mAdapter.hwc1Vsync(display, timestamp);
-        }
-
-        static void hotplugHook(const hwc_procs_t* procs, int display,
-                int connected) {
-            auto callbacks = static_cast<const Callbacks*>(procs);
-            callbacks->mAdapter.hwc1Hotplug(display, connected);
-        }
-
-    private:
-        CfHWC2& mAdapter;
-};
-
-static int closeHook(hw_device_t* /*device*/)
-{
-    // Do nothing, since the real work is done in the class destructor, but we
-    // need to provide a valid function pointer for hwc2_close to call
-    return 0;
-}
-
-CfHWC2::CfHWC2(hwc_composer_device_1_t* hwc1Device)
-  : mDumpString(),
-    mHwc1Device(hwc1Device),
-    mHwc1MinorVersion(getMinorVersion(hwc1Device)),
-    mHwc1SupportsVirtualDisplays(false),
-    mHwc1SupportsBackgroundColor(false),
-    mHwc1Callbacks(std::make_unique<Callbacks>(*this)),
-    mCapabilities(),
-    mLayers(),
-    mHwc1VirtualDisplay(),
-    mStateMutex(),
-    mCallbacks(),
-    mHasPendingInvalidate(false),
-    mPendingVsyncs(),
-    mPendingHotplugs(),
-    mDisplays(),
-    mHwc1DisplayMap()
-{
-    common.tag = HARDWARE_DEVICE_TAG;
-    common.version = HWC_DEVICE_API_VERSION_2_0;
-    common.close = closeHook;
-    getCapabilities = getCapabilitiesHook;
-    getFunction = getFunctionHook;
-    populateCapabilities();
-    populatePrimary();
-    mHwc1Device->registerProcs(mHwc1Device,
-            static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
-}
-
-CfHWC2::~CfHWC2() {
-    hwc_close_1(mHwc1Device);
-}
-
-void CfHWC2::doGetCapabilities(uint32_t* outCount,
-        int32_t* outCapabilities) {
-    if (outCapabilities == nullptr) {
-        *outCount = mCapabilities.size();
-        return;
-    }
-
-    auto capabilityIter = mCapabilities.cbegin();
-    for (size_t written = 0; written < *outCount; ++written) {
-        if (capabilityIter == mCapabilities.cend()) {
-            return;
-        }
-        outCapabilities[written] = static_cast<int32_t>(*capabilityIter);
-        ++capabilityIter;
-    }
-}
-
-hwc2_function_pointer_t CfHWC2::doGetFunction(
-        FunctionDescriptor descriptor) {
-    switch (descriptor) {
-        // Device functions
-        case FunctionDescriptor::CreateVirtualDisplay:
-            return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
-                    createVirtualDisplayHook);
-        case FunctionDescriptor::DestroyVirtualDisplay:
-            return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
-                    destroyVirtualDisplayHook);
-        case FunctionDescriptor::Dump:
-            return asFP<HWC2_PFN_DUMP>(dumpHook);
-        case FunctionDescriptor::GetMaxVirtualDisplayCount:
-            return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
-                    getMaxVirtualDisplayCountHook);
-        case FunctionDescriptor::RegisterCallback:
-            return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
-
-        // Display functions
-        case FunctionDescriptor::AcceptDisplayChanges:
-            return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
-                    displayHook<decltype(&Display::acceptChanges),
-                    &Display::acceptChanges>);
-        case FunctionDescriptor::CreateLayer:
-            return asFP<HWC2_PFN_CREATE_LAYER>(
-                    displayHook<decltype(&Display::createLayer),
-                    &Display::createLayer, hwc2_layer_t*>);
-        case FunctionDescriptor::DestroyLayer:
-            return asFP<HWC2_PFN_DESTROY_LAYER>(
-                    displayHook<decltype(&Display::destroyLayer),
-                    &Display::destroyLayer, hwc2_layer_t>);
-        case FunctionDescriptor::GetActiveConfig:
-            return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(
-                    displayHook<decltype(&Display::getActiveConfig),
-                    &Display::getActiveConfig, hwc2_config_t*>);
-        case FunctionDescriptor::GetChangedCompositionTypes:
-            return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
-                    displayHook<decltype(&Display::getChangedCompositionTypes),
-                    &Display::getChangedCompositionTypes, uint32_t*,
-                    hwc2_layer_t*, int32_t*>);
-        case FunctionDescriptor::GetColorModes:
-            return asFP<HWC2_PFN_GET_COLOR_MODES>(
-                    displayHook<decltype(&Display::getColorModes),
-                    &Display::getColorModes, uint32_t*, int32_t*>);
-        case FunctionDescriptor::GetDisplayAttribute:
-            return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
-                    getDisplayAttributeHook);
-        case FunctionDescriptor::GetDisplayConfigs:
-            return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(
-                    displayHook<decltype(&Display::getConfigs),
-                    &Display::getConfigs, uint32_t*, hwc2_config_t*>);
-        case FunctionDescriptor::GetDisplayName:
-            return asFP<HWC2_PFN_GET_DISPLAY_NAME>(
-                    displayHook<decltype(&Display::getName),
-                    &Display::getName, uint32_t*, char*>);
-        case FunctionDescriptor::GetDisplayRequests:
-            return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(
-                    displayHook<decltype(&Display::getRequests),
-                    &Display::getRequests, int32_t*, uint32_t*, hwc2_layer_t*,
-                    int32_t*>);
-        case FunctionDescriptor::GetDisplayType:
-            return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(
-                    displayHook<decltype(&Display::getType),
-                    &Display::getType, int32_t*>);
-        case FunctionDescriptor::GetDozeSupport:
-            return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
-                    displayHook<decltype(&Display::getDozeSupport),
-                    &Display::getDozeSupport, int32_t*>);
-        case FunctionDescriptor::GetHdrCapabilities:
-            return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
-                    displayHook<decltype(&Display::getHdrCapabilities),
-                    &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
-                    float*, float*>);
-        case FunctionDescriptor::GetReleaseFences:
-            return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
-                    displayHook<decltype(&Display::getReleaseFences),
-                    &Display::getReleaseFences, uint32_t*, hwc2_layer_t*,
-                    int32_t*>);
-        case FunctionDescriptor::PresentDisplay:
-            return asFP<HWC2_PFN_PRESENT_DISPLAY>(
-                    displayHook<decltype(&Display::present),
-                    &Display::present, int32_t*>);
-        case FunctionDescriptor::SetActiveConfig:
-            return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(
-                    displayHook<decltype(&Display::setActiveConfig),
-                    &Display::setActiveConfig, hwc2_config_t>);
-        case FunctionDescriptor::SetClientTarget:
-            return asFP<HWC2_PFN_SET_CLIENT_TARGET>(
-                    displayHook<decltype(&Display::setClientTarget),
-                    &Display::setClientTarget, buffer_handle_t, int32_t,
-                    int32_t, hwc_region_t>);
-        case FunctionDescriptor::SetColorMode:
-            return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
-        case FunctionDescriptor::SetColorTransform:
-            return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
-        case FunctionDescriptor::SetOutputBuffer:
-            return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(
-                    displayHook<decltype(&Display::setOutputBuffer),
-                    &Display::setOutputBuffer, buffer_handle_t, int32_t>);
-        case FunctionDescriptor::SetPowerMode:
-            return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
-        case FunctionDescriptor::SetVsyncEnabled:
-            return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
-        case FunctionDescriptor::ValidateDisplay:
-            return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
-                    displayHook<decltype(&Display::validate),
-                    &Display::validate, uint32_t*, uint32_t*>);
-        case FunctionDescriptor::GetClientTargetSupport:
-            return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
-                    displayHook<decltype(&Display::getClientTargetSupport),
-                    &Display::getClientTargetSupport, uint32_t, uint32_t,
-                                                      int32_t, int32_t>);
-
-        // 2.3 required functions
-        case FunctionDescriptor::GetDisplayIdentificationData:
-            return asFP<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
-                    displayHook<decltype(&Display::getDisplayIdentificationData),
-                    &Display::getDisplayIdentificationData, uint8_t*, uint32_t*, uint8_t*>);
-        case FunctionDescriptor::GetDisplayCapabilities:
-            return asFP<HWC2_PFN_GET_DISPLAY_CAPABILITIES>(
-                    displayHook<decltype(&Display::getDisplayCapabilities),
-                    &Display::getDisplayCapabilities, uint32_t*, uint32_t*>);
-        case FunctionDescriptor::GetDisplayBrightnessSupport:
-            return asFP<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(
-                    displayHook<decltype(&Display::getDisplayBrightnessSupport),
-                    &Display::getDisplayBrightnessSupport, bool*>);
-        case FunctionDescriptor::SetDisplayBrightness:
-            return asFP<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
-                    displayHook<decltype(&Display::setDisplayBrightness),
-                    &Display::setDisplayBrightness, float>);
-
-        // Layer functions
-        case FunctionDescriptor::SetCursorPosition:
-            return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
-                    layerHook<decltype(&Layer::setCursorPosition),
-                    &Layer::setCursorPosition, int32_t, int32_t>);
-        case FunctionDescriptor::SetLayerBuffer:
-            return asFP<HWC2_PFN_SET_LAYER_BUFFER>(
-                    layerHook<decltype(&Layer::setBuffer), &Layer::setBuffer,
-                    buffer_handle_t, int32_t>);
-        case FunctionDescriptor::SetLayerSurfaceDamage:
-            return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
-                    layerHook<decltype(&Layer::setSurfaceDamage),
-                    &Layer::setSurfaceDamage, hwc_region_t>);
-
-        // Layer state functions
-        case FunctionDescriptor::SetLayerBlendMode:
-            return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(
-                    setLayerBlendModeHook);
-        case FunctionDescriptor::SetLayerColor:
-            return asFP<HWC2_PFN_SET_LAYER_COLOR>(
-                    layerHook<decltype(&Layer::setColor), &Layer::setColor,
-                    hwc_color_t>);
-        case FunctionDescriptor::SetLayerCompositionType:
-            return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
-                    setLayerCompositionTypeHook);
-        case FunctionDescriptor::SetLayerDataspace:
-            return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerDataspaceHook);
-        case FunctionDescriptor::SetLayerDisplayFrame:
-            return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
-                    layerHook<decltype(&Layer::setDisplayFrame),
-                    &Layer::setDisplayFrame, hwc_rect_t>);
-        case FunctionDescriptor::SetLayerPlaneAlpha:
-            return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
-                    layerHook<decltype(&Layer::setPlaneAlpha),
-                    &Layer::setPlaneAlpha, float>);
-        case FunctionDescriptor::SetLayerSidebandStream:
-            return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
-                    layerHook<decltype(&Layer::setSidebandStream),
-                    &Layer::setSidebandStream, const native_handle_t*>);
-        case FunctionDescriptor::SetLayerSourceCrop:
-            return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
-                    layerHook<decltype(&Layer::setSourceCrop),
-                    &Layer::setSourceCrop, hwc_frect_t>);
-        case FunctionDescriptor::SetLayerTransform:
-            return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerTransformHook);
-        case FunctionDescriptor::SetLayerVisibleRegion:
-            return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
-                    layerHook<decltype(&Layer::setVisibleRegion),
-                    &Layer::setVisibleRegion, hwc_region_t>);
-        case FunctionDescriptor::SetLayerZOrder:
-            return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerZOrderHook);
-
-        default:
-            ALOGE("doGetFunction: Unknown function descriptor: %d (%s)",
-                    static_cast<int32_t>(descriptor),
-                    to_string(descriptor).c_str());
-            return nullptr;
-    }
-}
-
-// Device functions
-
-Error CfHWC2::createVirtualDisplay(uint32_t width,
-        uint32_t height, hwc2_display_t* outDisplay) {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    if (mHwc1VirtualDisplay) {
-        // We have already allocated our only HWC1 virtual display
-        ALOGE("createVirtualDisplay: HWC1 virtual display already allocated");
-        return Error::NoResources;
-    }
-
-    mHwc1VirtualDisplay = std::make_shared<CfHWC2::Display>(*this,
-            HWC2::DisplayType::Virtual);
-    mHwc1VirtualDisplay->populateConfigs(width, height);
-    const auto displayId = mHwc1VirtualDisplay->getId();
-    mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL] = displayId;
-    mHwc1VirtualDisplay->setHwc1Id(HWC_DISPLAY_VIRTUAL);
-    mDisplays.emplace(displayId, mHwc1VirtualDisplay);
-    *outDisplay = displayId;
-
-    return Error::None;
-}
-
-Error CfHWC2::destroyVirtualDisplay(hwc2_display_t displayId) {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) {
-        return Error::BadDisplay;
-    }
-
-    mHwc1VirtualDisplay.reset();
-    mHwc1DisplayMap.erase(HWC_DISPLAY_VIRTUAL);
-    mDisplays.erase(displayId);
-
-    return Error::None;
-}
-
-void CfHWC2::dump(uint32_t* outSize, char* outBuffer) {
-    if (outBuffer != nullptr) {
-        auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
-        *outSize = static_cast<uint32_t>(copiedBytes);
-        return;
-    }
-
-    std::stringstream output;
-
-    output << "-- CfHWC2 --\n";
-
-    output << "Adapting to a HWC 1." << static_cast<int>(mHwc1MinorVersion) <<
-            " device\n";
-
-    // Attempt to acquire the lock for 1 second, but proceed without the lock
-    // after that, so we can still get some information if we're deadlocked
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex,
-            std::defer_lock);
-    lock.try_lock_for(1s);
-
-    if (mCapabilities.empty()) {
-        output << "Capabilities: None\n";
-    } else {
-        output << "Capabilities:\n";
-        for (auto capability : mCapabilities) {
-            output << "  " << to_string(capability) << '\n';
-        }
-    }
-
-    output << "Displays:\n";
-    for (const auto& element : mDisplays) {
-        const auto& display = element.second;
-        output << display->dump();
-    }
-    output << '\n';
-
-    // Release the lock before calling into HWC1, and since we no longer require
-    // mutual exclusion to access mCapabilities or mDisplays
-    lock.unlock();
-
-    if (mHwc1Device->dump) {
-        output << "HWC1 dump:\n";
-        std::vector<char> hwc1Dump(4096);
-        // Call with size - 1 to preserve a null character at the end
-        mHwc1Device->dump(mHwc1Device, hwc1Dump.data(),
-                static_cast<int>(hwc1Dump.size() - 1));
-        output << hwc1Dump.data();
-    }
-
-    mDumpString = output.str();
-    *outSize = static_cast<uint32_t>(mDumpString.size());
-}
-
-uint32_t CfHWC2::getMaxVirtualDisplayCount() {
-    return mHwc1SupportsVirtualDisplays ? 1 : 0;
-}
-
-static bool isValid(Callback descriptor) {
-    switch (descriptor) {
-        case Callback::Hotplug: // Fall-through
-        case Callback::Refresh: // Fall-through
-        case Callback::Vsync: return true;
-        default: return false;
-    }
-}
-
-Error CfHWC2::registerCallback(Callback descriptor,
-        hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
-    if (!isValid(descriptor)) {
-        return Error::BadParameter;
-    }
-
-    ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(),
-            callbackData, pointer);
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    if (pointer != nullptr) {
-        mCallbacks[descriptor] = {callbackData, pointer};
-    } else {
-        ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
-        mCallbacks.erase(descriptor);
-        return Error::None;
-    }
-
-    bool hasPendingInvalidate = false;
-    std::vector<hwc2_display_t> displayIds;
-    std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;
-    std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;
-
-    if (descriptor == Callback::Refresh) {
-        hasPendingInvalidate = mHasPendingInvalidate;
-        if (hasPendingInvalidate) {
-            for (auto& displayPair : mDisplays) {
-                displayIds.emplace_back(displayPair.first);
-            }
-        }
-        mHasPendingInvalidate = false;
-    } else if (descriptor == Callback::Vsync) {
-        for (auto pending : mPendingVsyncs) {
-            auto hwc1DisplayId = pending.first;
-            if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-                ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d",
-                        hwc1DisplayId);
-                continue;
-            }
-            auto displayId = mHwc1DisplayMap[hwc1DisplayId];
-            auto timestamp = pending.second;
-            pendingVsyncs.emplace_back(displayId, timestamp);
-        }
-        mPendingVsyncs.clear();
-    } else if (descriptor == Callback::Hotplug) {
-        // Hotplug the primary display
-        pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY],
-                static_cast<int32_t>(Connection::Connected));
-
-        for (auto pending : mPendingHotplugs) {
-            auto hwc1DisplayId = pending.first;
-            if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-                ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d",
-                        hwc1DisplayId);
-                continue;
-            }
-            auto displayId = mHwc1DisplayMap[hwc1DisplayId];
-            auto connected = pending.second;
-            pendingHotplugs.emplace_back(displayId, connected);
-        }
-    }
-
-    // Call pending callbacks without the state lock held
-    lock.unlock();
-
-    if (hasPendingInvalidate) {
-        auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
-        for (auto displayId : displayIds) {
-            refresh(callbackData, displayId);
-        }
-    }
-    if (!pendingVsyncs.empty()) {
-        auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
-        for (auto& pendingVsync : pendingVsyncs) {
-            vsync(callbackData, pendingVsync.first, pendingVsync.second);
-        }
-    }
-    if (!pendingHotplugs.empty()) {
-        auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
-        for (auto& pendingHotplug : pendingHotplugs) {
-            hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);
-        }
-    }
-    return Error::None;
-}
-
-// Display functions
-
-std::atomic<hwc2_display_t> CfHWC2::Display::sNextId(1);
-
-CfHWC2::Display::Display(CfHWC2& device, HWC2::DisplayType type)
-  : mId(sNextId++),
-    mDevice(device),
-    mStateMutex(),
-    mHwc1RequestedContents(nullptr),
-    mRetireFence(),
-    mChanges(),
-    mHwc1Id(-1),
-    mConfigs(),
-    mActiveConfig(nullptr),
-    mActiveColorMode(static_cast<android_color_mode_t>(-1)),
-    mName(),
-    mType(type),
-    mPowerMode(PowerMode::Off),
-    mVsyncEnabled(Vsync::Invalid),
-    mClientTarget(),
-    mOutputBuffer(),
-    mHasColorTransform(false),
-    mLayers(),
-    mHwc1LayerMap(),
-    mNumAvailableRects(0),
-    mNextAvailableRect(nullptr),
-    mGeometryChanged(false)
-    {}
-
-Error CfHWC2::Display::acceptChanges() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        ALOGV("[%" PRIu64 "] acceptChanges failed, not validated", mId);
-        return Error::NotValidated;
-    }
-
-    ALOGV("[%" PRIu64 "] acceptChanges", mId);
-
-    for (auto& change : mChanges->getTypeChanges()) {
-        auto layerId = change.first;
-        auto type = change.second;
-        if (mDevice.mLayers.count(layerId) == 0) {
-            // This should never happen but somehow does.
-            ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
-                  layerId);
-            continue;
-        }
-        auto layer = mDevice.mLayers[layerId];
-        layer->setCompositionType(type);
-    }
-
-    mChanges->clearTypeChanges();
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::createLayer(hwc2_layer_t* outLayerId) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
-    mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
-    *outLayerId = layer->getId();
-    ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId);
-    markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Display::destroyLayer(hwc2_layer_t layerId) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    const auto mapLayer = mDevice.mLayers.find(layerId);
-    if (mapLayer == mDevice.mLayers.end()) {
-        ALOGV("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer",
-                mId, layerId);
-        return Error::BadLayer;
-    }
-    const auto layer = mapLayer->second;
-    mDevice.mLayers.erase(mapLayer);
-    const auto zRange = mLayers.equal_range(layer);
-    for (auto current = zRange.first; current != zRange.second; ++current) {
-        if (**current == *layer) {
-            current = mLayers.erase(current);
-            break;
-        }
-    }
-    ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId);
-    markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Display::getActiveConfig(hwc2_config_t* outConfig) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mActiveConfig) {
-        ALOGV("[%" PRIu64 "] getActiveConfig --> %s", mId,
-                to_string(Error::BadConfig).c_str());
-        return Error::BadConfig;
-    }
-    auto configId = mActiveConfig->getId();
-    ALOGV("[%" PRIu64 "] getActiveConfig --> %u", mId, configId);
-    *outConfig = configId;
-    return Error::None;
-}
-
-Error CfHWC2::Display::getAttribute(hwc2_config_t configId,
-        Attribute attribute, int32_t* outValue) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
-        ALOGV("[%" PRIu64 "] getAttribute failed: bad config (%u)", mId,
-                configId);
-        return Error::BadConfig;
-    }
-    *outValue = mConfigs[configId]->getAttribute(attribute);
-    ALOGV("[%" PRIu64 "] getAttribute(%u, %s) --> %d", mId, configId,
-            to_string(attribute).c_str(), *outValue);
-    return Error::None;
-}
-
-Error CfHWC2::Display::getChangedCompositionTypes(
-        uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        ALOGE("[%" PRIu64 "] getChangedCompositionTypes failed: not validated",
-                mId);
-        return Error::NotValidated;
-    }
-
-    if ((outLayers == nullptr) || (outTypes == nullptr)) {
-        *outNumElements = mChanges->getTypeChanges().size();
-        return Error::None;
-    }
-
-    uint32_t numWritten = 0;
-    for (const auto& element : mChanges->getTypeChanges()) {
-        if (numWritten == *outNumElements) {
-            break;
-        }
-        auto layerId = element.first;
-        auto intType = static_cast<int32_t>(element.second);
-        ALOGV("Adding %" PRIu64 " %s", layerId,
-                to_string(element.second).c_str());
-        outLayers[numWritten] = layerId;
-        outTypes[numWritten] = intType;
-        ++numWritten;
-    }
-    *outNumElements = numWritten;
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::getColorModes(uint32_t* outNumModes,
-        int32_t* outModes) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!outModes) {
-        *outNumModes = mColorModes.size();
-        return Error::None;
-    }
-    uint32_t numModes = std::min(*outNumModes,
-            static_cast<uint32_t>(mColorModes.size()));
-    std::copy_n(mColorModes.cbegin(), numModes, outModes);
-    *outNumModes = numModes;
-    return Error::None;
-}
-
-Error CfHWC2::Display::getConfigs(uint32_t* outNumConfigs,
-        hwc2_config_t* outConfigs) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!outConfigs) {
-        *outNumConfigs = mConfigs.size();
-        return Error::None;
-    }
-    uint32_t numWritten = 0;
-    for (const auto& config : mConfigs) {
-        if (numWritten == *outNumConfigs) {
-            break;
-        }
-        outConfigs[numWritten] = config->getId();
-        ++numWritten;
-    }
-    *outNumConfigs = numWritten;
-    return Error::None;
-}
-
-Error CfHWC2::Display::getDozeSupport(int32_t* outSupport) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) {
-        *outSupport = 0;
-    } else {
-        *outSupport = 1;
-    }
-    return Error::None;
-}
-
-Error CfHWC2::Display::getHdrCapabilities(uint32_t* outNumTypes,
-        int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
-        float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
-    // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
-    *outNumTypes = 0;
-    return Error::None;
-}
-
-Error CfHWC2::Display::getName(uint32_t* outSize, char* outName) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!outName) {
-        *outSize = mName.size();
-        return Error::None;
-    }
-    auto numCopied = mName.copy(outName, *outSize);
-    *outSize = numCopied;
-    return Error::None;
-}
-
-Error CfHWC2::Display::getReleaseFences(uint32_t* outNumElements,
-        hwc2_layer_t* outLayers, int32_t* outFences) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    uint32_t numWritten = 0;
-    bool outputsNonNull = (outLayers != nullptr) && (outFences != nullptr);
-    for (const auto& layer : mLayers) {
-        if (outputsNonNull && (numWritten == *outNumElements)) {
-            break;
-        }
-
-        auto releaseFence = layer->getReleaseFence();
-        if (releaseFence != MiniFence::NO_FENCE) {
-            if (outputsNonNull) {
-                outLayers[numWritten] = layer->getId();
-                outFences[numWritten] = releaseFence->dup();
-            }
-            ++numWritten;
-        }
-    }
-    *outNumElements = numWritten;
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::getRequests(int32_t* outDisplayRequests,
-        uint32_t* outNumElements, hwc2_layer_t* outLayers,
-        int32_t* outLayerRequests) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        return Error::NotValidated;
-    }
-
-    if (outLayers == nullptr || outLayerRequests == nullptr) {
-        *outNumElements = mChanges->getNumLayerRequests();
-        return Error::None;
-    }
-
-    // Display requests (HWC2::DisplayRequest) are not supported by hwc1:
-    // A hwc1 has always zero requests for the client.
-    *outDisplayRequests = 0;
-
-    uint32_t numWritten = 0;
-    for (const auto& request : mChanges->getLayerRequests()) {
-        if (numWritten == *outNumElements) {
-            break;
-        }
-        outLayers[numWritten] = request.first;
-        outLayerRequests[numWritten] = static_cast<int32_t>(request.second);
-        ++numWritten;
-    }
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::getType(int32_t* outType) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    *outType = static_cast<int32_t>(mType);
-    return Error::None;
-}
-
-Error CfHWC2::Display::present(int32_t* outRetireFence) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (mChanges) {
-        Error error = mDevice.setAllDisplays();
-        if (error != Error::None) {
-            ALOGE("[%" PRIu64 "] present: setAllDisplaysFailed (%s)", mId,
-                    to_string(error).c_str());
-            return error;
-        }
-    }
-
-    *outRetireFence = mRetireFence.get()->dup();
-    ALOGV("[%" PRIu64 "] present returning retire fence %d", mId,
-            *outRetireFence);
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::setActiveConfig(hwc2_config_t configId) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    auto config = getConfig(configId);
-    if (!config) {
-        return Error::BadConfig;
-    }
-    if (config == mActiveConfig) {
-        return Error::None;
-    }
-
-    if (mDevice.mHwc1MinorVersion >= 4) {
-        uint32_t hwc1Id = 0;
-        auto error = config->getHwc1IdForColorMode(mActiveColorMode, &hwc1Id);
-        if (error != Error::None) {
-            return error;
-        }
-
-        int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
-                mHwc1Id, static_cast<int>(hwc1Id));
-        if (intError != 0) {
-            ALOGE("setActiveConfig: Failed to set active config on HWC1 (%d)",
-                intError);
-            return Error::BadConfig;
-        }
-        mActiveConfig = config;
-    }
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::setClientTarget(buffer_handle_t target,
-        int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence);
-    mClientTarget.setBuffer(target);
-    mClientTarget.setFence(acquireFence);
-    // dataspace and damage can't be used by HWC1, so ignore them
-    return Error::None;
-}
-
-Error CfHWC2::Display::setColorMode(android_color_mode_t mode) {
-    std::unique_lock<std::recursive_mutex> lock (mStateMutex);
-
-    ALOGV("[%" PRIu64 "] setColorMode(%d)", mId, mode);
-
-    if (mode == mActiveColorMode) {
-        return Error::None;
-    }
-    if (mColorModes.count(mode) == 0) {
-        ALOGE("[%" PRIu64 "] Mode %d not found in mColorModes", mId, mode);
-        return Error::Unsupported;
-    }
-
-    if (mDevice.mHwc1MinorVersion >= 4) {
-        uint32_t hwc1Config = 0;
-        auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config);
-        if (error != Error::None) {
-            return error;
-        }
-
-        ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config);
-        int intError =
-            mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, hwc1Config);
-        if (intError != 0) {
-            ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError);
-            return Error::Unsupported;
-        }
-    }
-
-    mActiveColorMode = mode;
-    return Error::None;
-}
-
-Error CfHWC2::Display::setColorTransform(android_color_transform_t hint) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("%" PRIu64 "] setColorTransform(%d)", mId,
-            static_cast<int32_t>(hint));
-    mHasColorTransform = (hint != HAL_COLOR_TRANSFORM_IDENTITY);
-    return Error::None;
-}
-
-Error CfHWC2::Display::setOutputBuffer(buffer_handle_t buffer,
-        int32_t releaseFence) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence);
-    mOutputBuffer.setBuffer(buffer);
-    mOutputBuffer.setFence(releaseFence);
-    return Error::None;
-}
-
-static bool isValid(PowerMode mode) {
-    switch (mode) {
-        case PowerMode::Off: // Fall-through
-        case PowerMode::DozeSuspend: // Fall-through
-        case PowerMode::Doze: // Fall-through
-        case PowerMode::On: return true;
-    }
-}
-
-static int getHwc1PowerMode(PowerMode mode) {
-    switch (mode) {
-        case PowerMode::Off: return HWC_POWER_MODE_OFF;
-        case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND;
-        case PowerMode::Doze: return HWC_POWER_MODE_DOZE;
-        case PowerMode::On: return HWC_POWER_MODE_NORMAL;
-    }
-}
-
-Error CfHWC2::Display::setPowerMode(PowerMode mode) {
-    if (!isValid(mode)) {
-        return Error::BadParameter;
-    }
-    if (mode == mPowerMode) {
-        return Error::None;
-    }
-
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    int error = 0;
-    if (mDevice.mHwc1MinorVersion < 4) {
-        error = mDevice.mHwc1Device->blank(mDevice.mHwc1Device, mHwc1Id,
-                mode == PowerMode::Off);
-    } else {
-        error = mDevice.mHwc1Device->setPowerMode(mDevice.mHwc1Device,
-                mHwc1Id, getHwc1PowerMode(mode));
-    }
-    ALOGE_IF(error != 0, "setPowerMode: Failed to set power mode on HWC1 (%d)",
-            error);
-
-    ALOGV("[%" PRIu64 "] setPowerMode(%s)", mId, to_string(mode).c_str());
-    mPowerMode = mode;
-    return Error::None;
-}
-
-static bool isValid(Vsync enable) {
-    switch (enable) {
-        case Vsync::Enable: // Fall-through
-        case Vsync::Disable: return true;
-        case Vsync::Invalid: return false;
-    }
-}
-
-Error CfHWC2::Display::setVsyncEnabled(Vsync enable) {
-    if (!isValid(enable)) {
-        return Error::BadParameter;
-    }
-    if (enable == mVsyncEnabled) {
-        return Error::None;
-    }
-
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    int error = mDevice.mHwc1Device->eventControl(mDevice.mHwc1Device,
-            mHwc1Id, HWC_EVENT_VSYNC, enable == Vsync::Enable);
-    ALOGE_IF(error != 0, "setVsyncEnabled: Failed to set vsync on HWC1 (%d)",
-            error);
-
-    mVsyncEnabled = enable;
-    return Error::None;
-}
-
-Error CfHWC2::Display::validate(uint32_t* outNumTypes,
-        uint32_t* outNumRequests) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        if (!mDevice.prepareAllDisplays()) {
-            return Error::BadDisplay;
-        }
-    } else {
-        ALOGE("Validate was called more than once!");
-    }
-
-    *outNumTypes = mChanges->getNumTypes();
-    *outNumRequests = mChanges->getNumLayerRequests();
-    ALOGV("[%" PRIu64 "] validate --> %u types, %u requests", mId, *outNumTypes,
-            *outNumRequests);
-    for (auto request : mChanges->getTypeChanges()) {
-        ALOGV("Layer %" PRIu64 " --> %s", request.first,
-                to_string(request.second).c_str());
-    }
-    return *outNumTypes > 0 ? Error::HasChanges : Error::None;
-}
-
-Error CfHWC2::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    const auto mapLayer = mDevice.mLayers.find(layerId);
-    if (mapLayer == mDevice.mLayers.end()) {
-        ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", mId);
-        return Error::BadLayer;
-    }
-
-    const auto layer = mapLayer->second;
-    const auto zRange = mLayers.equal_range(layer);
-    bool layerOnDisplay = false;
-    for (auto current = zRange.first; current != zRange.second; ++current) {
-        if (**current == *layer) {
-            if ((*current)->getZ() == z) {
-                // Don't change anything if the Z hasn't changed
-                return Error::None;
-            }
-            current = mLayers.erase(current);
-            layerOnDisplay = true;
-            break;
-        }
-    }
-
-    if (!layerOnDisplay) {
-        ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display",
-                mId);
-        return Error::BadLayer;
-    }
-
-    layer->setZ(z);
-    mLayers.emplace(std::move(layer));
-    markGeometryChanged();
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::getClientTargetSupport(uint32_t width, uint32_t height,
-                                      int32_t format, int32_t dataspace){
-    if (mActiveConfig == nullptr) {
-        return Error::Unsupported;
-    }
-
-    if (width == mActiveConfig->getAttribute(Attribute::Width) &&
-            height == mActiveConfig->getAttribute(Attribute::Height) &&
-            format == HAL_PIXEL_FORMAT_RGBA_8888 &&
-            dataspace == HAL_DATASPACE_UNKNOWN) {
-        return Error::None;
-    }
-
-    return Error::Unsupported;
-}
-
-// thess EDIDs are carefully generated according to the EDID spec version 1.3, more info
-// can be found from the following file:
-//   frameworks/native/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
-// approved pnp ids can be found here: https://uefi.org/pnp_id_list
-// pnp id: GGL, name: EMU_display_0, last byte is checksum
-// display id is local:8141603649153536
-static const uint8_t sEDID0[] = {
-    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
-    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
-    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
-    0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x30, 0x00, 0x4b
-};
-
-// pnp id: GGL, name: EMU_display_1
-// display id is local:8140900251843329
-static const uint8_t sEDID1[] = {
-    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
-    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
-    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
-    0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x31, 0x00, 0x3b
-};
-
-// pnp id: GGL, name: EMU_display_2
-// display id is local:8140940453066754
-static const uint8_t sEDID2[] = {
-    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
-    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
-    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
-    0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x00, 0x49
-};
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
-Error CfHWC2::Display::getDisplayIdentificationData(uint8_t* outPort,
-        uint32_t* outDataSize, uint8_t* outData) {
-    ALOGV("%s DisplayId %u", __FUNCTION__, (uint32_t)mId);
-    if (outPort == nullptr || outDataSize == nullptr)
-        return Error::BadParameter;
-
-    uint32_t len = std::min(*outDataSize, (uint32_t)ARRAY_SIZE(sEDID0));
-    if (outData != nullptr && len < (uint32_t)ARRAY_SIZE(sEDID0)) {
-        ALOGW("%s DisplayId %u, small buffer size: %u is specified",
-                __FUNCTION__, (uint32_t)mId, len);
-    }
-    *outDataSize = ARRAY_SIZE(sEDID0);
-    switch (mId) {
-        case 0:
-            *outPort = 0;
-            if (outData)
-                memcpy(outData, sEDID0, len);
-            break;
-
-        case 1:
-            *outPort = 1;
-            if (outData)
-                memcpy(outData, sEDID1, len);
-            break;
-
-        case 2:
-            *outPort = 2;
-            if (outData)
-                memcpy(outData, sEDID2, len);
-            break;
-
-        default:
-            *outPort = (uint8_t)mId;
-            if (outData) {
-                memcpy(outData, sEDID2, len);
-                uint32_t size = ARRAY_SIZE(sEDID0);
-                // change the name to EMU_display_<mID>
-                // note the 3rd char from back is the number, _0, _1, _2, etc.
-                if (len >= size - 2)
-                    outData[size-3] = '0' + (uint8_t)mId;
-                if (len >= size) {
-                    // update the last byte, which is checksum byte
-                    uint8_t checksum = -(uint8_t)std::accumulate(
-                            outData, outData + size - 1, static_cast<uint8_t>(0));
-                    outData[size - 1] = checksum;
-                }
-            }
-            break;
-    }
-
-    return Error::None;
-}
-
-Error CfHWC2::Display::getDisplayCapabilities(uint32_t* outNumCapabilities,
-        uint32_t* outCapabilities) {
-    ALOGV("%s DisplayId %u", __FUNCTION__, (uint32_t)mId);
-    if (outNumCapabilities == nullptr) {
-        return Error::None;
-    }
-
-    bool brightness_support = true;
-    bool doze_support = true;
-
-    uint32_t count = 1  + static_cast<uint32_t>(doze_support) + (brightness_support ? 1 : 0);
-    int index = 0;
-    if (outCapabilities != nullptr && (*outNumCapabilities >= count)) {
-        outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
-        if (doze_support) {
-            outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_DOZE;
-        }
-        if (brightness_support) {
-            outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_BRIGHTNESS;
-       }
-    }
-
-    *outNumCapabilities = count;
-    return Error::None;
-}
-
-Error CfHWC2::Display::getDisplayBrightnessSupport(bool *out_support) {
-    *out_support = false;
-    return Error::None;
-}
-
-Error CfHWC2::Display::setDisplayBrightness(float brightness) {
-    ALOGW("TODO: setDisplayBrightness() is not implemented yet: brightness=%f", brightness);
-    return Error::None;
-}
-
-static constexpr uint32_t ATTRIBUTES_WITH_COLOR[] = {
-    HWC_DISPLAY_VSYNC_PERIOD,
-    HWC_DISPLAY_WIDTH,
-    HWC_DISPLAY_HEIGHT,
-    HWC_DISPLAY_DPI_X,
-    HWC_DISPLAY_DPI_Y,
-    HWC_DISPLAY_COLOR_TRANSFORM,
-    HWC_DISPLAY_NO_ATTRIBUTE,
-};
-
-static constexpr uint32_t ATTRIBUTES_WITHOUT_COLOR[] = {
-    HWC_DISPLAY_VSYNC_PERIOD,
-    HWC_DISPLAY_WIDTH,
-    HWC_DISPLAY_HEIGHT,
-    HWC_DISPLAY_DPI_X,
-    HWC_DISPLAY_DPI_Y,
-    HWC_DISPLAY_NO_ATTRIBUTE,
-};
-
-static constexpr size_t NUM_ATTRIBUTES_WITH_COLOR =
-        sizeof(ATTRIBUTES_WITH_COLOR) / sizeof(uint32_t);
-static_assert(sizeof(ATTRIBUTES_WITH_COLOR) > sizeof(ATTRIBUTES_WITHOUT_COLOR),
-        "Attribute tables have unexpected sizes");
-
-static constexpr uint32_t ATTRIBUTE_MAP_WITH_COLOR[] = {
-    6, // HWC_DISPLAY_NO_ATTRIBUTE = 0
-    0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
-    1, // HWC_DISPLAY_WIDTH = 2,
-    2, // HWC_DISPLAY_HEIGHT = 3,
-    3, // HWC_DISPLAY_DPI_X = 4,
-    4, // HWC_DISPLAY_DPI_Y = 5,
-    5, // HWC_DISPLAY_COLOR_TRANSFORM = 6,
-};
-
-static constexpr uint32_t ATTRIBUTE_MAP_WITHOUT_COLOR[] = {
-    5, // HWC_DISPLAY_NO_ATTRIBUTE = 0
-    0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
-    1, // HWC_DISPLAY_WIDTH = 2,
-    2, // HWC_DISPLAY_HEIGHT = 3,
-    3, // HWC_DISPLAY_DPI_X = 4,
-    4, // HWC_DISPLAY_DPI_Y = 5,
-};
-
-template <uint32_t attribute>
-static constexpr bool attributesMatch()
-{
-    bool match = (attribute ==
-            ATTRIBUTES_WITH_COLOR[ATTRIBUTE_MAP_WITH_COLOR[attribute]]);
-    if (attribute == HWC_DISPLAY_COLOR_TRANSFORM) {
-        return match;
-    }
-
-    return match && (attribute ==
-            ATTRIBUTES_WITHOUT_COLOR[ATTRIBUTE_MAP_WITHOUT_COLOR[attribute]]);
-}
-static_assert(attributesMatch<HWC_DISPLAY_VSYNC_PERIOD>(),
-        "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_WIDTH>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_HEIGHT>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_DPI_X>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_DPI_Y>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_COLOR_TRANSFORM>(),
-        "Tables out of sync");
-
-void CfHWC2::Display::populateConfigs() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("[%" PRIu64 "] populateConfigs", mId);
-
-    if (mHwc1Id == -1) {
-        ALOGE("populateConfigs: HWC1 ID not set");
-        return;
-    }
-
-    const size_t MAX_NUM_CONFIGS = 128;
-    uint32_t configs[MAX_NUM_CONFIGS] = {};
-    size_t numConfigs = MAX_NUM_CONFIGS;
-    mDevice.mHwc1Device->getDisplayConfigs(mDevice.mHwc1Device, mHwc1Id,
-            configs, &numConfigs);
-
-    for (size_t c = 0; c < numConfigs; ++c) {
-        uint32_t hwc1ConfigId = configs[c];
-        auto newConfig = std::make_shared<Config>(*this);
-
-        int32_t values[NUM_ATTRIBUTES_WITH_COLOR] = {};
-        bool hasColor = true;
-        auto result = mDevice.mHwc1Device->getDisplayAttributes(
-                mDevice.mHwc1Device, mHwc1Id, hwc1ConfigId,
-                ATTRIBUTES_WITH_COLOR, values);
-        if (result != 0) {
-            mDevice.mHwc1Device->getDisplayAttributes(mDevice.mHwc1Device,
-                    mHwc1Id, hwc1ConfigId, ATTRIBUTES_WITHOUT_COLOR, values);
-            hasColor = false;
-        }
-
-        auto attributeMap = hasColor ?
-                ATTRIBUTE_MAP_WITH_COLOR : ATTRIBUTE_MAP_WITHOUT_COLOR;
-
-        newConfig->setAttribute(Attribute::VsyncPeriod,
-                values[attributeMap[HWC_DISPLAY_VSYNC_PERIOD]]);
-        newConfig->setAttribute(Attribute::Width,
-                values[attributeMap[HWC_DISPLAY_WIDTH]]);
-        newConfig->setAttribute(Attribute::Height,
-                values[attributeMap[HWC_DISPLAY_HEIGHT]]);
-        newConfig->setAttribute(Attribute::DpiX,
-                values[attributeMap[HWC_DISPLAY_DPI_X]]);
-        newConfig->setAttribute(Attribute::DpiY,
-                values[attributeMap[HWC_DISPLAY_DPI_Y]]);
-        if (hasColor) {
-            // In HWC1, color modes are referred to as color transforms. To avoid confusion with
-            // the HWC2 concept of color transforms, we internally refer to them as color modes for
-            // both HWC1 and 2.
-            newConfig->setAttribute(ColorMode,
-                    values[attributeMap[HWC_DISPLAY_COLOR_TRANSFORM]]);
-        }
-
-        // We can only do this after attempting to read the color mode
-        newConfig->setHwc1Id(hwc1ConfigId);
-
-        for (auto& existingConfig : mConfigs) {
-            if (existingConfig->merge(*newConfig)) {
-                ALOGV("Merged config %d with existing config %u: %s",
-                        hwc1ConfigId, existingConfig->getId(),
-                        existingConfig->toString().c_str());
-                newConfig.reset();
-                break;
-            }
-        }
-
-        // If it wasn't merged with any existing config, add it to the end
-        if (newConfig) {
-            newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
-            ALOGV("Found new config %u: %s", newConfig->getId(),
-                    newConfig->toString().c_str());
-            mConfigs.emplace_back(std::move(newConfig));
-        }
-    }
-
-    initializeActiveConfig();
-    populateColorModes();
-}
-
-void CfHWC2::Display::populateConfigs(uint32_t width, uint32_t height) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    mConfigs.emplace_back(std::make_shared<Config>(*this));
-    auto& config = mConfigs[0];
-
-    config->setAttribute(Attribute::Width, static_cast<int32_t>(width));
-    config->setAttribute(Attribute::Height, static_cast<int32_t>(height));
-    config->setHwc1Id(0);
-    config->setId(0);
-    mActiveConfig = config;
-}
-
-bool CfHWC2::Display::prepare() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    // Only prepare display contents for displays HWC1 knows about
-    if (mHwc1Id == -1) {
-        return true;
-    }
-
-    // It doesn't make sense to prepare a display for which there is no active
-    // config, so return early
-    if (!mActiveConfig) {
-        ALOGE("[%" PRIu64 "] Attempted to prepare, but no config active", mId);
-        return false;
-    }
-
-    allocateRequestedContents();
-    assignHwc1LayerIds();
-
-    mHwc1RequestedContents->retireFenceFd = -1;
-    mHwc1RequestedContents->flags = 0;
-    if (mGeometryChanged) {
-        mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED;
-    }
-    mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
-    mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
-
-    // +1 is for framebuffer target layer.
-    mHwc1RequestedContents->numHwLayers = mLayers.size() + 1;
-    for (auto& layer : mLayers) {
-        auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
-        hwc1Layer.releaseFenceFd = -1;
-        hwc1Layer.acquireFenceFd = -1;
-        ALOGV("Applying states for layer %" PRIu64 " ", layer->getId());
-        layer->applyState(hwc1Layer);
-    }
-
-    prepareFramebufferTarget();
-
-    resetGeometryMarker();
-
-    return true;
-}
-
-void CfHWC2::Display::generateChanges() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    mChanges.reset(new Changes);
-
-    size_t numLayers = mHwc1RequestedContents->numHwLayers;
-    for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
-        const auto& receivedLayer = mHwc1RequestedContents->hwLayers[hwc1Id];
-        if (mHwc1LayerMap.count(hwc1Id) == 0) {
-            ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET,
-                    "generateChanges: HWC1 layer %zd doesn't have a"
-                    " matching HWC2 layer, and isn't the framebuffer target",
-                    hwc1Id);
-            continue;
-        }
-
-        Layer& layer = *mHwc1LayerMap[hwc1Id];
-        updateTypeChanges(receivedLayer, layer);
-        updateLayerRequests(receivedLayer, layer);
-    }
-}
-
-bool CfHWC2::Display::hasChanges() const {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-    return mChanges != nullptr;
-}
-
-Error CfHWC2::Display::set(hwc_display_contents_1& hwcContents) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges || (mChanges->getNumTypes() > 0)) {
-        ALOGE("[%" PRIu64 "] set failed: not validated", mId);
-        return Error::NotValidated;
-    }
-
-    // Set up the client/framebuffer target
-    auto numLayers = hwcContents.numHwLayers;
-
-    // Close acquire fences on FRAMEBUFFER layers, since they will not be used
-    // by HWC
-    for (size_t l = 0; l < numLayers - 1; ++l) {
-        auto& layer = hwcContents.hwLayers[l];
-        if (layer.compositionType == HWC_FRAMEBUFFER) {
-            ALOGV("Closing fence %d for layer %zd", layer.acquireFenceFd, l);
-            close(layer.acquireFenceFd);
-            layer.acquireFenceFd = -1;
-        }
-    }
-
-    auto& clientTargetLayer = hwcContents.hwLayers[numLayers - 1];
-    if (clientTargetLayer.compositionType == HWC_FRAMEBUFFER_TARGET) {
-        clientTargetLayer.handle = mClientTarget.getBuffer();
-        clientTargetLayer.acquireFenceFd = mClientTarget.getFence();
-    } else {
-        ALOGE("[%" PRIu64 "] set: last HWC layer wasn't FRAMEBUFFER_TARGET",
-                mId);
-    }
-
-    mChanges.reset();
-
-    return Error::None;
-}
-
-void CfHWC2::Display::addRetireFence(int fenceFd) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-    mRetireFence.add(fenceFd);
-}
-
-void CfHWC2::Display::addReleaseFences(
-        const hwc_display_contents_1_t& hwcContents) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    size_t numLayers = hwcContents.numHwLayers;
-    for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
-        const auto& receivedLayer = hwcContents.hwLayers[hwc1Id];
-        if (mHwc1LayerMap.count(hwc1Id) == 0) {
-            if (receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET) {
-                ALOGE("addReleaseFences: HWC1 layer %zd doesn't have a"
-                        " matching HWC2 layer, and isn't the framebuffer"
-                        " target", hwc1Id);
-            }
-            // Close the framebuffer target release fence since we will use the
-            // display retire fence instead
-            if (receivedLayer.releaseFenceFd != -1) {
-                close(receivedLayer.releaseFenceFd);
-            }
-            continue;
-        }
-
-        Layer& layer = *mHwc1LayerMap[hwc1Id];
-        ALOGV("Adding release fence %d to layer %" PRIu64,
-                receivedLayer.releaseFenceFd, layer.getId());
-        layer.addReleaseFence(receivedLayer.releaseFenceFd);
-    }
-}
-
-bool CfHWC2::Display::hasColorTransform() const {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-    return mHasColorTransform;
-}
-
-static std::string hwc1CompositionString(int32_t type) {
-    switch (type) {
-        case HWC_FRAMEBUFFER: return "Framebuffer";
-        case HWC_OVERLAY: return "Overlay";
-        case HWC_BACKGROUND: return "Background";
-        case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget";
-        case HWC_SIDEBAND: return "Sideband";
-        case HWC_CURSOR_OVERLAY: return "CursorOverlay";
-        default:
-            return std::string("Unknown (") + std::to_string(type) + ")";
-    }
-}
-
-static std::string hwc1TransformString(int32_t transform) {
-    switch (transform) {
-        case 0: return "None";
-        case HWC_TRANSFORM_FLIP_H: return "FlipH";
-        case HWC_TRANSFORM_FLIP_V: return "FlipV";
-        case HWC_TRANSFORM_ROT_90: return "Rotate90";
-        case HWC_TRANSFORM_ROT_180: return "Rotate180";
-        case HWC_TRANSFORM_ROT_270: return "Rotate270";
-        case HWC_TRANSFORM_FLIP_H_ROT_90: return "FlipHRotate90";
-        case HWC_TRANSFORM_FLIP_V_ROT_90: return "FlipVRotate90";
-        default:
-            return std::string("Unknown (") + std::to_string(transform) + ")";
-    }
-}
-
-static std::string hwc1BlendModeString(int32_t mode) {
-    switch (mode) {
-        case HWC_BLENDING_NONE: return "None";
-        case HWC_BLENDING_PREMULT: return "Premultiplied";
-        case HWC_BLENDING_COVERAGE: return "Coverage";
-        default:
-            return std::string("Unknown (") + std::to_string(mode) + ")";
-    }
-}
-
-static std::string rectString(hwc_rect_t rect) {
-    std::stringstream output;
-    output << "[" << rect.left << ", " << rect.top << ", ";
-    output << rect.right << ", " << rect.bottom << "]";
-    return output.str();
-}
-
-static std::string approximateFloatString(float f) {
-    if (static_cast<float>(static_cast<int32_t>(f)) == f) {
-        return std::to_string(static_cast<int32_t>(f));
-    }
-    int32_t truncated = static_cast<int32_t>(f * 10);
-    bool approximate = (static_cast<float>(truncated) != f * 10);
-    const size_t BUFFER_SIZE = 32;
-    char buffer[BUFFER_SIZE] = {};
-    auto bytesWritten = snprintf(buffer, BUFFER_SIZE,
-            "%s%.1f", approximate ? "~" : "", f);
-    return std::string(buffer, bytesWritten);
-}
-
-static std::string frectString(hwc_frect_t frect) {
-    std::stringstream output;
-    output << "[" << approximateFloatString(frect.left) << ", ";
-    output << approximateFloatString(frect.top) << ", ";
-    output << approximateFloatString(frect.right) << ", ";
-    output << approximateFloatString(frect.bottom) << "]";
-    return output.str();
-}
-
-static std::string colorString(hwc_color_t color) {
-    std::stringstream output;
-    output << "RGBA [";
-    output << static_cast<int32_t>(color.r) << ", ";
-    output << static_cast<int32_t>(color.g) << ", ";
-    output << static_cast<int32_t>(color.b) << ", ";
-    output << static_cast<int32_t>(color.a) << "]";
-    return output.str();
-}
-
-static std::string alphaString(float f) {
-    const size_t BUFFER_SIZE = 8;
-    char buffer[BUFFER_SIZE] = {};
-    auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f);
-    return std::string(buffer, bytesWritten);
-}
-
-static std::string to_string(const hwc_layer_1_t& hwcLayer,
-        int32_t hwc1MinorVersion) {
-    const char* fill = "          ";
-
-    std::stringstream output;
-
-    output << "  Composition: " <<
-            hwc1CompositionString(hwcLayer.compositionType);
-
-    if (hwcLayer.compositionType == HWC_BACKGROUND) {
-        output << "  Color: " << colorString(hwcLayer.backgroundColor) << '\n';
-    } else if (hwcLayer.compositionType == HWC_SIDEBAND) {
-        output << "  Stream: " << hwcLayer.sidebandStream << '\n';
-    } else {
-        output << "  Buffer: " << hwcLayer.handle << "/" <<
-                hwcLayer.acquireFenceFd << '\n';
-    }
-
-    output << fill << "Display frame: " << rectString(hwcLayer.displayFrame) <<
-            '\n';
-
-    output << fill << "Source crop: ";
-    if (hwc1MinorVersion >= 3) {
-        output << frectString(hwcLayer.sourceCropf) << '\n';
-    } else {
-        output << rectString(hwcLayer.sourceCropi) << '\n';
-    }
-
-    output << fill << "Transform: " << hwc1TransformString(hwcLayer.transform);
-    output << "  Blend mode: " << hwc1BlendModeString(hwcLayer.blending);
-    if (hwcLayer.planeAlpha != 0xFF) {
-        output << "  Alpha: " << alphaString(hwcLayer.planeAlpha / 255.0f);
-    }
-    output << '\n';
-
-    if (hwcLayer.hints != 0) {
-        output << fill << "Hints:";
-        if ((hwcLayer.hints & HWC_HINT_TRIPLE_BUFFER) != 0) {
-            output << " TripleBuffer";
-        }
-        if ((hwcLayer.hints & HWC_HINT_CLEAR_FB) != 0) {
-            output << " ClearFB";
-        }
-        output << '\n';
-    }
-
-    if (hwcLayer.flags != 0) {
-        output << fill << "Flags:";
-        if ((hwcLayer.flags & HWC_SKIP_LAYER) != 0) {
-            output << " SkipLayer";
-        }
-        if ((hwcLayer.flags & HWC_IS_CURSOR_LAYER) != 0) {
-            output << " IsCursorLayer";
-        }
-        output << '\n';
-    }
-
-    return output.str();
-}
-
-static std::string to_string(const hwc_display_contents_1_t& hwcContents,
-        int32_t hwc1MinorVersion) {
-    const char* fill = "      ";
-
-    std::stringstream output;
-    output << fill << "Geometry changed: " <<
-            ((hwcContents.flags & HWC_GEOMETRY_CHANGED) != 0 ? "Y\n" : "N\n");
-
-    output << fill << hwcContents.numHwLayers << " Layer" <<
-            ((hwcContents.numHwLayers == 1) ? "\n" : "s\n");
-    for (size_t layer = 0; layer < hwcContents.numHwLayers; ++layer) {
-        output << fill << "  Layer " << layer;
-        output << to_string(hwcContents.hwLayers[layer], hwc1MinorVersion);
-    }
-
-    if (hwcContents.outbuf != nullptr) {
-        output << fill << "Output buffer: " << hwcContents.outbuf << "/" <<
-                hwcContents.outbufAcquireFenceFd << '\n';
-    }
-
-    return output.str();
-}
-
-std::string CfHWC2::Display::dump() const {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    std::stringstream output;
-
-    output << "  Display " << mId << ": ";
-    output << to_string(mType) << "  ";
-    output << "HWC1 ID: " << mHwc1Id << "  ";
-    output << "Power mode: " << to_string(mPowerMode) << "  ";
-    output << "Vsync: " << to_string(mVsyncEnabled) << '\n';
-
-    output << "    Color modes [active]:";
-    for (const auto& mode : mColorModes) {
-        if (mode == mActiveColorMode) {
-            output << " [" << mode << ']';
-        } else {
-            output << " " << mode;
-        }
-    }
-    output << '\n';
-
-    output << "    " << mConfigs.size() << " Config" <<
-            (mConfigs.size() == 1 ? "" : "s") << " (* active)\n";
-    for (const auto& config : mConfigs) {
-        output << (config == mActiveConfig ? "    * " : "      ");
-        output << config->toString(true) << '\n';
-    }
-
-    output << "    " << mLayers.size() << " Layer" <<
-            (mLayers.size() == 1 ? "" : "s") << '\n';
-    for (const auto& layer : mLayers) {
-        output << layer->dump();
-    }
-
-    output << "    Client target: " << mClientTarget.getBuffer() << '\n';
-
-    if (mOutputBuffer.getBuffer() != nullptr) {
-        output << "    Output buffer: " << mOutputBuffer.getBuffer() << '\n';
-    }
-
-    if (mHwc1RequestedContents) {
-        output << "    Last requested HWC1 state\n";
-        output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion);
-    }
-
-    return output.str();
-}
-
-hwc_rect_t* CfHWC2::Display::GetRects(size_t numRects) {
-    if (numRects == 0) {
-        return nullptr;
-    }
-
-    if (numRects > mNumAvailableRects) {
-        // This should NEVER happen since we calculated how many rects the
-        // display would need.
-        ALOGE("Rect allocation failure! SF is likely to crash soon!");
-        return nullptr;
-
-    }
-    hwc_rect_t* rects = mNextAvailableRect;
-    mNextAvailableRect += numRects;
-    mNumAvailableRects -= numRects;
-    return rects;
-}
-
-hwc_display_contents_1* CfHWC2::Display::getDisplayContents() {
-    return mHwc1RequestedContents.get();
-}
-
-void CfHWC2::Display::Config::setAttribute(HWC2::Attribute attribute,
-        int32_t value) {
-    mAttributes[attribute] = value;
-}
-
-int32_t CfHWC2::Display::Config::getAttribute(Attribute attribute) const {
-    if (mAttributes.count(attribute) == 0) {
-        return -1;
-    }
-    return mAttributes.at(attribute);
-}
-
-void CfHWC2::Display::Config::setHwc1Id(uint32_t id) {
-    android_color_mode_t colorMode = static_cast<android_color_mode_t>(getAttribute(ColorMode));
-    mHwc1Ids.emplace(colorMode, id);
-}
-
-bool CfHWC2::Display::Config::hasHwc1Id(uint32_t id) const {
-    for (const auto& idPair : mHwc1Ids) {
-        if (id == idPair.second) {
-            return true;
-        }
-    }
-    return false;
-}
-
-Error CfHWC2::Display::Config::getColorModeForHwc1Id(
-        uint32_t id, android_color_mode_t* outMode) const {
-    for (const auto& idPair : mHwc1Ids) {
-        if (id == idPair.second) {
-            *outMode = idPair.first;
-            return Error::None;
-        }
-    }
-    ALOGE("Unable to find color mode for HWC ID %" PRIu32 " on config %u", id, mId);
-    return Error::BadParameter;
-}
-
-Error CfHWC2::Display::Config::getHwc1IdForColorMode(android_color_mode_t mode,
-        uint32_t* outId) const {
-    for (const auto& idPair : mHwc1Ids) {
-        if (mode == idPair.first) {
-            *outId = idPair.second;
-            return Error::None;
-        }
-    }
-    ALOGE("Unable to find HWC1 ID for color mode %d on config %u", mode, mId);
-    return Error::BadParameter;
-}
-
-bool CfHWC2::Display::Config::merge(const Config& other) {
-    auto attributes = {HWC2::Attribute::Width, HWC2::Attribute::Height,
-            HWC2::Attribute::VsyncPeriod, HWC2::Attribute::DpiX,
-            HWC2::Attribute::DpiY};
-    for (auto attribute : attributes) {
-        if (getAttribute(attribute) != other.getAttribute(attribute)) {
-            return false;
-        }
-    }
-    android_color_mode_t otherColorMode =
-            static_cast<android_color_mode_t>(other.getAttribute(ColorMode));
-    if (mHwc1Ids.count(otherColorMode) != 0) {
-        ALOGE("Attempted to merge two configs (%u and %u) which appear to be "
-                "identical", mHwc1Ids.at(otherColorMode),
-                other.mHwc1Ids.at(otherColorMode));
-        return false;
-    }
-    mHwc1Ids.emplace(otherColorMode,
-            other.mHwc1Ids.at(otherColorMode));
-    return true;
-}
-
-std::set<android_color_mode_t> CfHWC2::Display::Config::getColorModes() const {
-    std::set<android_color_mode_t> colorModes;
-    for (const auto& idPair : mHwc1Ids) {
-        colorModes.emplace(idPair.first);
-    }
-    return colorModes;
-}
-
-std::string CfHWC2::Display::Config::toString(bool splitLine) const {
-    std::string output;
-
-    const size_t BUFFER_SIZE = 100;
-    char buffer[BUFFER_SIZE] = {};
-    auto writtenBytes = snprintf(buffer, BUFFER_SIZE,
-            "%u x %u", mAttributes.at(HWC2::Attribute::Width),
-            mAttributes.at(HWC2::Attribute::Height));
-    output.append(buffer, writtenBytes);
-
-    if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) {
-        std::memset(buffer, 0, BUFFER_SIZE);
-        writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz",
-                1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod));
-        output.append(buffer, writtenBytes);
-    }
-
-    if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
-            mAttributes.at(HWC2::Attribute::DpiX) != -1) {
-        std::memset(buffer, 0, BUFFER_SIZE);
-        writtenBytes =
-                snprintf(buffer, BUFFER_SIZE, ", DPI: %.1f x %.1f",
-                         static_cast<float>(mAttributes.at(HWC2::Attribute::DpiX)) / 1000.0f,
-                         static_cast<float>(mAttributes.at(HWC2::Attribute::DpiY)) / 1000.0f);
-        output.append(buffer, writtenBytes);
-    }
-
-    std::memset(buffer, 0, BUFFER_SIZE);
-    if (splitLine) {
-        writtenBytes = snprintf(buffer, BUFFER_SIZE,
-                "\n        HWC1 ID/Color transform:");
-    } else {
-        writtenBytes = snprintf(buffer, BUFFER_SIZE,
-                ", HWC1 ID/Color transform:");
-    }
-    output.append(buffer, writtenBytes);
-
-
-    for (const auto& id : mHwc1Ids) {
-        android_color_mode_t colorMode = id.first;
-        uint32_t hwc1Id = id.second;
-        std::memset(buffer, 0, BUFFER_SIZE);
-        if (colorMode == mDisplay.mActiveColorMode) {
-            writtenBytes = snprintf(buffer, BUFFER_SIZE, " [%u/%d]", hwc1Id,
-                    colorMode);
-        } else {
-            writtenBytes = snprintf(buffer, BUFFER_SIZE, " %u/%d", hwc1Id,
-                    colorMode);
-        }
-        output.append(buffer, writtenBytes);
-    }
-
-    return output;
-}
-
-std::shared_ptr<const CfHWC2::Display::Config>
-        CfHWC2::Display::getConfig(hwc2_config_t configId) const {
-    if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
-        return nullptr;
-    }
-    return mConfigs[configId];
-}
-
-void CfHWC2::Display::populateColorModes() {
-    mColorModes = mConfigs[0]->getColorModes();
-    for (const auto& config : mConfigs) {
-        std::set<android_color_mode_t> intersection;
-        auto configModes = config->getColorModes();
-        std::set_intersection(mColorModes.cbegin(), mColorModes.cend(),
-                configModes.cbegin(), configModes.cend(),
-                std::inserter(intersection, intersection.begin()));
-        std::swap(intersection, mColorModes);
-    }
-}
-
-void CfHWC2::Display::initializeActiveConfig() {
-    if (mDevice.mHwc1Device->getActiveConfig == nullptr) {
-        ALOGV("getActiveConfig is null, choosing config 0");
-        mActiveConfig = mConfigs[0];
-        mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-        return;
-    }
-
-    auto activeConfig = mDevice.mHwc1Device->getActiveConfig(
-            mDevice.mHwc1Device, mHwc1Id);
-
-    // Some devices startup without an activeConfig:
-    // We need to set one ourselves.
-    if (activeConfig == HWC_ERROR) {
-        ALOGV("There is no active configuration: Picking the first one: 0.");
-        const int defaultIndex = 0;
-        mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, defaultIndex);
-        activeConfig = defaultIndex;
-    }
-
-    for (const auto& config : mConfigs) {
-        if (config->hasHwc1Id(activeConfig)) {
-            ALOGE("Setting active config to %d for HWC1 config %u", config->getId(), activeConfig);
-            mActiveConfig = config;
-            if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
-                // This should never happen since we checked for the config's presence before
-                // setting it as active.
-                ALOGE("Unable to find color mode for active HWC1 config %d", config->getId());
-                mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-            }
-            break;
-        }
-    }
-    if (!mActiveConfig) {
-        ALOGV("Unable to find active HWC1 config %u, defaulting to "
-                "config 0", activeConfig);
-        mActiveConfig = mConfigs[0];
-        mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-    }
-
-
-
-
-}
-
-void CfHWC2::Display::allocateRequestedContents() {
-    // What needs to be allocated:
-    // 1 hwc_display_contents_1_t
-    // 1 hwc_layer_1_t for each layer
-    // 1 hwc_rect_t for each layer's surfaceDamage
-    // 1 hwc_rect_t for each layer's visibleRegion
-    // 1 hwc_layer_1_t for the framebuffer
-    // 1 hwc_rect_t for the framebuffer's visibleRegion
-
-    // Count # of surfaceDamage
-    size_t numSurfaceDamages = 0;
-    for (const auto& layer : mLayers) {
-        numSurfaceDamages += layer->getNumSurfaceDamages();
-    }
-
-    // Count # of visibleRegions (start at 1 for mandatory framebuffer target
-    // region)
-    size_t numVisibleRegion = 1;
-    for (const auto& layer : mLayers) {
-        numVisibleRegion += layer->getNumVisibleRegions();
-    }
-
-    size_t numRects = numVisibleRegion + numSurfaceDamages;
-    auto numLayers = mLayers.size() + 1;
-    size_t size = sizeof(hwc_display_contents_1_t) +
-            sizeof(hwc_layer_1_t) * numLayers +
-            sizeof(hwc_rect_t) * numRects;
-    auto contents = static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
-    mHwc1RequestedContents.reset(contents);
-    mNextAvailableRect = reinterpret_cast<hwc_rect_t*>(&contents->hwLayers[numLayers]);
-    mNumAvailableRects = numRects;
-}
-
-void CfHWC2::Display::assignHwc1LayerIds() {
-    mHwc1LayerMap.clear();
-    size_t nextHwc1Id = 0;
-    for (auto& layer : mLayers) {
-        mHwc1LayerMap[nextHwc1Id] = layer;
-        layer->setHwc1Id(nextHwc1Id++);
-    }
-}
-
-void CfHWC2::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer,
-        const Layer& layer) {
-    auto layerId = layer.getId();
-    switch (hwc1Layer.compositionType) {
-        case HWC_FRAMEBUFFER:
-            if (layer.getCompositionType() != Composition::Client) {
-                mChanges->addTypeChange(layerId, Composition::Client);
-            }
-            break;
-        case HWC_OVERLAY:
-            if (layer.getCompositionType() != Composition::Device) {
-                mChanges->addTypeChange(layerId, Composition::Device);
-            }
-            break;
-        case HWC_BACKGROUND:
-            ALOGE_IF(layer.getCompositionType() != Composition::SolidColor,
-                    "updateTypeChanges: HWC1 requested BACKGROUND, but HWC2"
-                    " wasn't expecting SolidColor");
-            break;
-        case HWC_FRAMEBUFFER_TARGET:
-            // Do nothing, since it shouldn't be modified by HWC1
-            break;
-        case HWC_SIDEBAND:
-            ALOGE_IF(layer.getCompositionType() != Composition::Sideband,
-                    "updateTypeChanges: HWC1 requested SIDEBAND, but HWC2"
-                    " wasn't expecting Sideband");
-            break;
-        case HWC_CURSOR_OVERLAY:
-            ALOGE_IF(layer.getCompositionType() != Composition::Cursor,
-                    "updateTypeChanges: HWC1 requested CURSOR_OVERLAY, but"
-                    " HWC2 wasn't expecting Cursor");
-            break;
-    }
-}
-
-void CfHWC2::Display::updateLayerRequests(
-        const hwc_layer_1_t& hwc1Layer, const Layer& layer) {
-    if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) {
-        mChanges->addLayerRequest(layer.getId(),
-                LayerRequest::ClearClientTarget);
-    }
-}
-
-void CfHWC2::Display::prepareFramebufferTarget() {
-    // We check that mActiveConfig is valid in Display::prepare
-    int32_t width = mActiveConfig->getAttribute(Attribute::Width);
-    int32_t height = mActiveConfig->getAttribute(Attribute::Height);
-
-    auto& hwc1Target = mHwc1RequestedContents->hwLayers[mLayers.size()];
-    hwc1Target.compositionType = HWC_FRAMEBUFFER_TARGET;
-    hwc1Target.releaseFenceFd = -1;
-    hwc1Target.hints = 0;
-    hwc1Target.flags = 0;
-    hwc1Target.transform = 0;
-    hwc1Target.blending = HWC_BLENDING_PREMULT;
-    if (mDevice.getHwc1MinorVersion() < 3) {
-        hwc1Target.sourceCropi = {0, 0, width, height};
-    } else {
-        hwc1Target.sourceCropf = {0.0f, 0.0f, static_cast<float>(width),
-                static_cast<float>(height)};
-    }
-    hwc1Target.displayFrame = {0, 0, width, height};
-    hwc1Target.planeAlpha = 255;
-
-    hwc1Target.visibleRegionScreen.numRects = 1;
-    hwc_rect_t* rects = GetRects(1);
-    rects[0].left = 0;
-    rects[0].top = 0;
-    rects[0].right = width;
-    rects[0].bottom = height;
-    hwc1Target.visibleRegionScreen.rects = rects;
-
-    // We will set this to the correct value in set
-    hwc1Target.acquireFenceFd = -1;
-}
-
-// Layer functions
-
-std::atomic<hwc2_layer_t> CfHWC2::Layer::sNextId(1);
-
-CfHWC2::Layer::Layer(Display& display)
-  : mId(sNextId++),
-    mDisplay(display),
-    mBuffer(),
-    mSurfaceDamage(),
-    mBlendMode(BlendMode::None),
-    mColor({0, 0, 0, 0}),
-    mCompositionType(Composition::Invalid),
-    mDisplayFrame({0, 0, -1, -1}),
-    mPlaneAlpha(0.0f),
-    mSidebandStream(nullptr),
-    mSourceCrop({0.0f, 0.0f, -1.0f, -1.0f}),
-    mTransform(Transform::None),
-    mVisibleRegion(),
-    mZ(0),
-    mReleaseFence(),
-    mHwc1Id(0),
-    mHasUnsupportedPlaneAlpha(false) {}
-
-bool CfHWC2::SortLayersByZ::operator()(const std::shared_ptr<Layer>& lhs,
-                                               const std::shared_ptr<Layer>& rhs) const {
-    return lhs->getZ() < rhs->getZ();
-}
-
-Error CfHWC2::Layer::setBuffer(buffer_handle_t buffer,
-        int32_t acquireFence) {
-    ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId);
-    mBuffer.setBuffer(buffer);
-    mBuffer.setFence(acquireFence);
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setCursorPosition(int32_t x, int32_t y) {
-    if (mCompositionType != Composition::Cursor) {
-        return Error::BadLayer;
-    }
-
-    if (mDisplay.hasChanges()) {
-        return Error::NotValidated;
-    }
-
-    auto displayId = mDisplay.getHwc1Id();
-    auto hwc1Device = mDisplay.getDevice().getHwc1Device();
-    hwc1Device->setCursorPositionAsync(hwc1Device, displayId, x, y);
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setSurfaceDamage(hwc_region_t damage) {
-    // HWC1 supports surface damage starting only with version 1.5.
-    if (mDisplay.getDevice().mHwc1MinorVersion < 5) {
-        return Error::None;
-    }
-    mSurfaceDamage.resize(damage.numRects);
-    std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin());
-    return Error::None;
-}
-
-// Layer state functions
-
-Error CfHWC2::Layer::setBlendMode(BlendMode mode) {
-    mBlendMode = mode;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setColor(hwc_color_t color) {
-    mColor = color;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setCompositionType(Composition type) {
-    mCompositionType = type;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setDataspace(android_dataspace_t) {
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setDisplayFrame(hwc_rect_t frame) {
-    mDisplayFrame = frame;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setPlaneAlpha(float alpha) {
-    mPlaneAlpha = alpha;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setSidebandStream(const native_handle_t* stream) {
-    mSidebandStream = stream;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setSourceCrop(hwc_frect_t crop) {
-    mSourceCrop = crop;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setTransform(Transform transform) {
-    mTransform = transform;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
-    return rect1.left == rect2.left &&
-            rect1.right == rect2.right &&
-            rect1.top == rect2.top &&
-            rect1.bottom == rect2.bottom;
-}
-
-Error CfHWC2::Layer::setVisibleRegion(hwc_region_t visible) {
-    if ((getNumVisibleRegions() != visible.numRects) ||
-        !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
-                    compareRects)) {
-        mVisibleRegion.resize(visible.numRects);
-        std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
-        mDisplay.markGeometryChanged();
-    }
-    return Error::None;
-}
-
-Error CfHWC2::Layer::setZ(uint32_t z) {
-    mZ = z;
-    return Error::None;
-}
-
-void CfHWC2::Layer::addReleaseFence(int fenceFd) {
-    ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId);
-    mReleaseFence.add(fenceFd);
-}
-
-const sp<MiniFence>& CfHWC2::Layer::getReleaseFence() const {
-    return mReleaseFence.get();
-}
-
-void CfHWC2::Layer::applyState(hwc_layer_1_t& hwc1Layer) {
-    applyCommonState(hwc1Layer);
-    applyCompositionType(hwc1Layer);
-    switch (mCompositionType) {
-        case Composition::SolidColor : applySolidColorState(hwc1Layer); break;
-        case Composition::Sideband : applySidebandState(hwc1Layer); break;
-        default: applyBufferState(hwc1Layer); break;
-    }
-}
-
-static std::string regionStrings(const std::vector<hwc_rect_t>& visibleRegion,
-        const std::vector<hwc_rect_t>& surfaceDamage) {
-    std::string regions;
-    regions += "        Visible Region";
-    regions.resize(40, ' ');
-    regions += "Surface Damage\n";
-
-    size_t numPrinted = 0;
-    size_t maxSize = std::max(visibleRegion.size(), surfaceDamage.size());
-    while (numPrinted < maxSize) {
-        std::string line("        ");
-        if (visibleRegion.empty() && numPrinted == 0) {
-            line += "None";
-        } else if (numPrinted < visibleRegion.size()) {
-            line += rectString(visibleRegion[numPrinted]);
-        }
-        line.resize(40, ' ');
-        if (surfaceDamage.empty() && numPrinted == 0) {
-            line += "None";
-        } else if (numPrinted < surfaceDamage.size()) {
-            line += rectString(surfaceDamage[numPrinted]);
-        }
-        line += '\n';
-        regions += line;
-        ++numPrinted;
-    }
-    return regions;
-}
-
-std::string CfHWC2::Layer::dump() const {
-    std::stringstream output;
-    const char* fill = "      ";
-
-    output << fill << to_string(mCompositionType);
-    output << " Layer  HWC2/1: " << mId << "/" << mHwc1Id << "  ";
-    output << "Z: " << mZ;
-    if (mCompositionType == HWC2::Composition::SolidColor) {
-        output << "  " << colorString(mColor);
-    } else if (mCompositionType == HWC2::Composition::Sideband) {
-        output << "  Handle: " << mSidebandStream << '\n';
-    } else {
-        output << "  Buffer: " << mBuffer.getBuffer() << '\n';
-        output << fill << "  Display frame [LTRB]: " <<
-                rectString(mDisplayFrame) << '\n';
-        output << fill << "  Source crop: " <<
-                frectString(mSourceCrop) << '\n';
-        output << fill << "  Transform: " << to_string(mTransform);
-        output << "  Blend mode: " << to_string(mBlendMode);
-        if (mPlaneAlpha != 1.0f) {
-            output << "  Alpha: " <<
-                alphaString(mPlaneAlpha) << '\n';
-        } else {
-            output << '\n';
-        }
-        output << regionStrings(mVisibleRegion, mSurfaceDamage);
-    }
-    return output.str();
-}
-
-static int getHwc1Blending(HWC2::BlendMode blendMode) {
-    switch (blendMode) {
-        case BlendMode::Coverage: return HWC_BLENDING_COVERAGE;
-        case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT;
-        default: return HWC_BLENDING_NONE;
-    }
-}
-
-void CfHWC2::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer) {
-    auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion();
-    hwc1Layer.blending = getHwc1Blending(mBlendMode);
-    hwc1Layer.displayFrame = mDisplayFrame;
-
-    auto pendingAlpha = mPlaneAlpha;
-    if (minorVersion < 2) {
-        mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
-    } else {
-        hwc1Layer.planeAlpha =
-                static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
-    }
-
-    if (minorVersion < 3) {
-        auto pending = mSourceCrop;
-        hwc1Layer.sourceCropi.left =
-                static_cast<int32_t>(std::ceil(pending.left));
-        hwc1Layer.sourceCropi.top =
-                static_cast<int32_t>(std::ceil(pending.top));
-        hwc1Layer.sourceCropi.right =
-                static_cast<int32_t>(std::floor(pending.right));
-        hwc1Layer.sourceCropi.bottom =
-                static_cast<int32_t>(std::floor(pending.bottom));
-    } else {
-        hwc1Layer.sourceCropf = mSourceCrop;
-    }
-
-    hwc1Layer.transform = static_cast<uint32_t>(mTransform);
-
-    auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
-    hwc1VisibleRegion.numRects = mVisibleRegion.size();
-    hwc_rect_t* rects = mDisplay.GetRects(hwc1VisibleRegion.numRects);
-    hwc1VisibleRegion.rects = rects;
-    for (size_t i = 0; i < mVisibleRegion.size(); i++) {
-        rects[i] = mVisibleRegion[i];
-    }
-}
-
-void CfHWC2::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer) {
-    // If the device does not support background color it is likely to make
-    // assumption regarding backgroundColor and handle (both fields occupy
-    // the same location in hwc_layer_1_t union).
-    // To not confuse these devices we don't set background color and we
-    // make sure handle is a null pointer.
-    if (hasUnsupportedBackgroundColor()) {
-        hwc1Layer.handle = nullptr;
-    } else {
-        hwc1Layer.backgroundColor = mColor;
-    }
-}
-
-void CfHWC2::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer) {
-    hwc1Layer.sidebandStream = mSidebandStream;
-}
-
-void CfHWC2::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer) {
-    hwc1Layer.handle = mBuffer.getBuffer();
-    hwc1Layer.acquireFenceFd = mBuffer.getFence();
-}
-
-void CfHWC2::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer) {
-    // HWC1 never supports color transforms or dataspaces and only sometimes
-    // supports plane alpha (depending on the version). These require us to drop
-    // some or all layers to client composition.
-    if (mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform() ||
-            hasUnsupportedBackgroundColor()) {
-        hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-        hwc1Layer.flags = HWC_SKIP_LAYER;
-        return;
-    }
-
-    hwc1Layer.flags = 0;
-    switch (mCompositionType) {
-        case Composition::Client:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            hwc1Layer.flags |= HWC_SKIP_LAYER;
-            break;
-        case Composition::Device:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            break;
-        case Composition::SolidColor:
-            // In theory the following line should work, but since the HWC1
-            // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
-            // devices may not work correctly. To be on the safe side, we
-            // fall back to client composition.
-            //
-            // hwc1Layer.compositionType = HWC_BACKGROUND;
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            hwc1Layer.flags |= HWC_SKIP_LAYER;
-            break;
-        case Composition::Cursor:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
-                hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
-            }
-            break;
-        case Composition::Sideband:
-            if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
-                hwc1Layer.compositionType = HWC_SIDEBAND;
-            } else {
-                hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-                hwc1Layer.flags |= HWC_SKIP_LAYER;
-            }
-            break;
-        default:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            hwc1Layer.flags |= HWC_SKIP_LAYER;
-            break;
-    }
-    ALOGV("Layer %" PRIu64 " %s set to %d", mId,
-            to_string(mCompositionType).c_str(),
-            hwc1Layer.compositionType);
-    ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, "    and skipping");
-}
-
-// Adapter helpers
-
-void CfHWC2::populateCapabilities() {
-    if (mHwc1MinorVersion >= 3U) {
-        int supportedTypes = 0;
-        auto result = mHwc1Device->query(mHwc1Device,
-                HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes);
-        if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL_BIT) != 0)) {
-            ALOGI("Found support for HWC virtual displays");
-            mHwc1SupportsVirtualDisplays = true;
-        }
-    }
-    if (mHwc1MinorVersion >= 4U) {
-        mCapabilities.insert(Capability::SidebandStream);
-    }
-
-    // Check for HWC background color layer support.
-    if (mHwc1MinorVersion >= 1U) {
-        int backgroundColorSupported = 0;
-        auto result = mHwc1Device->query(mHwc1Device,
-                                         HWC_BACKGROUND_LAYER_SUPPORTED,
-                                         &backgroundColorSupported);
-        if ((result == 0) && (backgroundColorSupported == 1)) {
-            ALOGV("Found support for HWC background color");
-            mHwc1SupportsBackgroundColor = true;
-        }
-    }
-
-    // Some devices might have HWC1 retire fences that accurately emulate
-    // HWC2 present fences when they are deferred, but it's not very reliable.
-    // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices.
-    //mCapabilities.insert(Capability::PresentFenceIsNotReliable);
-}
-
-CfHWC2::Display* CfHWC2::getDisplay(hwc2_display_t id) {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    auto display = mDisplays.find(id);
-    if (display == mDisplays.end()) {
-        return nullptr;
-    }
-
-    return display->second.get();
-}
-
-std::tuple<CfHWC2::Layer*, Error> CfHWC2::getLayer(
-        hwc2_display_t displayId, hwc2_layer_t layerId) {
-    auto display = getDisplay(displayId);
-    if (!display) {
-        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
-    }
-
-    auto layerEntry = mLayers.find(layerId);
-    if (layerEntry == mLayers.end()) {
-        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
-    }
-
-    auto layer = layerEntry->second;
-    if (layer->getDisplay().getId() != displayId) {
-        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
-    }
-    return std::make_tuple(layer.get(), Error::None);
-}
-
-void CfHWC2::populatePrimary() {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
-    mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId();
-    display->setHwc1Id(HWC_DISPLAY_PRIMARY);
-    display->populateConfigs();
-    mDisplays.emplace(display->getId(), std::move(display));
-}
-
-bool CfHWC2::prepareAllDisplays() {
-    ATRACE_CALL();
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    for (const auto& displayPair : mDisplays) {
-        auto& display = displayPair.second;
-        if (!display->prepare()) {
-            return false;
-        }
-    }
-
-    if (mHwc1DisplayMap.count(HWC_DISPLAY_PRIMARY) == 0) {
-        ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
-        return false;
-    }
-
-    // Build an array of hwc_display_contents_1 to call prepare() on HWC1.
-    mHwc1Contents.clear();
-
-    // Always push the primary display
-    auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY];
-    auto& primaryDisplay = mDisplays[primaryDisplayId];
-    mHwc1Contents.push_back(primaryDisplay->getDisplayContents());
-
-    // Push the external display, if present
-    if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) {
-        auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL];
-        auto& externalDisplay = mDisplays[externalDisplayId];
-        mHwc1Contents.push_back(externalDisplay->getDisplayContents());
-    } else {
-        // Even if an external display isn't present, we still need to send
-        // at least two displays down to HWC1
-        mHwc1Contents.push_back(nullptr);
-    }
-
-    // Push the hardware virtual display, if supported and present
-    if (mHwc1MinorVersion >= 3) {
-        if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) {
-            auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL];
-            auto& virtualDisplay = mDisplays[virtualDisplayId];
-            mHwc1Contents.push_back(virtualDisplay->getDisplayContents());
-        } else {
-            mHwc1Contents.push_back(nullptr);
-        }
-    }
-
-    for (auto& displayContents : mHwc1Contents) {
-        if (!displayContents) {
-            continue;
-        }
-
-        ALOGV("Display %zd layers:", mHwc1Contents.size() - 1);
-        for (size_t l = 0; l < displayContents->numHwLayers; ++l) {
-            auto& layer = displayContents->hwLayers[l];
-            ALOGV("  %zd: %d", l, layer.compositionType);
-        }
-    }
-
-    ALOGV("Calling HWC1 prepare");
-    {
-        ATRACE_NAME("HWC1 prepare");
-        mHwc1Device->prepare(mHwc1Device, mHwc1Contents.size(),
-                mHwc1Contents.data());
-    }
-
-    for (size_t c = 0; c < mHwc1Contents.size(); ++c) {
-        auto& contents = mHwc1Contents[c];
-        if (!contents) {
-            continue;
-        }
-        ALOGV("Display %zd layers:", c);
-        for (size_t l = 0; l < contents->numHwLayers; ++l) {
-            ALOGV("  %zd: %d", l, contents->hwLayers[l].compositionType);
-        }
-    }
-
-    // Return the received contents to their respective displays
-    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
-        if (mHwc1Contents[hwc1Id] == nullptr) {
-            continue;
-        }
-
-        auto displayId = mHwc1DisplayMap[hwc1Id];
-        auto& display = mDisplays[displayId];
-        display->generateChanges();
-    }
-
-    return true;
-}
-
-void dumpHWC1Message(hwc_composer_device_1* device, size_t numDisplays,
-                     hwc_display_contents_1_t** displays) {
-    ALOGV("*****************************");
-    size_t displayId = 0;
-    while (displayId < numDisplays) {
-        hwc_display_contents_1_t* display = displays[displayId];
-
-        ALOGV("hwc_display_contents_1_t[%zu] @0x%p", displayId, display);
-        if (display == nullptr) {
-            displayId++;
-            continue;
-        }
-        ALOGV("  retirefd:0x%08x", display->retireFenceFd);
-        ALOGV("  outbuf  :0x%p", display->outbuf);
-        ALOGV("  outbuffd:0x%08x", display->outbufAcquireFenceFd);
-        ALOGV("  flags   :0x%08x", display->flags);
-        for(size_t layerId=0 ; layerId < display->numHwLayers ; layerId++) {
-            hwc_layer_1_t& layer = display->hwLayers[layerId];
-            ALOGV("    Layer[%zu]:", layerId);
-            ALOGV("      composition        : 0x%08x", layer.compositionType);
-            ALOGV("      hints              : 0x%08x", layer.hints);
-            ALOGV("      flags              : 0x%08x", layer.flags);
-            ALOGV("      handle             : 0x%p", layer.handle);
-            ALOGV("      transform          : 0x%08x", layer.transform);
-            ALOGV("      blending           : 0x%08x", layer.blending);
-            ALOGV("      sourceCropf        : %f, %f, %f, %f",
-                  layer.sourceCropf.left,
-                  layer.sourceCropf.top,
-                  layer.sourceCropf.right,
-                  layer.sourceCropf.bottom);
-            ALOGV("      displayFrame       : %d, %d, %d, %d",
-                  layer.displayFrame.left,
-                  layer.displayFrame.left,
-                  layer.displayFrame.left,
-                  layer.displayFrame.left);
-            hwc_region_t& visReg = layer.visibleRegionScreen;
-            ALOGV("      visibleRegionScreen: #0x%08zx[@0x%p]",
-                  visReg.numRects,
-                  visReg.rects);
-            for (size_t visRegId=0; visRegId < visReg.numRects ; visRegId++) {
-                if (layer.visibleRegionScreen.rects == nullptr) {
-                    ALOGV("        null");
-                } else {
-                    ALOGV("        visibleRegionScreen[%zu] %d, %d, %d, %d",
-                          visRegId,
-                          visReg.rects[visRegId].left,
-                          visReg.rects[visRegId].top,
-                          visReg.rects[visRegId].right,
-                          visReg.rects[visRegId].bottom);
-                }
-            }
-            ALOGV("      acquireFenceFd     : 0x%08x", layer.acquireFenceFd);
-            ALOGV("      releaseFenceFd     : 0x%08x", layer.releaseFenceFd);
-            ALOGV("      planeAlpha         : 0x%08x", layer.planeAlpha);
-            if (getMinorVersion(device) < 5)
-               continue;
-            ALOGV("      surfaceDamage      : #0x%08zx[@0x%p]",
-                  layer.surfaceDamage.numRects,
-                  layer.surfaceDamage.rects);
-            for (size_t sdId=0; sdId < layer.surfaceDamage.numRects ; sdId++) {
-                if (layer.surfaceDamage.rects == nullptr) {
-                    ALOGV("      null");
-                } else {
-                    ALOGV("      surfaceDamage[%zu] %d, %d, %d, %d",
-                          sdId,
-                          layer.surfaceDamage.rects[sdId].left,
-                          layer.surfaceDamage.rects[sdId].top,
-                          layer.surfaceDamage.rects[sdId].right,
-                          layer.surfaceDamage.rects[sdId].bottom);
-                }
-            }
-        }
-        displayId++;
-    }
-    ALOGV("-----------------------------");
-}
-
-Error CfHWC2::setAllDisplays() {
-    ATRACE_CALL();
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    // Make sure we're ready to validate
-    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
-        if (mHwc1Contents[hwc1Id] == nullptr) {
-            continue;
-        }
-
-        auto displayId = mHwc1DisplayMap[hwc1Id];
-        auto& display = mDisplays[displayId];
-        Error error = display->set(*mHwc1Contents[hwc1Id]);
-        if (error != Error::None) {
-            ALOGE("setAllDisplays: Failed to set display %zd: %s", hwc1Id,
-                    to_string(error).c_str());
-            return error;
-        }
-    }
-
-    ALOGV("Calling HWC1 set");
-    {
-        ATRACE_NAME("HWC1 set");
-        //dumpHWC1Message(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data());
-        mHwc1Device->set(mHwc1Device, mHwc1Contents.size(),
-                mHwc1Contents.data());
-    }
-
-    // Add retire and release fences
-    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
-        if (mHwc1Contents[hwc1Id] == nullptr) {
-            continue;
-        }
-
-        auto displayId = mHwc1DisplayMap[hwc1Id];
-        auto& display = mDisplays[displayId];
-        auto retireFenceFd = mHwc1Contents[hwc1Id]->retireFenceFd;
-        ALOGV("setAllDisplays: Adding retire fence %d to display %zd",
-                retireFenceFd, hwc1Id);
-        display->addRetireFence(mHwc1Contents[hwc1Id]->retireFenceFd);
-        display->addReleaseFences(*mHwc1Contents[hwc1Id]);
-    }
-
-    return Error::None;
-}
-
-void CfHWC2::hwc1Invalidate() {
-    ALOGV("Received hwc1Invalidate");
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    // If the HWC2-side callback hasn't been registered yet, buffer this until
-    // it is registered.
-    if (mCallbacks.count(Callback::Refresh) == 0) {
-        mHasPendingInvalidate = true;
-        return;
-    }
-
-    const auto& callbackInfo = mCallbacks[Callback::Refresh];
-    std::vector<hwc2_display_t> displays;
-    for (const auto& displayPair : mDisplays) {
-        displays.emplace_back(displayPair.first);
-    }
-
-    // Call back without the state lock held.
-    lock.unlock();
-
-    auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(callbackInfo.pointer);
-    for (auto display : displays) {
-        refresh(callbackInfo.data, display);
-    }
-}
-
-void CfHWC2::hwc1Vsync(int hwc1DisplayId, int64_t timestamp) {
-    ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp);
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    // If the HWC2-side callback hasn't been registered yet, buffer this until
-    // it is registered.
-    if (mCallbacks.count(Callback::Vsync) == 0) {
-        mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp);
-        return;
-    }
-
-    if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-        ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId);
-        return;
-    }
-
-    const auto& callbackInfo = mCallbacks[Callback::Vsync];
-    auto displayId = mHwc1DisplayMap[hwc1DisplayId];
-
-    // Call back without the state lock held.
-    lock.unlock();
-
-    auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
-    vsync(callbackInfo.data, displayId, timestamp);
-}
-
-void CfHWC2::hwc1Hotplug(int hwc1DisplayId, int connected) {
-    ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
-
-    if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
-        ALOGE("hwc1Hotplug: Received hotplug for non-external display");
-        return;
-    }
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    hwc2_display_t displayId = UINT64_MAX;
-    if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-        if (connected == 0) {
-            ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
-            return;
-        }
-
-        // Create a new display on connect
-        auto display = std::make_shared<CfHWC2::Display>(*this,
-                HWC2::DisplayType::Physical);
-        display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
-        display->populateConfigs();
-        displayId = display->getId();
-        mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
-        mDisplays.emplace(displayId, std::move(display));
-    } else {
-        if (connected != 0) {
-            ALOGW("hwc1Hotplug: Received connect for previously connected "
-                    "display");
-            return;
-        }
-
-        // Disconnect an existing display
-        displayId = mHwc1DisplayMap[hwc1DisplayId];
-        mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
-        mDisplays.erase(displayId);
-    }
-
-    // If the HWC2-side callback hasn't been registered yet, buffer this until
-    // it is registered
-    if (mCallbacks.count(Callback::Hotplug) == 0) {
-        mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
-        return;
-    }
-
-    const auto& callbackInfo = mCallbacks[Callback::Hotplug];
-
-    // Call back without the state lock held
-    lock.unlock();
-
-    auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
-    auto hwc2Connected = (connected == 0) ?
-            HWC2::Connection::Disconnected : HWC2::Connection::Connected;
-    hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
-}
-
-static int hwc2DevOpen(const struct hw_module_t *module, const char *name,
-        struct hw_device_t **dev) {
-    ALOGV("%s()", __FUNCTION__);
-    if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
-        ALOGE("Invalid module name- %s", name);
-        return -EINVAL;
-    }
-
-    std::unique_ptr<cvd::ScreenView> screen_view(new cvd::VsocketScreenView());
-    if (!screen_view) {
-      ALOGE("Failed to instantiate screen view");
-      return -1;
-    }
-
-    hw_device_t* device;
-    int error = cvd::cvd_hwc_open(std::move(screen_view), module, name, &device);
-    if (error) {
-        ALOGE("failed to open hwcomposer device: %s", strerror(-error));
-        return -1;
-    }
-
-    int major = (device->version >> 24) & 0xf;
-    ALOGV("%s(): major=%d", __FUNCTION__, major);
-    if (major < 2) {
-        CfHWC2* hwc2 = new CfHWC2(std::move(reinterpret_cast<hwc_composer_device_1*>(device)));
-        hwc2->common.module = const_cast<hw_module_t *>(module);
-        *dev = &hwc2->common;
-    } else {
-        *dev = device;
-    }
-
-    return 0;
-}
-
-} // namespace android
-
-static struct hw_module_methods_t hwc2_module_methods = {
-    .open = android::hwc2DevOpen
-};
-
-hw_module_t HAL_MODULE_INFO_SYM = {
-    .tag = HARDWARE_MODULE_TAG,
-    .version_major = 2,
-    .version_minor = 0,
-    .id = HWC_HARDWARE_MODULE_ID,
-    .name = "CuttleFish HWC2 module",
-    .author = "Google",
-    .methods = &hwc2_module_methods,
-    .dso = NULL,
-    .reserved = {0},
-};
diff --git a/guest/hals/hwcomposer/cutf_cvm/HWC2.h b/guest/hals/hwcomposer/cutf_cvm/HWC2.h
deleted file mode 100644
index 7739b25..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/HWC2.h
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-#ifndef ANDROID_SF_HWC2_ON_1_ADAPTER_H
-#define ANDROID_SF_HWC2_ON_1_ADAPTER_H
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "MiniFence.h"
-
-#include <atomic>
-#include <map>
-#include <mutex>
-#include <numeric>
-#include <queue>
-#include <set>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-struct hwc_composer_device_1;
-struct hwc_display_contents_1;
-struct hwc_layer_1;
-
-namespace android {
-
-class CfHWC2 : public hwc2_device_t
-{
-public:
-    explicit CfHWC2(struct hwc_composer_device_1* hwc1Device);
-    ~CfHWC2();
-
-    struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
-    uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; }
-
-private:
-    static inline CfHWC2* getAdapter(hwc2_device_t* device) {
-        return static_cast<CfHWC2*>(device);
-    }
-
-    // getCapabilities
-
-    void doGetCapabilities(uint32_t* outCount,
-            int32_t* /*hwc2_capability_t*/ outCapabilities);
-    static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
-            int32_t* /*hwc2_capability_t*/ outCapabilities) {
-        getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
-    }
-
-    bool supportsBackgroundColor() {
-        return mHwc1SupportsBackgroundColor;
-    }
-
-    // getFunction
-
-    hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
-    static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
-            int32_t intDesc) {
-        auto descriptor = static_cast<HWC2::FunctionDescriptor>(intDesc);
-        return getAdapter(device)->doGetFunction(descriptor);
-    }
-
-    // Device functions
-
-    HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
-            hwc2_display_t* outDisplay);
-    static int32_t createVirtualDisplayHook(hwc2_device_t* device,
-            uint32_t width, uint32_t height, int32_t* /*format*/,
-            hwc2_display_t* outDisplay) {
-        // HWC1 implementations cannot override the buffer format requested by
-        // the consumer
-        auto error = getAdapter(device)->createVirtualDisplay(width, height,
-                outDisplay);
-        return static_cast<int32_t>(error);
-    }
-
-    HWC2::Error destroyVirtualDisplay(hwc2_display_t display);
-    static int32_t destroyVirtualDisplayHook(hwc2_device_t* device,
-            hwc2_display_t display) {
-        auto error = getAdapter(device)->destroyVirtualDisplay(display);
-        return static_cast<int32_t>(error);
-    }
-
-    std::string mDumpString;
-    void dump(uint32_t* outSize, char* outBuffer);
-    static void dumpHook(hwc2_device_t* device, uint32_t* outSize,
-            char* outBuffer) {
-        getAdapter(device)->dump(outSize, outBuffer);
-    }
-
-    uint32_t getMaxVirtualDisplayCount();
-    static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
-        return getAdapter(device)->getMaxVirtualDisplayCount();
-    }
-
-    HWC2::Error registerCallback(HWC2::Callback descriptor,
-            hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer);
-    static int32_t registerCallbackHook(hwc2_device_t* device,
-            int32_t intDesc, hwc2_callback_data_t callbackData,
-            hwc2_function_pointer_t pointer) {
-        auto descriptor = static_cast<HWC2::Callback>(intDesc);
-        auto error = getAdapter(device)->registerCallback(descriptor,
-                callbackData, pointer);
-        return static_cast<int32_t>(error);
-    }
-
-    // Display functions
-
-    class Layer;
-
-    class SortLayersByZ {
-        public:
-         bool operator()(const std::shared_ptr<Layer>& lhs,
-                         const std::shared_ptr<Layer>& rhs) const;
-    };
-
-    // The semantics of the fences returned by the device differ between
-    // hwc1.set() and hwc2.present(). Read hwcomposer.h and hwcomposer2.h
-    // for more information.
-    //
-    // Release fences in hwc1 are obtained on set() for a frame n and signaled
-    // when the layer buffer is not needed for read operations anymore
-    // (typically on frame n+1). In HWC2, release fences are obtained with a
-    // special call after present() for frame n. These fences signal
-    // on frame n: More specifically, the fence for a given buffer provided in
-    // frame n will signal when the prior buffer is no longer required.
-    //
-    // A retire fence (HWC1) is signaled when a composition is replaced
-    // on the panel whereas a present fence (HWC2) is signaled when a
-    // composition starts to be displayed on a panel.
-    //
-    // The HWC2to1Adapter emulates the new fence semantics for a frame
-    // n by returning the fence from frame n-1. For frame 0, the adapter
-    // returns NO_FENCE.
-    class DeferredFence {
-        public:
-            DeferredFence()
-              : mFences({MiniFence::NO_FENCE, MiniFence::NO_FENCE}) {}
-
-            void add(int32_t fenceFd) {
-                mFences.emplace(new MiniFence(fenceFd));
-                mFences.pop();
-            }
-
-            const sp<MiniFence>& get() const {
-                return mFences.front();
-            }
-
-        private:
-            // There are always two fences in this queue.
-            std::queue<sp<MiniFence>> mFences;
-    };
-
-    class FencedBuffer {
-        public:
-            FencedBuffer() : mBuffer(nullptr), mFence(MiniFence::NO_FENCE) {}
-
-            void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
-            void setFence(int fenceFd) { mFence = new MiniFence(fenceFd); }
-
-            buffer_handle_t getBuffer() const { return mBuffer; }
-            int getFence() const { return mFence->dup(); }
-
-        private:
-            buffer_handle_t mBuffer;
-            sp<MiniFence> mFence;
-    };
-
-    class Display {
-        public:
-            Display(CfHWC2& device, HWC2::DisplayType type);
-
-            hwc2_display_t getId() const { return mId; }
-            CfHWC2& getDevice() const { return mDevice; }
-
-            // Does not require locking because it is set before adding the
-            // Displays to the Adapter's list of displays
-            void setHwc1Id(int32_t id) { mHwc1Id = id; }
-            int32_t getHwc1Id() const { return mHwc1Id; }
-
-            // HWC2 Display functions
-            HWC2::Error acceptChanges();
-            HWC2::Error createLayer(hwc2_layer_t* outLayerId);
-            HWC2::Error destroyLayer(hwc2_layer_t layerId);
-            HWC2::Error getActiveConfig(hwc2_config_t* outConfigId);
-            HWC2::Error getAttribute(hwc2_config_t configId,
-                    HWC2::Attribute attribute, int32_t* outValue);
-            HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements,
-                    hwc2_layer_t* outLayers, int32_t* outTypes);
-            HWC2::Error getColorModes(uint32_t* outNumModes, int32_t* outModes);
-            HWC2::Error getConfigs(uint32_t* outNumConfigs,
-                    hwc2_config_t* outConfigIds);
-            HWC2::Error getDozeSupport(int32_t* outSupport);
-            HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
-                    int32_t* outTypes, float* outMaxLuminance,
-                    float* outMaxAverageLuminance, float* outMinLuminance);
-            HWC2::Error getName(uint32_t* outSize, char* outName);
-            HWC2::Error getReleaseFences(uint32_t* outNumElements,
-                    hwc2_layer_t* outLayers, int32_t* outFences);
-            HWC2::Error getRequests(int32_t* outDisplayRequests,
-                    uint32_t* outNumElements, hwc2_layer_t* outLayers,
-                    int32_t* outLayerRequests);
-            HWC2::Error getType(int32_t* outType);
-
-            // Since HWC1 "presents" (called "set" in HWC1) all Displays
-            // at once, the first call to any Display::present will trigger
-            // present() on all Displays in the Device. Subsequent calls without
-            // first calling validate() are noop (except for duping/returning
-            // the retire fence).
-            HWC2::Error present(int32_t* outRetireFence);
-
-            HWC2::Error setActiveConfig(hwc2_config_t configId);
-            HWC2::Error setClientTarget(buffer_handle_t target,
-                    int32_t acquireFence, int32_t dataspace,
-                    hwc_region_t damage);
-            HWC2::Error setColorMode(android_color_mode_t mode);
-            HWC2::Error setColorTransform(android_color_transform_t hint);
-            HWC2::Error setOutputBuffer(buffer_handle_t buffer,
-                    int32_t releaseFence);
-            HWC2::Error setPowerMode(HWC2::PowerMode mode);
-            HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
-
-            // Since HWC1 "validates" (called "prepare" in HWC1) all Displays
-            // at once, the first call to any Display::validate() will trigger
-            // validate() on all other Displays in the Device.
-            HWC2::Error validate(uint32_t* outNumTypes,
-                    uint32_t* outNumRequests);
-
-            HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
-
-            HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
-                     int32_t format, int32_t dataspace);
-
-            // 2.3 required functions
-            HWC2::Error getDisplayIdentificationData(uint8_t* outPort,
-                    uint32_t* outDataSize, uint8_t* outData);
-            HWC2::Error getDisplayCapabilities(uint32_t* outNumCapabilities,
-                    uint32_t* outCapabilities);
-            HWC2::Error getDisplayBrightnessSupport(bool *out_support);
-            HWC2::Error setDisplayBrightness(float brightness);
-
-            // Read configs from HWC1 device
-            void populateConfigs();
-
-            // Set configs for a virtual display
-            void populateConfigs(uint32_t width, uint32_t height);
-
-            bool prepare();
-
-            // Called after hwc.prepare() with responses from the device.
-            void generateChanges();
-
-            bool hasChanges() const;
-            HWC2::Error set(hwc_display_contents_1& hwcContents);
-            void addRetireFence(int fenceFd);
-            void addReleaseFences(const hwc_display_contents_1& hwcContents);
-
-            bool hasColorTransform() const;
-
-            std::string dump() const;
-
-            // Return a rect from the pool allocated during validate()
-            hwc_rect_t* GetRects(size_t numRects);
-
-            hwc_display_contents_1* getDisplayContents();
-
-            void markGeometryChanged() { mGeometryChanged = true; }
-            void resetGeometryMarker() { mGeometryChanged = false;}
-        private:
-            class Config {
-                public:
-                    Config(Display& display)
-                      : mDisplay(display),
-                        mId(0),
-                        mAttributes() {}
-
-                    bool isOnDisplay(const Display& display) const {
-                        return display.getId() == mDisplay.getId();
-                    }
-
-                    void setAttribute(HWC2::Attribute attribute, int32_t value);
-                    int32_t getAttribute(HWC2::Attribute attribute) const;
-
-                    void setHwc1Id(uint32_t id);
-                    bool hasHwc1Id(uint32_t id) const;
-                    HWC2::Error getColorModeForHwc1Id(uint32_t id,
-                            android_color_mode_t *outMode) const;
-                    HWC2::Error getHwc1IdForColorMode(android_color_mode_t mode,
-                            uint32_t* outId) const;
-
-                    void setId(hwc2_config_t id) { mId = id; }
-                    hwc2_config_t getId() const { return mId; }
-
-                    // Attempts to merge two configs that differ only in color
-                    // mode. Returns whether the merge was successful
-                    bool merge(const Config& other);
-
-                    std::set<android_color_mode_t> getColorModes() const;
-
-                    // splitLine divides the output into two lines suitable for
-                    // dumpsys SurfaceFlinger
-                    std::string toString(bool splitLine = false) const;
-
-                private:
-                    Display& mDisplay;
-                    hwc2_config_t mId;
-                    std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
-
-                    // Maps from color transform to HWC1 config ID
-                    std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
-            };
-
-            // Stores changes requested from the device upon calling prepare().
-            // Handles change request to:
-            //   - Layer composition type.
-            //   - Layer hints.
-            class Changes {
-                public:
-                    uint32_t getNumTypes() const {
-                        return static_cast<uint32_t>(mTypeChanges.size());
-                    }
-
-                    uint32_t getNumLayerRequests() const {
-                        return static_cast<uint32_t>(mLayerRequests.size());
-                    }
-
-                    const std::unordered_map<hwc2_layer_t, HWC2::Composition>&
-                            getTypeChanges() const {
-                        return mTypeChanges;
-                    }
-
-                    const std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>&
-                            getLayerRequests() const {
-                        return mLayerRequests;
-                    }
-
-                    void addTypeChange(hwc2_layer_t layerId,
-                            HWC2::Composition type) {
-                        mTypeChanges.insert({layerId, type});
-                    }
-
-                    void clearTypeChanges() { mTypeChanges.clear(); }
-
-                    void addLayerRequest(hwc2_layer_t layerId,
-                            HWC2::LayerRequest request) {
-                        mLayerRequests.insert({layerId, request});
-                    }
-
-                private:
-                    std::unordered_map<hwc2_layer_t, HWC2::Composition>
-                            mTypeChanges;
-                    std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>
-                            mLayerRequests;
-            };
-
-            std::shared_ptr<const Config>
-                    getConfig(hwc2_config_t configId) const;
-
-            void populateColorModes();
-            void initializeActiveConfig();
-
-            // Creates a bi-directional mapping between index in HWC1
-            // prepare/set array and Layer object. Stores mapping in
-            // mHwc1LayerMap and also updates Layer's attribute mHwc1Id.
-            void assignHwc1LayerIds();
-
-            // Called after a response to prepare() has been received:
-            // Ingest composition type changes requested by the device.
-            void updateTypeChanges(const struct hwc_layer_1& hwc1Layer,
-                    const Layer& layer);
-
-            // Called after a response to prepare() has been received:
-            // Ingest layer hint changes requested by the device.
-            void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
-                    const Layer& layer);
-
-            // Set all fields in HWC1 comm array for layer containing the
-            // HWC_FRAMEBUFFER_TARGET (always the last layer).
-            void prepareFramebufferTarget();
-
-            // Display ID generator.
-            static std::atomic<hwc2_display_t> sNextId;
-            const hwc2_display_t mId;
-
-
-            CfHWC2& mDevice;
-
-            // The state of this display should only be modified from
-            // SurfaceFlinger's main loop, with the exception of when dump is
-            // called. To prevent a bad state from crashing us during a dump
-            // call, all public calls into Display must acquire this mutex.
-            //
-            // It is recursive because we don't want to deadlock in validate
-            // (or present) when we call CfHWC2::prepareAllDisplays
-            // (or setAllDisplays), which calls back into Display functions
-            // which require locking.
-            mutable std::recursive_mutex mStateMutex;
-
-            // Allocate RAM able to store all layers and rects used for
-            // communication with HWC1. Place allocated RAM in variable
-            // mHwc1RequestedContents.
-            void allocateRequestedContents();
-
-            // Array of structs exchanged between client and hwc1 device.
-            // Sent to device upon calling prepare().
-            std::unique_ptr<hwc_display_contents_1> mHwc1RequestedContents;
-    private:
-            DeferredFence mRetireFence;
-
-            // Will only be non-null after the Display has been validated and
-            // before it has been presented
-            std::unique_ptr<Changes> mChanges;
-
-            int32_t mHwc1Id;
-
-            std::vector<std::shared_ptr<Config>> mConfigs;
-            std::shared_ptr<const Config> mActiveConfig;
-            std::set<android_color_mode_t> mColorModes;
-            android_color_mode_t mActiveColorMode;
-            std::string mName;
-            HWC2::DisplayType mType;
-            HWC2::PowerMode mPowerMode;
-            HWC2::Vsync mVsyncEnabled;
-
-            // Used to populate HWC1 HWC_FRAMEBUFFER_TARGET layer
-            FencedBuffer mClientTarget;
-
-
-            FencedBuffer mOutputBuffer;
-
-            bool mHasColorTransform;
-
-            // All layers this Display is aware of.
-            std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
-
-            // Mapping between layer index in array of hwc_display_contents_1*
-            // passed to HWC1 during validate/set and Layer object.
-            std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
-
-            // All communication with HWC1 via prepare/set is done with one
-            // alloc. This pointer is pointing to a pool of hwc_rect_t.
-            size_t mNumAvailableRects;
-            hwc_rect_t* mNextAvailableRect;
-
-            // True if any of the Layers contained in this Display have been
-            // updated with anything other than a buffer since last call to
-            // Display::set()
-            bool mGeometryChanged;
-    };
-
-    // Utility template calling a Display object method directly based on the
-    // hwc2_display_t displayId parameter.
-    template <typename ...Args>
-    static int32_t callDisplayFunction(hwc2_device_t* device,
-            hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
-            Args... args) {
-        auto display = getAdapter(device)->getDisplay(displayId);
-        if (!display) {
-            return static_cast<int32_t>(HWC2::Error::BadDisplay);
-        }
-        auto error = ((*display).*member)(std::forward<Args>(args)...);
-        return static_cast<int32_t>(error);
-    }
-
-    template <typename MF, MF memFunc, typename ...Args>
-    static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
-            Args... args) {
-        return CfHWC2::callDisplayFunction(device, displayId, memFunc,
-                std::forward<Args>(args)...);
-    }
-
-    static int32_t getDisplayAttributeHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_config_t config,
-            int32_t intAttribute, int32_t* outValue) {
-        auto attribute = static_cast<HWC2::Attribute>(intAttribute);
-        return callDisplayFunction(device, display, &Display::getAttribute,
-                config, attribute, outValue);
-    }
-
-    static int32_t setColorTransformHook(hwc2_device_t* device,
-            hwc2_display_t display, const float* /*matrix*/,
-            int32_t /*android_color_transform_t*/ intHint) {
-        // We intentionally throw away the matrix, because if the hint is
-        // anything other than IDENTITY, we have to fall back to client
-        // composition anyway
-        auto hint = static_cast<android_color_transform_t>(intHint);
-        return callDisplayFunction(device, display, &Display::setColorTransform,
-                hint);
-    }
-
-    static int32_t setColorModeHook(hwc2_device_t* device,
-            hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
-        auto mode = static_cast<android_color_mode_t>(intMode);
-        return callDisplayFunction(device, display, &Display::setColorMode,
-                mode);
-    }
-
-    static int32_t setPowerModeHook(hwc2_device_t* device,
-            hwc2_display_t display, int32_t intMode) {
-        auto mode = static_cast<HWC2::PowerMode>(intMode);
-        return callDisplayFunction(device, display, &Display::setPowerMode,
-                mode);
-    }
-
-    static int32_t setVsyncEnabledHook(hwc2_device_t* device,
-            hwc2_display_t display, int32_t intEnabled) {
-        auto enabled = static_cast<HWC2::Vsync>(intEnabled);
-        return callDisplayFunction(device, display, &Display::setVsyncEnabled,
-                enabled);
-    }
-
-    class Layer {
-        public:
-            explicit Layer(Display& display);
-
-            bool operator==(const Layer& other) { return mId == other.mId; }
-            bool operator!=(const Layer& other) { return !(*this == other); }
-
-            hwc2_layer_t getId() const { return mId; }
-            Display& getDisplay() const { return mDisplay; }
-
-            // HWC2 Layer functions
-            HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
-            HWC2::Error setCursorPosition(int32_t x, int32_t y);
-            HWC2::Error setSurfaceDamage(hwc_region_t damage);
-
-            // HWC2 Layer state functions
-            HWC2::Error setBlendMode(HWC2::BlendMode mode);
-            HWC2::Error setColor(hwc_color_t color);
-            HWC2::Error setCompositionType(HWC2::Composition type);
-            HWC2::Error setDataspace(android_dataspace_t dataspace);
-            HWC2::Error setDisplayFrame(hwc_rect_t frame);
-            HWC2::Error setPlaneAlpha(float alpha);
-            HWC2::Error setSidebandStream(const native_handle_t* stream);
-            HWC2::Error setSourceCrop(hwc_frect_t crop);
-            HWC2::Error setTransform(HWC2::Transform transform);
-            HWC2::Error setVisibleRegion(hwc_region_t visible);
-            HWC2::Error setZ(uint32_t z);
-
-            HWC2::Composition getCompositionType() const {
-                return mCompositionType;
-            }
-            uint32_t getZ() const { return mZ; }
-
-            void addReleaseFence(int fenceFd);
-            const sp<MiniFence>& getReleaseFence() const;
-
-            void setHwc1Id(size_t id) { mHwc1Id = id; }
-            size_t getHwc1Id() const { return mHwc1Id; }
-
-            // Write state to HWC1 communication struct.
-            void applyState(struct hwc_layer_1& hwc1Layer);
-
-            std::string dump() const;
-
-            std::size_t getNumVisibleRegions() { return mVisibleRegion.size(); }
-
-            std::size_t getNumSurfaceDamages() { return mSurfaceDamage.size(); }
-
-            // True if a layer cannot be properly rendered by the device due
-            // to usage of SolidColor (a.k.a BackgroundColor in HWC1).
-            bool hasUnsupportedBackgroundColor() {
-                return (mCompositionType == HWC2::Composition::SolidColor &&
-                        !mDisplay.getDevice().supportsBackgroundColor());
-            }
-        private:
-            void applyCommonState(struct hwc_layer_1& hwc1Layer);
-            void applySolidColorState(struct hwc_layer_1& hwc1Layer);
-            void applySidebandState(struct hwc_layer_1& hwc1Layer);
-            void applyBufferState(struct hwc_layer_1& hwc1Layer);
-            void applyCompositionType(struct hwc_layer_1& hwc1Layer);
-
-            static std::atomic<hwc2_layer_t> sNextId;
-            const hwc2_layer_t mId;
-            Display& mDisplay;
-
-            FencedBuffer mBuffer;
-            std::vector<hwc_rect_t> mSurfaceDamage;
-
-            HWC2::BlendMode mBlendMode;
-            hwc_color_t mColor;
-            HWC2::Composition mCompositionType;
-            hwc_rect_t mDisplayFrame;
-            float mPlaneAlpha;
-            const native_handle_t* mSidebandStream;
-            hwc_frect_t mSourceCrop;
-            HWC2::Transform mTransform;
-            std::vector<hwc_rect_t> mVisibleRegion;
-
-            uint32_t mZ;
-
-            DeferredFence mReleaseFence;
-
-            size_t mHwc1Id;
-            bool mHasUnsupportedPlaneAlpha;
-    };
-
-    // Utility tempate calling a Layer object method based on ID parameters:
-    // hwc2_display_t displayId
-    // and
-    // hwc2_layer_t layerId
-    template <typename ...Args>
-    static int32_t callLayerFunction(hwc2_device_t* device,
-            hwc2_display_t displayId, hwc2_layer_t layerId,
-            HWC2::Error (Layer::*member)(Args...), Args... args) {
-        auto result = getAdapter(device)->getLayer(displayId, layerId);
-        auto error = std::get<HWC2::Error>(result);
-        if (error == HWC2::Error::None) {
-            auto layer = std::get<Layer*>(result);
-            error = ((*layer).*member)(std::forward<Args>(args)...);
-        }
-        return static_cast<int32_t>(error);
-    }
-
-    template <typename MF, MF memFunc, typename ...Args>
-    static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId,
-            hwc2_layer_t layerId, Args... args) {
-        return CfHWC2::callLayerFunction(device, displayId, layerId,
-                memFunc, std::forward<Args>(args)...);
-    }
-
-    // Layer state functions
-
-    static int32_t setLayerBlendModeHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) {
-        auto mode = static_cast<HWC2::BlendMode>(intMode);
-        return callLayerFunction(device, display, layer,
-                &Layer::setBlendMode, mode);
-    }
-
-    static int32_t setLayerCompositionTypeHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intType) {
-        auto type = static_cast<HWC2::Composition>(intType);
-        return callLayerFunction(device, display, layer,
-                &Layer::setCompositionType, type);
-    }
-
-    static int32_t setLayerDataspaceHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intDataspace) {
-        auto dataspace = static_cast<android_dataspace_t>(intDataspace);
-        return callLayerFunction(device, display, layer, &Layer::setDataspace,
-                dataspace);
-    }
-
-    static int32_t setLayerTransformHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) {
-        auto transform = static_cast<HWC2::Transform>(intTransform);
-        return callLayerFunction(device, display, layer, &Layer::setTransform,
-                transform);
-    }
-
-    static int32_t setLayerZOrderHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, uint32_t z) {
-        return callDisplayFunction(device, display, &Display::updateLayerZ,
-                layer, z);
-    }
-
-    // Adapter internals
-
-    void populateCapabilities();
-    Display* getDisplay(hwc2_display_t id);
-    std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
-            hwc2_layer_t layerId);
-    void populatePrimary();
-
-    bool prepareAllDisplays();
-    std::vector<struct hwc_display_contents_1*> mHwc1Contents;
-    HWC2::Error setAllDisplays();
-
-    // Callbacks
-    void hwc1Invalidate();
-    void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
-    void hwc1Hotplug(int hwc1DisplayId, int connected);
-
-    // These are set in the constructor and before any asynchronous events are
-    // possible
-
-    struct hwc_composer_device_1* const mHwc1Device;
-    const uint8_t mHwc1MinorVersion;
-    bool mHwc1SupportsVirtualDisplays;
-    bool mHwc1SupportsBackgroundColor;
-
-    class Callbacks;
-    const std::unique_ptr<Callbacks> mHwc1Callbacks;
-
-    std::unordered_set<HWC2::Capability> mCapabilities;
-
-    // These are only accessed from the main SurfaceFlinger thread (not from
-    // callbacks or dump
-
-    std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
-
-    // A HWC1 supports only one virtual display.
-    std::shared_ptr<Display> mHwc1VirtualDisplay;
-
-    // These are potentially accessed from multiple threads, and are protected
-    // by this mutex. This needs to be recursive, since the HWC1 implementation
-    // can call back into the invalidate callback on the same thread that is
-    // calling prepare.
-    std::recursive_timed_mutex mStateMutex;
-
-    struct CallbackInfo {
-        hwc2_callback_data_t data;
-        hwc2_function_pointer_t pointer;
-    };
-    std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
-    bool mHasPendingInvalidate;
-
-    // There is a small gap between the time the HWC1 module is started and
-    // when the callbacks for vsync and hotplugs are registered by the
-    // CfHWC2. To prevent losing events they are stored in these arrays
-    // and fed to the callback as soon as possible.
-    std::vector<std::pair<int, int64_t>> mPendingVsyncs;
-    std::vector<std::pair<int, int>> mPendingHotplugs;
-
-    // Mapping between HWC1 display id and Display objects.
-    std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
-
-    // Map HWC1 display type (HWC_DISPLAY_PRIMARY, HWC_DISPLAY_EXTERNAL,
-    // HWC_DISPLAY_VIRTUAL) to Display IDs generated by CfHWC2 objects.
-    std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
-};
-
-} // namespace android
-
-#endif
diff --git a/guest/hals/hwcomposer/cutf_cvm/MiniFence.cpp b/guest/hals/hwcomposer/cutf_cvm/MiniFence.cpp
deleted file mode 100644
index ecfb063..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/MiniFence.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "MiniFence.h"
-
-#include <unistd.h>
-
-namespace android {
-
-const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
-
-MiniFence::MiniFence() :
-    mFenceFd(-1) {
-}
-
-MiniFence::MiniFence(int fenceFd) :
-    mFenceFd(fenceFd) {
-}
-
-MiniFence::~MiniFence() {
-    if (mFenceFd != -1) {
-        close(mFenceFd);
-    }
-}
-
-int MiniFence::dup() const {
-    return ::dup(mFenceFd);
-}
-}
diff --git a/guest/hals/hwcomposer/cutf_cvm/MiniFence.h b/guest/hals/hwcomposer/cutf_cvm/MiniFence.h
deleted file mode 100644
index 34fbdd8..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/MiniFence.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef MINIFENCE_H
-#define MINIFENCE_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-
-/* MiniFence is a minimal re-implementation of Fence from libui. It exists to
- * avoid linking the HWC2on1Adapter to libui and satisfy Treble requirements.
- */
-class MiniFence : public LightRefBase<MiniFence> {
-public:
-    static const sp<MiniFence> NO_FENCE;
-
-    // Construct a new MiniFence object with an invalid file descriptor.
-    MiniFence();
-
-    // Construct a new MiniFence object to manage a given fence file descriptor.
-    // When the new MiniFence object is destructed the file descriptor will be
-    // closed.
-    explicit MiniFence(int fenceFd);
-
-    // Not copyable or movable.
-    MiniFence(const MiniFence& rhs) = delete;
-    MiniFence& operator=(const MiniFence& rhs) = delete;
-    MiniFence(MiniFence&& rhs) = delete;
-    MiniFence& operator=(MiniFence&& rhs) = delete;
-
-    // Return a duplicate of the fence file descriptor. The caller is
-    // responsible for closing the returned file descriptor. On error, -1 will
-    // be returned and errno will indicate the problem.
-    int dup() const;
-
-private:
-    // Only allow instantiation using ref counting.
-    friend class LightRefBase<MiniFence>;
-    ~MiniFence();
-
-    int mFenceFd;
-
-};
-}
-#endif //MINIFENCE_H
diff --git a/guest/hals/hwcomposer/cutf_cvm/hwcomposer.cpp b/guest/hals/hwcomposer/cutf_cvm/hwcomposer.cpp
deleted file mode 100644
index 976a68c..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/hwcomposer.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#define LOG_TAG "hwc.cutf_cvm"
-
-#include <cutils/properties.h>
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer_defs.h>
-#include <log/log.h>
-
-#include "guest/hals/hwcomposer/common/hwcomposer.h"
-
-#include "guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h"
-
-static int hwc_open(const struct hw_module_t* module, const char* name,
-                    struct hw_device_t** device) {
-  std::unique_ptr<cvd::ScreenView> screen_view(new cvd::VsocketScreenView());
-  if (!screen_view) {
-    ALOGE("Failed to instantiate screen view");
-    return -1;
-  }
-
-  return cvd::cvd_hwc_open(std::move(screen_view), module, name, device);
-}
-
-static struct hw_module_methods_t hwc_module_methods = {
-    hwc_open,
-};
-
-hwc_module_t HAL_MODULE_INFO_SYM = {{HARDWARE_MODULE_TAG,
-                                     HWC_MODULE_API_VERSION_0_1,
-                                     HARDWARE_HAL_API_VERSION,
-                                     HWC_HARDWARE_MODULE_ID,
-                                     "VSOCKET hwcomposer module",
-                                     "Google",
-                                     &hwc_module_methods,
-                                     NULL,
-                                     {0}}};
diff --git a/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.cpp b/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.cpp
deleted file mode 100644
index 16185b5..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#define LOG_TAG "vsock_hwc"
-
-#include "guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h"
-
-#include <cutils/properties.h>
-#include <log/log.h>
-
-#include "common/libs/device_config/device_config.h"
-
-namespace cvd {
-
-VsocketScreenView::VsocketScreenView()
-    : broadcast_thread_([this]() { BroadcastLoop(); }) {
-  GetScreenParameters();
-  // inner_buffer needs to be initialized after the final values of the screen
-  // parameters are set (either from the config server or default).
-  inner_buffer_ = std::vector<char>(buffer_size() * 8);
-}
-
-VsocketScreenView::~VsocketScreenView() {
-  running_ = false;
-  broadcast_thread_.join();
-}
-
-void VsocketScreenView::GetScreenParameters() {
-  auto device_config = cvd::DeviceConfig::Get();
-  if (!device_config) {
-    ALOGI(
-        "Failed to obtain device configuration from server, running in "
-        "headless mode");
-    // It is impossible to ensure host and guest agree on the screen parameters
-    // if these could not be read from the host configuration server. It's best
-    // to not attempt to send frames in this case.
-    running_ = false;
-    // Do a phony Broadcast to ensure the broadcaster thread exits.
-    Broadcast(-1);
-    return;
-  }
-  x_res_ = device_config->screen_x_res();
-  y_res_ = device_config->screen_y_res();
-  dpi_ = device_config->screen_dpi();
-  refresh_rate_ = device_config->screen_refresh_rate();
-  ALOGI("Received screen parameters: res=%dx%d, dpi=%d, freq=%d", x_res_,
-        y_res_, dpi_, refresh_rate_);
-}
-
-bool VsocketScreenView::ConnectToScreenServer() {
-  auto vsock_frames_port = property_get_int64("ro.boot.vsock_frames_port", -1);
-  if (vsock_frames_port <= 0) {
-    ALOGI("No screen server configured, operating on headless mode");
-    return false;
-  }
-
-  screen_server_ = cvd::SharedFD::VsockClient(
-      2, static_cast<unsigned int>(vsock_frames_port), SOCK_STREAM);
-  if (!screen_server_->IsOpen()) {
-    ALOGE("Unable to connect to screen server: %s", screen_server_->StrError());
-    return false;
-  }
-
-  return true;
-}
-
-void VsocketScreenView::BroadcastLoop() {
-  auto connected = ConnectToScreenServer();
-  if (!connected) {
-    ALOGE(
-        "Broadcaster thread exiting due to no connection to screen server. "
-        "Compositions will occur, but frames won't be sent anywhere");
-    return;
-  }
-  int current_seq = 0;
-  int current_offset;
-  ALOGI("Broadcaster thread loop starting");
-  while (true) {
-    {
-      std::unique_lock<std::mutex> lock(mutex_);
-      while (running_ && current_seq == current_seq_) {
-        cond_var_.wait(lock);
-      }
-      if (!running_) {
-        ALOGI("Broadcaster thread exiting");
-        return;
-      }
-      current_offset = current_offset_;
-      current_seq = current_seq_;
-    }
-    int32_t size = buffer_size();
-    screen_server_->Write(&size, sizeof(size));
-    auto buff = static_cast<char*>(GetBuffer(current_offset));
-    while (size > 0) {
-      auto written = screen_server_->Write(buff, size);
-      if (written == -1) {
-        ALOGE("Broadcaster thread failed to write frame: %s", strerror(errno));
-        break;
-      }
-      size -= written;
-      buff += written;
-    }
-  }
-}
-
-void VsocketScreenView::Broadcast(int offset, const CompositionStats*) {
-  std::lock_guard<std::mutex> lock(mutex_);
-  current_offset_ = offset;
-  current_seq_++;
-  cond_var_.notify_all();
-}
-
-void* VsocketScreenView::GetBuffer(int buffer_id) {
-  return &inner_buffer_[buffer_size() * buffer_id];
-}
-
-int32_t VsocketScreenView::x_res() const { return x_res_; }
-int32_t VsocketScreenView::y_res() const { return y_res_; }
-int32_t VsocketScreenView::dpi() const { return dpi_; }
-int32_t VsocketScreenView::refresh_rate() const { return refresh_rate_; }
-
-int VsocketScreenView::num_buffers() const {
-  return inner_buffer_.size() / buffer_size();
-}
-
-}  // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h b/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h
deleted file mode 100644
index 0d6d90a..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2016 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 <condition_variable>
-#include <functional>
-#include <mutex>
-#include <thread>
-#include <vector>
-
-#include "common/libs/fs/shared_fd.h"
-#include "guest/hals/hwcomposer/common/screen_view.h"
-
-namespace cvd {
-
-class VsocketScreenView : public ScreenView {
- public:
-  VsocketScreenView();
-  virtual ~VsocketScreenView();
-
-  void Broadcast(int buffer_id,
-                 const CompositionStats* stats = nullptr) override;
-  void* GetBuffer(int fb_index) override;
-
-  int32_t x_res() const override;
-  int32_t y_res() const override;
-  int32_t dpi() const override;
-  int32_t refresh_rate() const override;
-
-  int num_buffers() const override;
-
- private:
-  bool ConnectToScreenServer();
-  void GetScreenParameters();
-  void BroadcastLoop();
-
-  std::vector<char> inner_buffer_;
-  cvd::SharedFD screen_server_;
-  std::thread broadcast_thread_;
-  int current_offset_ = 0;
-  int current_seq_ = 0;
-  std::mutex mutex_;
-  std::condition_variable cond_var_;
-  bool running_ = true;
-  int32_t x_res_{720};
-  int32_t y_res_{1280};
-  int32_t dpi_{160};
-  int32_t refresh_rate_{60};
-};
-
-}  // namespace cvd
diff --git a/guest/hals/keymaster/OWNERS b/guest/hals/keymaster/OWNERS
new file mode 100644
index 0000000..fb015cb
--- /dev/null
+++ b/guest/hals/keymaster/OWNERS
@@ -0,0 +1 @@
+include platform/system/keymaster:/OWNERS
diff --git a/guest/hals/keymaster/remote/Android.bp b/guest/hals/keymaster/remote/Android.bp
new file mode 100644
index 0000000..805a803
--- /dev/null
+++ b/guest/hals/keymaster/remote/Android.bp
@@ -0,0 +1,53 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.keymaster@4.1-service.remote",
+    defaults: ["hidl_defaults", "cuttlefish_guest_only"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.keymaster@4.1-service.remote.rc"],
+    srcs: [
+        "service4.cpp",
+        "remote_keymaster4_device.cpp",
+        "remote_keymaster.cpp",
+    ],
+
+    static_libs: [
+        "libgflags",
+    ],
+
+    shared_libs: [
+        "android.hardware.keymaster@4.1",
+        "libbase",
+        "libcutils",
+        "libcuttlefish_fs",
+        "libcuttlefish_security",
+        "libdl",
+        "libhardware",
+        "libhidlbase",
+        "libkeymaster4",
+        "libkeymaster_messages",
+        "liblog",
+        "libtrusty",
+        "libutils",
+    ],
+
+    vintf_fragments: ["android.hardware.keymaster@4.1-service.remote.xml"],
+}
diff --git a/guest/hals/keymaster/remote/android.hardware.keymaster@4.1-service.remote.rc b/guest/hals/keymaster/remote/android.hardware.keymaster@4.1-service.remote.rc
new file mode 100644
index 0000000..d8ef4e1
--- /dev/null
+++ b/guest/hals/keymaster/remote/android.hardware.keymaster@4.1-service.remote.rc
@@ -0,0 +1,6 @@
+service vendor.keymaster-4-1 /vendor/bin/hw/android.hardware.keymaster@4.1-service.remote
+    interface android.hardware.keymaster@4.0::IKeymasterDevice default
+    interface android.hardware.keymaster@4.1::IKeymasterDevice default
+    class early_hal
+    user system
+    group system drmrpc
diff --git a/guest/hals/keymaster/remote/android.hardware.keymaster@4.1-service.remote.xml b/guest/hals/keymaster/remote/android.hardware.keymaster@4.1-service.remote.xml
new file mode 100644
index 0000000..af27c1e
--- /dev/null
+++ b/guest/hals/keymaster/remote/android.hardware.keymaster@4.1-service.remote.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.keymaster</name>
+        <transport>hwbinder</transport>
+        <fqname>@4.1::IKeymasterDevice/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/keymaster/remote/remote_keymaster.cpp b/guest/hals/keymaster/remote/remote_keymaster.cpp
new file mode 100644
index 0000000..daf5956
--- /dev/null
+++ b/guest/hals/keymaster/remote/remote_keymaster.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "remote_keymaster.h"
+
+#include <android-base/logging.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/keymaster_configuration.h>
+
+namespace keymaster {
+
+RemoteKeymaster::RemoteKeymaster(cuttlefish::KeymasterChannel* channel)
+    : channel_(channel) {}
+
+RemoteKeymaster::~RemoteKeymaster() {
+}
+
+void RemoteKeymaster::ForwardCommand(AndroidKeymasterCommand command, const Serializable& req,
+                                     KeymasterResponse* rsp) {
+    if (!channel_->SendRequest(command, req)) {
+        LOG(ERROR) << "Failed to send keymaster message: " << command;
+        rsp->error = KM_ERROR_UNKNOWN_ERROR;
+        return;
+    }
+    auto response = channel_->ReceiveMessage();
+    if (!response) {
+        LOG(ERROR) << "Failed to receive keymaster response: " << command;
+        rsp->error = KM_ERROR_UNKNOWN_ERROR;
+        return;
+    }
+    const uint8_t* buffer = response->payload;
+    const uint8_t* buffer_end = response->payload + response->payload_size;
+    if (!rsp->Deserialize(&buffer, buffer_end)) {
+        LOG(ERROR) << "Failed to deserialize keymaster response: " << command;
+        rsp->error = KM_ERROR_UNKNOWN_ERROR;
+        return;
+    }
+}
+
+bool RemoteKeymaster::Initialize() {
+    // We don't need to bother with GetVersion, because CF HAL and remote sides are always compiled
+    // together, so will never disagree about message versions.
+    ConfigureRequest req(message_version());
+    req.os_version = GetOsVersion();
+    req.os_patchlevel = GetOsPatchlevel();
+
+    ConfigureResponse rsp(message_version());
+    Configure(req, &rsp);
+
+    if (rsp.error != KM_ERROR_OK) {
+        LOG(ERROR) << "Failed to configure keymaster: " << rsp.error;
+        return false;
+    }
+
+    return true;
+}
+
+void RemoteKeymaster::GetVersion(const GetVersionRequest& request, GetVersionResponse* response) {
+    ForwardCommand(GET_VERSION, request, response);
+}
+
+void RemoteKeymaster::SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+                                          SupportedAlgorithmsResponse* response) {
+    ForwardCommand(GET_SUPPORTED_ALGORITHMS, request, response);
+}
+
+void RemoteKeymaster::SupportedBlockModes(const SupportedBlockModesRequest& request,
+                                          SupportedBlockModesResponse* response) {
+    ForwardCommand(GET_SUPPORTED_BLOCK_MODES, request, response);
+}
+
+void RemoteKeymaster::SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                                            SupportedPaddingModesResponse* response) {
+    ForwardCommand(GET_SUPPORTED_PADDING_MODES, request, response);
+}
+
+void RemoteKeymaster::SupportedDigests(const SupportedDigestsRequest& request,
+                                       SupportedDigestsResponse* response) {
+    ForwardCommand(GET_SUPPORTED_DIGESTS, request, response);
+}
+
+void RemoteKeymaster::SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                                             SupportedImportFormatsResponse* response) {
+    ForwardCommand(GET_SUPPORTED_IMPORT_FORMATS, request, response);
+}
+
+void RemoteKeymaster::SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                                             SupportedExportFormatsResponse* response) {
+    ForwardCommand(GET_SUPPORTED_EXPORT_FORMATS, request, response);
+}
+
+void RemoteKeymaster::AddRngEntropy(const AddEntropyRequest& request,
+                                    AddEntropyResponse* response) {
+    ForwardCommand(ADD_RNG_ENTROPY, request, response);
+}
+
+void RemoteKeymaster::Configure(const ConfigureRequest& request, ConfigureResponse* response) {
+    ForwardCommand(CONFIGURE, request, response);
+}
+
+void RemoteKeymaster::GenerateKey(const GenerateKeyRequest& request,
+                                  GenerateKeyResponse* response) {
+    GenerateKeyRequest datedRequest(request.message_version);
+    datedRequest.key_description = request.key_description;
+
+    if (!request.key_description.Contains(TAG_CREATION_DATETIME)) {
+        datedRequest.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+    }
+
+    ForwardCommand(GENERATE_KEY, datedRequest, response);
+}
+
+void RemoteKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+                                            GetKeyCharacteristicsResponse* response) {
+    ForwardCommand(GET_KEY_CHARACTERISTICS, request, response);
+}
+
+void RemoteKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
+    ForwardCommand(IMPORT_KEY, request, response);
+}
+
+void RemoteKeymaster::ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                                       ImportWrappedKeyResponse* response) {
+    ForwardCommand(IMPORT_WRAPPED_KEY, request, response);
+}
+
+void RemoteKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response) {
+    ForwardCommand(EXPORT_KEY, request, response);
+}
+
+void RemoteKeymaster::AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response) {
+    ForwardCommand(ATTEST_KEY, request, response);
+}
+
+void RemoteKeymaster::UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response) {
+    ForwardCommand(UPGRADE_KEY, request, response);
+}
+
+void RemoteKeymaster::DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response) {
+    ForwardCommand(DELETE_KEY, request, response);
+}
+
+void RemoteKeymaster::DeleteAllKeys(const DeleteAllKeysRequest& request,
+                                    DeleteAllKeysResponse* response) {
+    ForwardCommand(DELETE_ALL_KEYS, request, response);
+}
+
+void RemoteKeymaster::BeginOperation(const BeginOperationRequest& request,
+                                     BeginOperationResponse* response) {
+    ForwardCommand(BEGIN_OPERATION, request, response);
+}
+
+void RemoteKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+                                      UpdateOperationResponse* response) {
+    ForwardCommand(UPDATE_OPERATION, request, response);
+}
+
+void RemoteKeymaster::FinishOperation(const FinishOperationRequest& request,
+                                      FinishOperationResponse* response) {
+    ForwardCommand(FINISH_OPERATION, request, response);
+}
+
+void RemoteKeymaster::AbortOperation(const AbortOperationRequest& request,
+                                     AbortOperationResponse* response) {
+    ForwardCommand(ABORT_OPERATION, request, response);
+}
+
+GetHmacSharingParametersResponse RemoteKeymaster::GetHmacSharingParameters() {
+    // Unused empty buffer to allow ForwardCommand to have something to serialize
+    Buffer request;
+    GetHmacSharingParametersResponse response(message_version());
+    ForwardCommand(GET_HMAC_SHARING_PARAMETERS, request, &response);
+    return response;
+}
+
+ComputeSharedHmacResponse RemoteKeymaster::ComputeSharedHmac(
+        const ComputeSharedHmacRequest& request) {
+    ComputeSharedHmacResponse response(message_version());
+    ForwardCommand(COMPUTE_SHARED_HMAC, request, &response);
+    return response;
+}
+
+VerifyAuthorizationResponse RemoteKeymaster::VerifyAuthorization(
+        const VerifyAuthorizationRequest& request) {
+    VerifyAuthorizationResponse response(message_version());
+    ForwardCommand(VERIFY_AUTHORIZATION, request, &response);
+    return response;
+}
+
+DeviceLockedResponse RemoteKeymaster::DeviceLocked(
+        const DeviceLockedRequest& request) {
+    DeviceLockedResponse response(message_version());
+    ForwardCommand(DEVICE_LOCKED, request, &response);
+    return response;
+}
+
+EarlyBootEndedResponse RemoteKeymaster::EarlyBootEnded() {
+    // Unused empty buffer to allow ForwardCommand to have something to serialize
+    Buffer request;
+    EarlyBootEndedResponse response(message_version());
+    ForwardCommand(EARLY_BOOT_ENDED, request, &response);
+    return response;
+}
+
+}  // namespace keymaster
diff --git a/guest/hals/keymaster/remote/remote_keymaster.h b/guest/hals/keymaster/remote/remote_keymaster.h
new file mode 100644
index 0000000..13c428f
--- /dev/null
+++ b/guest/hals/keymaster/remote/remote_keymaster.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef REMOTE_KEYMASTER_H_
+#define REMOTE_KEYMASTER_H_
+
+#include <keymaster/android_keymaster_messages.h>
+
+#include "common/libs/security/keymaster_channel.h"
+
+namespace keymaster {
+
+class RemoteKeymaster {
+  private:
+    cuttlefish::KeymasterChannel* channel_;
+
+    void ForwardCommand(
+        AndroidKeymasterCommand command, const Serializable& req, KeymasterResponse* rsp);
+  public:
+    RemoteKeymaster(cuttlefish::KeymasterChannel*);
+    ~RemoteKeymaster();
+    bool Initialize();
+    void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
+    void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+                             SupportedAlgorithmsResponse* response);
+    void SupportedBlockModes(const SupportedBlockModesRequest& request,
+                             SupportedBlockModesResponse* response);
+    void SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                               SupportedPaddingModesResponse* response);
+    void SupportedDigests(const SupportedDigestsRequest& request,
+                          SupportedDigestsResponse* response);
+    void SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                                SupportedImportFormatsResponse* response);
+    void SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                                SupportedExportFormatsResponse* response);
+    void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
+    void Configure(const ConfigureRequest& request, ConfigureResponse* response);
+    void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+    void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+                               GetKeyCharacteristicsResponse* response);
+    void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
+    void ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                          ImportWrappedKeyResponse* response);
+    void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
+    void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+    void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response);
+    void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
+    void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
+    void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
+    void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response);
+    void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
+    void AbortOperation(const AbortOperationRequest& request, AbortOperationResponse* response);
+    GetHmacSharingParametersResponse GetHmacSharingParameters();
+    ComputeSharedHmacResponse ComputeSharedHmac(const ComputeSharedHmacRequest& request);
+    VerifyAuthorizationResponse VerifyAuthorization(const VerifyAuthorizationRequest& request);
+    DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
+    EarlyBootEndedResponse EarlyBootEnded();
+
+    // CF HAL and remote sides are always compiled together, so will never disagree about message
+    // versions.
+    uint32_t message_version() { return kDefaultMessageVersion; }
+};
+
+}  // namespace keymaster
+
+#endif  // REMOTE_KEYMASTER_H_
diff --git a/guest/hals/keymaster/remote/remote_keymaster4_device.cpp b/guest/hals/keymaster/remote/remote_keymaster4_device.cpp
new file mode 100644
index 0000000..b82aa83
--- /dev/null
+++ b/guest/hals/keymaster/remote/remote_keymaster4_device.cpp
@@ -0,0 +1,631 @@
+/*
+ **
+ ** Copyright 2018, 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.
+ */
+
+#define LOG_TAG "android.hardware.keymaster@4.0-impl.remote"
+
+#include "remote_keymaster4_device.h"
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+#include <authorization_set.h>
+#include <cutils/log.h>
+#include <keymaster/android_keymaster_messages.h>
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::AddEntropyRequest;
+using ::keymaster::AddEntropyResponse;
+using ::keymaster::AttestKeyRequest;
+using ::keymaster::AttestKeyResponse;
+using ::keymaster::AuthorizationSet;
+using ::keymaster::BeginOperationRequest;
+using ::keymaster::BeginOperationResponse;
+using ::keymaster::ExportKeyRequest;
+using ::keymaster::ExportKeyResponse;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::GenerateKeyRequest;
+using ::keymaster::GenerateKeyResponse;
+using ::keymaster::GetKeyCharacteristicsRequest;
+using ::keymaster::GetKeyCharacteristicsResponse;
+using ::keymaster::ImportKeyRequest;
+using ::keymaster::ImportKeyResponse;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using ::keymaster::ng::Tag;
+
+typedef ::android::hardware::keymaster::V3_0::Tag Tag3;
+using ::android::hardware::keymaster::V4_0::Constants;
+
+namespace keymaster {
+namespace V4_1 {
+namespace {
+
+inline keymaster_tag_t legacy_enum_conversion(const Tag value) {
+    return keymaster_tag_t(value);
+}
+inline Tag legacy_enum_conversion(const keymaster_tag_t value) {
+    return Tag(value);
+}
+inline keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) {
+    return keymaster_purpose_t(value);
+}
+inline keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) {
+    return keymaster_key_format_t(value);
+}
+
+inline SecurityLevel legacy_enum_conversion(const keymaster_security_level_t value) {
+    return static_cast<SecurityLevel>(value);
+}
+
+inline hw_authenticator_type_t legacy_enum_conversion(const HardwareAuthenticatorType value) {
+    return static_cast<hw_authenticator_type_t>(value);
+}
+
+inline ErrorCode legacy_enum_conversion(const keymaster_error_t value) {
+    return ErrorCode(value);
+}
+
+inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) {
+    return keymaster_tag_get_type(tag);
+}
+
+/*
+ * injectAuthToken translates a KM4 authToken into a legacy AUTH_TOKEN tag
+ *
+ * Currently, system/keymaster's reference implementation only accepts this
+ * method for passing an auth token, so until that changes we need to
+ * translate to the old format.
+ */
+inline hidl_vec<KeyParameter> injectAuthToken(const hidl_vec<KeyParameter>& keyParamsBase,
+                                              const HardwareAuthToken& authToken) {
+    std::vector<KeyParameter> keyParams(keyParamsBase);
+    const size_t mac_len = static_cast<size_t>(Constants::AUTH_TOKEN_MAC_LENGTH);
+    /*
+     * mac.size() == 0 indicates no token provided, so we should not copy.
+     * mac.size() != mac_len means it is incompatible with the old
+     *   hw_auth_token_t structure. This is forbidden by spec, but to be safe
+     *   we only copy if mac.size() == mac_len, e.g. there is an authToken
+     *   with a hw_auth_token_t compatible MAC.
+     */
+    if (authToken.mac.size() == mac_len) {
+        KeyParameter p;
+        p.tag = static_cast<Tag>(Tag3::AUTH_TOKEN);
+        p.blob.resize(sizeof(hw_auth_token_t));
+
+        hw_auth_token_t* auth_token = reinterpret_cast<hw_auth_token_t*>(p.blob.data());
+        auth_token->version = 0;
+        auth_token->challenge = authToken.challenge;
+        auth_token->user_id = authToken.userId;
+        auth_token->authenticator_id = authToken.authenticatorId;
+        auth_token->authenticator_type =
+                htobe32(static_cast<uint32_t>(authToken.authenticatorType));
+        auth_token->timestamp = htobe64(authToken.timestamp);
+        static_assert(mac_len == sizeof(auth_token->hmac));
+        memcpy(auth_token->hmac, authToken.mac.data(), mac_len);
+        keyParams.push_back(p);
+    }
+
+    return hidl_vec<KeyParameter>(std::move(keyParams));
+}
+
+class KmParamSet : public keymaster_key_param_set_t {
+  public:
+    KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
+        params = new keymaster_key_param_t[keyParams.size()];
+        length = keyParams.size();
+        for (size_t i = 0; i < keyParams.size(); ++i) {
+            auto tag = legacy_enum_conversion(keyParams[i].tag);
+            switch (typeFromTag(tag)) {
+                case KM_ENUM:
+                case KM_ENUM_REP:
+                    params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
+                    break;
+                case KM_UINT:
+                case KM_UINT_REP:
+                    params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
+                    break;
+                case KM_ULONG:
+                case KM_ULONG_REP:
+                    params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
+                    break;
+                case KM_DATE:
+                    params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
+                    break;
+                case KM_BOOL:
+                    if (keyParams[i].f.boolValue)
+                        params[i] = keymaster_param_bool(tag);
+                    else
+                        params[i].tag = KM_TAG_INVALID;
+                    break;
+                case KM_BIGNUM:
+                case KM_BYTES:
+                    params[i] = keymaster_param_blob(tag, &keyParams[i].blob[0],
+                                                     keyParams[i].blob.size());
+                    break;
+                case KM_INVALID:
+                default:
+                    params[i].tag = KM_TAG_INVALID;
+                    /* just skip */
+                    break;
+            }
+        }
+    }
+    KmParamSet(KmParamSet&& other) noexcept
+        : keymaster_key_param_set_t{other.params, other.length} {
+        other.length = 0;
+        other.params = nullptr;
+    }
+    KmParamSet(const KmParamSet&) = delete;
+    ~KmParamSet() { delete[] params; }
+};
+
+inline hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size);
+    return result;
+}
+
+inline hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length);
+    return result;
+}
+
+inline hidl_vec<uint8_t> kmBuffer2hidlVec(const ::keymaster::Buffer& buf) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(buf.peek_read()), buf.available_read());
+    return result;
+}
+
+inline static hidl_vec<hidl_vec<uint8_t>> kmCertChain2Hidl(
+        const keymaster_cert_chain_t& cert_chain) {
+    hidl_vec<hidl_vec<uint8_t>> result;
+    if (!cert_chain.entry_count || !cert_chain.entries) return result;
+
+    result.resize(cert_chain.entry_count);
+    for (size_t i = 0; i < cert_chain.entry_count; ++i) {
+        result[i] = kmBlob2hidlVec(cert_chain.entries[i]);
+    }
+
+    return result;
+}
+
+static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) {
+    hidl_vec<KeyParameter> result;
+    if (set.length == 0 || set.params == nullptr) return result;
+
+    result.resize(set.length);
+    keymaster_key_param_t* params = set.params;
+    for (size_t i = 0; i < set.length; ++i) {
+        auto tag = params[i].tag;
+        result[i].tag = legacy_enum_conversion(tag);
+        switch (typeFromTag(tag)) {
+            case KM_ENUM:
+            case KM_ENUM_REP:
+                result[i].f.integer = params[i].enumerated;
+                break;
+            case KM_UINT:
+            case KM_UINT_REP:
+                result[i].f.integer = params[i].integer;
+                break;
+            case KM_ULONG:
+            case KM_ULONG_REP:
+                result[i].f.longInteger = params[i].long_integer;
+                break;
+            case KM_DATE:
+                result[i].f.dateTime = params[i].date_time;
+                break;
+            case KM_BOOL:
+                result[i].f.boolValue = params[i].boolean;
+                break;
+            case KM_BIGNUM:
+            case KM_BYTES:
+                result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data),
+                                             params[i].blob.data_length);
+                break;
+            case KM_INVALID:
+            default:
+                params[i].tag = KM_TAG_INVALID;
+                /* just skip */
+                break;
+        }
+    }
+    return result;
+}
+
+void addClientAndAppData(const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                         ::keymaster::AuthorizationSet* params) {
+    params->Clear();
+    if (clientId.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_ID, clientId.data(), clientId.size());
+    }
+    if (appData.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_DATA, appData.data(), appData.size());
+    }
+}
+
+}  // anonymous namespace
+
+RemoteKeymaster4Device::RemoteKeymaster4Device(RemoteKeymaster* impl) : impl_(impl) {}
+
+RemoteKeymaster4Device::~RemoteKeymaster4Device() {}
+
+Return<void> RemoteKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_cb) {
+    _hidl_cb(SecurityLevel::TRUSTED_ENVIRONMENT, "RemoteKeymaster", "Google");
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::getHmacSharingParameters(
+        getHmacSharingParameters_cb _hidl_cb) {
+    const GetHmacSharingParametersResponse response = impl_->GetHmacSharingParameters();
+    // response.params is not the same as the HIDL structure, we need to convert it
+    HmacSharingParameters params;
+    params.seed.setToExternal(const_cast<uint8_t*>(response.params.seed.data),
+                              response.params.seed.data_length);
+    static_assert(sizeof(response.params.nonce) == params.nonce.size(), "Nonce sizes don't match");
+    memcpy(params.nonce.data(), response.params.nonce, params.nonce.size());
+    _hidl_cb(legacy_enum_conversion(response.error), params);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::computeSharedHmac(
+        const hidl_vec<HmacSharingParameters>& params, computeSharedHmac_cb _hidl_cb) {
+    ComputeSharedHmacRequest request(impl_->message_version());
+    request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()];
+    request.params_array.num_params = params.size();
+    for (size_t i = 0; i < params.size(); ++i) {
+        request.params_array.params_array[i].seed = {params[i].seed.data(), params[i].seed.size()};
+        static_assert(sizeof(request.params_array.params_array[i].nonce) ==
+                              decltype(params[i].nonce)::size(),
+                      "Nonce sizes don't match");
+        memcpy(request.params_array.params_array[i].nonce, params[i].nonce.data(),
+               params[i].nonce.size());
+    }
+
+    auto response = impl_->ComputeSharedHmac(request);
+    hidl_vec<uint8_t> sharing_check;
+    if (response.error == KM_ERROR_OK) {
+        sharing_check = kmBlob2hidlVec(response.sharing_check);
+    }
+
+    _hidl_cb(legacy_enum_conversion(response.error), sharing_check);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::verifyAuthorization(
+        uint64_t challenge, const hidl_vec<KeyParameter>& parametersToVerify,
+        const HardwareAuthToken& authToken, verifyAuthorization_cb _hidl_cb) {
+    VerifyAuthorizationRequest request(impl_->message_version());
+    request.challenge = challenge;
+    request.parameters_to_verify.Reinitialize(KmParamSet(parametersToVerify));
+    request.auth_token.challenge = authToken.challenge;
+    request.auth_token.user_id = authToken.userId;
+    request.auth_token.authenticator_id = authToken.authenticatorId;
+    request.auth_token.authenticator_type = legacy_enum_conversion(authToken.authenticatorType);
+    request.auth_token.timestamp = authToken.timestamp;
+    KeymasterBlob mac(authToken.mac.data(), authToken.mac.size());
+    request.auth_token.mac = mac;
+
+    auto response = impl_->VerifyAuthorization(request);
+
+    ::android::hardware::keymaster::V4_0::VerificationToken token;
+    token.challenge = response.token.challenge;
+    token.timestamp = response.token.timestamp;
+    token.parametersVerified = kmParamSet2Hidl(response.token.parameters_verified);
+    token.securityLevel = legacy_enum_conversion(response.token.security_level);
+    token.mac = kmBlob2hidlVec(response.token.mac);
+
+    _hidl_cb(legacy_enum_conversion(response.error), token);
+
+    return Void();
+}
+
+Return<ErrorCode> RemoteKeymaster4Device::addRngEntropy(const hidl_vec<uint8_t>& data) {
+    if (data.size() == 0) return ErrorCode::OK;
+    AddEntropyRequest request(impl_->message_version());
+    request.random_data.Reinitialize(data.data(), data.size());
+
+    AddEntropyResponse response(impl_->message_version());
+    impl_->AddRngEntropy(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+
+Return<void> RemoteKeymaster4Device::generateKey(const hidl_vec<KeyParameter>& keyParams,
+                                                 generateKey_cb _hidl_cb) {
+    GenerateKeyRequest request(impl_->message_version());
+    request.key_description.Reinitialize(KmParamSet(keyParams));
+
+    GenerateKeyResponse response(impl_->message_version());
+    impl_->GenerateKey(request, &response);
+
+    KeyCharacteristics resultCharacteristics;
+    hidl_vec<uint8_t> resultKeyBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+        resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                                           const hidl_vec<uint8_t>& clientId,
+                                                           const hidl_vec<uint8_t>& appData,
+                                                           getKeyCharacteristics_cb _hidl_cb) {
+    GetKeyCharacteristicsRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    addClientAndAppData(clientId, appData, &request.additional_params);
+
+    GetKeyCharacteristicsResponse response(impl_->message_version());
+    impl_->GetKeyCharacteristics(request, &response);
+
+    KeyCharacteristics resultCharacteristics;
+    if (response.error == KM_ERROR_OK) {
+        resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultCharacteristics);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::importKey(const hidl_vec<KeyParameter>& params,
+                                               KeyFormat keyFormat,
+                                               const hidl_vec<uint8_t>& keyData,
+                                               importKey_cb _hidl_cb) {
+    ImportKeyRequest request(impl_->message_version());
+    request.key_description.Reinitialize(KmParamSet(params));
+    request.key_format = legacy_enum_conversion(keyFormat);
+    request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
+
+    ImportKeyResponse response(impl_->message_version());
+    impl_->ImportKey(request, &response);
+
+    KeyCharacteristics resultCharacteristics;
+    hidl_vec<uint8_t> resultKeyBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+        resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::importWrappedKey(
+        const hidl_vec<uint8_t>& wrappedKeyData, const hidl_vec<uint8_t>& wrappingKeyBlob,
+        const hidl_vec<uint8_t>& maskingKey, const hidl_vec<KeyParameter>& unwrappingParams,
+        uint64_t passwordSid, uint64_t biometricSid, importWrappedKey_cb _hidl_cb) {
+    ImportWrappedKeyRequest request(impl_->message_version());
+    request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
+    request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
+    request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
+    request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
+    request.password_sid = passwordSid;
+    request.biometric_sid = biometricSid;
+
+    ImportWrappedKeyResponse response(impl_->message_version());
+    impl_->ImportWrappedKey(request, &response);
+
+    KeyCharacteristics resultCharacteristics;
+    hidl_vec<uint8_t> resultKeyBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+        resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::exportKey(KeyFormat exportFormat,
+                                               const hidl_vec<uint8_t>& keyBlob,
+                                               const hidl_vec<uint8_t>& clientId,
+                                               const hidl_vec<uint8_t>& appData,
+                                               exportKey_cb _hidl_cb) {
+    ExportKeyRequest request(impl_->message_version());
+    request.key_format = legacy_enum_conversion(exportFormat);
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    addClientAndAppData(clientId, appData, &request.additional_params);
+
+    ExportKeyResponse response(impl_->message_version());
+    impl_->ExportKey(request, &response);
+
+    hidl_vec<uint8_t> resultKeyBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultKeyBlob.setToExternal(response.key_data, response.key_data_length);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                                               const hidl_vec<KeyParameter>& attestParams,
+                                               attestKey_cb _hidl_cb) {
+    AttestKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyToAttest.data(), keyToAttest.size());
+    request.attest_params.Reinitialize(KmParamSet(attestParams));
+
+    AttestKeyResponse response(impl_->message_version());
+    impl_->AttestKey(request, &response);
+
+    hidl_vec<hidl_vec<uint8_t>> resultCertChain;
+    if (response.error == KM_ERROR_OK) {
+        resultCertChain = kmCertChain2Hidl(response.certificate_chain);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultCertChain);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                                                const hidl_vec<KeyParameter>& upgradeParams,
+                                                upgradeKey_cb _hidl_cb) {
+    UpgradeKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+    request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+    UpgradeKeyResponse response(impl_->message_version());
+    impl_->UpgradeKey(request, &response);
+
+    if (response.error == KM_ERROR_OK) {
+        _hidl_cb(ErrorCode::OK, kmBlob2hidlVec(response.upgraded_key));
+    } else {
+        _hidl_cb(legacy_enum_conversion(response.error), hidl_vec<uint8_t>());
+    }
+    return Void();
+}
+
+Return<ErrorCode> RemoteKeymaster4Device::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+    DeleteKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+    DeleteKeyResponse response(impl_->message_version());
+    impl_->DeleteKey(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+
+Return<ErrorCode> RemoteKeymaster4Device::deleteAllKeys() {
+    DeleteAllKeysRequest request(impl_->message_version());
+    DeleteAllKeysResponse response(impl_->message_version());
+    impl_->DeleteAllKeys(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+
+Return<ErrorCode> RemoteKeymaster4Device::destroyAttestationIds() {
+    return ErrorCode::UNIMPLEMENTED;
+}
+
+Return<void> RemoteKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                                           const hidl_vec<KeyParameter>& inParams,
+                                           const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
+    BeginOperationRequest request(impl_->message_version());
+    request.purpose = legacy_enum_conversion(purpose);
+    request.SetKeyMaterial(key.data(), key.size());
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
+
+    BeginOperationResponse response(impl_->message_version());
+    impl_->BeginOperation(request, &response);
+
+    hidl_vec<KeyParameter> resultParams;
+    if (response.error == KM_ERROR_OK) {
+        resultParams = kmParamSet2Hidl(response.output_params);
+    }
+
+    _hidl_cb(legacy_enum_conversion(response.error), resultParams, response.op_handle);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::update(uint64_t operationHandle,
+                                            const hidl_vec<KeyParameter>& inParams,
+                                            const hidl_vec<uint8_t>& input,
+                                            const HardwareAuthToken& authToken,
+                                            const VerificationToken& /* verificationToken */,
+                                            update_cb _hidl_cb) {
+    UpdateOperationRequest request(impl_->message_version());
+    UpdateOperationResponse response(impl_->message_version());
+    hidl_vec<KeyParameter> resultParams;
+    hidl_vec<uint8_t> resultBlob;
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
+    uint32_t resultConsumed = 0;
+
+    request.op_handle = operationHandle;
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
+
+    // TODO(schuffelen): Set a buffer size limit.
+    request.input.Reinitialize(input.data(), input.size());
+
+    impl_->UpdateOperation(request, &response);
+
+    if (response.error == KM_ERROR_OK) {
+        resultConsumed = response.input_consumed;
+        resultParams = kmParamSet2Hidl(response.output_params);
+        resultBlob = kmBuffer2hidlVec(response.output);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultConsumed, resultParams, resultBlob);
+    return Void();
+}
+
+Return<void> RemoteKeymaster4Device::finish(uint64_t operationHandle,
+                                            const hidl_vec<KeyParameter>& inParams,
+                                            const hidl_vec<uint8_t>& input,
+                                            const hidl_vec<uint8_t>& signature,
+                                            const HardwareAuthToken& authToken,
+                                            const VerificationToken& verificationToken,
+                                            finish_cb _hidl_cb) {
+    (void)verificationToken;
+    FinishOperationRequest request(impl_->message_version());
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
+    request.op_handle = operationHandle;
+    request.input.Reinitialize(input.data(), input.size());
+    request.signature.Reinitialize(signature.data(), signature.size());
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
+
+    FinishOperationResponse response(impl_->message_version());
+    impl_->FinishOperation(request, &response);
+
+    hidl_vec<KeyParameter> resultParams;
+    hidl_vec<uint8_t> resultBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultParams = kmParamSet2Hidl(response.output_params);
+        resultBlob = kmBuffer2hidlVec(response.output);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultParams, resultBlob);
+    return Void();
+}
+
+Return<ErrorCode> RemoteKeymaster4Device::abort(uint64_t operationHandle) {
+    AbortOperationRequest request(impl_->message_version());
+    request.op_handle = operationHandle;
+
+    AbortOperationResponse response(impl_->message_version());
+    impl_->AbortOperation(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+
+Return<ErrorCodeV41> RemoteKeymaster4Device::deviceLocked(
+    bool passwordOnly, const VerificationToken& verificationToken) {
+    keymaster::VerificationToken internal_verification_token;
+    internal_verification_token.challenge = verificationToken.challenge;
+    internal_verification_token.timestamp = verificationToken.timestamp;
+    internal_verification_token.parameters_verified.Reinitialize(
+        KmParamSet(verificationToken.parametersVerified));
+    internal_verification_token.security_level =
+        static_cast<keymaster_security_level_t>(verificationToken.securityLevel);
+    internal_verification_token.mac =
+        KeymasterBlob(verificationToken.mac.data(), verificationToken.mac.size());
+
+    DeviceLockedRequest request(impl_->message_version(),
+        passwordOnly, std::move(internal_verification_token));
+
+    auto response = impl_->DeviceLocked(request);
+
+    return ErrorCodeV41(response.error);
+}
+
+Return<ErrorCodeV41> RemoteKeymaster4Device::earlyBootEnded() {
+    auto response = impl_->EarlyBootEnded();
+
+    return ErrorCodeV41(response.error);
+}
+
+}  // namespace V4_1
+}  // namespace keymaster
diff --git a/guest/hals/keymaster/remote/remote_keymaster4_device.h b/guest/hals/keymaster/remote/remote_keymaster4_device.h
new file mode 100644
index 0000000..ec76f7c
--- /dev/null
+++ b/guest/hals/keymaster/remote/remote_keymaster4_device.h
@@ -0,0 +1,110 @@
+/*
+ **
+ ** Copyright 2017, 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 <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <hidl/Status.h>
+#include "guest/hals/keymaster/remote/remote_keymaster.h"
+
+namespace keymaster {
+
+namespace V4_1 {
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::keymaster::V4_0::ErrorCode;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HmacSharingParameters;
+using ::android::hardware::keymaster::V4_0::KeyCharacteristics;
+using ::android::hardware::keymaster::V4_0::KeyFormat;
+using ::android::hardware::keymaster::V4_0::KeyParameter;
+using ::android::hardware::keymaster::V4_0::KeyPurpose;
+using ::android::hardware::keymaster::V4_0::SecurityLevel;
+using ::android::hardware::keymaster::V4_0::Tag;
+using ::android::hardware::keymaster::V4_0::VerificationToken;
+using ::android::hardware::keymaster::V4_1::IKeymasterDevice;
+
+using ErrorCodeV41 = ::android::hardware::keymaster::V4_1::ErrorCode;
+
+class RemoteKeymaster4Device : public IKeymasterDevice {
+  public:
+    explicit RemoteKeymaster4Device(RemoteKeymaster* impl);
+    virtual ~RemoteKeymaster4Device();
+
+    Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override;
+    Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override;
+    Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+                                   computeSharedHmac_cb) override;
+    Return<void> verifyAuthorization(uint64_t challenge,
+                                     const hidl_vec<KeyParameter>& parametersToVerify,
+                                     const HardwareAuthToken& authToken,
+                                     verifyAuthorization_cb _hidl_cb) override;
+    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+                             generateKey_cb _hidl_cb) override;
+    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                       const hidl_vec<uint8_t>& clientId,
+                                       const hidl_vec<uint8_t>& appData,
+                                       getKeyCharacteristics_cb _hidl_cb) override;
+    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+    Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+                                  const hidl_vec<uint8_t>& wrappingKeyBlob,
+                                  const hidl_vec<uint8_t>& maskingKey,
+                                  const hidl_vec<KeyParameter>& unwrappingParams,
+                                  uint64_t passwordSid, uint64_t biometricSid,
+                                  importWrappedKey_cb _hidl_cb) override;
+    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                           exportKey_cb _hidl_cb) override;
+    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                           const hidl_vec<KeyParameter>& attestParams,
+                           attestKey_cb _hidl_cb) override;
+    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                            const hidl_vec<KeyParameter>& upgradeParams,
+                            upgradeKey_cb _hidl_cb) override;
+    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+    Return<ErrorCode> deleteAllKeys() override;
+    Return<ErrorCode> destroyAttestationIds() override;
+    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                       const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                       begin_cb _hidl_cb) override;
+    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, update_cb _hidl_cb) override;
+    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                        const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
+    Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+    // 4.1
+    Return<ErrorCodeV41> deviceLocked(
+        bool passwordOnly, const VerificationToken& verificationToken) override;
+    Return<ErrorCodeV41> earlyBootEnded() override;
+
+  private:
+    std::unique_ptr<::keymaster::RemoteKeymaster> impl_;
+};
+
+}  // namespace V4_1
+}  // namespace keymaster
diff --git a/guest/hals/keymaster/remote/service4.cpp b/guest/hals/keymaster/remote/service4.cpp
new file mode 100644
index 0000000..47f6261
--- /dev/null
+++ b/guest/hals/keymaster/remote/service4.cpp
@@ -0,0 +1,66 @@
+/*
+**
+** Copyright 2018, 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.
+*/
+
+#include <android-base/logging.h>
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <cutils/properties.h>
+#include <gflags/gflags.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/keymaster_channel.h"
+#include <guest/hals/keymaster/remote/remote_keymaster.h>
+#include <guest/hals/keymaster/remote/remote_keymaster4_device.h>
+
+const char device[] = "/dev/hvc3";
+
+int main(int argc, char** argv) {
+  ::android::base::InitLogging(argv, ::android::base::KernelLogger);
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
+  ::android::hardware::configureRpcThreadpool(1, true);
+
+  LOG(INFO) << "Starting keymaster service4";
+
+  auto fd = cuttlefish::SharedFD::Open(device, O_RDWR);
+  if (!fd->IsOpen()) {
+    LOG(FATAL) << "Could not connect to keymaster: " << fd->StrError();
+  }
+
+  if (fd->SetTerminalRaw() < 0) {
+    LOG(FATAL) << "Could not make " << device << " a raw terminal: "
+                << fd->StrError();
+  }
+
+  cuttlefish::KeymasterChannel keymasterChannel(fd, fd);
+
+  auto remoteKeymaster = new keymaster::RemoteKeymaster(&keymasterChannel);
+
+  if (!remoteKeymaster->Initialize()) {
+    LOG(FATAL) << "Could not initialize keymaster";
+  }
+
+  auto keymaster = new ::keymaster::V4_1::RemoteKeymaster4Device(remoteKeymaster);
+
+  auto status = keymaster->registerAsService();
+  if (status != android::OK) {
+    LOG(FATAL) << "Could not register service for Keymaster 4.1 (" << status << ")";
+    return -1;
+  }
+
+  android::hardware::joinRpcThreadpool();
+  return -1;  // Should never get here.
+}
diff --git a/guest/hals/keymint/OWNERS b/guest/hals/keymint/OWNERS
new file mode 100644
index 0000000..fb015cb
--- /dev/null
+++ b/guest/hals/keymint/OWNERS
@@ -0,0 +1 @@
+include platform/system/keymaster:/OWNERS
diff --git a/guest/hals/keymint/remote/Android.bp b/guest/hals/keymint/remote/Android.bp
new file mode 100644
index 0000000..a383c45
--- /dev/null
+++ b/guest/hals/keymint/remote/Android.bp
@@ -0,0 +1,62 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.security.keymint-service.remote",
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.security.keymint-service.remote.rc"],
+    vintf_fragments: [
+        "android.hardware.security.keymint-service.remote.xml",
+        "android.hardware.security.sharedsecret-service.remote.xml",
+        "android.hardware.security.secureclock-service.remote.xml",
+    ],
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
+        "lib_android_keymaster_keymint_utils",
+        "libbase",
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcrypto",
+        "libcuttlefish_fs",
+        "libcuttlefish_security",
+        "libhardware",
+        "libkeymaster_messages",
+        "libkeymint",
+        "liblog",
+        "libutils",
+    ],
+    srcs: [
+        "remote_keymint_device.cpp",
+        "remote_keymint_operation.cpp",
+        "remote_keymaster.cpp",
+        "remote_secure_clock.cpp",
+        "remote_shared_secret.cpp",
+        "service.cpp",
+    ],
+    defaults: [
+        "cuttlefish_guest_only",
+    ],
+}
diff --git a/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.rc b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.rc
new file mode 100644
index 0000000..422fe17
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.rc
@@ -0,0 +1,3 @@
+service vendor.keymint-remote /vendor/bin/hw/android.hardware.security.keymint-service.remote
+    class early_hal
+    user nobody
diff --git a/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.xml b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.xml
new file mode 100644
index 0000000..4aa05ef
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <fqname>IKeyMintDevice/default</fqname>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <fqname>IRemotelyProvisionedComponent/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/keymint/remote/android.hardware.security.secureclock-service.remote.xml b/guest/hals/keymint/remote/android.hardware.security.secureclock-service.remote.xml
new file mode 100644
index 0000000..c0ff775
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.secureclock-service.remote.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.secureclock</name>
+        <fqname>ISecureClock/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/keymint/remote/android.hardware.security.sharedsecret-service.remote.xml b/guest/hals/keymint/remote/android.hardware.security.sharedsecret-service.remote.xml
new file mode 100644
index 0000000..d37981f
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.sharedsecret-service.remote.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.sharedsecret</name>
+        <fqname>ISharedSecret/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/keymint/remote/remote_keymaster.cpp b/guest/hals/keymint/remote/remote_keymaster.cpp
new file mode 100644
index 0000000..5eee143
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymaster.cpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "remote_keymaster.h"
+
+#include <android-base/logging.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/keymaster_configuration.h>
+
+namespace keymaster {
+
+RemoteKeymaster::RemoteKeymaster(cuttlefish::KeymasterChannel* channel,
+                                 uint32_t message_version)
+    : channel_(channel), message_version_(message_version) {}
+
+RemoteKeymaster::~RemoteKeymaster() {}
+
+void RemoteKeymaster::ForwardCommand(AndroidKeymasterCommand command,
+                                     const Serializable& req,
+                                     KeymasterResponse* rsp) {
+  if (!channel_->SendRequest(command, req)) {
+    LOG(ERROR) << "Failed to send keymaster message: " << command;
+    rsp->error = KM_ERROR_UNKNOWN_ERROR;
+    return;
+  }
+  auto response = channel_->ReceiveMessage();
+  if (!response) {
+    LOG(ERROR) << "Failed to receive keymaster response: " << command;
+    rsp->error = KM_ERROR_UNKNOWN_ERROR;
+    return;
+  }
+  const uint8_t* buffer = response->payload;
+  const uint8_t* buffer_end = response->payload + response->payload_size;
+  if (!rsp->Deserialize(&buffer, buffer_end)) {
+    LOG(ERROR) << "Failed to deserialize keymaster response: " << command;
+    rsp->error = KM_ERROR_UNKNOWN_ERROR;
+    return;
+  }
+}
+
+bool RemoteKeymaster::Initialize() {
+  // We don't need to bother with GetVersion, because CF HAL and remote sides
+  // are always compiled together, so will never disagree about message
+  // versions.
+  ConfigureRequest req(message_version());
+  req.os_version = GetOsVersion();
+  req.os_patchlevel = GetOsPatchlevel();
+
+  ConfigureResponse rsp(message_version());
+  Configure(req, &rsp);
+
+  if (rsp.error != KM_ERROR_OK) {
+    LOG(ERROR) << "Failed to configure keymaster: " << rsp.error;
+    return false;
+  }
+
+  return true;
+}
+
+void RemoteKeymaster::GetVersion(const GetVersionRequest& request,
+                                 GetVersionResponse* response) {
+  ForwardCommand(GET_VERSION, request, response);
+}
+
+void RemoteKeymaster::SupportedAlgorithms(
+    const SupportedAlgorithmsRequest& request,
+    SupportedAlgorithmsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_ALGORITHMS, request, response);
+}
+
+void RemoteKeymaster::SupportedBlockModes(
+    const SupportedBlockModesRequest& request,
+    SupportedBlockModesResponse* response) {
+  ForwardCommand(GET_SUPPORTED_BLOCK_MODES, request, response);
+}
+
+void RemoteKeymaster::SupportedPaddingModes(
+    const SupportedPaddingModesRequest& request,
+    SupportedPaddingModesResponse* response) {
+  ForwardCommand(GET_SUPPORTED_PADDING_MODES, request, response);
+}
+
+void RemoteKeymaster::SupportedDigests(const SupportedDigestsRequest& request,
+                                       SupportedDigestsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_DIGESTS, request, response);
+}
+
+void RemoteKeymaster::SupportedImportFormats(
+    const SupportedImportFormatsRequest& request,
+    SupportedImportFormatsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_IMPORT_FORMATS, request, response);
+}
+
+void RemoteKeymaster::SupportedExportFormats(
+    const SupportedExportFormatsRequest& request,
+    SupportedExportFormatsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_EXPORT_FORMATS, request, response);
+}
+
+void RemoteKeymaster::AddRngEntropy(const AddEntropyRequest& request,
+                                    AddEntropyResponse* response) {
+  ForwardCommand(ADD_RNG_ENTROPY, request, response);
+}
+
+void RemoteKeymaster::Configure(const ConfigureRequest& request,
+                                ConfigureResponse* response) {
+  ForwardCommand(CONFIGURE, request, response);
+}
+
+void RemoteKeymaster::GenerateKey(const GenerateKeyRequest& request,
+                                  GenerateKeyResponse* response) {
+  GenerateKeyRequest datedRequest(request.message_version);
+  datedRequest.key_description = request.key_description;
+
+  if (!request.key_description.Contains(TAG_CREATION_DATETIME)) {
+    datedRequest.key_description.push_back(TAG_CREATION_DATETIME,
+                                           java_time(time(NULL)));
+  }
+
+  ForwardCommand(GENERATE_KEY, datedRequest, response);
+}
+
+void RemoteKeymaster::GetKeyCharacteristics(
+    const GetKeyCharacteristicsRequest& request,
+    GetKeyCharacteristicsResponse* response) {
+  ForwardCommand(GET_KEY_CHARACTERISTICS, request, response);
+}
+
+void RemoteKeymaster::ImportKey(const ImportKeyRequest& request,
+                                ImportKeyResponse* response) {
+  ForwardCommand(IMPORT_KEY, request, response);
+}
+
+void RemoteKeymaster::ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                                       ImportWrappedKeyResponse* response) {
+  ForwardCommand(IMPORT_WRAPPED_KEY, request, response);
+}
+
+void RemoteKeymaster::ExportKey(const ExportKeyRequest& request,
+                                ExportKeyResponse* response) {
+  ForwardCommand(EXPORT_KEY, request, response);
+}
+
+void RemoteKeymaster::AttestKey(const AttestKeyRequest& request,
+                                AttestKeyResponse* response) {
+  ForwardCommand(ATTEST_KEY, request, response);
+}
+
+void RemoteKeymaster::UpgradeKey(const UpgradeKeyRequest& request,
+                                 UpgradeKeyResponse* response) {
+  ForwardCommand(UPGRADE_KEY, request, response);
+}
+
+void RemoteKeymaster::DeleteKey(const DeleteKeyRequest& request,
+                                DeleteKeyResponse* response) {
+  ForwardCommand(DELETE_KEY, request, response);
+}
+
+void RemoteKeymaster::DeleteAllKeys(const DeleteAllKeysRequest& request,
+                                    DeleteAllKeysResponse* response) {
+  ForwardCommand(DELETE_ALL_KEYS, request, response);
+}
+
+void RemoteKeymaster::BeginOperation(const BeginOperationRequest& request,
+                                     BeginOperationResponse* response) {
+  ForwardCommand(BEGIN_OPERATION, request, response);
+}
+
+void RemoteKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+                                      UpdateOperationResponse* response) {
+  ForwardCommand(UPDATE_OPERATION, request, response);
+}
+
+void RemoteKeymaster::FinishOperation(const FinishOperationRequest& request,
+                                      FinishOperationResponse* response) {
+  ForwardCommand(FINISH_OPERATION, request, response);
+}
+
+void RemoteKeymaster::AbortOperation(const AbortOperationRequest& request,
+                                     AbortOperationResponse* response) {
+  ForwardCommand(ABORT_OPERATION, request, response);
+}
+
+GetHmacSharingParametersResponse RemoteKeymaster::GetHmacSharingParameters() {
+  // Unused empty buffer to allow ForwardCommand to have something to serialize
+  Buffer request;
+  GetHmacSharingParametersResponse response(message_version());
+  ForwardCommand(GET_HMAC_SHARING_PARAMETERS, request, &response);
+  return response;
+}
+
+ComputeSharedHmacResponse RemoteKeymaster::ComputeSharedHmac(
+    const ComputeSharedHmacRequest& request) {
+  ComputeSharedHmacResponse response(message_version());
+  ForwardCommand(COMPUTE_SHARED_HMAC, request, &response);
+  return response;
+}
+
+VerifyAuthorizationResponse RemoteKeymaster::VerifyAuthorization(
+    const VerifyAuthorizationRequest& request) {
+  VerifyAuthorizationResponse response(message_version());
+  ForwardCommand(VERIFY_AUTHORIZATION, request, &response);
+  return response;
+}
+
+DeviceLockedResponse RemoteKeymaster::DeviceLocked(
+    const DeviceLockedRequest& request) {
+  DeviceLockedResponse response(message_version());
+  ForwardCommand(DEVICE_LOCKED, request, &response);
+  return response;
+}
+
+EarlyBootEndedResponse RemoteKeymaster::EarlyBootEnded() {
+  // Unused empty buffer to allow ForwardCommand to have something to serialize
+  Buffer request;
+  EarlyBootEndedResponse response(message_version());
+  ForwardCommand(EARLY_BOOT_ENDED, request, &response);
+  return response;
+}
+
+void RemoteKeymaster::GenerateTimestampToken(
+    GenerateTimestampTokenRequest& request,
+    GenerateTimestampTokenResponse* response) {
+  // TODO(aosp/1641315): Send a message to the host.
+  ForwardCommand(GENERATE_TIMESTAMP_TOKEN, request, response);
+}
+
+}  // namespace keymaster
diff --git a/guest/hals/keymint/remote/remote_keymaster.h b/guest/hals/keymint/remote/remote_keymaster.h
new file mode 100644
index 0000000..bd86012
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymaster.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef REMOTE_KEYMASTER_H_
+#define REMOTE_KEYMASTER_H_
+
+#include <keymaster/android_keymaster_messages.h>
+
+#include "common/libs/security/keymaster_channel.h"
+
+namespace keymaster {
+
+class RemoteKeymaster {
+ private:
+  cuttlefish::KeymasterChannel* channel_;
+  const uint32_t message_version_;
+
+  void ForwardCommand(AndroidKeymasterCommand command, const Serializable& req,
+                      KeymasterResponse* rsp);
+
+ public:
+  RemoteKeymaster(cuttlefish::KeymasterChannel*,
+                  uint32_t message_version = kDefaultMessageVersion);
+  ~RemoteKeymaster();
+  bool Initialize();
+  void GetVersion(const GetVersionRequest& request,
+                  GetVersionResponse* response);
+  void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+                           SupportedAlgorithmsResponse* response);
+  void SupportedBlockModes(const SupportedBlockModesRequest& request,
+                           SupportedBlockModesResponse* response);
+  void SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                             SupportedPaddingModesResponse* response);
+  void SupportedDigests(const SupportedDigestsRequest& request,
+                        SupportedDigestsResponse* response);
+  void SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                              SupportedImportFormatsResponse* response);
+  void SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                              SupportedExportFormatsResponse* response);
+  void AddRngEntropy(const AddEntropyRequest& request,
+                     AddEntropyResponse* response);
+  void Configure(const ConfigureRequest& request, ConfigureResponse* response);
+  void GenerateKey(const GenerateKeyRequest& request,
+                   GenerateKeyResponse* response);
+  void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+                             GetKeyCharacteristicsResponse* response);
+  void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
+  void ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                        ImportWrappedKeyResponse* response);
+  void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
+  void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+  void UpgradeKey(const UpgradeKeyRequest& request,
+                  UpgradeKeyResponse* response);
+  void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
+  void DeleteAllKeys(const DeleteAllKeysRequest& request,
+                     DeleteAllKeysResponse* response);
+  void BeginOperation(const BeginOperationRequest& request,
+                      BeginOperationResponse* response);
+  void UpdateOperation(const UpdateOperationRequest& request,
+                       UpdateOperationResponse* response);
+  void FinishOperation(const FinishOperationRequest& request,
+                       FinishOperationResponse* response);
+  void AbortOperation(const AbortOperationRequest& request,
+                      AbortOperationResponse* response);
+  GetHmacSharingParametersResponse GetHmacSharingParameters();
+  ComputeSharedHmacResponse ComputeSharedHmac(
+      const ComputeSharedHmacRequest& request);
+  VerifyAuthorizationResponse VerifyAuthorization(
+      const VerifyAuthorizationRequest& request);
+  DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
+  EarlyBootEndedResponse EarlyBootEnded();
+  void GenerateTimestampToken(GenerateTimestampTokenRequest& request,
+                              GenerateTimestampTokenResponse* response);
+
+  // CF HAL and remote sides are always compiled together, so will never
+  // disagree about message versions.
+  uint32_t message_version() { return message_version_; }
+};
+
+}  // namespace keymaster
+
+#endif  // REMOTE_KEYMASTER_H_
diff --git a/guest/hals/keymint/remote/remote_keymint_device.cpp b/guest/hals/keymint/remote/remote_keymint_device.cpp
new file mode 100644
index 0000000..55903b7
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_device.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-impl.remote"
+#include <android-base/logging.h>
+
+#include "guest/hals/keymint/remote/remote_keymint_device.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/keymaster_configuration.h>
+
+#include "KeyMintUtils.h"
+#include "guest/hals/keymint/remote/remote_keymint_operation.h"
+
+namespace aidl::android::hardware::security::keymint {
+
+using namespace ::keymaster;
+using namespace km_utils;
+using secureclock::TimeStampToken;
+
+namespace {
+
+vector<KeyCharacteristics> convertKeyCharacteristics(
+    SecurityLevel keyMintSecurityLevel, const AuthorizationSet& sw_enforced,
+    const AuthorizationSet& hw_enforced) {
+  KeyCharacteristics keyMintEnforced{keyMintSecurityLevel, {}};
+
+  if (keyMintSecurityLevel != SecurityLevel::SOFTWARE) {
+    // We're pretending to be TRUSTED_ENVIRONMENT or STRONGBOX.
+    keyMintEnforced.authorizations = kmParamSet2Aidl(hw_enforced);
+    // Put all the software authorizations in the keystore list.
+    KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE,
+                                        kmParamSet2Aidl(sw_enforced)};
+    return {std::move(keyMintEnforced), std::move(keystoreEnforced)};
+  }
+
+  KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE, {}};
+  CHECK(hw_enforced.empty())
+      << "Hardware-enforced list is non-empty for pure SW KeyMint";
+
+  // This is a pure software implementation, so all tags are in sw_enforced.
+  // We need to walk through the SW-enforced list and figure out which tags to
+  // return in the software list and which in the keystore list.
+
+  for (auto& entry : sw_enforced) {
+    switch (entry.tag) {
+      /* Invalid and unused */
+      case KM_TAG_ECIES_SINGLE_HASH_MODE:
+      case KM_TAG_INVALID:
+      case KM_TAG_KDF:
+      case KM_TAG_ROLLBACK_RESISTANCE:
+        CHECK(false) << "We shouldn't see tag " << entry.tag;
+        break;
+
+      /* Unimplemented */
+      case KM_TAG_ALLOW_WHILE_ON_BODY:
+      case KM_TAG_BOOTLOADER_ONLY:
+      case KM_TAG_ROLLBACK_RESISTANT:
+      case KM_TAG_STORAGE_KEY:
+        break;
+
+      /* Unenforceable */
+      case KM_TAG_CREATION_DATETIME:
+        break;
+
+      /* Disallowed in KeyCharacteristics */
+      case KM_TAG_APPLICATION_DATA:
+      case KM_TAG_ATTESTATION_APPLICATION_ID:
+        break;
+
+      /* Not key characteristics */
+      case KM_TAG_ASSOCIATED_DATA:
+      case KM_TAG_ATTESTATION_CHALLENGE:
+      case KM_TAG_ATTESTATION_ID_BRAND:
+      case KM_TAG_ATTESTATION_ID_DEVICE:
+      case KM_TAG_ATTESTATION_ID_IMEI:
+      case KM_TAG_ATTESTATION_ID_MANUFACTURER:
+      case KM_TAG_ATTESTATION_ID_MEID:
+      case KM_TAG_ATTESTATION_ID_MODEL:
+      case KM_TAG_ATTESTATION_ID_PRODUCT:
+      case KM_TAG_ATTESTATION_ID_SERIAL:
+      case KM_TAG_AUTH_TOKEN:
+      case KM_TAG_CERTIFICATE_SERIAL:
+      case KM_TAG_CERTIFICATE_SUBJECT:
+      case KM_TAG_CERTIFICATE_NOT_AFTER:
+      case KM_TAG_CERTIFICATE_NOT_BEFORE:
+      case KM_TAG_CONFIRMATION_TOKEN:
+      case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+      case KM_TAG_IDENTITY_CREDENTIAL_KEY:
+      case KM_TAG_MAC_LENGTH:
+      case KM_TAG_NONCE:
+      case KM_TAG_RESET_SINCE_ID_ROTATION:
+      case KM_TAG_ROOT_OF_TRUST:
+      case KM_TAG_UNIQUE_ID:
+        break;
+
+      /* KeyMint-enforced */
+      case KM_TAG_ALGORITHM:
+      case KM_TAG_APPLICATION_ID:
+      case KM_TAG_AUTH_TIMEOUT:
+      case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+      case KM_TAG_BLOCK_MODE:
+      case KM_TAG_BOOT_PATCHLEVEL:
+      case KM_TAG_CALLER_NONCE:
+      case KM_TAG_DIGEST:
+      case KM_TAG_EARLY_BOOT_ONLY:
+      case KM_TAG_EC_CURVE:
+      case KM_TAG_EXPORTABLE:
+      case KM_TAG_INCLUDE_UNIQUE_ID:
+      case KM_TAG_KEY_SIZE:
+      case KM_TAG_MAX_USES_PER_BOOT:
+      case KM_TAG_MIN_MAC_LENGTH:
+      case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+      case KM_TAG_NO_AUTH_REQUIRED:
+      case KM_TAG_ORIGIN:
+      case KM_TAG_OS_PATCHLEVEL:
+      case KM_TAG_OS_VERSION:
+      case KM_TAG_PADDING:
+      case KM_TAG_PURPOSE:
+      case KM_TAG_RSA_OAEP_MGF_DIGEST:
+      case KM_TAG_RSA_PUBLIC_EXPONENT:
+      case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+      case KM_TAG_USER_AUTH_TYPE:
+      case KM_TAG_USER_SECURE_ID:
+      case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
+      case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+      case KM_TAG_VENDOR_PATCHLEVEL:
+        keyMintEnforced.authorizations.push_back(kmParam2Aidl(entry));
+        break;
+
+      /* Keystore-enforced */
+      case KM_TAG_ACTIVE_DATETIME:
+      case KM_TAG_ALL_APPLICATIONS:
+      case KM_TAG_ALL_USERS:
+      case KM_TAG_MAX_BOOT_LEVEL:
+      case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+      case KM_TAG_USAGE_EXPIRE_DATETIME:
+      case KM_TAG_USER_ID:
+      case KM_TAG_USAGE_COUNT_LIMIT:
+        keystoreEnforced.authorizations.push_back(kmParam2Aidl(entry));
+        break;
+    }
+  }
+
+  vector<KeyCharacteristics> retval;
+  retval.reserve(2);
+  if (!keyMintEnforced.authorizations.empty())
+    retval.push_back(std::move(keyMintEnforced));
+  if (!keystoreEnforced.authorizations.empty())
+    retval.push_back(std::move(keystoreEnforced));
+
+  return retval;
+}
+
+Certificate convertCertificate(const keymaster_blob_t& cert) {
+  return {std::vector<uint8_t>(cert.data, cert.data + cert.data_length)};
+}
+
+vector<Certificate> convertCertificateChain(const CertificateChain& chain) {
+  vector<Certificate> retval;
+  retval.reserve(chain.entry_count);
+  std::transform(chain.begin(), chain.end(), std::back_inserter(retval),
+                 convertCertificate);
+  return retval;
+}
+
+}  // namespace
+
+RemoteKeyMintDevice::RemoteKeyMintDevice(::keymaster::RemoteKeymaster& impl,
+                                         SecurityLevel securityLevel)
+    : impl_(impl), securityLevel_(securityLevel) {}
+
+RemoteKeyMintDevice::~RemoteKeyMintDevice() {}
+
+ScopedAStatus RemoteKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
+  info->versionNumber = 1;
+  info->securityLevel = securityLevel_;
+  info->keyMintName = "RemoteKeyMintDevice";
+  info->keyMintAuthorName = "Google";
+  info->timestampTokenRequired = false;
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
+  if (data.size() == 0) {
+    return ScopedAStatus::ok();
+  }
+
+  AddEntropyRequest request(impl_.message_version());
+  request.random_data.Reinitialize(data.data(), data.size());
+
+  AddEntropyResponse response(impl_.message_version());
+  impl_.AddRngEntropy(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::generateKey(
+    const vector<KeyParameter>& keyParams,
+    const optional<AttestationKey>& attestationKey,
+    KeyCreationResult* creationResult) {
+  GenerateKeyRequest request(impl_.message_version());
+  request.key_description.Reinitialize(KmParamSet(keyParams));
+  if (attestationKey) {
+    request.attestation_signing_key_blob = KeymasterKeyBlob(
+        attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+    request.attest_key_params.Reinitialize(
+        KmParamSet(attestationKey->attestKeyParams));
+    request.issuer_subject =
+        KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                      attestationKey->issuerSubjectName.size());
+  }
+
+  GenerateKeyResponse response(impl_.message_version());
+  impl_.GenerateKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    // Note a key difference between this current aidl and previous hal, is
+    // that hal returns void where as aidl returns the error status.  If
+    // aidl returns error, then aidl will not return any change you may make
+    // to the out parameters.  This is quite different from hal where all
+    // output variable can be modified due to hal returning void.
+    //
+    // So the caller need to be aware not to expect aidl functions to clear
+    // the output variables for you in case of error.  If you left some
+    // wrong data set in the out parameters, they will stay there.
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  creationResult->keyBlob = kmBlob2vector(response.key_blob);
+  creationResult->keyCharacteristics = convertKeyCharacteristics(
+      securityLevel_, response.unenforced, response.enforced);
+  creationResult->certificateChain =
+      convertCertificateChain(response.certificate_chain);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::importKey(
+    const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+    const vector<uint8_t>& keyData,
+    const optional<AttestationKey>& attestationKey,
+    KeyCreationResult* creationResult) {
+  ImportKeyRequest request(impl_.message_version());
+  request.key_description.Reinitialize(KmParamSet(keyParams));
+  request.key_format = legacy_enum_conversion(keyFormat);
+  request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
+  if (attestationKey) {
+    request.attestation_signing_key_blob = KeymasterKeyBlob(
+        attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+    request.attest_key_params.Reinitialize(
+        KmParamSet(attestationKey->attestKeyParams));
+    request.issuer_subject =
+        KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                      attestationKey->issuerSubjectName.size());
+  }
+
+  ImportKeyResponse response(impl_.message_version());
+  impl_.ImportKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  creationResult->keyBlob = kmBlob2vector(response.key_blob);
+  creationResult->keyCharacteristics = convertKeyCharacteristics(
+      securityLevel_, response.unenforced, response.enforced);
+  creationResult->certificateChain =
+      convertCertificateChain(response.certificate_chain);
+
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::importWrappedKey(
+    const vector<uint8_t>& wrappedKeyData,         //
+    const vector<uint8_t>& wrappingKeyBlob,        //
+    const vector<uint8_t>& maskingKey,             //
+    const vector<KeyParameter>& unwrappingParams,  //
+    int64_t passwordSid, int64_t biometricSid,     //
+    KeyCreationResult* creationResult) {
+  ImportWrappedKeyRequest request(impl_.message_version());
+  request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
+  request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
+  request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
+  request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
+  request.password_sid = static_cast<uint64_t>(passwordSid);
+  request.biometric_sid = static_cast<uint64_t>(biometricSid);
+
+  ImportWrappedKeyResponse response(impl_.message_version());
+  impl_.ImportWrappedKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  creationResult->keyBlob = kmBlob2vector(response.key_blob);
+  creationResult->keyCharacteristics = convertKeyCharacteristics(
+      securityLevel_, response.unenforced, response.enforced);
+  creationResult->certificateChain =
+      convertCertificateChain(response.certificate_chain);
+
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::upgradeKey(
+    const vector<uint8_t>& keyBlobToUpgrade,
+    const vector<KeyParameter>& upgradeParams, vector<uint8_t>* keyBlob) {
+  UpgradeKeyRequest request(impl_.message_version());
+  request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+  request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+  UpgradeKeyResponse response(impl_.message_version());
+  impl_.UpgradeKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  *keyBlob = kmBlob2vector(response.upgraded_key);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
+  DeleteKeyRequest request(impl_.message_version());
+  request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+  DeleteKeyResponse response(impl_.message_version());
+  impl_.DeleteKey(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::deleteAllKeys() {
+  // There's nothing to be done to delete software key blobs.
+  DeleteAllKeysRequest request(impl_.message_version());
+  DeleteAllKeysResponse response(impl_.message_version());
+  impl_.DeleteAllKeys(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::destroyAttestationIds() {
+  return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus RemoteKeyMintDevice::begin(
+    KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+    const vector<KeyParameter>& params,
+    const optional<HardwareAuthToken>& authToken, BeginResult* result) {
+  BeginOperationRequest request(impl_.message_version());
+  request.purpose = legacy_enum_conversion(purpose);
+  request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+  request.additional_params.Reinitialize(KmParamSet(params));
+
+  vector<uint8_t> vector_token = authToken2AidlVec(authToken);
+  request.additional_params.push_back(
+      TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(vector_token.data()),
+      vector_token.size());
+
+  BeginOperationResponse response(impl_.message_version());
+  impl_.BeginOperation(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  result->params = kmParamSet2Aidl(response.output_params);
+  result->challenge = response.op_handle;
+  result->operation = ndk::SharedRefBase::make<RemoteKeyMintOperation>(
+      impl_, response.op_handle);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::deviceLocked(
+    bool passwordOnly,
+    const std::optional<secureclock::TimeStampToken>& timestampToken) {
+  DeviceLockedRequest request(impl_.message_version());
+  request.passwordOnly = passwordOnly;
+  if (timestampToken.has_value()) {
+    request.token.challenge = timestampToken->challenge;
+    request.token.mac = {timestampToken->mac.data(),
+                         timestampToken->mac.size()};
+    request.token.timestamp = timestampToken->timestamp.milliSeconds;
+  }
+  DeviceLockedResponse response = impl_.DeviceLocked(request);
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::earlyBootEnded() {
+  EarlyBootEndedResponse response = impl_.EarlyBootEnded();
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::convertStorageKeyToEphemeral(
+    const std::vector<uint8_t>& /* storageKeyBlob */,
+    std::vector<uint8_t>* /* ephemeralKeyBlob */) {
+  return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus RemoteKeyMintDevice::getKeyCharacteristics(
+    const std::vector<uint8_t>& /* storageKeyBlob */,
+    const std::vector<uint8_t>& /* appId */,
+    const std::vector<uint8_t>& /* appData */,
+    std::vector<KeyCharacteristics>* /* keyCharacteristics */) {
+  return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_keymint_device.h b/guest/hals/keymint/remote/remote_keymint_device.h
new file mode 100644
index 0000000..c3ebad1
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_device.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 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 <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+
+#include "guest/hals/keymint/remote/remote_keymaster.h"
+
+namespace aidl::android::hardware::security::keymint {
+using ::ndk::ScopedAStatus;
+using std::optional;
+using std::shared_ptr;
+using std::vector;
+
+using secureclock::TimeStampToken;
+
+class RemoteKeyMintDevice : public BnKeyMintDevice {
+ public:
+  explicit RemoteKeyMintDevice(::keymaster::RemoteKeymaster&, SecurityLevel);
+  virtual ~RemoteKeyMintDevice();
+
+  ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
+
+  ScopedAStatus addRngEntropy(const vector<uint8_t>& data) override;
+
+  ScopedAStatus generateKey(const vector<KeyParameter>& keyParams,
+                            const optional<AttestationKey>& attestationKey,
+                            KeyCreationResult* creationResult) override;
+
+  ScopedAStatus importKey(const vector<KeyParameter>& keyParams,
+                          KeyFormat keyFormat, const vector<uint8_t>& keyData,
+                          const optional<AttestationKey>& attestationKey,
+                          KeyCreationResult* creationResult) override;
+
+  ScopedAStatus importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+                                 const vector<uint8_t>& wrappingKeyBlob,
+                                 const vector<uint8_t>& maskingKey,
+                                 const vector<KeyParameter>& unwrappingParams,
+                                 int64_t passwordSid, int64_t biometricSid,
+                                 KeyCreationResult* creationResult) override;
+
+  ScopedAStatus upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+                           const vector<KeyParameter>& upgradeParams,
+                           vector<uint8_t>* keyBlob) override;
+
+  ScopedAStatus deleteKey(const vector<uint8_t>& keyBlob) override;
+  ScopedAStatus deleteAllKeys() override;
+  ScopedAStatus destroyAttestationIds() override;
+
+  ScopedAStatus begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+                      const vector<KeyParameter>& params,
+                      const optional<HardwareAuthToken>& authToken,
+                      BeginResult* result) override;
+
+  ScopedAStatus deviceLocked(
+      bool passwordOnly,
+      const optional<TimeStampToken>& timestampToken) override;
+  ScopedAStatus earlyBootEnded() override;
+
+  ScopedAStatus convertStorageKeyToEphemeral(
+      const std::vector<uint8_t>& storageKeyBlob,
+      std::vector<uint8_t>* ephemeralKeyBlob) override;
+
+  ScopedAStatus getKeyCharacteristics(
+      const std::vector<uint8_t>& storageKeyBlob,
+      const std::vector<uint8_t>& appId, const std::vector<uint8_t>& appData,
+      std::vector<KeyCharacteristics>* keyCharacteristics) override;
+
+ protected:
+  ::keymaster::RemoteKeymaster& impl_;
+  SecurityLevel securityLevel_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_keymint_operation.cpp b/guest/hals/keymint/remote/remote_keymint_operation.cpp
new file mode 100644
index 0000000..b88715a
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_operation.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-impl.remote"
+#include <log/log.h>
+
+#include "guest/hals/keymint/remote/remote_keymint_operation.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <keymaster/android_keymaster.h>
+
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::Buffer;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::TAG_ASSOCIATED_DATA;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using secureclock::TimeStampToken;
+using namespace km_utils;
+
+RemoteKeyMintOperation::RemoteKeyMintOperation(
+    ::keymaster::RemoteKeymaster& impl, keymaster_operation_handle_t opHandle)
+    : impl_(impl), opHandle_(opHandle) {}
+
+RemoteKeyMintOperation::~RemoteKeyMintOperation() {
+  if (opHandle_ != 0) {
+    abort();
+  }
+}
+
+ScopedAStatus RemoteKeyMintOperation::updateAad(
+    const vector<uint8_t>& input,
+    const optional<HardwareAuthToken>& /* authToken */,
+    const optional<TimeStampToken>& /* timestampToken */) {
+  UpdateOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+  request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(),
+                                      input.size());
+
+  UpdateOperationResponse response(impl_.message_version());
+  impl_.UpdateOperation(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintOperation::update(
+    const vector<uint8_t>& input,
+    const optional<HardwareAuthToken>& /* authToken */,
+    const optional<TimeStampToken>&
+    /* timestampToken */,
+    vector<uint8_t>* output) {
+  if (!output) return kmError2ScopedAStatus(KM_ERROR_OUTPUT_PARAMETER_NULL);
+
+  UpdateOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+  request.input.Reinitialize(input.data(), input.size());
+
+  UpdateOperationResponse response(impl_.message_version());
+  impl_.UpdateOperation(request, &response);
+
+  if (response.error != KM_ERROR_OK)
+    return kmError2ScopedAStatus(response.error);
+  if (response.input_consumed != request.input.buffer_size()) {
+    return kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+  }
+
+  *output = kmBuffer2vector(response.output);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintOperation::finish(
+    const optional<vector<uint8_t>>& input,      //
+    const optional<vector<uint8_t>>& signature,  //
+    const optional<HardwareAuthToken>& /* authToken */,
+    const optional<TimeStampToken>& /* timestampToken */,
+    const optional<vector<uint8_t>>& /* confirmationToken */,
+    vector<uint8_t>* output) {
+  if (!output) {
+    return ScopedAStatus(AStatus_fromServiceSpecificError(
+        static_cast<int32_t>(ErrorCode::OUTPUT_PARAMETER_NULL)));
+  }
+
+  FinishOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+  if (input) request.input.Reinitialize(input->data(), input->size());
+  if (signature)
+    request.signature.Reinitialize(signature->data(), signature->size());
+
+  FinishOperationResponse response(impl_.message_version());
+  impl_.FinishOperation(request, &response);
+  opHandle_ = 0;
+
+  if (response.error != KM_ERROR_OK)
+    return kmError2ScopedAStatus(response.error);
+
+  *output = kmBuffer2vector(response.output);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintOperation::abort() {
+  AbortOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+
+  AbortOperationResponse response(impl_.message_version());
+  impl_.AbortOperation(request, &response);
+  opHandle_ = 0;
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_keymint_operation.h b/guest/hals/keymint/remote/remote_keymint_operation.h
new file mode 100644
index 0000000..eb3c78b
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_operation.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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 <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <hardware/keymaster_defs.h>
+
+#include "guest/hals/keymint/remote/remote_keymaster.h"
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using std::optional;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+class RemoteKeyMintOperation : public BnKeyMintOperation {
+ public:
+  explicit RemoteKeyMintOperation(::keymaster::RemoteKeymaster& implementation,
+                                  keymaster_operation_handle_t opHandle);
+  virtual ~RemoteKeyMintOperation();
+
+  ScopedAStatus updateAad(
+      const vector<uint8_t>& input,
+      const optional<HardwareAuthToken>& authToken,
+      const optional<TimeStampToken>& timestampToken) override;
+
+  ScopedAStatus update(const vector<uint8_t>& input,
+                       const optional<HardwareAuthToken>& authToken,
+                       const optional<TimeStampToken>& timestampToken,
+                       vector<uint8_t>* output) override;
+
+  ScopedAStatus finish(const optional<vector<uint8_t>>& input,        //
+                       const optional<vector<uint8_t>>& signature,    //
+                       const optional<HardwareAuthToken>& authToken,  //
+                       const optional<TimeStampToken>& timestampToken,
+                       const optional<vector<uint8_t>>& confirmationToken,
+                       vector<uint8_t>* output) override;
+
+  ScopedAStatus abort() override;
+
+ protected:
+  ::keymaster::RemoteKeymaster& impl_;
+  keymaster_operation_handle_t opHandle_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_secure_clock.cpp b/guest/hals/keymint/remote/remote_secure_clock.cpp
new file mode 100644
index 0000000..307e0ab
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_secure_clock.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "android.hardware.security.secureclock-impl.remote"
+#include <log/log.h>
+
+#include "guest/hals/keymint/remote/remote_secure_clock.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/keymaster_configuration.h>
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::secureclock {
+
+using namespace ::keymaster;
+using namespace ::aidl::android::hardware::security::keymint::km_utils;
+
+RemoteSecureClock::RemoteSecureClock(keymaster::RemoteKeymaster& impl)
+    : impl_(impl) {}
+
+RemoteSecureClock::~RemoteSecureClock() {}
+
+ScopedAStatus RemoteSecureClock::generateTimeStamp(int64_t challenge,
+                                                   TimeStampToken* token) {
+  GenerateTimestampTokenRequest request(impl_.message_version());
+  request.challenge = challenge;
+  GenerateTimestampTokenResponse response(request.message_version);
+  impl_.GenerateTimestampToken(request, &response);
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+  token->challenge = response.token.challenge;
+  token->timestamp.milliSeconds =
+      static_cast<int64_t>(response.token.timestamp);
+  token->mac = kmBlob2vector(response.token.mac);
+  return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::security::secureclock
diff --git a/guest/hals/keymint/remote/remote_secure_clock.h b/guest/hals/keymint/remote/remote_secure_clock.h
new file mode 100644
index 0000000..a0330e2
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_secure_clock.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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 <aidl/android/hardware/security/secureclock/BnSecureClock.h>
+#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
+#include <aidl/android/hardware/security/secureclock/Timestamp.h>
+#include "guest/hals/keymint/remote/remote_keymaster.h"
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+
+namespace aidl::android::hardware::security::secureclock {
+using ::ndk::ScopedAStatus;
+using std::shared_ptr;
+using std::vector;
+
+class RemoteSecureClock : public BnSecureClock {
+ public:
+  explicit RemoteSecureClock(::keymaster::RemoteKeymaster& keymint);
+  virtual ~RemoteSecureClock();
+  ScopedAStatus generateTimeStamp(int64_t challenge,
+                                  TimeStampToken* token) override;
+
+ private:
+  ::keymaster::RemoteKeymaster& impl_;
+};
+}  // namespace aidl::android::hardware::security::secureclock
diff --git a/guest/hals/keymint/remote/remote_shared_secret.cpp b/guest/hals/keymint/remote/remote_shared_secret.cpp
new file mode 100644
index 0000000..6c50900
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_shared_secret.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "android.hardware.security.sharedsecret-impl"
+#include <log/log.h>
+
+#include "guest/hals/keymint/remote/remote_shared_secret.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <keymaster/android_keymaster.h>
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::sharedsecret {
+
+using namespace ::keymaster;
+using namespace ::aidl::android::hardware::security::keymint::km_utils;
+
+RemoteSharedSecret::RemoteSharedSecret(::keymaster::RemoteKeymaster& keymint)
+    : impl_(keymint) {}
+
+RemoteSharedSecret::~RemoteSharedSecret() {}
+
+ScopedAStatus RemoteSharedSecret::getSharedSecretParameters(
+    SharedSecretParameters* params) {
+  auto response = impl_.GetHmacSharingParameters();
+  params->seed = kmBlob2vector(response.params.seed);
+  params->nonce = {std::begin(response.params.nonce),
+                   std::end(response.params.nonce)};
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteSharedSecret::computeSharedSecret(
+    const vector<SharedSecretParameters>& params,
+    vector<uint8_t>* sharingCheck) {
+  ComputeSharedHmacRequest request(impl_.message_version());
+  request.params_array.params_array =
+      new keymaster::HmacSharingParameters[params.size()];
+  request.params_array.num_params = params.size();
+  for (size_t i = 0; i < params.size(); ++i) {
+    request.params_array.params_array[i].seed = {params[i].seed.data(),
+                                                 params[i].seed.size()};
+    if (sizeof(request.params_array.params_array[i].nonce) !=
+        params[i].nonce.size()) {
+      return kmError2ScopedAStatus(KM_ERROR_INVALID_ARGUMENT);
+    }
+    memcpy(request.params_array.params_array[i].nonce, params[i].nonce.data(),
+           params[i].nonce.size());
+  }
+  auto response = impl_.ComputeSharedHmac(request);
+  if (response.error == KM_ERROR_OK)
+    *sharingCheck = kmBlob2vector(response.sharing_check);
+  return kmError2ScopedAStatus(response.error);
+}
+
+}  // namespace aidl::android::hardware::security::sharedsecret
diff --git a/guest/hals/keymint/remote/remote_shared_secret.h b/guest/hals/keymint/remote/remote_shared_secret.h
new file mode 100644
index 0000000..9c1aae2
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_shared_secret.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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 <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
+#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
+#include "guest/hals/keymint/remote/remote_keymaster.h"
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+namespace aidl::android::hardware::security::sharedsecret {
+using ::ndk::ScopedAStatus;
+using std::shared_ptr;
+using std::vector;
+
+class RemoteSharedSecret : public BnSharedSecret {
+ public:
+  explicit RemoteSharedSecret(::keymaster::RemoteKeymaster& keymint);
+  virtual ~RemoteSharedSecret();
+  ScopedAStatus getSharedSecretParameters(
+      SharedSecretParameters* params) override;
+  ScopedAStatus computeSharedSecret(
+      const vector<SharedSecretParameters>& params,
+      vector<uint8_t>* sharingCheck) override;
+
+ private:
+  ::keymaster::RemoteKeymaster& impl_;
+};
+}  // namespace aidl::android::hardware::security::sharedsecret
diff --git a/guest/hals/keymint/remote/service.cpp b/guest/hals/keymint/remote/service.cpp
new file mode 100644
index 0000000..404df77
--- /dev/null
+++ b/guest/hals/keymint/remote/service.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-service"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/km_version.h>
+#include <keymaster/soft_keymaster_logger.h>
+#include "guest/hals/keymint/remote/remote_keymint_device.h"
+
+#include <guest/hals/keymint/remote/remote_keymaster.h>
+#include <guest/hals/keymint/remote/remote_keymint_device.h>
+#include <guest/hals/keymint/remote/remote_secure_clock.h>
+#include <guest/hals/keymint/remote/remote_shared_secret.h>
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/keymaster_channel.h"
+
+static const char device[] = "/dev/hvc3";
+
+using aidl::android::hardware::security::keymint::RemoteKeyMintDevice;
+using aidl::android::hardware::security::keymint::SecurityLevel;
+using aidl::android::hardware::security::secureclock::RemoteSecureClock;
+using aidl::android::hardware::security::sharedsecret::RemoteSharedSecret;
+
+template <typename T, class... Args>
+static std::shared_ptr<T> addService(Args&&... args) {
+  std::shared_ptr<T> ser =
+      ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
+  auto instanceName = std::string(T::descriptor) + "/default";
+  LOG(INFO) << "adding keymint service instance: " << instanceName;
+  binder_status_t status =
+      AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
+  CHECK(status == STATUS_OK);
+  return ser;
+}
+
+int main(int, char** argv) {
+  android::base::InitLogging(argv, android::base::KernelLogger);
+  // Zero threads seems like a useless pool, but below we'll join this thread to
+  // it, increasing the pool size to 1.
+  ABinderProcess_setThreadPoolMaxThreadCount(0);
+  // Add Keymint Service
+  auto fd = cuttlefish::SharedFD::Open(device, O_RDWR);
+  if (!fd->IsOpen()) {
+    LOG(FATAL) << "Could not connect to keymaster: " << fd->StrError();
+  }
+
+  if (fd->SetTerminalRaw() < 0) {
+    LOG(FATAL) << "Could not make " << device
+               << " a raw terminal: " << fd->StrError();
+  }
+
+  cuttlefish::KeymasterChannel keymasterChannel(fd, fd);
+
+  keymaster::RemoteKeymaster remote_keymaster(
+      &keymasterChannel, keymaster::MessageVersion(
+                             keymaster::KmVersion::KEYMINT_1, 0 /* km_date */));
+
+  addService<RemoteKeyMintDevice>(remote_keymaster,
+                                  SecurityLevel::TRUSTED_ENVIRONMENT);
+  addService<RemoteSecureClock>(remote_keymaster);
+  addService<RemoteSharedSecret>(remote_keymaster);
+
+  ABinderProcess_joinThreadPool();
+  return EXIT_FAILURE;  // should not reach
+}
diff --git a/guest/hals/ril/.clang-format b/guest/hals/ril/.clang-format
new file mode 120000
index 0000000..5e8e20b
--- /dev/null
+++ b/guest/hals/ril/.clang-format
@@ -0,0 +1 @@
+../../../../../../build/soong/scripts/system-clang-format
\ No newline at end of file
diff --git a/guest/hals/ril/Android.mk b/guest/hals/ril/Android.mk
deleted file mode 100644
index 808d4ec..0000000
--- a/guest/hals/ril/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-  cuttlefish_ril.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-  liblog \
-  libcutils \
-  libutils \
-  ${CUTTLEFISH_LIBRIL_NAME} \
-  libcuttlefish_fs \
-  cuttlefish_net \
-  libbase \
-  libcuttlefish_device_config \
-
-LOCAL_C_INCLUDES := \
-    device/google/cuttlefish
-
-LOCAL_CFLAGS += \
-  -Wall \
-  -Werror \
-  $(VSOC_VERSION_CFLAGS)
-
-LOCAL_MODULE:= libcuttlefish-ril
-LOCAL_MODULE_TAGS := optional
-LOCAL_VENDOR_MODULE := true
-
-# See b/67109557
-ifeq (true, $(TARGET_TRANSLATE_2ND_ARCH))
-LOCAL_MULTILIB := first
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/guest/hals/ril/cuttlefish_ril.cpp b/guest/hals/ril/cuttlefish_ril.cpp
deleted file mode 100644
index 29fca7e..0000000
--- a/guest/hals/ril/cuttlefish_ril.cpp
+++ /dev/null
@@ -1,2609 +0,0 @@
-/*
-** Copyright 2017, 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 ioogle/s 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.
-*/
-
-#include "guest/hals/ril/cuttlefish_ril.h"
-
-#include <cutils/properties.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "common/libs/device_config/device_config.h"
-#include "common/libs/net/netlink_client.h"
-#include "common/libs/net/network_interface.h"
-#include "common/libs/net/network_interface_manager.h"
-
-#define CUTTLEFISH_RIL_VERSION_STRING "Android Cuttlefish RIL 1.4"
-
-/* Modem Technology bits */
-#define MDM_GSM 0x01
-#define MDM_WCDMA 0x02
-#define MDM_CDMA 0x04
-#define MDM_EVDO 0x08
-#define MDM_LTE 0x10
-
-typedef enum {
-  SIM_ABSENT = 0,
-  SIM_NOT_READY = 1,
-  SIM_READY = 2,  // SIM_READY means the radio state is RADIO_STATE_SIM_READY
-  SIM_PIN = 3,
-  SIM_PUK = 4,
-  SIM_NETWORK_PERSONALIZATION = 5,
-  RUIM_ABSENT = 6,
-  RUIM_NOT_READY = 7,
-  RUIM_READY = 8,
-  RUIM_PIN = 9,
-  RUIM_PUK = 10,
-  RUIM_NETWORK_PERSONALIZATION = 11
-} SIM_Status;
-
-static std::unique_ptr<cvd::DeviceConfig> global_ril_config = nullptr;
-
-static const struct RIL_Env* gce_ril_env;
-
-static const struct timeval TIMEVAL_SIMPOLL = {3, 0};
-
-static time_t gce_ril_start_time;
-
-static void pollSIMState(void* param);
-
-RIL_RadioState gRadioPowerState = RADIO_STATE_OFF;
-RIL_RadioAccessFamily default_access = RAF_LTE;
-
-struct DataCall {
-  enum AllowedAuthenticationType { kNone = 0, kPap = 1, kChap = 2, kBoth = 3 };
-
-  enum ConnectionType {
-    kConnTypeIPv4,
-    kConnTypeIPv6,
-    kConnTypeIPv4v6,
-    kConnTypePPP
-  };
-
-  enum LinkState {
-    kLinkStateInactive = 0,
-    kLinkStateDown = 1,
-    kLinkStateUp = 2,
-  };
-
-  RIL_RadioTechnology technology_;
-  RIL_DataProfile profile_;
-  std::string access_point_;
-  std::string username_;
-  std::string password_;
-  AllowedAuthenticationType auth_type_;
-  ConnectionType connection_type_;
-  LinkState link_state_;
-  RIL_DataCallFailCause fail_cause_;
-  std::string other_properties_;
-};
-
-static std::string gSimPIN = "0000";
-static const std::string gSimPUK = "11223344";
-static int gSimPINAttempts = 0;
-static const int gSimPINAttemptsMax = 3;
-static SIM_Status gSimStatus = SIM_NOT_READY;
-static bool areUiccApplicationsEnabled = true;
-
-// SetUpNetworkInterface configures IP and Broadcast addresses on a RIL
-// controlled network interface.
-// This call returns true, if operation was successful.
-bool SetUpNetworkInterface(const char* ipaddr, int prefixlen,
-                           const char* bcaddr) {
-  auto factory = cvd::NetlinkClientFactory::Default();
-  std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
-  std::unique_ptr<cvd::NetworkInterfaceManager> nm(
-      cvd::NetworkInterfaceManager::New(factory));
-  std::unique_ptr<cvd::NetworkInterface> ni(nm->Open("rmnet0", "eth1"));
-
-  if (ni) {
-    ni->SetName("rmnet0");
-    ni->SetAddress(ipaddr);
-    ni->SetBroadcastAddress(bcaddr);
-    ni->SetPrefixLength(prefixlen);
-    ni->SetOperational(true);
-    bool res = nm->ApplyChanges(*ni);
-    if (!res) ALOGE("Could not configure rmnet0");
-    return res;
-  }
-  return false;
-}
-
-// TearDownNetworkInterface disables network interface.
-// This call returns true, if operation was successful.
-bool TearDownNetworkInterface() {
-  auto nm(cvd::NetworkInterfaceManager::New(nullptr));
-  auto ni(nm->Open("rmnet0", "eth1"));
-
-  if (ni) {
-    ni->SetOperational(false);
-    bool res = nm->ApplyChanges(*ni);
-    if (!res) ALOGE("Could not disable rmnet0");
-    return res;
-  }
-  return false;
-}
-
-static int gNextDataCallId = 8;
-static std::map<int, DataCall> gDataCalls;
-static bool gRilConnected = false;
-
-static int request_or_send_data_calllist(RIL_Token* t) {
-  RIL_Data_Call_Response_v11* responses =
-      new RIL_Data_Call_Response_v11[gDataCalls.size()];
-
-  int index = 0;
-
-  ALOGV("Query data call list: %zu data calls tracked.", gDataCalls.size());
-
-  for (std::map<int, DataCall>::iterator iter = gDataCalls.begin();
-       iter != gDataCalls.end(); ++iter, ++index) {
-    responses[index].status = iter->second.fail_cause_;
-    responses[index].suggestedRetryTime = -1;
-    responses[index].cid = iter->first;
-    responses[index].active = iter->second.link_state_;
-
-    switch (iter->second.connection_type_) {
-      case DataCall::kConnTypeIPv4:
-        responses[index].type = (char*)"IP";
-        break;
-      case DataCall::kConnTypeIPv6:
-        responses[index].type = (char*)"IPV6";
-        break;
-      case DataCall::kConnTypeIPv4v6:
-        responses[index].type = (char*)"IPV4V6";
-        break;
-      case DataCall::kConnTypePPP:
-        responses[index].type = (char*)"PPP";
-        break;
-      default:
-        responses[index].type = (char*)"IP";
-        break;
-    }
-
-    responses[index].ifname = (char*)"rmnet0";
-    responses[index].addresses =
-      const_cast<char*>(global_ril_config->ril_address_and_prefix());
-    responses[index].dnses = const_cast<char*>(global_ril_config->ril_dns());
-    responses[index].gateways = const_cast<char*>(global_ril_config->ril_gateway());
-    responses[index].pcscf = (char*)"";
-    responses[index].mtu = 1440;
-  }
-
-  bool new_conn_state = (gDataCalls.size() > 0);
-
-  if (gRilConnected != new_conn_state) {
-    time_t curr_time;
-    time(&curr_time);
-    double diff_in_secs = difftime(curr_time, gce_ril_start_time);
-
-    gRilConnected = new_conn_state;
-
-    if (new_conn_state) {
-      ALOGV("MOBILE_DATA_CONNECTED %.2lf seconds", diff_in_secs);
-    } else {
-      ALOGV("MOBILE_DATA_DISCONNECTED %.2lf seconds", diff_in_secs);
-    }
-
-    if (property_set("ril.net_connected", new_conn_state ? "1" : "0")) {
-      ALOGE("Couldn't set a system property ril.net_connected.");
-    }
-  }
-
-  if (t != NULL) {
-    gce_ril_env->OnRequestComplete(*t, RIL_E_SUCCESS, responses,
-                                   gDataCalls.size() * sizeof(*responses));
-  } else {
-    gce_ril_env->OnUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
-                                       responses,
-                                       gDataCalls.size() * sizeof(*responses));
-  }
-  delete[] responses;
-  return 0;
-}
-
-static void request_datacall_fail_cause(RIL_Token t) {
-  RIL_DataCallFailCause fail = PDP_FAIL_DATA_REGISTRATION_FAIL;
-
-  if (gDataCalls.size() > 0) {
-    fail = gDataCalls.rbegin()->second.fail_cause_;
-  }
-
-  ALOGV("Requesting last data call setup fail cause (%d)", fail);
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &fail, sizeof(fail));
-};
-
-static void request_data_calllist(void* /*data*/, size_t /*datalen*/,
-                                  RIL_Token t) {
-  request_or_send_data_calllist(&t);
-}
-
-static void request_setup_data_call(void* data, size_t datalen, RIL_Token t) {
-  char** details = static_cast<char**>(data);
-  const size_t fields = datalen / sizeof(details[0]);
-
-  // There are two different versions of this interface, one providing 7 strings
-  // and the other providing 8. The code below will assume the presence of 7
-  // strings in all cases, so bail out here if things appear to be wrong. We
-  // protect the 8 string case below.
-  if (fields < 7) {
-    ALOGE("%s returning: called with small datalen %zu", __FUNCTION__, datalen);
-    return;
-  }
-
-  DataCall call;
-  int tech = atoi(details[0]);
-  switch (tech) {
-    case 0:
-    case 2 + RADIO_TECH_1xRTT:
-      call.technology_ = RADIO_TECH_1xRTT;
-      break;
-
-    case 1:
-    case 2 + RADIO_TECH_EDGE:
-      call.technology_ = RADIO_TECH_EDGE;
-      break;
-
-    default:
-      call.technology_ = RIL_RadioTechnology(tech - 2);
-      break;
-  }
-
-  int profile = atoi(details[1]);
-  call.profile_ = RIL_DataProfile(profile);
-
-  if (details[2]) call.access_point_ = details[2];
-  if (details[3]) call.username_ = details[3];
-  if (details[4]) call.password_ = details[4];
-
-  int auth_type = atoi(details[5]);
-  call.auth_type_ = DataCall::AllowedAuthenticationType(auth_type);
-
-  if (!strcmp("IP", details[6])) {
-    call.connection_type_ = DataCall::kConnTypeIPv4;
-  } else if (!strcmp("IPV6", details[6])) {
-    call.connection_type_ = DataCall::kConnTypeIPv6;
-  } else if (!strcmp("IPV4V6", details[6])) {
-    call.connection_type_ = DataCall::kConnTypeIPv4v6;
-  } else if (!strcmp("PPP", details[6])) {
-    call.connection_type_ = DataCall::kConnTypePPP;
-  } else {
-    ALOGW("Unknown / unsupported connection type %s. Falling back to IPv4",
-          details[6]);
-    call.connection_type_ = DataCall::kConnTypeIPv4;
-  }
-
-  if (call.connection_type_ != DataCall::kConnTypeIPv4) {
-    ALOGE("Non-IPv4 connections are not supported by Cuttlefish RIL.");
-    gce_ril_env->OnRequestComplete(t, RIL_E_INVALID_ARGUMENTS, NULL, 0);
-    return;
-  }
-
-  call.link_state_ = DataCall::kLinkStateUp;
-  call.fail_cause_ = PDP_FAIL_NONE;
-  if (fields > 7) {
-    if (details[7]) call.other_properties_ = details[7];
-  }
-
-  if (gDataCalls.empty()) {
-    SetUpNetworkInterface(global_ril_config->ril_ipaddr(),
-                          global_ril_config->ril_prefixlen(),
-                          global_ril_config->ril_broadcast());
-  }
-
-  gDataCalls[gNextDataCallId] = call;
-  gNextDataCallId++;
-
-  ALOGV("Requesting data call setup to APN %s, technology %s, prof %s",
-        details[2], details[0], details[1]);
-
-  request_or_send_data_calllist(&t);
-
-  gRilConnected = (gDataCalls.size() > 0);
-}
-
-static void request_teardown_data_call(void* data, size_t /*datalen*/,
-                                       RIL_Token t) {
-  char** data_strs = (char**)data;
-  int call_id = atoi(data_strs[0]);
-  int reason = atoi(data_strs[1]);
-
-  ALOGV("Tearing down data call %d, reason: %d", call_id, reason);
-
-  gDataCalls.erase(call_id);
-  gRilConnected = (gDataCalls.size() > 0);
-
-  if (!gRilConnected) {
-    TearDownNetworkInterface();
-  }
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void set_radio_state(RIL_RadioState new_state, RIL_Token t) {
-  // From header:
-  // Toggle radio on and off (for "airplane" mode)
-  // If the radio is is turned off/on the radio modem subsystem
-  // is expected return to an initialized state. For instance,
-  // any voice and data calls will be terminated and all associated
-  // lists emptied.
-  gDataCalls.clear();
-
-  gSimStatus = SIM_NOT_READY;
-  ALOGV("RIL_RadioState change %d to %d", gRadioPowerState, new_state);
-  gRadioPowerState = new_state;
-
-  if (new_state == RADIO_STATE_OFF) {
-    TearDownNetworkInterface();
-  }
-
-  if (t != NULL) {
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  }
-
-  gce_ril_env->OnUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
-                                     NULL, 0);
-
-  pollSIMState(NULL);
-}
-
-// returns 1 if on, 0 if off, and -1 on error
-static void request_radio_power(void* data, size_t /*datalen*/, RIL_Token t) {
-  int on = ((int*)data)[0];
-  set_radio_state(on ? RADIO_STATE_ON : RADIO_STATE_OFF, t);
-}
-
-// TODO(ender): this should be a class member. Move where it belongs.
-struct CallState {
-  RIL_CallState state;  // e.g. RIL_CALL_HOLDING;
-  bool isInternational;
-  bool isMobileTerminated;
-  bool isVoice;
-  bool isMultiParty;
-
-  std::string number;
-  std::string name;
-  std::string dtmf;
-
-  bool canPresentNumber;
-  bool canPresentName;
-
-  CallState()
-      : state(RIL_CallState(0)),
-        isInternational(false),
-        isMobileTerminated(true),
-        isVoice(true),
-        isMultiParty(false),
-        canPresentNumber(true),
-        canPresentName(true) {}
-
-  CallState(const std::string& number)
-      : state(RIL_CALL_INCOMING),
-        isInternational(false),
-        isMobileTerminated(true),
-        isVoice(true),
-        isMultiParty(false),
-        number(number),
-        name(number),
-        canPresentNumber(true),
-        canPresentName(true) {}
-
-  bool isBackground() { return state == RIL_CALL_HOLDING; }
-
-  bool isActive() { return state == RIL_CALL_ACTIVE; }
-
-  bool isDialing() { return state == RIL_CALL_DIALING; }
-
-  bool isIncoming() { return state == RIL_CALL_INCOMING; }
-
-  bool isWaiting() { return state == RIL_CALL_WAITING; }
-
-  void addDtmfDigit(char c) {
-    dtmf.push_back(c);
-    ALOGV("Call to %s: DTMF %s", number.c_str(), dtmf.c_str());
-  }
-
-  bool makeBackground() {
-    if (state == RIL_CALL_ACTIVE) {
-      state = RIL_CALL_HOLDING;
-      return true;
-    }
-
-    return false;
-  }
-
-  bool makeActive() {
-    if (state == RIL_CALL_INCOMING || state == RIL_CALL_WAITING ||
-        state == RIL_CALL_DIALING || state == RIL_CALL_HOLDING) {
-      state = RIL_CALL_ACTIVE;
-      return true;
-    }
-
-    return false;
-  }
-};
-
-static int gLastActiveCallIndex = 1;
-static int gMicrophoneMute = 0;
-static std::map<int, CallState> gActiveCalls;
-
-static void request_get_current_calls(void* /*data*/, size_t /*datalen*/,
-                                      RIL_Token t) {
-  const int countCalls = gActiveCalls.size();
-
-  RIL_Call** pp_calls = (RIL_Call**)alloca(countCalls * sizeof(RIL_Call*));
-  RIL_Call* p_calls = (RIL_Call*)alloca(countCalls * sizeof(RIL_Call));
-
-  memset(p_calls, 0, countCalls * sizeof(RIL_Call));
-
-  /* init the pointer array */
-  for (int i = 0; i < countCalls; i++) {
-    pp_calls[i] = &(p_calls[i]);
-  }
-
-  // TODO(ender): This should be built from calls requested via RequestDial.
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end(); ++iter, ++p_calls) {
-    p_calls->state = iter->second.state;
-    p_calls->index = iter->first;
-    p_calls->toa = iter->second.isInternational ? 145 : 129;
-    p_calls->isMpty = iter->second.isMultiParty;
-    p_calls->isMT = iter->second.isMobileTerminated;
-    p_calls->als = iter->first;
-    p_calls->isVoice = iter->second.isVoice;
-    p_calls->isVoicePrivacy = 0;
-    p_calls->number = strdup(iter->second.number.c_str());
-    p_calls->numberPresentation = iter->second.canPresentNumber ? 0 : 1;
-    p_calls->name = strdup(iter->second.name.c_str());
-    p_calls->namePresentation = iter->second.canPresentName ? 0 : 1;
-    p_calls->uusInfo = NULL;
-
-    ALOGV("Call to %s (%s): voice=%d mt=%d type=%d state=%d index=%d",
-          p_calls->name, p_calls->number, p_calls->isVoice, p_calls->isMT,
-          p_calls->toa, p_calls->state, p_calls->index);
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, pp_calls,
-                                 countCalls * sizeof(RIL_Call*));
-
-  ALOGV("Get Current calls: %d calls found.\n", countCalls);
-}
-
-static void simulate_pending_calls_answered(void* /*ignore*/) {
-  ALOGV("Simulating outgoing call answered.");
-  // This also resumes held calls.
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end(); ++iter) {
-    if (iter->second.isDialing()) {
-      iter->second.makeActive();
-    }
-  }
-
-  // Only unsolicited here.
-  gce_ril_env->OnUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
-                                     NULL, 0);
-}
-
-static void request_dial(void* data, size_t /*datalen*/, RIL_Token t) {
-  RIL_Dial* p_dial = (RIL_Dial*)data;
-
-  ALOGV("Dialing %s, number presentation is %s.", p_dial->address,
-        (p_dial->clir == 0) ? "defined by operator"
-                            : (p_dial->clir == 1) ? "allowed" : "restricted");
-
-  CallState state(p_dial->address);
-  state.isMobileTerminated = false;
-  state.state = RIL_CALL_DIALING;
-
-  switch (p_dial->clir) {
-    case 0:  // default
-    case 1:  // allow
-      state.canPresentNumber = true;
-      break;
-
-    case 2:  // restrict
-      state.canPresentNumber = false;
-      break;
-  }
-
-  int call_index = gLastActiveCallIndex++;
-  gActiveCalls[call_index] = state;
-
-  static const struct timeval kAnswerTime = {5, 0};
-  gce_ril_env->RequestTimedCallback(simulate_pending_calls_answered, NULL,
-                                    &kAnswerTime);
-
-  // success or failure is ignored by the upper layer here.
-  // it will call GET_CURRENT_CALLS and determine success that way
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-void request_set_mute(void* data, size_t /*datalen*/, RIL_Token t) {
-  gMicrophoneMute = ((int*)data)[0] != 0;
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-void request_get_mute(RIL_Token t) {
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &gMicrophoneMute,
-                                 sizeof(gMicrophoneMute));
-}
-
-// TODO(ender): this should be a class member. Move where it belongs.
-struct SmsMessage {
-  enum SmsStatus { kUnread = 0, kRead = 1, kUnsent = 2, kSent = 3 };
-
-  std::string message;
-  SmsStatus status;
-};
-
-static int gNextMessageId = 1;
-static std::map<int, SmsMessage> gMessagesOnSimCard;
-
-static void request_write_sms_to_sim(void* data, size_t /*datalen*/,
-                                     RIL_Token t) {
-  RIL_SMS_WriteArgs* p_args = (RIL_SMS_WriteArgs*)data;
-
-  SmsMessage message;
-  message.status = SmsMessage::SmsStatus(p_args->status);
-  message.message = p_args->pdu;
-
-  ALOGV("Storing SMS message: '%s' with state: %s.", message.message.c_str(),
-        (message.status < SmsMessage::kUnsent)
-            ? ((message.status == SmsMessage::kRead) ? "READ" : "UNREAD")
-            : ((message.status == SmsMessage::kSent) ? "SENT" : "UNSENT"));
-
-  // TODO(ender): simulate SIM FULL?
-  int index = gNextMessageId++;
-  gMessagesOnSimCard[index] = message;
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &index, sizeof(index));
-}
-
-static void request_delete_sms_on_sim(void* data, size_t /*datalen*/,
-                                      RIL_Token t) {
-  int index = *(int*)data;
-
-  ALOGV("Delete SMS message %d", index);
-
-  if (gMessagesOnSimCard.erase(index) == 0) {
-    // No such message
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-    return;
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_hangup(void* data, size_t /*datalen*/, RIL_Token t) {
-  int* p_line = (int*)data;
-
-  ALOGV("Hanging up call %d.", *p_line);
-  std::map<int, CallState>::iterator iter = gActiveCalls.find(*p_line);
-
-  if (iter == gActiveCalls.end()) {
-    ALOGV("No such call: %d.", *p_line);
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-  } else {
-    gActiveCalls.erase(iter);
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  }
-}
-
-static void request_hangup_waiting(void* /*data*/, size_t /*datalen*/,
-                                   RIL_Token t) {
-  ALOGV("Hanging up background/held calls.");
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end();) {
-    if (iter->second.isBackground()) {
-      // C++98 -- std::map::erase doesn't return iterator.
-      std::map<int, CallState>::iterator temp = iter++;
-      gActiveCalls.erase(temp);
-    } else {
-      ++iter;
-    }
-  }
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_hangup_current(RIL_Token t) {
-  ALOGV("Hanging up foreground/active calls.");
-  // This also resumes held calls.
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end();) {
-    if (iter->second.isBackground()) {
-      iter->second.makeActive();
-      ++iter;
-    } else {
-      // C++98 -- std::map::erase doesn't return iterator.
-      std::map<int, CallState>::iterator temp = iter++;
-      gActiveCalls.erase(temp);
-    }
-  }
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_switch_current_and_waiting(RIL_Token t) {
-  ALOGV("Toggle foreground and background calls.");
-  // TODO(ender): fix all states. Max 2 calls.
-  //   BEFORE                               AFTER
-  // Call 1   Call 2                 Call 1       Call 2
-  // ACTIVE   HOLDING                HOLDING     ACTIVE
-  // ACTIVE   WAITING                HOLDING     ACTIVE
-  // HOLDING  WAITING                HOLDING     ACTIVE
-  // ACTIVE   IDLE                   HOLDING     IDLE
-  // IDLE     IDLE                   IDLE        IDLE
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end(); ++iter) {
-    // TODO(ender): call could also be waiting or dialing or...
-    if (iter->second.isBackground()) {
-      iter->second.makeActive();
-    } else {
-      iter->second.makeBackground();
-    }
-  }
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_answer_incoming(RIL_Token t) {
-  ALOGV("Answering incoming call.");
-
-  // There's two types of incoming calls:
-  // - incoming: we are receiving this call while nothing happens,
-  // - waiting: we are receiving this call while we're already talking.
-  // We only accept the incoming ones.
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end(); ++iter) {
-    if (iter->second.isIncoming()) {
-      iter->second.makeActive();
-    }
-  }
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_combine_multiparty_call(void* /*data*/, size_t /*datalen*/,
-                                            RIL_Token t) {
-  ALOGW("Conference calls are not supported.");
-  gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-}
-
-static void request_split_multiparty_call(void* /*data*/, size_t /*datalen*/,
-                                          RIL_Token t) {
-  ALOGW("Conference calls are not supported.");
-  gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-}
-
-static void request_udub_on_incoming_calls(RIL_Token t) {
-  // UDUB = user determined user busy.
-  // We don't exactly do that. We simply drop these calls.
-  ALOGV("Reporting busy signal to incoming calls.");
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end();) {
-    // If we have an incoming call, there should be no waiting call.
-    // If we have a waiting call, then previous incoming call has been answered.
-    if (iter->second.isIncoming() || iter->second.isWaiting()) {
-      // C++98 -- std::map::erase doesn't return iterator.
-      std::map<int, CallState>::iterator temp = iter++;
-      gActiveCalls.erase(temp);
-    } else {
-      ++iter;
-    }
-  }
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_send_dtmf(void* data, size_t /*datalen*/, RIL_Token t) {
-  char c = ((char*)data)[0];
-  ALOGV("Sending DTMF digit '%c'", c);
-
-  for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
-       iter != gActiveCalls.end(); ++iter) {
-    if (iter->second.isActive()) {
-      iter->second.addDtmfDigit(c);
-      break;
-    }
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_send_dtmf_stop(RIL_Token t) {
-  ALOGV("DTMF tone end.");
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-// Check SignalStrength.java file for more details on how these map to signal
-// strength bars.
-const int kGatewaySignalStrengthMin = 4;
-const int kGatewaySignalStrengthMax = 30;
-const int kCDMASignalStrengthMin = -110;
-const int kCDMASignalStrengthMax = -60;
-const int kEVDOSignalStrengthMin = -160;
-const int kEVDOSignalStrengthMax = -70;
-const int kLTESignalStrengthMin = 4;
-const int kLTESignalStrengthMax = 30;
-
-static int gGatewaySignalStrength = kGatewaySignalStrengthMax;
-static int gCDMASignalStrength = kCDMASignalStrengthMax;
-static int gEVDOSignalStrength = kEVDOSignalStrengthMax;
-static int gLTESignalStrength = kLTESignalStrengthMax;
-
-static void request_signal_strength(void* /*data*/, size_t /*datalen*/,
-                                    RIL_Token t) {
-  // TODO(ender): possible to support newer APIs here.
-  RIL_SignalStrength_v10 strength;
-
-  gGatewaySignalStrength += (rand() % 3 - 1);
-  gCDMASignalStrength += (rand() % 3 - 1);
-  gEVDOSignalStrength += (rand() % 3 - 1);
-  gLTESignalStrength += (rand() % 3 - 1);
-
-  if (gGatewaySignalStrength < kGatewaySignalStrengthMin)
-    gGatewaySignalStrength = kGatewaySignalStrengthMin;
-  if (gGatewaySignalStrength > kGatewaySignalStrengthMax)
-    gGatewaySignalStrength = kGatewaySignalStrengthMax;
-  if (gCDMASignalStrength < kCDMASignalStrengthMin)
-    gCDMASignalStrength = kCDMASignalStrengthMin;
-  if (gCDMASignalStrength > kCDMASignalStrengthMax)
-    gCDMASignalStrength = kCDMASignalStrengthMax;
-  if (gEVDOSignalStrength < kEVDOSignalStrengthMin)
-    gEVDOSignalStrength = kEVDOSignalStrengthMin;
-  if (gEVDOSignalStrength > kEVDOSignalStrengthMax)
-    gEVDOSignalStrength = kEVDOSignalStrengthMax;
-  if (gLTESignalStrength < kLTESignalStrengthMin)
-    gLTESignalStrength = kLTESignalStrengthMin;
-  if (gLTESignalStrength > kLTESignalStrengthMax)
-    gLTESignalStrength = kLTESignalStrengthMax;
-
-  strength.GW_SignalStrength.signalStrength = gGatewaySignalStrength;
-  strength.GW_SignalStrength.bitErrorRate = 0;  // 0..7%
-
-  strength.CDMA_SignalStrength.dbm = gCDMASignalStrength;
-  strength.CDMA_SignalStrength.ecio = 0;  // Ec/Io; keep high to use dbm.
-
-  strength.EVDO_SignalStrength.dbm = gEVDOSignalStrength;
-  strength.EVDO_SignalStrength.ecio = 0;  // Ec/Io; keep high to use dbm.
-
-  strength.LTE_SignalStrength.signalStrength = gLTESignalStrength;
-  strength.LTE_SignalStrength.rsrp = INT_MAX;   // Invalid = Use signalStrength.
-  strength.LTE_SignalStrength.rsrq = INT_MAX;   // Invalid = Use signalStrength.
-  strength.LTE_SignalStrength.rssnr = INT_MAX;  // Invalid = Use signalStrength.
-  strength.LTE_SignalStrength.cqi = INT_MAX;    // Invalid = Use signalStrength.
-
-  ALOGV("Reporting signal strength: GW=%d CDMA=%d EVDO=%d LTE=%d",
-        gGatewaySignalStrength, gCDMASignalStrength, gEVDOSignalStrength,
-        gLTESignalStrength);
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &strength, sizeof(strength));
-}
-
-static std::map<RIL_PreferredNetworkType, int> gModemSupportedNetworkTypes;
-
-static void init_modem_supported_network_types() {
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_WCDMA] = MDM_GSM | MDM_WCDMA;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_ONLY] = MDM_GSM;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_WCDMA] = MDM_WCDMA;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_WCDMA_AUTO] =
-      MDM_GSM | MDM_WCDMA;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_CDMA_EVDO_AUTO] =
-      MDM_CDMA | MDM_EVDO;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_CDMA_ONLY] = MDM_CDMA;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_EVDO_ONLY] = MDM_EVDO;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO] =
-      MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_CDMA_EVDO] =
-      MDM_LTE | MDM_CDMA | MDM_EVDO;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_GSM_WCDMA] =
-      MDM_LTE | MDM_GSM | MDM_WCDMA;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA] =
-      MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA;
-  gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_ONLY] = MDM_LTE;
-}
-
-static std::map<RIL_PreferredNetworkType, int> gModemTechnologies;
-
-RIL_RadioTechnology gDataTechnologiesPreferenceOrder[] = {
-    RADIO_TECH_LTE,    RADIO_TECH_EHRPD, RADIO_TECH_HSPAP,  RADIO_TECH_HSPA,
-    RADIO_TECH_HSDPA,  RADIO_TECH_HSUPA, RADIO_TECH_EVDO_B, RADIO_TECH_EVDO_A,
-    RADIO_TECH_EVDO_0, RADIO_TECH_1xRTT, RADIO_TECH_UMTS,   RADIO_TECH_EDGE,
-    RADIO_TECH_GPRS};
-
-RIL_RadioTechnology gVoiceTechnologiesPreferenceOrder[] = {
-    RADIO_TECH_LTE,    RADIO_TECH_EHRPD, RADIO_TECH_EVDO_B, RADIO_TECH_EVDO_A,
-    RADIO_TECH_EVDO_0, RADIO_TECH_1xRTT, RADIO_TECH_IS95B,  RADIO_TECH_IS95A,
-    RADIO_TECH_UMTS,   RADIO_TECH_GSM};
-
-static void init_modem_technologies() {
-  gModemTechnologies[PREF_NET_TYPE_GSM_WCDMA] =
-      (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) | (1 << RADIO_TECH_EDGE) |
-      (1 << RADIO_TECH_UMTS);
-  gModemTechnologies[PREF_NET_TYPE_GSM_ONLY] =
-      (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) | (1 << RADIO_TECH_EDGE);
-  gModemTechnologies[PREF_NET_TYPE_WCDMA] =
-      (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS);
-  gModemTechnologies[PREF_NET_TYPE_GSM_WCDMA_AUTO] =
-      (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) | (1 << RADIO_TECH_EDGE) |
-      (1 << RADIO_TECH_UMTS);
-  gModemTechnologies[PREF_NET_TYPE_CDMA_EVDO_AUTO] =
-      (1 << RADIO_TECH_IS95A) | (1 << RADIO_TECH_IS95B) |
-      (1 << RADIO_TECH_1xRTT) | (1 << RADIO_TECH_EVDO_0) |
-      (1 << RADIO_TECH_EVDO_A) | (1 << RADIO_TECH_HSDPA) |
-      (1 << RADIO_TECH_HSUPA) | (1 << RADIO_TECH_HSPA) |
-      (1 << RADIO_TECH_EVDO_B);
-  gModemTechnologies[PREF_NET_TYPE_CDMA_ONLY] = (1 << RADIO_TECH_IS95A) |
-                                                (1 << RADIO_TECH_IS95B) |
-                                                (1 << RADIO_TECH_1xRTT);
-  gModemTechnologies[PREF_NET_TYPE_EVDO_ONLY] =
-      (1 << RADIO_TECH_EVDO_0) | (1 << RADIO_TECH_EVDO_A) |
-      (1 << RADIO_TECH_EVDO_A) | (1 << RADIO_TECH_HSDPA) |
-      (1 << RADIO_TECH_HSUPA) | (1 << RADIO_TECH_HSPA) |
-      (1 << RADIO_TECH_EVDO_B);
-  gModemTechnologies[PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO] =
-      (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) | (1 << RADIO_TECH_EDGE) |
-      (1 << RADIO_TECH_UMTS) | (1 << RADIO_TECH_IS95A) |
-      (1 << RADIO_TECH_IS95B) | (1 << RADIO_TECH_1xRTT) |
-      (1 << RADIO_TECH_EVDO_0) | (1 << RADIO_TECH_EVDO_A) |
-      (1 << RADIO_TECH_HSDPA) | (1 << RADIO_TECH_HSUPA) |
-      (1 << RADIO_TECH_HSPA) | (1 << RADIO_TECH_EVDO_B);
-  gModemTechnologies[PREF_NET_TYPE_LTE_CDMA_EVDO] =
-      (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) |
-      (1 << RADIO_TECH_EHRPD) | (1 << RADIO_TECH_IS95A) |
-      (1 << RADIO_TECH_IS95B) | (1 << RADIO_TECH_1xRTT) |
-      (1 << RADIO_TECH_EVDO_0) | (1 << RADIO_TECH_EVDO_A) |
-      (1 << RADIO_TECH_HSDPA) | (1 << RADIO_TECH_HSUPA) |
-      (1 << RADIO_TECH_HSPA) | (1 << RADIO_TECH_EVDO_B);
-  gModemTechnologies[PREF_NET_TYPE_LTE_GSM_WCDMA] =
-      (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) |
-      (1 << RADIO_TECH_EHRPD) | (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) |
-      (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS);
-
-  gModemTechnologies[PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA] =
-      (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) |
-      (1 << RADIO_TECH_EHRPD) | (1 << RADIO_TECH_IS95A) |
-      (1 << RADIO_TECH_IS95B) | (1 << RADIO_TECH_1xRTT) |
-      (1 << RADIO_TECH_EVDO_0) | (1 << RADIO_TECH_EVDO_A) |
-      (1 << RADIO_TECH_HSDPA) | (1 << RADIO_TECH_HSUPA) |
-      (1 << RADIO_TECH_HSPA) | (1 << RADIO_TECH_EVDO_B) |
-      (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) | (1 << RADIO_TECH_EDGE) |
-      (1 << RADIO_TECH_UMTS);
-  gModemTechnologies[PREF_NET_TYPE_LTE_ONLY] =
-      (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) | (1 << RADIO_TECH_EHRPD);
-}
-
-static const RIL_PreferredNetworkType gModemDefaultType =
-    PREF_NET_TYPE_LTE_GSM_WCDMA;
-static RIL_PreferredNetworkType gModemCurrentType = gModemDefaultType;
-static RIL_RadioTechnology gModemVoiceTechnology = RADIO_TECH_LTE;
-
-// Report technology change.
-// Select best technology from the list of supported techs.
-// Demotes RADIO_TECH_GSM as it's voice-only.
-static RIL_RadioTechnology getBestDataTechnology(
-    RIL_PreferredNetworkType network_type) {
-  RIL_RadioTechnology technology = RADIO_TECH_GPRS;
-
-  std::map<RIL_PreferredNetworkType, int>::iterator iter =
-      gModemTechnologies.find(network_type);
-
-  ALOGV("Searching for best data technology for network type %d...",
-        network_type);
-
-  // Find which technology bits are lit. Pick the top most.
-  for (size_t tech_index = 0;
-       tech_index < sizeof(gDataTechnologiesPreferenceOrder) /
-                        sizeof(gDataTechnologiesPreferenceOrder[0]);
-       ++tech_index) {
-    if (iter->second & (1 << gDataTechnologiesPreferenceOrder[tech_index])) {
-      technology = gDataTechnologiesPreferenceOrder[tech_index];
-      break;
-    }
-  }
-
-  ALOGV("Best data technology: %d.", technology);
-  return technology;
-}
-
-static RIL_RadioTechnology getBestVoiceTechnology(
-    RIL_PreferredNetworkType network_type) {
-  RIL_RadioTechnology technology = RADIO_TECH_GSM;
-
-  std::map<RIL_PreferredNetworkType, int>::iterator iter =
-      gModemTechnologies.find(network_type);
-
-  ALOGV("Searching for best voice technology for network type %d...",
-        network_type);
-
-  // Find which technology bits are lit. Pick the top most.
-  for (size_t tech_index = 0;
-       tech_index < sizeof(gVoiceTechnologiesPreferenceOrder) /
-                        sizeof(gVoiceTechnologiesPreferenceOrder[0]);
-       ++tech_index) {
-    if (iter->second & (1 << gVoiceTechnologiesPreferenceOrder[tech_index])) {
-      technology = gVoiceTechnologiesPreferenceOrder[tech_index];
-      break;
-    }
-  }
-
-  ALOGV("Best voice technology: %d.", technology);
-  return technology;
-}
-
-static void setRadioTechnology(RIL_PreferredNetworkType network_type) {
-  RIL_RadioTechnology technology = getBestVoiceTechnology(network_type);
-
-  if (technology != gModemVoiceTechnology) {
-    gModemVoiceTechnology = technology;
-    gce_ril_env->OnUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
-                                       &gModemVoiceTechnology,
-                                       sizeof(gModemVoiceTechnology));
-  }
-}
-
-static void request_get_radio_capability(RIL_Token t) {
-  ALOGV("Requesting radio capability.");
-  RIL_RadioCapability rc;
-  rc.version = RIL_RADIO_CAPABILITY_VERSION;
-  rc.session = 1;
-  rc.phase = RC_PHASE_CONFIGURED;
-  rc.rat = RAF_HSPAP;
-  strncpy(rc.logicalModemUuid, "com.google.cvdgce1.modem", MAX_UUID_LENGTH);
-  rc.status = RC_STATUS_SUCCESS;
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &rc, sizeof(rc));
-}
-
-static void request_set_radio_capability(void* data, size_t datalen,
-                                         RIL_Token t) {
-  RIL_RadioCapability* rc = (RIL_RadioCapability*)data;
-  ALOGV(
-      "RadioCapability version %d session %d phase %d rat %d "
-      "logicalModemUuid %s status %d",
-      rc->version, rc->session, rc->phase, rc->rat, rc->logicalModemUuid,
-      rc->status);
-  // TODO(ender): do something about these numbers.
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, rc, datalen);
-}
-
-static void request_set_preferred_network_type(int /*request*/, void* data,
-                                               size_t /*datalen*/,
-                                               RIL_Token t) {
-  RIL_PreferredNetworkType desired_type = *(RIL_PreferredNetworkType*)(data);
-
-  // TODO(ender): telephony still believes this phone is GSM only.
-  ALOGV("Requesting modem technology change -> %d", desired_type);
-
-  if (gModemSupportedNetworkTypes.find(desired_type) ==
-      gModemSupportedNetworkTypes.end()) {
-    desired_type = gModemSupportedNetworkTypes.begin()->first;
-  }
-
-  if (gModemCurrentType == desired_type) {
-    ALOGV("Modem technology already set to %d.", desired_type);
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-    return;
-  }
-
-  int supported_technologies = gModemSupportedNetworkTypes[gModemDefaultType];
-  int desired_technologies = gModemSupportedNetworkTypes[desired_type];
-
-  ALOGV("Requesting modem technology change %d -> %d", gModemCurrentType,
-        desired_type);
-
-  // Check if we support this technology.
-  if ((supported_technologies & desired_technologies) != desired_technologies) {
-    ALOGV("Desired technology is not supported.");
-    gce_ril_env->OnRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
-    return;
-  }
-
-  gModemCurrentType = desired_type;
-  setRadioTechnology(desired_type);
-  ALOGV("Technology change successful.");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_get_preferred_network_type(int /*request*/, void* /*data*/,
-                                               size_t /*datalen*/,
-                                               RIL_Token t) {
-  gce_ril_env->OnRequestComplete(
-      t, RIL_E_SUCCESS,
-      const_cast<RIL_PreferredNetworkType*>(&gModemDefaultType),
-      sizeof(gModemDefaultType));
-}
-
-enum RegistrationState {
-  kUnregistered = 0,
-  kRegisteredInHomeNetwork = 1,
-  kSearchingForOperators = 2,
-  kRegistrationDenied = 3,
-  kUnknown = 4,
-  kRegisteredInRoamingMode = 5,
-
-  kUnregistered_EmergencyCallsOnly = 10,
-  kSearchingForOperators_EmergencyCallsOnly = 12,
-  kRegistrationDenied_EmergencyCallsOnly = 13,
-  kUnknown_EmergencyCallsOnly = 14
-};
-
-static const char kCdmaMobileDeviceNumber[] = "5551234567";
-static const char kCdmaSID[] = "123";
-static const char kCdmaNID[] = "65535";  // special: indicates free roaming.
-
-static void request_registration_state(int request, void* /*data*/,
-                                       size_t /*datalen*/, RIL_Token t) {
-  char** responseStr = NULL;
-  int numElements = 0;
-
-  // See RIL_REQUEST_VOICE_REGISTRATION_STATE and
-  // RIL_REQUEST_DATA_REGISTRATION_STATE.
-  numElements = (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) ? 15 : 6;
-  responseStr = (char**)malloc(numElements * sizeof(char*));
-
-  asprintf(&responseStr[0], "%d", kRegisteredInHomeNetwork);
-  responseStr[1] = NULL;  // LAC - needed for GSM / WCDMA only.
-  responseStr[2] = NULL;  // CID - needed for GSM / WCDMA only.
-
-  // This is (and always has been) a huge memory leak.
-  if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
-    ALOGV("Requesting voice registration state.");
-    asprintf(&responseStr[3], "%d", getBestVoiceTechnology(gModemCurrentType));
-    responseStr[4] = strdup("1");       // BSID
-    responseStr[5] = strdup("123");     // Latitude
-    responseStr[6] = strdup("222");     // Longitude
-    responseStr[7] = strdup("0");       // CSS Indicator
-    responseStr[8] = strdup(kCdmaSID);  // SID
-    responseStr[9] = strdup(kCdmaNID);  // NID
-    responseStr[10] = strdup("0");      // Roaming indicator
-    responseStr[11] = strdup("1");      // System is in PRL
-    responseStr[12] = strdup("0");      // Default Roaming indicator
-    responseStr[13] = strdup("0");      // Reason for denial
-    responseStr[14] = strdup("0");      // Primary Scrambling Code of Current
-  } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
-    ALOGV("Requesting data registration state.");
-    asprintf(&responseStr[3], "%d", getBestDataTechnology(gModemCurrentType));
-    responseStr[4] = strdup("");   // DataServiceDenyReason
-    responseStr[5] = strdup("1");  // Max simultaneous data calls.
-  } else {
-    ALOGV("Unexpected request type: %d", request);
-    return;
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, responseStr,
-                                 numElements * sizeof(responseStr));
-}
-
-static void request_baseband_version(RIL_Token t) {
-  const char* response_str = "CVD_R1.0.0";
-
-  ALOGV("Requested phone baseband version.");
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, strdup(response_str),
-                                 sizeof(response_str));
-}
-
-// Returns true, if modem is CDMA capable.
-static bool isCDMA() {
-  switch (gModemCurrentType) {
-    case PREF_NET_TYPE_GSM_WCDMA:
-    case PREF_NET_TYPE_GSM_ONLY:
-    case PREF_NET_TYPE_WCDMA:
-    case PREF_NET_TYPE_GSM_WCDMA_AUTO:
-    case PREF_NET_TYPE_LTE_GSM_WCDMA:
-    case PREF_NET_TYPE_LTE_ONLY:
-      return false;
-
-    case PREF_NET_TYPE_CDMA_EVDO_AUTO:
-    case PREF_NET_TYPE_CDMA_ONLY:
-    case PREF_NET_TYPE_EVDO_ONLY:
-    case PREF_NET_TYPE_LTE_CDMA_EVDO:
-    case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
-    case PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO:
-      return true;
-    default:
-      break;
-  }
-
-  ALOGE("INVALID MODEM TYPE: %d", gModemCurrentType);
-  return false;
-}
-
-// Returns true, if modem is GSM capable.
-// Note, this is not same as !isCDMA().
-static bool isGSM() {
-  switch (gModemCurrentType) {
-    case PREF_NET_TYPE_GSM_WCDMA:
-    case PREF_NET_TYPE_GSM_ONLY:
-    case PREF_NET_TYPE_WCDMA:
-    case PREF_NET_TYPE_GSM_WCDMA_AUTO:
-    case PREF_NET_TYPE_LTE_GSM_WCDMA:
-    case PREF_NET_TYPE_LTE_ONLY:
-    case PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO:
-      return true;
-
-    case PREF_NET_TYPE_CDMA_EVDO_AUTO:
-    case PREF_NET_TYPE_CDMA_ONLY:
-    case PREF_NET_TYPE_EVDO_ONLY:
-    case PREF_NET_TYPE_LTE_CDMA_EVDO:
-    case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
-      return false;
-    default:
-      break;
-  }
-
-  ALOGE("INVALID MODEM TYPE: %d", gModemCurrentType);
-  return false;
-}
-
-static const char gIdentityGsmImei[] = "12345678902468";  // Luhn cksum = 0.
-static const char gIdentityGsmImeiSv[] = "01";            // Arbitrary version.
-static const char gIdentityCdmaEsn[] = "A0123456";        // 8 digits, ^[A-F].*
-static const char gIdentityCdmaMeid[] =
-    "A0123456789012";  // 14 digits, ^[A-F].*
-
-static void request_get_imei(RIL_Token t) {
-  ALOGV("Requesting IMEI");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS,
-                                 const_cast<char*>(gIdentityGsmImei),
-                                 strlen(gIdentityGsmImei));
-}
-
-static void request_get_imei_sv(RIL_Token t) {
-  ALOGV("Requesting IMEI SV");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS,
-                                 const_cast<char*>(gIdentityGsmImeiSv),
-                                 strlen(gIdentityGsmImeiSv));
-}
-
-static void request_device_identity(int /*request*/, void* /*data*/,
-                                    size_t /*datalen*/, RIL_Token t) {
-  char* response[4] = {NULL};
-
-  ALOGV("Requesting device identity...");
-
-  if (isCDMA()) {
-    response[2] = strdup(&gIdentityCdmaEsn[0]);
-    response[3] = strdup(&gIdentityCdmaMeid[0]);
-  }
-
-  if (isGSM()) {
-    response[0] = strdup(&gIdentityGsmImei[0]);
-    response[1] = strdup(&gIdentityGsmImeiSv[0]);
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
-
-  free(response[0]);
-  free(response[1]);
-}
-
-// Let's pretend we have SIM for CDMA (by default).
-static bool gCdmaHasSim = true;
-static RIL_CdmaSubscriptionSource gCdmaSubscriptionType =
-    CDMA_SUBSCRIPTION_SOURCE_RUIM_SIM;
-
-static void request_cdma_get_subscription_source(int /*request*/,
-                                                 void* /*data*/,
-                                                 size_t /*datalen*/,
-                                                 RIL_Token t) {
-  ALOGV("Requesting CDMA Subscription source.");
-
-  if (!isCDMA()) {
-    // No such radio.
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-    return;
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &gCdmaSubscriptionType,
-                                 sizeof(gCdmaSubscriptionType));
-}
-
-static void request_cdma_set_subscription_source(int /*request*/, void* data,
-                                                 size_t /*datalen*/,
-                                                 RIL_Token t) {
-  ALOGV("Setting CDMA Subscription source.");
-
-  if (!isCDMA()) {
-    // No such radio.
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-    return;
-  }
-
-  RIL_CdmaSubscriptionSource new_source = *(RIL_CdmaSubscriptionSource*)(data);
-
-  if (new_source == CDMA_SUBSCRIPTION_SOURCE_RUIM_SIM && !gCdmaHasSim) {
-    // No such radio.
-    gce_ril_env->OnRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
-    return;
-  }
-
-  ALOGV("Changed CDMA subscription type from %d to %d", gCdmaSubscriptionType,
-        new_source);
-  gCdmaSubscriptionType = new_source;
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  gce_ril_env->OnUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
-                                     &gCdmaSubscriptionType,
-                                     sizeof(gCdmaSubscriptionType));
-}
-
-static void request_cdma_subscription(int /*request*/, void* /*data*/,
-                                      size_t /*datalen*/, RIL_Token t) {
-  ALOGV("Requesting CDMA Subscription.");
-
-  if (!isCDMA()) {
-    // No such radio.
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-    return;
-  }
-
-  char* responseStr[5] = {NULL};
-  responseStr[0] = strdup(&kCdmaMobileDeviceNumber[0]);  // MDN
-  responseStr[1] = strdup(&kCdmaSID[0]);                 // SID
-  responseStr[2] = strdup(&kCdmaNID[0]);                 // NID
-  responseStr[3] = strdup(&kCdmaMobileDeviceNumber[0]);  // MIN
-  responseStr[4] = strdup("1");                          // PRL Version
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, responseStr,
-                                 sizeof(responseStr));
-}
-
-static const int gMaxConcurrentVoiceCalls = 4;
-static const int gMaxConcurrentDataCalls = 4;
-static const int gMaxConcurrentStandbyConnections = 4;
-
-static void request_hardware_config(RIL_Token t) {
-  RIL_HardwareConfig hw_cfg[2];
-
-  ALOGV("Requesting hardware configuration.");
-
-  strncpy(hw_cfg[0].uuid, "com.google.cvdgce1.modem", sizeof(hw_cfg[0].uuid));
-  strncpy(hw_cfg[1].uuid, "com.google.cvdgce1.sim", sizeof(hw_cfg[1].uuid));
-
-  int technologies = 0;  // = unknown.
-  std::map<RIL_PreferredNetworkType, int>::iterator iter =
-      gModemTechnologies.find(gModemDefaultType);
-  if (iter != gModemTechnologies.end()) {
-    technologies = iter->second;
-  }
-
-  hw_cfg[0].type = RIL_HARDWARE_CONFIG_MODEM;
-  hw_cfg[0].state = RIL_HARDWARE_CONFIG_STATE_ENABLED;
-  hw_cfg[0].cfg.modem.rilModel = 0;
-  hw_cfg[0].cfg.modem.rat = technologies;
-  hw_cfg[0].cfg.modem.maxVoice = gMaxConcurrentVoiceCalls;
-  hw_cfg[0].cfg.modem.maxData = gMaxConcurrentDataCalls;
-  hw_cfg[0].cfg.modem.maxStandby = gMaxConcurrentStandbyConnections;
-
-  hw_cfg[1].type = RIL_HARDWARE_CONFIG_SIM;
-  hw_cfg[1].state = RIL_HARDWARE_CONFIG_STATE_ENABLED;
-  memcpy(hw_cfg[1].cfg.sim.modemUuid, hw_cfg[0].uuid,
-         sizeof(hw_cfg[1].cfg.sim.modemUuid));
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &hw_cfg, sizeof(hw_cfg));
-}
-
-// 0 = Home network only, 1 = preferred networks only, 2 = all networks.
-static int gCdmaRoamingPreference = 2;
-
-static void request_cdma_get_roaming_preference(int /*request*/, void* /*data*/,
-                                                size_t /*datalen*/,
-                                                RIL_Token t) {
-  if (!isCDMA()) {
-    // No such radio.
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-    return;
-  }
-
-  ALOGV("Requesting CDMA Roaming preference");
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &gCdmaRoamingPreference,
-                                 sizeof(gCdmaRoamingPreference));
-}
-
-static void request_cdma_set_roaming_preference(int /*request*/, void* data,
-                                                size_t /*datalen*/,
-                                                RIL_Token t) {
-  if (!isCDMA()) {
-    // No such radio.
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-    return;
-  }
-
-  int pref = *(int*)data;
-  ALOGV("Changing CDMA roaming preference: %d -> %d", gCdmaRoamingPreference,
-        pref);
-
-  if ((pref < 0) || (pref > 2)) {
-    ALOGV("Unsupported roaming preference: %d", pref);
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-    return;
-  }
-
-  gCdmaRoamingPreference = pref;
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_send_ussd(void* /*data*/, size_t /*datalen*/, RIL_Token t) {
-  ALOGV("Sending USSD code is currently not supported");
-  // TODO(ender): support this feature
-  gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
-}
-
-static void request_cancel_ussd(RIL_Token t) {
-  ALOGV("Cancelling USSD code is currently not supported");
-  // TODO(ender): support this feature
-  gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
-}
-
-static void request_exit_emergency_mode(void* /*data*/, size_t /*datalen*/,
-                                        RIL_Token t) {
-  ALOGV("Exiting emergency callback mode.");
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static RIL_RadioState gce_ril_current_state() {
-  ALOGV("Reporting radio state %d", gRadioPowerState);
-  return gRadioPowerState;
-}
-
-static int gce_ril_on_supports(int requestCode) {
-  ALOGE("%s: Request code %d not implemented", __FUNCTION__, requestCode);
-  return 1;
-}
-
-static void gce_ril_on_cancel(RIL_Token /*t*/) {
-  ALOGE("Cancel operation not implemented");
-}
-
-static const char* gce_ril_get_version(void) {
-  ALOGV("Reporting Cuttlefish version " CUTTLEFISH_RIL_VERSION_STRING);
-  return CUTTLEFISH_RIL_VERSION_STRING;
-}
-
-static int s_cell_info_rate_ms = INT_MAX;
-static int s_mcc = 0;
-static int s_mnc = 0;
-static int s_lac = 0;
-static int s_cid = 0;
-
-std::vector<RIL_NeighboringCell> gGSMNeighboringCells;
-
-static void request_get_neighboring_cell_ids(void* /*data*/, size_t /*datalen*/,
-                                             RIL_Token t) {
-  ALOGV("Requesting GSM neighboring cell ids");
-
-  if (!isGSM() || gGSMNeighboringCells.empty()) {
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-    return;
-  }
-
-  RIL_NeighboringCell** cells =
-      new RIL_NeighboringCell*[gGSMNeighboringCells.size()];
-
-  for (size_t index = 0; index < gGSMNeighboringCells.size(); ++index) {
-    cells[index] = &gGSMNeighboringCells[index];
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, cells,
-                                 sizeof(RIL_NeighboringCell*));
-  delete[] cells;
-}
-
-static void request_get_cell_info_list(void* /*data*/, size_t /*datalen*/,
-                                       RIL_Token t) {
-  struct timespec now;
-  uint64_t curTime;
-
-  ALOGV("Requesting Cell Info List");
-
-  clock_gettime(CLOCK_MONOTONIC, &now);
-  curTime = now.tv_sec * 1000000000LL + now.tv_nsec;
-
-  RIL_CellInfo_v12 ci;
-
-  if (isGSM()) {
-    ci.cellInfoType = RIL_CELL_INFO_TYPE_GSM;
-    ci.registered = 1;
-    ci.timeStampType = RIL_TIMESTAMP_TYPE_ANTENNA;  // Our own timestamp.
-    ci.timeStamp = curTime - 1000;                  // Fake time in the past.
-    ci.CellInfo.gsm.cellIdentityGsm.mcc = s_mcc;
-    ci.CellInfo.gsm.cellIdentityGsm.mnc = s_mnc;
-    ci.CellInfo.gsm.cellIdentityGsm.lac = s_lac;
-    ci.CellInfo.gsm.cellIdentityGsm.cid = s_cid;
-    ci.CellInfo.gsm.signalStrengthGsm.signalStrength = 10;
-    ci.CellInfo.gsm.signalStrengthGsm.bitErrorRate = 0;
-
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &ci, sizeof(ci));
-  } else if (isCDMA()) {
-    // TODO(ender): CDMA cell support. And LTE.
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-  } else {
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-  }
-}
-
-struct NetworkOperator {
-  std::string long_name;
-  std::string short_name;
-  bool is_accessible;
-
-  NetworkOperator() {}
-
-  NetworkOperator(const std::string& long_name, const std::string& short_name,
-                  bool is_accessible)
-      : long_name(long_name),
-        short_name(short_name),
-        is_accessible(is_accessible) {}
-};
-
-static std::map<std::string, NetworkOperator> gNetworkOperators;
-static std::string gCurrentNetworkOperator = "";
-
-enum OperatorSelectionMethod {
-  kOperatorAutomatic = 0,
-  kOperatorManual = 1,
-  kOperatorDeregistered = 2,
-  kOperatorManualThenAutomatic = 4
-};
-
-static void init_virtual_network() {
-  gGSMNeighboringCells.resize(1);
-  gGSMNeighboringCells[0].cid = (char*)"0000";
-  gGSMNeighboringCells[0].rssi = 75;
-  gNetworkOperators["311740"] =
-      NetworkOperator("Android Virtual Operator", "Android", true);
-  gNetworkOperators["310300"] =
-      NetworkOperator("Alternative Operator", "Alternative", true);
-  gNetworkOperators["310400"] =
-      NetworkOperator("Hermetic Network Operator", "Hermetic", false);
-}
-
-static OperatorSelectionMethod gOperatorSelectionMethod = kOperatorDeregistered;
-
-static void request_query_network_selection_mode(void* /*data*/,
-                                                 size_t /*datalen*/,
-                                                 RIL_Token t) {
-  ALOGV("Query operator selection mode (%d)", gOperatorSelectionMethod);
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &gOperatorSelectionMethod,
-                                 sizeof(gOperatorSelectionMethod));
-}
-
-static void request_operator(void* /*data*/, size_t /*datalen*/, RIL_Token t) {
-  std::map<std::string, NetworkOperator>::iterator iter =
-      gNetworkOperators.find(gCurrentNetworkOperator);
-
-  ALOGV("Requesting current operator info");
-
-  if (iter == gNetworkOperators.end()) {
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-    return;
-  }
-
-  const char* response[] = {iter->second.long_name.c_str(),
-                            iter->second.short_name.c_str(),
-                            iter->first.c_str()};
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
-}
-
-static void request_query_available_networks(void* /*data*/, size_t /*datalen*/,
-                                             RIL_Token t) {
-  const char** available_networks =
-      new const char*[gNetworkOperators.size() * 4];
-
-  ALOGV("Querying available networks.");
-
-  // TODO(ender): this should only respond once operator is selected and
-  // registered.
-  int index = 0;
-  for (std::map<std::string, NetworkOperator>::iterator iter =
-           gNetworkOperators.begin();
-       iter != gNetworkOperators.end(); ++iter) {
-    // TODO(ender): wrap in a neat structure maybe?
-    available_networks[index++] = iter->second.long_name.c_str();
-    available_networks[index++] = iter->second.short_name.c_str();
-    available_networks[index++] = iter->first.c_str();
-    if (!iter->second.is_accessible) {
-      available_networks[index++] = "forbidden";
-    } else if (iter->first == gCurrentNetworkOperator) {
-      available_networks[index++] = "current";
-    } else {
-      available_networks[index++] = "available";
-    }
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &available_networks,
-                                 4 * gNetworkOperators.size());
-  delete[] available_networks;
-}
-
-static void request_set_automatic_network_selection(RIL_Token t) {
-  ALOGV("Requesting automatic operator selection");
-  gCurrentNetworkOperator = gNetworkOperators.begin()->first;
-  gOperatorSelectionMethod = kOperatorAutomatic;
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_set_manual_network_selection(void* data, size_t /*datalen*/,
-                                                 RIL_Token t) {
-  char* mccmnc = (char*)data;
-
-  ALOGV("Requesting manual operator selection: %s", mccmnc);
-
-  std::map<std::string, NetworkOperator>::iterator iter =
-      gNetworkOperators.find(mccmnc);
-
-  if (iter == gNetworkOperators.end() || iter->second.is_accessible) {
-    gce_ril_env->OnRequestComplete(t, RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0);
-    return;
-  }
-
-  gCurrentNetworkOperator = mccmnc;
-  gOperatorSelectionMethod = kOperatorManual;
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static const char kDefaultSMSC[] = "00";
-static int gNextSmsMessageId = 1;
-
-static void request_cdma_send_SMS(void* /*data*/, RIL_Token t) {
-  RIL_SMS_Response response = {0, 0, 0};
-  // RIL_CDMA_SMS_Message* rcsm = (RIL_CDMA_SMS_Message*) data;
-
-  ALOGW("CDMA SMS Send is currently not implemented.");
-
-  // Cdma Send SMS implementation will go here:
-  // But it is not implemented yet.
-  memset(&response, 0, sizeof(response));
-  response.messageRef = -1;  // This must be BearerData MessageId.
-  gce_ril_env->OnRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response,
-                                 sizeof(response));
-}
-
-static void request_send_SMS(void* data, RIL_Token t) {
-  RIL_SMS_Response response = {0, 0, 0};
-
-  ALOGV("Send GSM SMS Message");
-
-  // SMSC is an address of SMS center or NULL for default.
-  const char* smsc = ((const char**)data)[0];
-  if (smsc == NULL) smsc = &kDefaultSMSC[0];
-
-  response.messageRef = gNextSmsMessageId++;
-  response.ackPDU = NULL;
-  response.errorCode = 0;
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
-
-  // response.messageRef = -1;
-  // gce_ril_env->OnRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response,
-  //                                sizeof(response));
-}
-
-static void request_set_cell_info_list_rate(void* data, size_t /*datalen*/,
-                                            RIL_Token t) {
-  // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
-  // will be sent.
-  ALOGV("Setting cell info list rate.");
-  s_cell_info_rate_ms = ((int*)data)[0];
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-static void request_ims_send_SMS(void* data, size_t /*datalen*/, RIL_Token t) {
-  RIL_IMS_SMS_Message* args = (RIL_IMS_SMS_Message*)data;
-  RIL_SMS_Response response{};
-
-  ALOGV("Send IMS SMS Message");
-
-  switch (args->tech) {
-    case RADIO_TECH_3GPP:
-      return request_send_SMS(args->message.gsmMessage, t);
-
-    case RADIO_TECH_3GPP2:
-      return request_cdma_send_SMS(args->message.gsmMessage, t);
-
-    default:
-      ALOGE("Invalid SMS format value: %d", args->tech);
-      response.messageRef = -2;
-      gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, &response,
-                                     sizeof(response));
-  }
-}
-
-static void request_SMS_acknowledge(void* data, size_t /*datalen*/,
-                                    RIL_Token t) {
-  int* ack = (int*)data;
-
-  // TODO(ender): we should retain "incoming" sms for later reception.
-  ALOGV("SMS receipt %ssuccessful (reason %d).", ack[0] ? "" : "un", ack[1]);
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-struct SimFileCommand {
-  uint8_t command;
-  uint16_t efid;
-  uint8_t param1;
-  uint8_t param2;
-  uint8_t param3;
-
-  bool operator<(const SimFileCommand& other) const {
-    uint64_t sum1, sum2;
-    sum1 = (command * 1ull << 40) | (efid * 1ull << 24) | (param1 << 16) |
-           (param2 << 8) | (param3);
-    sum2 = (other.command * 1ull << 40) | (other.efid * 1ull << 24) |
-           (other.param1 << 16) | (other.param2 << 8) | (other.param3);
-    return sum1 < sum2;
-  }
-
-  SimFileCommand(uint8_t cmd, uint16_t efid, uint8_t p1, uint8_t p2, uint8_t p3)
-      : command(cmd), efid(efid), param1(p1), param2(p2), param3(p3) {}
-};
-
-struct SimFileResponse {
-  uint8_t sw1;
-  uint8_t sw2;
-  const char* data;
-
-  SimFileResponse() : sw1(0), sw2(0), data(NULL) {}
-
-  SimFileResponse(uint8_t sw1, uint8_t sw2, const char* data)
-      : sw1(sw1), sw2(sw2), data(data) {}
-};
-
-// TODO(ender): Double check & rewrite these.
-std::map<SimFileCommand, SimFileResponse> gSimFileSystem;
-
-static void init_sim_file_system() {
-  gSimFileSystem[SimFileCommand(192, 28436, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000146f1404001aa0aa01020000");
-  gSimFileSystem[SimFileCommand(176, 28436, 0, 0, 20)] =
-      SimFileResponse(144, 0, "416e64726f6964ffffffffffffffffffffffffff");
-  gSimFileSystem[SimFileCommand(192, 28433, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000016f11040011a0aa01020000");
-  gSimFileSystem[SimFileCommand(176, 28433, 0, 0, 1)] =
-      SimFileResponse(144, 0, "55");
-  gSimFileSystem[SimFileCommand(192, 12258, 0, 0, 15)] =
-      SimFileResponse(144, 0, "0000000a2fe204000fa0aa01020000");
-  gSimFileSystem[SimFileCommand(176, 12258, 0, 0, 10)] =
-      SimFileResponse(144, 0, "98101430121181157002");
-  gSimFileSystem[SimFileCommand(192, 28435, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000016f13040011a0aa01020000");
-  gSimFileSystem[SimFileCommand(176, 28435, 0, 0, 1)] =
-      SimFileResponse(144, 0, "55");
-  gSimFileSystem[SimFileCommand(192, 28472, 0, 0, 15)] =
-      SimFileResponse(144, 0, "0000000f6f3804001aa0aa01020000");
-  gSimFileSystem[SimFileCommand(176, 28472, 0, 0, 15)] =
-      SimFileResponse(144, 0, "ff30ffff3c003c03000c0000f03f00");
-  gSimFileSystem[SimFileCommand(192, 28617, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000086fc9040011a0aa01020104");
-  gSimFileSystem[SimFileCommand(178, 28617, 1, 4, 4)] =
-      SimFileResponse(144, 0, "01000000");
-  gSimFileSystem[SimFileCommand(192, 28618, 0, 0, 15)] =
-      SimFileResponse(144, 0, "0000000a6fca040011a0aa01020105");
-  gSimFileSystem[SimFileCommand(178, 28618, 1, 4, 5)] =
-      SimFileResponse(144, 0, "0000000000");
-  gSimFileSystem[SimFileCommand(192, 28589, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000046fad04000aa0aa01020000");
-  gSimFileSystem[SimFileCommand(176, 28589, 0, 0, 4)] =
-      SimFileResponse(144, 0, "00000003");
-  gSimFileSystem[SimFileCommand(192, 28438, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000026f1604001aa0aa01020000");
-  gSimFileSystem[SimFileCommand(176, 28438, 0, 0, 2)] =
-      SimFileResponse(144, 0, "0233");
-  gSimFileSystem[SimFileCommand(192, 28486, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28621, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28613, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000f06fc504000aa0aa01020118");
-  gSimFileSystem[SimFileCommand(178, 28613, 1, 4, 24)] = SimFileResponse(
-      144, 0, "43058441aa890affffffffffffffffffffffffffffffffff");
-  gSimFileSystem[SimFileCommand(192, 28480, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000806f40040011a0aa01020120");
-  // Primary phone number encapsulated
-  // [51][55][21][43][65][f7] = 1 555 1234 567$
-  gSimFileSystem[SimFileCommand(178, 28480, 1, 4, 32)] = SimFileResponse(
-      144, 0,
-      "ffffffffffffffffffffffffffffffffffff07915155214365f7ffffffffffff");
-  gSimFileSystem[SimFileCommand(192, 28615, 0, 0, 15)] =
-      SimFileResponse(144, 0, "000000406fc7040011a0aa01020120");
-  // Voice mail number encapsulated
-  // [56][6f][69][63][65][6d][61][69][6c] = 'Voicemail'
-  // [51][55][67][45][23][f1] = 1 555 7654 321$
-  gSimFileSystem[SimFileCommand(178, 28615, 1, 4, 32)] = SimFileResponse(
-      144, 0,
-      "566f6963656d61696cffffffffffffffffff07915155674523f1ffffffffffff");
-  gSimFileSystem[SimFileCommand(192, 12037, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28437, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28478, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28450, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28456, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28474, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28481, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28484, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28493, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(192, 28619, 0, 0, 15)] =
-      SimFileResponse(148, 4, NULL);
-  gSimFileSystem[SimFileCommand(176, 28506, 0, 0, 4)] =
-      SimFileResponse(144, 0, "00000013");
-}
-
-static void request_SIM_IO(void* data, size_t /*datalen*/, RIL_Token t) {
-  const RIL_SIM_IO_v6& args = *(RIL_SIM_IO_v6*)data;
-  RIL_SIM_IO_Response sr = {0, 0, 0};
-
-  ALOGV(
-      "Requesting SIM File IO: %d EFID %x, Params: %d, %d, %d, path: %s, "
-      "data %s PIN: %s AID: %s",
-      args.command, args.fileid, args.p1, args.p2, args.p3, args.path,
-      args.data, args.pin2, args.aidPtr);
-
-  SimFileCommand cmd(args.command, args.fileid, args.p1, args.p2, args.p3);
-
-  std::map<SimFileCommand, SimFileResponse>::iterator resp =
-      gSimFileSystem.find(cmd);
-
-  if (resp != gSimFileSystem.end()) {
-    sr.sw1 = resp->second.sw1;
-    sr.sw2 = resp->second.sw2;
-    if (resp->second.data) sr.simResponse = strdup(resp->second.data);
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
-    return;
-  }
-
-  ALOGW("Unsupported SIM File IO command.");
-  gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-}
-
-static void request_enter_sim_pin(void* data, size_t /*datalen*/, RIL_Token t) {
-  const char** pin_aid = (const char**)data;
-
-  ALOGV("Entering PIN: %s / %s", pin_aid[0], pin_aid[1]);
-
-  ++gSimPINAttempts;
-  int remaining_attempts = gSimPINAttemptsMax - gSimPINAttempts;
-
-  bool is_valid = false;
-
-  if (gSimStatus == SIM_PIN) {
-    is_valid = (gSimPIN == pin_aid[0]);
-  } else if (gSimStatus == SIM_PUK) {
-    is_valid = (gSimPUK == pin_aid[0]);
-  } else {
-    ALOGV("Unexpected SIM status for unlock: %d", gSimStatus);
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-    return;
-  }
-
-  if (!is_valid) {
-    if (gSimPINAttempts == gSimPINAttemptsMax) {
-      if (gSimStatus == SIM_PIN) {
-        gSimStatus = SIM_PUK;
-        gSimPINAttempts = 0;
-      } else {
-        ALOGV("PIN and PUK verification failed; locking SIM card.");
-        gSimStatus = SIM_NOT_READY;
-        gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-        return;
-      }
-    }
-
-    gce_ril_env->OnRequestComplete(t, RIL_E_PASSWORD_INCORRECT,
-                                   &remaining_attempts,
-                                   sizeof(remaining_attempts));
-  } else {
-    if (gSimStatus == SIM_PUK) {
-      ALOGV("Resetting SIM PIN to %s", pin_aid[1]);
-      gSimPIN = pin_aid[1];
-    }
-
-    gSimPINAttempts = 0;
-    gSimStatus = SIM_READY;
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &remaining_attempts,
-                                   sizeof(remaining_attempts));
-  }
-
-  pollSIMState(NULL);
-}
-
-/**
- * No longer POLL.
- */
-static void pollSIMState(void* /*param*/) {
-  // TODO(ender): check radio state?
-
-  ALOGV("Polling SIM Status.");
-
-  switch (gSimStatus) {
-    case SIM_ABSENT:
-    case SIM_PIN:
-    case SIM_PUK:
-    case SIM_NETWORK_PERSONALIZATION:
-    default:
-      ALOGV("SIM Absent or Locked");
-      break;
-
-    case SIM_NOT_READY:
-      // Transition directly to READY. Set default network operator.
-      if (gRadioPowerState == RADIO_STATE_ON) {
-        gSimStatus = SIM_READY;
-        gCurrentNetworkOperator = "311740";
-      }
-
-      gce_ril_env->RequestTimedCallback(pollSIMState, NULL, &TIMEVAL_SIMPOLL);
-      break;
-
-    case SIM_READY:
-      ALOGV("SIM Ready. Notifying network state changed.");
-      break;
-  }
-
-  if (gRadioPowerState != RADIO_STATE_OFF) {
-    gce_ril_env->OnUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
-                                       NULL, 0);
-    gce_ril_env->OnUnsolicitedResponse(
-        RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0);
-  }
-}
-
-std::map<SIM_Status, RIL_AppStatus> gRilAppStatus;
-
-static void init_sim_status() {
-  gRilAppStatus[SIM_ABSENT] = (RIL_AppStatus){RIL_APPTYPE_UNKNOWN,
-                                              RIL_APPSTATE_UNKNOWN,
-                                              RIL_PERSOSUBSTATE_UNKNOWN,
-                                              NULL,
-                                              NULL,
-                                              0,
-                                              RIL_PINSTATE_UNKNOWN,
-                                              RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[SIM_NOT_READY] =
-      (RIL_AppStatus){RIL_APPTYPE_SIM,
-                      RIL_APPSTATE_DETECTED,
-                      RIL_PERSOSUBSTATE_UNKNOWN,
-                      NULL,
-                      NULL,
-                      0,
-                      RIL_PINSTATE_ENABLED_NOT_VERIFIED,
-                      RIL_PINSTATE_ENABLED_NOT_VERIFIED};
-  gRilAppStatus[SIM_READY] = (RIL_AppStatus){
-      RIL_APPTYPE_SIM,
-      RIL_APPSTATE_READY,
-      RIL_PERSOSUBSTATE_READY,
-      NULL,
-      NULL,
-      0,
-      RIL_PINSTATE_ENABLED_VERIFIED,
-      RIL_PINSTATE_ENABLED_VERIFIED,
-  };
-  gRilAppStatus[SIM_PIN] = (RIL_AppStatus){RIL_APPTYPE_SIM,
-                                           RIL_APPSTATE_PIN,
-                                           RIL_PERSOSUBSTATE_UNKNOWN,
-                                           NULL,
-                                           NULL,
-                                           0,
-                                           RIL_PINSTATE_ENABLED_NOT_VERIFIED,
-                                           RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[SIM_PUK] = (RIL_AppStatus){RIL_APPTYPE_SIM,
-                                           RIL_APPSTATE_PUK,
-                                           RIL_PERSOSUBSTATE_UNKNOWN,
-                                           NULL,
-                                           NULL,
-                                           0,
-                                           RIL_PINSTATE_ENABLED_BLOCKED,
-                                           RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[SIM_NETWORK_PERSONALIZATION] =
-      (RIL_AppStatus){RIL_APPTYPE_SIM,
-                      RIL_APPSTATE_SUBSCRIPTION_PERSO,
-                      RIL_PERSOSUBSTATE_SIM_NETWORK,
-                      NULL,
-                      NULL,
-                      0,
-                      RIL_PINSTATE_ENABLED_NOT_VERIFIED,
-                      RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[RUIM_ABSENT] = (RIL_AppStatus){RIL_APPTYPE_UNKNOWN,
-                                               RIL_APPSTATE_UNKNOWN,
-                                               RIL_PERSOSUBSTATE_UNKNOWN,
-                                               NULL,
-                                               NULL,
-                                               0,
-                                               RIL_PINSTATE_UNKNOWN,
-                                               RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[RUIM_NOT_READY] = (RIL_AppStatus){RIL_APPTYPE_RUIM,
-                                                  RIL_APPSTATE_DETECTED,
-                                                  RIL_PERSOSUBSTATE_UNKNOWN,
-                                                  NULL,
-                                                  NULL,
-                                                  0,
-                                                  RIL_PINSTATE_UNKNOWN,
-                                                  RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[RUIM_READY] = (RIL_AppStatus){RIL_APPTYPE_RUIM,
-                                              RIL_APPSTATE_READY,
-                                              RIL_PERSOSUBSTATE_READY,
-                                              NULL,
-                                              NULL,
-                                              0,
-                                              RIL_PINSTATE_UNKNOWN,
-                                              RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[RUIM_PIN] = (RIL_AppStatus){RIL_APPTYPE_RUIM,
-                                            RIL_APPSTATE_PIN,
-                                            RIL_PERSOSUBSTATE_UNKNOWN,
-                                            NULL,
-                                            NULL,
-                                            0,
-                                            RIL_PINSTATE_ENABLED_NOT_VERIFIED,
-                                            RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[RUIM_PUK] = (RIL_AppStatus){RIL_APPTYPE_RUIM,
-                                            RIL_APPSTATE_PUK,
-                                            RIL_PERSOSUBSTATE_UNKNOWN,
-                                            NULL,
-                                            NULL,
-                                            0,
-                                            RIL_PINSTATE_ENABLED_BLOCKED,
-                                            RIL_PINSTATE_UNKNOWN};
-  gRilAppStatus[RUIM_NETWORK_PERSONALIZATION] =
-      (RIL_AppStatus){RIL_APPTYPE_RUIM,
-                      RIL_APPSTATE_SUBSCRIPTION_PERSO,
-                      RIL_PERSOSUBSTATE_SIM_NETWORK,
-                      NULL,
-                      NULL,
-                      0,
-                      RIL_PINSTATE_ENABLED_NOT_VERIFIED,
-                      RIL_PINSTATE_UNKNOWN};
-}
-
-/**
- * Get the current card status.
- */
-static void getCardStatus(RIL_Token t) {
-  ALOGV("Querying SIM status.");
-  RIL_CardStatus_v6 card_status;
-
-  if (gSimStatus == SIM_ABSENT) {
-    card_status.card_state = RIL_CARDSTATE_ABSENT;
-    card_status.num_applications = 0;
-  } else {
-    card_status.card_state = RIL_CARDSTATE_PRESENT;
-    card_status.num_applications = 1;
-  }
-
-  card_status.universal_pin_state = RIL_PINSTATE_UNKNOWN;
-  card_status.gsm_umts_subscription_app_index = -1;
-  card_status.cdma_subscription_app_index = -1;
-  card_status.ims_subscription_app_index = -1;
-
-  // Initialize application status
-  for (int i = 0; i < RIL_CARD_MAX_APPS; i++) {
-    card_status.applications[i] = gRilAppStatus[SIM_ABSENT];
-  }
-
-  if (card_status.num_applications > 0) {
-    card_status.gsm_umts_subscription_app_index = 0;
-
-    card_status.applications[0] = gRilAppStatus[gSimStatus];
-    card_status.universal_pin_state = card_status.applications[0].pin1;
-    // To enable basic CDMA (currently neither supported nor functional):
-    //    card_status.num_applications = 2;
-    //    card_status.cdma_subscription_app_index = 1;
-    //    card_status.applications[1] =
-    //        gRilAppStatus[SIM_Status(gSimStatus + RUIM_ABSENT)];
-  }
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &card_status,
-                                 sizeof(card_status));
-}
-
-struct SimSession {
-  std::string aid;
-};
-
-static int gNextSimSessionId = 1;
-static std::map<int, SimSession> gSimSessions;
-
-static void request_sim_open_channel(void* data, size_t /*datalen*/,
-                                     RIL_Token t) {
-  char* aid = (char*)data;
-  SimSession session;
-
-  ALOGV("Requesting new SIM session");
-
-  if (aid != NULL) {
-    session.aid = aid;
-  }
-
-  int response = gNextSimSessionId++;
-  gSimSessions[response] = session;
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
-}
-
-static void request_sim_close_channel(void* data, size_t /*datalen*/,
-                                      RIL_Token t) {
-  int session = *(int*)(data);
-
-  ALOGV("Closing SIM session %d", session);
-
-  if (gSimSessions.erase(session) == 0) {
-    // No such session.
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-  } else {
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  }
-}
-
-static void request_sim_apdu(void* data, size_t /*datalen*/, RIL_Token t) {
-  RIL_SIM_APDU* apdu = (RIL_SIM_APDU*)data;
-
-  ALOGV("Requesting APDU: Session %d CLA %d INST %d Params: %d %d %d, data %s",
-        apdu->sessionid, apdu->cla, apdu->instruction, apdu->p1, apdu->p2,
-        apdu->p3, apdu->data);
-
-  if (gSimSessions.find(apdu->sessionid) != gSimSessions.end()) {
-    RIL_SIM_IO_Response sr{};
-
-    // Fallback / default behavior.
-    sr.sw1 = 144;
-    sr.sw2 = 0;
-    sr.simResponse = NULL;
-
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
-  } else {
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-  }
-}
-
-// 0 = Lock is available, but disabled.
-// 1 = Lock is available and enabled,
-// 2 = lock is neither available nor enabled
-static const int kFacilityLockAllDisabled = 0;
-
-static void request_facility_lock(void* data, size_t /*datalen*/, RIL_Token t) {
-  char** data_vec = (char**)data;
-
-  // TODO(ender): implement this; essentially: AT+CLCK
-  // See http://www.activexperts.com/sms-component/at/commands/?at=%2BCLCK
-  // and
-  // opt/telephony/src/java/com/android/internal/telephony/CommandsInterface.java
-  // opt/telephony/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
-
-  ALOGV("Query Facility Lock Code: %s PIN2: %s Service(s): %s AID: %s",
-        data_vec[0], data_vec[1], data_vec[2], data_vec[3]);
-
-  // TODO(ender): there should be a bit vector of responses for each of the
-  // services requested.
-  // Depending on lock code, facilities may be unlocked or locked. We report
-  // these are all unlocked, regardless of the query.
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS,
-                                 const_cast<int*>(&kFacilityLockAllDisabled),
-                                 sizeof(kFacilityLockAllDisabled));
-}
-
-static void request_international_subscriber_id_number(RIL_Token t) {
-  // TODO(ender): Reuse MCC and MNC.
-  std::string subscriber_id = gCurrentNetworkOperator.c_str();
-  subscriber_id += "123456789";
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS,
-                                 strdup(subscriber_id.c_str()), sizeof(char*));
-}
-
-static bool gScreenIsOn = true;
-
-static void request_set_screen_state(void* data, size_t /*datalen*/,
-                                     RIL_Token t) {
-  gScreenIsOn = *(int*)data ? true : false;
-  ALOGV("Screen is %s", gScreenIsOn ? "on" : "off");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-// Unsure which section this belongs in.
-
-static int gModemTtyMode = 1;  // 0 = off, 1 = full, 2 = HCO, 3 = VCO.
-static void request_set_tty_mode(void* data, size_t /*datalen*/, RIL_Token t) {
-  int new_tty_mode = *(int*)(data);
-  ALOGV("Switching modem TTY mode %d -> %d", gModemTtyMode, new_tty_mode);
-
-  if (new_tty_mode >= 0 && new_tty_mode <= 3) {
-    gModemTtyMode = new_tty_mode;
-    gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  } else {
-    gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-  }
-}
-
-static void request_get_tty_mode(RIL_Token t) {
-  ALOGV("Querying TTY mode");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &gModemTtyMode,
-                                 sizeof(gModemTtyMode));
-}
-
-static bool gImsRegistered = false;
-static int gImsFormat = RADIO_TECH_3GPP;
-
-static void request_ims_registration_state(RIL_Token t) {
-  ALOGV("Querying IMS mode");
-  int reply[2];
-  reply[0] = gImsRegistered;
-  reply[1] = gImsFormat;
-
-  ALOGV("Requesting IMS Registration state: %d, format=%d ", reply[0],
-        reply[1]);
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
-}
-
-// New functions after P.
-static void request_start_network_scan(RIL_Token t) {
-  ALOGV("Scanning network - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_set_preferred_network_type_bitmap(int /*request*/, void* data,
-                                               size_t /*datalen*/,
-                                               RIL_Token t) {
-  RIL_RadioAccessFamily desired_access = *(RIL_RadioAccessFamily*)(data);
-
-  ALOGV("Requesting modem technology change %d -> %d", default_access, desired_access);
-
-  /** TODO future implementation: set modem type based on radio access family.
-   * 1) find supported_technologies and desired_technologies
-   * 2) return RIL_E_MODE_NOT_SUPPORTED error if not supported
-   */
-  default_access = desired_access;
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_get_preferred_network_type_bitmap(int /*request*/, void* /*data*/,
-                                               size_t /*datalen*/,
-                                               RIL_Token t) {
-  ALOGV("Requesting modem radio access family: %d", default_access);
-  gce_ril_env->OnRequestComplete(
-      t, RIL_E_SUCCESS, (RIL_RadioAccessFamily*)(&default_access), sizeof(default_access));
-}
-
-static void request_emergency_dial(int /*request*/, void* /*data*/, size_t /*datalen*/,
-    RIL_Token t) {
-  ALOGV("Emergency dial");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_set_sim_card_power(int /*request*/, void* /*data*/, size_t /*datalen*/,
-    RIL_Token t) {
-  ALOGV("Set sim card power - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_get_modem_stack_status(int /*request*/, RIL_Token t) {
-  ALOGV("Getting modem stack status - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_enable_modem(int /*request*/, RIL_Token t) {
-  ALOGV("Enabling modem - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_set_system_selection_channels(int /*request*/, RIL_Token t) {
-  ALOGV("request_set_system_selection_channels - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-// New functions after Q.
-static void request_set_signal_strength_reporting_criteria(int /*request*/, void* /*data*/,
-                                                           size_t /*datalen*/, RIL_Token t) {
-  ALOGV("request_set_signal_strength_reporting_criteria - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_set_link_capacity_reporting_criteria(int /*request*/, void* /*data*/,
-                                                         size_t /*datalen*/, RIL_Token t) {
-  ALOGV("request_set_link_capacity_reporting_criteria - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_enable_uicc_applications(int /*request*/, void* data,
-                                             size_t datalen,
-                                             RIL_Token t) {
-  ALOGV("Enable uicc applications.");
-
-  if (data == NULL || datalen != sizeof(int)) {
-    gce_ril_env->OnRequestComplete(t, RIL_E_INTERNAL_ERR, NULL, 0);
-    return;
-  }
-
-  bool enable = *(int *)(data) != 0;
-
-  ALOGV("areUiccApplicationsEnabled change from %d to %d", areUiccApplicationsEnabled, enable);
-
-  areUiccApplicationsEnabled = enable;
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-}
-
-static void request_are_uicc_applications_enabled(int /*request*/, void* /*data*/,
-                                                  size_t /*datalen*/,
-                                                  RIL_Token t) {
-  ALOGV("Getting whether uicc applications are enabled.");
-
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &areUiccApplicationsEnabled, sizeof(bool));
-}
-
-static void request_enter_sim_depersonalization(RIL_Token t) {
-  ALOGV("request_enter_sim_depersonalization - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void request_cdma_send_sms_expect_more(RIL_Token t) {
-  ALOGV("request_cdma_send_sms_expect_more - void");
-  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-  return;
-}
-
-static void gce_ril_on_request(int request, void* data, size_t datalen,
-                               RIL_Token t) {
-  // Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
-  // when RADIO_STATE_UNAVAILABLE.
-  if (gRadioPowerState == RADIO_STATE_UNAVAILABLE &&
-      request != RIL_REQUEST_GET_SIM_STATUS) {
-    gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-    return;
-  }
-
-  // Ignore all non-power requests when RADIO_STATE_OFF.
-  if (gRadioPowerState == RADIO_STATE_OFF) {
-    switch (request) {
-      case RIL_REQUEST_GET_SIM_STATUS:
-      case RIL_REQUEST_OPERATOR:
-      case RIL_REQUEST_RADIO_POWER:
-      case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
-        // Process all the above, even though the radio is off
-        break;
-      default:
-        gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-        return;
-    }
-  }
-
-  ALOGV("Received request %d", request);
-
-  switch (request) {
-    case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
-      request_query_available_networks(data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_IMEI:
-      request_get_imei(t);
-      break;
-    case RIL_REQUEST_GET_IMEISV:
-      request_get_imei_sv(t);
-      break;
-    case RIL_REQUEST_DEACTIVATE_DATA_CALL:
-      request_teardown_data_call(data, datalen, t);
-      break;
-    case RIL_REQUEST_SCREEN_STATE:
-      request_set_screen_state(data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_SIM_STATUS:
-      getCardStatus(t);
-      break;
-    case RIL_REQUEST_GET_CURRENT_CALLS:
-      request_get_current_calls(data, datalen, t);
-      break;
-    case RIL_REQUEST_DIAL:
-      request_dial(data, datalen, t);
-      break;
-    case RIL_REQUEST_HANGUP:
-      request_hangup(data, datalen, t);
-      break;
-    case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
-      request_hangup_waiting(data, datalen, t);
-      break;
-    case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
-      request_hangup_current(t);
-      break;
-    case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
-      request_switch_current_and_waiting(t);
-      break;
-    case RIL_REQUEST_ANSWER:
-      request_answer_incoming(t);
-      break;
-    case RIL_REQUEST_SET_MUTE:
-      request_set_mute(data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_MUTE:
-      request_get_mute(t);
-      break;
-    case RIL_REQUEST_CONFERENCE:
-      request_combine_multiparty_call(data, datalen, t);
-      break;
-    case RIL_REQUEST_SEPARATE_CONNECTION:
-      request_split_multiparty_call(data, datalen, t);
-      break;
-    case RIL_REQUEST_UDUB:
-      request_udub_on_incoming_calls(t);
-      break;
-    case RIL_REQUEST_SIGNAL_STRENGTH:
-      request_signal_strength(data, datalen, t);
-      break;
-    case RIL_REQUEST_VOICE_REGISTRATION_STATE:
-    case RIL_REQUEST_DATA_REGISTRATION_STATE:
-      request_registration_state(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_OPERATOR:
-      request_operator(data, datalen, t);
-      break;
-    case RIL_REQUEST_RADIO_POWER:
-      request_radio_power(data, datalen, t);
-      break;
-    case RIL_REQUEST_DTMF:
-    case RIL_REQUEST_DTMF_START:
-      request_send_dtmf(data, datalen, t);
-      break;
-    case RIL_REQUEST_DTMF_STOP:
-      request_send_dtmf_stop(t);
-      break;
-    case RIL_REQUEST_SEND_SMS:
-      request_send_SMS(data, t);
-      break;
-    case RIL_REQUEST_CDMA_SEND_SMS:
-      request_cdma_send_SMS(data, t);
-      break;
-    case RIL_REQUEST_SETUP_DATA_CALL:
-      request_setup_data_call(data, datalen, t);
-      break;
-    case RIL_REQUEST_SMS_ACKNOWLEDGE:
-      request_SMS_acknowledge(data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_IMSI:
-      request_international_subscriber_id_number(t);
-      break;
-    case RIL_REQUEST_QUERY_FACILITY_LOCK:
-      request_facility_lock(data, datalen, t);
-      break;
-    case RIL_REQUEST_SIM_IO:
-      request_SIM_IO(data, datalen, t);
-      break;
-    case RIL_REQUEST_SEND_USSD:
-      request_send_ussd(data, datalen, t);
-      break;
-    case RIL_REQUEST_CANCEL_USSD:
-      request_cancel_ussd(t);
-      break;
-    case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
-      request_set_automatic_network_selection(t);
-      break;
-    case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
-      request_set_manual_network_selection(data, datalen, t);
-      break;
-    case RIL_REQUEST_DATA_CALL_LIST:
-      request_data_calllist(data, datalen, t);
-      break;
-    case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE:
-      request_datacall_fail_cause(t);
-      break;
-    case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
-      request_query_network_selection_mode(data, datalen, t);
-      break;
-    case RIL_REQUEST_OEM_HOOK_RAW:
-    case RIL_REQUEST_OEM_HOOK_STRINGS:
-      ALOGV("OEM Hooks not supported!");
-      gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
-      break;
-    case RIL_REQUEST_WRITE_SMS_TO_SIM:
-      request_write_sms_to_sim(data, datalen, t);
-      break;
-    case RIL_REQUEST_DELETE_SMS_ON_SIM:
-      request_delete_sms_on_sim(data, datalen, t);
-      break;
-    case RIL_REQUEST_ENTER_SIM_PIN:
-    case RIL_REQUEST_ENTER_SIM_PUK:
-    case RIL_REQUEST_ENTER_SIM_PIN2:
-    case RIL_REQUEST_ENTER_SIM_PUK2:
-    case RIL_REQUEST_CHANGE_SIM_PIN:
-    case RIL_REQUEST_CHANGE_SIM_PIN2:
-      request_enter_sim_pin(data, datalen, t);
-      break;
-    case RIL_REQUEST_VOICE_RADIO_TECH: {
-      RIL_RadioTechnology tech = getBestVoiceTechnology(gModemCurrentType);
-      gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
-      break;
-    }
-    case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
-      request_set_preferred_network_type(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
-      request_get_preferred_network_type(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
-      request_get_neighboring_cell_ids(data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_CELL_INFO_LIST:
-      request_get_cell_info_list(data, datalen, t);
-      break;
-    case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
-      request_set_cell_info_list_rate(data, datalen, t);
-      break;
-    case RIL_REQUEST_BASEBAND_VERSION:
-      request_baseband_version(t);
-      break;
-    case RIL_REQUEST_SET_TTY_MODE:
-      request_set_tty_mode(data, datalen, t);
-      break;
-    case RIL_REQUEST_QUERY_TTY_MODE:
-      request_get_tty_mode(t);
-      break;
-    case RIL_REQUEST_GET_RADIO_CAPABILITY:
-      request_get_radio_capability(t);
-      break;
-    case RIL_REQUEST_SET_RADIO_CAPABILITY:
-      request_set_radio_capability(data, datalen, t);
-      break;
-    case RIL_REQUEST_SET_DATA_PROFILE:
-      gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-      break;
-    case RIL_REQUEST_GET_HARDWARE_CONFIG:
-      request_hardware_config(t);
-      break;
-    case RIL_REQUEST_IMS_REGISTRATION_STATE:
-      request_ims_registration_state(t);
-      break;
-    case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
-      request_sim_apdu(data, datalen, t);
-      break;
-    case RIL_REQUEST_SIM_OPEN_CHANNEL:
-      request_sim_open_channel(data, datalen, t);
-      break;
-    case RIL_REQUEST_SIM_CLOSE_CHANNEL:
-      request_sim_close_channel(data, datalen, t);
-      break;
-    case RIL_REQUEST_IMS_SEND_SMS:
-      request_ims_send_SMS(data, datalen, t);
-      break;
-    case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
-      ALOGW("INITIAL ATTACH APN");
-      gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-      break;
-
-// New requests after P.
-    case RIL_REQUEST_START_NETWORK_SCAN:
-      request_start_network_scan(t);
-      break;
-    case RIL_REQUEST_GET_MODEM_STACK_STATUS:
-      request_get_modem_stack_status(request, t);
-      break;
-    case RIL_REQUEST_ENABLE_MODEM:
-      request_enable_modem(request, t);
-      break;
-    case RIL_REQUEST_EMERGENCY_DIAL:
-      request_emergency_dial(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_SET_SIM_CARD_POWER:
-      request_set_sim_card_power(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP:
-      request_get_preferred_network_type_bitmap(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP:
-      request_set_preferred_network_type_bitmap(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS:
-      request_set_system_selection_channels(request, t);
-      break;
-    case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING:
-      gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-      break;
-    case RIL_REQUEST_DEVICE_IDENTITY:
-      request_device_identity(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
-      request_cdma_get_subscription_source(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_CDMA_SUBSCRIPTION:
-      request_cdma_subscription(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
-      request_cdma_set_subscription_source(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
-      request_cdma_get_roaming_preference(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
-      request_cdma_set_roaming_preference(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
-      request_exit_emergency_mode(data, datalen, t);
-      break;
-
-// New requests after Q.
-    case RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA:
-      request_set_signal_strength_reporting_criteria(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA:
-      request_set_link_capacity_reporting_criteria(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_ENABLE_UICC_APPLICATIONS:
-      request_enable_uicc_applications(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED:
-      request_are_uicc_applications_enabled(request, data, datalen, t);
-      break;
-    case RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION:
-      request_enter_sim_depersonalization(t);
-      break;
-    case RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE:
-      request_cdma_send_sms_expect_more(t);
-      break;
-    default:
-      ALOGE("Request %d not supported.", request);
-      gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
-      break;
-  }
-}
-
-#define CUTTLEFISH_RIL_VERSION 6
-
-static const RIL_RadioFunctions ril_callbacks = {
-    CUTTLEFISH_RIL_VERSION,     gce_ril_on_request, gce_ril_current_state,
-    gce_ril_on_supports, gce_ril_on_cancel,  gce_ril_get_version};
-
-extern "C" {
-
-const RIL_RadioFunctions* RIL_Init(const struct RIL_Env* env, int /*argc*/,
-                                   char** /*argv*/) {
-  time(&gce_ril_start_time);
-  gce_ril_env = env;
-
-  global_ril_config = cvd::DeviceConfig::Get();
-  if (!global_ril_config) {
-    ALOGE("Failed to open device configuration!!!");
-    return nullptr;
-  }
-
-  TearDownNetworkInterface();
-
-  init_modem_supported_network_types();
-  init_modem_technologies();
-  init_virtual_network();
-  init_sim_file_system();
-  init_sim_status();
-
-  return &ril_callbacks;
-}
-
-}  // extern "C"
diff --git a/guest/hals/ril/cuttlefish_ril.h b/guest/hals/ril/cuttlefish_ril.h
deleted file mode 100644
index 97d4ae1..0000000
--- a/guest/hals/ril/cuttlefish_ril.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2006 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
-
-#define RIL_SHLIB
-
-#define LOG_TAG "CuttlefishRil"
-
-#include <log/log.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#include <guest/hals/ril/libril/ril.h>
-
-#include <telephony/ril_cdma_sms.h>
\ No newline at end of file
diff --git a/guest/hals/ril/libril/Android.mk b/guest/hals/ril/libril/Android.mk
deleted file mode 100644
index 1fe4986..0000000
--- a/guest/hals/ril/libril/Android.mk
+++ /dev/null
@@ -1,65 +0,0 @@
-# Copyright (C) 2019 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.
-
-# We're forced to use Android.mk here because:
-#   This depends on headers in hardware/ril/libril
-#   hardware/ril/libril is still on Android.mk
-
-ifeq (libril-cuttlefish-fork,$(CUTTLEFISH_LIBRIL_NAME))
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE := libril-cuttlefish-fork
-LOCAL_SRC_FILES:= \
-    ril.cpp \
-    ril_service.cpp \
-    ril_event.cpp \
-    RilSapSocket.cpp \
-    sap_service.cpp \
-
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libutils \
-    libcutils \
-    libhardware_legacy \
-    libhidlbase \
-    librilutils \
-    android.hardware.radio@1.0 \
-    android.hardware.radio@1.1 \
-    android.hardware.radio.deprecated@1.0 \
-    android.hardware.radio@1.2 \
-    android.hardware.radio@1.3 \
-    android.hardware.radio@1.4 \
-    android.hardware.radio@1.5 \
-
-LOCAL_STATIC_LIBRARIES := \
-    libprotobuf-c-nano-enable_malloc \
-
-LOCAL_C_INCLUDES += \
-    device/google/cuttlefish \
-    hardware/include \
-    external/nanopb-c \
-    hardware/ril/include \
-    hardware/ril/libril
-
-LOCAL_CFLAGS += \
-    -Wextra \
-    -Wno-unused-parameter
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := hardware/ril/include
-
-include $(BUILD_SHARED_LIBRARY)
-endif
diff --git a/guest/hals/ril/libril/RilSapSocket.cpp b/guest/hals/ril/libril/RilSapSocket.cpp
deleted file mode 100644
index 3465807..0000000
--- a/guest/hals/ril/libril/RilSapSocket.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
-* Copyright (C) 2014 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.
-*/
-
-#define __STDC_LIMIT_MACROS
-#include <stdint.h>
-#define RIL_SHLIB
-#include "RilSapSocket.h"
-#include "pb_decode.h"
-#include "pb_encode.h"
-#undef LOG_TAG
-#define LOG_TAG "RIL_UIM_SOCKET"
-#include <utils/Log.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <sap_service.h>
-#include <guest/hals/ril/libril/ril.h>
-
-static RilSapSocket::RilSapSocketList *head = NULL;
-
-extern "C" void
-RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
-        const struct timeval *relativeTime);
-
-struct RIL_Env RilSapSocket::uimRilEnv = {
-        .OnRequestComplete = RilSapSocket::sOnRequestComplete,
-        .OnUnsolicitedResponse = RilSapSocket::sOnUnsolicitedResponse,
-        .RequestTimedCallback = RIL_requestTimedCallback
-};
-
-void RilSapSocket::sOnRequestComplete (RIL_Token t,
-        RIL_Errno e,
-        void *response,
-        size_t responselen) {
-    RilSapSocket *sap_socket;
-    SapSocketRequest *request = (SapSocketRequest*) t;
-
-    RLOGD("Socket id:%d", request->socketId);
-
-    sap_socket = getSocketById(request->socketId);
-
-    if (sap_socket) {
-        sap_socket->onRequestComplete(t,e,response,responselen);
-    } else {
-        RLOGE("Invalid socket id");
-        if (request->curr) {
-            free(request->curr);
-        }
-        free(request);
-    }
-}
-
-#if defined(ANDROID_MULTI_SIM)
-void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse,
-        const void *data,
-        size_t datalen,
-        RIL_SOCKET_ID socketId) {
-    RilSapSocket *sap_socket = getSocketById(socketId);
-    if (sap_socket) {
-        sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen);
-    }
-}
-#else
-void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse,
-       const void *data,
-       size_t datalen) {
-    RilSapSocket *sap_socket = getSocketById(RIL_SOCKET_1);
-    if(sap_socket){
-        sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen);
-    }
-}
-#endif
-
-void RilSapSocket::printList() {
-    RilSapSocketList *current = head;
-    RLOGD("Printing socket list");
-    while(NULL != current) {
-        RLOGD("SocketName:%s",current->socket->name);
-        RLOGD("Socket id:%d",current->socket->id);
-        current = current->next;
-    }
-}
-
-RilSapSocket *RilSapSocket::getSocketById(RIL_SOCKET_ID socketId) {
-    RilSapSocket *sap_socket;
-    RilSapSocketList *current = head;
-
-    RLOGD("Entered getSocketById");
-    printList();
-
-    while(NULL != current) {
-        if(socketId == current->socket->id) {
-            sap_socket = current->socket;
-            return sap_socket;
-        }
-        current = current->next;
-    }
-    return NULL;
-}
-
-void RilSapSocket::initSapSocket(const char *socketName,
-        const RIL_RadioFunctions *uimFuncs) {
-
-    if (strcmp(socketName, RIL1_SERVICE_NAME) == 0) {
-        if(!SocketExists(socketName)) {
-            addSocketToList(socketName, RIL_SOCKET_1, uimFuncs);
-        }
-    }
-
-#if (SIM_COUNT >= 2)
-    if (strcmp(socketName, RIL2_SERVICE_NAME) == 0) {
-        if(!SocketExists(socketName)) {
-            addSocketToList(socketName, RIL_SOCKET_2, uimFuncs);
-        }
-    }
-#endif
-
-#if (SIM_COUNT >= 3)
-    if (strcmp(socketName, RIL3_SERVICE_NAME) == 0) {
-        if(!SocketExists(socketName)) {
-            addSocketToList(socketName, RIL_SOCKET_3, uimFuncs);
-        }
-    }
-#endif
-
-#if (SIM_COUNT >= 4)
-    if (strcmp(socketName, RIL4_SERVICE_NAME) == 0) {
-        if(!SocketExists(socketName)) {
-            addSocketToList(socketName, RIL_SOCKET_4, uimFuncs);
-        }
-    }
-#endif
-}
-
-void RilSapSocket::addSocketToList(const char *socketName, RIL_SOCKET_ID socketid,
-        const RIL_RadioFunctions *uimFuncs) {
-    RilSapSocket* socket = NULL;
-    RilSapSocketList *current;
-
-    if(!SocketExists(socketName)) {
-        socket = new RilSapSocket(socketName, socketid, uimFuncs);
-        RilSapSocketList* listItem = (RilSapSocketList*)malloc(sizeof(RilSapSocketList));
-        if (!listItem) {
-            RLOGE("addSocketToList: OOM");
-            delete socket;
-            return;
-        }
-        listItem->socket = socket;
-        listItem->next = NULL;
-
-        RLOGD("Adding socket with id: %d", socket->id);
-
-        if(NULL == head) {
-            head = listItem;
-            head->next = NULL;
-        }
-        else {
-            current = head;
-            while(NULL != current->next) {
-                current = current->next;
-            }
-            current->next = listItem;
-        }
-    }
-}
-
-bool RilSapSocket::SocketExists(const char *socketName) {
-    RilSapSocketList* current = head;
-
-    while(NULL != current) {
-        if(strcmp(current->socket->name, socketName) == 0) {
-            return true;
-        }
-        current = current->next;
-    }
-    return false;
-}
-
-RilSapSocket::RilSapSocket(const char *socketName,
-        RIL_SOCKET_ID socketId,
-        const RIL_RadioFunctions *inputUimFuncs):
-        RilSocket(socketName, socketId) {
-    if (inputUimFuncs) {
-        uimFuncs = inputUimFuncs;
-    }
-}
-
-void RilSapSocket::dispatchRequest(MsgHeader *req) {
-    // SapSocketRequest will be deallocated in onRequestComplete()
-    SapSocketRequest* currRequest=(SapSocketRequest*)malloc(sizeof(SapSocketRequest));
-    if (!currRequest) {
-        RLOGE("dispatchRequest: OOM");
-        // Free MsgHeader allocated in pushRecord()
-        free(req);
-        return;
-    }
-    currRequest->token = req->token;
-    currRequest->curr = req;
-    currRequest->p_next = NULL;
-    currRequest->socketId = id;
-
-    pendingResponseQueue.enqueue(currRequest);
-
-    if (uimFuncs) {
-        RLOGI("RilSapSocket::dispatchRequest [%d] > SAP REQUEST type: %d. id: %d. error: %d, \
-                token 0x%p",
-                req->token,
-                req->type,
-                req->id,
-                req->error,
-                currRequest );
-
-#if defined(ANDROID_MULTI_SIM)
-        uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest, id);
-#else
-        uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest);
-#endif
-    }
-}
-
-void RilSapSocket::onRequestComplete(RIL_Token t, RIL_Errno e, void *response,
-        size_t response_len) {
-    SapSocketRequest* request= (SapSocketRequest*)t;
-
-    if (!request || !request->curr) {
-        RLOGE("RilSapSocket::onRequestComplete: request/request->curr is NULL");
-        return;
-    }
-
-    MsgHeader *hdr = request->curr;
-
-    MsgHeader rsp;
-    rsp.token = request->curr->token;
-    rsp.type = MsgType_RESPONSE;
-    rsp.id = request->curr->id;
-    rsp.error = (Error)e;
-    rsp.payload = (pb_bytes_array_t *)calloc(1, sizeof(pb_bytes_array_t) + response_len);
-    if (!rsp.payload) {
-        RLOGE("onRequestComplete: OOM");
-    } else {
-        if (response && response_len > 0) {
-            memcpy(rsp.payload->bytes, response, response_len);
-            rsp.payload->size = response_len;
-        } else {
-            rsp.payload->size = 0;
-        }
-
-        RLOGE("RilSapSocket::onRequestComplete: Token:%d, MessageId:%d ril token 0x%p",
-                hdr->token, hdr->id, t);
-
-        sap::processResponse(&rsp, this);
-        free(rsp.payload);
-    }
-
-    // Deallocate SapSocketRequest
-    if(!pendingResponseQueue.checkAndDequeue(hdr->id, hdr->token)) {
-        RLOGE("Token:%d, MessageId:%d", hdr->token, hdr->id);
-        RLOGE ("RilSapSocket::onRequestComplete: invalid Token or Message Id");
-    }
-
-    // Deallocate MsgHeader
-    free(hdr);
-}
-
-void RilSapSocket::onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) {
-    if (data && datalen > 0) {
-        pb_bytes_array_t *payload = (pb_bytes_array_t *)calloc(1,
-                sizeof(pb_bytes_array_t) + datalen);
-        if (!payload) {
-            RLOGE("onUnsolicitedResponse: OOM");
-            return;
-        }
-        memcpy(payload->bytes, data, datalen);
-        payload->size = datalen;
-        MsgHeader rsp;
-        rsp.payload = payload;
-        rsp.type = MsgType_UNSOL_RESPONSE;
-        rsp.id = (MsgId)unsolResponse;
-        rsp.error = Error_RIL_E_SUCCESS;
-        sap::processUnsolResponse(&rsp, this);
-        free(payload);
-    }
-}
diff --git a/guest/hals/ril/libril/ril.cpp b/guest/hals/ril/libril/ril.cpp
deleted file mode 100644
index 1c385df..0000000
--- a/guest/hals/ril/libril/ril.cpp
+++ /dev/null
@@ -1,1251 +0,0 @@
-/* //guest/hals/ril/ril.cpp
-**
-** Copyright 2006, 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.
-*/
-
-#define LOG_TAG "RILC"
-
-#include <hardware_legacy/power.h>
-#include <guest/hals/ril/libril/ril.h>
-#include <telephony/ril_cdma_sms.h>
-#include <cutils/sockets.h>
-#include <telephony/record_stream.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/limits.h>
-#include <sys/system_properties.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <errno.h>
-#include <assert.h>
-#include <ctype.h>
-#include <sys/un.h>
-#include <assert.h>
-#include <netinet/in.h>
-#include <cutils/properties.h>
-#include <RilSapSocket.h>
-#include <guest/hals/ril/libril/ril_service.h>
-#include <sap_service.h>
-
-extern "C" void
-RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen);
-
-extern "C" void
-RIL_onRequestAck(RIL_Token t);
-namespace android {
-
-#define PHONE_PROCESS "radio"
-#define BLUETOOTH_PROCESS "bluetooth"
-
-#define ANDROID_WAKE_LOCK_NAME "radio-interface"
-
-#define ANDROID_WAKE_LOCK_SECS 0
-#define ANDROID_WAKE_LOCK_USECS 200000
-
-#define PROPERTY_RIL_IMPL "gsm.version.ril-impl"
-
-// match with constant in RIL.java
-#define MAX_COMMAND_BYTES (8 * 1024)
-
-// Basically: memset buffers that the client library
-// shouldn't be using anymore in an attempt to find
-// memory usage issues sooner.
-#define MEMSET_FREED 1
-
-#define NUM_ELEMS(a)     (sizeof (a) / sizeof (a)[0])
-
-/* Negative values for private RIL errno's */
-#define RIL_ERRNO_INVALID_RESPONSE (-1)
-#define RIL_ERRNO_NO_MEMORY (-12)
-
-// request, response, and unsolicited msg print macro
-#define PRINTBUF_SIZE 8096
-
-enum WakeType {DONT_WAKE, WAKE_PARTIAL};
-
-typedef struct {
-    int requestNumber;
-    int (*responseFunction) (int slotId, int responseType, int token,
-            RIL_Errno e, void *response, size_t responselen);
-    WakeType wakeType;
-} UnsolResponseInfo;
-
-typedef struct UserCallbackInfo {
-    RIL_TimedCallback p_callback;
-    void *userParam;
-    struct ril_event event;
-    struct UserCallbackInfo *p_next;
-} UserCallbackInfo;
-
-extern "C" const char * failCauseToString(RIL_Errno);
-extern "C" const char * callStateToString(RIL_CallState);
-extern "C" const char * radioStateToString(RIL_RadioState);
-extern "C" const char * rilSocketIdToString(RIL_SOCKET_ID socket_id);
-
-extern "C"
-char ril_service_name_base[MAX_SERVICE_NAME_LENGTH] = RIL_SERVICE_NAME_BASE;
-extern "C"
-char ril_service_name[MAX_SERVICE_NAME_LENGTH] = RIL1_SERVICE_NAME;
-/*******************************************************************/
-
-RIL_RadioFunctions s_callbacks = {0, NULL, NULL, NULL, NULL, NULL};
-static int s_registerCalled = 0;
-
-static pthread_t s_tid_dispatch;
-static int s_started = 0;
-
-static int s_fdWakeupRead;
-static int s_fdWakeupWrite;
-
-int s_wakelock_count = 0;
-
-static struct ril_event s_wakeupfd_event;
-
-static pthread_mutex_t s_pendingRequestsMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t s_wakeLockCountMutex = PTHREAD_MUTEX_INITIALIZER;
-static RequestInfo *s_pendingRequests = NULL;
-
-#if (SIM_COUNT >= 2)
-static pthread_mutex_t s_pendingRequestsMutex_socket2  = PTHREAD_MUTEX_INITIALIZER;
-static RequestInfo *s_pendingRequests_socket2          = NULL;
-#endif
-
-#if (SIM_COUNT >= 3)
-static pthread_mutex_t s_pendingRequestsMutex_socket3  = PTHREAD_MUTEX_INITIALIZER;
-static RequestInfo *s_pendingRequests_socket3          = NULL;
-#endif
-
-#if (SIM_COUNT >= 4)
-static pthread_mutex_t s_pendingRequestsMutex_socket4  = PTHREAD_MUTEX_INITIALIZER;
-static RequestInfo *s_pendingRequests_socket4          = NULL;
-#endif
-
-static const struct timeval TIMEVAL_WAKE_TIMEOUT = {ANDROID_WAKE_LOCK_SECS,ANDROID_WAKE_LOCK_USECS};
-
-
-static pthread_mutex_t s_startupMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t s_startupCond = PTHREAD_COND_INITIALIZER;
-
-static UserCallbackInfo *s_last_wake_timeout_info = NULL;
-
-static void *s_lastNITZTimeData = NULL;
-static size_t s_lastNITZTimeDataSize;
-
-#if RILC_LOG
-    static char printBuf[PRINTBUF_SIZE];
-#endif
-
-/*******************************************************************/
-static void grabPartialWakeLock();
-void releaseWakeLock();
-static void wakeTimeoutCallback(void *);
-
-#ifdef RIL_SHLIB
-#if defined(ANDROID_MULTI_SIM)
-extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen, RIL_SOCKET_ID socket_id);
-#else
-extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen);
-#endif
-#endif
-
-#if defined(ANDROID_MULTI_SIM)
-#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c), (d))
-#else
-#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c))
-#endif
-
-static UserCallbackInfo * internalRequestTimedCallback
-    (RIL_TimedCallback callback, void *param,
-        const struct timeval *relativeTime);
-
-/** Index == requestNumber */
-static CommandInfo s_commands[] = {
-#include "ril_commands.h"
-};
-
-static UnsolResponseInfo s_unsolResponses[] = {
-#include "ril_unsol_commands.h"
-};
-
-char * RIL_getServiceName() {
-    return ril_service_name;
-}
-
-RequestInfo *
-addRequestToList(int serial, int slotId, int request) {
-    RequestInfo *pRI;
-    int ret;
-    RIL_SOCKET_ID socket_id = (RIL_SOCKET_ID) slotId;
-    /* Hook for current context */
-    /* pendingRequestsMutextHook refer to &s_pendingRequestsMutex */
-    pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex;
-    /* pendingRequestsHook refer to &s_pendingRequests */
-    RequestInfo**    pendingRequestsHook = &s_pendingRequests;
-
-#if (SIM_COUNT >= 2)
-    if (socket_id == RIL_SOCKET_2) {
-        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket2;
-        pendingRequestsHook = &s_pendingRequests_socket2;
-    }
-#if (SIM_COUNT >= 3)
-    else if (socket_id == RIL_SOCKET_3) {
-        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket3;
-        pendingRequestsHook = &s_pendingRequests_socket3;
-    }
-#endif
-#if (SIM_COUNT >= 4)
-    else if (socket_id == RIL_SOCKET_4) {
-        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket4;
-        pendingRequestsHook = &s_pendingRequests_socket4;
-    }
-#endif
-#endif
-
-    pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
-    if (pRI == NULL) {
-        RLOGE("Memory allocation failed for request %s", requestToString(request));
-        return NULL;
-    }
-
-    pRI->token = serial;
-    pRI->pCI = &(s_commands[request]);
-    pRI->socket_id = socket_id;
-
-    ret = pthread_mutex_lock(pendingRequestsMutexHook);
-    assert (ret == 0);
-
-    pRI->p_next = *pendingRequestsHook;
-    *pendingRequestsHook = pRI;
-
-    ret = pthread_mutex_unlock(pendingRequestsMutexHook);
-    assert (ret == 0);
-
-    return pRI;
-}
-
-static void triggerEvLoop() {
-    int ret;
-    if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
-        /* trigger event loop to wakeup. No reason to do this,
-         * if we're in the event loop thread */
-         do {
-            ret = write (s_fdWakeupWrite, " ", 1);
-         } while (ret < 0 && errno == EINTR);
-    }
-}
-
-static void rilEventAddWakeup(struct ril_event *ev) {
-    ril_event_add(ev);
-    triggerEvLoop();
-}
-
-/**
- * A write on the wakeup fd is done just to pop us out of select()
- * We empty the buffer here and then ril_event will reset the timers on the
- * way back down
- */
-static void processWakeupCallback(int fd, short flags, void *param) {
-    char buff[16];
-    int ret;
-
-    RLOGV("processWakeupCallback");
-
-    /* empty our wakeup socket out */
-    do {
-        ret = read(s_fdWakeupRead, &buff, sizeof(buff));
-    } while (ret > 0 || (ret < 0 && errno == EINTR));
-}
-
-static void resendLastNITZTimeData(RIL_SOCKET_ID socket_id) {
-    if (s_lastNITZTimeData != NULL) {
-        int responseType = (s_callbacks.version >= 13)
-                           ? RESPONSE_UNSOLICITED_ACK_EXP
-                           : RESPONSE_UNSOLICITED;
-        // acquire read lock for the service before calling nitzTimeReceivedInd() since it reads
-        // nitzTimeReceived in ril_service
-        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_5::getRadioServiceRwlock(
-                (int) socket_id);
-        int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-
-        int ret = radio_1_5::nitzTimeReceivedInd(
-            (int)socket_id, responseType, 0,
-            RIL_E_SUCCESS, s_lastNITZTimeData, s_lastNITZTimeDataSize);
-        if (ret == 0) {
-            free(s_lastNITZTimeData);
-            s_lastNITZTimeData = NULL;
-        }
-
-        rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-    }
-}
-
-void onNewCommandConnect(RIL_SOCKET_ID socket_id) {
-    // Inform we are connected and the ril version
-    int rilVer = s_callbacks.version;
-    RIL_UNSOL_RESPONSE(RIL_UNSOL_RIL_CONNECTED,
-                                    &rilVer, sizeof(rilVer), socket_id);
-
-    // implicit radio state changed
-    RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
-                                    NULL, 0, socket_id);
-
-    // Send last NITZ time data, in case it was missed
-    if (s_lastNITZTimeData != NULL) {
-        resendLastNITZTimeData(socket_id);
-    }
-
-    // Get version string
-    if (s_callbacks.getVersion != NULL) {
-        const char *version;
-        version = s_callbacks.getVersion();
-        RLOGI("RIL Daemon version: %s\n", version);
-
-        property_set(PROPERTY_RIL_IMPL, version);
-    } else {
-        RLOGI("RIL Daemon version: unavailable\n");
-        property_set(PROPERTY_RIL_IMPL, "unavailable");
-    }
-
-}
-
-static void userTimerCallback (int fd, short flags, void *param) {
-    UserCallbackInfo *p_info;
-
-    p_info = (UserCallbackInfo *)param;
-
-    p_info->p_callback(p_info->userParam);
-
-
-    // FIXME generalize this...there should be a cancel mechanism
-    if (s_last_wake_timeout_info != NULL && s_last_wake_timeout_info == p_info) {
-        s_last_wake_timeout_info = NULL;
-    }
-
-    free(p_info);
-}
-
-
-static void *
-eventLoop(void *param) {
-    int ret;
-    int filedes[2];
-
-    ril_event_init();
-
-    pthread_mutex_lock(&s_startupMutex);
-
-    s_started = 1;
-    pthread_cond_broadcast(&s_startupCond);
-
-    pthread_mutex_unlock(&s_startupMutex);
-
-    ret = pipe(filedes);
-
-    if (ret < 0) {
-        RLOGE("Error in pipe() errno:%d", errno);
-        return NULL;
-    }
-
-    s_fdWakeupRead = filedes[0];
-    s_fdWakeupWrite = filedes[1];
-
-    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
-
-    ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
-                processWakeupCallback, NULL);
-
-    rilEventAddWakeup (&s_wakeupfd_event);
-
-    // Only returns on error
-    ril_event_loop();
-    RLOGE ("error in event_loop_base errno:%d", errno);
-    // kill self to restart on error
-    kill(0, SIGKILL);
-
-    return NULL;
-}
-
-extern "C" void
-RIL_startEventLoop(void) {
-    /* spin up eventLoop thread and wait for it to get started */
-    s_started = 0;
-    pthread_mutex_lock(&s_startupMutex);
-
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
-    int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
-    if (result != 0) {
-        RLOGE("Failed to create dispatch thread: %s", strerror(result));
-        goto done;
-    }
-
-    while (s_started == 0) {
-        pthread_cond_wait(&s_startupCond, &s_startupMutex);
-    }
-
-done:
-    pthread_mutex_unlock(&s_startupMutex);
-}
-
-// Used for testing purpose only.
-extern "C" void RIL_setcallbacks (const RIL_RadioFunctions *callbacks) {
-    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
-}
-
-extern "C" void
-RIL_register (const RIL_RadioFunctions *callbacks) {
-    RLOGI("SIM_COUNT: %d", SIM_COUNT);
-
-    if (callbacks == NULL) {
-        RLOGE("RIL_register: RIL_RadioFunctions * null");
-        return;
-    }
-    if (callbacks->version < RIL_VERSION_MIN) {
-        RLOGE("RIL_register: version %d is to old, min version is %d",
-             callbacks->version, RIL_VERSION_MIN);
-        return;
-    }
-
-    RLOGD("RIL_register: Vsoc RIL version %d", callbacks->version);
-
-    if (s_registerCalled > 0) {
-        RLOGE("RIL_register has been called more than once. "
-                "Subsequent call ignored");
-        return;
-    }
-
-    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
-
-    s_registerCalled = 1;
-
-    RLOGI("s_registerCalled flag set, %d", s_started);
-    // Little self-check
-
-    for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
-        assert(i == s_commands[i].requestNumber);
-    }
-
-    for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
-        assert(i + RIL_UNSOL_RESPONSE_BASE
-                == s_unsolResponses[i].requestNumber);
-    }
-
-    radio_1_5::registerService(&s_callbacks, s_commands);
-    RLOGI("RILHIDL called registerService");
-
-}
-
-extern "C" void
-RIL_register_socket (const RIL_RadioFunctions *(*Init)(const struct RIL_Env *, int, char **),
-        RIL_SOCKET_TYPE socketType, int argc, char **argv) {
-
-    const RIL_RadioFunctions* UimFuncs = NULL;
-
-    if(Init) {
-        UimFuncs = Init(&RilSapSocket::uimRilEnv, argc, argv);
-
-        switch(socketType) {
-            case RIL_SAP_SOCKET:
-                RilSapSocket::initSapSocket(RIL1_SERVICE_NAME, UimFuncs);
-
-#if (SIM_COUNT >= 2)
-                RilSapSocket::initSapSocket(RIL2_SERVICE_NAME, UimFuncs);
-#endif
-
-#if (SIM_COUNT >= 3)
-                RilSapSocket::initSapSocket(RIL3_SERVICE_NAME, UimFuncs);
-#endif
-
-#if (SIM_COUNT >= 4)
-                RilSapSocket::initSapSocket(RIL4_SERVICE_NAME, UimFuncs);
-#endif
-                break;
-            default:;
-        }
-
-        RLOGI("RIL_register_socket: calling registerService");
-        sap::registerService(UimFuncs);
-    }
-}
-
-// Check and remove RequestInfo if its a response and not just ack sent back
-static int
-checkAndDequeueRequestInfoIfAck(struct RequestInfo *pRI, bool isAck) {
-    int ret = 0;
-    /* Hook for current context
-       pendingRequestsMutextHook refer to &s_pendingRequestsMutex */
-    pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex;
-    /* pendingRequestsHook refer to &s_pendingRequests */
-    RequestInfo ** pendingRequestsHook = &s_pendingRequests;
-
-    if (pRI == NULL) {
-        return 0;
-    }
-
-#if (SIM_COUNT >= 2)
-    if (pRI->socket_id == RIL_SOCKET_2) {
-        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket2;
-        pendingRequestsHook = &s_pendingRequests_socket2;
-    }
-#if (SIM_COUNT >= 3)
-        if (pRI->socket_id == RIL_SOCKET_3) {
-            pendingRequestsMutexHook = &s_pendingRequestsMutex_socket3;
-            pendingRequestsHook = &s_pendingRequests_socket3;
-        }
-#endif
-#if (SIM_COUNT >= 4)
-    if (pRI->socket_id == RIL_SOCKET_4) {
-        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket4;
-        pendingRequestsHook = &s_pendingRequests_socket4;
-    }
-#endif
-#endif
-    pthread_mutex_lock(pendingRequestsMutexHook);
-
-    for(RequestInfo **ppCur = pendingRequestsHook
-        ; *ppCur != NULL
-        ; ppCur = &((*ppCur)->p_next)
-    ) {
-        if (pRI == *ppCur) {
-            ret = 1;
-            if (isAck) { // Async ack
-                if (pRI->wasAckSent == 1) {
-                    RLOGD("Ack was already sent for %s", requestToString(pRI->pCI->requestNumber));
-                } else {
-                    pRI->wasAckSent = 1;
-                }
-            } else {
-                *ppCur = (*ppCur)->p_next;
-            }
-            break;
-        }
-    }
-
-    pthread_mutex_unlock(pendingRequestsMutexHook);
-
-    return ret;
-}
-
-extern "C" void
-RIL_onRequestAck(RIL_Token t) {
-    RequestInfo *pRI;
-
-    RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
-
-    pRI = (RequestInfo *)t;
-
-    if (!checkAndDequeueRequestInfoIfAck(pRI, true)) {
-        RLOGE ("RIL_onRequestAck: invalid RIL_Token");
-        return;
-    }
-
-    socket_id = pRI->socket_id;
-
-#if VDBG
-    RLOGD("Request Ack, %s", rilSocketIdToString(socket_id));
-#endif
-
-    appendPrintBuf("Ack [%04d]< %s", pRI->token, requestToString(pRI->pCI->requestNumber));
-
-    if (pRI->cancelled == 0) {
-        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_5::getRadioServiceRwlock(
-                (int) socket_id);
-        int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-
-        radio_1_5::acknowledgeRequest((int) socket_id, pRI->token);
-
-        rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-    }
-}
-extern "C" void
-RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
-    RequestInfo *pRI;
-    int ret;
-    RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
-
-    pRI = (RequestInfo *)t;
-
-    if (!checkAndDequeueRequestInfoIfAck(pRI, false)) {
-        RLOGE ("RIL_onRequestComplete: invalid RIL_Token");
-        return;
-    }
-
-    socket_id = pRI->socket_id;
-
-#if VDBG
-    RLOGD("RequestComplete, %s", rilSocketIdToString(socket_id));
-#endif
-
-    if (pRI->local > 0) {
-        // Locally issued command...void only!
-        // response does not go back up the command socket
-        RLOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
-
-        free(pRI);
-        return;
-    }
-
-    appendPrintBuf("[%04d]< %s",
-        pRI->token, requestToString(pRI->pCI->requestNumber));
-
-    if (pRI->cancelled == 0) {
-        int responseType;
-        if (s_callbacks.version >= 13 && pRI->wasAckSent == 1) {
-            // If ack was already sent, then this call is an asynchronous response. So we need to
-            // send id indicating that we expect an ack from RIL.java as we acquire wakelock here.
-            responseType = RESPONSE_SOLICITED_ACK_EXP;
-            grabPartialWakeLock();
-        } else {
-            responseType = RESPONSE_SOLICITED;
-        }
-
-        // there is a response payload, no matter success or not.
-#if VDBG
-        RLOGE ("Calling responseFunction() for token %d", pRI->token);
-#endif
-
-        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_5::getRadioServiceRwlock((int) socket_id);
-        int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-
-        ret = pRI->pCI->responseFunction((int) socket_id,
-                responseType, pRI->token, e, response, responselen);
-
-        rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-    }
-    free(pRI);
-}
-
-static void
-grabPartialWakeLock() {
-    if (s_callbacks.version >= 13) {
-        int ret;
-        ret = pthread_mutex_lock(&s_wakeLockCountMutex);
-        assert(ret == 0);
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, ANDROID_WAKE_LOCK_NAME);
-
-        UserCallbackInfo *p_info =
-                internalRequestTimedCallback(wakeTimeoutCallback, NULL, &TIMEVAL_WAKE_TIMEOUT);
-        if (p_info == NULL) {
-            release_wake_lock(ANDROID_WAKE_LOCK_NAME);
-        } else {
-            s_wakelock_count++;
-            if (s_last_wake_timeout_info != NULL) {
-                s_last_wake_timeout_info->userParam = (void *)1;
-            }
-            s_last_wake_timeout_info = p_info;
-        }
-        ret = pthread_mutex_unlock(&s_wakeLockCountMutex);
-        assert(ret == 0);
-    } else {
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, ANDROID_WAKE_LOCK_NAME);
-    }
-}
-
-void
-releaseWakeLock() {
-    if (s_callbacks.version >= 13) {
-        int ret;
-        ret = pthread_mutex_lock(&s_wakeLockCountMutex);
-        assert(ret == 0);
-
-        if (s_wakelock_count > 1) {
-            s_wakelock_count--;
-        } else {
-            s_wakelock_count = 0;
-            release_wake_lock(ANDROID_WAKE_LOCK_NAME);
-            if (s_last_wake_timeout_info != NULL) {
-                s_last_wake_timeout_info->userParam = (void *)1;
-            }
-        }
-
-        ret = pthread_mutex_unlock(&s_wakeLockCountMutex);
-        assert(ret == 0);
-    } else {
-        release_wake_lock(ANDROID_WAKE_LOCK_NAME);
-    }
-}
-
-/**
- * Timer callback to put us back to sleep before the default timeout
- */
-static void
-wakeTimeoutCallback (void *param) {
-    // We're using "param != NULL" as a cancellation mechanism
-    if (s_callbacks.version >= 13) {
-        if (param == NULL) {
-            int ret;
-            ret = pthread_mutex_lock(&s_wakeLockCountMutex);
-            assert(ret == 0);
-            s_wakelock_count = 0;
-            release_wake_lock(ANDROID_WAKE_LOCK_NAME);
-            ret = pthread_mutex_unlock(&s_wakeLockCountMutex);
-            assert(ret == 0);
-        }
-    } else {
-        if (param == NULL) {
-            releaseWakeLock();
-        }
-    }
-}
-
-#if defined(ANDROID_MULTI_SIM)
-extern "C"
-void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen, RIL_SOCKET_ID socket_id)
-#else
-extern "C"
-void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen)
-#endif
-{
-    int unsolResponseIndex;
-    int ret;
-    bool shouldScheduleTimeout = false;
-    RIL_SOCKET_ID soc_id = RIL_SOCKET_1;
-
-#if defined(ANDROID_MULTI_SIM)
-    soc_id = socket_id;
-#endif
-
-
-    if (s_registerCalled == 0) {
-        // Ignore RIL_onUnsolicitedResponse before RIL_register
-        RLOGW("RIL_onUnsolicitedResponse called before RIL_register");
-        return;
-    }
-
-    unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
-
-    if ((unsolResponseIndex < 0)
-        || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
-        RLOGE("unsupported unsolicited response code %d", unsolResponse);
-        return;
-    }
-
-    // Grab a wake lock if needed for this reponse,
-    // as we exit we'll either release it immediately
-    // or set a timer to release it later.
-    switch (s_unsolResponses[unsolResponseIndex].wakeType) {
-        case WAKE_PARTIAL:
-            grabPartialWakeLock();
-            shouldScheduleTimeout = true;
-        break;
-
-        case DONT_WAKE:
-        default:
-            // No wake lock is grabed so don't set timeout
-            shouldScheduleTimeout = false;
-            break;
-    }
-
-    appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
-
-    int responseType;
-    if (s_callbacks.version >= 13
-                && s_unsolResponses[unsolResponseIndex].wakeType == WAKE_PARTIAL) {
-        responseType = RESPONSE_UNSOLICITED_ACK_EXP;
-    } else {
-        responseType = RESPONSE_UNSOLICITED;
-    }
-
-    pthread_rwlock_t *radioServiceRwlockPtr = radio_1_5::getRadioServiceRwlock((int) soc_id);
-    int rwlockRet;
-
-    if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
-        // get a write lock in caes of NITZ since setNitzTimeReceived() is called
-        rwlockRet = pthread_rwlock_wrlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-        radio_1_5::setNitzTimeReceived((int) soc_id, android::elapsedRealtime());
-    } else {
-        rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
-        assert(rwlockRet == 0);
-    }
-
-    if (s_unsolResponses[unsolResponseIndex].responseFunction) {
-        RLOGD("calling UNSOLICITED responseFunction for index %d", unsolResponseIndex);
-        ret = s_unsolResponses[unsolResponseIndex].responseFunction(
-                (int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(data),
-                datalen);
-    } else {
-        RLOGW("No call responseFunction defined for UNSOLICITED");
-    }
-
-    rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
-    assert(rwlockRet == 0);
-
-    if (s_callbacks.version < 13) {
-        if (shouldScheduleTimeout) {
-            UserCallbackInfo *p_info = internalRequestTimedCallback(wakeTimeoutCallback, NULL,
-                    &TIMEVAL_WAKE_TIMEOUT);
-
-            if (p_info == NULL) {
-                goto error_exit;
-            } else {
-                // Cancel the previous request
-                if (s_last_wake_timeout_info != NULL) {
-                    s_last_wake_timeout_info->userParam = (void *)1;
-                }
-                s_last_wake_timeout_info = p_info;
-            }
-        }
-    }
-
-#if VDBG
-    RLOGI("%s UNSOLICITED: %s length:%zu", rilSocketIdToString(soc_id),
-            requestToString(unsolResponse), datalen);
-#endif
-
-    if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
-        // Unfortunately, NITZ time is not poll/update like everything
-        // else in the system. So, if the upstream client isn't connected,
-        // keep a copy of the last NITZ response (with receive time noted
-        // above) around so we can deliver it when it is connected
-
-        if (s_lastNITZTimeData != NULL) {
-            free(s_lastNITZTimeData);
-            s_lastNITZTimeData = NULL;
-        }
-
-        s_lastNITZTimeData = calloc(datalen, 1);
-        if (s_lastNITZTimeData == NULL) {
-            RLOGE("Memory allocation failed in RIL_onUnsolicitedResponse");
-            goto error_exit;
-        }
-        s_lastNITZTimeDataSize = datalen;
-        memcpy(s_lastNITZTimeData, data, datalen);
-    }
-
-    // Normal exit
-    return;
-
-error_exit:
-    if (shouldScheduleTimeout) {
-        releaseWakeLock();
-    }
-}
-
-/** FIXME generalize this if you track UserCAllbackInfo, clear it
-    when the callback occurs
-*/
-static UserCallbackInfo *
-internalRequestTimedCallback (RIL_TimedCallback callback, void *param,
-                                const struct timeval *relativeTime)
-{
-    struct timeval myRelativeTime;
-    UserCallbackInfo *p_info;
-
-    p_info = (UserCallbackInfo *) calloc(1, sizeof(UserCallbackInfo));
-    if (p_info == NULL) {
-        RLOGE("Memory allocation failed in internalRequestTimedCallback");
-        return p_info;
-
-    }
-
-    p_info->p_callback = callback;
-    p_info->userParam = param;
-
-    if (relativeTime == NULL) {
-        /* treat null parameter as a 0 relative time */
-        memset (&myRelativeTime, 0, sizeof(myRelativeTime));
-    } else {
-        /* FIXME I think event_add's tv param is really const anyway */
-        memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
-    }
-
-    ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);
-
-    ril_timer_add(&(p_info->event), &myRelativeTime);
-
-    triggerEvLoop();
-    return p_info;
-}
-
-
-extern "C" void
-RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
-                                const struct timeval *relativeTime) {
-    internalRequestTimedCallback (callback, param, relativeTime);
-}
-
-const char *
-failCauseToString(RIL_Errno e) {
-    switch(e) {
-        case RIL_E_SUCCESS: return "E_SUCCESS";
-        case RIL_E_RADIO_NOT_AVAILABLE: return "E_RADIO_NOT_AVAILABLE";
-        case RIL_E_GENERIC_FAILURE: return "E_GENERIC_FAILURE";
-        case RIL_E_PASSWORD_INCORRECT: return "E_PASSWORD_INCORRECT";
-        case RIL_E_SIM_PIN2: return "E_SIM_PIN2";
-        case RIL_E_SIM_PUK2: return "E_SIM_PUK2";
-        case RIL_E_REQUEST_NOT_SUPPORTED: return "E_REQUEST_NOT_SUPPORTED";
-        case RIL_E_CANCELLED: return "E_CANCELLED";
-        case RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL: return "E_OP_NOT_ALLOWED_DURING_VOICE_CALL";
-        case RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW: return "E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW";
-        case RIL_E_SMS_SEND_FAIL_RETRY: return "E_SMS_SEND_FAIL_RETRY";
-        case RIL_E_SIM_ABSENT:return "E_SIM_ABSENT";
-        case RIL_E_ILLEGAL_SIM_OR_ME:return "E_ILLEGAL_SIM_OR_ME";
-#ifdef FEATURE_MULTIMODE_ANDROID
-        case RIL_E_SUBSCRIPTION_NOT_AVAILABLE:return "E_SUBSCRIPTION_NOT_AVAILABLE";
-        case RIL_E_MODE_NOT_SUPPORTED:return "E_MODE_NOT_SUPPORTED";
-#endif
-        case RIL_E_FDN_CHECK_FAILURE: return "E_FDN_CHECK_FAILURE";
-        case RIL_E_MISSING_RESOURCE: return "E_MISSING_RESOURCE";
-        case RIL_E_NO_SUCH_ELEMENT: return "E_NO_SUCH_ELEMENT";
-        case RIL_E_DIAL_MODIFIED_TO_USSD: return "E_DIAL_MODIFIED_TO_USSD";
-        case RIL_E_DIAL_MODIFIED_TO_SS: return "E_DIAL_MODIFIED_TO_SS";
-        case RIL_E_DIAL_MODIFIED_TO_DIAL: return "E_DIAL_MODIFIED_TO_DIAL";
-        case RIL_E_USSD_MODIFIED_TO_DIAL: return "E_USSD_MODIFIED_TO_DIAL";
-        case RIL_E_USSD_MODIFIED_TO_SS: return "E_USSD_MODIFIED_TO_SS";
-        case RIL_E_USSD_MODIFIED_TO_USSD: return "E_USSD_MODIFIED_TO_USSD";
-        case RIL_E_SS_MODIFIED_TO_DIAL: return "E_SS_MODIFIED_TO_DIAL";
-        case RIL_E_SS_MODIFIED_TO_USSD: return "E_SS_MODIFIED_TO_USSD";
-        case RIL_E_SUBSCRIPTION_NOT_SUPPORTED: return "E_SUBSCRIPTION_NOT_SUPPORTED";
-        case RIL_E_SS_MODIFIED_TO_SS: return "E_SS_MODIFIED_TO_SS";
-        case RIL_E_LCE_NOT_SUPPORTED: return "E_LCE_NOT_SUPPORTED";
-        case RIL_E_NO_MEMORY: return "E_NO_MEMORY";
-        case RIL_E_INTERNAL_ERR: return "E_INTERNAL_ERR";
-        case RIL_E_SYSTEM_ERR: return "E_SYSTEM_ERR";
-        case RIL_E_MODEM_ERR: return "E_MODEM_ERR";
-        case RIL_E_INVALID_STATE: return "E_INVALID_STATE";
-        case RIL_E_NO_RESOURCES: return "E_NO_RESOURCES";
-        case RIL_E_SIM_ERR: return "E_SIM_ERR";
-        case RIL_E_INVALID_ARGUMENTS: return "E_INVALID_ARGUMENTS";
-        case RIL_E_INVALID_SIM_STATE: return "E_INVALID_SIM_STATE";
-        case RIL_E_INVALID_MODEM_STATE: return "E_INVALID_MODEM_STATE";
-        case RIL_E_INVALID_CALL_ID: return "E_INVALID_CALL_ID";
-        case RIL_E_NO_SMS_TO_ACK: return "E_NO_SMS_TO_ACK";
-        case RIL_E_NETWORK_ERR: return "E_NETWORK_ERR";
-        case RIL_E_REQUEST_RATE_LIMITED: return "E_REQUEST_RATE_LIMITED";
-        case RIL_E_SIM_BUSY: return "E_SIM_BUSY";
-        case RIL_E_SIM_FULL: return "E_SIM_FULL";
-        case RIL_E_NETWORK_REJECT: return "E_NETWORK_REJECT";
-        case RIL_E_OPERATION_NOT_ALLOWED: return "E_OPERATION_NOT_ALLOWED";
-        case RIL_E_EMPTY_RECORD: return "E_EMPTY_RECORD";
-        case RIL_E_INVALID_SMS_FORMAT: return "E_INVALID_SMS_FORMAT";
-        case RIL_E_ENCODING_ERR: return "E_ENCODING_ERR";
-        case RIL_E_INVALID_SMSC_ADDRESS: return "E_INVALID_SMSC_ADDRESS";
-        case RIL_E_NO_SUCH_ENTRY: return "E_NO_SUCH_ENTRY";
-        case RIL_E_NETWORK_NOT_READY: return "E_NETWORK_NOT_READY";
-        case RIL_E_NOT_PROVISIONED: return "E_NOT_PROVISIONED";
-        case RIL_E_NO_SUBSCRIPTION: return "E_NO_SUBSCRIPTION";
-        case RIL_E_NO_NETWORK_FOUND: return "E_NO_NETWORK_FOUND";
-        case RIL_E_DEVICE_IN_USE: return "E_DEVICE_IN_USE";
-        case RIL_E_ABORTED: return "E_ABORTED";
-        case RIL_E_INVALID_RESPONSE: return "INVALID_RESPONSE";
-        case RIL_E_OEM_ERROR_1: return "E_OEM_ERROR_1";
-        case RIL_E_OEM_ERROR_2: return "E_OEM_ERROR_2";
-        case RIL_E_OEM_ERROR_3: return "E_OEM_ERROR_3";
-        case RIL_E_OEM_ERROR_4: return "E_OEM_ERROR_4";
-        case RIL_E_OEM_ERROR_5: return "E_OEM_ERROR_5";
-        case RIL_E_OEM_ERROR_6: return "E_OEM_ERROR_6";
-        case RIL_E_OEM_ERROR_7: return "E_OEM_ERROR_7";
-        case RIL_E_OEM_ERROR_8: return "E_OEM_ERROR_8";
-        case RIL_E_OEM_ERROR_9: return "E_OEM_ERROR_9";
-        case RIL_E_OEM_ERROR_10: return "E_OEM_ERROR_10";
-        case RIL_E_OEM_ERROR_11: return "E_OEM_ERROR_11";
-        case RIL_E_OEM_ERROR_12: return "E_OEM_ERROR_12";
-        case RIL_E_OEM_ERROR_13: return "E_OEM_ERROR_13";
-        case RIL_E_OEM_ERROR_14: return "E_OEM_ERROR_14";
-        case RIL_E_OEM_ERROR_15: return "E_OEM_ERROR_15";
-        case RIL_E_OEM_ERROR_16: return "E_OEM_ERROR_16";
-        case RIL_E_OEM_ERROR_17: return "E_OEM_ERROR_17";
-        case RIL_E_OEM_ERROR_18: return "E_OEM_ERROR_18";
-        case RIL_E_OEM_ERROR_19: return "E_OEM_ERROR_19";
-        case RIL_E_OEM_ERROR_20: return "E_OEM_ERROR_20";
-        case RIL_E_OEM_ERROR_21: return "E_OEM_ERROR_21";
-        case RIL_E_OEM_ERROR_22: return "E_OEM_ERROR_22";
-        case RIL_E_OEM_ERROR_23: return "E_OEM_ERROR_23";
-        case RIL_E_OEM_ERROR_24: return "E_OEM_ERROR_24";
-        case RIL_E_OEM_ERROR_25: return "E_OEM_ERROR_25";
-        default: return "<unknown error>";
-    }
-}
-
-const char *
-radioStateToString(RIL_RadioState s) {
-    switch(s) {
-        case RADIO_STATE_OFF: return "RADIO_OFF";
-        case RADIO_STATE_UNAVAILABLE: return "RADIO_UNAVAILABLE";
-        case RADIO_STATE_ON:return"RADIO_ON";
-        default: return "<unknown state>";
-    }
-}
-
-const char *
-callStateToString(RIL_CallState s) {
-    switch(s) {
-        case RIL_CALL_ACTIVE : return "ACTIVE";
-        case RIL_CALL_HOLDING: return "HOLDING";
-        case RIL_CALL_DIALING: return "DIALING";
-        case RIL_CALL_ALERTING: return "ALERTING";
-        case RIL_CALL_INCOMING: return "INCOMING";
-        case RIL_CALL_WAITING: return "WAITING";
-        default: return "<unknown state>";
-    }
-}
-
-const char *
-requestToString(int request) {
-/*
- cat guest/hals/ril/libril/ril_commands.h \
- | egrep "^ *{RIL_" \
- | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/'
-
-
- cat guest/hals/ril/libril/ril_unsol_commands.h \
- | egrep "^ *{RIL_" \
- | sed -re 's/\{RIL_([^,]+),([^}]+).+/case RIL_\1: return "\1";/'
-
-*/
-    switch(request) {
-        case RIL_REQUEST_GET_SIM_STATUS: return "GET_SIM_STATUS";
-        case RIL_REQUEST_ENTER_SIM_PIN: return "ENTER_SIM_PIN";
-        case RIL_REQUEST_ENTER_SIM_PUK: return "ENTER_SIM_PUK";
-        case RIL_REQUEST_ENTER_SIM_PIN2: return "ENTER_SIM_PIN2";
-        case RIL_REQUEST_ENTER_SIM_PUK2: return "ENTER_SIM_PUK2";
-        case RIL_REQUEST_CHANGE_SIM_PIN: return "CHANGE_SIM_PIN";
-        case RIL_REQUEST_CHANGE_SIM_PIN2: return "CHANGE_SIM_PIN2";
-        case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: return "ENTER_NETWORK_DEPERSONALIZATION";
-        case RIL_REQUEST_GET_CURRENT_CALLS: return "GET_CURRENT_CALLS";
-        case RIL_REQUEST_DIAL: return "DIAL";
-        case RIL_REQUEST_GET_IMSI: return "GET_IMSI";
-        case RIL_REQUEST_HANGUP: return "HANGUP";
-        case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: return "HANGUP_WAITING_OR_BACKGROUND";
-        case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: return "HANGUP_FOREGROUND_RESUME_BACKGROUND";
-        case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: return "SWITCH_WAITING_OR_HOLDING_AND_ACTIVE";
-        case RIL_REQUEST_CONFERENCE: return "CONFERENCE";
-        case RIL_REQUEST_UDUB: return "UDUB";
-        case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: return "LAST_CALL_FAIL_CAUSE";
-        case RIL_REQUEST_SIGNAL_STRENGTH: return "SIGNAL_STRENGTH";
-        case RIL_REQUEST_VOICE_REGISTRATION_STATE: return "VOICE_REGISTRATION_STATE";
-        case RIL_REQUEST_DATA_REGISTRATION_STATE: return "DATA_REGISTRATION_STATE";
-        case RIL_REQUEST_OPERATOR: return "OPERATOR";
-        case RIL_REQUEST_RADIO_POWER: return "RADIO_POWER";
-        case RIL_REQUEST_DTMF: return "DTMF";
-        case RIL_REQUEST_SEND_SMS: return "SEND_SMS";
-        case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE";
-        case RIL_REQUEST_SETUP_DATA_CALL: return "SETUP_DATA_CALL";
-        case RIL_REQUEST_SIM_IO: return "SIM_IO";
-        case RIL_REQUEST_SEND_USSD: return "SEND_USSD";
-        case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD";
-        case RIL_REQUEST_GET_CLIR: return "GET_CLIR";
-        case RIL_REQUEST_SET_CLIR: return "SET_CLIR";
-        case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: return "QUERY_CALL_FORWARD_STATUS";
-        case RIL_REQUEST_SET_CALL_FORWARD: return "SET_CALL_FORWARD";
-        case RIL_REQUEST_QUERY_CALL_WAITING: return "QUERY_CALL_WAITING";
-        case RIL_REQUEST_SET_CALL_WAITING: return "SET_CALL_WAITING";
-        case RIL_REQUEST_SMS_ACKNOWLEDGE: return "SMS_ACKNOWLEDGE";
-        case RIL_REQUEST_GET_IMEI: return "GET_IMEI";
-        case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV";
-        case RIL_REQUEST_ANSWER: return "ANSWER";
-        case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "DEACTIVATE_DATA_CALL";
-        case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK";
-        case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK";
-        case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD";
-        case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: return "QUERY_NETWORK_SELECTION_MODE";
-        case RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS: return "RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS";
-        case RIL_REQUEST_START_NETWORK_SCAN: return "RIL_REQUEST_START_NETWORK_SCAN";
-        case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: return "SET_NETWORK_SELECTION_AUTOMATIC";
-        case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: return "SET_NETWORK_SELECTION_MANUAL";
-        case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: return "QUERY_AVAILABLE_NETWORKS";
-        case RIL_REQUEST_DTMF_START: return "DTMF_START";
-        case RIL_REQUEST_DTMF_STOP: return "DTMF_STOP";
-        case RIL_REQUEST_BASEBAND_VERSION: return "BASEBAND_VERSION";
-        case RIL_REQUEST_SEPARATE_CONNECTION: return "SEPARATE_CONNECTION";
-        case RIL_REQUEST_SET_MUTE: return "SET_MUTE";
-        case RIL_REQUEST_GET_MUTE: return "GET_MUTE";
-        case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP";
-        case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: return "LAST_DATA_CALL_FAIL_CAUSE";
-        case RIL_REQUEST_DATA_CALL_LIST: return "DATA_CALL_LIST";
-        case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO";
-        case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW";
-        case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS";
-        case RIL_REQUEST_SCREEN_STATE: return "SCREEN_STATE";
-        case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: return "SET_SUPP_SVC_NOTIFICATION";
-        case RIL_REQUEST_WRITE_SMS_TO_SIM: return "WRITE_SMS_TO_SIM";
-        case RIL_REQUEST_DELETE_SMS_ON_SIM: return "DELETE_SMS_ON_SIM";
-        case RIL_REQUEST_SET_BAND_MODE: return "SET_BAND_MODE";
-        case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: return "QUERY_AVAILABLE_BAND_MODE";
-        case RIL_REQUEST_STK_GET_PROFILE: return "STK_GET_PROFILE";
-        case RIL_REQUEST_STK_SET_PROFILE: return "STK_SET_PROFILE";
-        case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: return "STK_SEND_ENVELOPE_COMMAND";
-        case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: return "STK_SEND_TERMINAL_RESPONSE";
-        case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: return "STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM";
-        case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: return "EXPLICIT_CALL_TRANSFER";
-        case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: return "SET_PREFERRED_NETWORK_TYPE";
-        case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "GET_PREFERRED_NETWORK_TYPE";
-        case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "GET_NEIGHBORING_CELL_IDS";
-        case RIL_REQUEST_SET_LOCATION_UPDATES: return "SET_LOCATION_UPDATES";
-        case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: return "CDMA_SET_SUBSCRIPTION_SOURCE";
-        case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: return "CDMA_SET_ROAMING_PREFERENCE";
-        case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: return "CDMA_QUERY_ROAMING_PREFERENCE";
-        case RIL_REQUEST_SET_TTY_MODE: return "SET_TTY_MODE";
-        case RIL_REQUEST_QUERY_TTY_MODE: return "QUERY_TTY_MODE";
-        case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: return "CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE";
-        case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: return "CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE";
-        case RIL_REQUEST_CDMA_FLASH: return "CDMA_FLASH";
-        case RIL_REQUEST_CDMA_BURST_DTMF: return "CDMA_BURST_DTMF";
-        case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: return "CDMA_VALIDATE_AND_WRITE_AKEY";
-        case RIL_REQUEST_CDMA_SEND_SMS: return "CDMA_SEND_SMS";
-        case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: return "CDMA_SMS_ACKNOWLEDGE";
-        case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG: return "GSM_GET_BROADCAST_SMS_CONFIG";
-        case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG: return "GSM_SET_BROADCAST_SMS_CONFIG";
-        case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION: return "GSM_SMS_BROADCAST_ACTIVATION";
-        case RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG: return "CDMA_GET_BROADCAST_SMS_CONFIG";
-        case RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG: return "CDMA_SET_BROADCAST_SMS_CONFIG";
-        case RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION: return "CDMA_SMS_BROADCAST_ACTIVATION";
-        case RIL_REQUEST_CDMA_SUBSCRIPTION: return "CDMA_SUBSCRIPTION";
-        case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "CDMA_WRITE_SMS_TO_RUIM";
-        case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "CDMA_DELETE_SMS_ON_RUIM";
-        case RIL_REQUEST_DEVICE_IDENTITY: return "DEVICE_IDENTITY";
-        case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: return "EXIT_EMERGENCY_CALLBACK_MODE";
-        case RIL_REQUEST_GET_SMSC_ADDRESS: return "GET_SMSC_ADDRESS";
-        case RIL_REQUEST_SET_SMSC_ADDRESS: return "SET_SMSC_ADDRESS";
-        case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: return "REPORT_SMS_MEMORY_STATUS";
-        case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: return "REPORT_STK_SERVICE_IS_RUNNING";
-        case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE: return "CDMA_GET_SUBSCRIPTION_SOURCE";
-        case RIL_REQUEST_ISIM_AUTHENTICATION: return "ISIM_AUTHENTICATION";
-        case RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU: return "ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU";
-        case RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS: return "STK_SEND_ENVELOPE_WITH_STATUS";
-        case RIL_REQUEST_VOICE_RADIO_TECH: return "VOICE_RADIO_TECH";
-        case RIL_REQUEST_GET_CELL_INFO_LIST: return "GET_CELL_INFO_LIST";
-        case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE: return "SET_UNSOL_CELL_INFO_LIST_RATE";
-        case RIL_REQUEST_SET_INITIAL_ATTACH_APN: return "SET_INITIAL_ATTACH_APN";
-        case RIL_REQUEST_IMS_REGISTRATION_STATE: return "IMS_REGISTRATION_STATE";
-        case RIL_REQUEST_IMS_SEND_SMS: return "IMS_SEND_SMS";
-        case RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC: return "SIM_TRANSMIT_APDU_BASIC";
-        case RIL_REQUEST_SIM_OPEN_CHANNEL: return "SIM_OPEN_CHANNEL";
-        case RIL_REQUEST_SIM_CLOSE_CHANNEL: return "SIM_CLOSE_CHANNEL";
-        case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL: return "SIM_TRANSMIT_APDU_CHANNEL";
-        case RIL_REQUEST_NV_READ_ITEM: return "NV_READ_ITEM";
-        case RIL_REQUEST_NV_WRITE_ITEM: return "NV_WRITE_ITEM";
-        case RIL_REQUEST_NV_WRITE_CDMA_PRL: return "NV_WRITE_CDMA_PRL";
-        case RIL_REQUEST_NV_RESET_CONFIG: return "NV_RESET_CONFIG";
-        case RIL_REQUEST_SET_UICC_SUBSCRIPTION: return "SET_UICC_SUBSCRIPTION";
-        case RIL_REQUEST_ALLOW_DATA: return "ALLOW_DATA";
-        case RIL_REQUEST_GET_HARDWARE_CONFIG: return "GET_HARDWARE_CONFIG";
-        case RIL_REQUEST_SIM_AUTHENTICATION: return "SIM_AUTHENTICATION";
-        case RIL_REQUEST_GET_DC_RT_INFO: return "GET_DC_RT_INFO";
-        case RIL_REQUEST_SET_DC_RT_INFO_RATE: return "SET_DC_RT_INFO_RATE";
-        case RIL_REQUEST_SET_DATA_PROFILE: return "SET_DATA_PROFILE";
-        case RIL_REQUEST_SHUTDOWN: return "SHUTDOWN";
-        case RIL_REQUEST_GET_RADIO_CAPABILITY: return "GET_RADIO_CAPABILITY";
-        case RIL_REQUEST_SET_RADIO_CAPABILITY: return "SET_RADIO_CAPABILITY";
-        case RIL_REQUEST_START_LCE: return "START_LCE";
-        case RIL_REQUEST_STOP_LCE: return "STOP_LCE";
-        case RIL_REQUEST_PULL_LCEDATA: return "PULL_LCEDATA";
-        case RIL_REQUEST_GET_ACTIVITY_INFO: return "GET_ACTIVITY_INFO";
-        case RIL_REQUEST_SET_CARRIER_RESTRICTIONS: return "SET_CARRIER_RESTRICTIONS";
-        case RIL_REQUEST_GET_CARRIER_RESTRICTIONS: return "GET_CARRIER_RESTRICTIONS";
-        case RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION: return "SET_CARRIER_INFO_IMSI_ENCRYPTION";
-        case RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA: return "SET_SIGNAL_STRENGTH_REPORTING_CRITERIA";
-        case RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA: return "SET_LINK_CAPACITY_REPORTING_CRITERIA";
-        case RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE: return "CDMA_SEND_SMS_EXPECT_MORE";
-        case RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION: return "ENTER_SIM_DEPERSONALIZATION";
-        case RIL_RESPONSE_ACKNOWLEDGEMENT: return "RESPONSE_ACKNOWLEDGEMENT";
-        case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
-        case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
-        case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED";
-        case RIL_UNSOL_RESPONSE_NEW_SMS: return "UNSOL_RESPONSE_NEW_SMS";
-        case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: return "UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT";
-        case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: return "UNSOL_RESPONSE_NEW_SMS_ON_SIM";
-        case RIL_UNSOL_ON_USSD: return "UNSOL_ON_USSD";
-        case RIL_UNSOL_ON_USSD_REQUEST: return "UNSOL_ON_USSD_REQUEST";
-        case RIL_UNSOL_NITZ_TIME_RECEIVED: return "UNSOL_NITZ_TIME_RECEIVED";
-        case RIL_UNSOL_SIGNAL_STRENGTH: return "UNSOL_SIGNAL_STRENGTH";
-        case RIL_UNSOL_DATA_CALL_LIST_CHANGED: return "UNSOL_DATA_CALL_LIST_CHANGED";
-        case RIL_UNSOL_SUPP_SVC_NOTIFICATION: return "UNSOL_SUPP_SVC_NOTIFICATION";
-        case RIL_UNSOL_STK_SESSION_END: return "UNSOL_STK_SESSION_END";
-        case RIL_UNSOL_STK_PROACTIVE_COMMAND: return "UNSOL_STK_PROACTIVE_COMMAND";
-        case RIL_UNSOL_STK_EVENT_NOTIFY: return "UNSOL_STK_EVENT_NOTIFY";
-        case RIL_UNSOL_STK_CALL_SETUP: return "UNSOL_STK_CALL_SETUP";
-        case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL";
-        case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH";
-        case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING";
-        case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: return "UNSOL_RESPONSE_SIM_STATUS_CHANGED";
-        case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: return "UNSOL_RESPONSE_CDMA_NEW_SMS";
-        case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: return "UNSOL_RESPONSE_NEW_BROADCAST_SMS";
-        case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: return "UNSOL_CDMA_RUIM_SMS_STORAGE_FULL";
-        case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "UNSOL_RESTRICTED_STATE_CHANGED";
-        case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: return "UNSOL_ENTER_EMERGENCY_CALLBACK_MODE";
-        case RIL_UNSOL_CDMA_CALL_WAITING: return "UNSOL_CDMA_CALL_WAITING";
-        case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: return "UNSOL_CDMA_OTA_PROVISION_STATUS";
-        case RIL_UNSOL_CDMA_INFO_REC: return "UNSOL_CDMA_INFO_REC";
-        case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW";
-        case RIL_UNSOL_RINGBACK_TONE: return "UNSOL_RINGBACK_TONE";
-        case RIL_UNSOL_RESEND_INCALL_MUTE: return "UNSOL_RESEND_INCALL_MUTE";
-        case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED: return "UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED";
-        case RIL_UNSOL_CDMA_PRL_CHANGED: return "UNSOL_CDMA_PRL_CHANGED";
-        case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: return "UNSOL_EXIT_EMERGENCY_CALLBACK_MODE";
-        case RIL_UNSOL_RIL_CONNECTED: return "UNSOL_RIL_CONNECTED";
-        case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED: return "UNSOL_VOICE_RADIO_TECH_CHANGED";
-        case RIL_UNSOL_CELL_INFO_LIST: return "UNSOL_CELL_INFO_LIST";
-        case RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED";
-        case RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED: return "UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED";
-        case RIL_UNSOL_SRVCC_STATE_NOTIFY: return "UNSOL_SRVCC_STATE_NOTIFY";
-        case RIL_UNSOL_HARDWARE_CONFIG_CHANGED: return "UNSOL_HARDWARE_CONFIG_CHANGED";
-        case RIL_UNSOL_DC_RT_INFO_CHANGED: return "UNSOL_DC_RT_INFO_CHANGED";
-        case RIL_UNSOL_RADIO_CAPABILITY: return "UNSOL_RADIO_CAPABILITY";
-        case RIL_UNSOL_MODEM_RESTART: return "UNSOL_MODEM_RESTART";
-        case RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION: return "UNSOL_CARRIER_INFO_IMSI_ENCRYPTION";
-        case RIL_UNSOL_ON_SS: return "UNSOL_ON_SS";
-        case RIL_UNSOL_STK_CC_ALPHA_NOTIFY: return "UNSOL_STK_CC_ALPHA_NOTIFY";
-        case RIL_UNSOL_LCEDATA_RECV: return "UNSOL_LCEDATA_RECV";
-        case RIL_UNSOL_PCO_DATA: return "UNSOL_PCO_DATA";
-        default: return "<unknown request>";
-    }
-}
-
-const char *
-rilSocketIdToString(RIL_SOCKET_ID socket_id)
-{
-    switch(socket_id) {
-        case RIL_SOCKET_1:
-            return "RIL_SOCKET_1";
-#if (SIM_COUNT >= 2)
-        case RIL_SOCKET_2:
-            return "RIL_SOCKET_2";
-#endif
-#if (SIM_COUNT >= 3)
-        case RIL_SOCKET_3:
-            return "RIL_SOCKET_3";
-#endif
-#if (SIM_COUNT >= 4)
-        case RIL_SOCKET_4:
-            return "RIL_SOCKET_4";
-#endif
-        default:
-            return "not a valid RIL";
-    }
-}
-
-} /* namespace android */
diff --git a/guest/hals/ril/libril/ril.h b/guest/hals/ril/libril/ril.h
deleted file mode 100644
index a2479eb..0000000
--- a/guest/hals/ril/libril/ril.h
+++ /dev/null
@@ -1,7771 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-#ifndef ANDROID_RIL_H
-#define ANDROID_RIL_H 1
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <telephony/ril_cdma_sms.h>
-#include <telephony/ril_nv_items.h>
-#include <telephony/ril_msim.h>
-
-#ifndef FEATURE_UNIT_TEST
-#include <sys/time.h>
-#endif /* !FEATURE_UNIT_TEST */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef SIM_COUNT
-#if defined(ANDROID_SIM_COUNT_2)
-#define SIM_COUNT 2
-#elif defined(ANDROID_SIM_COUNT_3)
-#define SIM_COUNT 3
-#elif defined(ANDROID_SIM_COUNT_4)
-#define SIM_COUNT 4
-#else
-#define SIM_COUNT 1
-#endif
-
-#ifndef ANDROID_MULTI_SIM
-#define SIM_COUNT 1
-#endif
-#endif
-
-/*
- * RIL version.
- * Value of RIL_VERSION should not be changed in future. Here onwards,
- * when a new change is supposed to be introduced  which could involve new
- * schemes added like Wakelocks, data structures added/updated, etc, we would
- * just document RIL version associated with that change below. When OEM updates its
- * RIL with those changes, they would return that new RIL version during RIL_REGISTER.
- * We should make use of the returned version by vendor to identify appropriate scheme
- * or data structure version to use.
- *
- * Documentation of RIL version and associated changes
- * RIL_VERSION = 12 : This version corresponds to updated data structures namely
- *                    RIL_Data_Call_Response_v11, RIL_SIM_IO_v6, RIL_CardStatus_v6,
- *                    RIL_SimRefreshResponse_v7, RIL_CDMA_CallWaiting_v6,
- *                    RIL_LTE_SignalStrength_v8, RIL_SignalStrength_v10, RIL_CellIdentityGsm_v12
- *                    RIL_CellIdentityWcdma_v12, RIL_CellIdentityLte_v12,RIL_CellInfoGsm_v12,
- *                    RIL_CellInfoWcdma_v12, RIL_CellInfoLte_v12, RIL_CellInfo_v12.
- *
- * RIL_VERSION = 13 : This version includes new wakelock semantics and as the first
- *                    strongly versioned version it enforces structure use.
- *
- * RIL_VERSION = 14 : New data structures are added, namely RIL_CarrierMatchType,
- *                    RIL_Carrier, RIL_CarrierRestrictions and RIL_PCO_Data.
- *                    New commands added: RIL_REQUEST_SET_CARRIER_RESTRICTIONS,
- *                    RIL_REQUEST_SET_CARRIER_RESTRICTIONS and RIL_UNSOL_PCO_DATA.
- *
- * RIL_VERSION = 15 : New commands added:
- *                    RIL_UNSOL_MODEM_RESTART,
- *                    RIL_REQUEST_SEND_DEVICE_STATE,
- *                    RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER,
- *                    RIL_REQUEST_SET_SIM_CARD_POWER,
- *                    RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION,
- *                    RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION
- *                    RIL_REQUEST_START_NETWORK_SCAN
- *                    RIL_REQUEST_STOP_NETWORK_SCAN
- *                    RIL_UNSOL_NETWORK_SCAN_RESULT
- *                    RIL_REQUEST_GET_MODEM_STACK_STATUS
- *                    RIL_REQUEST_ENABLE_MODEM
- *                    RIL_REQUEST_EMERGENCY_DIAL
- *                    RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS
- *                    RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA
- *                    RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA
- *                    RIL_REQUEST_ENABLE_UICC_APPLICATIONS
- *                    RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED
- *                    RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION
- *                    RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE
- *                    The new parameters for RIL_REQUEST_SETUP_DATA_CALL,
- *                    Updated data structures: RIL_DataProfileInfo_v15, RIL_InitialAttachApn_v15,
- *                    RIL_Data_Call_Response_v12.
- *                    New data structure RIL_DataRegistrationStateResponse, RIL_OpenChannelParams,
- *                    RIL_VoiceRegistrationStateResponse same is
- *                    used in RIL_REQUEST_DATA_REGISTRATION_STATE and
- *                    RIL_REQUEST_VOICE_REGISTRATION_STATE respectively.
- */
-#define RIL_VERSION 12
-#define LAST_IMPRECISE_RIL_VERSION 12 // Better self-documented name
-#define RIL_VERSION_MIN 6 /* Minimum RIL_VERSION supported */
-
-#define CDMA_ALPHA_INFO_BUFFER_LENGTH 64
-#define CDMA_NUMBER_INFO_BUFFER_LENGTH 81
-
-#define MAX_RILDS 3
-#define MAX_SERVICE_NAME_LENGTH 6
-#define MAX_CLIENT_ID_LENGTH 2
-#define MAX_DEBUG_SOCKET_NAME_LENGTH 12
-#define MAX_QEMU_PIPE_NAME_LENGTH  11
-#define MAX_UUID_LENGTH 64
-#define MAX_BANDS 8
-#define MAX_CHANNELS 32
-#define MAX_RADIO_ACCESS_NETWORKS 8
-#define MAX_BROADCAST_SMS_CONFIG_INFO 25
-
-
-typedef void * RIL_Token;
-
-typedef enum {
-    RIL_SOCKET_1,
-#if (SIM_COUNT >= 2)
-    RIL_SOCKET_2,
-#if (SIM_COUNT >= 3)
-    RIL_SOCKET_3,
-#endif
-#if (SIM_COUNT >= 4)
-    RIL_SOCKET_4,
-#endif
-#endif
-    RIL_SOCKET_NUM
-} RIL_SOCKET_ID;
-
-
-typedef enum {
-    RIL_E_SUCCESS = 0,
-    RIL_E_RADIO_NOT_AVAILABLE = 1,     /* If radio did not start or is resetting */
-    RIL_E_GENERIC_FAILURE = 2,
-    RIL_E_PASSWORD_INCORRECT = 3,      /* for PIN/PIN2 methods only! */
-    RIL_E_SIM_PIN2 = 4,                /* Operation requires SIM PIN2 to be entered */
-    RIL_E_SIM_PUK2 = 5,                /* Operation requires SIM PIN2 to be entered */
-    RIL_E_REQUEST_NOT_SUPPORTED = 6,
-    RIL_E_CANCELLED = 7,
-    RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8, /* data ops are not allowed during voice
-                                                   call on a Class C GPRS device */
-    RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,  /* data ops are not allowed before device
-                                                   registers in network */
-    RIL_E_SMS_SEND_FAIL_RETRY = 10,             /* fail to send sms and need retry */
-    RIL_E_SIM_ABSENT = 11,                      /* fail to set the location where CDMA subscription
-                                                   shall be retrieved because of SIM or RUIM
-                                                   card absent */
-    RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,      /* fail to find CDMA subscription from specified
-                                                   location */
-    RIL_E_MODE_NOT_SUPPORTED = 13,              /* HW does not support preferred network type */
-    RIL_E_FDN_CHECK_FAILURE = 14,               /* command failed because recipient is not on FDN list */
-    RIL_E_ILLEGAL_SIM_OR_ME = 15,               /* network selection failed due to
-                                                   illegal SIM or ME */
-    RIL_E_MISSING_RESOURCE = 16,                /* no logical channel available */
-    RIL_E_NO_SUCH_ELEMENT = 17,                  /* application not found on SIM */
-    RIL_E_DIAL_MODIFIED_TO_USSD = 18,           /* DIAL request modified to USSD */
-    RIL_E_DIAL_MODIFIED_TO_SS = 19,             /* DIAL request modified to SS */
-    RIL_E_DIAL_MODIFIED_TO_DIAL = 20,           /* DIAL request modified to DIAL with different
-                                                   data */
-    RIL_E_USSD_MODIFIED_TO_DIAL = 21,           /* USSD request modified to DIAL */
-    RIL_E_USSD_MODIFIED_TO_SS = 22,             /* USSD request modified to SS */
-    RIL_E_USSD_MODIFIED_TO_USSD = 23,           /* USSD request modified to different USSD
-                                                   request */
-    RIL_E_SS_MODIFIED_TO_DIAL = 24,             /* SS request modified to DIAL */
-    RIL_E_SS_MODIFIED_TO_USSD = 25,             /* SS request modified to USSD */
-    RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,      /* Subscription not supported by RIL */
-    RIL_E_SS_MODIFIED_TO_SS = 27,               /* SS request modified to different SS request */
-    RIL_E_LCE_NOT_SUPPORTED = 36,               /* LCE service not supported(36 in RILConstants.java) */
-    RIL_E_NO_MEMORY = 37,                       /* Not sufficient memory to process the request */
-    RIL_E_INTERNAL_ERR = 38,                    /* Modem hit unexpected error scenario while handling
-                                                   this request */
-    RIL_E_SYSTEM_ERR = 39,                      /* Hit platform or system error */
-    RIL_E_MODEM_ERR = 40,                       /* Vendor RIL got unexpected or incorrect response
-                                                   from modem for this request */
-    RIL_E_INVALID_STATE = 41,                   /* Unexpected request for the current state */
-    RIL_E_NO_RESOURCES = 42,                    /* Not sufficient resource to process the request */
-    RIL_E_SIM_ERR = 43,                         /* Received error from SIM card */
-    RIL_E_INVALID_ARGUMENTS = 44,               /* Received invalid arguments in request */
-    RIL_E_INVALID_SIM_STATE = 45,               /* Can not process the request in current SIM state */
-    RIL_E_INVALID_MODEM_STATE = 46,             /* Can not process the request in current Modem state */
-    RIL_E_INVALID_CALL_ID = 47,                 /* Received invalid call id in request */
-    RIL_E_NO_SMS_TO_ACK = 48,                   /* ACK received when there is no SMS to ack */
-    RIL_E_NETWORK_ERR = 49,                     /* Received error from network */
-    RIL_E_REQUEST_RATE_LIMITED = 50,            /* Operation denied due to overly-frequent requests */
-    RIL_E_SIM_BUSY = 51,                        /* SIM is busy */
-    RIL_E_SIM_FULL = 52,                        /* The target EF is full */
-    RIL_E_NETWORK_REJECT = 53,                  /* Request is rejected by network */
-    RIL_E_OPERATION_NOT_ALLOWED = 54,           /* Not allowed the request now */
-    RIL_E_EMPTY_RECORD = 55,                    /* The request record is empty */
-    RIL_E_INVALID_SMS_FORMAT = 56,              /* Invalid sms format */
-    RIL_E_ENCODING_ERR = 57,                    /* Message not encoded properly */
-    RIL_E_INVALID_SMSC_ADDRESS = 58,            /* SMSC address specified is invalid */
-    RIL_E_NO_SUCH_ENTRY = 59,                   /* No such entry present to perform the request */
-    RIL_E_NETWORK_NOT_READY = 60,               /* Network is not ready to perform the request */
-    RIL_E_NOT_PROVISIONED = 61,                 /* Device doesnot have this value provisioned */
-    RIL_E_NO_SUBSCRIPTION = 62,                 /* Device doesnot have subscription */
-    RIL_E_NO_NETWORK_FOUND = 63,                /* Network cannot be found */
-    RIL_E_DEVICE_IN_USE = 64,                   /* Operation cannot be performed because the device
-                                                   is currently in use */
-    RIL_E_ABORTED = 65,                         /* Operation aborted */
-    RIL_E_INVALID_RESPONSE = 66,                /* Invalid response sent by vendor code */
-    // OEM specific error codes. To be used by OEM when they don't want to reveal
-    // specific error codes which would be replaced by Generic failure.
-    RIL_E_OEM_ERROR_1 = 501,
-    RIL_E_OEM_ERROR_2 = 502,
-    RIL_E_OEM_ERROR_3 = 503,
-    RIL_E_OEM_ERROR_4 = 504,
-    RIL_E_OEM_ERROR_5 = 505,
-    RIL_E_OEM_ERROR_6 = 506,
-    RIL_E_OEM_ERROR_7 = 507,
-    RIL_E_OEM_ERROR_8 = 508,
-    RIL_E_OEM_ERROR_9 = 509,
-    RIL_E_OEM_ERROR_10 = 510,
-    RIL_E_OEM_ERROR_11 = 511,
-    RIL_E_OEM_ERROR_12 = 512,
-    RIL_E_OEM_ERROR_13 = 513,
-    RIL_E_OEM_ERROR_14 = 514,
-    RIL_E_OEM_ERROR_15 = 515,
-    RIL_E_OEM_ERROR_16 = 516,
-    RIL_E_OEM_ERROR_17 = 517,
-    RIL_E_OEM_ERROR_18 = 518,
-    RIL_E_OEM_ERROR_19 = 519,
-    RIL_E_OEM_ERROR_20 = 520,
-    RIL_E_OEM_ERROR_21 = 521,
-    RIL_E_OEM_ERROR_22 = 522,
-    RIL_E_OEM_ERROR_23 = 523,
-    RIL_E_OEM_ERROR_24 = 524,
-    RIL_E_OEM_ERROR_25 = 525
-} RIL_Errno;
-
-typedef enum {
-    RIL_CALL_ACTIVE = 0,
-    RIL_CALL_HOLDING = 1,
-    RIL_CALL_DIALING = 2,    /* MO call only */
-    RIL_CALL_ALERTING = 3,   /* MO call only */
-    RIL_CALL_INCOMING = 4,   /* MT call only */
-    RIL_CALL_WAITING = 5     /* MT call only */
-} RIL_CallState;
-
-typedef enum {
-    RADIO_STATE_OFF = 0,                   /* Radio explictly powered off (eg CFUN=0) */
-    RADIO_STATE_UNAVAILABLE = 1,           /* Radio unavailable (eg, resetting or not booted) */
-    RADIO_STATE_ON = 10                    /* Radio is on */
-} RIL_RadioState;
-
-typedef enum {
-    RADIO_TECH_UNKNOWN = 0,
-    RADIO_TECH_GPRS = 1,
-    RADIO_TECH_EDGE = 2,
-    RADIO_TECH_UMTS = 3,
-    RADIO_TECH_IS95A = 4,
-    RADIO_TECH_IS95B = 5,
-    RADIO_TECH_1xRTT =  6,
-    RADIO_TECH_EVDO_0 = 7,
-    RADIO_TECH_EVDO_A = 8,
-    RADIO_TECH_HSDPA = 9,
-    RADIO_TECH_HSUPA = 10,
-    RADIO_TECH_HSPA = 11,
-    RADIO_TECH_EVDO_B = 12,
-    RADIO_TECH_EHRPD = 13,
-    RADIO_TECH_LTE = 14,
-    RADIO_TECH_HSPAP = 15, // HSPA+
-    RADIO_TECH_GSM = 16, // Only supports voice
-    RADIO_TECH_TD_SCDMA = 17,
-    RADIO_TECH_IWLAN = 18,
-    RADIO_TECH_LTE_CA = 19
-} RIL_RadioTechnology;
-
-typedef enum {
-    RAF_UNKNOWN =  (1 <<  RADIO_TECH_UNKNOWN),
-    RAF_GPRS = (1 << RADIO_TECH_GPRS),
-    RAF_EDGE = (1 << RADIO_TECH_EDGE),
-    RAF_UMTS = (1 << RADIO_TECH_UMTS),
-    RAF_IS95A = (1 << RADIO_TECH_IS95A),
-    RAF_IS95B = (1 << RADIO_TECH_IS95B),
-    RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
-    RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
-    RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
-    RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
-    RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
-    RAF_HSPA = (1 << RADIO_TECH_HSPA),
-    RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
-    RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
-    RAF_LTE = (1 << RADIO_TECH_LTE),
-    RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
-    RAF_GSM = (1 << RADIO_TECH_GSM),
-    RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
-    RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
-} RIL_RadioAccessFamily;
-
-typedef enum {
-    BAND_MODE_UNSPECIFIED = 0,      //"unspecified" (selected by baseband automatically)
-    BAND_MODE_EURO = 1,             //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
-    BAND_MODE_USA = 2,              //"US band" (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
-    BAND_MODE_JPN = 3,              //"JPN band" (WCDMA-800 / WCDMA-IMT-2000)
-    BAND_MODE_AUS = 4,              //"AUS band" (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
-    BAND_MODE_AUS_2 = 5,            //"AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
-    BAND_MODE_CELL_800 = 6,         //"Cellular" (800-MHz Band)
-    BAND_MODE_PCS = 7,              //"PCS" (1900-MHz Band)
-    BAND_MODE_JTACS = 8,            //"Band Class 3" (JTACS Band)
-    BAND_MODE_KOREA_PCS = 9,        //"Band Class 4" (Korean PCS Band)
-    BAND_MODE_5_450M = 10,          //"Band Class 5" (450-MHz Band)
-    BAND_MODE_IMT2000 = 11,         //"Band Class 6" (2-GMHz IMT2000 Band)
-    BAND_MODE_7_700M_2 = 12,        //"Band Class 7" (Upper 700-MHz Band)
-    BAND_MODE_8_1800M = 13,         //"Band Class 8" (1800-MHz Band)
-    BAND_MODE_9_900M = 14,          //"Band Class 9" (900-MHz Band)
-    BAND_MODE_10_800M_2 = 15,       //"Band Class 10" (Secondary 800-MHz Band)
-    BAND_MODE_EURO_PAMR_400M = 16,  //"Band Class 11" (400-MHz European PAMR Band)
-    BAND_MODE_AWS = 17,             //"Band Class 15" (AWS Band)
-    BAND_MODE_USA_2500M = 18        //"Band Class 16" (US 2.5-GHz Band)
-} RIL_RadioBandMode;
-
-typedef enum {
-    RC_PHASE_CONFIGURED = 0,  // LM is configured is initial value and value after FINISH completes
-    RC_PHASE_START      = 1,  // START is sent before Apply and indicates that an APPLY will be
-                              // forthcoming with these same parameters
-    RC_PHASE_APPLY      = 2,  // APPLY is sent after all LM's receive START and returned
-                              // RIL_RadioCapability.status = 0, if any START's fail no
-                              // APPLY will be sent
-    RC_PHASE_UNSOL_RSP  = 3,  // UNSOL_RSP is sent with RIL_UNSOL_RADIO_CAPABILITY
-    RC_PHASE_FINISH     = 4   // FINISH is sent after all commands have completed. If an error
-                              // occurs in any previous command the RIL_RadioAccessesFamily and
-                              // logicalModemUuid fields will be the prior configuration thus
-                              // restoring the configuration to the previous value. An error
-                              // returned by this command will generally be ignored or may
-                              // cause that logical modem to be removed from service.
-} RadioCapabilityPhase;
-
-typedef enum {
-    RC_STATUS_NONE       = 0, // This parameter has no meaning with RC_PHASE_START,
-                              // RC_PHASE_APPLY
-    RC_STATUS_SUCCESS    = 1, // Tell modem the action transaction of set radio
-                              // capability was success with RC_PHASE_FINISH
-    RC_STATUS_FAIL       = 2, // Tell modem the action transaction of set radio
-                              // capability is fail with RC_PHASE_FINISH.
-} RadioCapabilityStatus;
-
-#define RIL_RADIO_CAPABILITY_VERSION 1
-typedef struct {
-    int version;            // Version of structure, RIL_RADIO_CAPABILITY_VERSION
-    int session;            // Unique session value defined by framework returned in all "responses/unsol"
-    int phase;              // CONFIGURED, START, APPLY, FINISH
-    int rat;                // RIL_RadioAccessFamily for the radio
-    char logicalModemUuid[MAX_UUID_LENGTH]; // A UUID typically "com.xxxx.lmX where X is the logical modem.
-    int status;             // Return status and an input parameter for RC_PHASE_FINISH
-} RIL_RadioCapability;
-
-// Do we want to split Data from Voice and the use
-// RIL_RadioTechnology for get/setPreferredVoice/Data ?
-typedef enum {
-    PREF_NET_TYPE_GSM_WCDMA                = 0, /* GSM/WCDMA (WCDMA preferred) */
-    PREF_NET_TYPE_GSM_ONLY                 = 1, /* GSM only */
-    PREF_NET_TYPE_WCDMA                    = 2, /* WCDMA  */
-    PREF_NET_TYPE_GSM_WCDMA_AUTO           = 3, /* GSM/WCDMA (auto mode, according to PRL) */
-    PREF_NET_TYPE_CDMA_EVDO_AUTO           = 4, /* CDMA and EvDo (auto mode, according to PRL) */
-    PREF_NET_TYPE_CDMA_ONLY                = 5, /* CDMA only */
-    PREF_NET_TYPE_EVDO_ONLY                = 6, /* EvDo only */
-    PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7, /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) */
-    PREF_NET_TYPE_LTE_CDMA_EVDO            = 8, /* LTE, CDMA and EvDo */
-    PREF_NET_TYPE_LTE_GSM_WCDMA            = 9, /* LTE, GSM/WCDMA */
-    PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA  = 10, /* LTE, CDMA, EvDo, GSM/WCDMA */
-    PREF_NET_TYPE_LTE_ONLY                 = 11, /* LTE only */
-    PREF_NET_TYPE_LTE_WCDMA                = 12,  /* LTE/WCDMA */
-    PREF_NET_TYPE_TD_SCDMA_ONLY            = 13, /* TD-SCDMA only */
-    PREF_NET_TYPE_TD_SCDMA_WCDMA           = 14, /* TD-SCDMA and WCDMA */
-    PREF_NET_TYPE_TD_SCDMA_LTE             = 15, /* TD-SCDMA and LTE */
-    PREF_NET_TYPE_TD_SCDMA_GSM             = 16, /* TD-SCDMA and GSM */
-    PREF_NET_TYPE_TD_SCDMA_GSM_LTE         = 17, /* TD-SCDMA,GSM and LTE */
-    PREF_NET_TYPE_TD_SCDMA_GSM_WCDMA       = 18, /* TD-SCDMA, GSM/WCDMA */
-    PREF_NET_TYPE_TD_SCDMA_WCDMA_LTE       = 19, /* TD-SCDMA, WCDMA and LTE */
-    PREF_NET_TYPE_TD_SCDMA_GSM_WCDMA_LTE   = 20, /* TD-SCDMA, GSM/WCDMA and LTE */
-    PREF_NET_TYPE_TD_SCDMA_GSM_WCDMA_CDMA_EVDO_AUTO  = 21, /* TD-SCDMA, GSM/WCDMA, CDMA and EvDo */
-    PREF_NET_TYPE_TD_SCDMA_LTE_CDMA_EVDO_GSM_WCDMA   = 22  /* TD-SCDMA, LTE, CDMA, EvDo GSM/WCDMA */
-} RIL_PreferredNetworkType;
-
-/* Source for cdma subscription */
-typedef enum {
-   CDMA_SUBSCRIPTION_SOURCE_RUIM_SIM = 0,
-   CDMA_SUBSCRIPTION_SOURCE_NV = 1
-} RIL_CdmaSubscriptionSource;
-
-/* User-to-User signaling Info activation types derived from 3GPP 23.087 v8.0 */
-typedef enum {
-    RIL_UUS_TYPE1_IMPLICIT = 0,
-    RIL_UUS_TYPE1_REQUIRED = 1,
-    RIL_UUS_TYPE1_NOT_REQUIRED = 2,
-    RIL_UUS_TYPE2_REQUIRED = 3,
-    RIL_UUS_TYPE2_NOT_REQUIRED = 4,
-    RIL_UUS_TYPE3_REQUIRED = 5,
-    RIL_UUS_TYPE3_NOT_REQUIRED = 6
-} RIL_UUS_Type;
-
-/* User-to-User Signaling Information data coding schemes. Possible values for
- * Octet 3 (Protocol Discriminator field) in the UUIE. The values have been
- * specified in section 10.5.4.25 of 3GPP TS 24.008 */
-typedef enum {
-    RIL_UUS_DCS_USP = 0,          /* User specified protocol */
-    RIL_UUS_DCS_OSIHLP = 1,       /* OSI higher layer protocol */
-    RIL_UUS_DCS_X244 = 2,         /* X.244 */
-    RIL_UUS_DCS_RMCF = 3,         /* Reserved for system mangement
-                                     convergence function */
-    RIL_UUS_DCS_IA5c = 4          /* IA5 characters */
-} RIL_UUS_DCS;
-
-/* User-to-User Signaling Information defined in 3GPP 23.087 v8.0
- * This data is passed in RIL_ExtensionRecord and rec contains this
- * structure when type is RIL_UUS_INFO_EXT_REC */
-typedef struct {
-  RIL_UUS_Type    uusType;    /* UUS Type */
-  RIL_UUS_DCS     uusDcs;     /* UUS Data Coding Scheme */
-  int             uusLength;  /* Length of UUS Data */
-  char *          uusData;    /* UUS Data */
-} RIL_UUS_Info;
-
-/* CDMA Signal Information Record as defined in C.S0005 section 3.7.5.5 */
-typedef struct {
-  char isPresent;    /* non-zero if signal information record is present */
-  char signalType;   /* as defined 3.7.5.5-1 */
-  char alertPitch;   /* as defined 3.7.5.5-2 */
-  char signal;       /* as defined 3.7.5.5-3, 3.7.5.5-4 or 3.7.5.5-5 */
-} RIL_CDMA_SignalInfoRecord;
-
-typedef struct {
-    RIL_CallState   state;
-    int             index;      /* Connection Index for use with, eg, AT+CHLD */
-    int             toa;        /* type of address, eg 145 = intl */
-    char            isMpty;     /* nonzero if is mpty call */
-    char            isMT;       /* nonzero if call is mobile terminated */
-    char            als;        /* ALS line indicator if available
-                                   (0 = line 1) */
-    char            isVoice;    /* nonzero if this is is a voice call */
-    char            isVoicePrivacy;     /* nonzero if CDMA voice privacy mode is active */
-    char *          number;     /* Remote party number */
-    int             numberPresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown 3=Payphone */
-    char *          name;       /* Remote party name */
-    int             namePresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown 3=Payphone */
-    RIL_UUS_Info *  uusInfo;    /* NULL or Pointer to User-User Signaling Information */
-} RIL_Call;
-
-/* Deprecated, use RIL_Data_Call_Response_v6 */
-typedef struct {
-    int             cid;        /* Context ID, uniquely identifies this call */
-    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
-    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
-                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". */
-    char *          apn;        /* ignored */
-    char *          address;    /* An address, e.g., "192.0.1.3" or "2001:db8::1". */
-} RIL_Data_Call_Response_v4;
-
-/*
- * Returned by RIL_REQUEST_SETUP_DATA_CALL, RIL_REQUEST_DATA_CALL_LIST
- * and RIL_UNSOL_DATA_CALL_LIST_CHANGED, on error status != 0.
- */
-typedef struct {
-    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
-    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
-                                           back-off timer value RIL wants to override the one
-                                           pre-configured in FW.
-                                           The unit is miliseconds.
-                                           The value < 0 means no value is suggested.
-                                           The value 0 means retry should be done ASAP.
-                                           The value of INT_MAX(0x7fffffff) means no retry. */
-    int             cid;        /* Context ID, uniquely identifies this call */
-    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
-    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
-                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
-                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
-                                   such as "IP" or "IPV6" */
-    char *          ifname;     /* The network interface name */
-    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix length,
-                                   e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
-                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
-                                   one of each. If the prefix length is absent the addresses
-                                   are assumed to be point to point with IPv4 having a prefix
-                                   length of 32 and IPv6 128. */
-    char *          dnses;      /* A space-delimited list of DNS server addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty. */
-    char *          gateways;   /* A space-delimited list of default gateway addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty in which case the addresses represent point
-                                   to point connections. */
-} RIL_Data_Call_Response_v6;
-
-typedef struct {
-    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
-    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
-                                           back-off timer value RIL wants to override the one
-                                           pre-configured in FW.
-                                           The unit is miliseconds.
-                                           The value < 0 means no value is suggested.
-                                           The value 0 means retry should be done ASAP.
-                                           The value of INT_MAX(0x7fffffff) means no retry. */
-    int             cid;        /* Context ID, uniquely identifies this call */
-    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
-    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
-                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
-                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
-                                   such as "IP" or "IPV6" */
-    char *          ifname;     /* The network interface name */
-    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix length,
-                                   e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
-                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
-                                   one of each. If the prefix length is absent the addresses
-                                   are assumed to be point to point with IPv4 having a prefix
-                                   length of 32 and IPv6 128. */
-    char *          dnses;      /* A space-delimited list of DNS server addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty. */
-    char *          gateways;   /* A space-delimited list of default gateway addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty in which case the addresses represent point
-                                   to point connections. */
-    char *          pcscf;    /* the Proxy Call State Control Function address
-                                 via PCO(Protocol Configuration Option) for IMS client. */
-} RIL_Data_Call_Response_v9;
-
-typedef struct {
-    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
-    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
-                                           back-off timer value RIL wants to override the one
-                                           pre-configured in FW.
-                                           The unit is miliseconds.
-                                           The value < 0 means no value is suggested.
-                                           The value 0 means retry should be done ASAP.
-                                           The value of INT_MAX(0x7fffffff) means no retry. */
-    int             cid;        /* Context ID, uniquely identifies this call */
-    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
-    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
-                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
-                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
-                                   such as "IP" or "IPV6" */
-    char *          ifname;     /* The network interface name */
-    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix length,
-                                   e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
-                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
-                                   one of each. If the prefix length is absent the addresses
-                                   are assumed to be point to point with IPv4 having a prefix
-                                   length of 32 and IPv6 128. */
-    char *          dnses;      /* A space-delimited list of DNS server addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty. */
-    char *          gateways;   /* A space-delimited list of default gateway addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty in which case the addresses represent point
-                                   to point connections. */
-    char *          pcscf;    /* the Proxy Call State Control Function address
-                                 via PCO(Protocol Configuration Option) for IMS client. */
-    int             mtu;        /* MTU received from network
-                                   Value <= 0 means network has either not sent a value or
-                                   sent an invalid value */
-} RIL_Data_Call_Response_v11;
-
-typedef struct {
-    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
-    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
-                                           back-off timer value RIL wants to override the one
-                                           pre-configured in FW.
-                                           The unit is milliseconds.
-                                           The value < 0 means no value is suggested.
-                                           The value 0 means retry should be done ASAP.
-                                           The value of INT_MAX(0x7fffffff) means no retry. */
-    int             cid;        /* Context ID, uniquely identifies this call */
-    int             active;     /* 0=inactive, 1=active/physical link down,
-                                   2=active/physical link up */
-    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
-                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
-                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
-                                   such as "IP" or "IPV6" */
-    char *          ifname;     /* The network interface name */
-    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix
-                                   length, e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
-                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
-                                   one of each. If the prefix length is absent the addresses
-                                   are assumed to be point to point with IPv4 having a prefix
-                                   length of 32 and IPv6 128. */
-    char *          dnses;      /* A space-delimited list of DNS server addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty. */
-    char *          gateways;   /* A space-delimited list of default gateway addresses,
-                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
-                                   May be empty in which case the addresses represent point
-                                   to point connections. */
-    char *          pcscf;      /* the Proxy Call State Control Function address
-                                   via PCO(Protocol Configuration Option) for IMS client. */
-    int             mtuV4;      /* MTU received from network for IPv4.
-                                   Value <= 0 means network has either not sent a value or
-                                   sent an invalid value. */
-    int             mtuV6;      /* MTU received from network for IPv6.
-                                   Value <= 0 means network has either not sent a value or
-                                   sent an invalid value. */
-} RIL_Data_Call_Response_v12;
-
-typedef enum {
-    RADIO_TECH_3GPP = 1, /* 3GPP Technologies - GSM, WCDMA */
-    RADIO_TECH_3GPP2 = 2 /* 3GPP2 Technologies - CDMA */
-} RIL_RadioTechnologyFamily;
-
-typedef struct {
-    RIL_RadioTechnologyFamily tech;
-    unsigned char             retry;       /* 0 == not retry, nonzero == retry */
-    int                       messageRef;  /* Valid field if retry is set to nonzero.
-                                              Contains messageRef from RIL_SMS_Response
-                                              corresponding to failed MO SMS.
-                                            */
-
-    union {
-        /* Valid field if tech is RADIO_TECH_3GPP2. See RIL_REQUEST_CDMA_SEND_SMS */
-        RIL_CDMA_SMS_Message* cdmaMessage;
-
-        /* Valid field if tech is RADIO_TECH_3GPP. See RIL_REQUEST_SEND_SMS */
-        char**                gsmMessage;   /* This is an array of pointers where pointers
-                                               are contiguous but elements pointed by those pointers
-                                               are not contiguous
-                                            */
-    } message;
-} RIL_IMS_SMS_Message;
-
-typedef struct {
-    int messageRef;   /* TP-Message-Reference for GSM,
-                         and BearerData MessageId for CDMA
-                         (See 3GPP2 C.S0015-B, v2.0, table 4.5-1). */
-    char *ackPDU;     /* or NULL if n/a */
-    int errorCode;    /* See 3GPP 27.005, 3.2.5 for GSM/UMTS,
-                         3GPP2 N.S0005 (IS-41C) Table 171 for CDMA,
-                         -1 if unknown or not applicable*/
-} RIL_SMS_Response;
-
-/** Used by RIL_REQUEST_WRITE_SMS_TO_SIM */
-typedef struct {
-    int status;     /* Status of message.  See TS 27.005 3.1, "<stat>": */
-                    /*      0 = "REC UNREAD"    */
-                    /*      1 = "REC READ"      */
-                    /*      2 = "STO UNSENT"    */
-                    /*      3 = "STO SENT"      */
-    char * pdu;     /* PDU of message to write, as an ASCII hex string less the SMSC address,
-                       the TP-layer length is "strlen(pdu)/2". */
-    char * smsc;    /* SMSC address in GSM BCD format prefixed by a length byte
-                       (as expected by TS 27.005) or NULL for default SMSC */
-} RIL_SMS_WriteArgs;
-
-/** Used by RIL_REQUEST_DIAL */
-typedef struct {
-    char * address;
-    int clir;
-            /* (same as 'n' paremeter in TS 27.007 7.7 "+CLIR"
-             * clir == 0 on "use subscription default value"
-             * clir == 1 on "CLIR invocation" (restrict CLI presentation)
-             * clir == 2 on "CLIR suppression" (allow CLI presentation)
-             */
-    RIL_UUS_Info *  uusInfo;    /* NULL or Pointer to User-User Signaling Information */
-} RIL_Dial;
-
-typedef struct {
-    int command;    /* one of the commands listed for TS 27.007 +CRSM*/
-    int fileid;     /* EF id */
-    char *path;     /* "pathid" from TS 27.007 +CRSM command.
-                       Path is in hex asciii format eg "7f205f70"
-                       Path must always be provided.
-                     */
-    int p1;
-    int p2;
-    int p3;
-    char *data;     /* May be NULL*/
-    char *pin2;     /* May be NULL*/
-} RIL_SIM_IO_v5;
-
-typedef struct {
-    int command;    /* one of the commands listed for TS 27.007 +CRSM*/
-    int fileid;     /* EF id */
-    char *path;     /* "pathid" from TS 27.007 +CRSM command.
-                       Path is in hex asciii format eg "7f205f70"
-                       Path must always be provided.
-                     */
-    int p1;
-    int p2;
-    int p3;
-    char *data;     /* May be NULL*/
-    char *pin2;     /* May be NULL*/
-    char *aidPtr;   /* AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value. */
-} RIL_SIM_IO_v6;
-
-/* Used by RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL and
- * RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC. */
-typedef struct {
-    int sessionid;  /* "sessionid" from TS 27.007 +CGLA command. Should be
-                       ignored for +CSIM command. */
-
-    /* Following fields are used to derive the APDU ("command" and "length"
-       values in TS 27.007 +CSIM and +CGLA commands). */
-    int cla;
-    int instruction;
-    int p1;
-    int p2;
-    int p3;         /* A negative P3 implies a 4 byte APDU. */
-    char *data;     /* May be NULL. In hex string format. */
-} RIL_SIM_APDU;
-
-typedef struct {
-    int sw1;
-    int sw2;
-    char *simResponse;  /* In hex string format ([a-fA-F0-9]*), except for SIM_AUTHENTICATION
-                           response for which it is in Base64 format, see 3GPP TS 31.102 7.1.2 */
-} RIL_SIM_IO_Response;
-
-/* See also com.android.internal.telephony.gsm.CallForwardInfo */
-
-typedef struct {
-    int             status;     /*
-                                 * For RIL_REQUEST_QUERY_CALL_FORWARD_STATUS
-                                 * status 1 = active, 0 = not active
-                                 *
-                                 * For RIL_REQUEST_SET_CALL_FORWARD:
-                                 * status is:
-                                 * 0 = disable
-                                 * 1 = enable
-                                 * 2 = interrogate
-                                 * 3 = registeration
-                                 * 4 = erasure
-                                 */
-
-    int             reason;      /* from TS 27.007 7.11 "reason" */
-    int             serviceClass;/* From 27.007 +CCFC/+CLCK "class"
-                                    See table for Android mapping from
-                                    MMI service code
-                                    0 means user doesn't input class */
-    int             toa;         /* "type" from TS 27.007 7.11 */
-    char *          number;      /* "number" from TS 27.007 7.11. May be NULL */
-    int             timeSeconds; /* for CF no reply only */
-}RIL_CallForwardInfo;
-
-typedef struct {
-   char * cid;         /* Combination of LAC and Cell Id in 32 bits in GSM.
-                        * Upper 16 bits is LAC and lower 16 bits
-                        * is CID (as described in TS 27.005)
-                        * Primary Scrambling Code (as described in TS 25.331)
-                        *         in 9 bits in UMTS
-                        * Valid values are hexadecimal 0x0000 - 0xffffffff.
-                        */
-   int    rssi;        /* Received RSSI in GSM,
-                        * Level index of CPICH Received Signal Code Power in UMTS
-                        */
-} RIL_NeighboringCell;
-
-typedef struct {
-  char lce_status;                 /* LCE service status:
-                                    * -1 = not supported;
-                                    * 0 = stopped;
-                                    * 1 = active.
-                                    */
-  unsigned int actual_interval_ms; /* actual LCE reporting interval,
-                                    * meaningful only if LCEStatus = 1.
-                                    */
-} RIL_LceStatusInfo;
-
-typedef struct {
-  unsigned int last_hop_capacity_kbps; /* last-hop cellular capacity: kilobits/second. */
-  unsigned char confidence_level;      /* capacity estimate confidence: 0-100 */
-  unsigned char lce_suspended;         /* LCE report going to be suspended? (e.g., radio
-                                        * moves to inactive state or network type change)
-                                        * 1 = suspended;
-                                        * 0 = not suspended.
-                                        */
-} RIL_LceDataInfo;
-
-typedef enum {
-    RIL_MATCH_ALL = 0,          /* Apply to all carriers with the same mcc/mnc */
-    RIL_MATCH_SPN = 1,          /* Use SPN and mcc/mnc to identify the carrier */
-    RIL_MATCH_IMSI_PREFIX = 2,  /* Use IMSI prefix and mcc/mnc to identify the carrier */
-    RIL_MATCH_GID1 = 3,         /* Use GID1 and mcc/mnc to identify the carrier */
-    RIL_MATCH_GID2 = 4,         /* Use GID2 and mcc/mnc to identify the carrier */
-} RIL_CarrierMatchType;
-
-typedef struct {
-    const char * mcc;
-    const char * mnc;
-    RIL_CarrierMatchType match_type;   /* Specify match type for the carrier.
-                                        * If it’s RIL_MATCH_ALL, match_data is null;
-                                        * otherwise, match_data is the value for the match type.
-                                        */
-    const char * match_data;
-} RIL_Carrier;
-
-typedef struct {
-  int32_t len_allowed_carriers;         /* length of array allowed_carriers */
-  int32_t len_excluded_carriers;        /* length of array excluded_carriers */
-  RIL_Carrier * allowed_carriers;       /* whitelist for allowed carriers */
-  RIL_Carrier * excluded_carriers;      /* blacklist for explicitly excluded carriers
-                                         * which match allowed_carriers. Eg. allowed_carriers match
-                                         * mcc/mnc, excluded_carriers has same mcc/mnc and gid1
-                                         * is ABCD. It means except the carrier whose gid1 is ABCD,
-                                         * all carriers with the same mcc/mnc are allowed.
-                                         */
-} RIL_CarrierRestrictions;
-
-typedef enum {
-    NO_MULTISIM_POLICY = 0,             /* configuration applies to each slot independently. */
-    ONE_VALID_SIM_MUST_BE_PRESENT = 1,  /* Any SIM card can be used as far as one valid card is
-                                         * present in the device.
-                                         */
-} RIL_SimLockMultiSimPolicy;
-
-typedef struct {
-  int32_t len_allowed_carriers;         /* length of array allowed_carriers */
-  int32_t len_excluded_carriers;        /* length of array excluded_carriers */
-  RIL_Carrier * allowed_carriers;       /* whitelist for allowed carriers */
-  RIL_Carrier * excluded_carriers;      /* blacklist for explicitly excluded carriers
-                                         * which match allowed_carriers. Eg. allowed_carriers match
-                                         * mcc/mnc, excluded_carriers has same mcc/mnc and gid1
-                                         * is ABCD. It means except the carrier whose gid1 is ABCD,
-                                         * all carriers with the same mcc/mnc are allowed.
-                                         */
-  int allowedCarriersPrioritized;       /* allowed list prioritized */
-  RIL_SimLockMultiSimPolicy multiSimPolicy; /* multisim policy */
-} RIL_CarrierRestrictionsWithPriority;
-
-typedef struct {
-  char * mcc;                         /* MCC of the Carrier. */
-  char * mnc ;                        /* MNC of the Carrier. */
-  uint8_t * carrierKey;               /* Public Key from the Carrier used to encrypt the
-                                       * IMSI/IMPI.
-                                       */
-  int32_t carrierKeyLength;            /* Length of the Public Key. */
-  char * keyIdentifier;               /* The keyIdentifier Attribute value pair that helps
-                                       * a server locate the private key to decrypt the
-                                       * permanent identity.
-                                       */
-  int64_t expirationTime;             /* Date-Time (in UTC) when the key will expire. */
-
-} RIL_CarrierInfoForImsiEncryption;
-
-/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
-typedef enum {
-    CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
-    CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
-    CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
-    CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
-    CALL_FAIL_NORMAL = 16,
-    CALL_FAIL_BUSY = 17,
-    CALL_FAIL_NO_USER_RESPONDING = 18,
-    CALL_FAIL_NO_ANSWER_FROM_USER = 19,
-    CALL_FAIL_CALL_REJECTED = 21,
-    CALL_FAIL_NUMBER_CHANGED = 22,
-    CALL_FAIL_PREEMPTION = 25,
-    CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
-    CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
-    CALL_FAIL_FACILITY_REJECTED = 29,
-    CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
-    CALL_FAIL_NORMAL_UNSPECIFIED = 31,
-    CALL_FAIL_CONGESTION = 34,
-    CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
-    CALL_FAIL_TEMPORARY_FAILURE = 41,
-    CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
-    CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
-    CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
-    CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
-    CALL_FAIL_QOS_UNAVAILABLE = 49,
-    CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
-    CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
-    CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
-    CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
-    CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
-    CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
-    CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
-    CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
-    CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
-    CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
-    CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
-    CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
-    CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
-    CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
-    CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
-    CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
-    CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
-    CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
-    CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
-    CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
-    CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
-    CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
-    CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
-    CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
-    CALL_FAIL_CALL_BARRED = 240,
-    CALL_FAIL_FDN_BLOCKED = 241,
-    CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
-    CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
-    CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244, /* STK Call Control */
-    CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
-    CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
-    CALL_FAIL_RADIO_OFF = 247, /* Radio is OFF */
-    CALL_FAIL_OUT_OF_SERVICE = 248, /* No cellular coverage */
-    CALL_FAIL_NO_VALID_SIM = 249, /* No valid SIM is present */
-    CALL_FAIL_RADIO_INTERNAL_ERROR = 250, /* Internal error at Modem */
-    CALL_FAIL_NETWORK_RESP_TIMEOUT = 251, /* No response from network */
-    CALL_FAIL_NETWORK_REJECT = 252, /* Explicit network reject */
-    CALL_FAIL_RADIO_ACCESS_FAILURE = 253, /* RRC connection failure. Eg.RACH */
-    CALL_FAIL_RADIO_LINK_FAILURE = 254, /* Radio Link Failure */
-    CALL_FAIL_RADIO_LINK_LOST = 255, /* Radio link lost due to poor coverage */
-    CALL_FAIL_RADIO_UPLINK_FAILURE = 256, /* Radio uplink failure */
-    CALL_FAIL_RADIO_SETUP_FAILURE = 257, /* RRC connection setup failure */
-    CALL_FAIL_RADIO_RELEASE_NORMAL = 258, /* RRC connection release, normal */
-    CALL_FAIL_RADIO_RELEASE_ABNORMAL = 259, /* RRC connection release, abnormal */
-    CALL_FAIL_ACCESS_CLASS_BLOCKED = 260, /* Access class barring */
-    CALL_FAIL_NETWORK_DETACH = 261, /* Explicit network detach */
-    CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000,
-    CALL_FAIL_CDMA_DROP = 1001,
-    CALL_FAIL_CDMA_INTERCEPT = 1002,
-    CALL_FAIL_CDMA_REORDER = 1003,
-    CALL_FAIL_CDMA_SO_REJECT = 1004,
-    CALL_FAIL_CDMA_RETRY_ORDER = 1005,
-    CALL_FAIL_CDMA_ACCESS_FAILURE = 1006,
-    CALL_FAIL_CDMA_PREEMPTED = 1007,
-    CALL_FAIL_CDMA_NOT_EMERGENCY = 1008, /* For non-emergency number dialed
-                                            during emergency callback mode */
-    CALL_FAIL_CDMA_ACCESS_BLOCKED = 1009, /* CDMA network access probes blocked */
-
-    /* OEM specific error codes. Used to distinguish error from
-     * CALL_FAIL_ERROR_UNSPECIFIED and help assist debugging */
-    CALL_FAIL_OEM_CAUSE_1 = 0xf001,
-    CALL_FAIL_OEM_CAUSE_2 = 0xf002,
-    CALL_FAIL_OEM_CAUSE_3 = 0xf003,
-    CALL_FAIL_OEM_CAUSE_4 = 0xf004,
-    CALL_FAIL_OEM_CAUSE_5 = 0xf005,
-    CALL_FAIL_OEM_CAUSE_6 = 0xf006,
-    CALL_FAIL_OEM_CAUSE_7 = 0xf007,
-    CALL_FAIL_OEM_CAUSE_8 = 0xf008,
-    CALL_FAIL_OEM_CAUSE_9 = 0xf009,
-    CALL_FAIL_OEM_CAUSE_10 = 0xf00a,
-    CALL_FAIL_OEM_CAUSE_11 = 0xf00b,
-    CALL_FAIL_OEM_CAUSE_12 = 0xf00c,
-    CALL_FAIL_OEM_CAUSE_13 = 0xf00d,
-    CALL_FAIL_OEM_CAUSE_14 = 0xf00e,
-    CALL_FAIL_OEM_CAUSE_15 = 0xf00f,
-
-    CALL_FAIL_ERROR_UNSPECIFIED = 0xffff /* This error will be deprecated soon,
-                                            vendor code should make sure to map error
-                                            code to specific error */
-} RIL_LastCallFailCause;
-
-typedef struct {
-  RIL_LastCallFailCause cause_code;
-  char *                vendor_cause;
-} RIL_LastCallFailCauseInfo;
-
-/* See RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE */
-typedef enum {
-    PDP_FAIL_NONE = 0, /* No error, connection ok */
-
-    /* an integer cause code defined in TS 24.008
-       section 6.1.3.1.3 or TS 24.301 Release 8+ Annex B.
-       If the implementation does not have access to the exact cause codes,
-       then it should return one of the following values,
-       as the UI layer needs to distinguish these
-       cases for error notification and potential retries. */
-    PDP_FAIL_OPERATOR_BARRED = 0x08,               /* no retry */
-    PDP_FAIL_NAS_SIGNALLING = 0x0E,
-    PDP_FAIL_LLC_SNDCP = 0x19,
-    PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
-    PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,            /* no retry */
-    PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,      /* no retry */
-    PDP_FAIL_USER_AUTHENTICATION = 0x1D,           /* no retry */
-    PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,        /* no retry */
-    PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
-    PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,  /* no retry */
-    PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21, /* no retry */
-    PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
-    PDP_FAIL_NSAPI_IN_USE = 0x23,                  /* no retry */
-    PDP_FAIL_REGULAR_DEACTIVATION = 0x24,          /* possibly restart radio,
-                                                      based on framework config */
-    PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
-    PDP_FAIL_NETWORK_FAILURE = 0x26,
-    PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
-    PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
-    PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
-    PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
-    PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
-    PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
-    PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
-    PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
-    PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,             /* no retry */
-    PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,             /* no retry */
-    PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
-    PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
-    PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
-    PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
-    PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
-    PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
-    PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
-    PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
-    PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
-    PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
-    PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
-    PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
-    PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
-    PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
-    PDP_FAIL_PROTOCOL_ERRORS = 0x6F,             /* no retry */
-    PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
-    PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
-    PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
-    PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
-    PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
-    PDP_FAIL_IFACE_MISMATCH = 0x75,
-    PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
-    PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
-    PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
-    PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
-    PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
-
-    // OEM specific error codes. To be used by OEMs when they don't want to
-    // reveal error code which would be replaced by PDP_FAIL_ERROR_UNSPECIFIED
-    PDP_FAIL_OEM_DCFAILCAUSE_1 = 0x1001,
-    PDP_FAIL_OEM_DCFAILCAUSE_2 = 0x1002,
-    PDP_FAIL_OEM_DCFAILCAUSE_3 = 0x1003,
-    PDP_FAIL_OEM_DCFAILCAUSE_4 = 0x1004,
-    PDP_FAIL_OEM_DCFAILCAUSE_5 = 0x1005,
-    PDP_FAIL_OEM_DCFAILCAUSE_6 = 0x1006,
-    PDP_FAIL_OEM_DCFAILCAUSE_7 = 0x1007,
-    PDP_FAIL_OEM_DCFAILCAUSE_8 = 0x1008,
-    PDP_FAIL_OEM_DCFAILCAUSE_9 = 0x1009,
-    PDP_FAIL_OEM_DCFAILCAUSE_10 = 0x100A,
-    PDP_FAIL_OEM_DCFAILCAUSE_11 = 0x100B,
-    PDP_FAIL_OEM_DCFAILCAUSE_12 = 0x100C,
-    PDP_FAIL_OEM_DCFAILCAUSE_13 = 0x100D,
-    PDP_FAIL_OEM_DCFAILCAUSE_14 = 0x100E,
-    PDP_FAIL_OEM_DCFAILCAUSE_15 = 0x100F,
-
-    /* Not mentioned in the specification */
-    PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
-    PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
-
-   /* reasons for data call drop - network/modem disconnect */
-    PDP_FAIL_SIGNAL_LOST = -3,
-    PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,/* preferred technology has changed, should retry
-                                             with parameters appropriate for new technology */
-    PDP_FAIL_RADIO_POWER_OFF = -5,        /* data call was disconnected because radio was resetting,
-                                             powered off - no retry */
-    PDP_FAIL_TETHERED_CALL_ACTIVE = -6,   /* data call was disconnected by modem because tethered
-                                             mode was up on same APN/data profile - no retry until
-                                             tethered call is off */
-
-    PDP_FAIL_ERROR_UNSPECIFIED = 0xffff,  /* retry silently. Will be deprecated soon as
-                                             new error codes are added making this unnecessary */
-} RIL_DataCallFailCause;
-
-/* See RIL_REQUEST_SETUP_DATA_CALL */
-typedef enum {
-    RIL_DATA_PROFILE_DEFAULT    = 0,
-    RIL_DATA_PROFILE_TETHERED   = 1,
-    RIL_DATA_PROFILE_IMS        = 2,
-    RIL_DATA_PROFILE_FOTA       = 3,
-    RIL_DATA_PROFILE_CBS        = 4,
-    RIL_DATA_PROFILE_OEM_BASE   = 1000,    /* Start of OEM-specific profiles */
-    RIL_DATA_PROFILE_INVALID    = 0xFFFFFFFF
-} RIL_DataProfile;
-
-/* Used by RIL_UNSOL_SUPP_SVC_NOTIFICATION */
-typedef struct {
-    int     notificationType;   /*
-                                 * 0 = MO intermediate result code
-                                 * 1 = MT unsolicited result code
-                                 */
-    int     code;               /* See 27.007 7.17
-                                   "code1" for MO
-                                   "code2" for MT. */
-    int     index;              /* CUG index. See 27.007 7.17. */
-    int     type;               /* "type" from 27.007 7.17 (MT only). */
-    char *  number;             /* "number" from 27.007 7.17
-                                   (MT only, may be NULL). */
-} RIL_SuppSvcNotification;
-
-#define RIL_CARD_MAX_APPS     8
-
-typedef enum {
-    RIL_CARDSTATE_ABSENT     = 0,
-    RIL_CARDSTATE_PRESENT    = 1,
-    RIL_CARDSTATE_ERROR      = 2,
-    RIL_CARDSTATE_RESTRICTED = 3  /* card is present but not usable due to carrier restrictions.*/
-} RIL_CardState;
-
-typedef enum {
-    RIL_PERSOSUBSTATE_UNKNOWN                   = 0, /* initial state */
-    RIL_PERSOSUBSTATE_IN_PROGRESS               = 1, /* in between each lock transition */
-    RIL_PERSOSUBSTATE_READY                     = 2, /* when either SIM or RUIM Perso is finished
-                                                        since each app can only have 1 active perso
-                                                        involved */
-    RIL_PERSOSUBSTATE_SIM_NETWORK               = 3,
-    RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET        = 4,
-    RIL_PERSOSUBSTATE_SIM_CORPORATE             = 5,
-    RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER      = 6,
-    RIL_PERSOSUBSTATE_SIM_SIM                   = 7,
-    RIL_PERSOSUBSTATE_SIM_NETWORK_PUK           = 8, /* The corresponding perso lock is blocked */
-    RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK    = 9,
-    RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK         = 10,
-    RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK  = 11,
-    RIL_PERSOSUBSTATE_SIM_SIM_PUK               = 12,
-    RIL_PERSOSUBSTATE_RUIM_NETWORK1             = 13,
-    RIL_PERSOSUBSTATE_RUIM_NETWORK2             = 14,
-    RIL_PERSOSUBSTATE_RUIM_HRPD                 = 15,
-    RIL_PERSOSUBSTATE_RUIM_CORPORATE            = 16,
-    RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER     = 17,
-    RIL_PERSOSUBSTATE_RUIM_RUIM                 = 18,
-    RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK         = 19, /* The corresponding perso lock is blocked */
-    RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK         = 20,
-    RIL_PERSOSUBSTATE_RUIM_HRPD_PUK             = 21,
-    RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK        = 22,
-    RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
-    RIL_PERSOSUBSTATE_RUIM_RUIM_PUK             = 24
-} RIL_PersoSubstate;
-
-typedef enum {
-    RIL_APPSTATE_UNKNOWN               = 0,
-    RIL_APPSTATE_DETECTED              = 1,
-    RIL_APPSTATE_PIN                   = 2, /* If PIN1 or UPin is required */
-    RIL_APPSTATE_PUK                   = 3, /* If PUK1 or Puk for UPin is required */
-    RIL_APPSTATE_SUBSCRIPTION_PERSO    = 4, /* perso_substate should be look at
-                                               when app_state is assigned to this value */
-    RIL_APPSTATE_READY                 = 5
-} RIL_AppState;
-
-typedef enum {
-    RIL_PINSTATE_UNKNOWN              = 0,
-    RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
-    RIL_PINSTATE_ENABLED_VERIFIED     = 2,
-    RIL_PINSTATE_DISABLED             = 3,
-    RIL_PINSTATE_ENABLED_BLOCKED      = 4,
-    RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
-} RIL_PinState;
-
-typedef enum {
-  RIL_APPTYPE_UNKNOWN = 0,
-  RIL_APPTYPE_SIM     = 1,
-  RIL_APPTYPE_USIM    = 2,
-  RIL_APPTYPE_RUIM    = 3,
-  RIL_APPTYPE_CSIM    = 4,
-  RIL_APPTYPE_ISIM    = 5
-} RIL_AppType;
-
-/*
- * Please note that registration state UNKNOWN is
- * treated as "out of service" in the Android telephony.
- * Registration state REG_DENIED must be returned if Location Update
- * Reject (with cause 17 - Network Failure) is received
- * repeatedly from the network, to facilitate
- * "managed roaming"
- */
-typedef enum {
-    RIL_NOT_REG_AND_NOT_SEARCHING = 0,           // Not registered, MT is not currently searching
-                                                 // a new operator to register
-    RIL_REG_HOME = 1,                            // Registered, home network
-    RIL_NOT_REG_AND_SEARCHING = 2,               // Not registered, but MT is currently searching
-                                                 // a new operator to register
-    RIL_REG_DENIED = 3,                          // Registration denied
-    RIL_UNKNOWN = 4,                             // Unknown
-    RIL_REG_ROAMING = 5,                         // Registered, roaming
-    RIL_NOT_REG_AND_EMERGENCY_AVAILABLE_AND_NOT_SEARCHING = 10,   // Same as
-                                                 // RIL_NOT_REG_AND_NOT_SEARCHING but indicates that
-                                                 // emergency calls are enabled.
-    RIL_NOT_REG_AND_EMERGENCY_AVAILABLE_AND_SEARCHING = 12,  // Same as RIL_NOT_REG_AND_SEARCHING
-                                                 // but indicates that
-                                                 // emergency calls are enabled.
-    RIL_REG_DENIED_AND_EMERGENCY_AVAILABLE = 13, // Same as REG_DENIED but indicates that
-                                                 // emergency calls are enabled.
-    RIL_UNKNOWN_AND_EMERGENCY_AVAILABLE = 14,    // Same as UNKNOWN but indicates that
-                                                 // emergency calls are enabled.
-} RIL_RegState;
-
-typedef struct
-{
-  RIL_AppType      app_type;
-  RIL_AppState     app_state;
-  RIL_PersoSubstate perso_substate; /* applicable only if app_state ==
-                                       RIL_APPSTATE_SUBSCRIPTION_PERSO */
-  char             *aid_ptr;        /* null terminated string, e.g., from 0xA0, 0x00 -> 0x41,
-                                       0x30, 0x30, 0x30 */
-  char             *app_label_ptr;  /* null terminated string */
-  int              pin1_replaced;   /* applicable to USIM, CSIM & ISIM */
-  RIL_PinState     pin1;
-  RIL_PinState     pin2;
-} RIL_AppStatus;
-
-/* Deprecated, use RIL_CardStatus_v6 */
-typedef struct
-{
-  RIL_CardState card_state;
-  RIL_PinState  universal_pin_state;             /* applicable to USIM and CSIM: RIL_PINSTATE_xxx */
-  int           gsm_umts_subscription_app_index; /* value < RIL_CARD_MAX_APPS, -1 if none */
-  int           cdma_subscription_app_index;     /* value < RIL_CARD_MAX_APPS, -1 if none */
-  int           num_applications;                /* value <= RIL_CARD_MAX_APPS */
-  RIL_AppStatus applications[RIL_CARD_MAX_APPS];
-} RIL_CardStatus_v5;
-
-typedef struct
-{
-  RIL_CardState card_state;
-  RIL_PinState  universal_pin_state;             /* applicable to USIM and CSIM: RIL_PINSTATE_xxx */
-  int           gsm_umts_subscription_app_index; /* value < RIL_CARD_MAX_APPS, -1 if none */
-  int           cdma_subscription_app_index;     /* value < RIL_CARD_MAX_APPS, -1 if none */
-  int           ims_subscription_app_index;      /* value < RIL_CARD_MAX_APPS, -1 if none */
-  int           num_applications;                /* value <= RIL_CARD_MAX_APPS */
-  RIL_AppStatus applications[RIL_CARD_MAX_APPS];
-} RIL_CardStatus_v6;
-
-/** The result of a SIM refresh, returned in data[0] of RIL_UNSOL_SIM_REFRESH
- *      or as part of RIL_SimRefreshResponse_v7
- */
-typedef enum {
-    /* A file on SIM has been updated.  data[1] contains the EFID. */
-    SIM_FILE_UPDATE = 0,
-    /* SIM initialized.  All files should be re-read. */
-    SIM_INIT = 1,
-    /* SIM reset.  SIM power required, SIM may be locked and all files should be re-read. */
-    SIM_RESET = 2
-} RIL_SimRefreshResult;
-
-typedef struct {
-    RIL_SimRefreshResult result;
-    int                  ef_id; /* is the EFID of the updated file if the result is */
-                                /* SIM_FILE_UPDATE or 0 for any other result. */
-    char *               aid;   /* is AID(application ID) of the card application */
-                                /* See ETSI 102.221 8.1 and 101.220 4 */
-                                /*     For SIM_FILE_UPDATE result it can be set to AID of */
-                                /*         application in which updated EF resides or it can be */
-                                /*         NULL if EF is outside of an application. */
-                                /*     For SIM_INIT result this field is set to AID of */
-                                /*         application that caused REFRESH */
-                                /*     For SIM_RESET result it is NULL. */
-} RIL_SimRefreshResponse_v7;
-
-/* Deprecated, use RIL_CDMA_CallWaiting_v6 */
-typedef struct {
-    char *          number;             /* Remote party number */
-    int             numberPresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown */
-    char *          name;               /* Remote party name */
-    RIL_CDMA_SignalInfoRecord signalInfoRecord;
-} RIL_CDMA_CallWaiting_v5;
-
-typedef struct {
-    char *          number;             /* Remote party number */
-    int             numberPresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown */
-    char *          name;               /* Remote party name */
-    RIL_CDMA_SignalInfoRecord signalInfoRecord;
-    /* Number type/Number plan required to support International Call Waiting */
-    int             number_type;        /* 0=Unknown, 1=International, 2=National,
-                                           3=Network specific, 4=subscriber */
-    int             number_plan;        /* 0=Unknown, 1=ISDN, 3=Data, 4=Telex, 8=Nat'l, 9=Private */
-} RIL_CDMA_CallWaiting_v6;
-
-/**
- * Which types of Cell Broadcast Message (CBM) are to be received by the ME
- *
- * uFromServiceID - uToServiceID defines a range of CBM message identifiers
- * whose value is 0x0000 - 0xFFFF as defined in TS 23.041 9.4.1.2.2 for GMS
- * and 9.4.4.2.2 for UMTS. All other values can be treated as empty
- * CBM message ID.
- *
- * uFromCodeScheme - uToCodeScheme defines a range of CBM data coding schemes
- * whose value is 0x00 - 0xFF as defined in TS 23.041 9.4.1.2.3 for GMS
- * and 9.4.4.2.3 for UMTS.
- * All other values can be treated as empty CBM data coding scheme.
- *
- * selected 0 means message types specified in <fromServiceId, toServiceId>
- * and <fromCodeScheme, toCodeScheme>are not accepted, while 1 means accepted.
- *
- * Used by RIL_REQUEST_GSM_GET_BROADCAST_CONFIG and
- * RIL_REQUEST_GSM_SET_BROADCAST_CONFIG.
- */
-typedef struct {
-    int fromServiceId;
-    int toServiceId;
-    int fromCodeScheme;
-    int toCodeScheme;
-    unsigned char selected;
-} RIL_GSM_BroadcastSmsConfigInfo;
-
-/* No restriction at all including voice/SMS/USSD/SS/AV64 and packet data. */
-#define RIL_RESTRICTED_STATE_NONE           0x00
-/* Block emergency call due to restriction. But allow all normal voice/SMS/USSD/SS/AV64. */
-#define RIL_RESTRICTED_STATE_CS_EMERGENCY   0x01
-/* Block all normal voice/SMS/USSD/SS/AV64 due to restriction. Only Emergency call allowed. */
-#define RIL_RESTRICTED_STATE_CS_NORMAL      0x02
-/* Block all voice/SMS/USSD/SS/AV64 including emergency call due to restriction.*/
-#define RIL_RESTRICTED_STATE_CS_ALL         0x04
-/* Block packet data access due to restriction. */
-#define RIL_RESTRICTED_STATE_PS_ALL         0x10
-
-/* The status for an OTASP/OTAPA session */
-typedef enum {
-    CDMA_OTA_PROVISION_STATUS_SPL_UNLOCKED,
-    CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED,
-    CDMA_OTA_PROVISION_STATUS_A_KEY_EXCHANGED,
-    CDMA_OTA_PROVISION_STATUS_SSD_UPDATED,
-    CDMA_OTA_PROVISION_STATUS_NAM_DOWNLOADED,
-    CDMA_OTA_PROVISION_STATUS_MDN_DOWNLOADED,
-    CDMA_OTA_PROVISION_STATUS_IMSI_DOWNLOADED,
-    CDMA_OTA_PROVISION_STATUS_PRL_DOWNLOADED,
-    CDMA_OTA_PROVISION_STATUS_COMMITTED,
-    CDMA_OTA_PROVISION_STATUS_OTAPA_STARTED,
-    CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED,
-    CDMA_OTA_PROVISION_STATUS_OTAPA_ABORTED
-} RIL_CDMA_OTA_ProvisionStatus;
-
-typedef struct {
-    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
-    int bitErrorRate;    /* bit error rate (0-7, 99) as defined in TS 27.007 8.5 */
-} RIL_GW_SignalStrength;
-
-typedef struct {
-    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
-    int bitErrorRate;    /* bit error rate (0-7, 99) as defined in TS 27.007 8.5 */
-    int timingAdvance;   /* Timing Advance in bit periods. 1 bit period = 48/13 us.
-                          * INT_MAX denotes invalid value */
-} RIL_GSM_SignalStrength_v12;
-
-typedef struct {
-    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
-    int bitErrorRate;    /* bit error rate (0-7, 99) as defined in TS 27.007 8.5 */
-} RIL_SignalStrengthWcdma;
-
-typedef struct {
-    int dbm;  /* Valid values are positive integers.  This value is the actual RSSI value
-               * multiplied by -1.  Example: If the actual RSSI is -75, then this response
-               * value will be 75.
-               */
-    int ecio; /* Valid values are positive integers.  This value is the actual Ec/Io multiplied
-               * by -10.  Example: If the actual Ec/Io is -12.5 dB, then this response value
-               * will be 125.
-               */
-} RIL_CDMA_SignalStrength;
-
-
-typedef struct {
-    int dbm;  /* Valid values are positive integers.  This value is the actual RSSI value
-               * multiplied by -1.  Example: If the actual RSSI is -75, then this response
-               * value will be 75.
-               */
-    int ecio; /* Valid values are positive integers.  This value is the actual Ec/Io multiplied
-               * by -10.  Example: If the actual Ec/Io is -12.5 dB, then this response value
-               * will be 125.
-               */
-    int signalNoiseRatio; /* Valid values are 0-8.  8 is the highest signal to noise ratio. */
-} RIL_EVDO_SignalStrength;
-
-typedef struct {
-    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
-    int rsrp;            /* The current Reference Signal Receive Power in dBm multipled by -1.
-                          * Range: 44 to 140 dBm
-                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.133 9.1.4 */
-    int rsrq;            /* The current Reference Signal Receive Quality in dB multiplied by -1.
-                          * Range: 20 to 3 dB.
-                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.133 9.1.7 */
-    int rssnr;           /* The current reference signal signal-to-noise ratio in 0.1 dB units.
-                          * Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
-                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.101 8.1.1 */
-    int cqi;             /* The current Channel Quality Indicator.
-                          * Range: 0 to 15.
-                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.101 9.2, 9.3, A.4 */
-} RIL_LTE_SignalStrength;
-
-typedef struct {
-    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
-    int rsrp;            /* The current Reference Signal Receive Power in dBm multipled by -1.
-                          * Range: 44 to 140 dBm
-                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.133 9.1.4 */
-    int rsrq;            /* The current Reference Signal Receive Quality in dB multiplied by -1.
-                          * Range: 20 to 3 dB.
-                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.133 9.1.7 */
-    int rssnr;           /* The current reference signal signal-to-noise ratio in 0.1 dB units.
-                          * Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
-                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.101 8.1.1 */
-    int cqi;             /* The current Channel Quality Indicator.
-                          * Range: 0 to 15.
-                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP TS 36.101 9.2, 9.3, A.4 */
-    int timingAdvance;   /* timing advance in micro seconds for a one way trip from cell to device.
-                          * Approximate distance can be calculated using 300m/us * timingAdvance.
-                          * Range: 0 to 0x7FFFFFFE
-                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
-                          * Reference: 3GPP 36.321 section 6.1.3.5
-                          * also: http://www.cellular-planningoptimization.com/2010/02/timing-advance-with-calculation.html */
-} RIL_LTE_SignalStrength_v8;
-
-typedef struct {
-    int rscp;    /* The Received Signal Code Power in dBm multipled by -1.
-                  * Range : 25 to 120
-                  * INT_MAX: 0x7FFFFFFF denotes invalid value.
-                  * Reference: 3GPP TS 25.123, section 9.1.1.1 */
-} RIL_TD_SCDMA_SignalStrength;
-
-/* Deprecated, use RIL_SignalStrength_v6 */
-typedef struct {
-    RIL_GW_SignalStrength   GW_SignalStrength;
-    RIL_CDMA_SignalStrength CDMA_SignalStrength;
-    RIL_EVDO_SignalStrength EVDO_SignalStrength;
-} RIL_SignalStrength_v5;
-
-typedef struct {
-    RIL_GW_SignalStrength   GW_SignalStrength;
-    RIL_CDMA_SignalStrength CDMA_SignalStrength;
-    RIL_EVDO_SignalStrength EVDO_SignalStrength;
-    RIL_LTE_SignalStrength  LTE_SignalStrength;
-} RIL_SignalStrength_v6;
-
-typedef struct {
-    RIL_GW_SignalStrength       GW_SignalStrength;
-    RIL_CDMA_SignalStrength     CDMA_SignalStrength;
-    RIL_EVDO_SignalStrength     EVDO_SignalStrength;
-    RIL_LTE_SignalStrength_v8   LTE_SignalStrength;
-} RIL_SignalStrength_v8;
-
-typedef struct {
-    RIL_GW_SignalStrength       GW_SignalStrength;
-    RIL_CDMA_SignalStrength     CDMA_SignalStrength;
-    RIL_EVDO_SignalStrength     EVDO_SignalStrength;
-    RIL_LTE_SignalStrength_v8   LTE_SignalStrength;
-    RIL_TD_SCDMA_SignalStrength TD_SCDMA_SignalStrength;
-} RIL_SignalStrength_v10;
-
-typedef struct {
-    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown */
-    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
-                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
-                   INT_MAX if unknown */
-    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
-    int cid;    /* 16-bit GSM Cell Identity described in TS 27.007, 0..65535, INT_MAX if unknown  */
-} RIL_CellIdentityGsm;
-
-typedef struct {
-    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown */
-    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
-                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
-                   INT_MAX if unknown */
-    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
-    int cid;    /* 16-bit GSM Cell Identity described in TS 27.007, 0..65535, INT_MAX if unknown  */
-    int arfcn;  /* 16-bit GSM Absolute RF channel number; this value must be reported */
-    uint8_t bsic; /* 6-bit Base Station Identity Code; 0xFF if unknown */
-} RIL_CellIdentityGsm_v12;
-
-typedef struct {
-    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
-    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
-                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
-                   INT_MAX if unknown */
-    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
-    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
-    int psc;    /* 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511, INT_MAX if unknown */
-} RIL_CellIdentityWcdma;
-
-typedef struct {
-    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
-    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
-                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
-                   INT_MAX if unknown */
-    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
-    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
-    int psc;    /* 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511; this value must be reported */
-    int uarfcn; /* 16-bit UMTS Absolute RF Channel Number; this value must be reported */
-} RIL_CellIdentityWcdma_v12;
-
-typedef struct {
-    int networkId;      /* Network Id 0..65535, INT_MAX if unknown */
-    int systemId;       /* CDMA System Id 0..32767, INT_MAX if unknown  */
-    int basestationId;  /* Base Station Id 0..65535, INT_MAX if unknown  */
-    int longitude;      /* Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
-                         * It is represented in units of 0.25 seconds and ranges from -2592000
-                         * to 2592000, both values inclusive (corresponding to a range of -180
-                         * to +180 degrees). INT_MAX if unknown */
-
-    int latitude;       /* Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
-                         * It is represented in units of 0.25 seconds and ranges from -1296000
-                         * to 1296000, both values inclusive (corresponding to a range of -90
-                         * to +90 degrees). INT_MAX if unknown */
-} RIL_CellIdentityCdma;
-
-typedef struct {
-    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
-    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
-                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
-                   INT_MAX if unknown */
-    int ci;     /* 28-bit Cell Identity described in TS ???, INT_MAX if unknown */
-    int pci;    /* physical cell id 0..503, INT_MAX if unknown  */
-    int tac;    /* 16-bit tracking area code, INT_MAX if unknown  */
-} RIL_CellIdentityLte;
-
-typedef struct {
-    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
-    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
-                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
-                   INT_MAX if unknown */
-    int ci;     /* 28-bit Cell Identity described in TS ???, INT_MAX if unknown */
-    int pci;    /* physical cell id 0..503; this value must be reported */
-    int tac;    /* 16-bit tracking area code, INT_MAX if unknown  */
-    int earfcn; /* 18-bit LTE Absolute RF Channel Number; this value must be reported */
-} RIL_CellIdentityLte_v12;
-
-typedef struct {
-    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
-    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
-                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
-                   INT_MAX if unknown */
-    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
-    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
-    int cpid;    /* 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown */
-} RIL_CellIdentityTdscdma;
-
-typedef struct {
-  RIL_CellIdentityGsm   cellIdentityGsm;
-  RIL_GW_SignalStrength signalStrengthGsm;
-} RIL_CellInfoGsm;
-
-typedef struct {
-  RIL_CellIdentityGsm_v12   cellIdentityGsm;
-  RIL_GSM_SignalStrength_v12 signalStrengthGsm;
-} RIL_CellInfoGsm_v12;
-
-typedef struct {
-  RIL_CellIdentityWcdma cellIdentityWcdma;
-  RIL_SignalStrengthWcdma signalStrengthWcdma;
-} RIL_CellInfoWcdma;
-
-typedef struct {
-  RIL_CellIdentityWcdma_v12 cellIdentityWcdma;
-  RIL_SignalStrengthWcdma signalStrengthWcdma;
-} RIL_CellInfoWcdma_v12;
-
-typedef struct {
-  RIL_CellIdentityCdma      cellIdentityCdma;
-  RIL_CDMA_SignalStrength   signalStrengthCdma;
-  RIL_EVDO_SignalStrength   signalStrengthEvdo;
-} RIL_CellInfoCdma;
-
-typedef struct {
-  RIL_CellIdentityLte        cellIdentityLte;
-  RIL_LTE_SignalStrength_v8  signalStrengthLte;
-} RIL_CellInfoLte;
-
-typedef struct {
-  RIL_CellIdentityLte_v12    cellIdentityLte;
-  RIL_LTE_SignalStrength_v8  signalStrengthLte;
-} RIL_CellInfoLte_v12;
-
-typedef struct {
-  RIL_CellIdentityTdscdma cellIdentityTdscdma;
-  RIL_TD_SCDMA_SignalStrength signalStrengthTdscdma;
-} RIL_CellInfoTdscdma;
-
-// Must be the same as CellInfo.TYPE_XXX
-typedef enum {
-  RIL_CELL_INFO_TYPE_NONE   = 0, /* indicates no cell information */
-  RIL_CELL_INFO_TYPE_GSM    = 1,
-  RIL_CELL_INFO_TYPE_CDMA   = 2,
-  RIL_CELL_INFO_TYPE_LTE    = 3,
-  RIL_CELL_INFO_TYPE_WCDMA  = 4,
-  RIL_CELL_INFO_TYPE_TD_SCDMA  = 5
-} RIL_CellInfoType;
-
-// Must be the same as CellInfo.TIMESTAMP_TYPE_XXX
-typedef enum {
-    RIL_TIMESTAMP_TYPE_UNKNOWN = 0,
-    RIL_TIMESTAMP_TYPE_ANTENNA = 1,
-    RIL_TIMESTAMP_TYPE_MODEM = 2,
-    RIL_TIMESTAMP_TYPE_OEM_RIL = 3,
-    RIL_TIMESTAMP_TYPE_JAVA_RIL = 4,
-} RIL_TimeStampType;
-
-typedef struct {
-  RIL_CellInfoType  cellInfoType;   /* cell type for selecting from union CellInfo */
-  int               registered;     /* !0 if this cell is registered 0 if not registered */
-  RIL_TimeStampType timeStampType;  /* type of time stamp represented by timeStamp */
-  uint64_t          timeStamp;      /* Time in nanos as returned by ril_nano_time */
-  union {
-    RIL_CellInfoGsm     gsm;
-    RIL_CellInfoCdma    cdma;
-    RIL_CellInfoLte     lte;
-    RIL_CellInfoWcdma   wcdma;
-    RIL_CellInfoTdscdma tdscdma;
-  } CellInfo;
-} RIL_CellInfo;
-
-typedef struct {
-  RIL_CellInfoType  cellInfoType;   /* cell type for selecting from union CellInfo */
-  int               registered;     /* !0 if this cell is registered 0 if not registered */
-  RIL_TimeStampType timeStampType;  /* type of time stamp represented by timeStamp */
-  uint64_t          timeStamp;      /* Time in nanos as returned by ril_nano_time */
-  union {
-    RIL_CellInfoGsm_v12     gsm;
-    RIL_CellInfoCdma        cdma;
-    RIL_CellInfoLte_v12     lte;
-    RIL_CellInfoWcdma_v12   wcdma;
-    RIL_CellInfoTdscdma     tdscdma;
-  } CellInfo;
-} RIL_CellInfo_v12;
-
-typedef struct {
-  RIL_CellInfoType  cellInfoType;   /* cell type for selecting from union CellInfo */
-  union {
-    RIL_CellIdentityGsm_v12 cellIdentityGsm;
-    RIL_CellIdentityWcdma_v12 cellIdentityWcdma;
-    RIL_CellIdentityLte_v12 cellIdentityLte;
-    RIL_CellIdentityTdscdma cellIdentityTdscdma;
-    RIL_CellIdentityCdma cellIdentityCdma;
-  };
-}RIL_CellIdentity_v16;
-
-typedef struct {
-    RIL_RegState regState;                // Valid reg states are RIL_NOT_REG_AND_NOT_SEARCHING,
-                                          // REG_HOME, RIL_NOT_REG_AND_SEARCHING, REG_DENIED,
-                                          // UNKNOWN, REG_ROAMING defined in RegState
-    RIL_RadioTechnology rat;              // indicates the available voice radio technology,
-                                          // valid values as defined by RadioTechnology.
-    int32_t cssSupported;                 // concurrent services support indicator. if
-                                          // registered on a CDMA system.
-                                          // 0 - Concurrent services not supported,
-                                          // 1 - Concurrent services supported
-    int32_t roamingIndicator;             // TSB-58 Roaming Indicator if registered
-                                          // on a CDMA or EVDO system or -1 if not.
-                                          // Valid values are 0-255.
-    int32_t systemIsInPrl;                // indicates whether the current system is in the
-                                          // PRL if registered on a CDMA or EVDO system or -1 if
-                                          // not. 0=not in the PRL, 1=in the PRL
-    int32_t defaultRoamingIndicator;      // default Roaming Indicator from the PRL,
-                                          // if registered on a CDMA or EVDO system or -1 if not.
-                                          // Valid values are 0-255.
-    int32_t reasonForDenial;              // reasonForDenial if registration state is 3
-                                          // (Registration denied) this is an enumerated reason why
-                                          // registration was denied. See 3GPP TS 24.008,
-                                          // 10.5.3.6 and Annex G.
-                                          // 0 - General
-                                          // 1 - Authentication Failure
-                                          // 2 - IMSI unknown in HLR
-                                          // 3 - Illegal MS
-                                          // 4 - Illegal ME
-                                          // 5 - PLMN not allowed
-                                          // 6 - Location area not allowed
-                                          // 7 - Roaming not allowed
-                                          // 8 - No Suitable Cells in this Location Area
-                                          // 9 - Network failure
-                                          // 10 - Persistent location update reject
-                                          // 11 - PLMN not allowed
-                                          // 12 - Location area not allowed
-                                          // 13 - Roaming not allowed in this Location Area
-                                          // 15 - No Suitable Cells in this Location Area
-                                          // 17 - Network Failure
-                                          // 20 - MAC Failure
-                                          // 21 - Sync Failure
-                                          // 22 - Congestion
-                                          // 23 - GSM Authentication unacceptable
-                                          // 25 - Not Authorized for this CSG
-                                          // 32 - Service option not supported
-                                          // 33 - Requested service option not subscribed
-                                          // 34 - Service option temporarily out of order
-                                          // 38 - Call cannot be identified
-                                          // 48-63 - Retry upon entry into a new cell
-                                          // 95 - Semantically incorrect message
-                                          // 96 - Invalid mandatory information
-                                          // 97 - Message type non-existent or not implemented
-                                          // 98 - Message type not compatible with protocol state
-                                          // 99 - Information element non-existent or
-                                          //      not implemented
-                                          // 100 - Conditional IE error
-                                          // 101 - Message not compatible with protocol state;
-    RIL_CellIdentity_v16 cellIdentity;    // current cell information
-}RIL_VoiceRegistrationStateResponse;
-
-
-typedef struct {
-    RIL_RegState regState;                // Valid reg states are RIL_NOT_REG_AND_NOT_SEARCHING,
-                                          // REG_HOME, RIL_NOT_REG_AND_SEARCHING, REG_DENIED,
-                                          // UNKNOWN, REG_ROAMING defined in RegState
-    RIL_RadioTechnology rat;              // indicates the available data radio technology,
-                                          // valid values as defined by RadioTechnology.
-    int32_t reasonDataDenied;             // if registration state is 3 (Registration
-                                          // denied) this is an enumerated reason why
-                                          // registration was denied. See 3GPP TS 24.008,
-                                          // Annex G.6 "Additional cause codes for GMM".
-                                          // 7 == GPRS services not allowed
-                                          // 8 == GPRS services and non-GPRS services not allowed
-                                          // 9 == MS identity cannot be derived by the network
-                                          // 10 == Implicitly detached
-                                          // 14 == GPRS services not allowed in this PLMN
-                                          // 16 == MSC temporarily not reachable
-                                          // 40 == No PDP context activated
-    int32_t maxDataCalls;                 // The maximum number of simultaneous Data Calls that
-                                          // must be established using setupDataCall().
-    RIL_CellIdentity_v16 cellIdentity;    // Current cell information
-}RIL_DataRegistrationStateResponse;
-
-/* Names of the CDMA info records (C.S0005 section 3.7.5) */
-typedef enum {
-  RIL_CDMA_DISPLAY_INFO_REC,
-  RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC,
-  RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC,
-  RIL_CDMA_CONNECTED_NUMBER_INFO_REC,
-  RIL_CDMA_SIGNAL_INFO_REC,
-  RIL_CDMA_REDIRECTING_NUMBER_INFO_REC,
-  RIL_CDMA_LINE_CONTROL_INFO_REC,
-  RIL_CDMA_EXTENDED_DISPLAY_INFO_REC,
-  RIL_CDMA_T53_CLIR_INFO_REC,
-  RIL_CDMA_T53_RELEASE_INFO_REC,
-  RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC
-} RIL_CDMA_InfoRecName;
-
-/* Display Info Rec as defined in C.S0005 section 3.7.5.1
-   Extended Display Info Rec as defined in C.S0005 section 3.7.5.16
-   Note: the Extended Display info rec contains multiple records of the
-   form: display_tag, display_len, and display_len occurrences of the
-   chari field if the display_tag is not 10000000 or 10000001.
-   To save space, the records are stored consecutively in a byte buffer.
-   The display_tag, display_len and chari fields are all 1 byte.
-*/
-
-typedef struct {
-  char alpha_len;
-  char alpha_buf[CDMA_ALPHA_INFO_BUFFER_LENGTH];
-} RIL_CDMA_DisplayInfoRecord;
-
-/* Called Party Number Info Rec as defined in C.S0005 section 3.7.5.2
-   Calling Party Number Info Rec as defined in C.S0005 section 3.7.5.3
-   Connected Number Info Rec as defined in C.S0005 section 3.7.5.4
-*/
-
-typedef struct {
-  char len;
-  char buf[CDMA_NUMBER_INFO_BUFFER_LENGTH];
-  char number_type;
-  char number_plan;
-  char pi;
-  char si;
-} RIL_CDMA_NumberInfoRecord;
-
-/* Redirecting Number Information Record as defined in C.S0005 section 3.7.5.11 */
-typedef enum {
-  RIL_REDIRECTING_REASON_UNKNOWN = 0,
-  RIL_REDIRECTING_REASON_CALL_FORWARDING_BUSY = 1,
-  RIL_REDIRECTING_REASON_CALL_FORWARDING_NO_REPLY = 2,
-  RIL_REDIRECTING_REASON_CALLED_DTE_OUT_OF_ORDER = 9,
-  RIL_REDIRECTING_REASON_CALL_FORWARDING_BY_THE_CALLED_DTE = 10,
-  RIL_REDIRECTING_REASON_CALL_FORWARDING_UNCONDITIONAL = 15,
-  RIL_REDIRECTING_REASON_RESERVED
-} RIL_CDMA_RedirectingReason;
-
-typedef struct {
-  RIL_CDMA_NumberInfoRecord redirectingNumber;
-  /* redirectingReason is set to RIL_REDIRECTING_REASON_UNKNOWN if not included */
-  RIL_CDMA_RedirectingReason redirectingReason;
-} RIL_CDMA_RedirectingNumberInfoRecord;
-
-/* Line Control Information Record as defined in C.S0005 section 3.7.5.15 */
-typedef struct {
-  char lineCtrlPolarityIncluded;
-  char lineCtrlToggle;
-  char lineCtrlReverse;
-  char lineCtrlPowerDenial;
-} RIL_CDMA_LineControlInfoRecord;
-
-/* T53 CLIR Information Record */
-typedef struct {
-  char cause;
-} RIL_CDMA_T53_CLIRInfoRecord;
-
-/* T53 Audio Control Information Record */
-typedef struct {
-  char upLink;
-  char downLink;
-} RIL_CDMA_T53_AudioControlInfoRecord;
-
-typedef struct {
-
-  RIL_CDMA_InfoRecName name;
-
-  union {
-    /* Display and Extended Display Info Rec */
-    RIL_CDMA_DisplayInfoRecord           display;
-
-    /* Called Party Number, Calling Party Number, Connected Number Info Rec */
-    RIL_CDMA_NumberInfoRecord            number;
-
-    /* Signal Info Rec */
-    RIL_CDMA_SignalInfoRecord            signal;
-
-    /* Redirecting Number Info Rec */
-    RIL_CDMA_RedirectingNumberInfoRecord redir;
-
-    /* Line Control Info Rec */
-    RIL_CDMA_LineControlInfoRecord       lineCtrl;
-
-    /* T53 CLIR Info Rec */
-    RIL_CDMA_T53_CLIRInfoRecord          clir;
-
-    /* T53 Audio Control Info Rec */
-    RIL_CDMA_T53_AudioControlInfoRecord  audioCtrl;
-  } rec;
-} RIL_CDMA_InformationRecord;
-
-#define RIL_CDMA_MAX_NUMBER_OF_INFO_RECS 10
-
-typedef struct {
-  char numberOfInfoRecs;
-  RIL_CDMA_InformationRecord infoRec[RIL_CDMA_MAX_NUMBER_OF_INFO_RECS];
-} RIL_CDMA_InformationRecords;
-
-/* See RIL_REQUEST_NV_READ_ITEM */
-typedef struct {
-  RIL_NV_Item itemID;
-} RIL_NV_ReadItem;
-
-/* See RIL_REQUEST_NV_WRITE_ITEM */
-typedef struct {
-  RIL_NV_Item   itemID;
-  char *        value;
-} RIL_NV_WriteItem;
-
-typedef enum {
-    HANDOVER_STARTED = 0,
-    HANDOVER_COMPLETED = 1,
-    HANDOVER_FAILED = 2,
-    HANDOVER_CANCELED = 3
-} RIL_SrvccState;
-
-/* hardware configuration reported to RILJ. */
-typedef enum {
-   RIL_HARDWARE_CONFIG_MODEM = 0,
-   RIL_HARDWARE_CONFIG_SIM = 1,
-} RIL_HardwareConfig_Type;
-
-typedef enum {
-   RIL_HARDWARE_CONFIG_STATE_ENABLED = 0,
-   RIL_HARDWARE_CONFIG_STATE_STANDBY = 1,
-   RIL_HARDWARE_CONFIG_STATE_DISABLED = 2,
-} RIL_HardwareConfig_State;
-
-typedef struct {
-   int rilModel;
-   uint32_t rat; /* bitset - ref. RIL_RadioTechnology. */
-   int maxVoice;
-   int maxData;
-   int maxStandby;
-} RIL_HardwareConfig_Modem;
-
-typedef struct {
-   char modemUuid[MAX_UUID_LENGTH];
-} RIL_HardwareConfig_Sim;
-
-typedef struct {
-  RIL_HardwareConfig_Type type;
-  char uuid[MAX_UUID_LENGTH];
-  RIL_HardwareConfig_State state;
-  union {
-     RIL_HardwareConfig_Modem modem;
-     RIL_HardwareConfig_Sim sim;
-  } cfg;
-} RIL_HardwareConfig;
-
-typedef enum {
-  SS_CFU,
-  SS_CF_BUSY,
-  SS_CF_NO_REPLY,
-  SS_CF_NOT_REACHABLE,
-  SS_CF_ALL,
-  SS_CF_ALL_CONDITIONAL,
-  SS_CLIP,
-  SS_CLIR,
-  SS_COLP,
-  SS_COLR,
-  SS_WAIT,
-  SS_BAOC,
-  SS_BAOIC,
-  SS_BAOIC_EXC_HOME,
-  SS_BAIC,
-  SS_BAIC_ROAMING,
-  SS_ALL_BARRING,
-  SS_OUTGOING_BARRING,
-  SS_INCOMING_BARRING
-} RIL_SsServiceType;
-
-typedef enum {
-  SS_ACTIVATION,
-  SS_DEACTIVATION,
-  SS_INTERROGATION,
-  SS_REGISTRATION,
-  SS_ERASURE
-} RIL_SsRequestType;
-
-typedef enum {
-  SS_ALL_TELE_AND_BEARER_SERVICES,
-  SS_ALL_TELESEVICES,
-  SS_TELEPHONY,
-  SS_ALL_DATA_TELESERVICES,
-  SS_SMS_SERVICES,
-  SS_ALL_TELESERVICES_EXCEPT_SMS
-} RIL_SsTeleserviceType;
-
-#define SS_INFO_MAX 4
-#define NUM_SERVICE_CLASSES 7
-
-typedef struct {
-  int numValidIndexes; /* This gives the number of valid values in cfInfo.
-                       For example if voice is forwarded to one number and data
-                       is forwarded to a different one then numValidIndexes will be
-                       2 indicating total number of valid values in cfInfo.
-                       Similarly if all the services are forwarded to the same
-                       number then the value of numValidIndexes will be 1. */
-
-  RIL_CallForwardInfo cfInfo[NUM_SERVICE_CLASSES]; /* This is the response data
-                                                      for SS request to query call
-                                                      forward status. see
-                                                      RIL_REQUEST_QUERY_CALL_FORWARD_STATUS */
-} RIL_CfData;
-
-typedef struct {
-  RIL_SsServiceType serviceType;
-  RIL_SsRequestType requestType;
-  RIL_SsTeleserviceType teleserviceType;
-  int serviceClass;
-  RIL_Errno result;
-
-  union {
-    int ssInfo[SS_INFO_MAX]; /* This is the response data for most of the SS GET/SET
-                                RIL requests. E.g. RIL_REQUSET_GET_CLIR returns
-                                two ints, so first two values of ssInfo[] will be
-                                used for response if serviceType is SS_CLIR and
-                                requestType is SS_INTERROGATION */
-
-    RIL_CfData cfData;
-  };
-} RIL_StkCcUnsolSsResponse;
-
-/**
- * Data connection power state
- */
-typedef enum {
-    RIL_DC_POWER_STATE_LOW      = 1,        // Low power state
-    RIL_DC_POWER_STATE_MEDIUM   = 2,        // Medium power state
-    RIL_DC_POWER_STATE_HIGH     = 3,        // High power state
-    RIL_DC_POWER_STATE_UNKNOWN  = INT32_MAX // Unknown state
-} RIL_DcPowerStates;
-
-/**
- * Data connection real time info
- */
-typedef struct {
-    uint64_t                    time;       // Time in nanos as returned by ril_nano_time
-    RIL_DcPowerStates           powerState; // Current power state
-} RIL_DcRtInfo;
-
-/**
- * Data profile to modem
- */
-typedef struct {
-    /* id of the data profile */
-    int profileId;
-    /* the APN to connect to */
-    char* apn;
-    /** one of the PDP_type values in TS 27.007 section 10.1.1.
-     * For example, "IP", "IPV6", "IPV4V6", or "PPP".
-     */
-    char* protocol;
-    /** authentication protocol used for this PDP context
-     * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
-     */
-    int authType;
-    /* the username for APN, or NULL */
-    char* user;
-    /* the password for APN, or NULL */
-    char* password;
-    /* the profile type, TYPE_COMMON-0, TYPE_3GPP-1, TYPE_3GPP2-2 */
-    int type;
-    /* the period in seconds to limit the maximum connections */
-    int maxConnsTime;
-    /* the maximum connections during maxConnsTime */
-    int maxConns;
-    /** the required wait time in seconds after a successful UE initiated
-     * disconnect of a given PDN connection before the device can send
-     * a new PDN connection request for that given PDN
-     */
-    int waitTime;
-    /* true to enable the profile, 0 to disable, 1 to enable */
-    int enabled;
-} RIL_DataProfileInfo;
-
-typedef struct {
-    /* id of the data profile */
-    int profileId;
-    /* the APN to connect to */
-    char* apn;
-    /** one of the PDP_type values in TS 27.007 section 10.1.1.
-     * For example, "IP", "IPV6", "IPV4V6", or "PPP".
-     */
-    char* protocol;
-    /** one of the PDP_type values in TS 27.007 section 10.1.1 used on roaming network.
-     * For example, "IP", "IPV6", "IPV4V6", or "PPP".
-     */
-    char *roamingProtocol;
-    /** authentication protocol used for this PDP context
-     * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
-     */
-    int authType;
-    /* the username for APN, or NULL */
-    char* user;
-    /* the password for APN, or NULL */
-    char* password;
-    /* the profile type, TYPE_COMMON-0, TYPE_3GPP-1, TYPE_3GPP2-2 */
-    int type;
-    /* the period in seconds to limit the maximum connections */
-    int maxConnsTime;
-    /* the maximum connections during maxConnsTime */
-    int maxConns;
-    /** the required wait time in seconds after a successful UE initiated
-     * disconnect of a given PDN connection before the device can send
-     * a new PDN connection request for that given PDN
-     */
-    int waitTime;
-    /* true to enable the profile, 0 to disable, 1 to enable */
-    int enabled;
-    /* supported APN types bitmask. See RIL_ApnTypes for the value of each bit. */
-    int supportedTypesBitmask;
-    /** the bearer bitmask. See RIL_RadioAccessFamily for the value of each bit. */
-    int bearerBitmask;
-    /** maximum transmission unit (MTU) size in bytes */
-    int mtu;
-    /** the MVNO type: possible values are "imsi", "gid", "spn" */
-    char *mvnoType;
-    /** MVNO match data. Can be anything defined by the carrier. For example,
-     *        SPN like: "A MOBILE", "BEN NL", etc...
-     *        IMSI like: "302720x94", "2060188", etc...
-     *        GID like: "4E", "33", etc...
-     */
-    char *mvnoMatchData;
-} RIL_DataProfileInfo_v15;
-
-/* Tx Power Levels */
-#define RIL_NUM_TX_POWER_LEVELS     5
-
-/**
- * Aggregate modem activity information
- */
-typedef struct {
-
-  /* total time (in ms) when modem is in a low power or
-   * sleep state
-   */
-  uint32_t sleep_mode_time_ms;
-
-  /* total time (in ms) when modem is awake but neither
-   * the transmitter nor receiver are active/awake */
-  uint32_t idle_mode_time_ms;
-
-  /* total time (in ms) during which the transmitter is active/awake,
-   * subdivided by manufacturer-defined device-specific
-   * contiguous increasing ranges of transmit power between
-   * 0 and the transmitter's maximum transmit power.
-   */
-  uint32_t tx_mode_time_ms[RIL_NUM_TX_POWER_LEVELS];
-
-  /* total time (in ms) for which receiver is active/awake and
-   * the transmitter is inactive */
-  uint32_t rx_mode_time_ms;
-} RIL_ActivityStatsInfo;
-
-typedef enum {
-    RIL_APN_TYPE_UNKNOWN      = 0x0,          // Unknown
-    RIL_APN_TYPE_DEFAULT      = 0x1,          // APN type for default data traffic
-    RIL_APN_TYPE_MMS          = 0x2,          // APN type for MMS traffic
-    RIL_APN_TYPE_SUPL         = 0x4,          // APN type for SUPL assisted GPS
-    RIL_APN_TYPE_DUN          = 0x8,          // APN type for DUN traffic
-    RIL_APN_TYPE_HIPRI        = 0x10,         // APN type for HiPri traffic
-    RIL_APN_TYPE_FOTA         = 0x20,         // APN type for FOTA
-    RIL_APN_TYPE_IMS          = 0x40,         // APN type for IMS
-    RIL_APN_TYPE_CBS          = 0x80,         // APN type for CBS
-    RIL_APN_TYPE_IA           = 0x100,        // APN type for IA Initial Attach APN
-    RIL_APN_TYPE_EMERGENCY    = 0x200,        // APN type for Emergency PDN. This is not an IA apn,
-                                              // but is used for access to carrier services in an
-                                              // emergency call situation.
-    RIL_APN_TYPE_MCX          = 0x400,        // APN type for Mission Critical Service
-    RIL_APN_TYPE_XCAP         = 0x800,        // APN type for XCAP
-    RIL_APN_TYPE_ALL          = 0xFFFFFFFF    // All APN types
-} RIL_ApnTypes;
-
-typedef enum {
-    RIL_DST_POWER_SAVE_MODE,        // Device power save mode (provided by PowerManager)
-                                    // True indicates the device is in power save mode.
-    RIL_DST_CHARGING_STATE,         // Device charging state (provided by BatteryManager)
-                                    // True indicates the device is charging.
-    RIL_DST_LOW_DATA_EXPECTED       // Low data expected mode. True indicates low data traffic
-                                    // is expected, for example, when the device is idle
-                                    // (e.g. not doing tethering in the background). Note
-                                    // this doesn't mean no data is expected.
-} RIL_DeviceStateType;
-
-typedef enum {
-    RIL_UR_SIGNAL_STRENGTH            = 0x01, // When this bit is set, modem should always send the
-                                              // signal strength update through
-                                              // RIL_UNSOL_SIGNAL_STRENGTH, otherwise suppress it.
-    RIL_UR_FULL_NETWORK_STATE         = 0x02, // When this bit is set, modem should always send
-                                              // RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
-                                              // when any field in
-                                              // RIL_REQUEST_VOICE_REGISTRATION_STATE or
-                                              // RIL_REQUEST_DATA_REGISTRATION_STATE changes. When
-                                              // this bit is not set, modem should suppress
-                                              // RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
-                                              // only when insignificant fields change
-                                              // (e.g. cell info).
-                                              // Modem should continue sending
-                                              // RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
-                                              // when significant fields are updated even when this
-                                              // bit is not set. The following fields are
-                                              // considered significant, registration state and
-                                              // radio technology.
-    RIL_UR_DATA_CALL_DORMANCY_CHANGED = 0x04  // When this bit is set, modem should send the data
-                                              // call list changed unsolicited response
-                                              // RIL_UNSOL_DATA_CALL_LIST_CHANGED whenever any
-                                              // field in RIL_Data_Call_Response changes.
-                                              // Otherwise modem should suppress the unsolicited
-                                              // response when the only changed field is 'active'
-                                              // (for data dormancy). For all other fields change,
-                                              // modem should continue sending
-                                              // RIL_UNSOL_DATA_CALL_LIST_CHANGED regardless this
-                                              // bit is set or not.
-} RIL_UnsolicitedResponseFilter;
-
-typedef struct {
-    char * aidPtr; /* AID value, See ETSI 102.221 and 101.220*/
-    int p2;        /* P2 parameter (described in ISO 7816-4)
-                      P2Constants:NO_P2 if to be ignored */
-} RIL_OpenChannelParams;
-
-typedef enum {
-    RIL_ONE_SHOT = 0x01, // Performs the scan only once
-    RIL_PERIODIC = 0x02  // Performs the scan periodically until cancelled
-} RIL_ScanType;
-
-typedef enum {
-    UNKNOWN = 0x00,     // Unknown Radio Access Network
-    GERAN = 0x01,       // GSM EDGE Radio Access Network
-    UTRAN = 0x02,       // Universal Terrestrial Radio Access Network
-    EUTRAN = 0x03,      // Evolved Universal Terrestrial Radio Access Network
-    NGRAN = 0x04,       // Next-Generation Radio Access Network
-    CDMA2000 = 0x05,    // CDMA 2000 Radio AccessNetwork
-} RIL_RadioAccessNetworks;
-
-typedef enum {
-    GERAN_BAND_T380 = 1,
-    GERAN_BAND_T410 = 2,
-    GERAN_BAND_450 = 3,
-    GERAN_BAND_480 = 4,
-    GERAN_BAND_710 = 5,
-    GERAN_BAND_750 = 6,
-    GERAN_BAND_T810 = 7,
-    GERAN_BAND_850 = 8,
-    GERAN_BAND_P900 = 9,
-    GERAN_BAND_E900 = 10,
-    GERAN_BAND_R900 = 11,
-    GERAN_BAND_DCS1800 = 12,
-    GERAN_BAND_PCS1900 = 13,
-    GERAN_BAND_ER900 = 14,
-} RIL_GeranBands;
-
-typedef enum {
-    UTRAN_BAND_1 = 1,
-    UTRAN_BAND_2 = 2,
-    UTRAN_BAND_3 = 3,
-    UTRAN_BAND_4 = 4,
-    UTRAN_BAND_5 = 5,
-    UTRAN_BAND_6 = 6,
-    UTRAN_BAND_7 = 7,
-    UTRAN_BAND_8 = 8,
-    UTRAN_BAND_9 = 9,
-    UTRAN_BAND_10 = 10,
-    UTRAN_BAND_11 = 11,
-    UTRAN_BAND_12 = 12,
-    UTRAN_BAND_13 = 13,
-    UTRAN_BAND_14 = 14,
-    UTRAN_BAND_19 = 19,
-    UTRAN_BAND_20 = 20,
-    UTRAN_BAND_21 = 21,
-    UTRAN_BAND_22 = 22,
-    UTRAN_BAND_25 = 25,
-    UTRAN_BAND_26 = 26,
-} RIL_UtranBands;
-
-typedef enum {
-    EUTRAN_BAND_1 = 1,
-    EUTRAN_BAND_2 = 2,
-    EUTRAN_BAND_3 = 3,
-    EUTRAN_BAND_4 = 4,
-    EUTRAN_BAND_5 = 5,
-    EUTRAN_BAND_6 = 6,
-    EUTRAN_BAND_7 = 7,
-    EUTRAN_BAND_8 = 8,
-    EUTRAN_BAND_9 = 9,
-    EUTRAN_BAND_10 = 10,
-    EUTRAN_BAND_11 = 11,
-    EUTRAN_BAND_12 = 12,
-    EUTRAN_BAND_13 = 13,
-    EUTRAN_BAND_14 = 14,
-    EUTRAN_BAND_17 = 17,
-    EUTRAN_BAND_18 = 18,
-    EUTRAN_BAND_19 = 19,
-    EUTRAN_BAND_20 = 20,
-    EUTRAN_BAND_21 = 21,
-    EUTRAN_BAND_22 = 22,
-    EUTRAN_BAND_23 = 23,
-    EUTRAN_BAND_24 = 24,
-    EUTRAN_BAND_25 = 25,
-    EUTRAN_BAND_26 = 26,
-    EUTRAN_BAND_27 = 27,
-    EUTRAN_BAND_28 = 28,
-    EUTRAN_BAND_30 = 30,
-    EUTRAN_BAND_31 = 31,
-    EUTRAN_BAND_33 = 33,
-    EUTRAN_BAND_34 = 34,
-    EUTRAN_BAND_35 = 35,
-    EUTRAN_BAND_36 = 36,
-    EUTRAN_BAND_37 = 37,
-    EUTRAN_BAND_38 = 38,
-    EUTRAN_BAND_39 = 39,
-    EUTRAN_BAND_40 = 40,
-    EUTRAN_BAND_41 = 41,
-    EUTRAN_BAND_42 = 42,
-    EUTRAN_BAND_43 = 43,
-    EUTRAN_BAND_44 = 44,
-    EUTRAN_BAND_45 = 45,
-    EUTRAN_BAND_46 = 46,
-    EUTRAN_BAND_47 = 47,
-    EUTRAN_BAND_48 = 48,
-    EUTRAN_BAND_65 = 65,
-    EUTRAN_BAND_66 = 66,
-    EUTRAN_BAND_68 = 68,
-    EUTRAN_BAND_70 = 70,
-} RIL_EutranBands;
-
-typedef enum {
-    NGRAN_BAND_1 = 1,
-    NGRAN_BAND_2 = 2,
-    NGRAN_BAND_3 = 3,
-    NGRAN_BAND_5 = 5,
-    NGRAN_BAND_7 = 7,
-    NGRAN_BAND_8 = 8,
-    NGRAN_BAND_12 = 12,
-    NGRAN_BAND_20 = 20,
-    NGRAN_BAND_25 = 25,
-    NGRAN_BAND_28 = 28,
-    NGRAN_BAND_34 = 34,
-    NGRAN_BAND_38 = 38,
-    NGRAN_BAND_39 = 39,
-    NGRAN_BAND_40 = 40,
-    NGRAN_BAND_41 = 41,
-    NGRAN_BAND_50 = 50,
-    NGRAN_BAND_51 = 51,
-    NGRAN_BAND_66 = 66,
-    NGRAN_BAND_70 = 70,
-    NGRAN_BAND_71 = 71,
-    NGRAN_BAND_74 = 74,
-    NGRAN_BAND_75 = 75,
-    NGRAN_BAND_76 = 76,
-    NGRAN_BAND_77 = 77,
-    NGRAN_BAND_78 = 78,
-    NGRAN_BAND_79 = 79,
-    NGRAN_BAND_80 = 80,
-    NGRAN_BAND_81 = 81,
-    NGRAN_BAND_82 = 82,
-    NGRAN_BAND_83 = 83,
-    NGRAN_BAND_84 = 84,
-    NGRAN_BAND_86 = 86,
-    NGRAN_BAND_257 = 257,
-    NGRAN_BAND_258 = 258,
-    NGRAN_BAND_260 = 260,
-    NGRAN_BAND_261 = 261,
-} RIL_NgranBands;
-
-typedef struct {
-    RIL_RadioAccessNetworks radio_access_network; // The type of network to scan.
-    uint32_t bands_length;                        // Length of bands
-    union {
-        RIL_GeranBands geran_bands[MAX_BANDS];
-        RIL_UtranBands utran_bands[MAX_BANDS];
-        RIL_EutranBands eutran_bands[MAX_BANDS];
-        RIL_NgranBands ngran_bands[MAX_BANDS];
-    } bands;
-    uint32_t channels_length;                     // Length of channels
-    uint32_t channels[MAX_CHANNELS];              // Frequency channels to scan
-} RIL_RadioAccessSpecifier;
-
-typedef struct {
-    RIL_ScanType type;                                              // Type of the scan
-    int32_t interval;                                               // Time interval in seconds
-                                                                    // between periodic scans, only
-                                                                    // valid when type=RIL_PERIODIC
-    uint32_t specifiers_length;                                     // Length of specifiers
-    RIL_RadioAccessSpecifier specifiers[MAX_RADIO_ACCESS_NETWORKS]; // Radio access networks
-                                                                    // with bands/channels.
-} RIL_NetworkScanRequest;
-
-typedef enum {
-    PARTIAL = 0x01,   // The result contains a part of the scan results
-    COMPLETE = 0x02,  // The result contains the last part of the scan results
-} RIL_ScanStatus;
-
-typedef struct {
-    RIL_ScanStatus status;              // The status of the scan
-    uint32_t network_infos_length;      // Total length of RIL_CellInfo
-    RIL_CellInfo_v12* network_infos;    // List of network information
-    RIL_Errno error;
-} RIL_NetworkScanResult;
-
-/**
- * RIL_REQUEST_GET_SIM_STATUS
- *
- * Requests status of the SIM interface and the SIM card
- *
- * "data" is NULL
- *
- * "response" is const RIL_CardStatus_v6 *
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_GET_SIM_STATUS 1
-
-/**
- * RIL_REQUEST_ENTER_SIM_PIN
- *
- * Supplies SIM PIN. Only called if RIL_CardStatus has RIL_APPSTATE_PIN state
- *
- * "data" is const char **
- * ((const char **)data)[0] is PIN value
- * ((const char **)data)[1] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *
- * SUCCESS
- * RADIO_NOT_AVAILABLE (radio resetting)
- * PASSWORD_INCORRECT
- * INTERNAL_ERR
- * NO_MEMORY
- * NO_RESOURCES
- * CANCELLED
- * INVALID_ARGUMENTS
- * INVALID_SIM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_ENTER_SIM_PIN 2
-
-/**
- * RIL_REQUEST_ENTER_SIM_PUK
- *
- * Supplies SIM PUK and new PIN.
- *
- * "data" is const char **
- * ((const char **)data)[0] is PUK value
- * ((const char **)data)[1] is new PIN value
- * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  PASSWORD_INCORRECT
- *     (PUK is invalid)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_ARGUMENTS
- *  INVALID_SIM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_ENTER_SIM_PUK 3
-
-/**
- * RIL_REQUEST_ENTER_SIM_PIN2
- *
- * Supplies SIM PIN2. Only called following operation where SIM_PIN2 was
- * returned as a a failure from a previous operation.
- *
- * "data" is const char **
- * ((const char **)data)[0] is PIN2 value
- * ((const char **)data)[1] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  PASSWORD_INCORRECT
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_ARGUMENTS
- *  INVALID_SIM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_ENTER_SIM_PIN2 4
-
-/**
- * RIL_REQUEST_ENTER_SIM_PUK2
- *
- * Supplies SIM PUK2 and new PIN2.
- *
- * "data" is const char **
- * ((const char **)data)[0] is PUK2 value
- * ((const char **)data)[1] is new PIN2 value
- * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  PASSWORD_INCORRECT
- *     (PUK2 is invalid)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_ARGUMENTS
- *  INVALID_SIM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_ENTER_SIM_PUK2 5
-
-/**
- * RIL_REQUEST_CHANGE_SIM_PIN
- *
- * Supplies old SIM PIN and new PIN.
- *
- * "data" is const char **
- * ((const char **)data)[0] is old PIN value
- * ((const char **)data)[1] is new PIN value
- * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  PASSWORD_INCORRECT
- *     (old PIN is invalid)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_ARGUMENTS
- *  INVALID_SIM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_CHANGE_SIM_PIN 6
-
-
-/**
- * RIL_REQUEST_CHANGE_SIM_PIN2
- *
- * Supplies old SIM PIN2 and new PIN2.
- *
- * "data" is const char **
- * ((const char **)data)[0] is old PIN2 value
- * ((const char **)data)[1] is new PIN2 value
- * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  PASSWORD_INCORRECT
- *     (old PIN2 is invalid)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_ARGUMENTS
- *  INVALID_SIM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- */
-
-#define RIL_REQUEST_CHANGE_SIM_PIN2 7
-
-/**
- * RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION
- *
- * Requests that network personlization be deactivated
- *
- * "data" is const char **
- * ((const char **)(data))[0]] is network depersonlization code
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  PASSWORD_INCORRECT
- *  SIM_ABSENT
- *     (code is invalid)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
-
-/**
- * RIL_REQUEST_GET_CURRENT_CALLS
- *
- * Requests current call list
- *
- * "data" is NULL
- *
- * "response" must be a "const RIL_Call **"
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *      (request will be made again in a few hundred msec)
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_GET_CURRENT_CALLS 9
-
-
-/**
- * RIL_REQUEST_DIAL
- *
- * Initiate voice call
- *
- * "data" is const RIL_Dial *
- * "response" is NULL
- *
- * This method is never used for supplementary service codes
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  DIAL_MODIFIED_TO_USSD
- *  DIAL_MODIFIED_TO_SS
- *  DIAL_MODIFIED_TO_DIAL
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  INVALID_STATE
- *  NO_RESOURCES
- *  INTERNAL_ERR
- *  FDN_CHECK_FAILURE
- *  MODEM_ERR
- *  NO_SUBSCRIPTION
- *  NO_NETWORK_FOUND
- *  INVALID_CALL_ID
- *  DEVICE_IN_USE
- *  OPERATION_NOT_ALLOWED
- *  ABORTED
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_DIAL 10
-
-/**
- * RIL_REQUEST_GET_IMSI
- *
- * Get the SIM IMSI
- *
- * Only valid when radio state is "RADIO_STATE_ON"
- *
- * "data" is const char **
- * ((const char **)data)[0] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- * "response" is a const char * containing the IMSI
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_SIM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_GET_IMSI 11
-
-/**
- * RIL_REQUEST_HANGUP
- *
- * Hang up a specific line (like AT+CHLD=1x)
- *
- * After this HANGUP request returns, RIL should show the connection is NOT
- * active anymore in next RIL_REQUEST_GET_CURRENT_CALLS query.
- *
- * "data" is an int *
- * (int *)data)[0] contains Connection index (value of 'x' in CHLD above)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  INVALID_STATE
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  INVALID_CALL_ID
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_HANGUP 12
-
-/**
- * RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND
- *
- * Hang up waiting or held (like AT+CHLD=0)
- *
- * After this HANGUP request returns, RIL should show the connection is NOT
- * active anymore in next RIL_REQUEST_GET_CURRENT_CALLS query.
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_STATE
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  INVALID_CALL_ID
- *  NO_RESOURCES
- *  OPERATION_NOT_ALLOWED
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
-
-/**
- * RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
- *
- * Hang up waiting or held (like AT+CHLD=1)
- *
- * After this HANGUP request returns, RIL should show the connection is NOT
- * active anymore in next RIL_REQUEST_GET_CURRENT_CALLS query.
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_STATE
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  OPERATION_NOT_ALLOWED
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
-
-/**
- * RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE
- *
- * Switch waiting or holding call and active call (like AT+CHLD=2)
- *
- * State transitions should be is follows:
- *
- * If call 1 is waiting and call 2 is active, then if this re
- *
- *   BEFORE                               AFTER
- * Call 1   Call 2                 Call 1       Call 2
- * ACTIVE   HOLDING                HOLDING     ACTIVE
- * ACTIVE   WAITING                HOLDING     ACTIVE
- * HOLDING  WAITING                HOLDING     ACTIVE
- * ACTIVE   IDLE                   HOLDING     IDLE
- * IDLE     IDLE                   IDLE        IDLE
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_STATE
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  INVALID_CALL_ID
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE 15
-#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
-
-/**
- * RIL_REQUEST_CONFERENCE
- *
- * Conference holding and active (like AT+CHLD=3)
-
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_STATE
- *  INVALID_CALL_ID
- *  INVALID_ARGUMENTS
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_CONFERENCE 16
-
-/**
- * RIL_REQUEST_UDUB
- *
- * Send UDUB (user determined used busy) to ringing or
- * waiting call answer)(RIL_BasicRequest r);
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_STATE
- *  NO_RESOURCES
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  OPERATION_NOT_ALLOWED
- *  INVALID_ARGUMENTS
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_UDUB 17
-
-/**
- * RIL_REQUEST_LAST_CALL_FAIL_CAUSE
- *
- * Requests the failure cause code for the most recently terminated call
- *
- * "data" is NULL
- * "response" is a const RIL_LastCallFailCauseInfo *
- * RIL_LastCallFailCauseInfo contains LastCallFailCause and vendor cause.
- * The vendor cause code must be used for debugging purpose only.
- * The implementation must return one of the values of LastCallFailCause
- * as mentioned below.
- *
- * GSM failure reasons codes for the cause codes defined in TS 24.008 Annex H
- * where possible.
- * CDMA failure reasons codes for the possible call failure scenarios
- * described in the "CDMA IS-2000 Release A (C.S0005-A v6.0)" standard.
- * Any of the following reason codes if the call is failed or dropped due to reason
- * mentioned with in the braces.
- *
- *      CALL_FAIL_RADIO_OFF (Radio is OFF)
- *      CALL_FAIL_OUT_OF_SERVICE (No cell coverage)
- *      CALL_FAIL_NO_VALID_SIM (No valid SIM)
- *      CALL_FAIL_RADIO_INTERNAL_ERROR (Modem hit unexpected error scenario)
- *      CALL_FAIL_NETWORK_RESP_TIMEOUT (No response from network)
- *      CALL_FAIL_NETWORK_REJECT (Explicit network reject)
- *      CALL_FAIL_RADIO_ACCESS_FAILURE (RRC connection failure. Eg.RACH)
- *      CALL_FAIL_RADIO_LINK_FAILURE (Radio Link Failure)
- *      CALL_FAIL_RADIO_LINK_LOST (Radio link lost due to poor coverage)
- *      CALL_FAIL_RADIO_UPLINK_FAILURE (Radio uplink failure)
- *      CALL_FAIL_RADIO_SETUP_FAILURE (RRC connection setup failure)
- *      CALL_FAIL_RADIO_RELEASE_NORMAL (RRC connection release, normal)
- *      CALL_FAIL_RADIO_RELEASE_ABNORMAL (RRC connection release, abnormal)
- *      CALL_FAIL_ACCESS_CLASS_BLOCKED (Access class barring)
- *      CALL_FAIL_NETWORK_DETACH (Explicit network detach)
- *
- * OEM causes (CALL_FAIL_OEM_CAUSE_XX) must be used for debug purpose only
- *
- * If the implementation does not have access to the exact cause codes,
- * then it should return one of the values listed in RIL_LastCallFailCause,
- * as the UI layer needs to distinguish these cases for tone generation or
- * error notification.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE
- */
-#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
-
-/**
- * RIL_REQUEST_SIGNAL_STRENGTH
- *
- * Requests current signal strength and associated information
- *
- * Must succeed if radio is on.
- *
- * "data" is NULL
- *
- * "response" is a const RIL_SignalStrength *
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SIGNAL_STRENGTH 19
-
-/**
- * RIL_REQUEST_VOICE_REGISTRATION_STATE
- *
- * Request current registration state
- *
- * "data" is NULL
- * "response" is a const RIL_VoiceRegistrationStateResponse *
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
-
-/**
- * RIL_REQUEST_DATA_REGISTRATION_STATE
- *
- * Request current DATA registration state
- *
- * "data" is NULL
- * "response" is a const RIL_DataRegistrationStateResponse *
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
-
-/**
- * RIL_REQUEST_OPERATOR
- *
- * Request current operator ONS or EONS
- *
- * "data" is NULL
- * "response" is a "const char **"
- * ((const char **)response)[0] is long alpha ONS or EONS
- *                                  or NULL if unregistered
- *
- * ((const char **)response)[1] is short alpha ONS or EONS
- *                                  or NULL if unregistered
- * ((const char **)response)[2] is 5 or 6 digit numeric code (MCC + MNC)
- *                                  or NULL if unregistered
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_OPERATOR 22
-
-/**
- * RIL_REQUEST_RADIO_POWER
- *
- * Toggle radio on and off (for "airplane" mode)
- * If the radio is is turned off/on the radio modem subsystem
- * is expected return to an initialized state. For instance,
- * any voice and data calls will be terminated and all associated
- * lists emptied.
- *
- * "data" is int *
- * ((int *)data)[0] is > 0 for "Radio On"
- * ((int *)data)[0] is == 0 for "Radio Off"
- *
- * "response" is NULL
- *
- * Turn radio on if "on" > 0
- * Turn radio off if "on" == 0
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  INVALID_STATE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  DEVICE_IN_USE
- *  OPERATION_NOT_ALLOWED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_RADIO_POWER 23
-
-/**
- * RIL_REQUEST_DTMF
- *
- * Send a DTMF tone
- *
- * If the implementation is currently playing a tone requested via
- * RIL_REQUEST_DTMF_START, that tone should be cancelled and the new tone
- * should be played instead
- *
- * "data" is a char * containing a single character with one of 12 values: 0-9,*,#
- * "response" is NULL
- *
- * FIXME should this block/mute microphone?
- * How does this interact with local DTMF feedback?
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_DTMF_STOP, RIL_REQUEST_DTMF_START
- *
- */
-#define RIL_REQUEST_DTMF 24
-
-/**
- * RIL_REQUEST_SEND_SMS
- *
- * Send an SMS message
- *
- * "data" is const char **
- * ((const char **)data)[0] is SMSC address in GSM BCD format prefixed
- *      by a length byte (as expected by TS 27.005) or NULL for default SMSC
- * ((const char **)data)[1] is SMS in PDU format as an ASCII hex string
- *      less the SMSC address
- *      TP-Layer-Length is be "strlen(((const char **)data)[1])/2"
- *
- * "response" is a const RIL_SMS_Response *
- *
- * Based on the return error, caller decides to resend if sending sms
- * fails. SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SMS_SEND_FAIL_RETRY
- *  FDN_CHECK_FAILURE
- *  NETWORK_REJECT
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  INVALID_SMS_FORMAT
- *  SYSTEM_ERR
- *  ENCODING_ERR
- *  INVALID_SMSC_ADDRESS
- *  MODEM_ERR
- *  NETWORK_ERR
- *  OPERATION_NOT_ALLOWED
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  MODE_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- * FIXME how do we specify TP-Message-Reference if we need to resend?
- */
-#define RIL_REQUEST_SEND_SMS 25
-
-
-/**
- * RIL_REQUEST_SEND_SMS_EXPECT_MORE
- *
- * Send an SMS message. Identical to RIL_REQUEST_SEND_SMS,
- * except that more messages are expected to be sent soon. If possible,
- * keep SMS relay protocol link open (eg TS 27.005 AT+CMMS command)
- *
- * "data" is const char **
- * ((const char **)data)[0] is SMSC address in GSM BCD format prefixed
- *      by a length byte (as expected by TS 27.005) or NULL for default SMSC
- * ((const char **)data)[1] is SMS in PDU format as an ASCII hex string
- *      less the SMSC address
- *      TP-Layer-Length is be "strlen(((const char **)data)[1])/2"
- *
- * "response" is a const RIL_SMS_Response *
- *
- * Based on the return error, caller decides to resend if sending sms
- * fails. SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SMS_SEND_FAIL_RETRY
- *  NETWORK_REJECT
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  INVALID_SMS_FORMAT
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
- *  FDN_CHECK_FAILURE
- *  MODEM_ERR
- *  NETWORK_ERR
- *  ENCODING_ERR
- *  INVALID_SMSC_ADDRESS
- *  OPERATION_NOT_ALLOWED
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  MODE_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- */
-#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
-
-
-/**
- * RIL_REQUEST_SETUP_DATA_CALL
- *
- * Setup a packet data connection. If RIL_Data_Call_Response_v6.status
- * return success it is added to the list of data calls and a
- * RIL_UNSOL_DATA_CALL_LIST_CHANGED is sent. The call remains in the
- * list until RIL_REQUEST_DEACTIVATE_DATA_CALL is issued or the
- * radio is powered off/on. This list is returned by RIL_REQUEST_DATA_CALL_LIST
- * and RIL_UNSOL_DATA_CALL_LIST_CHANGED.
- *
- * The RIL is expected to:
- *  - Create one data call context.
- *  - Create and configure a dedicated interface for the context
- *  - The interface must be point to point.
- *  - The interface is configured with one or more addresses and
- *    is capable of sending and receiving packets. The prefix length
- *    of the addresses must be /32 for IPv4 and /128 for IPv6.
- *  - Must NOT change the linux routing table.
- *  - Support up to RIL_REQUEST_DATA_REGISTRATION_STATE response[5]
- *    number of simultaneous data call contexts.
- *
- * "data" is a const char **
- * ((const char **)data)[0] Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2...
- *                          for values above 2 this is RIL_RadioTechnology + 2.
- * ((const char **)data)[1] is a RIL_DataProfile (support is optional)
- * ((const char **)data)[2] is the APN to connect to if radio technology is GSM/UMTS. This APN will
- *                          override the one in the profile. NULL indicates no APN overrride.
- * ((const char **)data)[3] is the username for APN, or NULL
- * ((const char **)data)[4] is the password for APN, or NULL
- * ((const char **)data)[5] is the PAP / CHAP auth type. Values:
- *                          0 => PAP and CHAP is never performed.
- *                          1 => PAP may be performed; CHAP is never performed.
- *                          2 => CHAP may be performed; PAP is never performed.
- *                          3 => PAP / CHAP may be performed - baseband dependent.
- * ((const char **)data)[6] is the non-roaming/home connection type to request. Must be one of the
- *                          PDP_type values in TS 27.007 section 10.1.1.
- *                          For example, "IP", "IPV6", "IPV4V6", or "PPP".
- * ((const char **)data)[7] is the roaming connection type to request. Must be one of the
- *                          PDP_type values in TS 27.007 section 10.1.1.
- *                          For example, "IP", "IPV6", "IPV4V6", or "PPP".
- * ((const char **)data)[8] is the bitmask of APN type in decimal string format. The
- *                          bitmask will encapsulate the following values:
- *                          ia,mms,agps,supl,hipri,fota,dun,ims,default.
- * ((const char **)data)[9] is the bearer bitmask in decimal string format. Each bit is a
- *                          RIL_RadioAccessFamily. "0" or NULL indicates all RATs.
- * ((const char **)data)[10] is the boolean in string format indicating the APN setting was
- *                           sent to the modem through RIL_REQUEST_SET_DATA_PROFILE earlier.
- * ((const char **)data)[11] is the mtu size in bytes of the mobile interface to which
- *                           the apn is connected.
- * ((const char **)data)[12] is the MVNO type:
- *                           possible values are "imsi", "gid", "spn".
- * ((const char **)data)[13] is MVNO match data in string. Can be anything defined by the carrier.
- *                           For example,
- *                           SPN like: "A MOBILE", "BEN NL", etc...
- *                           IMSI like: "302720x94", "2060188", etc...
- *                           GID like: "4E", "33", etc...
- * ((const char **)data)[14] is the boolean string indicating data roaming is allowed or not. "1"
- *                           indicates data roaming is enabled by the user, "0" indicates disabled.
- *
- * "response" is a RIL_Data_Call_Response_v11
- *
- * FIXME may need way to configure QoS settings
- *
- * Valid errors:
- *  SUCCESS should be returned on both success and failure of setup with
- *  the RIL_Data_Call_Response_v6.status containing the actual status.
- *  For all other errors the RIL_Data_Call_Resonse_v6 is ignored.
- *
- *  Other errors could include:
- *    RADIO_NOT_AVAILABLE, OP_NOT_ALLOWED_BEFORE_REG_TO_NW,
- *    OP_NOT_ALLOWED_DURING_VOICE_CALL, REQUEST_NOT_SUPPORTED,
- *    INVALID_ARGUMENTS, INTERNAL_ERR, NO_MEMORY, NO_RESOURCES,
- *    CANCELLED and SIM_ABSENT
- *
- * See also: RIL_REQUEST_DEACTIVATE_DATA_CALL
- */
-#define RIL_REQUEST_SETUP_DATA_CALL 27
-
-
-/**
- * RIL_REQUEST_SIM_IO
- *
- * Request SIM I/O operation.
- * This is similar to the TS 27.007 "restricted SIM" operation
- * where it assumes all of the EF selection will be done by the
- * callee.
- *
- * "data" is a const RIL_SIM_IO_v6 *
- * Please note that RIL_SIM_IO has a "PIN2" field which may be NULL,
- * or may specify a PIN2 for operations that require a PIN2 (eg
- * updating FDN records)
- *
- * "response" is a const RIL_SIM_IO_Response *
- *
- * Arguments and responses that are unused for certain
- * values of "command" should be ignored or set to NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SIM_PIN2
- *  SIM_PUK2
- *  INVALID_SIM_STATE
- *  SIM_ERR
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SIM_IO 28
-
-/**
- * RIL_REQUEST_SEND_USSD
- *
- * Send a USSD message
- *
- * If a USSD session already exists, the message should be sent in the
- * context of that session. Otherwise, a new session should be created.
- *
- * The network reply should be reported via RIL_UNSOL_ON_USSD
- *
- * Only one USSD session may exist at a time, and the session is assumed
- * to exist until:
- *   a) The android system invokes RIL_REQUEST_CANCEL_USSD
- *   b) The implementation sends a RIL_UNSOL_ON_USSD with a type code
- *      of "0" (USSD-Notify/no further action) or "2" (session terminated)
- *
- * "data" is a const char * containing the USSD request in UTF-8 format
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  FDN_CHECK_FAILURE
- *  USSD_MODIFIED_TO_DIAL
- *  USSD_MODIFIED_TO_SS
- *  USSD_MODIFIED_TO_USSD
- *  SIM_BUSY
- *  OPERATION_NOT_ALLOWED
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  ABORTED
- *  SYSTEM_ERR
- *  INVALID_STATE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_CANCEL_USSD, RIL_UNSOL_ON_USSD
- */
-
-#define RIL_REQUEST_SEND_USSD 29
-
-/**
- * RIL_REQUEST_CANCEL_USSD
- *
- * Cancel the current USSD session if one exists
- *
- * "data" is null
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SIM_BUSY
- *  OPERATION_NOT_ALLOWED
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  INVALID_STATE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_CANCEL_USSD 30
-
-/**
- * RIL_REQUEST_GET_CLIR
- *
- * Gets current CLIR status
- * "data" is NULL
- * "response" is int *
- * ((int *)data)[0] is "n" parameter from TS 27.007 7.7
- * ((int *)data)[1] is "m" parameter from TS 27.007 7.7
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  FDN_CHECK_FAILURE
- *  SYSTEM_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_GET_CLIR 31
-
-/**
- * RIL_REQUEST_SET_CLIR
- *
- * "data" is int *
- * ((int *)data)[0] is "n" parameter from TS 27.007 7.7
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  INVALID_ARGUMENTS
- *  SYSTEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SET_CLIR 32
-
-/**
- * RIL_REQUEST_QUERY_CALL_FORWARD_STATUS
- *
- * "data" is const RIL_CallForwardInfo *
- *
- * "response" is const RIL_CallForwardInfo **
- * "response" points to an array of RIL_CallForwardInfo *'s, one for
- * each distinct registered phone number.
- *
- * For example, if data is forwarded to +18005551212 and voice is forwarded
- * to +18005559999, then two separate RIL_CallForwardInfo's should be returned
- *
- * If, however, both data and voice are forwarded to +18005551212, then
- * a single RIL_CallForwardInfo can be returned with the service class
- * set to "data + voice = 3")
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  FDN_CHECK_FAILURE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
-
-
-/**
- * RIL_REQUEST_SET_CALL_FORWARD
- *
- * Configure call forward rule
- *
- * "data" is const RIL_CallForwardInfo *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_STATE
- *  FDN_CHECK_FAILURE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SET_CALL_FORWARD 34
-
-
-/**
- * RIL_REQUEST_QUERY_CALL_WAITING
- *
- * Query current call waiting state
- *
- * "data" is const int *
- * ((const int *)data)[0] is the TS 27.007 service class to query.
- * "response" is a const int *
- * ((const int *)response)[0] is 0 for "disabled" and 1 for "enabled"
- *
- * If ((const int *)response)[0] is = 1, then ((const int *)response)[1]
- * must follow, with the TS 27.007 service class bit vector of services
- * for which call waiting is enabled.
- *
- * For example, if ((const int *)response)[0]  is 1 and
- * ((const int *)response)[1] is 3, then call waiting is enabled for data
- * and voice and disabled for everything else
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  FDN_CHECK_FAILURE
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_QUERY_CALL_WAITING 35
-
-
-/**
- * RIL_REQUEST_SET_CALL_WAITING
- *
- * Configure current call waiting state
- *
- * "data" is const int *
- * ((const int *)data)[0] is 0 for "disabled" and 1 for "enabled"
- * ((const int *)data)[1] is the TS 27.007 service class bit vector of
- *                           services to modify
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_STATE
- *  FDN_CHECK_FAILURE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SET_CALL_WAITING 36
-
-/**
- * RIL_REQUEST_SMS_ACKNOWLEDGE
- *
- * Acknowledge successful or failed receipt of SMS previously indicated
- * via RIL_UNSOL_RESPONSE_NEW_SMS
- *
- * "data" is int *
- * ((int *)data)[0] is 1 on successful receipt
- *                  (basically, AT+CNMA=1 from TS 27.005
- *                  is 0 on failed receipt
- *                  (basically, AT+CNMA=2 from TS 27.005)
- * ((int *)data)[1] if data[0] is 0, this contains the failure cause as defined
- *                  in TS 23.040, 9.2.3.22. Currently only 0xD3 (memory
- *                  capacity exceeded) and 0xFF (unspecified error) are
- *                  reported.
- *
- * "response" is NULL
- *
- * FIXME would like request that specified RP-ACK/RP-ERROR PDU
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SMS_ACKNOWLEDGE  37
-
-/**
- * RIL_REQUEST_GET_IMEI - DEPRECATED
- *
- * Get the device IMEI, including check digit
- *
- * The request is DEPRECATED, use RIL_REQUEST_DEVICE_IDENTITY
- * Valid when RadioState is not RADIO_STATE_UNAVAILABLE
- *
- * "data" is NULL
- * "response" is a const char * containing the IMEI
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-
-#define RIL_REQUEST_GET_IMEI 38
-
-/**
- * RIL_REQUEST_GET_IMEISV - DEPRECATED
- *
- * Get the device IMEISV, which should be two decimal digits
- *
- * The request is DEPRECATED, use RIL_REQUEST_DEVICE_IDENTITY
- * Valid when RadioState is not RADIO_STATE_UNAVAILABLE
- *
- * "data" is NULL
- * "response" is a const char * containing the IMEISV
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-
-#define RIL_REQUEST_GET_IMEISV 39
-
-
-/**
- * RIL_REQUEST_ANSWER
- *
- * Answer incoming call
- *
- * Will not be called for WAITING calls.
- * RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE will be used in this case
- * instead
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_STATE
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_ANSWER 40
-
-/**
- * RIL_REQUEST_DEACTIVATE_DATA_CALL
- *
- * Deactivate packet data connection and remove from the
- * data call list if SUCCESS is returned. Any other return
- * values should also try to remove the call from the list,
- * but that may not be possible. In any event a
- * RIL_REQUEST_RADIO_POWER off/on must clear the list. An
- * RIL_UNSOL_DATA_CALL_LIST_CHANGED is not expected to be
- * issued because of an RIL_REQUEST_DEACTIVATE_DATA_CALL.
- *
- * "data" is const char **
- * ((char**)data)[0] indicating CID
- * ((char**)data)[1] indicating Disconnect Reason
- *                   0 => No specific reason specified
- *                   1 => Radio shutdown requested
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_CALL_ID
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  REQUEST_NOT_SUPPORTED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  SIM_ABSENT
- *
- * See also: RIL_REQUEST_SETUP_DATA_CALL
- */
-#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
-
-/**
- * RIL_REQUEST_QUERY_FACILITY_LOCK
- *
- * Query the status of a facility lock state
- *
- * "data" is const char **
- * ((const char **)data)[0] is the facility string code from TS 27.007 7.4
- *                      (eg "AO" for BAOC, "SC" for SIM lock)
- * ((const char **)data)[1] is the password, or "" if not required
- * ((const char **)data)[2] is the TS 27.007 service class bit vector of
- *                           services to query
- * ((const char **)data)[3] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *                            This is only applicable in the case of Fixed Dialing Numbers
- *                            (FDN) requests.
- *
- * "response" is an int *
- * ((const int *)response) 0 is the TS 27.007 service class bit vector of
- *                           services for which the specified barring facility
- *                           is active. "0" means "disabled for all"
- *
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  FDN_CHECK_FAILURE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
-
-/**
- * RIL_REQUEST_SET_FACILITY_LOCK
- *
- * Enable/disable one facility lock
- *
- * "data" is const char **
- *
- * ((const char **)data)[0] = facility string code from TS 27.007 7.4
- * (eg "AO" for BAOC)
- * ((const char **)data)[1] = "0" for "unlock" and "1" for "lock"
- * ((const char **)data)[2] = password
- * ((const char **)data)[3] = string representation of decimal TS 27.007
- *                            service class bit vector. Eg, the string
- *                            "1" means "set this facility for voice services"
- * ((const char **)data)[4] = AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
- *                            This is only applicable in the case of Fixed Dialing Numbers
- *                            (FDN) requests.
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  INVALID_ARGUMENTS
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  MODEM_ERR
- *  INVALID_STATE
- *  FDN_CHECK_FAILURE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_SET_FACILITY_LOCK 43
-
-/**
- * RIL_REQUEST_CHANGE_BARRING_PASSWORD
- *
- * Change call barring facility password
- *
- * "data" is const char **
- *
- * ((const char **)data)[0] = facility string code from TS 27.007 7.4
- * (eg "AO" for BAOC)
- * ((const char **)data)[1] = old password
- * ((const char **)data)[2] = new password
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  FDN_CHECK_FAILURE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
-
-/**
- * RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE
- *
- * Query current network selectin mode
- *
- * "data" is NULL
- *
- * "response" is int *
- * ((const int *)response)[0] is
- *     0 for automatic selection
- *     1 for manual selection
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
-
-/**
- * RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC
- *
- * Specify that the network should be selected automatically
- *
- * "data" is NULL
- * "response" is NULL
- *
- * This request must not respond until the new operator is selected
- * and registered
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  ILLEGAL_SIM_OR_ME
- *  OPERATION_NOT_ALLOWED
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- * Note: Returns ILLEGAL_SIM_OR_ME when the failure is permanent and
- *       no retries needed, such as illegal SIM or ME.
- *
- */
-#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
-
-/**
- * RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL
- *
- * Manually select a specified network.
- *
- * "data" is const char * specifying MCCMNC of network to select (eg "310170")
- * "response" is NULL
- *
- * This request must not respond until the new operator is selected
- * and registered
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  ILLEGAL_SIM_OR_ME
- *  OPERATION_NOT_ALLOWED
- *  INVALID_STATE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- * Note: Returns ILLEGAL_SIM_OR_ME when the failure is permanent and
- *       no retries needed, such as illegal SIM or ME.
- *
- */
-#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
-
-/**
- * RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
- *
- * Scans for available networks
- *
- * "data" is NULL
- * "response" is const char ** that should be an array of n*4 strings, where
- *    n is the number of available networks
- * For each available network:
- *
- * ((const char **)response)[n+0] is long alpha ONS or EONS
- * ((const char **)response)[n+1] is short alpha ONS or EONS
- * ((const char **)response)[n+2] is 5 or 6 digit numeric code (MCC + MNC)
- * ((const char **)response)[n+3] is a string value of the status:
- *           "unknown"
- *           "available"
- *           "current"
- *           "forbidden"
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  ABORTED
- *  DEVICE_IN_USE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  CANCELLED
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
-
-/**
- * RIL_REQUEST_DTMF_START
- *
- * Start playing a DTMF tone. Continue playing DTMF tone until
- * RIL_REQUEST_DTMF_STOP is received
- *
- * If a RIL_REQUEST_DTMF_START is received while a tone is currently playing,
- * it should cancel the previous tone and play the new one.
- *
- * "data" is a char *
- * ((char *)data)[0] is a single character with one of 12 values: 0-9,*,#
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_DTMF, RIL_REQUEST_DTMF_STOP
- */
-#define RIL_REQUEST_DTMF_START 49
-
-/**
- * RIL_REQUEST_DTMF_STOP
- *
- * Stop playing a currently playing DTMF tone.
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  NO_MEMORY
- *  INVALID_ARGUMENTS
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_DTMF, RIL_REQUEST_DTMF_START
- */
-#define RIL_REQUEST_DTMF_STOP 50
-
-/**
- * RIL_REQUEST_BASEBAND_VERSION
- *
- * Return string value indicating baseband version, eg
- * response from AT+CGMR
- *
- * "data" is NULL
- * "response" is const char * containing version string for log reporting
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  EMPTY_RECORD
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_BASEBAND_VERSION 51
-
-/**
- * RIL_REQUEST_SEPARATE_CONNECTION
- *
- * Separate a party from a multiparty call placing the multiparty call
- * (less the specified party) on hold and leaving the specified party
- * as the only other member of the current (active) call
- *
- * Like AT+CHLD=2x
- *
- * See TS 22.084 1.3.8.2 (iii)
- * TS 22.030 6.5.5 "Entering "2X followed by send"
- * TS 27.007 "AT+CHLD=2x"
- *
- * "data" is an int *
- * (int *)data)[0] contains Connection index (value of 'x' in CHLD above) "response" is NULL
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_ARGUMENTS
- *  INVALID_STATE
- *  NO_RESOURCES
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  INVALID_STATE
- *  OPERATION_NOT_ALLOWED
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SEPARATE_CONNECTION 52
-
-
-/**
- * RIL_REQUEST_SET_MUTE
- *
- * Turn on or off uplink (microphone) mute.
- *
- * Will only be sent while voice call is active.
- * Will always be reset to "disable mute" when a new voice call is initiated
- *
- * "data" is an int *
- * (int *)data)[0] is 1 for "enable mute" and 0 for "disable mute"
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_SET_MUTE 53
-
-/**
- * RIL_REQUEST_GET_MUTE
- *
- * Queries the current state of the uplink mute setting
- *
- * "data" is NULL
- * "response" is an int *
- * (int *)response)[0] is 1 for "mute enabled" and 0 for "mute disabled"
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  SS_MODIFIED_TO_DIAL
- *  SS_MODIFIED_TO_USSD
- *  SS_MODIFIED_TO_SS
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_GET_MUTE 54
-
-/**
- * RIL_REQUEST_QUERY_CLIP
- *
- * Queries the status of the CLIP supplementary service
- *
- * (for MMI code "*#30#")
- *
- * "data" is NULL
- * "response" is an int *
- * (int *)response)[0] is 1 for "CLIP provisioned"
- *                           and 0 for "CLIP not provisioned"
- *                           and 2 for "unknown, e.g. no network etc"
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  FDN_CHECK_FAILURE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_QUERY_CLIP 55
-
-/**
- * RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE - Deprecated use the status
- * field in RIL_Data_Call_Response_v6.
- *
- * Requests the failure cause code for the most recently failed PDP
- * context or CDMA data connection active
- * replaces RIL_REQUEST_LAST_PDP_FAIL_CAUSE
- *
- * "data" is NULL
- *
- * "response" is a "int *"
- * ((int *)response)[0] is an integer cause code defined in TS 24.008
- *   section 6.1.3.1.3 or close approximation
- *
- * If the implementation does not have access to the exact cause codes,
- * then it should return one of the values listed in
- * RIL_DataCallFailCause, as the UI layer needs to distinguish these
- * cases for error notification
- * and potential retries.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_LAST_CALL_FAIL_CAUSE
- *
- * Deprecated use the status field in RIL_Data_Call_Response_v6.
- */
-
-#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
-
-/**
- * RIL_REQUEST_DATA_CALL_LIST
- *
- * Returns the data call list. An entry is added when a
- * RIL_REQUEST_SETUP_DATA_CALL is issued and removed on a
- * RIL_REQUEST_DEACTIVATE_DATA_CALL. The list is emptied
- * when RIL_REQUEST_RADIO_POWER off/on is issued.
- *
- * "data" is NULL
- * "response" is an array of RIL_Data_Call_Response_v6
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- * See also: RIL_UNSOL_DATA_CALL_LIST_CHANGED
- */
-
-#define RIL_REQUEST_DATA_CALL_LIST 57
-
-/**
- * RIL_REQUEST_RESET_RADIO - DEPRECATED
- *
- * Request a radio reset. The RIL implementation may postpone
- * the reset until after this request is responded to if the baseband
- * is presently busy.
- *
- * The request is DEPRECATED, use RIL_REQUEST_RADIO_POWER
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_RESET_RADIO 58
-
-/**
- * RIL_REQUEST_OEM_HOOK_RAW
- *
- * This request reserved for OEM-specific uses. It passes raw byte arrays
- * back and forth.
- *
- * It can be invoked on the Java side from
- * com.android.internal.telephony.Phone.invokeOemRilRequestRaw()
- *
- * "data" is a char * of bytes copied from the byte[] data argument in java
- * "response" is a char * of bytes that will returned via the
- * caller's "response" Message here:
- * (byte[])(((AsyncResult)response.obj).result)
- *
- * An error response here will result in
- * (((AsyncResult)response.obj).result) == null and
- * (((AsyncResult)response.obj).exception) being an instance of
- * com.android.internal.telephony.gsm.CommandException
- *
- * Valid errors:
- *  All
- */
-
-#define RIL_REQUEST_OEM_HOOK_RAW 59
-
-/**
- * RIL_REQUEST_OEM_HOOK_STRINGS
- *
- * This request reserved for OEM-specific uses. It passes strings
- * back and forth.
- *
- * It can be invoked on the Java side from
- * com.android.internal.telephony.Phone.invokeOemRilRequestStrings()
- *
- * "data" is a const char **, representing an array of null-terminated UTF-8
- * strings copied from the "String[] strings" argument to
- * invokeOemRilRequestStrings()
- *
- * "response" is a const char **, representing an array of null-terminated UTF-8
- * stings that will be returned via the caller's response message here:
- *
- * (String[])(((AsyncResult)response.obj).result)
- *
- * An error response here will result in
- * (((AsyncResult)response.obj).result) == null and
- * (((AsyncResult)response.obj).exception) being an instance of
- * com.android.internal.telephony.gsm.CommandException
- *
- * Valid errors:
- *  All
- */
-
-#define RIL_REQUEST_OEM_HOOK_STRINGS 60
-
-/**
- * RIL_REQUEST_SCREEN_STATE - DEPRECATED
- *
- * Indicates the current state of the screen.  When the screen is off, the
- * RIL should notify the baseband to suppress certain notifications (eg,
- * signal strength and changes in LAC/CID or BID/SID/NID/latitude/longitude)
- * in an effort to conserve power.  These notifications should resume when the
- * screen is on.
- *
- * Note this request is deprecated. Use RIL_REQUEST_SEND_DEVICE_STATE to report the device state
- * to the modem and use RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER to turn on/off unsolicited
- * response from the modem in different scenarios.
- *
- * "data" is int *
- * ((int *)data)[0] is == 1 for "Screen On"
- * ((int *)data)[0] is == 0 for "Screen Off"
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SCREEN_STATE 61
-
-
-/**
- * RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION
- *
- * Enables/disables supplementary service related notifications
- * from the network.
- *
- * Notifications are reported via RIL_UNSOL_SUPP_SVC_NOTIFICATION.
- *
- * "data" is int *
- * ((int *)data)[0] is == 1 for notifications enabled
- * ((int *)data)[0] is == 0 for notifications disabled
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SIM_BUSY
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_UNSOL_SUPP_SVC_NOTIFICATION.
- */
-#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
-
-/**
- * RIL_REQUEST_WRITE_SMS_TO_SIM
- *
- * Stores a SMS message to SIM memory.
- *
- * "data" is RIL_SMS_WriteArgs *
- *
- * "response" is int *
- * ((const int *)response)[0] is the record index where the message is stored.
- *
- * Valid errors:
- *  SUCCESS
- *  SIM_FULL
- *  INVALID_ARGUMENTS
- *  INVALID_SMS_FORMAT
- *  INTERNAL_ERR
- *  MODEM_ERR
- *  ENCODING_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  INVALID_MODEM_STATE
- *  OPERATION_NOT_ALLOWED
- *  INVALID_SMSC_ADDRESS
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- */
-#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
-
-/**
- * RIL_REQUEST_DELETE_SMS_ON_SIM
- *
- * Deletes a SMS message from SIM memory.
- *
- * "data" is int  *
- * ((int *)data)[0] is the record index of the message to delete.
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  SIM_FULL
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NO_SUCH_ENTRY
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- */
-#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
-
-/**
- * RIL_REQUEST_SET_BAND_MODE
- *
- * Assign a specified band for RF configuration.
- *
- * "data" is int *
- * ((int *)data)[0] is a RIL_RadioBandMode
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- * See also: RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE
- */
-#define RIL_REQUEST_SET_BAND_MODE 65
-
-/**
- * RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE
- *
- * Query the list of band mode supported by RF.
- *
- * "data" is NULL
- *
- * "response" is int *
- * "response" points to an array of int's, the int[0] is the size of array;
- * subsequent values are a list of RIL_RadioBandMode listing supported modes.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- * See also: RIL_REQUEST_SET_BAND_MODE
- */
-#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
-
-/**
- * RIL_REQUEST_STK_GET_PROFILE
- *
- * Requests the profile of SIM tool kit.
- * The profile indicates the SAT/USAT features supported by ME.
- * The SAT/USAT features refer to 3GPP TS 11.14 and 3GPP TS 31.111
- *
- * "data" is NULL
- *
- * "response" is a const char * containing SAT/USAT profile
- * in hexadecimal format string starting with first byte of terminal profile
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_STK_GET_PROFILE 67
-
-/**
- * RIL_REQUEST_STK_SET_PROFILE
- *
- * Download the STK terminal profile as part of SIM initialization
- * procedure
- *
- * "data" is a const char * containing SAT/USAT profile
- * in hexadecimal format string starting with first byte of terminal profile
- *
- * "response" is NULL
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_STK_SET_PROFILE 68
-
-/**
- * RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND
- *
- * Requests to send a SAT/USAT envelope command to SIM.
- * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111
- *
- * "data" is a const char * containing SAT/USAT command
- * in hexadecimal format string starting with command tag
- *
- * "response" is a const char * containing SAT/USAT response
- * in hexadecimal format string starting with first byte of response
- * (May be NULL)
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
- *  SIM_BUSY
- *  OPERATION_NOT_ALLOWED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
-
-/**
- * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE
- *
- * Requests to send a terminal response to SIM for a received
- * proactive command
- *
- * "data" is a const char * containing SAT/USAT response
- * in hexadecimal format string starting with first byte of response data
- *
- * "response" is NULL
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
- *  RIL_E_OPERATION_NOT_ALLOWED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
-
-/**
- * RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM
- *
- * When STK application gets RIL_UNSOL_STK_CALL_SETUP, the call actually has
- * been initialized by ME already. (We could see the call has been in the 'call
- * list') So, STK application needs to accept/reject the call according as user
- * operations.
- *
- * "data" is int *
- * ((int *)data)[0] is > 0 for "accept" the call setup
- * ((int *)data)[0] is == 0 for "reject" the call setup
- *
- * "response" is NULL
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
- *  RIL_E_OPERATION_NOT_ALLOWED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
-
-/**
- * RIL_REQUEST_EXPLICIT_CALL_TRANSFER
- *
- * Connects the two calls and disconnects the subscriber from both calls.
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  INVALID_STATE
- *  NO_RESOURCES
- *  NO_MEMORY
- *  INVALID_ARGUMENTS
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  INVALID_STATE
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
-
-/**
- * RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
- *
- * Requests to set the preferred network type for searching and registering
- * (CS/PS domain, RAT, and operation mode)
- *
- * "data" is int * which is RIL_PreferredNetworkType
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  OPERATION_NOT_ALLOWED
- *  MODE_NOT_SUPPORTED
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
-
-/**
- * RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE
- *
- * Query the preferred network type (CS/PS domain, RAT, and operation mode)
- * for searching and registering
- *
- * "data" is NULL
- *
- * "response" is int *
- * ((int *)reponse)[0] is == RIL_PreferredNetworkType
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- * See also: RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
- */
-#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
-
-/**
- * RIL_REQUEST_NEIGHBORING_CELL_IDS
- *
- * Request neighboring cell id in GSM network
- *
- * "data" is NULL
- * "response" must be a " const RIL_NeighboringCell** "
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NO_NETWORK_FOUND
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
-
-/**
- * RIL_REQUEST_SET_LOCATION_UPDATES
- *
- * Enables/disables network state change notifications due to changes in
- * LAC and/or CID (for GSM) or BID/SID/NID/latitude/longitude (for CDMA).
- * Basically +CREG=2 vs. +CREG=1 (TS 27.007).
- *
- * Note:  The RIL implementation should default to "updates enabled"
- * when the screen is on and "updates disabled" when the screen is off.
- *
- * "data" is int *
- * ((int *)data)[0] is == 1 for updates enabled (+CREG=2)
- * ((int *)data)[0] is == 0 for updates disabled (+CREG=1)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- * See also: RIL_REQUEST_SCREEN_STATE, RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED
- */
-#define RIL_REQUEST_SET_LOCATION_UPDATES 76
-
-/**
- * RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE
- *
- * Request to set the location where the CDMA subscription shall
- * be retrieved
- *
- * "data" is int *
- * ((int *)data)[0] is == RIL_CdmaSubscriptionSource
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SIM_ABSENT
- *  SUBSCRIPTION_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE
- */
-#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
-
-/**
- * RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE
- *
- * Request to set the roaming preferences in CDMA
- *
- * "data" is int *
- * ((int *)data)[0] is == 0 for Home Networks only, as defined in PRL
- * ((int *)data)[0] is == 1 for Roaming on Affiliated networks, as defined in PRL
- * ((int *)data)[0] is == 2 for Roaming on Any Network, as defined in the PRL
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
-
-/**
- * RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE
- *
- * Request the actual setting of the roaming preferences in CDMA in the modem
- *
- * "data" is NULL
- *
- * "response" is int *
- * ((int *)response)[0] is == 0 for Home Networks only, as defined in PRL
- * ((int *)response)[0] is == 1 for Roaming on Affiliated networks, as defined in PRL
- * ((int *)response)[0] is == 2 for Roaming on Any Network, as defined in the PRL
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
-
-/**
- * RIL_REQUEST_SET_TTY_MODE
- *
- * Request to set the TTY mode
- *
- * "data" is int *
- * ((int *)data)[0] is == 0 for TTY off
- * ((int *)data)[0] is == 1 for TTY Full
- * ((int *)data)[0] is == 2 for TTY HCO (hearing carryover)
- * ((int *)data)[0] is == 3 for TTY VCO (voice carryover)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SET_TTY_MODE 80
-
-/**
- * RIL_REQUEST_QUERY_TTY_MODE
- *
- * Request the setting of TTY mode
- *
- * "data" is NULL
- *
- * "response" is int *
- * ((int *)response)[0] is == 0 for TTY off
- * ((int *)response)[0] is == 1 for TTY Full
- * ((int *)response)[0] is == 2 for TTY HCO (hearing carryover)
- * ((int *)response)[0] is == 3 for TTY VCO (voice carryover)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_QUERY_TTY_MODE 81
-
-/**
- * RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE
- *
- * Request to set the preferred voice privacy mode used in voice
- * scrambling
- *
- * "data" is int *
- * ((int *)data)[0] is == 0 for Standard Privacy Mode (Public Long Code Mask)
- * ((int *)data)[0] is == 1 for Enhanced Privacy Mode (Private Long Code Mask)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  INVALID_CALL_ID
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
-
-/**
- * RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE
- *
- * Request the setting of preferred voice privacy mode
- *
- * "data" is NULL
- *
- * "response" is int *
- * ((int *)response)[0] is == 0 for Standard Privacy Mode (Public Long Code Mask)
- * ((int *)response)[0] is == 1 for Enhanced Privacy Mode (Private Long Code Mask)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
-
-/**
- * RIL_REQUEST_CDMA_FLASH
- *
- * Send FLASH
- *
- * "data" is const char *
- * ((const char *)data)[0] is a FLASH string
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  INVALID_STATE
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_CDMA_FLASH 84
-
-/**
- * RIL_REQUEST_CDMA_BURST_DTMF
- *
- * Send DTMF string
- *
- * "data" is const char **
- * ((const char **)data)[0] is a DTMF string
- * ((const char **)data)[1] is the DTMF ON length in milliseconds, or 0 to use
- *                          default
- * ((const char **)data)[2] is the DTMF OFF length in milliseconds, or 0 to use
- *                          default
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  INVALID_CALL_ID
- *  NO_RESOURCES
- *  CANCELLED
- *  OPERATION_NOT_ALLOWED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_CDMA_BURST_DTMF 85
-
-/**
- * RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY
- *
- * Takes a 26 digit string (20 digit AKEY + 6 digit checksum).
- * If the checksum is valid the 20 digit AKEY is written to NV,
- * replacing the existing AKEY no matter what it was before.
- *
- * "data" is const char *
- * ((const char *)data)[0] is a 26 digit string (ASCII digits '0'-'9')
- *                         where the last 6 digits are a checksum of the
- *                         first 20, as specified in TR45.AHAG
- *                         "Common Cryptographic Algorithms, Revision D.1
- *                         Section 2.2"
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
-
-/**
- * RIL_REQUEST_CDMA_SEND_SMS
- *
- * Send a CDMA SMS message
- *
- * "data" is const RIL_CDMA_SMS_Message *
- *
- * "response" is a const RIL_SMS_Response *
- *
- * Based on the return error, caller decides to resend if sending sms
- * fails. The CDMA error class is derived as follows,
- * SUCCESS is error class 0 (no error)
- * SMS_SEND_FAIL_RETRY is error class 2 (temporary failure)
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SMS_SEND_FAIL_RETRY
- *  NETWORK_REJECT
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  INVALID_SMS_FORMAT
- *  SYSTEM_ERR
- *  FDN_CHECK_FAILURE
- *  MODEM_ERR
- *  NETWORK_ERR
- *  ENCODING_ERR
- *  INVALID_SMSC_ADDRESS
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  MODE_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- */
-#define RIL_REQUEST_CDMA_SEND_SMS 87
-
-/**
- * RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE
- *
- * Acknowledge the success or failure in the receipt of SMS
- * previously indicated via RIL_UNSOL_RESPONSE_CDMA_NEW_SMS
- *
- * "data" is const RIL_CDMA_SMS_Ack *
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  NO_SMS_TO_ACK
- *  INVALID_STATE
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INVALID_STATE
- *  OPERATION_NOT_ALLOWED
- *  NETWORK_NOT_READY
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
-
-/**
- * RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG
- *
- * Request the setting of GSM/WCDMA Cell Broadcast SMS config.
- *
- * "data" is NULL
- *
- * "response" is a const RIL_GSM_BroadcastSmsConfigInfo **
- * "responselen" is count * sizeof (RIL_GSM_BroadcastSmsConfigInfo *)
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_STATE
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  SYSTEM_ERR
- *  NO_RESOURCES
- *  MODEM_ERR
- *  SYSTEM_ERR
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
-
-/**
- * RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG
- *
- * Set GSM/WCDMA Cell Broadcast SMS config
- *
- * "data" is a const RIL_GSM_BroadcastSmsConfigInfo **
- * "datalen" is count * sizeof(RIL_GSM_BroadcastSmsConfigInfo *)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
- *  MODEM_ERR
- *  SYSTEM_ERR
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
-
-/**
- * RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION
- *
-* Enable or disable the reception of GSM/WCDMA Cell Broadcast SMS
- *
- * "data" is const int *
- * (const int *)data[0] indicates to activate or turn off the
- * reception of GSM/WCDMA Cell Broadcast SMS, 0-1,
- *                       0 - Activate, 1 - Turn off
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
-*   MODEM_ERR
-*   INTERNAL_ERR
-*   NO_RESOURCES
-*   CANCELLED
-*   INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
-
-/**
- * RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG
- *
- * Request the setting of CDMA Broadcast SMS config
- *
- * "data" is NULL
- *
- * "response" is a const RIL_CDMA_BroadcastSmsConfigInfo **
- * "responselen" is count * sizeof (RIL_CDMA_BroadcastSmsConfigInfo *)
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_STATE
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  SYSTEM_ERR
- *  NO_RESOURCES
- *  MODEM_ERR
- *  SYSTEM_ERR
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
-
-/**
- * RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG
- *
- * Set CDMA Broadcast SMS config
- *
- * "data" is a const RIL_CDMA_BroadcastSmsConfigInfo **
- * "datalen" is count * sizeof(const RIL_CDMA_BroadcastSmsConfigInfo *)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
- *  MODEM_ERR
- *  SYSTEM_ERR
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
-
-/**
- * RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION
- *
- * Enable or disable the reception of CDMA Broadcast SMS
- *
- * "data" is const int *
- * (const int *)data[0] indicates to activate or turn off the
- * reception of CDMA Broadcast SMS, 0-1,
- *                       0 - Activate, 1 - Turn off
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
-
-/**
- * RIL_REQUEST_CDMA_SUBSCRIPTION
- *
- * Request the device MDN / H_SID / H_NID.
- *
- * The request is only allowed when CDMA subscription is available.  When CDMA
- * subscription is changed, application layer should re-issue the request to
- * update the subscription information.
- *
- * If a NULL value is returned for any of the device id, it means that error
- * accessing the device.
- *
- * "response" is const char **
- * ((const char **)response)[0] is MDN if CDMA subscription is available
- * ((const char **)response)[1] is a comma separated list of H_SID (Home SID) if
- *                              CDMA subscription is available, in decimal format
- * ((const char **)response)[2] is a comma separated list of H_NID (Home NID) if
- *                              CDMA subscription is available, in decimal format
- * ((const char **)response)[3] is MIN (10 digits, MIN2+MIN1) if CDMA subscription is available
- * ((const char **)response)[4] is PRL version if CDMA subscription is available
- *
- * Valid errors:
- *  SUCCESS
- *  RIL_E_SUBSCRIPTION_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-
-#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
-
-/**
- * RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM
- *
- * Stores a CDMA SMS message to RUIM memory.
- *
- * "data" is RIL_CDMA_SMS_WriteArgs *
- *
- * "response" is int *
- * ((const int *)response)[0] is the record index where the message is stored.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SIM_FULL
- *  INVALID_ARGUMENTS
- *  INVALID_SMS_FORMAT
- *  INTERNAL_ERR
- *  MODEM_ERR
- *  ENCODING_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  INVALID_MODEM_STATE
- *  OPERATION_NOT_ALLOWED
- *  INVALID_SMSC_ADDRESS
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- */
-#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
-
-/**
- * RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM
- *
- * Deletes a CDMA SMS message from RUIM memory.
- *
- * "data" is int  *
- * ((int *)data)[0] is the record index of the message to delete.
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NO_SUCH_ENTRY
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- */
-#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
-
-/**
- * RIL_REQUEST_DEVICE_IDENTITY
- *
- * Request the device ESN / MEID / IMEI / IMEISV.
- *
- * The request is always allowed and contains GSM and CDMA device identity;
- * it substitutes the deprecated requests RIL_REQUEST_GET_IMEI and
- * RIL_REQUEST_GET_IMEISV.
- *
- * If a NULL value is returned for any of the device id, it means that error
- * accessing the device.
- *
- * When CDMA subscription is changed the ESN/MEID may change.  The application
- * layer should re-issue the request to update the device identity in this case.
- *
- * "response" is const char **
- * ((const char **)response)[0] is IMEI if GSM subscription is available
- * ((const char **)response)[1] is IMEISV if GSM subscription is available
- * ((const char **)response)[2] is ESN if CDMA subscription is available
- * ((const char **)response)[3] is MEID if CDMA subscription is available
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_DEVICE_IDENTITY 98
-
-/**
- * RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE
- *
- * Request the radio's system selection module to exit emergency
- * callback mode.  RIL will not respond with SUCCESS until the modem has
- * completely exited from Emergency Callback Mode.
- *
- * "data" is NULL
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
-
-/**
- * RIL_REQUEST_GET_SMSC_ADDRESS
- *
- * Queries the default Short Message Service Center address on the device.
- *
- * "data" is NULL
- *
- * "response" is const char * containing the SMSC address.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  SYSTEM_ERR
- *  INTERNAL_ERR
- *  MODEM_ERR
- *  INVALID_ARGUMENTS
- *  INVALID_MODEM_STATE
- *  NOT_PROVISIONED
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- *
- */
-#define RIL_REQUEST_GET_SMSC_ADDRESS 100
-
-/**
- * RIL_REQUEST_SET_SMSC_ADDRESS
- *
- * Sets the default Short Message Service Center address on the device.
- *
- * "data" is const char * containing the SMSC address.
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  INVALID_SMS_FORMAT
- *  NO_MEMORY
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
- *  MODEM_ERR
- *  NO_RESOURCES
- *  INTERNAL_ERR
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- */
-#define RIL_REQUEST_SET_SMSC_ADDRESS 101
-
-/**
- * RIL_REQUEST_REPORT_SMS_MEMORY_STATUS
- *
- * Indicates whether there is storage available for new SMS messages.
- *
- * "data" is int *
- * ((int *)data)[0] is 1 if memory is available for storing new messages
- *                  is 0 if memory capacity is exceeded
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  INVALID_STATE
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
- *  MODEM_ERR
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
-
-/**
- * RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING
- *
- * Indicates that the StkSerivce is running and is
- * ready to receive RIL_UNSOL_STK_XXXXX commands.
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
-
-/**
- * RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE
- *
- * Request to query the location where the CDMA subscription shall
- * be retrieved
- *
- * "data" is NULL
- *
- * "response" is int *
- * ((int *)data)[0] is == RIL_CdmaSubscriptionSource
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SUBSCRIPTION_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- * See also: RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE
- */
-#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
-
-/**
- * RIL_REQUEST_ISIM_AUTHENTICATION
- *
- * Request the ISIM application on the UICC to perform AKA
- * challenge/response algorithm for IMS authentication
- *
- * "data" is a const char * containing the challenge string in Base64 format
- * "response" is a const char * containing the response in Base64 format
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_ISIM_AUTHENTICATION 105
-
-/**
- * RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU
- *
- * Acknowledge successful or failed receipt of SMS previously indicated
- * via RIL_UNSOL_RESPONSE_NEW_SMS, including acknowledgement TPDU to send
- * as the RP-User-Data element of the RP-ACK or RP-ERROR PDU.
- *
- * "data" is const char **
- * ((const char **)data)[0] is "1" on successful receipt (send RP-ACK)
- *                          is "0" on failed receipt (send RP-ERROR)
- * ((const char **)data)[1] is the acknowledgement TPDU in hexadecimal format
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
-
-/**
- * RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS
- *
- * Requests to send a SAT/USAT envelope command to SIM.
- * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111.
- *
- * This request has one difference from RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND:
- * the SW1 and SW2 status bytes from the UICC response are returned along with
- * the response data, using the same structure as RIL_REQUEST_SIM_IO.
- *
- * The RIL implementation shall perform the normal processing of a '91XX'
- * response in SW1/SW2 to retrieve the pending proactive command and send it
- * as an unsolicited response, as RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND does.
- *
- * "data" is a const char * containing the SAT/USAT command
- * in hexadecimal format starting with command tag
- *
- * "response" is a const RIL_SIM_IO_Response *
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
- *  SIM_BUSY
- *  OPERATION_NOT_ALLOWED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- */
-#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
-
-/**
- * RIL_REQUEST_VOICE_RADIO_TECH
- *
- * Query the radio technology type (3GPP/3GPP2) used for voice. Query is valid only
- * when radio state is not RADIO_STATE_UNAVAILABLE
- *
- * "data" is NULL
- * "response" is int *
- * ((int *) response)[0] is of type const RIL_RadioTechnology
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_VOICE_RADIO_TECH 108
-
-/**
- * RIL_REQUEST_GET_CELL_INFO_LIST
- *
- * Request all of the current cell information known to the radio. The radio
- * must a list of all current cells, including the neighboring cells. If for a particular
- * cell information isn't known then the appropriate unknown value will be returned.
- * This does not cause or change the rate of RIL_UNSOL_CELL_INFO_LIST.
- *
- * "data" is NULL
- *
- * "response" is an array of  RIL_CellInfo_v12.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  NO_NETWORK_FOUND
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_GET_CELL_INFO_LIST 109
-
-/**
- * RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE
- *
- * Sets the minimum time between when RIL_UNSOL_CELL_INFO_LIST should be invoked.
- * A value of 0, means invoke RIL_UNSOL_CELL_INFO_LIST when any of the reported
- * information changes. Setting the value to INT_MAX(0x7fffffff) means never issue
- * a RIL_UNSOL_CELL_INFO_LIST.
- *
- * "data" is int *
- * ((int *)data)[0] is minimum time in milliseconds
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
-
-/**
- * RIL_REQUEST_SET_INITIAL_ATTACH_APN
- *
- * Set an apn to initial attach network
- *
- * "data" is a const char **
- * ((const char **)data)[0] is the APN to connect if radio technology is LTE
- * ((const char **)data)[1] is the connection type to request must be one of the
- *                          PDP_type values in TS 27.007 section 10.1.1.
- *                          For example, "IP", "IPV6", "IPV4V6", or "PPP".
- * ((const char **)data)[2] is the PAP / CHAP auth type. Values:
- *                          0 => PAP and CHAP is never performed.
- *                          1 => PAP may be performed; CHAP is never performed.
- *                          2 => CHAP may be performed; PAP is never performed.
- *                          3 => PAP / CHAP may be performed - baseband dependent.
- * ((const char **)data)[3] is the username for APN, or NULL
- * ((const char **)data)[4] is the password for APN, or NULL
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  SUBSCRIPTION_NOT_AVAILABLE
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  NOT_PROVISIONED
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
-
-/**
- * RIL_REQUEST_IMS_REGISTRATION_STATE
- *
- * This message is DEPRECATED and shall be removed in a future release (target: 2018);
- * instead, provide IMS registration status via an IMS Service.
- *
- * Request current IMS registration state
- *
- * "data" is NULL
- *
- * "response" is int *
- * ((int *)response)[0] is registration state:
- *              0 - Not registered
- *              1 - Registered
- *
- * If ((int*)response)[0] is = 1, then ((int *) response)[1]
- * must follow with IMS SMS format:
- *
- * ((int *) response)[1] is of type RIL_RadioTechnologyFamily
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
-
-/**
- * RIL_REQUEST_IMS_SEND_SMS
- *
- * Send a SMS message over IMS
- *
- * "data" is const RIL_IMS_SMS_Message *
- *
- * "response" is a const RIL_SMS_Response *
- *
- * Based on the return error, caller decides to resend if sending sms
- * fails. SMS_SEND_FAIL_RETRY means retry, and other errors means no retry.
- * In case of retry, data is encoded based on Voice Technology available.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SMS_SEND_FAIL_RETRY
- *  FDN_CHECK_FAILURE
- *  NETWORK_REJECT
- *  INVALID_ARGUMENTS
- *  INVALID_STATE
- *  NO_MEMORY
- *  INVALID_SMS_FORMAT
- *  SYSTEM_ERR
- *  REQUEST_RATE_LIMITED
- *  MODEM_ERR
- *  NETWORK_ERR
- *  ENCODING_ERR
- *  INVALID_SMSC_ADDRESS
- *  OPERATION_NOT_ALLOWED
- *  INTERNAL_ERR
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_IMS_SEND_SMS 113
-
-/**
- * RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC
- *
- * Request APDU exchange on the basic channel. This command reflects TS 27.007
- * "generic SIM access" operation (+CSIM). The modem must ensure proper function
- * of GSM/CDMA, and filter commands appropriately. It should filter
- * channel management and SELECT by DF name commands.
- *
- * "data" is a const RIL_SIM_APDU *
- * "sessionid" field should be ignored.
- *
- * "response" is a const RIL_SIM_IO_Response *
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
-
-/**
- * RIL_REQUEST_SIM_OPEN_CHANNEL
- *
- * Open a new logical channel and select the given application. This command
- * reflects TS 27.007 "open logical channel" operation (+CCHO). This request
- * also specifies the P2 parameter (described in ISO 7816-4).
- *
- * "data" is a const RIL_OpenChannelParam *
- *
- * "response" is int *
- * ((int *)data)[0] contains the session id of the logical channel.
- * ((int *)data)[1] onwards may optionally contain the select response for the
- *     open channel command with one byte per integer.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  MISSING_RESOURCE
- *  NO_SUCH_ELEMENT
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  SIM_ERR
- *  INVALID_SIM_STATE
- *  MISSING_RESOURCE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
-
-/**
- * RIL_REQUEST_SIM_CLOSE_CHANNEL
- *
- * Close a previously opened logical channel. This command reflects TS 27.007
- * "close logical channel" operation (+CCHC).
- *
- * "data" is int *
- * ((int *)data)[0] is the session id of logical the channel to close.
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
-
-/**
- * RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL
- *
- * Exchange APDUs with a UICC over a previously opened logical channel. This
- * command reflects TS 27.007 "generic logical channel access" operation
- * (+CGLA). The modem should filter channel management and SELECT by DF name
- * commands.
- *
- * "data" is a const RIL_SIM_APDU*
- *
- * "response" is a const RIL_SIM_IO_Response *
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
-
-/**
- * RIL_REQUEST_NV_READ_ITEM
- *
- * Read one of the radio NV items defined in RadioNVItems.java / ril_nv_items.h.
- * This is used for device configuration by some CDMA operators.
- *
- * "data" is a const RIL_NV_ReadItem *
- *
- * "response" is const char * containing the contents of the NV item
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_NV_READ_ITEM 118
-
-/**
- * RIL_REQUEST_NV_WRITE_ITEM
- *
- * Write one of the radio NV items defined in RadioNVItems.java / ril_nv_items.h.
- * This is used for device configuration by some CDMA operators.
- *
- * "data" is a const RIL_NV_WriteItem *
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_NV_WRITE_ITEM 119
-
-/**
- * RIL_REQUEST_NV_WRITE_CDMA_PRL
- *
- * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
- * This is used for device configuration by some CDMA operators.
- *
- * "data" is a const char * containing the PRL as a byte array
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
-
-/**
- * RIL_REQUEST_NV_RESET_CONFIG
- *
- * Reset the radio NV configuration to the factory state.
- * This is used for device configuration by some CDMA operators.
- *
- * "data" is int *
- * ((int *)data)[0] is 1 to reload all NV items
- * ((int *)data)[0] is 2 for erase NV reset (SCRTN)
- * ((int *)data)[0] is 3 for factory reset (RTN)
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_NV_RESET_CONFIG 121
-
- /** RIL_REQUEST_SET_UICC_SUBSCRIPTION
- * FIXME This API needs to have more documentation.
- *
- * Selection/de-selection of a subscription from a SIM card
- * "data" is const  RIL_SelectUiccSub*
-
- *
- * "response" is NULL
- *
- *  Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  SUBSCRIPTION_NOT_SUPPORTED
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_SET_UICC_SUBSCRIPTION  122
-
-/**
- *  RIL_REQUEST_ALLOW_DATA
- *
- *  Tells the modem whether data calls are allowed or not
- *
- * "data" is int *
- * FIXME slotId and aid will be added.
- * ((int *)data)[0] is == 0 to allow data calls
- * ((int *)data)[0] is == 1 to disallow data calls
- *
- * "response" is NULL
- *
- *  Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  MODEM_ERR
- *  INVALID_ARGUMENTS
- *  DEVICE_IN_USE
- *  INVALID_MODEM_STATE
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_ALLOW_DATA  123
-
-/**
- * RIL_REQUEST_GET_HARDWARE_CONFIG
- *
- * Request all of the current hardware (modem and sim) associated
- * with the RIL.
- *
- * "data" is NULL
- *
- * "response" is an array of  RIL_HardwareConfig.
- *
- * Valid errors:
- * RADIO_NOT_AVAILABLE
- * REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
-
-/**
- * RIL_REQUEST_SIM_AUTHENTICATION
- *
- * Returns the response of SIM Authentication through RIL to a
- * challenge request.
- *
- * "data" Base64 encoded string containing challenge:
- *      int   authContext;          P2 value of authentication command, see P2 parameter in
- *                                  3GPP TS 31.102 7.1.2
- *      char *authData;             the challenge string in Base64 format, see 3GPP
- *                                  TS 31.102 7.1.2
- *      char *aid;                  AID value, See ETSI 102.221 8.1 and 101.220 4,
- *                                  NULL if no value
- *
- * "response" Base64 encoded strings containing response:
- *      int   sw1;                  Status bytes per 3GPP TS 31.102 section 7.3
- *      int   sw2;
- *      char *simResponse;          Response in Base64 format, see 3GPP TS 31.102 7.1.2
- *
- *  Valid errors:
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  INVALID_MODEM_STATE
- *  INVALID_ARGUMENTS
- *  SIM_ERR
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_SIM_AUTHENTICATION 125
-
-/**
- * RIL_REQUEST_GET_DC_RT_INFO
- *
- * The request is DEPRECATED, use RIL_REQUEST_GET_ACTIVITY_INFO
- * Requests the Data Connection Real Time Info
- *
- * "data" is NULL
- *
- * "response" is the most recent RIL_DcRtInfo
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  REQUEST_NOT_SUPPORTED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *
- * See also: RIL_UNSOL_DC_RT_INFO_CHANGED
- */
-#define RIL_REQUEST_GET_DC_RT_INFO 126
-
-/**
- * RIL_REQUEST_SET_DC_RT_INFO_RATE
- *
- * The request is DEPRECATED
- * This is the minimum number of milliseconds between successive
- * RIL_UNSOL_DC_RT_INFO_CHANGED messages and defines the highest rate
- * at which RIL_UNSOL_DC_RT_INFO_CHANGED's will be sent. A value of
- * 0 means send as fast as possible.
- *
- * "data" The number of milliseconds as an int
- *
- * "response" is null
- *
- * Valid errors:
- *  SUCCESS must not fail
- */
-#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
-
-/**
- * RIL_REQUEST_SET_DATA_PROFILE
- *
- * Set data profile in modem
- * Modem should erase existed profiles from framework, and apply new profiles
- * "data" is a const RIL_DataProfileInfo **
- * "datalen" is count * sizeof(const RIL_DataProfileInfo *)
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  SUBSCRIPTION_NOT_AVAILABLE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- */
-#define RIL_REQUEST_SET_DATA_PROFILE 128
-
-/**
- * RIL_REQUEST_SHUTDOWN
- *
- * Device is shutting down. All further commands are ignored
- * and RADIO_NOT_AVAILABLE must be returned.
- *
- * "data" is null
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SHUTDOWN 129
-
-/**
- * RIL_REQUEST_GET_RADIO_CAPABILITY
- *
- * Used to get phone radio capablility.
- *
- * "data" is the RIL_RadioCapability structure
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  INVALID_STATE
- *  REQUEST_NOT_SUPPORTED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
-
-/**
- * RIL_REQUEST_SET_RADIO_CAPABILITY
- *
- * Used to set the phones radio capability. Be VERY careful
- * using this request as it may cause some vendor modems to reset. Because
- * of the possible modem reset any RIL commands after this one may not be
- * processed.
- *
- * "data" is the RIL_RadioCapability structure
- *
- * "response" is the RIL_RadioCapability structure, used to feedback return status
- *
- * Valid errors:
- *  SUCCESS means a RIL_UNSOL_RADIO_CAPABILITY will be sent within 30 seconds.
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  MODEM_ERR
- *  INVALID_STATE
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
-
-/**
- * RIL_REQUEST_START_LCE
- *
- * Start Link Capacity Estimate (LCE) service if supported by the radio.
- *
- * "data" is const int *
- * ((const int*)data)[0] specifies the desired reporting interval (ms).
- * ((const int*)data)[1] specifies the LCE service mode. 1: PULL; 0: PUSH.
- *
- * "response" is the RIL_LceStatusInfo.
- *
- * Valid errors:
- * SUCCESS
- * RADIO_NOT_AVAILABLE
- * LCE_NOT_SUPPORTED
- * INTERNAL_ERR
- * REQUEST_NOT_SUPPORTED
- * NO_MEMORY
- * NO_RESOURCES
- * CANCELLED
- * SIM_ABSENT
- */
-#define RIL_REQUEST_START_LCE 132
-
-/**
- * RIL_REQUEST_STOP_LCE
- *
- * Stop Link Capacity Estimate (LCE) service, the STOP operation should be
- * idempotent for the radio modem.
- *
- * "response" is the RIL_LceStatusInfo.
- *
- * Valid errors:
- * SUCCESS
- * RADIO_NOT_AVAILABLE
- * LCE_NOT_SUPPORTED
- * INTERNAL_ERR
- * NO_MEMORY
- * NO_RESOURCES
- * CANCELLED
- * REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- */
-#define RIL_REQUEST_STOP_LCE 133
-
-/**
- * RIL_REQUEST_PULL_LCEDATA
- *
- * Pull LCE service for capacity information.
- *
- * "response" is the RIL_LceDataInfo.
- *
- * Valid errors:
- * SUCCESS
- * RADIO_NOT_AVAILABLE
- * LCE_NOT_SUPPORTED
- * INTERNAL_ERR
- * NO_MEMORY
- * NO_RESOURCES
- * CANCELLED
- * REQUEST_NOT_SUPPORTED
- *  SIM_ABSENT
- */
-#define RIL_REQUEST_PULL_LCEDATA 134
-
-/**
- * RIL_REQUEST_GET_ACTIVITY_INFO
- *
- * Get modem activity information for power consumption estimation.
- *
- * Request clear-on-read statistics information that is used for
- * estimating the per-millisecond power consumption of the cellular
- * modem.
- *
- * "data" is null
- * "response" is const RIL_ActivityStatsInfo *
- *
- * Valid errors:
- *
- * SUCCESS
- * RADIO_NOT_AVAILABLE (radio resetting)
- * NO_MEMORY
- * INTERNAL_ERR
- * SYSTEM_ERR
- * MODEM_ERR
- * NOT_PROVISIONED
- * REQUEST_NOT_SUPPORTED
- * NO_RESOURCES CANCELLED
- */
-#define RIL_REQUEST_GET_ACTIVITY_INFO 135
-
-/**
- * RIL_REQUEST_SET_CARRIER_RESTRICTIONS
- *
- * Set carrier restrictions for this sim slot. Expected modem behavior:
- *  If never receives this command
- *  - Must allow all carriers
- *  Receives this command with data being NULL
- *  - Must allow all carriers. If a previously allowed SIM is present, modem must not reload
- *    the SIM. If a previously disallowed SIM is present, reload the SIM and notify Android.
- *  Receives this command with a list of carriers
- *  - Only allow specified carriers, persist across power cycles and FDR. If a present SIM
- *    is in the allowed list, modem must not reload the SIM. If a present SIM is *not* in
- *    the allowed list, modem must detach from the registered network and only keep emergency
- *    service, and notify Android SIM refresh reset with new SIM state being
- *    RIL_CARDSTATE_RESTRICTED. Emergency service must be enabled.
- *
- * "data" is const RIL_CarrierRestrictions *
- * A list of allowed carriers and possibly a list of excluded carriers.
- * If data is NULL, means to clear previous carrier restrictions and allow all carriers
- *
- * "response" is int *
- * ((int *)data)[0] contains the number of allowed carriers which have been set correctly.
- * On success, it should match the length of list data->allowed_carriers.
- * If data is NULL, the value must be 0.
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_INVALID_ARGUMENTS
- *  RIL_E_RADIO_NOT_AVAILABLE
- *  RIL_E_REQUEST_NOT_SUPPORTED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SET_CARRIER_RESTRICTIONS 136
-
-/**
- * RIL_REQUEST_GET_CARRIER_RESTRICTIONS
- *
- * Get carrier restrictions for this sim slot. Expected modem behavior:
- *  Return list of allowed carriers, or null if all carriers are allowed.
- *
- * "data" is NULL
- *
- * "response" is const RIL_CarrierRestrictions *.
- * If response is NULL, it means all carriers are allowed.
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE
- *  RIL_E_REQUEST_NOT_SUPPORTED
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_GET_CARRIER_RESTRICTIONS 137
-
-/**
- * RIL_REQUEST_SEND_DEVICE_STATE
- *
- * Send the updated device state.
- * Modem can perform power saving based on the provided device state.
- * "data" is const int *
- * ((const int*)data)[0] A RIL_DeviceStateType that specifies the device state type.
- * ((const int*)data)[1] Specifies the state. See RIL_DeviceStateType for the definition of each
- *                       type.
- *
- * "datalen" is count * sizeof(const RIL_DeviceState *)
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  INVALID_ARGUMENTS
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SEND_DEVICE_STATE 138
-
-/**
- * RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER
- *
- * Set the unsolicited response filter
- * This is used to prevent unnecessary application processor
- * wake up for power saving purposes by suppressing the
- * unsolicited responses in certain scenarios.
- *
- * "data" is an int *
- *
- * ((int *)data)[0] is a 32-bit bitmask of RIL_UnsolicitedResponseFilter
- *
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  INVALID_ARGUMENTS (e.g. the requested filter doesn't exist)
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  NO_MEMORY
- *  INTERNAL_ERR
- *  SYSTEM_ERR
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER 139
-
- /**
-  * RIL_REQUEST_SET_SIM_CARD_POWER
-  *
-  * Set SIM card power up or down
-  *
-  * Request is equivalent to inserting and removing the card, with
-  * an additional effect where the ability to detect card removal/insertion
-  * is disabled when the SIM card is powered down.
-  *
-  * This will generate RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
-  * as if the SIM had been inserted or removed.
-  *
-  * "data" is int *
-  * ((int *)data)[0] is 1 for "SIM POWER UP"
-  * ((int *)data)[0] is 0 for "SIM POWER DOWN"
-  *
-  * "response" is NULL
-  *
-  * Valid errors:
-  *  SUCCESS
-  *  RADIO_NOT_AVAILABLE
-  *  REQUEST_NOT_SUPPORTED
-  *  SIM_ABSENT
-  *  INVALID_ARGUMENTS
-  *  INTERNAL_ERR
-  *  NO_MEMORY
-  *  NO_RESOURCES
-  *  CANCELLED
-  */
-#define RIL_REQUEST_SET_SIM_CARD_POWER 140
-
-/**
- * RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION
- *
- * Provide Carrier specific information to the modem that will be used to
- * encrypt the IMSI and IMPI. Sent by the framework during boot, carrier
- * switch and everytime we receive a new certificate.
- *
- * "data" is the RIL_CarrierInfoForImsiEncryption * structure.
- *
- * "response" is NULL
- *
- * Valid errors:
- *  RIL_E_SUCCESS
- *  RIL_E_RADIO_NOT_AVAILABLE
- *  SIM_ABSENT
- *  RIL_E_REQUEST_NOT_SUPPORTED
- *  INVALID_ARGUMENTS
- *  MODEM_INTERNAL_FAILURE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- */
-#define RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION 141
-
-/**
- * RIL_REQUEST_START_NETWORK_SCAN
- *
- * Starts a new network scan
- *
- * Request to start a network scan with specified radio access networks with frequency bands and/or
- * channels.
- *
- * "data" is a const RIL_NetworkScanRequest *.
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  OPERATION_NOT_ALLOWED
- *  DEVICE_IN_USE
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  MODEM_ERR
- *  INVALID_ARGUMENTS
- *  REQUEST_NOT_SUPPORTED
- *  NO_RESOURCES
- *  CANCELLED
- *
- */
-#define RIL_REQUEST_START_NETWORK_SCAN 142
-
-/**
- * RIL_REQUEST_STOP_NETWORK_SCAN
- *
- * Stops an ongoing network scan
- *
- * Request to stop the ongoing network scan. Since the modem can only perform one scan at a time,
- * there is no parameter for this request.
- *
- * "data" is NULL
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  INTERNAL_ERR
- *  MODEM_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *
- */
-#define RIL_REQUEST_STOP_NETWORK_SCAN 143
-
-/**
- * RIL_REQUEST_START_KEEPALIVE
- *
- * Start a keepalive session
- *
- * Request that the modem begin sending keepalive packets on a particular
- * data call, with a specified source, destination, and format.
- *
- * "data" is a const RIL_RequestKeepalive
- * "response" is RIL_KeepaliveStatus with a valid "handle"
- *
- * Valid errors:
- *  SUCCESS
- *  NO_RESOURCES
- *  INVALID_ARGUMENTS
- *
- */
-#define RIL_REQUEST_START_KEEPALIVE 144
-
-/**
- * RIL_REQUEST_STOP_KEEPALIVE
- *
- * Stops an ongoing keepalive session
- *
- * Requests that a keepalive session with the given handle be stopped.
- * there is no parameter for this request.
- *
- * "data" is an integer handle
- * "response" is NULL
- *
- * Valid errors:
- *  SUCCESS
- *  INVALID_ARGUMENTS
- *
- */
-#define RIL_REQUEST_STOP_KEEPALIVE 145
-
-/**
- * RIL_REQUEST_GET_MODEM_STACK_STATUS
- *
- * Request status of a logical modem
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  MODEM_ERR
- *
- */
-#define RIL_REQUEST_GET_MODEM_STACK_STATUS 146
-
-/**
- * @param info Response info struct containing response type, serial no. and error
- * @param networkTypeBitmap a 32-bit bitmap of RadioAccessFamily.
- *
- * Valid errors returned:
- *   RadioError:NONE
- *   RadioError:RADIO_NOT_AVAILABLE
- *   RadioError:INTERNAL_ERR
- *   RadioError:INVALID_ARGUMENTS
- *   RadioError:MODEM_ERR
- *   RadioError:REQUEST_NOT_SUPPORTED
- *   RadioError:NO_RESOURCES
- */
-#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP 147
-
-/**
- * Callback of IRadio.setPreferredNetworkTypeBitmap(int, bitfield<RadioAccessFamily>)
- *
- * @param info Response info struct containing response type, serial no. and error
- *
- * Valid errors returned:
- *   RadioError:NONE
- *   RadioError:RADIO_NOT_AVAILABLE
- *   RadioError:OPERATION_NOT_ALLOWED
- *   RadioError:MODE_NOT_SUPPORTED
- *   RadioError:INTERNAL_ERR
- *   RadioError:INVALID_ARGUMENTS
- *   RadioError:MODEM_ERR
- *   RadioError:REQUEST_NOT_SUPPORTED
- *   RadioError:NO_RESOURCES
- */
-#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP 148
-
-/**
- * RIL_REQUEST_EMERGENCY_DIAL
- *
- * Initiate emergency voice call, with zero or more emergency service category(s), zero or
- * more emergency Uniform Resource Names (URN), and routing information for handling the call.
- * Android uses this request to make its emergency call instead of using @1.0::IRadio.dial
- * if the 'address' in the 'dialInfo' field is identified as an emergency number by Android.
- *
- * In multi-sim scenario, if the emergency number is from a specific subscription, this radio
- * request is sent through the IRadio service that serves the subscription, no matter of the
- * PUK/PIN state of the subscription and the service state of the radio.
- *
- * Some countries or carriers require some emergency numbers that must be handled with normal
- * call routing or emergency routing. If the 'routing' field is specified as
- * @1.4::EmergencyNumberRouting#NORMAL, the implementation must use normal call routing to
- * handle the call; if it is specified as @1.4::EmergencyNumberRouting#EMERGENCY, the
- * implementation must use emergency routing to handle the call; if it is
- * @1.4::EmergencyNumberRouting#UNKNOWN, Android does not know how to handle the call.
- *
- * If the dialed emergency number does not have a specified emergency service category, the
- * 'categories' field is set to @1.4::EmergencyServiceCategory#UNSPECIFIED; if the dialed
- * emergency number does not have specified emergency Uniform Resource Names, the 'urns' field
- * is set to an empty list. If the underlying technology used to request emergency services
- * does not support the emergency service category or emergency uniform resource names, the
- * field 'categories' or 'urns' may be ignored.
- *
- * 'fromEmergencyDialer' indicates if this request originated from emergency dialer/shortcut,
- * which means an explicit intent from the user to dial an emergency number. The modem must
- * treat this as an actual emergency dial and not try to disambiguate.
- *
- * If 'isTesting' is true, this request is for testing purpose, and must not be sent to a real
- * emergency service; otherwise it's for a real emergency call request.
- * Valid errors:
- *  NONE
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  DIAL_MODIFIED_TO_USSD
- *  DIAL_MODIFIED_TO_SS
- *  DIAL_MODIFIED_TO_DIAL
- *  INVALID_ARGUMENTS
- *  NO_RESOURCES
- *  INTERNAL_ERR
- *  FDN_CHECK_FAILURE
- *  MODEM_ERR
- *  NO_SUBSCRIPTION
- *  NO_NETWORK_FOUND
- *  INVALID_CALL_ID
- *  DEVICE_IN_USE
- *  ABORTED
- *  INVALID_MODEM_STATE
- */
-#define RIL_REQUEST_EMERGENCY_DIAL 149
-
-/**
- * Specify which bands modem's background scan must act on.
- * If specifyChannels is true, it only scans bands specified in specifiers.
- * If specifyChannels is false, it scans all bands.
- *
- * For example, CBRS is only on LTE band 48. By specifying this band,
- * modem saves more power.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  INTERNAL_ERR
- *
- */
-#define RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS 150
-
-/**
- * RIL_REQUEST_ENABLE_MODEM
- *
- * Enable a logical modem
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  MODEM_ERR
- *
- */
-#define RIL_REQUEST_ENABLE_MODEM 151
-
-/**
- * RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA
- *
- * Sets the signal strength reporting criteria.
- *
- * The resulting reporting rules are the AND of all the supplied criteria. For each RAN
- * The hysteresisDb apply to only the following measured quantities:
- * -GERAN    - RSSI
- * -CDMA2000 - RSSI
- * -UTRAN    - RSCP
- * -EUTRAN   - RSRP/RSRQ/RSSNR
- *
- * The thresholds apply to only the following measured quantities:
- * -GERAN    - RSSI
- * -CDMA2000 - RSSI
- * -UTRAN    - RSCP
- * -EUTRAN   - RSRP/RSRQ/RSSNR
- * -NGRAN    - SSRSRP/SSRSRQ/SSSINR
- *
- * Note: Reporting criteria must be individually set for each RAN. For any unset reporting
- * criteria, the value is implementation-defined.
- *
- * Note: @1.5::SignalThresholdInfo includes fields 'hysteresisDb', 'hysteresisMs',
- * and 'thresholds'. As this mechanism generally only constrains reports based on one
- * measured quantity per RAN, if multiple measured quantities must be used to trigger a report
- * for a given RAN, the only valid field may be hysteresisMs: hysteresisDb and thresholds must
- * be set to zero and length zero respectively. If either hysteresisDb or thresholds is set,
- * then reports shall only be triggered by the respective measured quantity, subject to the
- * applied constraints.
- *
- * Valid errors returned:
- *   RadioError:NONE
- *   RadioError:INVALID_ARGUMENTS
- *   RadioError:RADIO_NOT_AVAILABLE
- */
-#define RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA 152
-
-/**
- * RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA
- *
- * Sets the link capacity reporting criteria. The resulting reporting criteria are the AND of
- * all the supplied criteria.
- *
- * Note: Reporting criteria ust be individually set for each RAN. If unset, reporting criteria
- * for that RAN are implementation-defined.
- *
- * Valid errors returned:
- *   RadioError:NONE
- *   RadioError:INVALID_ARGUMENTS
- *   RadioError:RADIO_NOT_AVAILABLE
- *   RadioError:INTERNAL_ERR
- */
-#define RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA 153
-
-/**
- * RIL_REQUEST_ENABLE_UICC_APPLICATIONS
- *
- * Enable or disable uicc applications.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SIM_ABSENT
- *  INTERNAL_ERR
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_ENABLE_UICC_APPLICATIONS 154
-
-/**
- * RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED
- *
- * Whether uicc applications are enabled.
- *
- * Response: a boolean of enable or not.
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SIM_ABSENT
- *  INTERNAL_ERR
- *  REQUEST_NOT_SUPPORTED
- */
-#define RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED 155
-
-/**
- * RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION
- *
- * Requests that sim personlization be deactivated
- *
- * "data" is const char **
- * ((const char **)(data))[0]] is  sim depersonlization code
- *
- * "response" is int *
- * ((int *)response)[0] is the number of retries remaining,
- * or -1 if number of retries are infinite.
- *
- * Valid errors:
- *
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE (radio resetting)
- *  PASSWORD_INCORRECT
- *  SIM_ABSENT (code is invalid)
- *  INTERNAL_ERR
- *  NO_MEMORY
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- */
-
-#define RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION 156
-
-/**
- * RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE
- *
- * Send a CDMA SMS message
- *
- * "data" is const RIL_CDMA_SMS_Message *
- *
- * "response" is a const RIL_SMS_Response *
- *
- * Based on the return error, caller decides to resend if sending sms
- * fails. The CDMA error class is derived as follows,
- * SUCCESS is error class 0 (no error)
- * SMS_SEND_FAIL_RETRY is error class 2 (temporary failure)
- *
- * Valid errors:
- *  SUCCESS
- *  RADIO_NOT_AVAILABLE
- *  SMS_SEND_FAIL_RETRY
- *  NETWORK_REJECT
- *  INVALID_STATE
- *  INVALID_ARGUMENTS
- *  NO_MEMORY
- *  REQUEST_RATE_LIMITED
- *  INVALID_SMS_FORMAT
- *  SYSTEM_ERR
- *  FDN_CHECK_FAILURE
- *  MODEM_ERR
- *  NETWORK_ERR
- *  ENCODING_ERR
- *  INVALID_SMSC_ADDRESS
- *  OPERATION_NOT_ALLOWED
- *  NO_RESOURCES
- *  CANCELLED
- *  REQUEST_NOT_SUPPORTED
- *  MODE_NOT_SUPPORTED
- *  SIM_ABSENT
- */
-#define RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE 157
-
-/***********************************************************************/
-
-/**
- * RIL_RESPONSE_ACKNOWLEDGEMENT
- *
- * This is used by Asynchronous solicited messages and Unsolicited messages
- * to acknowledge the receipt of those messages in RIL.java so that the ack
- * can be used to let ril.cpp to release wakelock.
- *
- * Valid errors
- * SUCCESS
- * RADIO_NOT_AVAILABLE
- */
-
-#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
-
-/***********************************************************************/
-
-
-#define RIL_UNSOL_RESPONSE_BASE 1000
-
-/**
- * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
- *
- * Indicate when value of RIL_RadioState has changed.
- *
- * Callee will invoke RIL_RadioStateRequest method on main thread
- *
- * "data" is NULL
- */
-
-#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
-
-
-/**
- * RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED
- *
- * Indicate when call state has changed
- *
- * Callee will invoke RIL_REQUEST_GET_CURRENT_CALLS on main thread
- *
- * "data" is NULL
- *
- * Response should be invoked on, for example,
- * "RING", "BUSY", "NO CARRIER", and also call state
- * transitions (DIALING->ALERTING ALERTING->ACTIVE)
- *
- * Redundent or extraneous invocations are tolerated
- */
-#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
-
-
-/**
- * RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
- *
- * Called when the voice network state changed
- *
- * Callee will invoke the following requests on main thread:
- *
- * RIL_REQUEST_VOICE_REGISTRATION_STATE
- * RIL_REQUEST_OPERATOR
- *
- * "data" is NULL
- *
- * FIXME should this happen when SIM records are loaded? (eg, for
- * EONS)
- */
-#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
-
-/**
- * RIL_UNSOL_RESPONSE_NEW_SMS
- *
- * Called when new SMS is received.
- *
- * "data" is const char *
- * This is a pointer to a string containing the PDU of an SMS-DELIVER
- * as an ascii string of hex digits. The PDU starts with the SMSC address
- * per TS 27.005 (+CMT:)
- *
- * Callee will subsequently confirm the receipt of thei SMS with a
- * RIL_REQUEST_SMS_ACKNOWLEDGE
- *
- * No new RIL_UNSOL_RESPONSE_NEW_SMS
- * or RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT messages should be sent until a
- * RIL_REQUEST_SMS_ACKNOWLEDGE has been received
- */
-
-#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
-
-/**
- * RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT
- *
- * Called when new SMS Status Report is received.
- *
- * "data" is const char *
- * This is a pointer to a string containing the PDU of an SMS-STATUS-REPORT
- * as an ascii string of hex digits. The PDU starts with the SMSC address
- * per TS 27.005 (+CDS:).
- *
- * Callee will subsequently confirm the receipt of the SMS with a
- * RIL_REQUEST_SMS_ACKNOWLEDGE
- *
- * No new RIL_UNSOL_RESPONSE_NEW_SMS
- * or RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT messages should be sent until a
- * RIL_REQUEST_SMS_ACKNOWLEDGE has been received
- */
-
-#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
-
-/**
- * RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM
- *
- * Called when new SMS has been stored on SIM card
- *
- * "data" is const int *
- * ((const int *)data)[0] contains the slot index on the SIM that contains
- * the new message
- */
-
-#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
-
-/**
- * RIL_UNSOL_ON_USSD
- *
- * Called when a new USSD message is received.
- *
- * "data" is const char **
- * ((const char **)data)[0] points to a type code, which is
- *  one of these string values:
- *      "0"   USSD-Notify -- text in ((const char **)data)[1]
- *      "1"   USSD-Request -- text in ((const char **)data)[1]
- *      "2"   Session terminated by network
- *      "3"   other local client (eg, SIM Toolkit) has responded
- *      "4"   Operation not supported
- *      "5"   Network timeout
- *
- * The USSD session is assumed to persist if the type code is "1", otherwise
- * the current session (if any) is assumed to have terminated.
- *
- * ((const char **)data)[1] points to a message string if applicable, which
- * should always be in UTF-8.
- */
-#define RIL_UNSOL_ON_USSD 1006
-/* Previously #define RIL_UNSOL_ON_USSD_NOTIFY 1006   */
-
-/**
- * RIL_UNSOL_ON_USSD_REQUEST
- *
- * Obsolete. Send via RIL_UNSOL_ON_USSD
- */
-#define RIL_UNSOL_ON_USSD_REQUEST 1007
-
-/**
- * RIL_UNSOL_NITZ_TIME_RECEIVED
- *
- * Called when radio has received a NITZ time message
- *
- * "data" is const char * pointing to NITZ time string
- * in the form "yy/mm/dd,hh:mm:ss(+/-)tz,dt"
- */
-#define RIL_UNSOL_NITZ_TIME_RECEIVED  1008
-
-/**
- * RIL_UNSOL_SIGNAL_STRENGTH
- *
- * Radio may report signal strength rather han have it polled.
- *
- * "data" is a const RIL_SignalStrength *
- */
-#define RIL_UNSOL_SIGNAL_STRENGTH  1009
-
-
-/**
- * RIL_UNSOL_DATA_CALL_LIST_CHANGED
- *
- * "data" is an array of RIL_Data_Call_Response_v6 identical to that
- * returned by RIL_REQUEST_DATA_CALL_LIST. It is the complete list
- * of current data contexts including new contexts that have been
- * activated. A data call is only removed from this list when the
- * framework sends a RIL_REQUEST_DEACTIVATE_DATA_CALL or the radio
- * is powered off/on.
- *
- * See also: RIL_REQUEST_DATA_CALL_LIST
- */
-
-#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
-
-/**
- * RIL_UNSOL_SUPP_SVC_NOTIFICATION
- *
- * Reports supplementary service related notification from the network.
- *
- * "data" is a const RIL_SuppSvcNotification *
- *
- */
-
-#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
-
-/**
- * RIL_UNSOL_STK_SESSION_END
- *
- * Indicate when STK session is terminated by SIM.
- *
- * "data" is NULL
- */
-#define RIL_UNSOL_STK_SESSION_END 1012
-
-/**
- * RIL_UNSOL_STK_PROACTIVE_COMMAND
- *
- * Indicate when SIM issue a STK proactive command to applications
- *
- * "data" is a const char * containing SAT/USAT proactive command
- * in hexadecimal format string starting with command tag
- *
- */
-#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
-
-/**
- * RIL_UNSOL_STK_EVENT_NOTIFY
- *
- * Indicate when SIM notifies applcations some event happens.
- * Generally, application does not need to have any feedback to
- * SIM but shall be able to indicate appropriate messages to users.
- *
- * "data" is a const char * containing SAT/USAT commands or responses
- * sent by ME to SIM or commands handled by ME, in hexadecimal format string
- * starting with first byte of response data or command tag
- *
- */
-#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
-
-/**
- * RIL_UNSOL_STK_CALL_SETUP
- *
- * Indicate when SIM wants application to setup a voice call.
- *
- * "data" is const int *
- * ((const int *)data)[0] contains timeout value (in milliseconds)
- */
-#define RIL_UNSOL_STK_CALL_SETUP 1015
-
-/**
- * RIL_UNSOL_SIM_SMS_STORAGE_FULL
- *
- * Indicates that SMS storage on the SIM is full.  Sent when the network
- * attempts to deliver a new SMS message.  Messages cannot be saved on the
- * SIM until space is freed.  In particular, incoming Class 2 messages
- * cannot be stored.
- *
- * "data" is null
- *
- */
-#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
-
-/**
- * RIL_UNSOL_SIM_REFRESH
- *
- * Indicates that file(s) on the SIM have been updated, or the SIM
- * has been reinitialized.
- *
- * In the case where RIL is version 6 or older:
- * "data" is an int *
- * ((int *)data)[0] is a RIL_SimRefreshResult.
- * ((int *)data)[1] is the EFID of the updated file if the result is
- * SIM_FILE_UPDATE or NULL for any other result.
- *
- * In the case where RIL is version 7:
- * "data" is a RIL_SimRefreshResponse_v7 *
- *
- * Note: If the SIM state changes as a result of the SIM refresh (eg,
- * SIM_READY -> SIM_LOCKED_OR_ABSENT), RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
- * should be sent.
- */
-#define RIL_UNSOL_SIM_REFRESH 1017
-
-/**
- * RIL_UNSOL_CALL_RING
- *
- * Ring indication for an incoming call (eg, RING or CRING event).
- * There must be at least one RIL_UNSOL_CALL_RING at the beginning
- * of a call and sending multiple is optional. If the system property
- * ro.telephony.call_ring.multiple is false then the upper layers
- * will generate the multiple events internally. Otherwise the vendor
- * ril must generate multiple RIL_UNSOL_CALL_RING if
- * ro.telephony.call_ring.multiple is true or if it is absent.
- *
- * The rate of these events is controlled by ro.telephony.call_ring.delay
- * and has a default value of 3000 (3 seconds) if absent.
- *
- * "data" is null for GSM
- * "data" is const RIL_CDMA_SignalInfoRecord * if CDMA
- */
-#define RIL_UNSOL_CALL_RING 1018
-
-/**
- * RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
- *
- * Indicates that SIM state changes.
- *
- * Callee will invoke RIL_REQUEST_GET_SIM_STATUS on main thread
-
- * "data" is null
- */
-#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
-
-/**
- * RIL_UNSOL_RESPONSE_CDMA_NEW_SMS
- *
- * Called when new CDMA SMS is received
- *
- * "data" is const RIL_CDMA_SMS_Message *
- *
- * Callee will subsequently confirm the receipt of the SMS with
- * a RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE
- *
- * No new RIL_UNSOL_RESPONSE_CDMA_NEW_SMS should be sent until
- * RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE has been received
- *
- */
-#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
-
-/**
- * RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS
- *
- * Called when new Broadcast SMS is received
- *
- * "data" can be one of the following:
- * If received from GSM network, "data" is const char of 88 bytes
- * which indicates each page of a CBS Message sent to the MS by the
- * BTS as coded in 3GPP 23.041 Section 9.4.1.2.
- * If received from UMTS network, "data" is const char of 90 up to 1252
- * bytes which contain between 1 and 15 CBS Message pages sent as one
- * packet to the MS by the BTS as coded in 3GPP 23.041 Section 9.4.2.2.
- *
- */
-#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
-
-/**
- * RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL
- *
- * Indicates that SMS storage on the RUIM is full.  Messages
- * cannot be saved on the RUIM until space is freed.
- *
- * "data" is null
- *
- */
-#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
-
-/**
- * RIL_UNSOL_RESTRICTED_STATE_CHANGED
- *
- * Indicates a restricted state change (eg, for Domain Specific Access Control).
- *
- * Radio need send this msg after radio off/on cycle no matter it is changed or not.
- *
- * "data" is an int *
- * ((int *)data)[0] contains a bitmask of RIL_RESTRICTED_STATE_* values.
- */
-#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
-
-/**
- * RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE
- *
- * Indicates that the radio system selection module has
- * autonomously entered emergency callback mode.
- *
- * "data" is null
- *
- */
-#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
-
-/**
- * RIL_UNSOL_CDMA_CALL_WAITING
- *
- * Called when CDMA radio receives a call waiting indication.
- *
- * "data" is const RIL_CDMA_CallWaiting *
- *
- */
-#define RIL_UNSOL_CDMA_CALL_WAITING 1025
-
-/**
- * RIL_UNSOL_CDMA_OTA_PROVISION_STATUS
- *
- * Called when CDMA radio receives an update of the progress of an
- * OTASP/OTAPA call.
- *
- * "data" is const int *
- *  For CDMA this is an integer OTASP/OTAPA status listed in
- *  RIL_CDMA_OTA_ProvisionStatus.
- *
- */
-#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
-
-/**
- * RIL_UNSOL_CDMA_INFO_REC
- *
- * Called when CDMA radio receives one or more info recs.
- *
- * "data" is const RIL_CDMA_InformationRecords *
- *
- */
-#define RIL_UNSOL_CDMA_INFO_REC 1027
-
-/**
- * RIL_UNSOL_OEM_HOOK_RAW
- *
- * This is for OEM specific use.
- *
- * "data" is a byte[]
- */
-#define RIL_UNSOL_OEM_HOOK_RAW 1028
-
-/**
- * RIL_UNSOL_RINGBACK_TONE
- *
- * Indicates that nework doesn't have in-band information,  need to
- * play out-band tone.
- *
- * "data" is an int *
- * ((int *)data)[0] == 0 for stop play ringback tone.
- * ((int *)data)[0] == 1 for start play ringback tone.
- */
-#define RIL_UNSOL_RINGBACK_TONE 1029
-
-/**
- * RIL_UNSOL_RESEND_INCALL_MUTE
- *
- * Indicates that framework/application need reset the uplink mute state.
- *
- * There may be situations where the mute state becomes out of sync
- * between the application and device in some GSM infrastructures.
- *
- * "data" is null
- */
-#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
-
-/**
- * RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED
- *
- * Called when CDMA subscription source changed.
- *
- * "data" is int *
- * ((int *)data)[0] is == RIL_CdmaSubscriptionSource
- */
-#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
-
-/**
- * RIL_UNSOL_CDMA_PRL_CHANGED
- *
- * Called when PRL (preferred roaming list) changes.
- *
- * "data" is int *
- * ((int *)data)[0] is PRL_VERSION as would be returned by RIL_REQUEST_CDMA_SUBSCRIPTION
- */
-#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
-
-/**
- * RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE
- *
- * Called when Emergency Callback Mode Ends
- *
- * Indicates that the radio system selection module has
- * proactively exited emergency callback mode.
- *
- * "data" is NULL
- *
- */
-#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
-
-/**
- * RIL_UNSOL_RIL_CONNECTED
- *
- * Called the ril connects and returns the version
- *
- * "data" is int *
- * ((int *)data)[0] is RIL_VERSION
- */
-#define RIL_UNSOL_RIL_CONNECTED 1034
-
-/**
- * RIL_UNSOL_VOICE_RADIO_TECH_CHANGED
- *
- * Indicates that voice technology has changed. Contains new radio technology
- * as a data in the message.
- *
- * "data" is int *
- * ((int *)data)[0] is of type const RIL_RadioTechnology
- *
- */
-#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
-
-/**
- * RIL_UNSOL_CELL_INFO_LIST
- *
- * Same information as returned by RIL_REQUEST_GET_CELL_INFO_LIST, but returned
- * at the rate no greater than specified by RIL_REQUEST_SET_UNSOL_CELL_INFO_RATE.
- *
- * "data" is NULL
- *
- * "response" is an array of RIL_CellInfo_v12.
- */
-#define RIL_UNSOL_CELL_INFO_LIST 1036
-
-/**
- * RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED
- *
- * This message is DEPRECATED and shall be removed in a future release (target: 2018);
- * instead, provide IMS registration status via an IMS Service.
- *
- * Called when IMS registration state has changed
- *
- * To get IMS registration state and IMS SMS format, callee needs to invoke the
- * following request on main thread:
- *
- * RIL_REQUEST_IMS_REGISTRATION_STATE
- *
- * "data" is NULL
- *
- */
-#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
-
-/**
- * RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED
- *
- * Indicated when there is a change in subscription status.
- * This event will be sent in the following scenarios
- *  - subscription readiness at modem, which was selected by telephony layer
- *  - when subscription is deactivated by modem due to UICC card removal
- *  - When network invalidates the subscription i.e. attach reject due to authentication reject
- *
- * "data" is const int *
- * ((const int *)data)[0] == 0 for Subscription Deactivated
- * ((const int *)data)[0] == 1 for Subscription Activated
- *
- */
-#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
-
-/**
- * RIL_UNSOL_SRVCC_STATE_NOTIFY
- *
- * Called when Single Radio Voice Call Continuity(SRVCC)
- * progress state has changed
- *
- * "data" is int *
- * ((int *)data)[0] is of type const RIL_SrvccState
- *
- */
-
-#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
-
-/**
- * RIL_UNSOL_HARDWARE_CONFIG_CHANGED
- *
- * Called when the hardware configuration associated with the RILd changes
- *
- * "data" is an array of RIL_HardwareConfig
- *
- */
-#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
-
-/**
- * RIL_UNSOL_DC_RT_INFO_CHANGED
- *
- * The message is DEPRECATED, use RIL_REQUEST_GET_ACTIVITY_INFO
- * Sent when the DC_RT_STATE changes but the time
- * between these messages must not be less than the
- * value set by RIL_REQUEST_SET_DC_RT_RATE.
- *
- * "data" is the most recent RIL_DcRtInfo
- *
- */
-#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
-
-/**
- * RIL_UNSOL_RADIO_CAPABILITY
- *
- * Sent when RIL_REQUEST_SET_RADIO_CAPABILITY completes.
- * Returns the phone radio capability exactly as
- * RIL_REQUEST_GET_RADIO_CAPABILITY and should be the
- * same set as sent by RIL_REQUEST_SET_RADIO_CAPABILITY.
- *
- * "data" is the RIL_RadioCapability structure
- */
-#define RIL_UNSOL_RADIO_CAPABILITY 1042
-
-/*
- * RIL_UNSOL_ON_SS
- *
- * Called when SS response is received when DIAL/USSD/SS is changed to SS by
- * call control.
- *
- * "data" is const RIL_StkCcUnsolSsResponse *
- *
- */
-#define RIL_UNSOL_ON_SS 1043
-
-/**
- * RIL_UNSOL_STK_CC_ALPHA_NOTIFY
- *
- * Called when there is an ALPHA from UICC during Call Control.
- *
- * "data" is const char * containing ALPHA string from UICC in UTF-8 format.
- *
- */
-#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
-
-/**
- * RIL_UNSOL_LCEDATA_RECV
- *
- * Called when there is an incoming Link Capacity Estimate (LCE) info report.
- *
- * "data" is the RIL_LceDataInfo structure.
- *
- */
-#define RIL_UNSOL_LCEDATA_RECV 1045
-
- /**
-  * RIL_UNSOL_PCO_DATA
-  *
-  * Called when there is new Carrier PCO data received for a data call.  Ideally
-  * only new data will be forwarded, though this is not required.  Multiple
-  * boxes of carrier PCO data for a given call should result in a series of
-  * RIL_UNSOL_PCO_DATA calls.
-  *
-  * "data" is the RIL_PCO_Data structure.
-  *
-  */
-#define RIL_UNSOL_PCO_DATA 1046
-
- /**
-  * RIL_UNSOL_MODEM_RESTART
-  *
-  * Called when there is a modem reset.
-  *
-  * "reason" is "const char *" containing the reason for the reset. It
-  * could be a crash signature if the restart was due to a crash or some
-  * string such as "user-initiated restart" or "AT command initiated
-  * restart" that explains the cause of the modem restart.
-  *
-  * When modem restarts, one of the following radio state transitions will happen
-  * 1) RADIO_STATE_ON->RADIO_STATE_UNAVAILABLE->RADIO_STATE_ON or
-  * 2) RADIO_STATE_OFF->RADIO_STATE_UNAVAILABLE->RADIO_STATE_OFF
-  * This message can be sent either just before the RADIO_STATE changes to RADIO_STATE_UNAVAILABLE
-  * or just after but should never be sent after the RADIO_STATE changes from UNAVAILABLE to
-  * AVAILABLE(RADIO_STATE_ON/RADIO_STATE_OFF) again.
-  *
-  * It should NOT be sent after the RADIO_STATE changes to AVAILABLE after the
-  * modem restart as that could be interpreted as a second modem reset by the
-  * framework.
-  */
-#define RIL_UNSOL_MODEM_RESTART 1047
-
-/**
- * RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION
- *
- * Called when the modem needs Carrier specific information that will
- * be used to encrypt IMSI and IMPI.
- *
- * "data" is NULL
- *
- */
-#define RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION 1048
-
-/**
- * RIL_UNSOL_NETWORK_SCAN_RESULT
- *
- * Returns incremental result for the network scan which is started by
- * RIL_REQUEST_START_NETWORK_SCAN, sent to report results, status, or errors.
- *
- * "data" is NULL
- * "response" is a const RIL_NetworkScanResult *
- */
-#define RIL_UNSOL_NETWORK_SCAN_RESULT 1049
-
-/**
- * RIL_UNSOL_KEEPALIVE_STATUS
- *
- * "data" is NULL
- * "response" is a const RIL_KeepaliveStatus *
- */
-#define RIL_UNSOL_KEEPALIVE_STATUS 1050
-
-/***********************************************************************/
-
-
-#if defined(ANDROID_MULTI_SIM)
-/**
- * RIL_Request Function pointer
- *
- * @param request is one of RIL_REQUEST_*
- * @param data is pointer to data defined for that RIL_REQUEST_*
- *        data is owned by caller, and should not be modified or freed by callee
- *        structures passed as data may contain pointers to non-contiguous memory
- * @param t should be used in subsequent call to RIL_onResponse
- * @param datalen is the length of "data" which is defined as other argument. It may or may
- *        not be equal to sizeof(data). Refer to the documentation of individual structures
- *        to find if pointers listed in the structure are contiguous and counted in the datalen
- *        length or not.
- *        (Eg: RIL_IMS_SMS_Message where we don't have datalen equal to sizeof(data))
- *
- */
-typedef void (*RIL_RequestFunc) (int request, void *data,
-                                    size_t datalen, RIL_Token t, RIL_SOCKET_ID socket_id);
-
-/**
- * This function should return the current radio state synchronously
- */
-typedef RIL_RadioState (*RIL_RadioStateRequest)(RIL_SOCKET_ID socket_id);
-
-#else
-/* Backward compatible */
-
-/**
- * RIL_Request Function pointer
- *
- * @param request is one of RIL_REQUEST_*
- * @param data is pointer to data defined for that RIL_REQUEST_*
- *        data is owned by caller, and should not be modified or freed by callee
- *        structures passed as data may contain pointers to non-contiguous memory
- * @param t should be used in subsequent call to RIL_onResponse
- * @param datalen is the length of "data" which is defined as other argument. It may or may
- *        not be equal to sizeof(data). Refer to the documentation of individual structures
- *        to find if pointers listed in the structure are contiguous and counted in the datalen
- *        length or not.
- *        (Eg: RIL_IMS_SMS_Message where we don't have datalen equal to sizeof(data))
- *
- */
-typedef void (*RIL_RequestFunc) (int request, void *data,
-                                    size_t datalen, RIL_Token t);
-
-/**
- * This function should return the current radio state synchronously
- */
-typedef RIL_RadioState (*RIL_RadioStateRequest)();
-
-#endif
-
-
-/**
- * This function returns "1" if the specified RIL_REQUEST code is
- * supported and 0 if it is not
- *
- * @param requestCode is one of RIL_REQUEST codes
- */
-
-typedef int (*RIL_Supports)(int requestCode);
-
-/**
- * This function is called from a separate thread--not the
- * thread that calls RIL_RequestFunc--and indicates that a pending
- * request should be cancelled.
- *
- * On cancel, the callee should do its best to abandon the request and
- * call RIL_onRequestComplete with RIL_Errno CANCELLED at some later point.
- *
- * Subsequent calls to  RIL_onRequestComplete for this request with
- * other results will be tolerated but ignored. (That is, it is valid
- * to ignore the cancellation request)
- *
- * RIL_Cancel calls should return immediately, and not wait for cancellation
- *
- * Please see ITU v.250 5.6.1 for how one might implement this on a TS 27.007
- * interface
- *
- * @param t token wants to be canceled
- */
-
-typedef void (*RIL_Cancel)(RIL_Token t);
-
-typedef void (*RIL_TimedCallback) (void *param);
-
-/**
- * Return a version string for your RIL implementation
- */
-typedef const char * (*RIL_GetVersion) (void);
-
-typedef struct {
-    int version;        /* set to RIL_VERSION */
-    RIL_RequestFunc onRequest;
-    RIL_RadioStateRequest onStateRequest;
-    RIL_Supports supports;
-    RIL_Cancel onCancel;
-    RIL_GetVersion getVersion;
-} RIL_RadioFunctions;
-
-typedef struct {
-    char *apn;                  /* the APN to connect to */
-    char *protocol;             /* one of the PDP_type values in TS 27.007 section 10.1.1 used on
-                                   roaming network. For example, "IP", "IPV6", "IPV4V6", or "PPP".*/
-    int authtype;               /* authentication protocol used for this PDP context
-                                   (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3) */
-    char *username;             /* the username for APN, or NULL */
-    char *password;             /* the password for APN, or NULL */
-} RIL_InitialAttachApn;
-
-typedef struct {
-    char *apn;                  /* the APN to connect to */
-    char *protocol;             /* one of the PDP_type values in TS 27.007 section 10.1.1 used on
-                                   home network. For example, "IP", "IPV6", "IPV4V6", or "PPP". */
-    char *roamingProtocol;      /* one of the PDP_type values in TS 27.007 section 10.1.1 used on
-                                   roaming network. For example, "IP", "IPV6", "IPV4V6", or "PPP".*/
-    int authtype;               /* authentication protocol used for this PDP context
-                                   (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3) */
-    char *username;             /* the username for APN, or NULL */
-    char *password;             /* the password for APN, or NULL */
-    int supportedTypesBitmask;  /* supported APN types bitmask. See RIL_ApnTypes for the value of
-                                   each bit. */
-    int bearerBitmask;          /* the bearer bitmask. See RIL_RadioAccessFamily for the value of
-                                   each bit. */
-    int modemCognitive;         /* indicating the APN setting was sent to the modem through
-                                   setDataProfile earlier. */
-    int mtu;                    /* maximum transmission unit (MTU) size in bytes */
-    char *mvnoType;             /* the MVNO type: possible values are "imsi", "gid", "spn" */
-    char *mvnoMatchData;        /* MVNO match data. Can be anything defined by the carrier.
-                                   For example,
-                                     SPN like: "A MOBILE", "BEN NL", etc...
-                                     IMSI like: "302720x94", "2060188", etc...
-                                     GID like: "4E", "33", etc... */
-} RIL_InitialAttachApn_v15;
-
-typedef struct {
-    int authContext;            /* P2 value of authentication command, see P2 parameter in
-                                   3GPP TS 31.102 7.1.2 */
-    char *authData;             /* the challenge string in Base64 format, see 3GPP
-                                   TS 31.102 7.1.2 */
-    char *aid;                  /* AID value, See ETSI 102.221 8.1 and 101.220 4,
-                                   NULL if no value. */
-} RIL_SimAuthentication;
-
-typedef struct {
-    int cid;                    /* Context ID, uniquely identifies this call */
-    char *bearer_proto;         /* One of the PDP_type values in TS 27.007 section 10.1.1.
-                                   For example, "IP", "IPV6", "IPV4V6". */
-    int pco_id;                 /* The protocol ID for this box.  Note that only IDs from
-                                   FF00H - FFFFH are accepted.  If more than one is included
-                                   from the network, multiple calls should be made to send all
-                                   of them. */
-    int contents_length;        /* The number of octets in the contents. */
-    char *contents;             /* Carrier-defined content.  It is binary, opaque and
-                                   loosely defined in LTE Layer 3 spec 24.008 */
-} RIL_PCO_Data;
-
-typedef enum {
-    NATT_IPV4 = 0,              /* Keepalive specified by RFC 3948 Sec. 2.3 using IPv4 */
-    NATT_IPV6 = 1               /* Keepalive specified by RFC 3948 Sec. 2.3 using IPv6 */
-} RIL_KeepaliveType;
-
-#define MAX_INADDR_LEN 16
-typedef struct {
-    RIL_KeepaliveType type;                  /* Type of keepalive packet */
-    char sourceAddress[MAX_INADDR_LEN];      /* Source address in network-byte order */
-    int sourcePort;                          /* Source port if applicable, or 0x7FFFFFFF;
-                                                the maximum value is 65535 */
-    char destinationAddress[MAX_INADDR_LEN]; /* Destination address in network-byte order */
-    int destinationPort;                     /* Destination port if applicable or 0x7FFFFFFF;
-                                                the maximum value is 65535 */
-    int maxKeepaliveIntervalMillis;          /* Maximum milliseconds between two packets */
-    int cid;                                 /* Context ID, uniquely identifies this call */
-} RIL_KeepaliveRequest;
-
-typedef enum {
-    KEEPALIVE_ACTIVE,                       /* Keepalive session is active */
-    KEEPALIVE_INACTIVE,                     /* Keepalive session is inactive */
-    KEEPALIVE_PENDING                       /* Keepalive session status not available */
-} RIL_KeepaliveStatusCode;
-
-typedef struct {
-    uint32_t sessionHandle;
-    RIL_KeepaliveStatusCode code;
-} RIL_KeepaliveStatus;
-
-#ifdef RIL_SHLIB
-struct RIL_Env {
-    /**
-     * "t" is parameter passed in on previous call to RIL_Notification
-     * routine.
-     *
-     * If "e" != SUCCESS, then response can be null/is ignored
-     *
-     * "response" is owned by caller, and should not be modified or
-     * freed by callee
-     *
-     * RIL_onRequestComplete will return as soon as possible
-     */
-    void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
-                           void *response, size_t responselen);
-
-#if defined(ANDROID_MULTI_SIM)
-    /**
-     * "unsolResponse" is one of RIL_UNSOL_RESPONSE_*
-     * "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_*
-     *
-     * "data" is owned by caller, and should not be modified or freed by callee
-     */
-    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id);
-#else
-    /**
-     * "unsolResponse" is one of RIL_UNSOL_RESPONSE_*
-     * "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_*
-     *
-     * "data" is owned by caller, and should not be modified or freed by callee
-     */
-    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen);
-#endif
-    /**
-     * Call user-specifed "callback" function on on the same thread that
-     * RIL_RequestFunc is called. If "relativeTime" is specified, then it specifies
-     * a relative time value at which the callback is invoked. If relativeTime is
-     * NULL or points to a 0-filled structure, the callback will be invoked as
-     * soon as possible
-     */
-
-    void (*RequestTimedCallback) (RIL_TimedCallback callback,
-                                   void *param, const struct timeval *relativeTime);
-   /**
-    * "t" is parameter passed in on previous call RIL_Notification routine
-    *
-    * RIL_onRequestAck will be called by vendor when an Async RIL request was received
-    * by them and an ack needs to be sent back to java ril.
-    */
-    void (*OnRequestAck) (RIL_Token t);
-};
-
-
-/**
- *  RIL implementations must defined RIL_Init
- *  argc and argv will be command line arguments intended for the RIL implementation
- *  Return NULL on error
- *
- * @param env is environment point defined as RIL_Env
- * @param argc number of arguments
- * @param argv list fo arguments
- *
- */
-const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv);
-
-/**
- *  If BT SAP(SIM Access Profile) is supported, then RIL implementations must define RIL_SAP_Init
- *  for initializing RIL_RadioFunctions used for BT SAP communcations. It is called whenever RILD
- *  starts or modem restarts. Returns handlers for SAP related request that are made on SAP
- *  sepecific socket, analogous to the RIL_RadioFunctions returned by the call to RIL_Init
- *  and used on the general RIL socket.
- *  argc and argv will be command line arguments intended for the RIL implementation
- *  Return NULL on error.
- *
- * @param env is environment point defined as RIL_Env
- * @param argc number of arguments
- * @param argv list fo arguments
- *
- */
-const RIL_RadioFunctions *RIL_SAP_Init(const struct RIL_Env *env, int argc, char **argv);
-
-#else /* RIL_SHLIB */
-
-/**
- * Call this once at startup to register notification routine
- *
- * @param callbacks user-specifed callback function
- */
-void RIL_register (const RIL_RadioFunctions *callbacks);
-
-void rilc_thread_pool();
-
-
-/**
- *
- * RIL_onRequestComplete will return as soon as possible
- *
- * @param t is parameter passed in on previous call to RIL_Notification
- *          routine.
- * @param e error code
- *          if "e" != SUCCESS, then response can be null/is ignored
- * @param response is owned by caller, and should not be modified or
- *                 freed by callee
- * @param responselen the length of response in byte
- */
-void RIL_onRequestComplete(RIL_Token t, RIL_Errno e,
-                           void *response, size_t responselen);
-
-/**
- * RIL_onRequestAck will be called by vendor when an Async RIL request was received by them and
- * an ack needs to be sent back to java ril. This doesn't mark the end of the command or it's
- * results, just that the command was received and will take a while. After sending this Ack
- * its vendor's responsibility to make sure that AP is up whenever needed while command is
- * being processed.
- *
- * @param t is parameter passed in on previous call to RIL_Notification
- *          routine.
- */
-void RIL_onRequestAck(RIL_Token t);
-
-#if defined(ANDROID_MULTI_SIM)
-/**
- * @param unsolResponse is one of RIL_UNSOL_RESPONSE_*
- * @param data is pointer to data defined for that RIL_UNSOL_RESPONSE_*
- *     "data" is owned by caller, and should not be modified or freed by callee
- * @param datalen the length of data in byte
- */
-
-void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen, RIL_SOCKET_ID socket_id);
-#else
-/**
- * @param unsolResponse is one of RIL_UNSOL_RESPONSE_*
- * @param data is pointer to data defined for that RIL_UNSOL_RESPONSE_*
- *     "data" is owned by caller, and should not be modified or freed by callee
- * @param datalen the length of data in byte
- */
-
-void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
-                                size_t datalen);
-#endif
-
-/**
- * Call user-specifed "callback" function on on the same thread that
- * RIL_RequestFunc is called. If "relativeTime" is specified, then it specifies
- * a relative time value at which the callback is invoked. If relativeTime is
- * NULL or points to a 0-filled structure, the callback will be invoked as
- * soon as possible
- *
- * @param callback user-specifed callback function
- * @param param parameter list
- * @param relativeTime a relative time value at which the callback is invoked
- */
-
-void RIL_requestTimedCallback (RIL_TimedCallback callback,
-                               void *param, const struct timeval *relativeTime);
-
-#endif /* RIL_SHLIB */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*ANDROID_RIL_H*/
diff --git a/guest/hals/ril/libril/ril_commands.h b/guest/hals/ril/libril/ril_commands.h
deleted file mode 100644
index 0f8a161..0000000
--- a/guest/hals/ril/libril/ril_commands.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/* //guest/hals/ril/libril/ril_commands.h
-**
-** Copyright 2006, 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.
-*/
-    {0, NULL},                   //none
-    {RIL_REQUEST_GET_SIM_STATUS, radio_1_5::getIccCardStatusResponse},
-    {RIL_REQUEST_ENTER_SIM_PIN, radio_1_5::supplyIccPinForAppResponse},
-    {RIL_REQUEST_ENTER_SIM_PUK, radio_1_5::supplyIccPukForAppResponse},
-    {RIL_REQUEST_ENTER_SIM_PIN2, radio_1_5::supplyIccPin2ForAppResponse},
-    {RIL_REQUEST_ENTER_SIM_PUK2, radio_1_5::supplyIccPuk2ForAppResponse},
-    {RIL_REQUEST_CHANGE_SIM_PIN, radio_1_5::changeIccPinForAppResponse},
-    {RIL_REQUEST_CHANGE_SIM_PIN2, radio_1_5::changeIccPin2ForAppResponse},
-    {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, radio_1_5::supplyNetworkDepersonalizationResponse},
-    {RIL_REQUEST_GET_CURRENT_CALLS, radio_1_5::getCurrentCallsResponse},
-    {RIL_REQUEST_DIAL, radio_1_5::dialResponse},
-    {RIL_REQUEST_GET_IMSI, radio_1_5::getIMSIForAppResponse},
-    {RIL_REQUEST_HANGUP, radio_1_5::hangupConnectionResponse},
-    {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, radio_1_5::hangupWaitingOrBackgroundResponse},
-    {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, radio_1_5::hangupForegroundResumeBackgroundResponse},
-    {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, radio_1_5::switchWaitingOrHoldingAndActiveResponse},
-    {RIL_REQUEST_CONFERENCE, radio_1_5::conferenceResponse},
-    {RIL_REQUEST_UDUB, radio_1_5::rejectCallResponse},
-    {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, radio_1_5::getLastCallFailCauseResponse},
-    {RIL_REQUEST_SIGNAL_STRENGTH, radio_1_5::getSignalStrengthResponse},
-    {RIL_REQUEST_VOICE_REGISTRATION_STATE, radio_1_5::getVoiceRegistrationStateResponse},
-    {RIL_REQUEST_DATA_REGISTRATION_STATE, radio_1_5::getDataRegistrationStateResponse},
-    {RIL_REQUEST_OPERATOR, radio_1_5::getOperatorResponse},
-    {RIL_REQUEST_RADIO_POWER, radio_1_5::setRadioPowerResponse},
-    {RIL_REQUEST_DTMF, radio_1_5::sendDtmfResponse},
-    {RIL_REQUEST_SEND_SMS, radio_1_5::sendSmsResponse},
-    {RIL_REQUEST_SEND_SMS_EXPECT_MORE, radio_1_5::sendSMSExpectMoreResponse},
-    {RIL_REQUEST_SETUP_DATA_CALL, radio_1_5::setupDataCallResponse},
-    {RIL_REQUEST_SIM_IO, radio_1_5::iccIOForAppResponse},
-    {RIL_REQUEST_SEND_USSD, radio_1_5::sendUssdResponse},
-    {RIL_REQUEST_CANCEL_USSD, radio_1_5::cancelPendingUssdResponse},
-    {RIL_REQUEST_GET_CLIR, radio_1_5::getClirResponse},
-    {RIL_REQUEST_SET_CLIR, radio_1_5::setClirResponse},
-    {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, radio_1_5::getCallForwardStatusResponse},
-    {RIL_REQUEST_SET_CALL_FORWARD, radio_1_5::setCallForwardResponse},
-    {RIL_REQUEST_QUERY_CALL_WAITING, radio_1_5::getCallWaitingResponse},
-    {RIL_REQUEST_SET_CALL_WAITING, radio_1_5::setCallWaitingResponse},
-    {RIL_REQUEST_SMS_ACKNOWLEDGE, radio_1_5::acknowledgeLastIncomingGsmSmsResponse},
-    {RIL_REQUEST_GET_IMEI, NULL},
-    {RIL_REQUEST_GET_IMEISV, NULL},
-    {RIL_REQUEST_ANSWER, radio_1_5::acceptCallResponse},
-    {RIL_REQUEST_DEACTIVATE_DATA_CALL, radio_1_5::deactivateDataCallResponse},
-    {RIL_REQUEST_QUERY_FACILITY_LOCK, radio_1_5::getFacilityLockForAppResponse},
-    {RIL_REQUEST_SET_FACILITY_LOCK, radio_1_5::setFacilityLockForAppResponse},
-    {RIL_REQUEST_CHANGE_BARRING_PASSWORD, radio_1_5::setBarringPasswordResponse},
-    {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, radio_1_5::getNetworkSelectionModeResponse},
-    {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, radio_1_5::setNetworkSelectionModeAutomaticResponse},
-    {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, radio_1_5::setNetworkSelectionModeManualResponse},
-    {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , radio_1_5::getAvailableNetworksResponse},
-    {RIL_REQUEST_DTMF_START, radio_1_5::startDtmfResponse},
-    {RIL_REQUEST_DTMF_STOP, radio_1_5::stopDtmfResponse},
-    {RIL_REQUEST_BASEBAND_VERSION, radio_1_5::getBasebandVersionResponse},
-    {RIL_REQUEST_SEPARATE_CONNECTION, radio_1_5::separateConnectionResponse},
-    {RIL_REQUEST_SET_MUTE, radio_1_5::setMuteResponse},
-    {RIL_REQUEST_GET_MUTE, radio_1_5::getMuteResponse},
-    {RIL_REQUEST_QUERY_CLIP, radio_1_5::getClipResponse},
-    {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, NULL},
-    {RIL_REQUEST_DATA_CALL_LIST, radio_1_5::getDataCallListResponse},
-    {RIL_REQUEST_RESET_RADIO, NULL},
-    {RIL_REQUEST_OEM_HOOK_RAW, radio_1_5::sendRequestRawResponse},
-    {RIL_REQUEST_OEM_HOOK_STRINGS, radio_1_5::sendRequestStringsResponse},
-    {RIL_REQUEST_SCREEN_STATE, radio_1_5::sendDeviceStateResponse},   // Note the response function is different.
-    {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, radio_1_5::setSuppServiceNotificationsResponse},
-    {RIL_REQUEST_WRITE_SMS_TO_SIM, radio_1_5::writeSmsToSimResponse},
-    {RIL_REQUEST_DELETE_SMS_ON_SIM, radio_1_5::deleteSmsOnSimResponse},
-    {RIL_REQUEST_SET_BAND_MODE, radio_1_5::setBandModeResponse},
-    {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, radio_1_5::getAvailableBandModesResponse},
-    {RIL_REQUEST_STK_GET_PROFILE, NULL},
-    {RIL_REQUEST_STK_SET_PROFILE, NULL},
-    {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, radio_1_5::sendEnvelopeResponse},
-    {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, radio_1_5::sendTerminalResponseToSimResponse},
-    {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, radio_1_5::handleStkCallSetupRequestFromSimResponse},
-    {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, radio_1_5::explicitCallTransferResponse},
-    {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, radio_1_5::setPreferredNetworkTypeResponse},
-    {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, radio_1_5::getPreferredNetworkTypeResponse},
-    {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, radio_1_5::getNeighboringCidsResponse},
-    {RIL_REQUEST_SET_LOCATION_UPDATES, radio_1_5::setLocationUpdatesResponse},
-    {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, radio_1_5::setCdmaSubscriptionSourceResponse},
-    {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, radio_1_5::setCdmaRoamingPreferenceResponse},
-    {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, radio_1_5::getCdmaRoamingPreferenceResponse},
-    {RIL_REQUEST_SET_TTY_MODE, radio_1_5::setTTYModeResponse},
-    {RIL_REQUEST_QUERY_TTY_MODE, radio_1_5::getTTYModeResponse},
-    {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, radio_1_5::setPreferredVoicePrivacyResponse},
-    {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, radio_1_5::getPreferredVoicePrivacyResponse},
-    {RIL_REQUEST_CDMA_FLASH, radio_1_5::sendCDMAFeatureCodeResponse},
-    {RIL_REQUEST_CDMA_BURST_DTMF, radio_1_5::sendBurstDtmfResponse},
-    {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, NULL},
-    {RIL_REQUEST_CDMA_SEND_SMS, radio_1_5::sendCdmaSmsResponse},
-    {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, radio_1_5::acknowledgeLastIncomingCdmaSmsResponse},
-    {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, radio_1_5::getGsmBroadcastConfigResponse},
-    {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, radio_1_5::setGsmBroadcastConfigResponse},
-    {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, radio_1_5::setGsmBroadcastActivationResponse},
-    {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, radio_1_5::getCdmaBroadcastConfigResponse},
-    {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, radio_1_5::setCdmaBroadcastConfigResponse},
-    {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, radio_1_5::setCdmaBroadcastActivationResponse},
-    {RIL_REQUEST_CDMA_SUBSCRIPTION, radio_1_5::getCDMASubscriptionResponse},
-    {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, radio_1_5::writeSmsToRuimResponse},
-    {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, radio_1_5::deleteSmsOnRuimResponse},
-    {RIL_REQUEST_DEVICE_IDENTITY, radio_1_5::getDeviceIdentityResponse},
-    {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, radio_1_5::exitEmergencyCallbackModeResponse},
-    {RIL_REQUEST_GET_SMSC_ADDRESS, radio_1_5::getSmscAddressResponse},
-    {RIL_REQUEST_SET_SMSC_ADDRESS, radio_1_5::setSmscAddressResponse},
-    {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, radio_1_5::reportSmsMemoryStatusResponse},
-    {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, radio_1_5::reportStkServiceIsRunningResponse},
-    {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, radio_1_5::getCdmaSubscriptionSourceResponse},
-    {RIL_REQUEST_ISIM_AUTHENTICATION, radio_1_5::requestIsimAuthenticationResponse},
-    {RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, radio_1_5::acknowledgeIncomingGsmSmsWithPduResponse},
-    {RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, radio_1_5::sendEnvelopeWithStatusResponse},
-    {RIL_REQUEST_VOICE_RADIO_TECH, radio_1_5::getVoiceRadioTechnologyResponse},
-    {RIL_REQUEST_GET_CELL_INFO_LIST, radio_1_5::getCellInfoListResponse},
-    {RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, radio_1_5::setCellInfoListRateResponse},
-    {RIL_REQUEST_SET_INITIAL_ATTACH_APN, radio_1_5::setInitialAttachApnResponse},
-    {RIL_REQUEST_IMS_REGISTRATION_STATE, radio_1_5::getImsRegistrationStateResponse},
-    {RIL_REQUEST_IMS_SEND_SMS, radio_1_5::sendImsSmsResponse},
-    {RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC, radio_1_5::iccTransmitApduBasicChannelResponse},
-    {RIL_REQUEST_SIM_OPEN_CHANNEL, radio_1_5::iccOpenLogicalChannelResponse},
-    {RIL_REQUEST_SIM_CLOSE_CHANNEL, radio_1_5::iccCloseLogicalChannelResponse},
-    {RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, radio_1_5::iccTransmitApduLogicalChannelResponse},
-    {RIL_REQUEST_NV_READ_ITEM, radio_1_5::nvReadItemResponse},
-    {RIL_REQUEST_NV_WRITE_ITEM, radio_1_5::nvWriteItemResponse},
-    {RIL_REQUEST_NV_WRITE_CDMA_PRL, radio_1_5::nvWriteCdmaPrlResponse},
-    {RIL_REQUEST_NV_RESET_CONFIG, radio_1_5::nvResetConfigResponse},
-    {RIL_REQUEST_SET_UICC_SUBSCRIPTION, radio_1_5::setUiccSubscriptionResponse},
-    {RIL_REQUEST_ALLOW_DATA, radio_1_5::setDataAllowedResponse},
-    {RIL_REQUEST_GET_HARDWARE_CONFIG, radio_1_5::getHardwareConfigResponse},
-    {RIL_REQUEST_SIM_AUTHENTICATION, radio_1_5::requestIccSimAuthenticationResponse},
-    {RIL_REQUEST_GET_DC_RT_INFO, NULL},
-    {RIL_REQUEST_SET_DC_RT_INFO_RATE, NULL},
-    {RIL_REQUEST_SET_DATA_PROFILE, radio_1_5::setDataProfileResponse},
-    {RIL_REQUEST_SHUTDOWN, radio_1_5::requestShutdownResponse},
-    {RIL_REQUEST_GET_RADIO_CAPABILITY, radio_1_5::getRadioCapabilityResponse},
-    {RIL_REQUEST_SET_RADIO_CAPABILITY, radio_1_5::setRadioCapabilityResponse},
-    {RIL_REQUEST_START_LCE, radio_1_5::startLceServiceResponse},
-    {RIL_REQUEST_STOP_LCE, radio_1_5::stopLceServiceResponse},
-    {RIL_REQUEST_PULL_LCEDATA, radio_1_5::pullLceDataResponse},
-    {RIL_REQUEST_GET_ACTIVITY_INFO, radio_1_5::getModemActivityInfoResponse},
-    {RIL_REQUEST_SET_CARRIER_RESTRICTIONS, radio_1_5::setAllowedCarriersResponse},
-    {RIL_REQUEST_GET_CARRIER_RESTRICTIONS, radio_1_5::getAllowedCarriersResponse},
-    {RIL_REQUEST_SEND_DEVICE_STATE, radio_1_5::sendDeviceStateResponse},
-    {RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER, radio_1_5::setIndicationFilterResponse},
-    {RIL_REQUEST_SET_SIM_CARD_POWER, radio_1_5::setSimCardPowerResponse},
-    {RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION, radio_1_5::setCarrierInfoForImsiEncryptionResponse},
-    {RIL_REQUEST_START_NETWORK_SCAN, radio_1_5::startNetworkScanResponse},
-    {RIL_REQUEST_STOP_NETWORK_SCAN, radio_1_5::stopNetworkScanResponse},
-    {RIL_REQUEST_START_KEEPALIVE, radio_1_5::startKeepaliveResponse},
-    {RIL_REQUEST_STOP_KEEPALIVE, radio_1_5::stopKeepaliveResponse},
-    {RIL_REQUEST_GET_MODEM_STACK_STATUS, radio_1_5::getModemStackStatusResponse},
-    {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP, radio_1_5::getPreferredNetworkTypeBitmapResponse},
-    {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP, radio_1_5::setPreferredNetworkTypeBitmapResponse},
-    {RIL_REQUEST_EMERGENCY_DIAL, radio_1_5::emergencyDialResponse},
-    {RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS, radio_1_5::setSystemSelectionChannelsResponse},
-    {RIL_REQUEST_ENABLE_MODEM, radio_1_5::enableModemResponse},
-    {RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA, radio_1_5::setSignalStrengthReportingCriteriaResponse},
-    {RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA, radio_1_5::setLinkCapacityReportingCriteriaResponse},
-    {RIL_REQUEST_ENABLE_UICC_APPLICATIONS, radio_1_5::enableUiccApplicationsResponse},
-    {RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED, radio_1_5::areUiccApplicationsEnabledResponse},
-    {RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION, radio_1_5::supplySimDepersonalizationResponse},
-    {RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE, radio_1_5::sendCdmaSmsExpectMoreResponse}
diff --git a/guest/hals/ril/libril/ril_ex.h b/guest/hals/ril/libril/ril_ex.h
deleted file mode 100644
index e0fcd7b..0000000
--- a/guest/hals/ril/libril/ril_ex.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-* Copyright (C) 2014 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.
-*/
-
-#ifndef RIL_EX_H_INCLUDED
-#define RIL_EX_H_INCLUDED
-
-#include <guest/hals/ril/libril/ril.h>
-#include <telephony/record_stream.h>
-
-#define NUM_ELEMS_SOCKET(a)     (sizeof (a) / sizeof (a)[0])
-
-struct ril_event;
-
-void rilEventAddWakeup_helper(struct ril_event *ev);
-int blockingWrite_helper(int fd, void* data, size_t len);
-
-enum SocketWakeType {DONT_WAKE, WAKE_PARTIAL};
-
-typedef enum {
-    RIL_TELEPHONY_SOCKET,
-    RIL_SAP_SOCKET
-} RIL_SOCKET_TYPE;
-
-typedef struct SocketListenParam {
-    RIL_SOCKET_ID socket_id;
-    int fdListen;
-    int fdCommand;
-    const char* processName;
-    struct ril_event* commands_event;
-    struct ril_event* listen_event;
-    void (*processCommandsCallback)(int fd, short flags, void *param);
-    RecordStream *p_rs;
-    RIL_SOCKET_TYPE type;
-} SocketListenParam;
-
-#endif
diff --git a/guest/hals/ril/libril/ril_service.cpp b/guest/hals/ril/libril/ril_service.cpp
deleted file mode 100644
index 42e2cae..0000000
--- a/guest/hals/ril/libril/ril_service.cpp
+++ /dev/null
@@ -1,10076 +0,0 @@
-/*
- * Copyright (c) 2016 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.
- */
-
-#define LOG_TAG "RILC"
-
-#include <android/hardware/radio/1.5/IRadio.h>
-#include <android/hardware/radio/1.5/IRadioResponse.h>
-#include <android/hardware/radio/1.5/IRadioIndication.h>
-#include <android/hardware/radio/1.5/types.h>
-
-#include <android/hardware/radio/deprecated/1.0/IOemHook.h>
-
-#include <hwbinder/IPCThreadState.h>
-#include <hwbinder/ProcessState.h>
-#include <guest/hals/ril/libril/ril.h>
-#include <telephony/ril_mnc.h>
-#include <guest/hals/ril/libril/ril_service.h>
-#include <hidl/HidlTransportSupport.h>
-#include <utils/SystemClock.h>
-#include <inttypes.h>
-
-#define INVALID_HEX_CHAR 16
-
-using namespace android::hardware::radio;
-using namespace android::hardware::radio::V1_0;
-using namespace android::hardware::radio::deprecated::V1_0;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::joinRpcThreadpool;
-using ::android::hardware::Return;
-using ::android::hardware::hidl_bitfield;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_array;
-using ::android::hardware::Void;
-using android::CommandInfo;
-using android::RequestInfo;
-using android::requestToString;
-using android::sp;
-
-#define BOOL_TO_INT(x) (x ? 1 : 0)
-#define ATOI_NULL_HANDLED(x) (x ? atoi(x) : -1)
-#define ATOI_NULL_HANDLED_DEF(x, defaultVal) (x ? atoi(x) : defaultVal)
-
-#if defined(ANDROID_MULTI_SIM)
-#define CALL_ONREQUEST(a, b, c, d, e) \
-        s_vendorFunctions->onRequest((a), (b), (c), (d), ((RIL_SOCKET_ID)(e)))
-#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest((RIL_SOCKET_ID)(a))
-#else
-#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), (c), (d))
-#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest()
-#endif
-
-#ifdef OEM_HOOK_DISABLED
-constexpr bool kOemHookEnabled = false;
-#else
-constexpr bool kOemHookEnabled = true;
-#endif
-
-RIL_RadioFunctions *s_vendorFunctions = NULL;
-static CommandInfo *s_commands;
-
-struct RadioImpl_1_5;
-struct OemHookImpl;
-
-#if (SIM_COUNT >= 2)
-sp<RadioImpl_1_5> radioService[SIM_COUNT];
-sp<OemHookImpl> oemHookService[SIM_COUNT];
-int64_t nitzTimeReceived[SIM_COUNT];
-// counter used for synchronization. It is incremented every time response callbacks are updated.
-volatile int32_t mCounterRadio[SIM_COUNT];
-volatile int32_t mCounterOemHook[SIM_COUNT];
-#else
-sp<RadioImpl_1_5> radioService[1];
-sp<OemHookImpl> oemHookService[1];
-int64_t nitzTimeReceived[1];
-// counter used for synchronization. It is incremented every time response callbacks are updated.
-volatile int32_t mCounterRadio[1];
-volatile int32_t mCounterOemHook[1];
-#endif
-
-static pthread_rwlock_t radioServiceRwlock = PTHREAD_RWLOCK_INITIALIZER;
-
-#if (SIM_COUNT >= 2)
-static pthread_rwlock_t radioServiceRwlock2 = PTHREAD_RWLOCK_INITIALIZER;
-#if (SIM_COUNT >= 3)
-static pthread_rwlock_t radioServiceRwlock3 = PTHREAD_RWLOCK_INITIALIZER;
-#if (SIM_COUNT >= 4)
-static pthread_rwlock_t radioServiceRwlock4 = PTHREAD_RWLOCK_INITIALIZER;
-#endif
-#endif
-#endif
-
-void convertRilHardwareConfigListToHal(void *response, size_t responseLen,
-        hidl_vec<HardwareConfig>& records);
-
-void convertRilRadioCapabilityToHal(void *response, size_t responseLen, RadioCapability& rc);
-
-void convertRilLceDataInfoToHal(void *response, size_t responseLen, LceDataInfo& lce);
-
-void convertRilSignalStrengthToHal(void *response, size_t responseLen,
-        SignalStrength& signalStrength);
-
-void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
-        SetupDataCallResult& dcResult);
-
-void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
-        ::android::hardware::radio::V1_4::SetupDataCallResult& dcResult);
-
-void convertRilDataCallToHal(RIL_Data_Call_Response_v12 *dcResponse,
-        ::android::hardware::radio::V1_5::SetupDataCallResult& dcResult);
-
-void convertRilDataCallListToHal(void *response, size_t responseLen,
-        hidl_vec<SetupDataCallResult>& dcResultList);
-
-void convertRilCellInfoListToHal(void *response, size_t responseLen, hidl_vec<CellInfo>& records);
-
-void populateResponseInfo(RadioResponseInfo& responseInfo, int serial, int responseType,
-                         RIL_Errno e);
-
-struct RadioImpl_1_5 : public V1_5::IRadio {
-    int32_t mSlotId;
-    sp<IRadioResponse> mRadioResponse;
-    sp<IRadioIndication> mRadioIndication;
-    sp<V1_2::IRadioResponse> mRadioResponseV1_2;
-    sp<V1_2::IRadioIndication> mRadioIndicationV1_2;
-    sp<V1_3::IRadioResponse> mRadioResponseV1_3;
-    sp<V1_3::IRadioIndication> mRadioIndicationV1_3;
-    sp<V1_4::IRadioResponse> mRadioResponseV1_4;
-    sp<V1_4::IRadioIndication> mRadioIndicationV1_4;
-    sp<V1_5::IRadioResponse> mRadioResponseV1_5;
-    sp<V1_5::IRadioIndication> mRadioIndicationV1_5;
-
-    Return<void> setResponseFunctions(
-            const ::android::sp<IRadioResponse>& radioResponse,
-            const ::android::sp<IRadioIndication>& radioIndication);
-
-    Return<void> getIccCardStatus(int32_t serial);
-
-    Return<void> supplyIccPinForApp(int32_t serial, const hidl_string& pin,
-            const hidl_string& aid);
-
-    Return<void> supplyIccPukForApp(int32_t serial, const hidl_string& puk,
-            const hidl_string& pin, const hidl_string& aid);
-
-    Return<void> supplyIccPin2ForApp(int32_t serial,
-            const hidl_string& pin2,
-            const hidl_string& aid);
-
-    Return<void> supplyIccPuk2ForApp(int32_t serial, const hidl_string& puk2,
-            const hidl_string& pin2, const hidl_string& aid);
-
-    Return<void> changeIccPinForApp(int32_t serial, const hidl_string& oldPin,
-            const hidl_string& newPin, const hidl_string& aid);
-
-    Return<void> changeIccPin2ForApp(int32_t serial, const hidl_string& oldPin2,
-            const hidl_string& newPin2, const hidl_string& aid);
-
-    Return<void> supplyNetworkDepersonalization(int32_t serial, const hidl_string& netPin);
-
-    Return<void> getCurrentCalls(int32_t serial);
-
-    Return<void> dial(int32_t serial, const Dial& dialInfo);
-
-    Return<void> getImsiForApp(int32_t serial,
-            const ::android::hardware::hidl_string& aid);
-
-    Return<void> hangup(int32_t serial, int32_t gsmIndex);
-
-    Return<void> hangupWaitingOrBackground(int32_t serial);
-
-    Return<void> hangupForegroundResumeBackground(int32_t serial);
-
-    Return<void> switchWaitingOrHoldingAndActive(int32_t serial);
-
-    Return<void> conference(int32_t serial);
-
-    Return<void> rejectCall(int32_t serial);
-
-    Return<void> getLastCallFailCause(int32_t serial);
-
-    Return<void> getSignalStrength(int32_t serial);
-
-    Return<void> getVoiceRegistrationState(int32_t serial);
-
-    Return<void> getDataRegistrationState(int32_t serial);
-
-    Return<void> getOperator(int32_t serial);
-
-    Return<void> setRadioPower(int32_t serial, bool on);
-
-    Return<void> sendDtmf(int32_t serial,
-            const ::android::hardware::hidl_string& s);
-
-    Return<void> sendSms(int32_t serial, const GsmSmsMessage& message);
-
-    Return<void> sendSMSExpectMore(int32_t serial, const GsmSmsMessage& message);
-
-    Return<void> setupDataCall(int32_t serial,
-            RadioTechnology radioTechnology,
-            const DataProfileInfo& profileInfo,
-            bool modemCognitive,
-            bool roamingAllowed,
-            bool isRoaming);
-
-    Return<void> iccIOForApp(int32_t serial,
-            const IccIo& iccIo);
-
-    Return<void> sendUssd(int32_t serial,
-            const ::android::hardware::hidl_string& ussd);
-
-    Return<void> cancelPendingUssd(int32_t serial);
-
-    Return<void> getClir(int32_t serial);
-
-    Return<void> setClir(int32_t serial, int32_t status);
-
-    Return<void> getCallForwardStatus(int32_t serial,
-            const CallForwardInfo& callInfo);
-
-    Return<void> setCallForward(int32_t serial,
-            const CallForwardInfo& callInfo);
-
-    Return<void> getCallWaiting(int32_t serial, int32_t serviceClass);
-
-    Return<void> setCallWaiting(int32_t serial, bool enable, int32_t serviceClass);
-
-    Return<void> acknowledgeLastIncomingGsmSms(int32_t serial,
-            bool success, SmsAcknowledgeFailCause cause);
-
-    Return<void> acceptCall(int32_t serial);
-
-    Return<void> deactivateDataCall(int32_t serial,
-            int32_t cid, bool reasonRadioShutDown);
-
-    Return<void> getFacilityLockForApp(int32_t serial,
-            const ::android::hardware::hidl_string& facility,
-            const ::android::hardware::hidl_string& password,
-            int32_t serviceClass,
-            const ::android::hardware::hidl_string& appId);
-
-    Return<void> setFacilityLockForApp(int32_t serial,
-            const ::android::hardware::hidl_string& facility,
-            bool lockState,
-            const ::android::hardware::hidl_string& password,
-            int32_t serviceClass,
-            const ::android::hardware::hidl_string& appId);
-
-    Return<void> setBarringPassword(int32_t serial,
-            const ::android::hardware::hidl_string& facility,
-            const ::android::hardware::hidl_string& oldPassword,
-            const ::android::hardware::hidl_string& newPassword);
-
-    Return<void> getNetworkSelectionMode(int32_t serial);
-
-    Return<void> setNetworkSelectionModeAutomatic(int32_t serial);
-
-    Return<void> setNetworkSelectionModeManual(int32_t serial,
-            const ::android::hardware::hidl_string& operatorNumeric);
-
-    Return<void> getAvailableNetworks(int32_t serial);
-
-    Return<void> startNetworkScan(int32_t serial, const V1_1::NetworkScanRequest& request);
-
-    Return<void> stopNetworkScan(int32_t serial);
-
-    Return<void> startDtmf(int32_t serial,
-            const ::android::hardware::hidl_string& s);
-
-    Return<void> stopDtmf(int32_t serial);
-
-    Return<void> getBasebandVersion(int32_t serial);
-
-    Return<void> separateConnection(int32_t serial, int32_t gsmIndex);
-
-    Return<void> setMute(int32_t serial, bool enable);
-
-    Return<void> getMute(int32_t serial);
-
-    Return<void> getClip(int32_t serial);
-
-    Return<void> getDataCallList(int32_t serial);
-
-    Return<void> setSuppServiceNotifications(int32_t serial, bool enable);
-
-    Return<void> writeSmsToSim(int32_t serial,
-            const SmsWriteArgs& smsWriteArgs);
-
-    Return<void> deleteSmsOnSim(int32_t serial, int32_t index);
-
-    Return<void> setBandMode(int32_t serial, RadioBandMode mode);
-
-    Return<void> getAvailableBandModes(int32_t serial);
-
-    Return<void> sendEnvelope(int32_t serial,
-            const ::android::hardware::hidl_string& command);
-
-    Return<void> sendTerminalResponseToSim(int32_t serial,
-            const ::android::hardware::hidl_string& commandResponse);
-
-    Return<void> handleStkCallSetupRequestFromSim(int32_t serial, bool accept);
-
-    Return<void> explicitCallTransfer(int32_t serial);
-
-    Return<void> setPreferredNetworkType(int32_t serial, PreferredNetworkType nwType);
-
-    Return<void> getPreferredNetworkType(int32_t serial);
-
-    Return<void> getNeighboringCids(int32_t serial);
-
-    Return<void> setLocationUpdates(int32_t serial, bool enable);
-
-    Return<void> setCdmaSubscriptionSource(int32_t serial,
-            CdmaSubscriptionSource cdmaSub);
-
-    Return<void> setCdmaRoamingPreference(int32_t serial, CdmaRoamingType type);
-
-    Return<void> getCdmaRoamingPreference(int32_t serial);
-
-    Return<void> setTTYMode(int32_t serial, TtyMode mode);
-
-    Return<void> getTTYMode(int32_t serial);
-
-    Return<void> setPreferredVoicePrivacy(int32_t serial, bool enable);
-
-    Return<void> getPreferredVoicePrivacy(int32_t serial);
-
-    Return<void> sendCDMAFeatureCode(int32_t serial,
-            const ::android::hardware::hidl_string& featureCode);
-
-    Return<void> sendBurstDtmf(int32_t serial,
-            const ::android::hardware::hidl_string& dtmf,
-            int32_t on,
-            int32_t off);
-
-    Return<void> sendCdmaSms(int32_t serial, const CdmaSmsMessage& sms);
-
-    Return<void> acknowledgeLastIncomingCdmaSms(int32_t serial,
-            const CdmaSmsAck& smsAck);
-
-    Return<void> getGsmBroadcastConfig(int32_t serial);
-
-    Return<void> setGsmBroadcastConfig(int32_t serial,
-            const hidl_vec<GsmBroadcastSmsConfigInfo>& configInfo);
-
-    Return<void> setGsmBroadcastActivation(int32_t serial, bool activate);
-
-    Return<void> getCdmaBroadcastConfig(int32_t serial);
-
-    Return<void> setCdmaBroadcastConfig(int32_t serial,
-            const hidl_vec<CdmaBroadcastSmsConfigInfo>& configInfo);
-
-    Return<void> setCdmaBroadcastActivation(int32_t serial, bool activate);
-
-    Return<void> getCDMASubscription(int32_t serial);
-
-    Return<void> writeSmsToRuim(int32_t serial, const CdmaSmsWriteArgs& cdmaSms);
-
-    Return<void> deleteSmsOnRuim(int32_t serial, int32_t index);
-
-    Return<void> getDeviceIdentity(int32_t serial);
-
-    Return<void> exitEmergencyCallbackMode(int32_t serial);
-
-    Return<void> getSmscAddress(int32_t serial);
-
-    Return<void> setSmscAddress(int32_t serial,
-            const ::android::hardware::hidl_string& smsc);
-
-    Return<void> reportSmsMemoryStatus(int32_t serial, bool available);
-
-    Return<void> reportStkServiceIsRunning(int32_t serial);
-
-    Return<void> getCdmaSubscriptionSource(int32_t serial);
-
-    Return<void> requestIsimAuthentication(int32_t serial,
-            const ::android::hardware::hidl_string& challenge);
-
-    Return<void> acknowledgeIncomingGsmSmsWithPdu(int32_t serial,
-            bool success,
-            const ::android::hardware::hidl_string& ackPdu);
-
-    Return<void> sendEnvelopeWithStatus(int32_t serial,
-            const ::android::hardware::hidl_string& contents);
-
-    Return<void> getVoiceRadioTechnology(int32_t serial);
-
-    Return<void> getCellInfoList(int32_t serial);
-
-    Return<void> setCellInfoListRate(int32_t serial, int32_t rate);
-
-    Return<void> setInitialAttachApn(int32_t serial, const DataProfileInfo& dataProfileInfo,
-            bool modemCognitive, bool isRoaming);
-
-    Return<void> getImsRegistrationState(int32_t serial);
-
-    Return<void> sendImsSms(int32_t serial, const ImsSmsMessage& message);
-
-    Return<void> iccTransmitApduBasicChannel(int32_t serial, const SimApdu& message);
-
-    Return<void> iccOpenLogicalChannel(int32_t serial,
-            const ::android::hardware::hidl_string& aid, int32_t p2);
-
-    Return<void> iccCloseLogicalChannel(int32_t serial, int32_t channelId);
-
-    Return<void> iccTransmitApduLogicalChannel(int32_t serial, const SimApdu& message);
-
-    Return<void> nvReadItem(int32_t serial, NvItem itemId);
-
-    Return<void> nvWriteItem(int32_t serial, const NvWriteItem& item);
-
-    Return<void> nvWriteCdmaPrl(int32_t serial,
-            const ::android::hardware::hidl_vec<uint8_t>& prl);
-
-    Return<void> nvResetConfig(int32_t serial, ResetNvType resetType);
-
-    Return<void> setUiccSubscription(int32_t serial, const SelectUiccSub& uiccSub);
-
-    Return<void> setDataAllowed(int32_t serial, bool allow);
-
-    Return<void> getHardwareConfig(int32_t serial);
-
-    Return<void> requestIccSimAuthentication(int32_t serial,
-            int32_t authContext,
-            const ::android::hardware::hidl_string& authData,
-            const ::android::hardware::hidl_string& aid);
-
-    Return<void> setDataProfile(int32_t serial,
-            const ::android::hardware::hidl_vec<DataProfileInfo>& profiles, bool isRoaming);
-
-    Return<void> requestShutdown(int32_t serial);
-
-    Return<void> getRadioCapability(int32_t serial);
-
-    Return<void> setRadioCapability(int32_t serial, const RadioCapability& rc);
-
-    Return<void> startLceService(int32_t serial, int32_t reportInterval, bool pullMode);
-
-    Return<void> stopLceService(int32_t serial);
-
-    Return<void> pullLceData(int32_t serial);
-
-    Return<void> getModemActivityInfo(int32_t serial);
-
-    Return<void> setAllowedCarriers(int32_t serial,
-            bool allAllowed,
-            const CarrierRestrictions& carriers);
-
-    Return<void> getAllowedCarriers(int32_t serial);
-
-    Return<void> sendDeviceState(int32_t serial, DeviceStateType deviceStateType, bool state);
-
-    Return<void> setIndicationFilter(int32_t serial, int32_t indicationFilter);
-
-    Return<void> startKeepalive(int32_t serial, const V1_1::KeepaliveRequest& keepalive);
-
-    Return<void> stopKeepalive(int32_t serial, int32_t sessionHandle);
-
-    Return<void> setSimCardPower(int32_t serial, bool powerUp);
-    Return<void> setSimCardPower_1_1(int32_t serial,
-            const V1_1::CardPowerState state);
-
-    Return<void> responseAcknowledgement();
-
-    Return<void> setCarrierInfoForImsiEncryption(int32_t serial,
-            const V1_1::ImsiEncryptionInfo& message);
-
-    void checkReturnStatus(Return<void>& ret);
-
-    // Methods from ::android::hardware::radio::V1_2::IRadio follow.
-    Return<void> startNetworkScan_1_2(int32_t serial,
-            const ::android::hardware::radio::V1_2::NetworkScanRequest& request);
-    Return<void> setIndicationFilter_1_2(int32_t serial,
-            hidl_bitfield<::android::hardware::radio::V1_2::IndicationFilter> indicationFilter);
-    Return<void> setSignalStrengthReportingCriteria(int32_t serial, int32_t hysteresisMs,
-            int32_t hysteresisDb, const hidl_vec<int32_t>& thresholdsDbm,
-            ::android::hardware::radio::V1_2::AccessNetwork accessNetwork);
-    Return<void> setLinkCapacityReportingCriteria(int32_t serial, int32_t hysteresisMs,
-            int32_t hysteresisDlKbps, int32_t hysteresisUlKbps,
-            const hidl_vec<int32_t>& thresholdsDownlinkKbps,
-            const hidl_vec<int32_t>& thresholdsUplinkKbps,
-            ::android::hardware::radio::V1_2::AccessNetwork accessNetwork);
-    Return<void> setupDataCall_1_2(int32_t serial,
-            ::android::hardware::radio::V1_2::AccessNetwork accessNetwork,
-            const ::android::hardware::radio::V1_0::DataProfileInfo& dataProfileInfo,
-            bool modemCognitive, bool roamingAllowed, bool isRoaming,
-            ::android::hardware::radio::V1_2::DataRequestReason reason,
-            const hidl_vec<hidl_string>& addresses, const hidl_vec<hidl_string>& dnses);
-    Return<void> deactivateDataCall_1_2(int32_t serial, int32_t cid,
-            ::android::hardware::radio::V1_2::DataRequestReason reason);
-
-    // Methods from ::android::hardware::radio::V1_3::IRadio follow.
-    Return<void> setSystemSelectionChannels(int32_t serial, bool specifyChannels,
-            const hidl_vec<::android::hardware::radio::V1_1::RadioAccessSpecifier>& specifiers);
-    Return<void> enableModem(int32_t serial, bool on);
-    Return<void> getModemStackStatus(int32_t serial);
-
-    // Methods from ::android::hardware::radio::V1_4::IRadio follow.
-    Return<void> setupDataCall_1_4(int32_t serial,
-            ::android::hardware::radio::V1_4::AccessNetwork accessNetwork,
-            const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo,
-            bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason reason,
-            const hidl_vec<hidl_string>& addresses, const hidl_vec<hidl_string>& dnses);
-    Return<void> setInitialAttachApn_1_4(int32_t serial,
-            const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo);
-    Return<void> setDataProfile_1_4(int32_t serial,
-            const hidl_vec<::android::hardware::radio::V1_4::DataProfileInfo>& profiles);
-    Return<void> emergencyDial(int32_t serial,
-            const ::android::hardware::radio::V1_0::Dial& dialInfo,
-            hidl_bitfield<android::hardware::radio::V1_4::EmergencyServiceCategory> categories,
-            const hidl_vec<hidl_string>& urns,
-            ::android::hardware::radio::V1_4::EmergencyCallRouting routing,
-            bool fromEmergencyDialer, bool isTesting);
-    Return<void> startNetworkScan_1_4(int32_t serial,
-            const ::android::hardware::radio::V1_2::NetworkScanRequest& request);
-    Return<void> getPreferredNetworkTypeBitmap(int32_t serial);
-    Return<void> setPreferredNetworkTypeBitmap(
-            int32_t serial, hidl_bitfield<RadioAccessFamily> networkTypeBitmap);
-    Return<void> setAllowedCarriers_1_4(int32_t serial,
-            const ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority& carriers,
-            ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicy);
-    Return<void> getAllowedCarriers_1_4(int32_t serial);
-    Return<void> getSignalStrength_1_4(int32_t serial);
-
-    // Methods from ::android::hardware::radio::V1_5::IRadio follow.
-    Return<void> setSignalStrengthReportingCriteria_1_5(int32_t serial,
-            const ::android::hardware::radio::V1_5::SignalThresholdInfo& signalThresholdInfo,
-            const ::android::hardware::radio::V1_5::AccessNetwork accessNetwork);
-    Return<void> setLinkCapacityReportingCriteria_1_5(int32_t serial, int32_t hysteresisMs,
-            int32_t hysteresisDlKbps, int32_t hysteresisUlKbps,
-            const hidl_vec<int32_t>& thresholdsDownlinkKbps,
-            const hidl_vec<int32_t>& thresholdsUplinkKbps,
-            V1_5::AccessNetwork accessNetwork);
-    Return<void> enableUiccApplications(int32_t serial, bool detach);
-    Return<void> areUiccApplicationsEnabled(int32_t serial);
-    Return<void> setSystemSelectionChannels_1_5(int32_t serial, bool specifyChannels,
-            const hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier>& specifiers);
-    Return<void> startNetworkScan_1_5(int32_t serial,
-            const ::android::hardware::radio::V1_5::NetworkScanRequest& request);
-    Return<void> setupDataCall_1_5(int32_t serial,
-            ::android::hardware::radio::V1_5::AccessNetwork accessNetwork,
-            const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
-            bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason reason,
-            const hidl_vec<::android::hardware::radio::V1_5::LinkAddress>& addresses,
-            const hidl_vec<hidl_string>& dnses);
-    Return<void> setInitialAttachApn_1_5(int32_t serial,
-            const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo);
-    Return<void> setDataProfile_1_5(int32_t serial,
-            const hidl_vec<::android::hardware::radio::V1_5::DataProfileInfo>& profiles);
-    Return<void> setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
-            bool preferredForEmergencyCall);
-    Return<void> setIndicationFilter_1_5(int32_t serial,
-            hidl_bitfield<::android::hardware::radio::V1_5::IndicationFilter> indicationFilter);
-    Return<void> getBarringInfo(int32_t serial);
-    Return<void> getVoiceRegistrationState_1_5(int32_t serial);
-    Return<void> getDataRegistrationState_1_5(int32_t serial);
-    Return<void> setNetworkSelectionModeManual_1_5(int32_t serial,
-            const hidl_string& operatorNumeric, V1_5::RadioAccessNetworks ran);
-    Return<void> sendCdmaSmsExpectMore(int32_t serial, const CdmaSmsMessage& sms);
-    Return<void> supplySimDepersonalization(int32_t serial, V1_5::PersoSubstate persoType,
-                                            const hidl_string& controlKey);
-};
-
-struct OemHookImpl : public IOemHook {
-    int32_t mSlotId;
-    sp<IOemHookResponse> mOemHookResponse;
-    sp<IOemHookIndication> mOemHookIndication;
-
-    Return<void> setResponseFunctions(
-            const ::android::sp<IOemHookResponse>& oemHookResponse,
-            const ::android::sp<IOemHookIndication>& oemHookIndication);
-
-    Return<void> sendRequestRaw(int32_t serial,
-            const ::android::hardware::hidl_vec<uint8_t>& data);
-
-    Return<void> sendRequestStrings(int32_t serial,
-            const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
-};
-
-void memsetAndFreeStrings(int numPointers, ...) {
-    va_list ap;
-    va_start(ap, numPointers);
-    for (int i = 0; i < numPointers; i++) {
-        char *ptr = va_arg(ap, char *);
-        if (ptr) {
-#ifdef MEMSET_FREED
-#define MAX_STRING_LENGTH 4096
-            memset(ptr, 0, strnlen(ptr, MAX_STRING_LENGTH));
-#endif
-            free(ptr);
-        }
-    }
-    va_end(ap);
-}
-
-void sendErrorResponse(RequestInfo *pRI, RIL_Errno err) {
-    pRI->pCI->responseFunction((int) pRI->socket_id,
-            (int) RadioResponseType::SOLICITED, pRI->token, err, NULL, 0);
-}
-
-/**
- * Copies over src to dest. If memory allocation fails, responseFunction() is called for the
- * request with error RIL_E_NO_MEMORY. The size() method is used to determine the size of the
- * destination buffer into which the HIDL string is copied. If there is a discrepancy between
- * the string length reported by the size() method, and the length of the string returned by
- * the c_str() method, the function will return false indicating a failure.
- *
- * Returns true on success, and false on failure.
- */
-bool copyHidlStringToRil(char **dest, const hidl_string &src, RequestInfo *pRI, bool allowEmpty) {
-    size_t len = src.size();
-    if (len == 0 && !allowEmpty) {
-        *dest = NULL;
-        return true;
-    }
-    *dest = (char *) calloc(len + 1, sizeof(char));
-    if (*dest == NULL) {
-        RLOGE("Memory allocation failed for request %s", requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-        return false;
-    }
-    if (strlcpy(*dest, src.c_str(), len + 1) >= (len + 1)) {
-        RLOGE("Copy of the HIDL string has been truncated, as "
-              "the string length reported by size() does not "
-              "match the length of string returned by c_str().");
-        free(*dest);
-        *dest = NULL;
-        sendErrorResponse(pRI, RIL_E_INTERNAL_ERR);
-        return false;
-    }
-    return true;
-}
-
-bool copyHidlStringToRil(char **dest, const hidl_string &src, RequestInfo *pRI) {
-    return copyHidlStringToRil(dest, src, pRI, false);
-}
-
-hidl_string convertCharPtrToHidlString(const char *ptr) {
-    hidl_string ret;
-    if (ptr != NULL) {
-        // TODO: replace this with strnlen
-        ret.setToExternal(ptr, strlen(ptr));
-    }
-    return ret;
-}
-
-bool dispatchVoid(int serial, int slotId, int request) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-    CALL_ONREQUEST(request, NULL, 0, pRI, slotId);
-    return true;
-}
-
-bool dispatchString(int serial, int slotId, int request, const char * str) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-
-    char *pString;
-    if (!copyHidlStringToRil(&pString, str, pRI)) {
-        return false;
-    }
-
-    CALL_ONREQUEST(request, pString, sizeof(char *), pRI, slotId);
-
-    memsetAndFreeStrings(1, pString);
-    return true;
-}
-
-bool dispatchStrings(int serial, int slotId, int request, bool allowEmpty, int countStrings, ...) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-
-    char **pStrings;
-    pStrings = (char **)calloc(countStrings, sizeof(char *));
-    if (pStrings == NULL) {
-        RLOGE("Memory allocation failed for request %s", requestToString(request));
-        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-        return false;
-    }
-    va_list ap;
-    va_start(ap, countStrings);
-    for (int i = 0; i < countStrings; i++) {
-        const char* str = va_arg(ap, const char *);
-        if (!copyHidlStringToRil(&pStrings[i], hidl_string(str), pRI, allowEmpty)) {
-            va_end(ap);
-            for (int j = 0; j < i; j++) {
-                memsetAndFreeStrings(1, pStrings[j]);
-            }
-            free(pStrings);
-            return false;
-        }
-    }
-    va_end(ap);
-
-    CALL_ONREQUEST(request, pStrings, countStrings * sizeof(char *), pRI, slotId);
-
-    if (pStrings != NULL) {
-        for (int i = 0 ; i < countStrings ; i++) {
-            memsetAndFreeStrings(1, pStrings[i]);
-        }
-
-#ifdef MEMSET_FREED
-        memset(pStrings, 0, countStrings * sizeof(char *));
-#endif
-        free(pStrings);
-    }
-    return true;
-}
-
-bool dispatchStrings(int serial, int slotId, int request, const hidl_vec<hidl_string>& data) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-
-    int countStrings = data.size();
-    char **pStrings;
-    pStrings = (char **)calloc(countStrings, sizeof(char *));
-    if (pStrings == NULL) {
-        RLOGE("Memory allocation failed for request %s", requestToString(request));
-        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-        return false;
-    }
-
-    for (int i = 0; i < countStrings; i++) {
-        if (!copyHidlStringToRil(&pStrings[i], data[i], pRI)) {
-            for (int j = 0; j < i; j++) {
-                memsetAndFreeStrings(1, pStrings[j]);
-            }
-            free(pStrings);
-            return false;
-        }
-    }
-
-    CALL_ONREQUEST(request, pStrings, countStrings * sizeof(char *), pRI, slotId);
-
-    if (pStrings != NULL) {
-        for (int i = 0 ; i < countStrings ; i++) {
-            memsetAndFreeStrings(1, pStrings[i]);
-        }
-
-#ifdef MEMSET_FREED
-        memset(pStrings, 0, countStrings * sizeof(char *));
-#endif
-        free(pStrings);
-    }
-    return true;
-}
-
-bool dispatchInts(int serial, int slotId, int request, int countInts, ...) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-
-    int *pInts = (int *)calloc(countInts, sizeof(int));
-
-    if (pInts == NULL) {
-        RLOGE("Memory allocation failed for request %s", requestToString(request));
-        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-        return false;
-    }
-    va_list ap;
-    va_start(ap, countInts);
-    for (int i = 0; i < countInts; i++) {
-        pInts[i] = va_arg(ap, int);
-    }
-    va_end(ap);
-
-    CALL_ONREQUEST(request, pInts, countInts * sizeof(int), pRI, slotId);
-
-    if (pInts != NULL) {
-#ifdef MEMSET_FREED
-        memset(pInts, 0, countInts * sizeof(int));
-#endif
-        free(pInts);
-    }
-    return true;
-}
-
-bool dispatchCallForwardStatus(int serial, int slotId, int request,
-                              const CallForwardInfo& callInfo) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-
-    RIL_CallForwardInfo cf;
-    cf.status = (int) callInfo.status;
-    cf.reason = callInfo.reason;
-    cf.serviceClass = callInfo.serviceClass;
-    cf.toa = callInfo.toa;
-    cf.timeSeconds = callInfo.timeSeconds;
-
-    if (!copyHidlStringToRil(&cf.number, callInfo.number, pRI)) {
-        return false;
-    }
-
-    CALL_ONREQUEST(request, &cf, sizeof(cf), pRI, slotId);
-
-    memsetAndFreeStrings(1, cf.number);
-
-    return true;
-}
-
-bool dispatchRaw(int serial, int slotId, int request, const hidl_vec<uint8_t>& rawBytes) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-
-    const uint8_t *uData = rawBytes.data();
-
-    CALL_ONREQUEST(request, (void *) uData, rawBytes.size(), pRI, slotId);
-
-    return true;
-}
-
-bool dispatchIccApdu(int serial, int slotId, int request, const SimApdu& message) {
-    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
-    if (pRI == NULL) {
-        return false;
-    }
-
-    RIL_SIM_APDU apdu = {};
-
-    apdu.sessionid = message.sessionId;
-    apdu.cla = message.cla;
-    apdu.instruction = message.instruction;
-    apdu.p1 = message.p1;
-    apdu.p2 = message.p2;
-    apdu.p3 = message.p3;
-
-    if (!copyHidlStringToRil(&apdu.data, message.data, pRI)) {
-        return false;
-    }
-
-    CALL_ONREQUEST(request, &apdu, sizeof(apdu), pRI, slotId);
-
-    memsetAndFreeStrings(1, apdu.data);
-
-    return true;
-}
-
-void checkReturnStatus(int32_t slotId, Return<void>& ret, bool isRadioService) {
-    if (ret.isOk() == false) {
-        RLOGE("checkReturnStatus: unable to call response/indication callback");
-        // Remote process hosting the callbacks must be dead. Reset the callback objects;
-        // there's no other recovery to be done here. When the client process is back up, it will
-        // call setResponseFunctions()
-
-        // Caller should already hold rdlock, release that first
-        // note the current counter to avoid overwriting updates made by another thread before
-        // write lock is acquired.
-        int counter = isRadioService ? mCounterRadio[slotId] : mCounterOemHook[slotId];
-        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_5::getRadioServiceRwlock(slotId);
-        int ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
-        assert(ret == 0);
-
-        // acquire wrlock
-        ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
-        assert(ret == 0);
-
-        // make sure the counter value has not changed
-        if (counter == (isRadioService ? mCounterRadio[slotId] : mCounterOemHook[slotId])) {
-            if (isRadioService) {
-                radioService[slotId]->mRadioResponse = NULL;
-                radioService[slotId]->mRadioIndication = NULL;
-                radioService[slotId]->mRadioResponseV1_2 = NULL;
-                radioService[slotId]->mRadioIndicationV1_2 = NULL;
-                radioService[slotId]->mRadioResponseV1_3 = NULL;
-                radioService[slotId]->mRadioIndicationV1_3 = NULL;
-                radioService[slotId]->mRadioResponseV1_4 = NULL;
-                radioService[slotId]->mRadioIndicationV1_4 = NULL;
-                radioService[slotId]->mRadioResponseV1_5 = NULL;
-                radioService[slotId]->mRadioIndicationV1_5 = NULL;
-            } else {
-                oemHookService[slotId]->mOemHookResponse = NULL;
-                oemHookService[slotId]->mOemHookIndication = NULL;
-            }
-            isRadioService ? mCounterRadio[slotId]++ : mCounterOemHook[slotId]++;
-        } else {
-            RLOGE("checkReturnStatus: not resetting responseFunctions as they likely "
-                    "got updated on another thread");
-        }
-
-        // release wrlock
-        ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
-        assert(ret == 0);
-
-        // Reacquire rdlock
-        ret = pthread_rwlock_rdlock(radioServiceRwlockPtr);
-        assert(ret == 0);
-    }
-}
-
-void RadioImpl_1_5::checkReturnStatus(Return<void>& ret) {
-    ::checkReturnStatus(mSlotId, ret, true);
-}
-
-Return<void> RadioImpl_1_5::setResponseFunctions(
-        const ::android::sp<IRadioResponse>& radioResponseParam,
-        const ::android::sp<IRadioIndication>& radioIndicationParam) {
-    RLOGD("setResponseFunctions");
-
-    pthread_rwlock_t *radioServiceRwlockPtr = radio_1_5::getRadioServiceRwlock(mSlotId);
-    int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
-    assert(ret == 0);
-
-    mRadioResponse = radioResponseParam;
-    mRadioIndication = radioIndicationParam;
-
-   mRadioResponseV1_5 = V1_5::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
-   mRadioIndicationV1_5 = V1_5::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
-   if (mRadioResponseV1_5 == nullptr || mRadioIndicationV1_5 == nullptr) {
-       mRadioResponseV1_5 = nullptr;
-       mRadioIndicationV1_5 = nullptr;
-   }
-
-    mRadioResponseV1_4 = V1_4::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
-    mRadioIndicationV1_4 = V1_4::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
-    if (mRadioResponseV1_4 == nullptr || mRadioIndicationV1_4 == nullptr) {
-        mRadioResponseV1_4 = nullptr;
-        mRadioIndicationV1_4 = nullptr;
-    }
-
-    mRadioResponseV1_3 = V1_3::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
-    mRadioIndicationV1_3 = V1_3::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
-    if (mRadioResponseV1_3 == nullptr || mRadioIndicationV1_3 == nullptr) {
-        mRadioResponseV1_3 = nullptr;
-        mRadioIndicationV1_3 = nullptr;
-    }
-
-    mRadioResponseV1_2 = V1_2::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
-    mRadioIndicationV1_2 = V1_2::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
-    if (mRadioResponseV1_2 == nullptr || mRadioIndicationV1_2 == nullptr) {
-        mRadioResponseV1_2 = nullptr;
-        mRadioIndicationV1_2 = nullptr;
-    }
-
-    mCounterRadio[mSlotId]++;
-
-    ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
-    assert(ret == 0);
-
-    // client is connected. Send initial indications.
-    android::onNewCommandConnect((RIL_SOCKET_ID) mSlotId);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getIccCardStatus(int32_t serial) {
-#if VDBG
-    RLOGD("getIccCardStatus: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SIM_STATUS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::supplyIccPinForApp(int32_t serial, const hidl_string& pin,
-        const hidl_string& aid) {
-#if VDBG
-    RLOGD("supplyIccPinForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PIN, true,
-            2, pin.c_str(), aid.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::supplyIccPukForApp(int32_t serial, const hidl_string& puk,
-                                           const hidl_string& pin, const hidl_string& aid) {
-#if VDBG
-    RLOGD("supplyIccPukForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PUK, true,
-            3, puk.c_str(), pin.c_str(), aid.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::supplyIccPin2ForApp(int32_t serial, const hidl_string& pin2,
-                                            const hidl_string& aid) {
-#if VDBG
-    RLOGD("supplyIccPin2ForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PIN2, true,
-            2, pin2.c_str(), aid.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::supplyIccPuk2ForApp(int32_t serial, const hidl_string& puk2,
-                                            const hidl_string& pin2, const hidl_string& aid) {
-#if VDBG
-    RLOGD("supplyIccPuk2ForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PUK2, true,
-            3, puk2.c_str(), pin2.c_str(), aid.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::changeIccPinForApp(int32_t serial, const hidl_string& oldPin,
-                                           const hidl_string& newPin, const hidl_string& aid) {
-#if VDBG
-    RLOGD("changeIccPinForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_CHANGE_SIM_PIN, true,
-            3, oldPin.c_str(), newPin.c_str(), aid.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::changeIccPin2ForApp(int32_t serial, const hidl_string& oldPin2,
-                                            const hidl_string& newPin2, const hidl_string& aid) {
-#if VDBG
-    RLOGD("changeIccPin2ForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_CHANGE_SIM_PIN2, true,
-            3, oldPin2.c_str(), newPin2.c_str(), aid.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::supplyNetworkDepersonalization(int32_t serial,
-                                                       const hidl_string& netPin) {
-#if VDBG
-    RLOGD("supplyNetworkDepersonalization: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, true,
-            1, netPin.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCurrentCalls(int32_t serial) {
-#if VDBG
-    RLOGD("getCurrentCalls: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CURRENT_CALLS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::dial(int32_t serial, const Dial& dialInfo) {
-#if VDBG
-    RLOGD("dial: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_DIAL);
-    if (pRI == NULL) {
-        return Void();
-    }
-    RIL_Dial dial = {};
-    RIL_UUS_Info uusInfo = {};
-    int32_t sizeOfDial = sizeof(dial);
-
-    if (!copyHidlStringToRil(&dial.address, dialInfo.address, pRI)) {
-        return Void();
-    }
-    dial.clir = (int) dialInfo.clir;
-
-    if (dialInfo.uusInfo.size() != 0) {
-        uusInfo.uusType = (RIL_UUS_Type) dialInfo.uusInfo[0].uusType;
-        uusInfo.uusDcs = (RIL_UUS_DCS) dialInfo.uusInfo[0].uusDcs;
-
-        if (dialInfo.uusInfo[0].uusData.size() == 0) {
-            uusInfo.uusData = NULL;
-            uusInfo.uusLength = 0;
-        } else {
-            if (!copyHidlStringToRil(&uusInfo.uusData, dialInfo.uusInfo[0].uusData, pRI)) {
-                memsetAndFreeStrings(1, dial.address);
-                return Void();
-            }
-            uusInfo.uusLength = dialInfo.uusInfo[0].uusData.size();
-        }
-
-        dial.uusInfo = &uusInfo;
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_DIAL, &dial, sizeOfDial, pRI, mSlotId);
-
-    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getImsiForApp(int32_t serial, const hidl_string& aid) {
-#if VDBG
-    RLOGD("getImsiForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_GET_IMSI, false,
-            1, aid.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::hangup(int32_t serial, int32_t gsmIndex) {
-#if VDBG
-    RLOGD("hangup: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_HANGUP, 1, gsmIndex);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::hangupWaitingOrBackground(int32_t serial) {
-#if VDBG
-    RLOGD("hangupWaitingOrBackground: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::hangupForegroundResumeBackground(int32_t serial) {
-#if VDBG
-    RLOGD("hangupForegroundResumeBackground: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::switchWaitingOrHoldingAndActive(int32_t serial) {
-#if VDBG
-    RLOGD("switchWaitingOrHoldingAndActive: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::conference(int32_t serial) {
-#if VDBG
-    RLOGD("conference: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_CONFERENCE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::rejectCall(int32_t serial) {
-#if VDBG
-    RLOGD("rejectCall: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_UDUB);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getLastCallFailCause(int32_t serial) {
-#if VDBG
-    RLOGD("getLastCallFailCause: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_LAST_CALL_FAIL_CAUSE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getSignalStrength(int32_t serial) {
-#if VDBG
-    RLOGD("getSignalStrength: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SIGNAL_STRENGTH);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getVoiceRegistrationState(int32_t serial) {
-#if VDBG
-    RLOGD("getVoiceRegistrationState: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_VOICE_REGISTRATION_STATE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getDataRegistrationState(int32_t serial) {
-#if VDBG
-    RLOGD("getDataRegistrationState: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_REGISTRATION_STATE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getOperator(int32_t serial) {
-#if VDBG
-    RLOGD("getOperator: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_OPERATOR);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setRadioPower(int32_t serial, bool on) {
-#if VDBG
-    RLOGD("setRadioPower: serial %d on %d", serial, on);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_RADIO_POWER, 1, BOOL_TO_INT(on));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendDtmf(int32_t serial, const hidl_string& s) {
-#if VDBG
-    RLOGD("sendDtmf: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_DTMF, s.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendSms(int32_t serial, const GsmSmsMessage& message) {
-#if VDBG
-    RLOGD("sendSms: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_SEND_SMS, false,
-            2, message.smscPdu.c_str(), message.pdu.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendSMSExpectMore(int32_t serial, const GsmSmsMessage& message) {
-#if VDBG
-    RLOGD("sendSMSExpectMore: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_SEND_SMS_EXPECT_MORE, false,
-            2, message.smscPdu.c_str(), message.pdu.c_str());
-    return Void();
-}
-
-static bool convertMvnoTypeToString(MvnoType type, char *&str) {
-    switch (type) {
-        case MvnoType::IMSI:
-            str = (char *)"imsi";
-            return true;
-        case MvnoType::GID:
-            str = (char *)"gid";
-            return true;
-        case MvnoType::SPN:
-            str = (char *)"spn";
-            return true;
-        case MvnoType::NONE:
-            str = (char *)"";
-            return true;
-    }
-    return false;
-}
-
-Return<void> RadioImpl_1_5::setupDataCall(int32_t serial, RadioTechnology radioTechnology,
-                                      const DataProfileInfo& dataProfileInfo, bool modemCognitive,
-                                      bool roamingAllowed, bool isRoaming) {
-
-#if VDBG
-    RLOGD("setupDataCall: serial %d", serial);
-#endif
-
-    if (s_vendorFunctions->version >= 4 && s_vendorFunctions->version <= 14) {
-        const hidl_string &protocol =
-                (isRoaming ? dataProfileInfo.roamingProtocol : dataProfileInfo.protocol);
-        dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 7,
-            std::to_string((int) radioTechnology + 2).c_str(),
-            std::to_string((int) dataProfileInfo.profileId).c_str(),
-            dataProfileInfo.apn.c_str(),
-            dataProfileInfo.user.c_str(),
-            dataProfileInfo.password.c_str(),
-            std::to_string((int) dataProfileInfo.authType).c_str(),
-            protocol.c_str());
-    } else if (s_vendorFunctions->version >= 15) {
-        char *mvnoTypeStr = NULL;
-        if (!convertMvnoTypeToString(dataProfileInfo.mvnoType, mvnoTypeStr)) {
-            RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-                    RIL_REQUEST_SETUP_DATA_CALL);
-            if (pRI != NULL) {
-                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-            }
-            return Void();
-        }
-        dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 15,
-            std::to_string((int) radioTechnology + 2).c_str(),
-            std::to_string((int) dataProfileInfo.profileId).c_str(),
-            dataProfileInfo.apn.c_str(),
-            dataProfileInfo.user.c_str(),
-            dataProfileInfo.password.c_str(),
-            std::to_string((int) dataProfileInfo.authType).c_str(),
-            dataProfileInfo.protocol.c_str(),
-            dataProfileInfo.roamingProtocol.c_str(),
-            std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
-            std::to_string(dataProfileInfo.bearerBitmap).c_str(),
-            modemCognitive ? "1" : "0",
-            std::to_string(dataProfileInfo.mtu).c_str(),
-            mvnoTypeStr,
-            dataProfileInfo.mvnoMatchData.c_str(),
-            roamingAllowed ? "1" : "0");
-    } else {
-        RLOGE("Unsupported RIL version %d, min version expected 4", s_vendorFunctions->version);
-        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-                RIL_REQUEST_SETUP_DATA_CALL);
-        if (pRI != NULL) {
-            sendErrorResponse(pRI, RIL_E_REQUEST_NOT_SUPPORTED);
-        }
-    }
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::iccIOForApp(int32_t serial, const IccIo& iccIo) {
-#if VDBG
-    RLOGD("iccIOForApp: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SIM_IO);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_SIM_IO_v6 rilIccIo = {};
-    rilIccIo.command = iccIo.command;
-    rilIccIo.fileid = iccIo.fileId;
-    if (!copyHidlStringToRil(&rilIccIo.path, iccIo.path, pRI)) {
-        return Void();
-    }
-
-    rilIccIo.p1 = iccIo.p1;
-    rilIccIo.p2 = iccIo.p2;
-    rilIccIo.p3 = iccIo.p3;
-
-    if (!copyHidlStringToRil(&rilIccIo.data, iccIo.data, pRI)) {
-        memsetAndFreeStrings(1, rilIccIo.path);
-        return Void();
-    }
-
-    if (!copyHidlStringToRil(&rilIccIo.pin2, iccIo.pin2, pRI)) {
-        memsetAndFreeStrings(2, rilIccIo.path, rilIccIo.data);
-        return Void();
-    }
-
-    if (!copyHidlStringToRil(&rilIccIo.aidPtr, iccIo.aid, pRI)) {
-        memsetAndFreeStrings(3, rilIccIo.path, rilIccIo.data, rilIccIo.pin2);
-        return Void();
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_SIM_IO, &rilIccIo, sizeof(rilIccIo), pRI, mSlotId);
-
-    memsetAndFreeStrings(4, rilIccIo.path, rilIccIo.data, rilIccIo.pin2, rilIccIo.aidPtr);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendUssd(int32_t serial, const hidl_string& ussd) {
-#if VDBG
-    RLOGD("sendUssd: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_SEND_USSD, ussd.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::cancelPendingUssd(int32_t serial) {
-#if VDBG
-    RLOGD("cancelPendingUssd: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_CANCEL_USSD);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getClir(int32_t serial) {
-#if VDBG
-    RLOGD("getClir: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CLIR);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setClir(int32_t serial, int32_t status) {
-#if VDBG
-    RLOGD("setClir: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_CLIR, 1, status);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCallForwardStatus(int32_t serial, const CallForwardInfo& callInfo) {
-#if VDBG
-    RLOGD("getCallForwardStatus: serial %d", serial);
-#endif
-    dispatchCallForwardStatus(serial, mSlotId, RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
-            callInfo);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCallForward(int32_t serial, const CallForwardInfo& callInfo) {
-#if VDBG
-    RLOGD("setCallForward: serial %d", serial);
-#endif
-    dispatchCallForwardStatus(serial, mSlotId, RIL_REQUEST_SET_CALL_FORWARD,
-            callInfo);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCallWaiting(int32_t serial, int32_t serviceClass) {
-#if VDBG
-    RLOGD("getCallWaiting: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_QUERY_CALL_WAITING, 1, serviceClass);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCallWaiting(int32_t serial, bool enable, int32_t serviceClass) {
-#if VDBG
-    RLOGD("setCallWaiting: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_CALL_WAITING, 2, BOOL_TO_INT(enable),
-            serviceClass);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::acknowledgeLastIncomingGsmSms(int32_t serial,
-                                                      bool success, SmsAcknowledgeFailCause cause) {
-#if VDBG
-    RLOGD("acknowledgeLastIncomingGsmSms: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SMS_ACKNOWLEDGE, 2, BOOL_TO_INT(success),
-            cause);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::acceptCall(int32_t serial) {
-#if VDBG
-    RLOGD("acceptCall: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_ANSWER);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::deactivateDataCall(int32_t serial,
-                                           int32_t cid, bool reasonRadioShutDown) {
-#if VDBG
-    RLOGD("deactivateDataCall: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_DEACTIVATE_DATA_CALL, false,
-            2, (std::to_string(cid)).c_str(), reasonRadioShutDown ? "1" : "0");
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getFacilityLockForApp(int32_t serial, const hidl_string& facility,
-                                              const hidl_string& password, int32_t serviceClass,
-                                              const hidl_string& appId) {
-#if VDBG
-    RLOGD("getFacilityLockForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_QUERY_FACILITY_LOCK, true,
-            4, facility.c_str(), password.c_str(),
-            (std::to_string(serviceClass)).c_str(), appId.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setFacilityLockForApp(int32_t serial, const hidl_string& facility,
-                                              bool lockState, const hidl_string& password,
-                                              int32_t serviceClass, const hidl_string& appId) {
-#if VDBG
-    RLOGD("setFacilityLockForApp: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_SET_FACILITY_LOCK, true,
-            5, facility.c_str(), lockState ? "1" : "0", password.c_str(),
-            (std::to_string(serviceClass)).c_str(), appId.c_str() );
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setBarringPassword(int32_t serial, const hidl_string& facility,
-                                           const hidl_string& oldPassword,
-                                           const hidl_string& newPassword) {
-#if VDBG
-    RLOGD("setBarringPassword: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_CHANGE_BARRING_PASSWORD, true,
-            3, facility.c_str(), oldPassword.c_str(), newPassword.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getNetworkSelectionMode(int32_t serial) {
-#if VDBG
-    RLOGD("getNetworkSelectionMode: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setNetworkSelectionModeAutomatic(int32_t serial) {
-#if VDBG
-    RLOGD("setNetworkSelectionModeAutomatic: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setNetworkSelectionModeManual(int32_t serial,
-                                                      const hidl_string& operatorNumeric) {
-#if VDBG
-    RLOGD("setNetworkSelectionModeManual: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
-            operatorNumeric.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getAvailableNetworks(int32_t serial) {
-#if VDBG
-    RLOGD("getAvailableNetworks: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::startNetworkScan(int32_t serial, const V1_1::NetworkScanRequest& request) {
-#if VDBG
-    RLOGD("startNetworkScan: serial %d", serial);
-#endif
-
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    if (request.specifiers.size() > MAX_RADIO_ACCESS_NETWORKS) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return Void();
-    }
-
-    RIL_NetworkScanRequest scan_request = {};
-
-    scan_request.type = (RIL_ScanType) request.type;
-    scan_request.interval = request.interval;
-    scan_request.specifiers_length = request.specifiers.size();
-    for (size_t i = 0; i < request.specifiers.size(); ++i) {
-        if (request.specifiers[i].geranBands.size() > MAX_BANDS ||
-            request.specifiers[i].utranBands.size() > MAX_BANDS ||
-            request.specifiers[i].eutranBands.size() > MAX_BANDS ||
-            request.specifiers[i].channels.size() > MAX_CHANNELS) {
-            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-            return Void();
-        }
-        const V1_1::RadioAccessSpecifier& ras_from =
-                request.specifiers[i];
-        RIL_RadioAccessSpecifier& ras_to = scan_request.specifiers[i];
-
-        ras_to.radio_access_network = (RIL_RadioAccessNetworks) ras_from.radioAccessNetwork;
-        ras_to.channels_length = ras_from.channels.size();
-
-        std::copy(ras_from.channels.begin(), ras_from.channels.end(), ras_to.channels);
-        const std::vector<uint32_t> * bands = nullptr;
-        switch (request.specifiers[i].radioAccessNetwork) {
-            case V1_1::RadioAccessNetworks::GERAN:
-                ras_to.bands_length = ras_from.geranBands.size();
-                bands = (std::vector<uint32_t> *) &ras_from.geranBands;
-                break;
-            case V1_1::RadioAccessNetworks::UTRAN:
-                ras_to.bands_length = ras_from.utranBands.size();
-                bands = (std::vector<uint32_t> *) &ras_from.utranBands;
-                break;
-            case V1_1::RadioAccessNetworks::EUTRAN:
-                ras_to.bands_length = ras_from.eutranBands.size();
-                bands = (std::vector<uint32_t> *) &ras_from.eutranBands;
-                break;
-            default:
-                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-                return Void();
-        }
-        // safe to copy to geran_bands because it's a union member
-        for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
-            ras_to.bands.geran_bands[idx] = (RIL_GeranBands) (*bands)[idx];
-        }
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
-            mSlotId);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::stopNetworkScan(int32_t serial) {
-#if VDBG
-    RLOGD("stopNetworkScan: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_STOP_NETWORK_SCAN);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::startDtmf(int32_t serial, const hidl_string& s) {
-#if VDBG
-    RLOGD("startDtmf: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_DTMF_START,
-            s.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::stopDtmf(int32_t serial) {
-#if VDBG
-    RLOGD("stopDtmf: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_DTMF_STOP);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getBasebandVersion(int32_t serial) {
-#if VDBG
-    RLOGD("getBasebandVersion: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_BASEBAND_VERSION);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::separateConnection(int32_t serial, int32_t gsmIndex) {
-#if VDBG
-    RLOGD("separateConnection: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SEPARATE_CONNECTION, 1, gsmIndex);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setMute(int32_t serial, bool enable) {
-#if VDBG
-    RLOGD("setMute: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_MUTE, 1, BOOL_TO_INT(enable));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getMute(int32_t serial) {
-#if VDBG
-    RLOGD("getMute: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_MUTE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getClip(int32_t serial) {
-#if VDBG
-    RLOGD("getClip: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_CLIP);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getDataCallList(int32_t serial) {
-#if VDBG
-    RLOGD("getDataCallList: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_CALL_LIST);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setSuppServiceNotifications(int32_t serial, bool enable) {
-#if VDBG
-    RLOGD("setSuppServiceNotifications: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, 1,
-            BOOL_TO_INT(enable));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::writeSmsToSim(int32_t serial, const SmsWriteArgs& smsWriteArgs) {
-#if VDBG
-    RLOGD("writeSmsToSim: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_WRITE_SMS_TO_SIM);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_SMS_WriteArgs args;
-    args.status = (int) smsWriteArgs.status;
-
-    if (!copyHidlStringToRil(&args.pdu, smsWriteArgs.pdu, pRI)) {
-        return Void();
-    }
-
-    if (!copyHidlStringToRil(&args.smsc, smsWriteArgs.smsc, pRI)) {
-        memsetAndFreeStrings(1, args.pdu);
-        return Void();
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_WRITE_SMS_TO_SIM, &args, sizeof(args), pRI, mSlotId);
-
-    memsetAndFreeStrings(2, args.smsc, args.pdu);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::deleteSmsOnSim(int32_t serial, int32_t index) {
-#if VDBG
-    RLOGD("deleteSmsOnSim: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_DELETE_SMS_ON_SIM, 1, index);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setBandMode(int32_t serial, RadioBandMode mode) {
-#if VDBG
-    RLOGD("setBandMode: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_BAND_MODE, 1, mode);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getAvailableBandModes(int32_t serial) {
-#if VDBG
-    RLOGD("getAvailableBandModes: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendEnvelope(int32_t serial, const hidl_string& command) {
-#if VDBG
-    RLOGD("sendEnvelope: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND,
-            command.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendTerminalResponseToSim(int32_t serial,
-                                                  const hidl_string& commandResponse) {
-#if VDBG
-    RLOGD("sendTerminalResponseToSim: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE,
-            commandResponse.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::handleStkCallSetupRequestFromSim(int32_t serial, bool accept) {
-#if VDBG
-    RLOGD("handleStkCallSetupRequestFromSim: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM,
-            1, BOOL_TO_INT(accept));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::explicitCallTransfer(int32_t serial) {
-#if VDBG
-    RLOGD("explicitCallTransfer: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_EXPLICIT_CALL_TRANSFER);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setPreferredNetworkType(int32_t serial, PreferredNetworkType nwType) {
-#if VDBG
-    RLOGD("setPreferredNetworkType: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, 1, nwType);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getPreferredNetworkType(int32_t serial) {
-#if VDBG
-    RLOGD("getPreferredNetworkType: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getNeighboringCids(int32_t serial) {
-#if VDBG
-    RLOGD("getNeighboringCids: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_NEIGHBORING_CELL_IDS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setLocationUpdates(int32_t serial, bool enable) {
-#if VDBG
-    RLOGD("setLocationUpdates: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_LOCATION_UPDATES, 1, BOOL_TO_INT(enable));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCdmaSubscriptionSource(int32_t serial, CdmaSubscriptionSource cdmaSub) {
-#if VDBG
-    RLOGD("setCdmaSubscriptionSource: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, 1, cdmaSub);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCdmaRoamingPreference(int32_t serial, CdmaRoamingType type) {
-#if VDBG
-    RLOGD("setCdmaRoamingPreference: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, 1, type);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCdmaRoamingPreference(int32_t serial) {
-#if VDBG
-    RLOGD("getCdmaRoamingPreference: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setTTYMode(int32_t serial, TtyMode mode) {
-#if VDBG
-    RLOGD("setTTYMode: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_TTY_MODE, 1, mode);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getTTYMode(int32_t serial) {
-#if VDBG
-    RLOGD("getTTYMode: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_TTY_MODE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setPreferredVoicePrivacy(int32_t serial, bool enable) {
-#if VDBG
-    RLOGD("setPreferredVoicePrivacy: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE,
-            1, BOOL_TO_INT(enable));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getPreferredVoicePrivacy(int32_t serial) {
-#if VDBG
-    RLOGD("getPreferredVoicePrivacy: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendCDMAFeatureCode(int32_t serial, const hidl_string& featureCode) {
-#if VDBG
-    RLOGD("sendCDMAFeatureCode: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_CDMA_FLASH,
-            featureCode.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendBurstDtmf(int32_t serial, const hidl_string& dtmf, int32_t on,
-                                      int32_t off) {
-#if VDBG
-    RLOGD("sendBurstDtmf: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_CDMA_BURST_DTMF, false,
-            3, dtmf.c_str(), (std::to_string(on)).c_str(),
-            (std::to_string(off)).c_str());
-    return Void();
-}
-
-void constructCdmaSms(RIL_CDMA_SMS_Message &rcsm, const CdmaSmsMessage& sms) {
-    rcsm.uTeleserviceID = sms.teleserviceId;
-    rcsm.bIsServicePresent = BOOL_TO_INT(sms.isServicePresent);
-    rcsm.uServicecategory = sms.serviceCategory;
-    rcsm.sAddress.digit_mode = (RIL_CDMA_SMS_DigitMode) sms.address.digitMode;
-    rcsm.sAddress.number_mode = (RIL_CDMA_SMS_NumberMode) sms.address.numberMode;
-    rcsm.sAddress.number_type = (RIL_CDMA_SMS_NumberType) sms.address.numberType;
-    rcsm.sAddress.number_plan = (RIL_CDMA_SMS_NumberPlan) sms.address.numberPlan;
-
-    rcsm.sAddress.number_of_digits = sms.address.digits.size();
-    int digitLimit= MIN((rcsm.sAddress.number_of_digits), RIL_CDMA_SMS_ADDRESS_MAX);
-    for (int i = 0; i < digitLimit; i++) {
-        rcsm.sAddress.digits[i] = sms.address.digits[i];
-    }
-
-    rcsm.sSubAddress.subaddressType = (RIL_CDMA_SMS_SubaddressType) sms.subAddress.subaddressType;
-    rcsm.sSubAddress.odd = BOOL_TO_INT(sms.subAddress.odd);
-
-    rcsm.sSubAddress.number_of_digits = sms.subAddress.digits.size();
-    digitLimit= MIN((rcsm.sSubAddress.number_of_digits), RIL_CDMA_SMS_SUBADDRESS_MAX);
-    for (int i = 0; i < digitLimit; i++) {
-        rcsm.sSubAddress.digits[i] = sms.subAddress.digits[i];
-    }
-
-    rcsm.uBearerDataLen = sms.bearerData.size();
-    digitLimit= MIN((rcsm.uBearerDataLen), RIL_CDMA_SMS_BEARER_DATA_MAX);
-    for (int i = 0; i < digitLimit; i++) {
-        rcsm.aBearerData[i] = sms.bearerData[i];
-    }
-}
-
-Return<void> RadioImpl_1_5::sendCdmaSms(int32_t serial, const CdmaSmsMessage& sms) {
-#if VDBG
-    RLOGD("sendCdmaSms: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_CDMA_SEND_SMS);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_CDMA_SMS_Message rcsm = {};
-    constructCdmaSms(rcsm, sms);
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsm, sizeof(rcsm), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::acknowledgeLastIncomingCdmaSms(int32_t serial, const CdmaSmsAck& smsAck) {
-#if VDBG
-    RLOGD("acknowledgeLastIncomingCdmaSms: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_CDMA_SMS_Ack rcsa = {};
-
-    rcsa.uErrorClass = (RIL_CDMA_SMS_ErrorClass) smsAck.errorClass;
-    rcsa.uSMSCauseCode = smsAck.smsCauseCode;
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsa, sizeof(rcsa), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getGsmBroadcastConfig(int32_t serial) {
-#if VDBG
-    RLOGD("getGsmBroadcastConfig: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setGsmBroadcastConfig(int32_t serial,
-                                              const hidl_vec<GsmBroadcastSmsConfigInfo>&
-                                              configInfo) {
-#if VDBG
-    RLOGD("setGsmBroadcastConfig: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    int num = configInfo.size();
-    if (num > MAX_BROADCAST_SMS_CONFIG_INFO) {
-        RLOGE("setGsmBroadcastConfig: Invalid configInfo length %s",
-                requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return Void();
-    }
-    RIL_GSM_BroadcastSmsConfigInfo gsmBci[num];
-    RIL_GSM_BroadcastSmsConfigInfo *gsmBciPtrs[num];
-
-    for (int i = 0 ; i < num ; i++ ) {
-        gsmBciPtrs[i] = &gsmBci[i];
-        gsmBci[i].fromServiceId = configInfo[i].fromServiceId;
-        gsmBci[i].toServiceId = configInfo[i].toServiceId;
-        gsmBci[i].fromCodeScheme = configInfo[i].fromCodeScheme;
-        gsmBci[i].toCodeScheme = configInfo[i].toCodeScheme;
-        gsmBci[i].selected = BOOL_TO_INT(configInfo[i].selected);
-    }
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, gsmBciPtrs,
-            num * sizeof(RIL_GSM_BroadcastSmsConfigInfo *), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setGsmBroadcastActivation(int32_t serial, bool activate) {
-#if VDBG
-    RLOGD("setGsmBroadcastActivation: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
-            1, BOOL_TO_INT(!activate));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCdmaBroadcastConfig(int32_t serial) {
-#if VDBG
-    RLOGD("getCdmaBroadcastConfig: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCdmaBroadcastConfig(int32_t serial,
-                                               const hidl_vec<CdmaBroadcastSmsConfigInfo>&
-                                               configInfo) {
-#if VDBG
-    RLOGD("setCdmaBroadcastConfig: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    int num = configInfo.size();
-    if (num > MAX_BROADCAST_SMS_CONFIG_INFO) {
-        RLOGE("setCdmaBroadcastConfig: Invalid configInfo length %s",
-                requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return Void();
-    }
-    RIL_CDMA_BroadcastSmsConfigInfo cdmaBci[num];
-    RIL_CDMA_BroadcastSmsConfigInfo *cdmaBciPtrs[num];
-
-    for (int i = 0 ; i < num ; i++ ) {
-        cdmaBciPtrs[i] = &cdmaBci[i];
-        cdmaBci[i].service_category = configInfo[i].serviceCategory;
-        cdmaBci[i].language = configInfo[i].language;
-        cdmaBci[i].selected = BOOL_TO_INT(configInfo[i].selected);
-    }
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, cdmaBciPtrs,
-            num * sizeof(RIL_CDMA_BroadcastSmsConfigInfo *), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCdmaBroadcastActivation(int32_t serial, bool activate) {
-#if VDBG
-    RLOGD("setCdmaBroadcastActivation: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION,
-            1, BOOL_TO_INT(!activate));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCDMASubscription(int32_t serial) {
-#if VDBG
-    RLOGD("getCDMASubscription: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_SUBSCRIPTION);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::writeSmsToRuim(int32_t serial, const CdmaSmsWriteArgs& cdmaSms) {
-#if VDBG
-    RLOGD("writeSmsToRuim: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_CDMA_SMS_WriteArgs rcsw = {};
-    rcsw.status = (int) cdmaSms.status;
-    constructCdmaSms(rcsw.message, cdmaSms.message);
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsw, sizeof(rcsw), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::deleteSmsOnRuim(int32_t serial, int32_t index) {
-#if VDBG
-    RLOGD("deleteSmsOnRuim: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, 1, index);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getDeviceIdentity(int32_t serial) {
-#if VDBG
-    RLOGD("getDeviceIdentity: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_DEVICE_IDENTITY);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::exitEmergencyCallbackMode(int32_t serial) {
-#if VDBG
-    RLOGD("exitEmergencyCallbackMode: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getSmscAddress(int32_t serial) {
-#if VDBG
-    RLOGD("getSmscAddress: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SMSC_ADDRESS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setSmscAddress(int32_t serial, const hidl_string& smsc) {
-#if VDBG
-    RLOGD("setSmscAddress: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_SET_SMSC_ADDRESS,
-            smsc.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::reportSmsMemoryStatus(int32_t serial, bool available) {
-#if VDBG
-    RLOGD("reportSmsMemoryStatus: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, 1,
-            BOOL_TO_INT(available));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::reportStkServiceIsRunning(int32_t serial) {
-#if VDBG
-    RLOGD("reportStkServiceIsRunning: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCdmaSubscriptionSource(int32_t serial) {
-#if VDBG
-    RLOGD("getCdmaSubscriptionSource: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::requestIsimAuthentication(int32_t serial, const hidl_string& challenge) {
-#if VDBG
-    RLOGD("requestIsimAuthentication: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_ISIM_AUTHENTICATION,
-            challenge.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::acknowledgeIncomingGsmSmsWithPdu(int32_t serial, bool success,
-                                                         const hidl_string& ackPdu) {
-#if VDBG
-    RLOGD("acknowledgeIncomingGsmSmsWithPdu: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, false,
-            2, success ? "1" : "0", ackPdu.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendEnvelopeWithStatus(int32_t serial, const hidl_string& contents) {
-#if VDBG
-    RLOGD("sendEnvelopeWithStatus: serial %d", serial);
-#endif
-    dispatchString(serial, mSlotId, RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS,
-            contents.c_str());
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getVoiceRadioTechnology(int32_t serial) {
-#if VDBG
-    RLOGD("getVoiceRadioTechnology: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_VOICE_RADIO_TECH);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getCellInfoList(int32_t serial) {
-#if VDBG
-    RLOGD("getCellInfoList: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CELL_INFO_LIST);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCellInfoListRate(int32_t serial, int32_t rate) {
-#if VDBG
-    RLOGD("setCellInfoListRate: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, 1, rate);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setInitialAttachApn(int32_t serial, const DataProfileInfo& dataProfileInfo,
-                                            bool modemCognitive, bool isRoaming) {
-#if VDBG
-    RLOGD("setInitialAttachApn: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_INITIAL_ATTACH_APN);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    if (s_vendorFunctions->version <= 14) {
-        RIL_InitialAttachApn iaa = {};
-
-        if (!copyHidlStringToRil(&iaa.apn, dataProfileInfo.apn, pRI, true)) {
-            return Void();
-        }
-
-        const hidl_string &protocol =
-                (isRoaming ? dataProfileInfo.roamingProtocol : dataProfileInfo.protocol);
-
-        if (!copyHidlStringToRil(&iaa.protocol, protocol, pRI)) {
-            memsetAndFreeStrings(1, iaa.apn);
-            return Void();
-        }
-        iaa.authtype = (int) dataProfileInfo.authType;
-        if (!copyHidlStringToRil(&iaa.username, dataProfileInfo.user, pRI)) {
-            memsetAndFreeStrings(2, iaa.apn, iaa.protocol);
-            return Void();
-        }
-        if (!copyHidlStringToRil(&iaa.password, dataProfileInfo.password, pRI)) {
-            memsetAndFreeStrings(3, iaa.apn, iaa.protocol, iaa.username);
-            return Void();
-        }
-
-        CALL_ONREQUEST(RIL_REQUEST_SET_INITIAL_ATTACH_APN, &iaa, sizeof(iaa), pRI, mSlotId);
-
-        memsetAndFreeStrings(4, iaa.apn, iaa.protocol, iaa.username, iaa.password);
-    } else {
-        RIL_InitialAttachApn_v15 iaa = {};
-
-        if (!copyHidlStringToRil(&iaa.apn, dataProfileInfo.apn, pRI, true)) {
-            return Void();
-        }
-
-        if (!copyHidlStringToRil(&iaa.protocol, dataProfileInfo.protocol, pRI)) {
-            memsetAndFreeStrings(1, iaa.apn);
-            return Void();
-        }
-        if (!copyHidlStringToRil(&iaa.roamingProtocol, dataProfileInfo.roamingProtocol, pRI)) {
-            memsetAndFreeStrings(2, iaa.apn, iaa.protocol);
-            return Void();
-        }
-        iaa.authtype = (int) dataProfileInfo.authType;
-        if (!copyHidlStringToRil(&iaa.username, dataProfileInfo.user, pRI)) {
-            memsetAndFreeStrings(3, iaa.apn, iaa.protocol, iaa.roamingProtocol);
-            return Void();
-        }
-        if (!copyHidlStringToRil(&iaa.password, dataProfileInfo.password, pRI)) {
-            memsetAndFreeStrings(4, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username);
-            return Void();
-        }
-        iaa.supportedTypesBitmask = dataProfileInfo.supportedApnTypesBitmap;
-        iaa.bearerBitmask = dataProfileInfo.bearerBitmap;
-        iaa.modemCognitive = BOOL_TO_INT(modemCognitive);
-        iaa.mtu = dataProfileInfo.mtu;
-
-        if (!convertMvnoTypeToString(dataProfileInfo.mvnoType, iaa.mvnoType)) {
-            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-            memsetAndFreeStrings(5, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username,
-                    iaa.password);
-            return Void();
-        }
-
-        if (!copyHidlStringToRil(&iaa.mvnoMatchData, dataProfileInfo.mvnoMatchData, pRI)) {
-            memsetAndFreeStrings(5, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username,
-                    iaa.password);
-            return Void();
-        }
-
-        CALL_ONREQUEST(RIL_REQUEST_SET_INITIAL_ATTACH_APN, &iaa, sizeof(iaa), pRI, mSlotId);
-
-        memsetAndFreeStrings(6, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username,
-                iaa.password, iaa.mvnoMatchData);
-    }
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getImsRegistrationState(int32_t serial) {
-#if VDBG
-    RLOGD("getImsRegistrationState: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_IMS_REGISTRATION_STATE);
-    return Void();
-}
-
-bool dispatchImsGsmSms(const ImsSmsMessage& message, RequestInfo *pRI) {
-    RIL_IMS_SMS_Message rism = {};
-    char **pStrings;
-    int countStrings = 2;
-    int dataLen = sizeof(char *) * countStrings;
-
-    rism.tech = RADIO_TECH_3GPP;
-    rism.retry = BOOL_TO_INT(message.retry);
-    rism.messageRef = message.messageRef;
-
-    if (message.gsmMessage.size() != 1) {
-        RLOGE("dispatchImsGsmSms: Invalid len %s", requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return false;
-    }
-
-    pStrings = (char **)calloc(countStrings, sizeof(char *));
-    if (pStrings == NULL) {
-        RLOGE("dispatchImsGsmSms: Memory allocation failed for request %s",
-                requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-        return false;
-    }
-
-    if (!copyHidlStringToRil(&pStrings[0], message.gsmMessage[0].smscPdu, pRI)) {
-#ifdef MEMSET_FREED
-        memset(pStrings, 0, dataLen);
-#endif
-        free(pStrings);
-        return false;
-    }
-
-    if (!copyHidlStringToRil(&pStrings[1], message.gsmMessage[0].pdu, pRI)) {
-        memsetAndFreeStrings(1, pStrings[0]);
-#ifdef MEMSET_FREED
-        memset(pStrings, 0, dataLen);
-#endif
-        free(pStrings);
-        return false;
-    }
-
-    rism.message.gsmMessage = pStrings;
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &rism, sizeof(RIL_RadioTechnologyFamily) +
-            sizeof(uint8_t) + sizeof(int32_t) + dataLen, pRI, pRI->socket_id);
-
-    for (int i = 0 ; i < countStrings ; i++) {
-        memsetAndFreeStrings(1, pStrings[i]);
-    }
-
-#ifdef MEMSET_FREED
-    memset(pStrings, 0, dataLen);
-#endif
-    free(pStrings);
-
-    return true;
-}
-
-struct ImsCdmaSms {
-    RIL_IMS_SMS_Message imsSms;
-    RIL_CDMA_SMS_Message cdmaSms;
-};
-
-bool dispatchImsCdmaSms(const ImsSmsMessage& message, RequestInfo *pRI) {
-    ImsCdmaSms temp = {};
-
-    if (message.cdmaMessage.size() != 1) {
-        RLOGE("dispatchImsCdmaSms: Invalid len %s", requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return false;
-    }
-
-    temp.imsSms.tech = RADIO_TECH_3GPP2;
-    temp.imsSms.retry = BOOL_TO_INT(message.retry);
-    temp.imsSms.messageRef = message.messageRef;
-    temp.imsSms.message.cdmaMessage = &temp.cdmaSms;
-
-    constructCdmaSms(temp.cdmaSms, message.cdmaMessage[0]);
-
-    // Vendor code expects payload length to include actual msg payload
-    // (sizeof(RIL_CDMA_SMS_Message)) instead of (RIL_CDMA_SMS_Message *) + size of other fields in
-    // RIL_IMS_SMS_Message
-    int payloadLen = sizeof(RIL_RadioTechnologyFamily) + sizeof(uint8_t) + sizeof(int32_t)
-            + sizeof(RIL_CDMA_SMS_Message);
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &temp.imsSms, payloadLen, pRI, pRI->socket_id);
-
-    return true;
-}
-
-Return<void> RadioImpl_1_5::sendImsSms(int32_t serial, const ImsSmsMessage& message) {
-#if VDBG
-    RLOGD("sendImsSms: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_IMS_SEND_SMS);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_RadioTechnologyFamily format = (RIL_RadioTechnologyFamily) message.tech;
-
-    if (RADIO_TECH_3GPP == format) {
-        dispatchImsGsmSms(message, pRI);
-    } else if (RADIO_TECH_3GPP2 == format) {
-        dispatchImsCdmaSms(message, pRI);
-    } else {
-        RLOGE("sendImsSms: Invalid radio tech %s",
-                requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-    }
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::iccTransmitApduBasicChannel(int32_t serial, const SimApdu& message) {
-#if VDBG
-    RLOGD("iccTransmitApduBasicChannel: serial %d", serial);
-#endif
-    dispatchIccApdu(serial, mSlotId, RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC, message);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::iccOpenLogicalChannel(int32_t serial, const hidl_string& aid, int32_t p2) {
-#if VDBG
-    RLOGD("iccOpenLogicalChannel: serial %d", serial);
-#endif
-    if (s_vendorFunctions->version < 15) {
-        dispatchString(serial, mSlotId, RIL_REQUEST_SIM_OPEN_CHANNEL, aid.c_str());
-    } else {
-        RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SIM_OPEN_CHANNEL);
-        if (pRI == NULL) {
-            return Void();
-        }
-
-        RIL_OpenChannelParams params = {};
-
-        params.p2 = p2;
-
-        if (!copyHidlStringToRil(&params.aidPtr, aid, pRI)) {
-            return Void();
-        }
-
-        CALL_ONREQUEST(pRI->pCI->requestNumber, &params, sizeof(params), pRI, mSlotId);
-
-        memsetAndFreeStrings(1, params.aidPtr);
-    }
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::iccCloseLogicalChannel(int32_t serial, int32_t channelId) {
-#if VDBG
-    RLOGD("iccCloseLogicalChannel: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SIM_CLOSE_CHANNEL, 1, channelId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::iccTransmitApduLogicalChannel(int32_t serial, const SimApdu& message) {
-#if VDBG
-    RLOGD("iccTransmitApduLogicalChannel: serial %d", serial);
-#endif
-    dispatchIccApdu(serial, mSlotId, RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, message);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::nvReadItem(int32_t serial, NvItem itemId) {
-#if VDBG
-    RLOGD("nvReadItem: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_NV_READ_ITEM);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_NV_ReadItem nvri = {};
-    nvri.itemID = (RIL_NV_Item) itemId;
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &nvri, sizeof(nvri), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::nvWriteItem(int32_t serial, const NvWriteItem& item) {
-#if VDBG
-    RLOGD("nvWriteItem: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_NV_WRITE_ITEM);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_NV_WriteItem nvwi = {};
-
-    nvwi.itemID = (RIL_NV_Item) item.itemId;
-
-    if (!copyHidlStringToRil(&nvwi.value, item.value, pRI)) {
-        return Void();
-    }
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &nvwi, sizeof(nvwi), pRI, mSlotId);
-
-    memsetAndFreeStrings(1, nvwi.value);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::nvWriteCdmaPrl(int32_t serial, const hidl_vec<uint8_t>& prl) {
-#if VDBG
-    RLOGD("nvWriteCdmaPrl: serial %d", serial);
-#endif
-    dispatchRaw(serial, mSlotId, RIL_REQUEST_NV_WRITE_CDMA_PRL, prl);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::nvResetConfig(int32_t serial, ResetNvType resetType) {
-    int rilResetType = -1;
-#if VDBG
-    RLOGD("nvResetConfig: serial %d", serial);
-#endif
-    /* Convert ResetNvType to RIL.h values
-     * RIL_REQUEST_NV_RESET_CONFIG
-     * 1 - reload all NV items
-     * 2 - erase NV reset (SCRTN)
-     * 3 - factory reset (RTN)
-     */
-    switch(resetType) {
-      case ResetNvType::RELOAD:
-        rilResetType = 1;
-        break;
-      case ResetNvType::ERASE:
-        rilResetType = 2;
-        break;
-      case ResetNvType::FACTORY_RESET:
-        rilResetType = 3;
-        break;
-    }
-    dispatchInts(serial, mSlotId, RIL_REQUEST_NV_RESET_CONFIG, 1, rilResetType);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setUiccSubscription(int32_t serial, const SelectUiccSub& uiccSub) {
-#if VDBG
-    RLOGD("setUiccSubscription: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_UICC_SUBSCRIPTION);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_SelectUiccSub rilUiccSub = {};
-
-    rilUiccSub.slot = uiccSub.slot;
-    rilUiccSub.app_index = uiccSub.appIndex;
-    rilUiccSub.sub_type = (RIL_SubscriptionType) uiccSub.subType;
-    rilUiccSub.act_status = (RIL_UiccSubActStatus) uiccSub.actStatus;
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &rilUiccSub, sizeof(rilUiccSub), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setDataAllowed(int32_t serial, bool allow) {
-#if VDBG
-    RLOGD("setDataAllowed: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_ALLOW_DATA, 1, BOOL_TO_INT(allow));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getHardwareConfig(int32_t serial) {
-#if VDBG
-    RLOGD("getHardwareConfig: serial %d", serial);
-#endif
-    RLOGD("getHardwareConfig: serial %d, mSlotId = %d", serial, mSlotId);
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_HARDWARE_CONFIG);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::requestIccSimAuthentication(int32_t serial, int32_t authContext,
-        const hidl_string& authData, const hidl_string& aid) {
-#if VDBG
-    RLOGD("requestIccSimAuthentication: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SIM_AUTHENTICATION);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_SimAuthentication pf = {};
-
-    pf.authContext = authContext;
-
-    if (!copyHidlStringToRil(&pf.authData, authData, pRI)) {
-        return Void();
-    }
-
-    if (!copyHidlStringToRil(&pf.aid, aid, pRI)) {
-        memsetAndFreeStrings(1, pf.authData);
-        return Void();
-    }
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &pf, sizeof(pf), pRI, mSlotId);
-
-    memsetAndFreeStrings(2, pf.authData, pf.aid);
-    return Void();
-}
-
-/**
- * @param numProfiles number of data profile
- * @param dataProfiles the pointer to the actual data profiles. The acceptable type is
-          RIL_DataProfileInfo or RIL_DataProfileInfo_v15.
- * @param dataProfilePtrs the pointer to the pointers that point to each data profile structure
- * @param numfields number of string-type member in the data profile structure
- * @param ... the variadic parameters are pointers to each string-type member
- **/
-template <typename T>
-void freeSetDataProfileData(int numProfiles, T *dataProfiles, T **dataProfilePtrs,
-                            int numfields, ...) {
-    va_list args;
-    va_start(args, numfields);
-
-    // Iterate through each string-type field that need to be free.
-    for (int i = 0; i < numfields; i++) {
-        // Iterate through each data profile and free that specific string-type field.
-        // The type 'char *T::*' is a type of pointer to a 'char *' member inside T structure.
-        char *T::*ptr = va_arg(args, char *T::*);
-        for (int j = 0; j < numProfiles; j++) {
-            memsetAndFreeStrings(1, dataProfiles[j].*ptr);
-        }
-    }
-
-    va_end(args);
-
-#ifdef MEMSET_FREED
-    memset(dataProfiles, 0, numProfiles * sizeof(T));
-    memset(dataProfilePtrs, 0, numProfiles * sizeof(T *));
-#endif
-    free(dataProfiles);
-    free(dataProfilePtrs);
-}
-
-Return<void> RadioImpl_1_5::setDataProfile(int32_t serial, const hidl_vec<DataProfileInfo>& profiles,
-                                       bool isRoaming) {
-#if VDBG
-    RLOGD("setDataProfile: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SET_DATA_PROFILE);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    size_t num = profiles.size();
-    bool success = false;
-
-    if (s_vendorFunctions->version <= 14) {
-
-        RIL_DataProfileInfo *dataProfiles =
-            (RIL_DataProfileInfo *) calloc(num, sizeof(RIL_DataProfileInfo));
-
-        if (dataProfiles == NULL) {
-            RLOGE("Memory allocation failed for request %s",
-                    requestToString(pRI->pCI->requestNumber));
-            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-            return Void();
-        }
-
-        RIL_DataProfileInfo **dataProfilePtrs =
-            (RIL_DataProfileInfo **) calloc(num, sizeof(RIL_DataProfileInfo *));
-        if (dataProfilePtrs == NULL) {
-            RLOGE("Memory allocation failed for request %s",
-                    requestToString(pRI->pCI->requestNumber));
-            free(dataProfiles);
-            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-            return Void();
-        }
-
-        for (size_t i = 0; i < num; i++) {
-            dataProfilePtrs[i] = &dataProfiles[i];
-
-            success = copyHidlStringToRil(&dataProfiles[i].apn, profiles[i].apn, pRI, true);
-
-            const hidl_string &protocol =
-                    (isRoaming ? profiles[i].roamingProtocol : profiles[i].protocol);
-
-            if (success && !copyHidlStringToRil(&dataProfiles[i].protocol, protocol, pRI, true)) {
-                success = false;
-            }
-
-            if (success && !copyHidlStringToRil(&dataProfiles[i].user, profiles[i].user, pRI,
-                    true)) {
-                success = false;
-            }
-            if (success && !copyHidlStringToRil(&dataProfiles[i].password, profiles[i].password,
-                    pRI, true)) {
-                success = false;
-            }
-
-            if (!success) {
-                freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 4,
-                    &RIL_DataProfileInfo::apn, &RIL_DataProfileInfo::protocol,
-                    &RIL_DataProfileInfo::user, &RIL_DataProfileInfo::password);
-                return Void();
-            }
-
-            dataProfiles[i].profileId = (RIL_DataProfile) profiles[i].profileId;
-            dataProfiles[i].authType = (int) profiles[i].authType;
-            dataProfiles[i].type = (int) profiles[i].type;
-            dataProfiles[i].maxConnsTime = profiles[i].maxConnsTime;
-            dataProfiles[i].maxConns = profiles[i].maxConns;
-            dataProfiles[i].waitTime = profiles[i].waitTime;
-            dataProfiles[i].enabled = BOOL_TO_INT(profiles[i].enabled);
-        }
-
-        CALL_ONREQUEST(RIL_REQUEST_SET_DATA_PROFILE, dataProfilePtrs,
-                num * sizeof(RIL_DataProfileInfo *), pRI, mSlotId);
-
-        freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 4,
-                &RIL_DataProfileInfo::apn, &RIL_DataProfileInfo::protocol,
-                &RIL_DataProfileInfo::user, &RIL_DataProfileInfo::password);
-    } else {
-        RIL_DataProfileInfo_v15 *dataProfiles =
-            (RIL_DataProfileInfo_v15 *) calloc(num, sizeof(RIL_DataProfileInfo_v15));
-
-        if (dataProfiles == NULL) {
-            RLOGE("Memory allocation failed for request %s",
-                    requestToString(pRI->pCI->requestNumber));
-            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-            return Void();
-        }
-
-        RIL_DataProfileInfo_v15 **dataProfilePtrs =
-            (RIL_DataProfileInfo_v15 **) calloc(num, sizeof(RIL_DataProfileInfo_v15 *));
-        if (dataProfilePtrs == NULL) {
-            RLOGE("Memory allocation failed for request %s",
-                    requestToString(pRI->pCI->requestNumber));
-            free(dataProfiles);
-            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-            return Void();
-        }
-
-        for (size_t i = 0; i < num; i++) {
-            dataProfilePtrs[i] = &dataProfiles[i];
-
-            success = copyHidlStringToRil(&dataProfiles[i].apn, profiles[i].apn, pRI, true);
-            if (success && !copyHidlStringToRil(&dataProfiles[i].protocol, profiles[i].protocol,
-                    pRI)) {
-                success = false;
-            }
-            if (success && !copyHidlStringToRil(&dataProfiles[i].roamingProtocol,
-                    profiles[i].roamingProtocol, pRI, true)) {
-                success = false;
-            }
-            if (success && !copyHidlStringToRil(&dataProfiles[i].user, profiles[i].user, pRI,
-                    true)) {
-                success = false;
-            }
-            if (success && !copyHidlStringToRil(&dataProfiles[i].password, profiles[i].password,
-                    pRI, true)) {
-                success = false;
-            }
-            if (success && !copyHidlStringToRil(&dataProfiles[i].mvnoMatchData,
-                    profiles[i].mvnoMatchData, pRI, true)) {
-                success = false;
-            }
-
-            if (success && !convertMvnoTypeToString(profiles[i].mvnoType,
-                    dataProfiles[i].mvnoType)) {
-                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-                success = false;
-            }
-
-            if (!success) {
-                freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 6,
-                    &RIL_DataProfileInfo_v15::apn, &RIL_DataProfileInfo_v15::protocol,
-                    &RIL_DataProfileInfo_v15::roamingProtocol, &RIL_DataProfileInfo_v15::user,
-                    &RIL_DataProfileInfo_v15::password, &RIL_DataProfileInfo_v15::mvnoMatchData);
-                return Void();
-            }
-
-            dataProfiles[i].profileId = (RIL_DataProfile) profiles[i].profileId;
-            dataProfiles[i].authType = (int) profiles[i].authType;
-            dataProfiles[i].type = (int) profiles[i].type;
-            dataProfiles[i].maxConnsTime = profiles[i].maxConnsTime;
-            dataProfiles[i].maxConns = profiles[i].maxConns;
-            dataProfiles[i].waitTime = profiles[i].waitTime;
-            dataProfiles[i].enabled = BOOL_TO_INT(profiles[i].enabled);
-            dataProfiles[i].supportedTypesBitmask = profiles[i].supportedApnTypesBitmap;
-            dataProfiles[i].bearerBitmask = profiles[i].bearerBitmap;
-            dataProfiles[i].mtu = profiles[i].mtu;
-        }
-
-        CALL_ONREQUEST(RIL_REQUEST_SET_DATA_PROFILE, dataProfilePtrs,
-                num * sizeof(RIL_DataProfileInfo_v15 *), pRI, mSlotId);
-
-        freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 6,
-                &RIL_DataProfileInfo_v15::apn, &RIL_DataProfileInfo_v15::protocol,
-                &RIL_DataProfileInfo_v15::roamingProtocol, &RIL_DataProfileInfo_v15::user,
-                &RIL_DataProfileInfo_v15::password, &RIL_DataProfileInfo_v15::mvnoMatchData);
-    }
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::requestShutdown(int32_t serial) {
-#if VDBG
-    RLOGD("requestShutdown: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SHUTDOWN);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getRadioCapability(int32_t serial) {
-#if VDBG
-    RLOGD("getRadioCapability: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_RADIO_CAPABILITY);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setRadioCapability(int32_t serial, const RadioCapability& rc) {
-#if VDBG
-    RLOGD("setRadioCapability: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SET_RADIO_CAPABILITY);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_RadioCapability rilRc = {};
-
-    // TODO : set rilRc.version using HIDL version ?
-    rilRc.session = rc.session;
-    rilRc.phase = (int) rc.phase;
-    rilRc.rat = (int) rc.raf;
-    rilRc.status = (int) rc.status;
-    strlcpy(rilRc.logicalModemUuid, rc.logicalModemUuid.c_str(), sizeof(rilRc.logicalModemUuid));
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &rilRc, sizeof(rilRc), pRI, mSlotId);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::startLceService(int32_t serial, int32_t reportInterval, bool pullMode) {
-#if VDBG
-    RLOGD("startLceService: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_START_LCE, 2, reportInterval,
-            BOOL_TO_INT(pullMode));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::stopLceService(int32_t serial) {
-#if VDBG
-    RLOGD("stopLceService: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_STOP_LCE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::pullLceData(int32_t serial) {
-#if VDBG
-    RLOGD("pullLceData: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_PULL_LCEDATA);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getModemActivityInfo(int32_t serial) {
-#if VDBG
-    RLOGD("getModemActivityInfo: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_ACTIVITY_INFO);
-    return Void();
-}
-
-int prepareCarrierRestrictions(RIL_CarrierRestrictions &request, bool allAllowed,
-                               const hidl_vec<Carrier>& allowedList,
-                               const hidl_vec<Carrier>& excludedList,
-                               RequestInfo *pRI) {
-    RIL_Carrier *allowedCarriers = NULL;
-    RIL_Carrier *excludedCarriers = NULL;
-
-    request.len_allowed_carriers = allowedList.size();
-    allowedCarriers = (RIL_Carrier *)calloc(request.len_allowed_carriers, sizeof(RIL_Carrier));
-    if (allowedCarriers == NULL) {
-        RLOGE("prepareCarrierRestrictions: Memory allocation failed for request %s",
-                requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-        return -1;
-    }
-    request.allowed_carriers = allowedCarriers;
-
-    request.len_excluded_carriers = excludedList.size();
-    excludedCarriers = (RIL_Carrier *)calloc(request.len_excluded_carriers, sizeof(RIL_Carrier));
-    if (excludedCarriers == NULL) {
-        RLOGE("prepareCarrierRestrictions: Memory allocation failed for request %s",
-                requestToString(pRI->pCI->requestNumber));
-        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
-#ifdef MEMSET_FREED
-        memset(allowedCarriers, 0, request.len_allowed_carriers * sizeof(RIL_Carrier));
-#endif
-        free(allowedCarriers);
-        return -1;
-    }
-    request.excluded_carriers = excludedCarriers;
-
-    for (int i = 0; i < request.len_allowed_carriers; i++) {
-        allowedCarriers[i].mcc = allowedList[i].mcc.c_str();
-        allowedCarriers[i].mnc = allowedList[i].mnc.c_str();
-        allowedCarriers[i].match_type = (RIL_CarrierMatchType) allowedList[i].matchType;
-        allowedCarriers[i].match_data = allowedList[i].matchData.c_str();
-    }
-
-    for (int i = 0; i < request.len_excluded_carriers; i++) {
-        excludedCarriers[i].mcc = excludedList[i].mcc.c_str();
-        excludedCarriers[i].mnc = excludedList[i].mnc.c_str();
-        excludedCarriers[i].match_type =
-                (RIL_CarrierMatchType) excludedList[i].matchType;
-        excludedCarriers[i].match_data = excludedList[i].matchData.c_str();
-    }
-
-    return 0;
-}
-
-void freeCarrierRestrictions(RIL_CarrierRestrictions &request) {
-    if (request.allowed_carriers != NULL) {
-#ifdef MEMSET_FREED
-        memset(request.allowed_carriers, 0, request.len_allowed_carriers * sizeof(RIL_Carrier));
-#endif
-        free(request.allowed_carriers);
-    }
-    if (request.excluded_carriers != NULL) {
-#ifdef MEMSET_FREED
-        memset(request.excluded_carriers, 0, request.len_excluded_carriers * sizeof(RIL_Carrier));
-#endif
-        free(request.excluded_carriers);
-    }
-}
-
-Return<void> RadioImpl_1_5::setAllowedCarriers(int32_t serial, bool allAllowed,
-                                           const CarrierRestrictions& carriers) {
-#if VDBG
-    RLOGD("setAllowedCarriers: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_CARRIER_RESTRICTIONS);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_CarrierRestrictions cr = {};
-    if (prepareCarrierRestrictions(cr, allAllowed, carriers.allowedCarriers,
-            carriers.excludedCarriers, pRI) < 0) {
-        return Void();
-    }
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &cr, sizeof(RIL_CarrierRestrictions), pRI, mSlotId);
-
-    freeCarrierRestrictions(cr);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getAllowedCarriers(int32_t serial) {
-#if VDBG
-    RLOGD("getAllowedCarriers: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CARRIER_RESTRICTIONS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendDeviceState(int32_t serial, DeviceStateType deviceStateType,
-                                        bool state) {
-#if VDBG
-    RLOGD("sendDeviceState: serial %d", serial);
-#endif
-    if (s_vendorFunctions->version < 15) {
-        if (deviceStateType ==  DeviceStateType::LOW_DATA_EXPECTED) {
-            RLOGD("sendDeviceState: calling screen state %d", BOOL_TO_INT(!state));
-            dispatchInts(serial, mSlotId, RIL_REQUEST_SCREEN_STATE, 1, BOOL_TO_INT(!state));
-        } else {
-            RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-                    RIL_REQUEST_SEND_DEVICE_STATE);
-            sendErrorResponse(pRI, RIL_E_REQUEST_NOT_SUPPORTED);
-        }
-        return Void();
-    }
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SEND_DEVICE_STATE, 2, (int) deviceStateType,
-            BOOL_TO_INT(state));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setIndicationFilter(int32_t serial, int32_t indicationFilter) {
-#if VDBG
-    RLOGD("setIndicationFilter: serial %d", serial);
-#endif
-    if (s_vendorFunctions->version < 15) {
-        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-                RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER);
-        sendErrorResponse(pRI, RIL_E_REQUEST_NOT_SUPPORTED);
-        return Void();
-    }
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER, 1, indicationFilter);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setSimCardPower(int32_t serial, bool powerUp) {
-#if VDBG
-    RLOGD("setSimCardPower: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_SIM_CARD_POWER, 1, BOOL_TO_INT(powerUp));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setSimCardPower_1_1(int32_t serial, const V1_1::CardPowerState state) {
-#if VDBG
-    RLOGD("setSimCardPower_1_1: serial %d state %d", serial, state);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_SIM_CARD_POWER, 1, state);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setCarrierInfoForImsiEncryption(int32_t serial,
-        const V1_1::ImsiEncryptionInfo& data) {
-#if VDBG
-    RLOGD("setCarrierInfoForImsiEncryption: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(
-            serial, mSlotId, RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_CarrierInfoForImsiEncryption imsiEncryption = {};
-
-    if (!copyHidlStringToRil(&imsiEncryption.mnc, data.mnc, pRI)) {
-        return Void();
-    }
-    if (!copyHidlStringToRil(&imsiEncryption.mcc, data.mcc, pRI)) {
-        memsetAndFreeStrings(1, imsiEncryption.mnc);
-        return Void();
-    }
-    if (!copyHidlStringToRil(&imsiEncryption.keyIdentifier, data.keyIdentifier, pRI)) {
-        memsetAndFreeStrings(2, imsiEncryption.mnc, imsiEncryption.mcc);
-        return Void();
-    }
-    imsiEncryption.carrierKeyLength = data.carrierKey.size();
-    imsiEncryption.carrierKey = new uint8_t[imsiEncryption.carrierKeyLength];
-    memcpy(imsiEncryption.carrierKey, data.carrierKey.data(), imsiEncryption.carrierKeyLength);
-    imsiEncryption.expirationTime = data.expirationTime;
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &imsiEncryption,
-            sizeof(RIL_CarrierInfoForImsiEncryption), pRI, mSlotId);
-    delete(imsiEncryption.carrierKey);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::startKeepalive(int32_t serial, const V1_1::KeepaliveRequest& keepalive) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_KEEPALIVE);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_KeepaliveRequest kaReq = {};
-
-    kaReq.type = static_cast<RIL_KeepaliveType>(keepalive.type);
-    switch(kaReq.type) {
-        case NATT_IPV4:
-            if (keepalive.sourceAddress.size() != 4 ||
-                    keepalive.destinationAddress.size() != 4) {
-                RLOGE("Invalid address for keepalive!");
-                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-                return Void();
-            }
-            break;
-        case NATT_IPV6:
-            if (keepalive.sourceAddress.size() != 16 ||
-                    keepalive.destinationAddress.size() != 16) {
-                RLOGE("Invalid address for keepalive!");
-                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-                return Void();
-            }
-            break;
-        default:
-            RLOGE("Unknown packet keepalive type!");
-            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-            return Void();
-    }
-
-    ::memcpy(kaReq.sourceAddress, keepalive.sourceAddress.data(), keepalive.sourceAddress.size());
-    kaReq.sourcePort = keepalive.sourcePort;
-
-    ::memcpy(kaReq.destinationAddress,
-            keepalive.destinationAddress.data(), keepalive.destinationAddress.size());
-    kaReq.destinationPort = keepalive.destinationPort;
-
-    kaReq.maxKeepaliveIntervalMillis = keepalive.maxKeepaliveIntervalMillis;
-    kaReq.cid = keepalive.cid; // This is the context ID of the data call
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &kaReq, sizeof(RIL_KeepaliveRequest), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::stopKeepalive(int32_t serial, int32_t sessionHandle) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_STOP_KEEPALIVE);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &sessionHandle, sizeof(uint32_t), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::responseAcknowledgement() {
-    android::releaseWakeLock();
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::V1_2::IRadio follow.
-int prepareNetworkScanRequest_1_2(RIL_NetworkScanRequest &scan_request,
-    const ::android::hardware::radio::V1_2::NetworkScanRequest& request,
-    RequestInfo *pRI) {
-
-    scan_request.type = (RIL_ScanType) request.type;
-    scan_request.interval = request.interval;
-    scan_request.specifiers_length = request.specifiers.size();
-
-    int intervalLow = static_cast<int>(::android::hardware::radio::V1_2::ScanIntervalRange::MIN);
-    int intervalHigh = static_cast<int>(::android::hardware::radio::V1_2::ScanIntervalRange::MAX);
-    int maxSearchTimeLow =
-        static_cast<int>(::android::hardware::radio::V1_2::MaxSearchTimeRange::MIN);
-    int maxSearchTimeHigh =
-        static_cast<int>(::android::hardware::radio::V1_2::MaxSearchTimeRange::MAX);
-    int incrementalResultsPeriodicityRangeLow =
-        static_cast<int>(::android::hardware::radio::V1_2::IncrementalResultsPeriodicityRange::MIN);
-    int incrementalResultsPeriodicityRangeHigh =
-        static_cast<int>(::android::hardware::radio::V1_2::IncrementalResultsPeriodicityRange::MAX);
-    uint maxSpecifierSize =
-        static_cast<uint>(::android::hardware::radio::V1_2::RadioConst
-            ::RADIO_ACCESS_SPECIFIER_MAX_SIZE);
-
-    if (request.interval < intervalLow || request.interval > intervalHigh) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-    // If defined, must fall in correct range.
-    if (request.maxSearchTime != 0
-        && (request.maxSearchTime < maxSearchTimeLow
-            || request.maxSearchTime > maxSearchTimeHigh)) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-    if (request.maxSearchTime != 0
-        && (request.incrementalResultsPeriodicity < incrementalResultsPeriodicityRangeLow
-            || request.incrementalResultsPeriodicity > incrementalResultsPeriodicityRangeHigh
-            || request.incrementalResultsPeriodicity > request.maxSearchTime)) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-    if (request.specifiers.size() == 0 || request.specifiers.size() > maxSpecifierSize) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-
-    for (size_t i = 0; i < request.specifiers.size(); ++i) {
-        if (request.specifiers[i].geranBands.size() > MAX_BANDS ||
-            request.specifiers[i].utranBands.size() > MAX_BANDS ||
-            request.specifiers[i].eutranBands.size() > MAX_BANDS ||
-            request.specifiers[i].channels.size() > MAX_CHANNELS) {
-            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-            return -1;
-        }
-        const V1_1::RadioAccessSpecifier& ras_from =
-                request.specifiers[i];
-        RIL_RadioAccessSpecifier& ras_to = scan_request.specifiers[i];
-
-        ras_to.radio_access_network = (RIL_RadioAccessNetworks) ras_from.radioAccessNetwork;
-        ras_to.channels_length = ras_from.channels.size();
-
-        std::copy(ras_from.channels.begin(), ras_from.channels.end(), ras_to.channels);
-        const std::vector<uint32_t> * bands = nullptr;
-        switch (request.specifiers[i].radioAccessNetwork) {
-            case V1_1::RadioAccessNetworks::GERAN:
-                ras_to.bands_length = ras_from.geranBands.size();
-                bands = (std::vector<uint32_t> *) &ras_from.geranBands;
-                break;
-            case V1_1::RadioAccessNetworks::UTRAN:
-                ras_to.bands_length = ras_from.utranBands.size();
-                bands = (std::vector<uint32_t> *) &ras_from.utranBands;
-                break;
-            case V1_1::RadioAccessNetworks::EUTRAN:
-                ras_to.bands_length = ras_from.eutranBands.size();
-                bands = (std::vector<uint32_t> *) &ras_from.eutranBands;
-                break;
-            default:
-                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-                return -1;
-        }
-        // safe to copy to geran_bands because it's a union member
-        for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
-            ras_to.bands.geran_bands[idx] = (RIL_GeranBands) (*bands)[idx];
-        }
-    }
-
-    return 0;
-}
-
-Return<void> RadioImpl_1_5::startNetworkScan_1_2(int32_t serial,
-        const ::android::hardware::radio::V1_2::NetworkScanRequest& request) {
-#if VDBG
-    RLOGD("startNetworkScan_1_2: serial %d", serial);
-#endif
-
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_NetworkScanRequest scan_request = {};
-
-    if (prepareNetworkScanRequest_1_2(scan_request, request, pRI) < 0) {
-        return Void();
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
-            mSlotId);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setIndicationFilter_1_2(int32_t /* serial */,
-        hidl_bitfield<::android::hardware::radio::V1_2::IndicationFilter> /* indicationFilter */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setSignalStrengthReportingCriteria(int32_t /* serial */,
-        int32_t /* hysteresisMs */, int32_t /* hysteresisDb */,
-        const hidl_vec<int32_t>& /* thresholdsDbm */,
-        ::android::hardware::radio::V1_2::AccessNetwork /* accessNetwork */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setLinkCapacityReportingCriteria(int32_t /* serial */,
-        int32_t /* hysteresisMs */, int32_t /* hysteresisDlKbps */, int32_t /* hysteresisUlKbps */,
-        const hidl_vec<int32_t>& /* thresholdsDownlinkKbps */,
-        const hidl_vec<int32_t>& /* thresholdsUplinkKbps */,
-        ::android::hardware::radio::V1_2::AccessNetwork /* accessNetwork */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setupDataCall_1_2(int32_t /* serial */,
-        ::android::hardware::radio::V1_2::AccessNetwork /* accessNetwork */,
-        const ::android::hardware::radio::V1_0::DataProfileInfo& /* dataProfileInfo */,
-        bool /* modemCognitive */, bool /* roamingAllowed */, bool /* isRoaming */,
-        ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
-        const hidl_vec<hidl_string>& /* addresses */, const hidl_vec<hidl_string>& /* dnses */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::deactivateDataCall_1_2(int32_t /* serial */, int32_t /* cid */,
-        ::android::hardware::radio::V1_2::DataRequestReason /* reason */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::V1_3::IRadio follow.
-Return<void> RadioImpl_1_5::setSystemSelectionChannels(int32_t serial, bool /* specifyChannels */,
-        const hidl_vec<::android::hardware::radio::V1_1::RadioAccessSpecifier>& /* specifiers */) {
-#if VDBG
-    RLOGD("setSystemSelectionChannels: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::enableModem(int32_t serial, bool /* on */) {
-#if VDBG
-    RLOGE("enableModem: serial = %d, enable = %s", serial, on);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_ENABLE_MODEM);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getModemStackStatus(int32_t serial) {
-#if VDBG
-    RLOGD("getModemStackStatus: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_MODEM_STACK_STATUS);
-    return Void();
-}
-
-const char * getProtocolString(const ::android::hardware::radio::V1_4::PdpProtocolType protocolVal) {
-    switch(protocolVal) {
-        case ::android::hardware::radio::V1_4::PdpProtocolType::IP:
-            return "IP";
-        case ::android::hardware::radio::V1_4::PdpProtocolType::IPV6:
-            return "IPV6";
-        case ::android::hardware::radio::V1_4::PdpProtocolType::IPV4V6:
-            return "IPV4V6";
-        case ::android::hardware::radio::V1_4::PdpProtocolType::PPP:
-            return "PPP";
-        case ::android::hardware::radio::V1_4::PdpProtocolType::NON_IP:
-            return "NON_IP";
-        case ::android::hardware::radio::V1_4::PdpProtocolType::UNSTRUCTURED:
-            return "UNSTRUCTURED";
-        default:
-            return "UNKNOWN";
-    }
-}
-
-// Methods from ::android::hardware::radio::V1_4::IRadio follow.
-Return<void> RadioImpl_1_5::setAllowedCarriers_1_4(int32_t  serial,
-        const V1_4::CarrierRestrictionsWithPriority& carriers,
-        V1_4::SimLockMultiSimPolicy multiSimPolicy) {
-#if VDBG
-    RLOGD("setAllowedCarriers_1_4: serial %d", serial);
-#endif
-
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_CARRIER_RESTRICTIONS);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    // Prepare legacy structure (defined in IRadio 1.0) to re-use existing code.
-    RIL_CarrierRestrictions cr = {};
-    if (prepareCarrierRestrictions(cr, false, carriers.allowedCarriers, carriers.excludedCarriers,
-            pRI) < 0) {
-        return Void();
-    }
-    // Copy the legacy structure into the new structure (defined in IRadio 1.4)
-    RIL_CarrierRestrictionsWithPriority crExt = {};
-    crExt.len_allowed_carriers = cr.len_allowed_carriers;
-    crExt.allowed_carriers = cr.allowed_carriers;
-    crExt.len_excluded_carriers = cr.len_excluded_carriers;
-    crExt.excluded_carriers = cr.excluded_carriers;
-    crExt.allowedCarriersPrioritized = BOOL_TO_INT(carriers.allowedCarriersPrioritized);
-    crExt.multiSimPolicy = (RIL_SimLockMultiSimPolicy)multiSimPolicy;
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &crExt, sizeof(RIL_CarrierRestrictionsWithPriority),
-            pRI, mSlotId);
-
-    freeCarrierRestrictions(cr);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getAllowedCarriers_1_4(int32_t serial) {
-#if VDBG
-    RLOGD("getAllowedCarriers_1_4: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CARRIER_RESTRICTIONS);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setupDataCall_1_4(int32_t serial ,
-        ::android::hardware::radio::V1_4::AccessNetwork /* accessNetwork */,
-        const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo,
-        bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
-        const hidl_vec<hidl_string>& /* addresses */, const hidl_vec<hidl_string>& /* dnses */) {
-
-#if VDBG
-    RLOGD("setupDataCall_1_4: serial %d", serial);
-#endif
-
-    char *mvnoTypeStr = NULL;
-    if (!convertMvnoTypeToString(MvnoType::IMSI, mvnoTypeStr)) {
-        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-                RIL_REQUEST_SETUP_DATA_CALL);
-        if (pRI != NULL) {
-            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        }
-        return Void();
-    }
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 15,
-        std::to_string((int) RadioTechnology::UNKNOWN + 2).c_str(),
-        std::to_string((int) dataProfileInfo.profileId).c_str(),
-        dataProfileInfo.apn.c_str(),
-        dataProfileInfo.user.c_str(),
-        dataProfileInfo.password.c_str(),
-        std::to_string((int) dataProfileInfo.authType).c_str(),
-        getProtocolString(dataProfileInfo.protocol),
-        getProtocolString(dataProfileInfo.roamingProtocol),
-        std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
-        std::to_string(dataProfileInfo.bearerBitmap).c_str(),
-        dataProfileInfo.persistent ? "1" : "0",
-        std::to_string(dataProfileInfo.mtu).c_str(),
-        mvnoTypeStr,
-        "302720x94",
-        roamingAllowed ? "1" : "0");
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setInitialAttachApn_1_4(int32_t  serial ,
-        const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo) {
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_INITIAL_ATTACH_APN);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
-
-    if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponseV1_4->setInitialAttachApnResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponse->setInitialAttachApnResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setInitialAttachApnResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
-    }
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setDataProfile_1_4(int32_t  serial ,
-        const hidl_vec<::android::hardware::radio::V1_4::DataProfileInfo>& /* profiles */) {
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_DATA_PROFILE);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
-
-    if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponseV1_4->setDataProfileResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponse->setDataProfileResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setDataProfileResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
-    }
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::emergencyDial(int32_t serial,
-        const ::android::hardware::radio::V1_0::Dial& dialInfo,
-        hidl_bitfield<android::hardware::radio::V1_4::EmergencyServiceCategory> /* categories */,
-        const hidl_vec<hidl_string>& /* urns */,
-        ::android::hardware::radio::V1_4::EmergencyCallRouting /* routing */,
-        bool /* fromEmergencyDialer */, bool /* isTesting */) {
-#if VDBG
-    RLOGD("emergencyDial: serial %d", serial);
-#endif
-
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_EMERGENCY_DIAL);
-    if (pRI == NULL) {
-        return Void();
-    }
-    RIL_Dial dial = {};
-    RIL_UUS_Info uusInfo = {};
-    int32_t sizeOfDial = sizeof(dial);
-
-    if (!copyHidlStringToRil(&dial.address, dialInfo.address, pRI)) {
-        return Void();
-    }
-    dial.clir = (int) dialInfo.clir;
-
-    if (dialInfo.uusInfo.size() != 0) {
-        uusInfo.uusType = (RIL_UUS_Type) dialInfo.uusInfo[0].uusType;
-        uusInfo.uusDcs = (RIL_UUS_DCS) dialInfo.uusInfo[0].uusDcs;
-
-        if (dialInfo.uusInfo[0].uusData.size() == 0) {
-            uusInfo.uusData = NULL;
-            uusInfo.uusLength = 0;
-        } else {
-            if (!copyHidlStringToRil(&uusInfo.uusData, dialInfo.uusInfo[0].uusData, pRI)) {
-                memsetAndFreeStrings(1, dial.address);
-                return Void();
-            }
-            uusInfo.uusLength = dialInfo.uusInfo[0].uusData.size();
-        }
-
-        dial.uusInfo = &uusInfo;
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_EMERGENCY_DIAL, &dial, sizeOfDial, pRI, mSlotId);
-
-    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::startNetworkScan_1_4(int32_t serial,
-        const ::android::hardware::radio::V1_2::NetworkScanRequest& request) {
-#if VDBG
-    RLOGD("startNetworkScan_1_4: serial %d", serial);
-#endif
-
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_NetworkScanRequest scan_request = {};
-
-    if (prepareNetworkScanRequest_1_2(scan_request, request, pRI) < 0) {
-        return Void();
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
-            mSlotId);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getPreferredNetworkTypeBitmap(int32_t serial ) {
-#if VDBG
-    RLOGD("getPreferredNetworkTypeBitmap: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setPreferredNetworkTypeBitmap(
-        int32_t serial, hidl_bitfield<RadioAccessFamily> networkTypeBitmap) {
-#if VDBG
-    RLOGD("setPreferredNetworkTypeBitmap: serial %d", serial);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP, 1, networkTypeBitmap);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getSignalStrength_1_4(int32_t serial) {
-#if VDBG
-    RLOGD("getSignalStrength_1_4: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SIGNAL_STRENGTH);
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::V1_5::IRadio follow.
-Return<void> RadioImpl_1_5::setSignalStrengthReportingCriteria_1_5(int32_t /* serial */,
-        const ::android::hardware::radio::V1_5::SignalThresholdInfo& /* signalThresholdInfo */,
-        const ::android::hardware::radio::V1_5::AccessNetwork /* accessNetwork */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setLinkCapacityReportingCriteria_1_5(int32_t /* serial */,
-        int32_t /* hysteresisMs */, int32_t /* hysteresisDlKbps */, int32_t /* hysteresisUlKbps */,
-        const hidl_vec<int32_t>& /* thresholdsDownlinkKbps */,
-        const hidl_vec<int32_t>& /* thresholdsUplinkKbps */,
-        V1_5::AccessNetwork /* accessNetwork */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::enableUiccApplications(int32_t serial, bool enable) {
-#if VDBG
-    RLOGD("enableUiccApplications: serial %d enable %d", serial, enable);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_ENABLE_UICC_APPLICATIONS, 1, BOOL_TO_INT(enable));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
-                                          bool preferredForEmergencyCall) {
-#if VDBG
-    RLOGD("setRadioPower_1_5: serial %d powerOn %d forEmergency %d preferredForEmergencyCall %d",
-        serial, powerOn, forEmergencyCall, preferredForEmergencyCall);
-#endif
-    dispatchInts(serial, mSlotId, RIL_REQUEST_RADIO_POWER, 1, BOOL_TO_INT(powerOn));
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::areUiccApplicationsEnabled(int32_t serial) {
-#if VDBG
-    RLOGD("areUiccApplicationsEnabled: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getVoiceRegistrationState_1_5(int32_t serial) {
-#if VDBG
-    RLOGD("getVoiceRegistrationState: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_VOICE_REGISTRATION_STATE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getDataRegistrationState_1_5(int32_t serial) {
-#if VDBG
-    RLOGD("getDataRegistrationState: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_REGISTRATION_STATE);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setSystemSelectionChannels_1_5(int32_t serial,
-        bool /* specifyChannels */, const hidl_vec<V1_5::RadioAccessSpecifier>& /* specifiers */) {
-#if VDBG
-    RLOGD("setSystemSelectionChannels_1_5: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS);
-    return Void();
-}
-
-int prepareNetworkScanRequest_1_5(RIL_NetworkScanRequest &scan_request,
-        const V1_5::NetworkScanRequest& request, RequestInfo *pRI) {
-    scan_request.type = (RIL_ScanType) request.type;
-    scan_request.interval = request.interval;
-    scan_request.specifiers_length = request.specifiers.size();
-
-    int intervalLow = static_cast<int>(V1_2::ScanIntervalRange::MIN);
-    int intervalHigh = static_cast<int>(V1_2::ScanIntervalRange::MAX);
-    int maxSearchTimeLow = static_cast<int>(V1_2::MaxSearchTimeRange::MIN);
-    int maxSearchTimeHigh = static_cast<int>(V1_2::MaxSearchTimeRange::MAX);
-    int incrementalResultsPeriodicityRangeLow =
-            static_cast<int>(V1_2::IncrementalResultsPeriodicityRange::MIN);
-    int incrementalResultsPeriodicityRangeHigh =
-            static_cast<int>(V1_2::IncrementalResultsPeriodicityRange::MAX);
-    uint maxSpecifierSize = static_cast<uint>(V1_2::RadioConst::RADIO_ACCESS_SPECIFIER_MAX_SIZE);
-
-    if (request.interval < intervalLow || request.interval > intervalHigh) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-    // If defined, must fall in correct range.
-    if (request.maxSearchTime != 0 && (request.maxSearchTime < maxSearchTimeLow
-            || request.maxSearchTime > maxSearchTimeHigh)) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-    if (request.maxSearchTime != 0
-            && (request.incrementalResultsPeriodicity < incrementalResultsPeriodicityRangeLow
-            || request.incrementalResultsPeriodicity > incrementalResultsPeriodicityRangeHigh
-            || request.incrementalResultsPeriodicity > request.maxSearchTime)) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-    if (request.specifiers.size() == 0 || request.specifiers.size() > maxSpecifierSize) {
-        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        return -1;
-    }
-
-    for (size_t i = 0; i < request.specifiers.size(); ++i) {
-        if (request.specifiers[i].bands.geranBands().size() > MAX_BANDS
-                || request.specifiers[i].bands.utranBands().size() > MAX_BANDS
-                || request.specifiers[i].bands.eutranBands().size() > MAX_BANDS
-                || request.specifiers[i].bands.ngranBands().size() > MAX_BANDS
-                || request.specifiers[i].channels.size() > MAX_CHANNELS) {
-            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-            return -1;
-        }
-        const V1_5::RadioAccessSpecifier& ras_from = request.specifiers[i];
-        RIL_RadioAccessSpecifier& ras_to = scan_request.specifiers[i];
-
-        ras_to.radio_access_network = (RIL_RadioAccessNetworks) ras_from.radioAccessNetwork;
-        ras_to.channels_length = ras_from.channels.size();
-
-        std::copy(ras_from.channels.begin(), ras_from.channels.end(), ras_to.channels);
-        const std::vector<uint32_t> * bands = nullptr;
-        switch (request.specifiers[i].radioAccessNetwork) {
-            case V1_5::RadioAccessNetworks::GERAN:
-                ras_to.bands_length = ras_from.bands.geranBands().size();
-                bands = (std::vector<uint32_t> *) &ras_from.bands;
-                break;
-            case V1_5::RadioAccessNetworks::UTRAN:
-                ras_to.bands_length = ras_from.bands.utranBands().size();
-                bands = (std::vector<uint32_t> *) &ras_from.bands;
-                break;
-            case V1_5::RadioAccessNetworks::EUTRAN:
-                ras_to.bands_length = ras_from.bands.eutranBands().size();
-                bands = (std::vector<uint32_t> *) &ras_from.bands;
-                break;
-            case V1_5::RadioAccessNetworks::NGRAN:
-                ras_to.bands_length = ras_from.bands.ngranBands().size();
-                bands = (std::vector<uint32_t> *) &ras_from.bands;
-                break;
-            default:
-                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-                return -1;
-        }
-        // safe to copy to geran_bands because it's a union member
-        for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
-            ras_to.bands.geran_bands[idx] = (RIL_GeranBands) (*bands)[idx];
-        }
-    }
-
-    return 0;
-}
-
-Return<void> RadioImpl_1_5::startNetworkScan_1_5(int32_t serial,
-        const ::android::hardware::radio::V1_5::NetworkScanRequest& request) {
-#if VDBG
-    RLOGD("startNetworkScan_1_5: serial %d", serial);
-#endif
-
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_NetworkScanRequest scan_request = {};
-
-    if (prepareNetworkScanRequest_1_5(scan_request, request, pRI) < 0) {
-        return Void();
-    }
-
-    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
-            mSlotId);
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setupDataCall_1_5(int32_t serial ,
-        ::android::hardware::radio::V1_5::AccessNetwork /* accessNetwork */,
-        const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
-        bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
-        const hidl_vec<::android::hardware::radio::V1_5::LinkAddress>& /* addresses */,
-        const hidl_vec<hidl_string>& /* dnses */) {
-
-#if VDBG
-    RLOGD("setupDataCall_1_5: serial %d", serial);
-#endif
-
-    char *mvnoTypeStr = NULL;
-    if (!convertMvnoTypeToString(MvnoType::IMSI, mvnoTypeStr)) {
-        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-                RIL_REQUEST_SETUP_DATA_CALL);
-        if (pRI != NULL) {
-            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
-        }
-        return Void();
-    }
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 15,
-        std::to_string((int) RadioTechnology::UNKNOWN + 2).c_str(),
-        std::to_string((int) dataProfileInfo.profileId).c_str(),
-        dataProfileInfo.apn.c_str(),
-        dataProfileInfo.user.c_str(),
-        dataProfileInfo.password.c_str(),
-        std::to_string((int) dataProfileInfo.authType).c_str(),
-        getProtocolString(dataProfileInfo.protocol),
-        getProtocolString(dataProfileInfo.roamingProtocol),
-        std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
-        std::to_string(dataProfileInfo.bearerBitmap).c_str(),
-        dataProfileInfo.persistent ? "1" : "0",
-        std::to_string(dataProfileInfo.mtuV4).c_str(),
-        std::to_string(dataProfileInfo.mtuV6).c_str(),
-        mvnoTypeStr,
-        "302720x94",
-        roamingAllowed ? "1" : "0");
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setInitialAttachApn_1_5(int32_t  serial ,
-        const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo) {
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_INITIAL_ATTACH_APN);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
-
-    if (radioService[mSlotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponseV1_5->setInitialAttachApnResponse(responseInfo);
-    } else if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponseV1_4->setInitialAttachApnResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponse->setInitialAttachApnResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setInitialAttachApnResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
-    }
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setDataProfile_1_5(int32_t  serial ,
-        const hidl_vec<::android::hardware::radio::V1_5::DataProfileInfo>& /* profiles */) {
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_SET_DATA_PROFILE);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
-
-    if (radioService[mSlotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponseV1_5->setDataProfileResponse(responseInfo);
-    } else if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponseV1_4->setDataProfileResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
-        Return<void> retStatus
-                = radioService[mSlotId]->mRadioResponse->setDataProfileResponse(responseInfo);
-        radioService[mSlotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setDataProfileResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
-    }
-
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setIndicationFilter_1_5(int32_t /* serial */,
-        hidl_bitfield<::android::hardware::radio::V1_5::IndicationFilter> /* indicationFilter */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::getBarringInfo(int32_t /* serial */) {
-    // TODO implement
-#if VDBG
-    RLOGE("[%04d]< %s", serial, "Method is not implemented");
-#endif
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::setNetworkSelectionModeManual_1_5(int32_t serial,
-        const hidl_string& operatorNumeric, V1_5::RadioAccessNetworks ran) {
-#if VDBG
-    RLOGD("setNetworkSelectionModeManual_1_5: serial %d", serial);
-#endif
-    dispatchVoid(serial, mSlotId, RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::sendCdmaSmsExpectMore(int32_t serial, const CdmaSmsMessage& sms) {
-#if VDBG
-    RLOGD("sendCdmaSmsExpectMore: serial %d", serial);
-#endif
-    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
-            RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE);
-    if (pRI == NULL) {
-        return Void();
-    }
-
-    RIL_CDMA_SMS_Message rcsm = {};
-    constructCdmaSms(rcsm, sms);
-
-    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsm, sizeof(rcsm), pRI, mSlotId);
-    return Void();
-}
-
-Return<void> RadioImpl_1_5::supplySimDepersonalization(int32_t serial,
-        V1_5::PersoSubstate persoType, const hidl_string& controlKey) {
-#if VDBG
-    RLOGD("supplySimDepersonalization: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION, true, 1,
-            controlKey.c_str());
-    return Void();
-}
-
-// OEM hook methods:
-Return<void> OemHookImpl::setResponseFunctions(
-        const ::android::sp<IOemHookResponse>& oemHookResponseParam,
-        const ::android::sp<IOemHookIndication>& oemHookIndicationParam) {
-#if VDBG
-    RLOGD("OemHookImpl::setResponseFunctions");
-#endif
-
-    pthread_rwlock_t *radioServiceRwlockPtr = radio_1_5::getRadioServiceRwlock(mSlotId);
-    int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
-    assert(ret == 0);
-
-    mOemHookResponse = oemHookResponseParam;
-    mOemHookIndication = oemHookIndicationParam;
-    mCounterOemHook[mSlotId]++;
-
-    ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
-    assert(ret == 0);
-
-    return Void();
-}
-
-Return<void> OemHookImpl::sendRequestRaw(int32_t serial, const hidl_vec<uint8_t>& data) {
-#if VDBG
-    RLOGD("OemHookImpl::sendRequestRaw: serial %d", serial);
-#endif
-    dispatchRaw(serial, mSlotId, RIL_REQUEST_OEM_HOOK_RAW, data);
-    return Void();
-}
-
-Return<void> OemHookImpl::sendRequestStrings(int32_t serial,
-        const hidl_vec<hidl_string>& data) {
-#if VDBG
-    RLOGD("OemHookImpl::sendRequestStrings: serial %d", serial);
-#endif
-    dispatchStrings(serial, mSlotId, RIL_REQUEST_OEM_HOOK_STRINGS, data);
-    return Void();
-}
-
-/***************************************************************************************************
- * RESPONSE FUNCTIONS
- * Functions above are used for requests going from framework to vendor code. The ones below are
- * responses for those requests coming back from the vendor code.
- **************************************************************************************************/
-
-void radio_1_5::acknowledgeRequest(int slotId, int serial) {
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->acknowledgeRequest(serial);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("acknowledgeRequest: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-}
-
-void populateResponseInfo(RadioResponseInfo& responseInfo, int serial, int responseType,
-                         RIL_Errno e) {
-    responseInfo.serial = serial;
-    switch (responseType) {
-        case RESPONSE_SOLICITED:
-            responseInfo.type = RadioResponseType::SOLICITED;
-            break;
-        case RESPONSE_SOLICITED_ACK_EXP:
-            responseInfo.type = RadioResponseType::SOLICITED_ACK_EXP;
-            break;
-    }
-    responseInfo.error = (RadioError) e;
-}
-
-int responseIntOrEmpty(RadioResponseInfo& responseInfo, int serial, int responseType, RIL_Errno e,
-               void *response, size_t responseLen) {
-    populateResponseInfo(responseInfo, serial, responseType, e);
-    int ret = -1;
-
-    if (response == NULL && responseLen == 0) {
-        // Earlier RILs did not send a response for some cases although the interface
-        // expected an integer as response. Do not return error if response is empty. Instead
-        // Return -1 in those cases to maintain backward compatibility.
-    } else if (response == NULL || responseLen != sizeof(int)) {
-        RLOGE("responseIntOrEmpty: Invalid response");
-        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-    } else {
-        int *p_int = (int *) response;
-        ret = p_int[0];
-    }
-    return ret;
-}
-
-int responseInt(RadioResponseInfo& responseInfo, int serial, int responseType, RIL_Errno e,
-               void *response, size_t responseLen) {
-    populateResponseInfo(responseInfo, serial, responseType, e);
-    int ret = -1;
-
-    if (response == NULL || responseLen != sizeof(int)) {
-        RLOGE("responseInt: Invalid response");
-        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-    } else {
-        int *p_int = (int *) response;
-        ret = p_int[0];
-    }
-    return ret;
-}
-
-int radio_1_5::getIccCardStatusResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responseLen) {
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL
-        || radioService[slotId]->mRadioResponseV1_2 != NULL
-        || radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        CardStatus cardStatus = {CardState::ABSENT, PinState::UNKNOWN, -1, -1, -1, {}};
-        RIL_CardStatus_v6 *p_cur = ((RIL_CardStatus_v6 *) response);
-        if (response == NULL || responseLen != sizeof(RIL_CardStatus_v6)
-                || p_cur->gsm_umts_subscription_app_index >= p_cur->num_applications
-                || p_cur->cdma_subscription_app_index >= p_cur->num_applications
-                || p_cur->ims_subscription_app_index >= p_cur->num_applications) {
-            RLOGE("getIccCardStatusResponse: Invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            cardStatus.cardState = (CardState) p_cur->card_state;
-            cardStatus.universalPinState = (PinState) p_cur->universal_pin_state;
-            cardStatus.gsmUmtsSubscriptionAppIndex = p_cur->gsm_umts_subscription_app_index;
-            cardStatus.cdmaSubscriptionAppIndex = p_cur->cdma_subscription_app_index;
-            cardStatus.imsSubscriptionAppIndex = p_cur->ims_subscription_app_index;
-
-            RIL_AppStatus *rilAppStatus = p_cur->applications;
-            cardStatus.applications.resize(p_cur->num_applications);
-            AppStatus *appStatus = cardStatus.applications.data();
-#if VDBG
-            RLOGD("getIccCardStatusResponse: num_applications %d", p_cur->num_applications);
-#endif
-            for (int i = 0; i < p_cur->num_applications; i++) {
-                appStatus[i].appType = (AppType) rilAppStatus[i].app_type;
-                appStatus[i].appState = (AppState) rilAppStatus[i].app_state;
-                appStatus[i].persoSubstate = (PersoSubstate) rilAppStatus[i].perso_substate;
-                appStatus[i].aidPtr = convertCharPtrToHidlString(rilAppStatus[i].aid_ptr);
-                appStatus[i].appLabelPtr = convertCharPtrToHidlString(
-                        rilAppStatus[i].app_label_ptr);
-                appStatus[i].pin1Replaced = rilAppStatus[i].pin1_replaced;
-                appStatus[i].pin1 = (PinState) rilAppStatus[i].pin1;
-                appStatus[i].pin2 = (PinState) rilAppStatus[i].pin2;
-            }
-        }
-
-        if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-            ::android::hardware::radio::V1_2::CardStatus cardStatusV1_2;
-            ::android::hardware::radio::V1_4::CardStatus cardStatusV1_4;
-            cardStatusV1_2.base = cardStatus;
-            cardStatusV1_2.physicalSlotId = -1;
-            cardStatusV1_4.base = cardStatusV1_2;
-            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->
-                    getIccCardStatusResponse_1_4(responseInfo, cardStatusV1_4);
-            radioService[slotId]->checkReturnStatus(retStatus);
-        } else if (radioService[slotId]->mRadioResponseV1_3 != NULL) {
-            ::android::hardware::radio::V1_2::CardStatus cardStatusV1_2;
-            cardStatusV1_2.base = cardStatus;
-            cardStatusV1_2.physicalSlotId = -1;
-            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_3->
-                    getIccCardStatusResponse_1_2(responseInfo, cardStatusV1_2);
-            radioService[slotId]->checkReturnStatus(retStatus);
-        } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
-            ::android::hardware::radio::V1_2::CardStatus cardStatusV1_2;
-            cardStatusV1_2.base = cardStatus;
-            cardStatusV1_2.physicalSlotId = -1;
-            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2->
-                    getIccCardStatusResponse_1_2(responseInfo, cardStatusV1_2);
-            radioService[slotId]->checkReturnStatus(retStatus);
-            // TODO: add 1.1 if needed.
-        } else {
-            Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                    getIccCardStatusResponse(responseInfo, cardStatus);
-            radioService[slotId]->checkReturnStatus(retStatus);
-        }
-    } else {
-        RLOGE("getIccCardStatusResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::supplyIccPinForAppResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("supplyIccPinForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                supplyIccPinForAppResponse(responseInfo, ret);
-        RLOGE("supplyIccPinForAppResponse: amit ret %d", ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("supplyIccPinForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::supplyIccPukForAppResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("supplyIccPukForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->supplyIccPukForAppResponse(
-                responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("supplyIccPukForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::supplyIccPin2ForAppResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("supplyIccPin2ForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                supplyIccPin2ForAppResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("supplyIccPin2ForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::supplyIccPuk2ForAppResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("supplyIccPuk2ForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                supplyIccPuk2ForAppResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("supplyIccPuk2ForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::changeIccPinForAppResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("changeIccPinForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                changeIccPinForAppResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("changeIccPinForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::changeIccPin2ForAppResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("changeIccPin2ForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                changeIccPin2ForAppResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("changeIccPin2ForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::supplyNetworkDepersonalizationResponse(int slotId,
-                                                 int responseType, int serial, RIL_Errno e,
-                                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("supplyNetworkDepersonalizationResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                supplyNetworkDepersonalizationResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("supplyNetworkDepersonalizationResponse: radioService[%d]->mRadioResponse == "
-                "NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCurrentCallsResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getCurrentCallsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        hidl_vec<Call> calls;
-        if ((response == NULL && responseLen != 0)
-                || (responseLen % sizeof(RIL_Call *)) != 0) {
-            RLOGE("getCurrentCallsResponse: Invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int num = responseLen / sizeof(RIL_Call *);
-            calls.resize(num);
-
-            for (int i = 0 ; i < num ; i++) {
-                RIL_Call *p_cur = ((RIL_Call **) response)[i];
-                /* each call info */
-                calls[i].state = (CallState) p_cur->state;
-                calls[i].index = p_cur->index;
-                calls[i].toa = p_cur->toa;
-                calls[i].isMpty = p_cur->isMpty;
-                calls[i].isMT = p_cur->isMT;
-                calls[i].als = p_cur->als;
-                calls[i].isVoice = p_cur->isVoice;
-                calls[i].isVoicePrivacy = p_cur->isVoicePrivacy;
-                calls[i].number = convertCharPtrToHidlString(p_cur->number);
-                calls[i].numberPresentation = (CallPresentation) p_cur->numberPresentation;
-                calls[i].name = convertCharPtrToHidlString(p_cur->name);
-                calls[i].namePresentation = (CallPresentation) p_cur->namePresentation;
-                if (p_cur->uusInfo != NULL && p_cur->uusInfo->uusData != NULL) {
-                    RIL_UUS_Info *uusInfo = p_cur->uusInfo;
-                    calls[i].uusInfo.resize(1);
-                    calls[i].uusInfo[0].uusType = (UusType) uusInfo->uusType;
-                    calls[i].uusInfo[0].uusDcs = (UusDcs) uusInfo->uusDcs;
-                    // convert uusInfo->uusData to a null-terminated string
-                    char *nullTermStr = strndup(uusInfo->uusData, uusInfo->uusLength);
-                    calls[i].uusInfo[0].uusData = nullTermStr;
-                    free(nullTermStr);
-                }
-            }
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                getCurrentCallsResponse(responseInfo, calls);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getCurrentCallsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::dialResponse(int slotId,
-                       int responseType, int serial, RIL_Errno e, void *response,
-                       size_t responseLen) {
-#if VDBG
-    RLOGD("dialResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->dialResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("dialResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getIMSIForAppResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e, void *response,
-                                size_t responseLen) {
-#if VDBG
-    RLOGD("getIMSIForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getIMSIForAppResponse(
-                responseInfo, convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getIMSIForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::hangupConnectionResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("hangupConnectionResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->hangupConnectionResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("hangupConnectionResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::hangupWaitingOrBackgroundResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("hangupWaitingOrBackgroundResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus =
-                radioService[slotId]->mRadioResponse->hangupWaitingOrBackgroundResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("hangupWaitingOrBackgroundResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::hangupForegroundResumeBackgroundResponse(int slotId, int responseType, int serial,
-                                                    RIL_Errno e, void *response,
-                                                    size_t responseLen) {
-#if VDBG
-    RLOGD("hangupWaitingOrBackgroundResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus =
-                radioService[slotId]->mRadioResponse->hangupWaitingOrBackgroundResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("hangupWaitingOrBackgroundResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::switchWaitingOrHoldingAndActiveResponse(int slotId, int responseType, int serial,
-                                                   RIL_Errno e, void *response,
-                                                   size_t responseLen) {
-#if VDBG
-    RLOGD("switchWaitingOrHoldingAndActiveResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus =
-                radioService[slotId]->mRadioResponse->switchWaitingOrHoldingAndActiveResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("switchWaitingOrHoldingAndActiveResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::conferenceResponse(int slotId, int responseType,
-                             int serial, RIL_Errno e, void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("conferenceResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->conferenceResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("conferenceResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::rejectCallResponse(int slotId, int responseType,
-                             int serial, RIL_Errno e, void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("rejectCallResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->rejectCallResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("rejectCallResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getLastCallFailCauseResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e, void *response,
-                                       size_t responseLen) {
-#if VDBG
-    RLOGD("getLastCallFailCauseResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        LastCallFailCauseInfo info = {};
-        info.vendorCause = hidl_string();
-        if (response == NULL) {
-            RLOGE("getCurrentCallsResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else if (responseLen == sizeof(int)) {
-            int *pInt = (int *) response;
-            info.causeCode = (LastCallFailCause) pInt[0];
-        } else if (responseLen == sizeof(RIL_LastCallFailCauseInfo))  {
-            RIL_LastCallFailCauseInfo *pFailCauseInfo = (RIL_LastCallFailCauseInfo *) response;
-            info.causeCode = (LastCallFailCause) pFailCauseInfo->cause_code;
-            info.vendorCause = convertCharPtrToHidlString(pFailCauseInfo->vendor_cause);
-        } else {
-            RLOGE("getCurrentCallsResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getLastCallFailCauseResponse(
-                responseInfo, info);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getLastCallFailCauseResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getSignalStrengthResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getSignalStrengthResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        SignalStrength signalStrength = {};
-        if (response == NULL || responseLen != sizeof(RIL_SignalStrength_v10)) {
-            RLOGE("getSignalStrengthResponse: Invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            convertRilSignalStrengthToHal(response, responseLen, signalStrength);
-        }
-
-        ::android::hardware::radio::V1_4::SignalStrength signalStrength_1_4;
-        signalStrength_1_4.gsm = signalStrength.gw;
-        signalStrength_1_4.cdma = signalStrength.cdma;
-        signalStrength_1_4.evdo = signalStrength.evdo;
-        signalStrength_1_4.lte = signalStrength.lte;
-        //TODO: future implementation needs to fill tdScdma, wcdma and nr signal strength.
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->
-                getSignalStrengthResponse_1_4(responseInfo, signalStrength_1_4);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        SignalStrength signalStrength = {};
-        if (response == NULL || responseLen != sizeof(RIL_SignalStrength_v10)) {
-            RLOGE("getSignalStrengthResponse: Invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            convertRilSignalStrengthToHal(response, responseLen, signalStrength);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getSignalStrengthResponse(
-                responseInfo, signalStrength);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getSignalStrengthResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-RIL_CellInfoType getCellInfoTypeRadioTechnology(char *rat) {
-    if (rat == NULL) {
-        return RIL_CELL_INFO_TYPE_NONE;
-    }
-
-    int radioTech = atoi(rat);
-
-    switch(radioTech) {
-
-        case RADIO_TECH_GPRS:
-        case RADIO_TECH_EDGE:
-        case RADIO_TECH_GSM: {
-            return RIL_CELL_INFO_TYPE_GSM;
-        }
-
-        case RADIO_TECH_UMTS:
-        case RADIO_TECH_HSDPA:
-        case RADIO_TECH_HSUPA:
-        case RADIO_TECH_HSPA:
-        case RADIO_TECH_HSPAP: {
-            return RIL_CELL_INFO_TYPE_WCDMA;
-        }
-
-        case RADIO_TECH_IS95A:
-        case RADIO_TECH_IS95B:
-        case RADIO_TECH_1xRTT:
-        case RADIO_TECH_EVDO_0:
-        case RADIO_TECH_EVDO_A:
-        case RADIO_TECH_EVDO_B:
-        case RADIO_TECH_EHRPD: {
-            return RIL_CELL_INFO_TYPE_CDMA;
-        }
-
-        case RADIO_TECH_LTE:
-        case RADIO_TECH_LTE_CA: {
-            return RIL_CELL_INFO_TYPE_LTE;
-        }
-
-        case RADIO_TECH_TD_SCDMA: {
-            return RIL_CELL_INFO_TYPE_TD_SCDMA;
-        }
-
-        default: {
-            break;
-        }
-    }
-
-    return RIL_CELL_INFO_TYPE_NONE;
-
-}
-
-void fillCellIdentityResponse(CellIdentity &cellIdentity, RIL_CellIdentity_v16 &rilCellIdentity) {
-
-    cellIdentity.cellIdentityGsm.resize(0);
-    cellIdentity.cellIdentityWcdma.resize(0);
-    cellIdentity.cellIdentityCdma.resize(0);
-    cellIdentity.cellIdentityTdscdma.resize(0);
-    cellIdentity.cellIdentityLte.resize(0);
-    cellIdentity.cellInfoType = (CellInfoType)rilCellIdentity.cellInfoType;
-    switch(rilCellIdentity.cellInfoType) {
-
-        case RIL_CELL_INFO_TYPE_GSM: {
-            cellIdentity.cellIdentityGsm.resize(1);
-            cellIdentity.cellIdentityGsm[0].mcc =
-                    std::to_string(rilCellIdentity.cellIdentityGsm.mcc);
-            cellIdentity.cellIdentityGsm[0].mnc =
-                    ril::util::mnc::decode(rilCellIdentity.cellIdentityGsm.mnc);
-            cellIdentity.cellIdentityGsm[0].lac = rilCellIdentity.cellIdentityGsm.lac;
-            cellIdentity.cellIdentityGsm[0].cid = rilCellIdentity.cellIdentityGsm.cid;
-            cellIdentity.cellIdentityGsm[0].arfcn = rilCellIdentity.cellIdentityGsm.arfcn;
-            cellIdentity.cellIdentityGsm[0].bsic = rilCellIdentity.cellIdentityGsm.bsic;
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_WCDMA: {
-            cellIdentity.cellIdentityWcdma.resize(1);
-            cellIdentity.cellIdentityWcdma[0].mcc =
-                    std::to_string(rilCellIdentity.cellIdentityWcdma.mcc);
-            cellIdentity.cellIdentityWcdma[0].mnc =
-                    ril::util::mnc::decode(rilCellIdentity.cellIdentityWcdma.mnc);
-            cellIdentity.cellIdentityWcdma[0].lac = rilCellIdentity.cellIdentityWcdma.lac;
-            cellIdentity.cellIdentityWcdma[0].cid = rilCellIdentity.cellIdentityWcdma.cid;
-            cellIdentity.cellIdentityWcdma[0].psc = rilCellIdentity.cellIdentityWcdma.psc;
-            cellIdentity.cellIdentityWcdma[0].uarfcn = rilCellIdentity.cellIdentityWcdma.uarfcn;
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_CDMA: {
-            cellIdentity.cellIdentityCdma.resize(1);
-            cellIdentity.cellIdentityCdma[0].networkId = rilCellIdentity.cellIdentityCdma.networkId;
-            cellIdentity.cellIdentityCdma[0].systemId = rilCellIdentity.cellIdentityCdma.systemId;
-            cellIdentity.cellIdentityCdma[0].baseStationId =
-                    rilCellIdentity.cellIdentityCdma.basestationId;
-            cellIdentity.cellIdentityCdma[0].longitude = rilCellIdentity.cellIdentityCdma.longitude;
-            cellIdentity.cellIdentityCdma[0].latitude = rilCellIdentity.cellIdentityCdma.latitude;
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_LTE: {
-            cellIdentity.cellIdentityLte.resize(1);
-            cellIdentity.cellIdentityLte[0].mcc =
-                    std::to_string(rilCellIdentity.cellIdentityLte.mcc);
-            cellIdentity.cellIdentityLte[0].mnc =
-                    ril::util::mnc::decode(rilCellIdentity.cellIdentityLte.mnc);
-            cellIdentity.cellIdentityLte[0].ci = rilCellIdentity.cellIdentityLte.ci;
-            cellIdentity.cellIdentityLte[0].pci = rilCellIdentity.cellIdentityLte.pci;
-            cellIdentity.cellIdentityLte[0].tac = rilCellIdentity.cellIdentityLte.tac;
-            cellIdentity.cellIdentityLte[0].earfcn = rilCellIdentity.cellIdentityLte.earfcn;
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_TD_SCDMA: {
-            cellIdentity.cellIdentityTdscdma.resize(1);
-            cellIdentity.cellIdentityTdscdma[0].mcc =
-                    std::to_string(rilCellIdentity.cellIdentityTdscdma.mcc);
-            cellIdentity.cellIdentityTdscdma[0].mnc =
-                    ril::util::mnc::decode(rilCellIdentity.cellIdentityTdscdma.mnc);
-            cellIdentity.cellIdentityTdscdma[0].lac = rilCellIdentity.cellIdentityTdscdma.lac;
-            cellIdentity.cellIdentityTdscdma[0].cid = rilCellIdentity.cellIdentityTdscdma.cid;
-            cellIdentity.cellIdentityTdscdma[0].cpid = rilCellIdentity.cellIdentityTdscdma.cpid;
-            break;
-        }
-
-        default: {
-            break;
-        }
-    }
-}
-
-int convertResponseStringEntryToInt(char **response, int index, int numStrings) {
-    if ((response != NULL) &&  (numStrings > index) && (response[index] != NULL)) {
-        return atoi(response[index]);
-    }
-
-    return -1;
-}
-
-int convertResponseHexStringEntryToInt(char **response, int index, int numStrings) {
-    const int hexBase = 16;
-    if ((response != NULL) &&  (numStrings > index) && (response[index] != NULL)) {
-        return strtol(response[index], NULL, hexBase);
-    }
-
-    return -1;
-}
-
-/* Fill Cell Identity info from Voice Registration State Response.
- * This fucntion is applicable only for RIL Version < 15.
- * Response is a  "char **".
- * First and Second entries are in hex string format
- * and rest are integers represented in ascii format. */
-void fillCellIdentityFromVoiceRegStateResponseString(CellIdentity &cellIdentity,
-        int numStrings, char** response) {
-
-    RIL_CellIdentity_v16 rilCellIdentity;
-    memset(&rilCellIdentity, -1, sizeof(RIL_CellIdentity_v16));
-
-    rilCellIdentity.cellInfoType = getCellInfoTypeRadioTechnology(response[3]);
-    switch(rilCellIdentity.cellInfoType) {
-
-        case RIL_CELL_INFO_TYPE_GSM: {
-            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
-            rilCellIdentity.cellIdentityGsm.lac =
-                    convertResponseHexStringEntryToInt(response, 1, numStrings);
-
-            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
-            rilCellIdentity.cellIdentityGsm.cid =
-                    convertResponseHexStringEntryToInt(response, 2, numStrings);
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_WCDMA: {
-            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
-            rilCellIdentity.cellIdentityWcdma.lac =
-                    convertResponseHexStringEntryToInt(response, 1, numStrings);
-
-            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
-            rilCellIdentity.cellIdentityWcdma.cid =
-                    convertResponseHexStringEntryToInt(response, 2, numStrings);
-            rilCellIdentity.cellIdentityWcdma.psc =
-                    convertResponseStringEntryToInt(response, 14, numStrings);
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_TD_SCDMA:{
-            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
-            rilCellIdentity.cellIdentityTdscdma.lac =
-                    convertResponseHexStringEntryToInt(response, 1, numStrings);
-
-            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
-            rilCellIdentity.cellIdentityTdscdma.cid =
-                    convertResponseHexStringEntryToInt(response, 2, numStrings);
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_CDMA:{
-            rilCellIdentity.cellIdentityCdma.basestationId =
-                    convertResponseStringEntryToInt(response, 4, numStrings);
-            /* Order of Lat. and Long. swapped between RIL and HIDL interface versions. */
-            rilCellIdentity.cellIdentityCdma.latitude =
-                    convertResponseStringEntryToInt(response, 5, numStrings);
-            rilCellIdentity.cellIdentityCdma.longitude =
-                    convertResponseStringEntryToInt(response, 6, numStrings);
-            rilCellIdentity.cellIdentityCdma.systemId =
-                    convertResponseStringEntryToInt(response, 8, numStrings);
-            rilCellIdentity.cellIdentityCdma.networkId =
-                    convertResponseStringEntryToInt(response, 9, numStrings);
-            break;
-        }
-
-        case RIL_CELL_INFO_TYPE_LTE:{
-            /* valid TAC are hexstrings in the range 0x0000 - 0xffff */
-            rilCellIdentity.cellIdentityLte.tac =
-                    convertResponseHexStringEntryToInt(response, 1, numStrings);
-
-            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
-            rilCellIdentity.cellIdentityLte.ci =
-                    convertResponseHexStringEntryToInt(response, 2, numStrings);
-            break;
-        }
-
-        default: {
-            break;
-        }
-    }
-
-    fillCellIdentityResponse(cellIdentity, rilCellIdentity);
-}
-
-/* Fill Cell Identity info from Data Registration State Response.
- * This fucntion is applicable only for RIL Version < 15.
- * Response is a  "char **".
- * First and Second entries are in hex string format
- * and rest are integers represented in ascii format. */
-void fillCellIdentityFromDataRegStateResponseString(CellIdentity &cellIdentity,
-        int numStrings, char** response) {
-
-    RIL_CellIdentity_v16 rilCellIdentity;
-    memset(&rilCellIdentity, -1, sizeof(RIL_CellIdentity_v16));
-
-    rilCellIdentity.cellInfoType = getCellInfoTypeRadioTechnology(response[3]);
-    switch(rilCellIdentity.cellInfoType) {
-        case RIL_CELL_INFO_TYPE_GSM: {
-            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
-            rilCellIdentity.cellIdentityGsm.lac =
-                    convertResponseHexStringEntryToInt(response, 1, numStrings);
-
-            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
-            rilCellIdentity.cellIdentityGsm.cid =
-                    convertResponseHexStringEntryToInt(response, 2, numStrings);
-            break;
-        }
-        case RIL_CELL_INFO_TYPE_WCDMA: {
-            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
-            rilCellIdentity.cellIdentityWcdma.lac =
-                    convertResponseHexStringEntryToInt(response, 1, numStrings);
-
-            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
-            rilCellIdentity.cellIdentityWcdma.cid =
-                    convertResponseHexStringEntryToInt(response, 2, numStrings);
-            break;
-        }
-        case RIL_CELL_INFO_TYPE_TD_SCDMA:{
-            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
-            rilCellIdentity.cellIdentityTdscdma.lac =
-                    convertResponseHexStringEntryToInt(response, 1, numStrings);
-
-            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
-            rilCellIdentity.cellIdentityTdscdma.cid =
-                    convertResponseHexStringEntryToInt(response, 2, numStrings);
-            break;
-        }
-        case RIL_CELL_INFO_TYPE_LTE: {
-            rilCellIdentity.cellIdentityLte.tac =
-                    convertResponseStringEntryToInt(response, 6, numStrings);
-            rilCellIdentity.cellIdentityLte.pci =
-                    convertResponseStringEntryToInt(response, 7, numStrings);
-            rilCellIdentity.cellIdentityLte.ci =
-                    convertResponseStringEntryToInt(response, 8, numStrings);
-            break;
-        }
-        default: {
-            break;
-        }
-    }
-
-    fillCellIdentityResponse(cellIdentity, rilCellIdentity);
-}
-
-int radio_1_5::getVoiceRegistrationStateResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getVoiceRegistrationStateResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        VoiceRegStateResult voiceRegResponse = {};
-        int numStrings = responseLen / sizeof(char *);
-        if (response == NULL) {
-               RLOGE("getVoiceRegistrationStateResponse Invalid response: NULL");
-               if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else if (s_vendorFunctions->version <= 14) {
-            if (numStrings != 15) {
-                RLOGE("getVoiceRegistrationStateResponse Invalid response: NULL");
-                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            } else {
-                char **resp = (char **) response;
-                voiceRegResponse.regState = (RegState) ATOI_NULL_HANDLED_DEF(resp[0], 4);
-                voiceRegResponse.rat = ATOI_NULL_HANDLED(resp[3]);
-                voiceRegResponse.cssSupported = ATOI_NULL_HANDLED_DEF(resp[7], 0);
-                voiceRegResponse.roamingIndicator = ATOI_NULL_HANDLED(resp[10]);
-                voiceRegResponse.systemIsInPrl = ATOI_NULL_HANDLED_DEF(resp[11], 0);
-                voiceRegResponse.defaultRoamingIndicator = ATOI_NULL_HANDLED_DEF(resp[12], 0);
-                voiceRegResponse.reasonForDenial = ATOI_NULL_HANDLED_DEF(resp[13], 0);
-                fillCellIdentityFromVoiceRegStateResponseString(voiceRegResponse.cellIdentity,
-                        numStrings, resp);
-            }
-        } else {
-            RIL_VoiceRegistrationStateResponse *voiceRegState =
-                    (RIL_VoiceRegistrationStateResponse *)response;
-
-            if (responseLen != sizeof(RIL_VoiceRegistrationStateResponse)) {
-                RLOGE("getVoiceRegistrationStateResponse Invalid response: NULL");
-                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            } else {
-                voiceRegResponse.regState = (RegState) voiceRegState->regState;
-                voiceRegResponse.rat = voiceRegState->rat;;
-                voiceRegResponse.cssSupported = voiceRegState->cssSupported;
-                voiceRegResponse.roamingIndicator = voiceRegState->roamingIndicator;
-                voiceRegResponse.systemIsInPrl = voiceRegState->systemIsInPrl;
-                voiceRegResponse.defaultRoamingIndicator = voiceRegState->defaultRoamingIndicator;
-                voiceRegResponse.reasonForDenial = voiceRegState->reasonForDenial;
-                fillCellIdentityResponse(voiceRegResponse.cellIdentity,
-                        voiceRegState->cellIdentity);
-            }
-        }
-
-        Return<void> retStatus =
-                radioService[slotId]->mRadioResponse->getVoiceRegistrationStateResponse(
-                responseInfo, voiceRegResponse);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getVoiceRegistrationStateResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getDataRegistrationStateResponse(int slotId,
-                                           int responseType, int serial, RIL_Errno e,
-                                           void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getDataRegistrationStateResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        DataRegStateResult dataRegResponse = {};
-        if (response == NULL) {
-            RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else if (s_vendorFunctions->version <= 14) {
-            int numStrings = responseLen / sizeof(char *);
-            if ((numStrings != 6) && (numStrings != 11)) {
-                RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
-                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            } else {
-                char **resp = (char **) response;
-                dataRegResponse.regState = (RegState) ATOI_NULL_HANDLED_DEF(resp[0], 4);
-                dataRegResponse.rat =  ATOI_NULL_HANDLED_DEF(resp[3], 0);
-                dataRegResponse.reasonDataDenied =  ATOI_NULL_HANDLED(resp[4]);
-                dataRegResponse.maxDataCalls =  ATOI_NULL_HANDLED_DEF(resp[5], 1);
-                fillCellIdentityFromDataRegStateResponseString(dataRegResponse.cellIdentity,
-                        numStrings, resp);
-            }
-        } else {
-            RIL_DataRegistrationStateResponse *dataRegState =
-                    (RIL_DataRegistrationStateResponse *)response;
-
-            if (responseLen != sizeof(RIL_DataRegistrationStateResponse)) {
-                RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
-                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            } else {
-                dataRegResponse.regState = (RegState) dataRegState->regState;
-                dataRegResponse.rat = dataRegState->rat;
-                dataRegResponse.reasonDataDenied = dataRegState->reasonDataDenied;
-                dataRegResponse.maxDataCalls = dataRegState->maxDataCalls;
-                fillCellIdentityResponse(dataRegResponse.cellIdentity, dataRegState->cellIdentity);
-            }
-        }
-
-        Return<void> retStatus =
-                radioService[slotId]->mRadioResponse->getDataRegistrationStateResponse(
-                        responseInfo, dataRegResponse);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getDataRegistrationStateResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getOperatorResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responseLen) {
-#if VDBG
-    RLOGD("getOperatorResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_string longName;
-        hidl_string shortName;
-        hidl_string numeric;
-        int numStrings = responseLen / sizeof(char *);
-        if (response == NULL || numStrings != 3) {
-            RLOGE("getOperatorResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-
-        } else {
-            char **resp = (char **) response;
-            longName = convertCharPtrToHidlString(resp[0]);
-            shortName = convertCharPtrToHidlString(resp[1]);
-            numeric = convertCharPtrToHidlString(resp[2]);
-        }
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getOperatorResponse(
-                responseInfo, longName, shortName, numeric);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getOperatorResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setRadioPowerResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e, void *response,
-                                size_t responseLen) {
-#if VDBG
-    RLOGD("setRadioPowerResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->setRadioPowerResponse_1_5(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponse
-                ->setRadioPowerResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setRadioPowerResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendDtmfResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e, void *response,
-                           size_t responseLen) {
-#if VDBG
-    RLOGD("sendDtmfResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendDtmfResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendDtmfResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-SendSmsResult makeSendSmsResult(RadioResponseInfo& responseInfo, int serial, int responseType,
-                                RIL_Errno e, void *response, size_t responseLen) {
-    populateResponseInfo(responseInfo, serial, responseType, e);
-    SendSmsResult result = {};
-
-    if (response == NULL || responseLen != sizeof(RIL_SMS_Response)) {
-        RLOGE("Invalid response: NULL");
-        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        result.ackPDU = hidl_string();
-    } else {
-        RIL_SMS_Response *resp = (RIL_SMS_Response *) response;
-        result.messageRef = resp->messageRef;
-        result.ackPDU = convertCharPtrToHidlString(resp->ackPDU);
-        result.errorCode = resp->errorCode;
-    }
-    return result;
-}
-
-int radio_1_5::sendSmsResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responseLen) {
-#if VDBG
-    RLOGD("sendSmsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendSmsResponse(responseInfo,
-                result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendSmsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendSMSExpectMoreResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responseLen) {
-#if VDBG
-    RLOGD("sendSMSExpectMoreResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendSMSExpectMoreResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendSMSExpectMoreResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setupDataCallResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responseLen) {
-#if VDBG
-    RLOGD("setupDataCallResponse: serial %d", serial);
-#endif
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        ::android::hardware::radio::V1_5::SetupDataCallResult result;
-        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
-            if (response != NULL) {
-                RLOGE("setupDataCallResponse_1_5: Invalid response");
-                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            }
-            result.cause = ::android::hardware::radio::V1_4::DataCallFailCause::ERROR_UNSPECIFIED;
-            result.type = ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
-            result.ifname = hidl_string();
-            result.addresses = hidl_vec<::android::hardware::radio::V1_5::LinkAddress>();
-            result.dnses = hidl_vec<hidl_string>();
-            result.gateways = hidl_vec<hidl_string>();
-            result.pcscf = hidl_vec<hidl_string>();
-        } else {
-            convertRilDataCallToHal((RIL_Data_Call_Response_v12 *) response, result);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5->setupDataCallResponse_1_5(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        ::android::hardware::radio::V1_4::SetupDataCallResult result;
-        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
-            if (response != NULL) {
-                RLOGE("setupDataCallResponse_1_4: Invalid response");
-                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            }
-            result.cause = ::android::hardware::radio::V1_4::DataCallFailCause::ERROR_UNSPECIFIED;
-            result.type = ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
-            result.ifname = hidl_string();
-            result.addresses = hidl_vec<hidl_string>();
-            result.dnses = hidl_vec<hidl_string>();
-            result.gateways = hidl_vec<hidl_string>();
-            result.pcscf = hidl_vec<hidl_string>();
-        } else {
-            convertRilDataCallToHal((RIL_Data_Call_Response_v11 *) response, result);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->setupDataCallResponse_1_4(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        SetupDataCallResult result = {};
-        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
-           if (response != NULL) {
-               RLOGE("setupDataCallResponse: Invalid response");
-               if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-           }
-           result.status = DataCallFailCause::ERROR_UNSPECIFIED;
-           result.type = hidl_string();
-           result.ifname = hidl_string();
-           result.addresses = hidl_string();
-           result.dnses = hidl_string();
-           result.gateways = hidl_string();
-           result.pcscf = hidl_string();
-        } else {
-           convertRilDataCallToHal((RIL_Data_Call_Response_v11 *) response, result);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->setupDataCallResponse(
-               responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setupDataCallResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-IccIoResult responseIccIo(RadioResponseInfo& responseInfo, int serial, int responseType,
-                           RIL_Errno e, void *response, size_t responseLen) {
-    populateResponseInfo(responseInfo, serial, responseType, e);
-    IccIoResult result = {};
-
-    if (response == NULL || responseLen != sizeof(RIL_SIM_IO_Response)) {
-        RLOGE("Invalid response: NULL");
-        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        result.simResponse = hidl_string();
-    } else {
-        RIL_SIM_IO_Response *resp = (RIL_SIM_IO_Response *) response;
-        result.sw1 = resp->sw1;
-        result.sw2 = resp->sw2;
-        result.simResponse = convertCharPtrToHidlString(resp->simResponse);
-    }
-    return result;
-}
-
-int radio_1_5::iccIOForAppResponse(int slotId,
-                      int responseType, int serial, RIL_Errno e, void *response,
-                      size_t responseLen) {
-#if VDBG
-    RLOGD("iccIOForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->iccIOForAppResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("iccIOForAppResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendUssdResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e, void *response,
-                           size_t responseLen) {
-#if VDBG
-    RLOGD("sendUssdResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendUssdResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendUssdResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cancelPendingUssdResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responseLen) {
-#if VDBG
-    RLOGD("cancelPendingUssdResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->cancelPendingUssdResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cancelPendingUssdResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getClirResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responseLen) {
-#if VDBG
-    RLOGD("getClirResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        int n = -1, m = -1;
-        int numInts = responseLen / sizeof(int);
-        if (response == NULL || numInts != 2) {
-            RLOGE("getClirResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            n = pInt[0];
-            m = pInt[1];
-        }
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getClirResponse(responseInfo,
-                n, m);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getClirResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setClirResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responseLen) {
-#if VDBG
-    RLOGD("setClirResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->setClirResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setClirResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCallForwardStatusResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e,
-                                       void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getCallForwardStatusResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<CallForwardInfo> callForwardInfos;
-
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_CallForwardInfo *) != 0) {
-            RLOGE("getCallForwardStatusResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int num = responseLen / sizeof(RIL_CallForwardInfo *);
-            callForwardInfos.resize(num);
-            for (int i = 0 ; i < num; i++) {
-                RIL_CallForwardInfo *resp = ((RIL_CallForwardInfo **) response)[i];
-                callForwardInfos[i].status = (CallForwardInfoStatus) resp->status;
-                callForwardInfos[i].reason = resp->reason;
-                callForwardInfos[i].serviceClass = resp->serviceClass;
-                callForwardInfos[i].toa = resp->toa;
-                callForwardInfos[i].number = convertCharPtrToHidlString(resp->number);
-                callForwardInfos[i].timeSeconds = resp->timeSeconds;
-            }
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getCallForwardStatusResponse(
-                responseInfo, callForwardInfos);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getCallForwardStatusResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCallForwardResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responseLen) {
-#if VDBG
-    RLOGD("setCallForwardResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->setCallForwardResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCallForwardResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCallWaitingResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responseLen) {
-#if VDBG
-    RLOGD("getCallWaitingResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        bool enable = false;
-        int serviceClass = -1;
-        int numInts = responseLen / sizeof(int);
-        if (response == NULL || numInts != 2) {
-            RLOGE("getCallWaitingResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            enable = pInt[0] == 1 ? true : false;
-            serviceClass = pInt[1];
-        }
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getCallWaitingResponse(
-                responseInfo, enable, serviceClass);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getCallWaitingResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCallWaitingResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responseLen) {
-#if VDBG
-    RLOGD("setCallWaitingResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->setCallWaitingResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCallWaitingResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::acknowledgeLastIncomingGsmSmsResponse(int slotId,
-                                                int responseType, int serial, RIL_Errno e,
-                                                void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("acknowledgeLastIncomingGsmSmsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus =
-                radioService[slotId]->mRadioResponse->acknowledgeLastIncomingGsmSmsResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("acknowledgeLastIncomingGsmSmsResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::acceptCallResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e,
-                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("acceptCallResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->acceptCallResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("acceptCallResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::deactivateDataCallResponse(int slotId,
-                                                int responseType, int serial, RIL_Errno e,
-                                                void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("deactivateDataCallResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->deactivateDataCallResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("deactivateDataCallResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getFacilityLockForAppResponse(int slotId,
-                                        int responseType, int serial, RIL_Errno e,
-                                        void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getFacilityLockForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                getFacilityLockForAppResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getFacilityLockForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setFacilityLockForAppResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setFacilityLockForAppResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setFacilityLockForAppResponse(responseInfo,
-                ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setFacilityLockForAppResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setBarringPasswordResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e,
-                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("acceptCallResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setBarringPasswordResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setBarringPasswordResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getNetworkSelectionModeResponse(int slotId,
-                                          int responseType, int serial, RIL_Errno e, void *response,
-                                          size_t responseLen) {
-#if VDBG
-    RLOGD("getNetworkSelectionModeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        bool manual = false;
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("getNetworkSelectionModeResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            manual = pInt[0] == 1 ? true : false;
-        }
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getNetworkSelectionModeResponse(
-                responseInfo,
-                manual);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getNetworkSelectionModeResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setNetworkSelectionModeAutomaticResponse(int slotId, int responseType, int serial,
-                                                    RIL_Errno e, void *response,
-                                                    size_t responseLen) {
-#if VDBG
-    RLOGD("setNetworkSelectionModeAutomaticResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setNetworkSelectionModeAutomaticResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setNetworkSelectionModeAutomaticResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setNetworkSelectionModeManualResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e,
-                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setNetworkSelectionModeManualResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->setNetworkSelectionModeManualResponse_1_5(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponse
-                ->setNetworkSelectionModeManualResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("acceptCallResponse: radioService[%d]->setNetworkSelectionModeManualResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int convertOperatorStatusToInt(const char *str) {
-    if (strncmp("unknown", str, 9) == 0) {
-        return (int) OperatorStatus::UNKNOWN;
-    } else if (strncmp("available", str, 9) == 0) {
-        return (int) OperatorStatus::AVAILABLE;
-    } else if (strncmp("current", str, 9) == 0) {
-        return (int) OperatorStatus::CURRENT;
-    } else if (strncmp("forbidden", str, 9) == 0) {
-        return (int) OperatorStatus::FORBIDDEN;
-    } else {
-        return -1;
-    }
-}
-
-int radio_1_5::getAvailableNetworksResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responseLen) {
-#if VDBG
-    RLOGD("getAvailableNetworksResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<OperatorInfo> networks;
-        if ((response == NULL && responseLen != 0)
-                || responseLen % (4 * sizeof(char *))!= 0) {
-            RLOGE("getAvailableNetworksResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            char **resp = (char **) response;
-            int numStrings = responseLen / sizeof(char *);
-            networks.resize(numStrings/4);
-            for (int i = 0, j = 0; i < numStrings; i = i + 4, j++) {
-                networks[j].alphaLong = convertCharPtrToHidlString(resp[i]);
-                networks[j].alphaShort = convertCharPtrToHidlString(resp[i + 1]);
-                networks[j].operatorNumeric = convertCharPtrToHidlString(resp[i + 2]);
-                int status = convertOperatorStatusToInt(resp[i + 3]);
-                if (status == -1) {
-                    if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-                } else {
-                    networks[j].status = (OperatorStatus) status;
-                }
-            }
-        }
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getAvailableNetworksResponse(responseInfo,
-                networks);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getAvailableNetworksResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::startDtmfResponse(int slotId,
-                            int responseType, int serial, RIL_Errno e,
-                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("startDtmfResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->startDtmfResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("startDtmfResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stopDtmfResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e,
-                           void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("stopDtmfResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->stopDtmfResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stopDtmfResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getBasebandVersionResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getBasebandVersionResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getBasebandVersionResponse(responseInfo,
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getBasebandVersionResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::separateConnectionResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("separateConnectionResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->separateConnectionResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("separateConnectionResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setMuteResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setMuteResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setMuteResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setMuteResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getMuteResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responseLen) {
-#if VDBG
-    RLOGD("getMuteResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        bool enable = false;
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("getMuteResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            enable = pInt[0] == 1 ? true : false;
-        }
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getMuteResponse(responseInfo,
-                enable);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getMuteResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getClipResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getClipResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getClipResponse(responseInfo,
-                (ClipStatus) ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getClipResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getDataCallListResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getDataCallListResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        hidl_vec<SetupDataCallResult> ret;
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_Data_Call_Response_v11) != 0) {
-            RLOGE("getDataCallListResponse: invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            convertRilDataCallListToHal(response, responseLen, ret);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getDataCallListResponse(
-                responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getDataCallListResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setSuppServiceNotificationsResponse(int slotId,
-                                              int responseType, int serial, RIL_Errno e,
-                                              void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setSuppServiceNotificationsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setSuppServiceNotificationsResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setSuppServiceNotificationsResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::deleteSmsOnSimResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("deleteSmsOnSimResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->deleteSmsOnSimResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("deleteSmsOnSimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setBandModeResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setBandModeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setBandModeResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setBandModeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::writeSmsToSimResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e,
-                                void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("writeSmsToSimResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->writeSmsToSimResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("writeSmsToSimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getAvailableBandModesResponse(int slotId,
-                                        int responseType, int serial, RIL_Errno e, void *response,
-                                        size_t responseLen) {
-#if VDBG
-    RLOGD("getAvailableBandModesResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<RadioBandMode> modes;
-        if ((response == NULL && responseLen != 0)|| responseLen % sizeof(int) != 0) {
-            RLOGE("getAvailableBandModesResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            int numInts = responseLen / sizeof(int);
-            modes.resize(numInts);
-            for (int i = 0; i < numInts; i++) {
-                modes[i] = (RadioBandMode) pInt[i];
-            }
-        }
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getAvailableBandModesResponse(responseInfo,
-                modes);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getAvailableBandModesResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendEnvelopeResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("sendEnvelopeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendEnvelopeResponse(responseInfo,
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendEnvelopeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendTerminalResponseToSimResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("sendTerminalResponseToSimResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendTerminalResponseToSimResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendTerminalResponseToSimResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::handleStkCallSetupRequestFromSimResponse(int slotId,
-                                                   int responseType, int serial,
-                                                   RIL_Errno e, void *response,
-                                                   size_t responseLen) {
-#if VDBG
-    RLOGD("handleStkCallSetupRequestFromSimResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->handleStkCallSetupRequestFromSimResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("handleStkCallSetupRequestFromSimResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::explicitCallTransferResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e,
-                                       void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("explicitCallTransferResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->explicitCallTransferResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("explicitCallTransferResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setPreferredNetworkTypeResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setPreferredNetworkTypeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setPreferredNetworkTypeResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setPreferredNetworkTypeResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-
-int radio_1_5::getPreferredNetworkTypeResponse(int slotId,
-                                          int responseType, int serial, RIL_Errno e,
-                                          void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getPreferredNetworkTypeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getPreferredNetworkTypeResponse(
-                responseInfo, (PreferredNetworkType) ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getPreferredNetworkTypeResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setPreferredNetworkTypeBitmapResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setPreferredNetworkTypeBitmapResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponseV1_4->setPreferredNetworkTypeBitmapResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setPreferredNetworkTypeBitmapResponse: radioService[%d]->mRadioResponseV1_4 == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-
-int radio_1_5::getPreferredNetworkTypeBitmapResponse(int slotId,
-                                          int responseType, int serial, RIL_Errno e,
-                                          void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getPreferredNetworkTypeBitmapResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponseV1_4->getPreferredNetworkTypeBitmapResponse(
-                responseInfo,
-                (const ::android::hardware::hidl_bitfield<
-                ::android::hardware::radio::V1_4::RadioAccessFamily>) ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getPreferredNetworkTypeBitmapResponse: radioService[%d]->mRadioResponseV1_4 == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getNeighboringCidsResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getNeighboringCidsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<NeighboringCell> cells;
-
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_NeighboringCell *) != 0) {
-            RLOGE("getNeighboringCidsResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int num = responseLen / sizeof(RIL_NeighboringCell *);
-            cells.resize(num);
-            for (int i = 0 ; i < num; i++) {
-                RIL_NeighboringCell *resp = ((RIL_NeighboringCell **) response)[i];
-                cells[i].cid = convertCharPtrToHidlString(resp->cid);
-                cells[i].rssi = resp->rssi;
-            }
-        }
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getNeighboringCidsResponse(responseInfo,
-                cells);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getNeighboringCidsResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setLocationUpdatesResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setLocationUpdatesResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setLocationUpdatesResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setLocationUpdatesResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCdmaSubscriptionSourceResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setCdmaSubscriptionSourceResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setCdmaSubscriptionSourceResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCdmaSubscriptionSourceResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCdmaRoamingPreferenceResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setCdmaRoamingPreferenceResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setCdmaRoamingPreferenceResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCdmaRoamingPreferenceResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCdmaRoamingPreferenceResponse(int slotId,
-                                           int responseType, int serial, RIL_Errno e,
-                                           void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getCdmaRoamingPreferenceResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getCdmaRoamingPreferenceResponse(
-                responseInfo, (CdmaRoamingType) ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getCdmaRoamingPreferenceResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setTTYModeResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e,
-                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setTTYModeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setTTYModeResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setTTYModeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getTTYModeResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e,
-                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getTTYModeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getTTYModeResponse(responseInfo,
-                (TtyMode) ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getTTYModeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setPreferredVoicePrivacyResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setPreferredVoicePrivacyResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setPreferredVoicePrivacyResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setPreferredVoicePrivacyResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getPreferredVoicePrivacyResponse(int slotId,
-                                           int responseType, int serial, RIL_Errno e,
-                                           void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getPreferredVoicePrivacyResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        bool enable = false;
-        int numInts = responseLen / sizeof(int);
-        if (response == NULL || numInts != 1) {
-            RLOGE("getPreferredVoicePrivacyResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            enable = pInt[0] == 1 ? true : false;
-        }
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getPreferredVoicePrivacyResponse(
-                responseInfo, enable);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getPreferredVoicePrivacyResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendCDMAFeatureCodeResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("sendCDMAFeatureCodeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendCDMAFeatureCodeResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendCDMAFeatureCodeResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendBurstDtmfResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("sendBurstDtmfResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendBurstDtmfResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendBurstDtmfResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendCdmaSmsResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responseLen) {
-#if VDBG
-    RLOGD("sendCdmaSmsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendCdmaSmsResponse(responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendCdmaSmsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::acknowledgeLastIncomingCdmaSmsResponse(int slotId,
-                                                 int responseType, int serial, RIL_Errno e,
-                                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("acknowledgeLastIncomingCdmaSmsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->acknowledgeLastIncomingCdmaSmsResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("acknowledgeLastIncomingCdmaSmsResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getGsmBroadcastConfigResponse(int slotId,
-                                        int responseType, int serial, RIL_Errno e,
-                                        void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getGsmBroadcastConfigResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<GsmBroadcastSmsConfigInfo> configs;
-
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_GSM_BroadcastSmsConfigInfo *) != 0) {
-            RLOGE("getGsmBroadcastConfigResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int num = responseLen / sizeof(RIL_GSM_BroadcastSmsConfigInfo *);
-            configs.resize(num);
-            for (int i = 0 ; i < num; i++) {
-                RIL_GSM_BroadcastSmsConfigInfo *resp =
-                        ((RIL_GSM_BroadcastSmsConfigInfo **) response)[i];
-                configs[i].fromServiceId = resp->fromServiceId;
-                configs[i].toServiceId = resp->toServiceId;
-                configs[i].fromCodeScheme = resp->fromCodeScheme;
-                configs[i].toCodeScheme = resp->toCodeScheme;
-                configs[i].selected = resp->selected == 1 ? true : false;
-            }
-        }
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getGsmBroadcastConfigResponse(responseInfo,
-                configs);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getGsmBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setGsmBroadcastConfigResponse(int slotId,
-                                        int responseType, int serial, RIL_Errno e,
-                                        void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setGsmBroadcastConfigResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setGsmBroadcastConfigResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setGsmBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setGsmBroadcastActivationResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setGsmBroadcastActivationResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setGsmBroadcastActivationResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setGsmBroadcastActivationResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCdmaBroadcastConfigResponse(int slotId,
-                                         int responseType, int serial, RIL_Errno e,
-                                         void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getCdmaBroadcastConfigResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<CdmaBroadcastSmsConfigInfo> configs;
-
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_CDMA_BroadcastSmsConfigInfo *) != 0) {
-            RLOGE("getCdmaBroadcastConfigResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int num = responseLen / sizeof(RIL_CDMA_BroadcastSmsConfigInfo *);
-            configs.resize(num);
-            for (int i = 0 ; i < num; i++) {
-                RIL_CDMA_BroadcastSmsConfigInfo *resp =
-                        ((RIL_CDMA_BroadcastSmsConfigInfo **) response)[i];
-                configs[i].serviceCategory = resp->service_category;
-                configs[i].language = resp->language;
-                configs[i].selected = resp->selected == 1 ? true : false;
-            }
-        }
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getCdmaBroadcastConfigResponse(responseInfo,
-                configs);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getCdmaBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCdmaBroadcastConfigResponse(int slotId,
-                                         int responseType, int serial, RIL_Errno e,
-                                         void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setCdmaBroadcastConfigResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setCdmaBroadcastConfigResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCdmaBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCdmaBroadcastActivationResponse(int slotId,
-                                             int responseType, int serial, RIL_Errno e,
-                                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setCdmaBroadcastActivationResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setCdmaBroadcastActivationResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCdmaBroadcastActivationResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCDMASubscriptionResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e, void *response,
-                                      size_t responseLen) {
-#if VDBG
-    RLOGD("getCDMASubscriptionResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        int numStrings = responseLen / sizeof(char *);
-        hidl_string emptyString;
-        if (response == NULL || numStrings != 5) {
-            RLOGE("getOperatorResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            Return<void> retStatus
-                    = radioService[slotId]->mRadioResponse->getCDMASubscriptionResponse(
-                    responseInfo, emptyString, emptyString, emptyString, emptyString, emptyString);
-            radioService[slotId]->checkReturnStatus(retStatus);
-        } else {
-            char **resp = (char **) response;
-            Return<void> retStatus
-                    = radioService[slotId]->mRadioResponse->getCDMASubscriptionResponse(
-                    responseInfo,
-                    convertCharPtrToHidlString(resp[0]),
-                    convertCharPtrToHidlString(resp[1]),
-                    convertCharPtrToHidlString(resp[2]),
-                    convertCharPtrToHidlString(resp[3]),
-                    convertCharPtrToHidlString(resp[4]));
-            radioService[slotId]->checkReturnStatus(retStatus);
-        }
-    } else {
-        RLOGE("getCDMASubscriptionResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::writeSmsToRuimResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("writeSmsToRuimResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->writeSmsToRuimResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("writeSmsToRuimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::deleteSmsOnRuimResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("deleteSmsOnRuimResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->deleteSmsOnRuimResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("deleteSmsOnRuimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getDeviceIdentityResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responseLen) {
-#if VDBG
-    RLOGD("getDeviceIdentityResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        int numStrings = responseLen / sizeof(char *);
-        hidl_string emptyString;
-        if (response == NULL || numStrings != 4) {
-            RLOGE("getDeviceIdentityResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            Return<void> retStatus
-                    = radioService[slotId]->mRadioResponse->getDeviceIdentityResponse(responseInfo,
-                    emptyString, emptyString, emptyString, emptyString);
-            radioService[slotId]->checkReturnStatus(retStatus);
-        } else {
-            char **resp = (char **) response;
-            Return<void> retStatus
-                    = radioService[slotId]->mRadioResponse->getDeviceIdentityResponse(responseInfo,
-                    convertCharPtrToHidlString(resp[0]),
-                    convertCharPtrToHidlString(resp[1]),
-                    convertCharPtrToHidlString(resp[2]),
-                    convertCharPtrToHidlString(resp[3]));
-            radioService[slotId]->checkReturnStatus(retStatus);
-        }
-    } else {
-        RLOGE("getDeviceIdentityResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::exitEmergencyCallbackModeResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("exitEmergencyCallbackModeResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->exitEmergencyCallbackModeResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("exitEmergencyCallbackModeResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getSmscAddressResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getSmscAddressResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getSmscAddressResponse(responseInfo,
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getSmscAddressResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setSmscAddressResponse(int slotId,
-                                             int responseType, int serial, RIL_Errno e,
-                                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setSmscAddressResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setSmscAddressResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setSmscAddressResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::reportSmsMemoryStatusResponse(int slotId,
-                                        int responseType, int serial, RIL_Errno e,
-                                        void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("reportSmsMemoryStatusResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->reportSmsMemoryStatusResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("reportSmsMemoryStatusResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::reportStkServiceIsRunningResponse(int slotId,
-                                             int responseType, int serial, RIL_Errno e,
-                                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("reportStkServiceIsRunningResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->
-                reportStkServiceIsRunningResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("reportStkServiceIsRunningResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCdmaSubscriptionSourceResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getCdmaSubscriptionSourceResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getCdmaSubscriptionSourceResponse(
-                responseInfo, (CdmaSubscriptionSource) ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getCdmaSubscriptionSourceResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::requestIsimAuthenticationResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("requestIsimAuthenticationResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->requestIsimAuthenticationResponse(
-                responseInfo,
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("requestIsimAuthenticationResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::acknowledgeIncomingGsmSmsWithPduResponse(int slotId,
-                                                   int responseType,
-                                                   int serial, RIL_Errno e, void *response,
-                                                   size_t responseLen) {
-#if VDBG
-    RLOGD("acknowledgeIncomingGsmSmsWithPduResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->acknowledgeIncomingGsmSmsWithPduResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("acknowledgeIncomingGsmSmsWithPduResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendEnvelopeWithStatusResponse(int slotId,
-                                         int responseType, int serial, RIL_Errno e, void *response,
-                                         size_t responseLen) {
-#if VDBG
-    RLOGD("sendEnvelopeWithStatusResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e,
-                response, responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendEnvelopeWithStatusResponse(responseInfo,
-                result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendEnvelopeWithStatusResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getVoiceRadioTechnologyResponse(int slotId,
-                                          int responseType, int serial, RIL_Errno e,
-                                          void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getVoiceRadioTechnologyResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getVoiceRadioTechnologyResponse(
-                responseInfo, (RadioTechnology) ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getVoiceRadioTechnologyResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getCellInfoListResponse(int slotId,
-                                   int responseType,
-                                   int serial, RIL_Errno e, void *response,
-                                   size_t responseLen) {
-#if VDBG
-    RLOGD("getCellInfoListResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        hidl_vec<CellInfo> ret;
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_CellInfo_v12) != 0) {
-            RLOGE("getCellInfoListResponse: Invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            convertRilCellInfoListToHal(response, responseLen, ret);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getCellInfoListResponse(
-                responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getCellInfoListResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCellInfoListRateResponse(int slotId,
-                                       int responseType,
-                                       int serial, RIL_Errno e, void *response,
-                                       size_t responseLen) {
-#if VDBG
-    RLOGD("setCellInfoListRateResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setCellInfoListRateResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCellInfoListRateResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setInitialAttachApnResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e,
-                                       void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setInitialAttachApnResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponseV1_5->setInitialAttachApnResponse_1_5(
-                responseInfo);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setInitialAttachApnResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setInitialAttachApnResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getImsRegistrationStateResponse(int slotId,
-                                           int responseType, int serial, RIL_Errno e,
-                                           void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getImsRegistrationStateResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        bool isRegistered = false;
-        int ratFamily = 0;
-        int numInts = responseLen / sizeof(int);
-        if (response == NULL || numInts != 2) {
-            RLOGE("getImsRegistrationStateResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            isRegistered = pInt[0] == 1 ? true : false;
-            ratFamily = pInt[1];
-        }
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getImsRegistrationStateResponse(
-                responseInfo, isRegistered, (RadioTechnologyFamily) ratFamily);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getImsRegistrationStateResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendImsSmsResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responseLen) {
-#if VDBG
-    RLOGD("sendImsSmsResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendImsSmsResponse(responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendSmsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::iccTransmitApduBasicChannelResponse(int slotId,
-                                               int responseType, int serial, RIL_Errno e,
-                                               void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("iccTransmitApduBasicChannelResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->iccTransmitApduBasicChannelResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("iccTransmitApduBasicChannelResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::iccOpenLogicalChannelResponse(int slotId,
-                                         int responseType, int serial, RIL_Errno e, void *response,
-                                         size_t responseLen) {
-#if VDBG
-    RLOGD("iccOpenLogicalChannelResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        int channelId = -1;
-        hidl_vec<int8_t> selectResponse;
-        int numInts = responseLen / sizeof(int);
-        if (response == NULL || responseLen % sizeof(int) != 0) {
-            RLOGE("iccOpenLogicalChannelResponse Invalid response: NULL");
-            if (response != NULL) {
-                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-            }
-        } else {
-            int *pInt = (int *) response;
-            channelId = pInt[0];
-            selectResponse.resize(numInts - 1);
-            for (int i = 1; i < numInts; i++) {
-                selectResponse[i - 1] = (int8_t) pInt[i];
-            }
-        }
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->iccOpenLogicalChannelResponse(responseInfo,
-                channelId, selectResponse);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("iccOpenLogicalChannelResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::iccCloseLogicalChannelResponse(int slotId,
-                                          int responseType, int serial, RIL_Errno e,
-                                          void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("iccCloseLogicalChannelResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->iccCloseLogicalChannelResponse(
-                responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("iccCloseLogicalChannelResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::iccTransmitApduLogicalChannelResponse(int slotId,
-                                                 int responseType, int serial, RIL_Errno e,
-                                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("iccTransmitApduLogicalChannelResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->iccTransmitApduLogicalChannelResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("iccTransmitApduLogicalChannelResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::nvReadItemResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("nvReadItemResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->nvReadItemResponse(
-                responseInfo,
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("nvReadItemResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::nvWriteItemResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("nvWriteItemResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->nvWriteItemResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("nvWriteItemResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::nvWriteCdmaPrlResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("nvWriteCdmaPrlResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->nvWriteCdmaPrlResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("nvWriteCdmaPrlResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::nvResetConfigResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("nvResetConfigResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->nvResetConfigResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("nvResetConfigResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setUiccSubscriptionResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e,
-                                       void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setUiccSubscriptionResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setUiccSubscriptionResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setUiccSubscriptionResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setDataAllowedResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setDataAllowedResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setDataAllowedResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setDataAllowedResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getHardwareConfigResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getHardwareConfigResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        hidl_vec<HardwareConfig> result;
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_HardwareConfig) != 0) {
-            RLOGE("hardwareConfigChangedInd: invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            convertRilHardwareConfigListToHal(response, responseLen, result);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getHardwareConfigResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getHardwareConfigResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::requestIccSimAuthenticationResponse(int slotId,
-                                               int responseType, int serial, RIL_Errno e,
-                                               void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("requestIccSimAuthenticationResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->requestIccSimAuthenticationResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("requestIccSimAuthenticationResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setDataProfileResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setDataProfileResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponseV1_5->setDataProfileResponse_1_5(
-                responseInfo);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->setDataProfileResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setDataProfileResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::requestShutdownResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("requestShutdownResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->requestShutdownResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("requestShutdownResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-void responseRadioCapability(RadioResponseInfo& responseInfo, int serial,
-        int responseType, RIL_Errno e, void *response, size_t responseLen, RadioCapability& rc) {
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (response == NULL || responseLen != sizeof(RIL_RadioCapability)) {
-        RLOGE("responseRadioCapability: Invalid response");
-        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        rc.logicalModemUuid = hidl_string();
-    } else {
-        convertRilRadioCapabilityToHal(response, responseLen, rc);
-    }
-}
-
-int radio_1_5::getRadioCapabilityResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getRadioCapabilityResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        RadioCapability result = {};
-        responseRadioCapability(responseInfo, serial, responseType, e, response, responseLen,
-                result);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->getRadioCapabilityResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getRadioCapabilityResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setRadioCapabilityResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setRadioCapabilityResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        RadioCapability result = {};
-        responseRadioCapability(responseInfo, serial, responseType, e, response, responseLen,
-                result);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->setRadioCapabilityResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setRadioCapabilityResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-LceStatusInfo responseLceStatusInfo(RadioResponseInfo& responseInfo, int serial, int responseType,
-                                    RIL_Errno e, void *response, size_t responseLen) {
-    populateResponseInfo(responseInfo, serial, responseType, e);
-    LceStatusInfo result = {};
-
-    if (response == NULL || responseLen != sizeof(RIL_LceStatusInfo)) {
-        RLOGE("Invalid response: NULL");
-        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-    } else {
-        RIL_LceStatusInfo *resp = (RIL_LceStatusInfo *) response;
-        result.lceStatus = (LceStatus) resp->lce_status;
-        result.actualIntervalMs = (uint8_t) resp->actual_interval_ms;
-    }
-    return result;
-}
-
-int radio_1_5::startLceServiceResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("startLceServiceResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        LceStatusInfo result = responseLceStatusInfo(responseInfo, serial, responseType, e,
-                response, responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->startLceServiceResponse(responseInfo,
-                result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("startLceServiceResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stopLceServiceResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("stopLceServiceResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        LceStatusInfo result = responseLceStatusInfo(responseInfo, serial, responseType, e,
-                response, responseLen);
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->stopLceServiceResponse(responseInfo,
-                result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stopLceServiceResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::pullLceDataResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("pullLceDataResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-
-        LceDataInfo result = {};
-        if (response == NULL || responseLen != sizeof(RIL_LceDataInfo)) {
-            RLOGE("pullLceDataResponse: Invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            convertRilLceDataInfoToHal(response, responseLen, result);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse->pullLceDataResponse(
-                responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("pullLceDataResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::getModemActivityInfoResponse(int slotId,
-                                        int responseType, int serial, RIL_Errno e,
-                                        void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getModemActivityInfoResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        ActivityStatsInfo info;
-        if (response == NULL || responseLen != sizeof(RIL_ActivityStatsInfo)) {
-            RLOGE("getModemActivityInfoResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            RIL_ActivityStatsInfo *resp = (RIL_ActivityStatsInfo *)response;
-            info.sleepModeTimeMs = resp->sleep_mode_time_ms;
-            info.idleModeTimeMs = resp->idle_mode_time_ms;
-            for(int i = 0; i < RIL_NUM_TX_POWER_LEVELS; i++) {
-                info.txmModetimeMs[i] = resp->tx_mode_time_ms[i];
-            }
-            info.rxModeTimeMs = resp->rx_mode_time_ms;
-        }
-
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->getModemActivityInfoResponse(responseInfo,
-                info);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getModemActivityInfoResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setAllowedCarriersResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setAllowedCarriersResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4
-                ->setAllowedCarriersResponse_1_4(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
-        Return<void> retStatus = radioService[slotId]->mRadioResponse
-                ->setAllowedCarriersResponse(responseInfo, ret);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setAllowedCarriersResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-void prepareCarrierRestrictionsResponse(hidl_vec<Carrier>& allowedCarriers,
-                                       hidl_vec<Carrier>& excludedCarriers,
-                                       bool& allAllowed,
-                                       const RIL_CarrierRestrictions* pCr) {
-    if (pCr->len_allowed_carriers > 0 || pCr->len_excluded_carriers > 0) {
-        allAllowed = false;
-    }
-    allowedCarriers.resize(pCr->len_allowed_carriers);
-    for(int i = 0; i < pCr->len_allowed_carriers; i++) {
-        RIL_Carrier *carrier = pCr->allowed_carriers + i;
-        allowedCarriers[i].mcc = convertCharPtrToHidlString(carrier->mcc);
-        allowedCarriers[i].mnc = convertCharPtrToHidlString(carrier->mnc);
-        allowedCarriers[i].matchType = (CarrierMatchType) carrier->match_type;
-        allowedCarriers[i].matchData =
-                convertCharPtrToHidlString(carrier->match_data);
-    }
-
-    excludedCarriers.resize(pCr->len_excluded_carriers);
-    for(int i = 0; i < pCr->len_excluded_carriers; i++) {
-        RIL_Carrier *carrier = pCr->excluded_carriers + i;
-        excludedCarriers[i].mcc = convertCharPtrToHidlString(carrier->mcc);
-        excludedCarriers[i].mnc = convertCharPtrToHidlString(carrier->mnc);
-        excludedCarriers[i].matchType = (CarrierMatchType) carrier->match_type;
-        excludedCarriers[i].matchData =
-                convertCharPtrToHidlString(carrier->match_data);
-    }
-}
-
-int radio_1_5::getAllowedCarriersResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("getAllowedCarriersResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        V1_4::CarrierRestrictionsWithPriority carrierInfo = {};
-        V1_4::SimLockMultiSimPolicy multiSimPolicy =
-                V1_4::SimLockMultiSimPolicy::NO_MULTISIM_POLICY;
-        bool allAllowed = true;
-
-        if (response == NULL) {
-#if VDBG
-            RLOGD("getAllowedCarriersResponse response is NULL: all allowed");
-#endif
-            carrierInfo.allowedCarriers.resize(0);
-            carrierInfo.excludedCarriers.resize(0);
-            carrierInfo.allowedCarriersPrioritized = false;
-        } else if (responseLen != sizeof(RIL_CarrierRestrictionsWithPriority)) {
-            RLOGE("getAllowedCarriersResponse Invalid response");
-            if (e == RIL_E_SUCCESS) {
-                responseInfo.error = RadioError::INVALID_RESPONSE;
-            }
-        } else {
-            RIL_CarrierRestrictionsWithPriority *pCrExt =
-                    (RIL_CarrierRestrictionsWithPriority *)response;
-
-            // Convert into the structure used in IRadio 1.0 to re-use existing code
-            RIL_CarrierRestrictions cr = {};
-            cr.len_allowed_carriers = pCrExt->len_allowed_carriers;
-            cr.len_excluded_carriers = pCrExt->len_excluded_carriers;
-            cr.allowed_carriers = pCrExt->allowed_carriers;
-            cr.excluded_carriers = pCrExt->excluded_carriers;
-            prepareCarrierRestrictionsResponse(carrierInfo.allowedCarriers,
-                    carrierInfo.excludedCarriers, allAllowed, &cr);
-
-            carrierInfo.allowedCarriersPrioritized = (bool)pCrExt->allowedCarriersPrioritized;
-            multiSimPolicy = (V1_4::SimLockMultiSimPolicy)pCrExt->multiSimPolicy;
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4
-                ->getAllowedCarriersResponse_1_4(responseInfo, carrierInfo, multiSimPolicy);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        CarrierRestrictions carrierInfo = {};
-        bool allAllowed = true;
-        if (response == NULL) {
-#if VDBG
-            RLOGD("getAllowedCarriersResponse response is NULL: all allowed");
-#endif
-            carrierInfo.allowedCarriers.resize(0);
-            carrierInfo.excludedCarriers.resize(0);
-        } else if (responseLen != sizeof(RIL_CarrierRestrictions)) {
-            RLOGE("getAllowedCarriersResponse Invalid response");
-            if (e == RIL_E_SUCCESS) {
-                responseInfo.error = RadioError::INVALID_RESPONSE;
-            }
-        } else {
-            RIL_CarrierRestrictions *pCr = (RIL_CarrierRestrictions *)response;
-            prepareCarrierRestrictionsResponse(carrierInfo.allowedCarriers,
-                    carrierInfo.excludedCarriers, allAllowed, pCr);
-        }
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponse
-                ->getAllowedCarriersResponse(responseInfo, allAllowed, carrierInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getAllowedCarriersResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendDeviceStateResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen) {
-#if VDBG
-    RLOGD("sendDeviceStateResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponse->sendDeviceStateResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendDeviceStateResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setCarrierInfoForImsiEncryptionResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen) {
-    RLOGD("setCarrierInfoForImsiEncryptionResponse: serial %d", serial);
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->
-                setCarrierInfoForImsiEncryptionResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setCarrierInfoForImsiEncryptionResponse: radioService[%d]->mRadioResponseV1_4 == "
-                "NULL", slotId);
-    }
-    return 0;
-}
-
-int radio_1_5::setIndicationFilterResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen) {
-#if VDBG
-    RLOGD("setIndicationFilterResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->setIndicationFilterResponse_1_5(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponse != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponse
-                ->setIndicationFilterResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setIndicationFilterResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setSimCardPowerResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("setSimCardPowerResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponse != NULL
-            || radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->
-                    setSimCardPowerResponse_1_1(responseInfo);
-            radioService[slotId]->checkReturnStatus(retStatus);
-        } else {
-            RLOGD("setSimCardPowerResponse: radioService[%d]->mRadioResponseV1_4 == NULL",
-                    slotId);
-            Return<void> retStatus
-                    = radioService[slotId]->mRadioResponse->setSimCardPowerResponse(responseInfo);
-            radioService[slotId]->checkReturnStatus(retStatus);
-        }
-    } else {
-        RLOGE("setSimCardPowerResponse: radioService[%d]->mRadioResponse == NULL && "
-                "radioService[%d]->mRadioResponseV1_4 == NULL", slotId, slotId);
-    }
-    return 0;
-}
-
-int radio_1_5::startNetworkScanResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                    void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("startNetworkScanResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->startNetworkScanResponse_1_5(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4
-                ->startNetworkScanResponse_1_4(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2
-                ->startNetworkScanResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("startNetworkScanResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stopNetworkScanResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("stopNetworkScanResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponseV1_4->stopNetworkScanResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stopNetworkScanResponse: radioService[%d]->mRadioResponseV1_4 == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::emergencyDialResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                    void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("emergencyDialResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponseV1_4->emergencyDialResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("emergencyDialResponse: radioService[%d]->mRadioResponseV1_4 == NULL", slotId);
-    }
-    return 0;
-}
-
-void convertRilKeepaliveStatusToHal(const RIL_KeepaliveStatus *rilStatus,
-        V1_1::KeepaliveStatus& halStatus) {
-    halStatus.sessionHandle = rilStatus->sessionHandle;
-    halStatus.code = static_cast<V1_1::KeepaliveStatusCode>(rilStatus->code);
-}
-
-int radio_1_5::startKeepaliveResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                    void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    // If we don't have a radio service, there's nothing we can do
-    if (radioService[slotId]->mRadioResponseV1_4 == NULL) {
-        RLOGE("%s: radioService[%d]->mRadioResponseV1_4 == NULL", __FUNCTION__, slotId);
-        return 0;
-    }
-
-    V1_1::KeepaliveStatus ks = {};
-    if (response == NULL || responseLen != sizeof(V1_1::KeepaliveStatus)) {
-        RLOGE("%s: invalid response - %d", __FUNCTION__, static_cast<int>(e));
-        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-    } else {
-        convertRilKeepaliveStatusToHal(static_cast<RIL_KeepaliveStatus*>(response), ks);
-    }
-
-    Return<void> retStatus =
-            radioService[slotId]->mRadioResponseV1_4->startKeepaliveResponse(responseInfo, ks);
-    radioService[slotId]->checkReturnStatus(retStatus);
-    return 0;
-}
-
-int radio_1_5::stopKeepaliveResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                    void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    // If we don't have a radio service, there's nothing we can do
-    if (radioService[slotId]->mRadioResponseV1_4 == NULL) {
-        RLOGE("%s: radioService[%d]->mRadioResponseV1_4 == NULL", __FUNCTION__, slotId);
-        return 0;
-    }
-
-    Return<void> retStatus =
-            radioService[slotId]->mRadioResponseV1_4->stopKeepaliveResponse(responseInfo);
-    radioService[slotId]->checkReturnStatus(retStatus);
-    return 0;
-}
-
-int radio_1_5::getModemStackStatusResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                    void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    // If we don't have a radio service, there's nothing we can do
-    if (radioService[slotId]->mRadioResponseV1_3 == NULL) {
-        RLOGE("%s: radioService[%d]->mRadioResponseV1_3 == NULL", __FUNCTION__, slotId);
-        return 0;
-    }
-
-    Return<void> retStatus =
-            radioService[slotId]->mRadioResponseV1_3->getModemStackStatusResponse(
-            responseInfo, true);
-    radioService[slotId]->checkReturnStatus(retStatus);
-    return 0;
-}
-
-int radio_1_5::enableModemResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                    void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    // If we don't have a radio service, there's nothing we can do
-    if (radioService[slotId]->mRadioResponseV1_3 == NULL) {
-        RLOGE("%s: radioService[%d]->mRadioResponseV1_3 == NULL", __FUNCTION__, slotId);
-        return 0;
-    }
-
-    Return<void> retStatus =
-            radioService[slotId]->mRadioResponseV1_3->enableModemResponse(responseInfo);
-    radioService[slotId]->checkReturnStatus(retStatus);
-    return 0;
-}
-
-int radio_1_5::sendRequestRawResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responseLen) {
-#if VDBG
-   RLOGD("sendRequestRawResponse: serial %d", serial);
-#endif
-
-    if (!kOemHookEnabled) return 0;
-
-    if (oemHookService[slotId]->mOemHookResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<uint8_t> data;
-
-        if (response == NULL) {
-            RLOGE("sendRequestRawResponse: Invalid response");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            data.setToExternal((uint8_t *) response, responseLen);
-        }
-        Return<void> retStatus = oemHookService[slotId]->mOemHookResponse->
-                sendRequestRawResponse(responseInfo, data);
-        checkReturnStatus(slotId, retStatus, false);
-    } else {
-        RLOGE("sendRequestRawResponse: oemHookService[%d]->mOemHookResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendRequestStringsResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("sendRequestStringsResponse: serial %d", serial);
-#endif
-
-    if (!kOemHookEnabled) return 0;
-
-    if (oemHookService[slotId]->mOemHookResponse != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        hidl_vec<hidl_string> data;
-
-        if ((response == NULL && responseLen != 0) || responseLen % sizeof(char *) != 0) {
-            RLOGE("sendRequestStringsResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            char **resp = (char **) response;
-            int numStrings = responseLen / sizeof(char *);
-            data.resize(numStrings);
-            for (int i = 0; i < numStrings; i++) {
-                data[i] = convertCharPtrToHidlString(resp[i]);
-            }
-        }
-        Return<void> retStatus
-                = oemHookService[slotId]->mOemHookResponse->sendRequestStringsResponse(
-                responseInfo, data);
-        checkReturnStatus(slotId, retStatus, false);
-    } else {
-        RLOGE("sendRequestStringsResponse: oemHookService[%d]->mOemHookResponse == "
-                "NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setSystemSelectionChannelsResponse(int slotId, int responseType, int serial,
-                                        RIL_Errno e, void* /* response */, size_t responseLen) {
-#if VDBG
-    RLOGD("setSystemSelectionChannelsResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->setSystemSelectionChannelsResponse_1_5(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponseV1_3 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_3
-                ->setSystemSelectionChannelsResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setSystemSelectionChannelsResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setSignalStrengthReportingCriteriaResponse(int slotId, int responseType, int serial,
-                                        RIL_Errno e, void* /* response */, size_t responseLen) {
-#if VDBG
-    RLOGD("setSignalStrengthReportingCriteriaResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->setSignalStrengthReportingCriteriaResponse_1_5(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2
-                ->setSignalStrengthReportingCriteriaResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setSignalStrengthReportingCriteriaResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::setLinkCapacityReportingCriteriaResponse(int slotId, int responseType, int serial,
-                                        RIL_Errno e, void* /* response */, size_t responseLen) {
-#if VDBG
-    RLOGD("setLinkCapacityReportingCriteriaResponse: serial %d", serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->setLinkCapacityReportingCriteriaResponse_1_5(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2
-                ->setLinkCapacityReportingCriteriaResponse(responseInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("setLinkCapacityReportingCriteriaResponse: radioService[%d]->mRadioResponse "
-                "== NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::enableUiccApplicationsResponse(int slotId, int responseType, int serial,
-                                    RIL_Errno e, void* /* response */, size_t responseLen) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    // If we don't have a radio service, there's nothing we can do
-    if (radioService[slotId]->mRadioResponseV1_5 == NULL) {
-        RLOGE("%s: radioService[%d]->mRadioResponseV1_5 == NULL", __FUNCTION__, slotId);
-        return 0;
-    }
-
-    Return<void> retStatus =
-            radioService[slotId]->mRadioResponseV1_5->enableUiccApplicationsResponse(
-            responseInfo);
-    radioService[slotId]->checkReturnStatus(retStatus);
-    return 0;
-}
-
-int radio_1_5::areUiccApplicationsEnabledResponse(int slotId, int responseType, int serial,
-                                        RIL_Errno e, void* response, size_t responseLen) {
-#if VDBG
-    RLOGD("%s(): %d", __FUNCTION__, serial);
-#endif
-    RadioResponseInfo responseInfo = {};
-    populateResponseInfo(responseInfo, serial, responseType, e);
-
-    // If we don't have a radio service, there's nothing we can do
-    if (radioService[slotId]->mRadioResponseV1_5 == NULL) {
-        RLOGE("%s: radioService[%d]->mRadioResponseV1_5 == NULL", __FUNCTION__, slotId);
-        return 0;
-    }
-
-    bool enable = false;
-    if (response == NULL || responseLen != sizeof(bool)) {
-        RLOGE("isSimDetachedFromNetwork Invalid response.");
-    } else {
-        enable = (*((bool *) response));
-    }
-
-    Return<void> retStatus =
-            radioService[slotId]->mRadioResponseV1_5->areUiccApplicationsEnabledResponse(
-            responseInfo, enable);
-    radioService[slotId]->checkReturnStatus(retStatus);
-    return 0;
-}
-
-int radio_1_5::getBarringInfoResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen) {
-#if VDBG
-    RLOGD("getBarringInfoResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        populateResponseInfo(responseInfo, serial, responseType, e);
-        ::android::hardware::radio::V1_5::CellIdentity cellIdentity;
-        hidl_vec<::android::hardware::radio::V1_5::BarringInfo> barringInfo;
-        Return<void> retStatus
-                = radioService[slotId]->mRadioResponseV1_5->
-                        getBarringInfoResponse(responseInfo, cellIdentity, barringInfo);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("getBarringInfoResponse: radioService[%d]->mRadioResponse == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::sendCdmaSmsExpectMoreResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                             void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("sendCdmaSmsExpectMoreResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
-                responseLen);
-
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->sendCdmaSmsExpectMoreResponse(responseInfo, result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("sendCdmaSmsExpectMoreResponse: radioService[%d]->mRadioResponse == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::supplySimDepersonalizationResponse(int slotId, int responseType, int serial,
-                                                  RIL_Errno e, void *response, size_t responseLen) {
-#if VDBG
-    RLOGD("supplySimDepersonalizationResponse: serial %d", serial);
-#endif
-
-    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
-        RadioResponseInfo responseInfo = {};
-        int persoType = -1, remainingRetries = -1;
-        int numInts = responseLen / sizeof(int);
-        if (response == NULL || numInts != 2) {
-            RLOGE("getClirResponse Invalid response: NULL");
-            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
-        } else {
-            int *pInt = (int *) response;
-            persoType = pInt[0];
-            remainingRetries = pInt[1];
-        }
-        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
-                ->supplySimDepersonalizationResponse(responseInfo, (V1_5::PersoSubstate) persoType,
-                remainingRetries);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("supplySimDepersonalizationResponse: radioService[%d]->mRadioResponseV1_5 == "
-                "NULL", slotId);
-    }
-
-    return 0;
-}
-
-/***************************************************************************************************
- * INDICATION FUNCTIONS
- * The below function handle unsolicited messages coming from the Radio
- * (messages for which there is no pending request)
- **************************************************************************************************/
-
-RadioIndicationType convertIntToRadioIndicationType(int indicationType) {
-    return indicationType == RESPONSE_UNSOLICITED ? (RadioIndicationType::UNSOLICITED) :
-            (RadioIndicationType::UNSOLICITED_ACK_EXP);
-}
-
-int radio_1_5::radioStateChangedInd(int slotId,
-                                 int indicationType, int token, RIL_Errno e, void *response,
-                                 size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        RadioState radioState =
-                (RadioState) CALL_ONSTATEREQUEST(slotId);
-        RLOGD("radioStateChangedInd: radioState %d", radioState);
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->radioStateChanged(
-                convertIntToRadioIndicationType(indicationType), radioState);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("radioStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::callStateChangedInd(int slotId,
-                               int indicationType, int token, RIL_Errno e, void *response,
-                               size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("callStateChangedInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->callStateChanged(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("callStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::networkStateChangedInd(int slotId,
-                                  int indicationType, int token, RIL_Errno e, void *response,
-                                  size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("networkStateChangedInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->networkStateChanged(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("networkStateChangedInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-uint8_t hexCharToInt(uint8_t c) {
-    if (c >= '0' && c <= '9') return (c - '0');
-    if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
-    if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
-
-    return INVALID_HEX_CHAR;
-}
-
-uint8_t * convertHexStringToBytes(void *response, size_t responseLen) {
-    if (responseLen % 2 != 0) {
-        return NULL;
-    }
-
-    uint8_t *bytes = (uint8_t *)calloc(responseLen/2, sizeof(uint8_t));
-    if (bytes == NULL) {
-        RLOGE("convertHexStringToBytes: cannot allocate memory for bytes string");
-        return NULL;
-    }
-    uint8_t *hexString = (uint8_t *)response;
-
-    for (size_t i = 0; i < responseLen; i += 2) {
-        uint8_t hexChar1 = hexCharToInt(hexString[i]);
-        uint8_t hexChar2 = hexCharToInt(hexString[i + 1]);
-
-        if (hexChar1 == INVALID_HEX_CHAR || hexChar2 == INVALID_HEX_CHAR) {
-            RLOGE("convertHexStringToBytes: invalid hex char %d %d",
-                    hexString[i], hexString[i + 1]);
-            free(bytes);
-            return NULL;
-        }
-        bytes[i/2] = ((hexChar1 << 4) | hexChar2);
-    }
-
-    return bytes;
-}
-
-int radio_1_5::newSmsInd(int slotId, int indicationType,
-                     int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("newSmsInd: invalid response");
-            return 0;
-        }
-
-        uint8_t *bytes = convertHexStringToBytes(response, responseLen);
-        if (bytes == NULL) {
-            RLOGE("newSmsInd: convertHexStringToBytes failed");
-            return 0;
-        }
-
-        hidl_vec<uint8_t> pdu;
-        pdu.setToExternal(bytes, responseLen/2);
-#if VDBG
-        RLOGD("newSmsInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->newSms(
-                convertIntToRadioIndicationType(indicationType), pdu);
-        radioService[slotId]->checkReturnStatus(retStatus);
-        free(bytes);
-    } else {
-        RLOGE("newSmsInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::newSmsStatusReportInd(int slotId,
-                                 int indicationType, int token, RIL_Errno e, void *response,
-                                 size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("newSmsStatusReportInd: invalid response");
-            return 0;
-        }
-
-        uint8_t *bytes = convertHexStringToBytes(response, responseLen);
-        if (bytes == NULL) {
-            RLOGE("newSmsStatusReportInd: convertHexStringToBytes failed");
-            return 0;
-        }
-
-        hidl_vec<uint8_t> pdu;
-        pdu.setToExternal(bytes, responseLen/2);
-#if VDBG
-        RLOGD("newSmsStatusReportInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->newSmsStatusReport(
-                convertIntToRadioIndicationType(indicationType), pdu);
-        radioService[slotId]->checkReturnStatus(retStatus);
-        free(bytes);
-    } else {
-        RLOGE("newSmsStatusReportInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::newSmsOnSimInd(int slotId, int indicationType,
-                          int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("newSmsOnSimInd: invalid response");
-            return 0;
-        }
-        int32_t recordNumber = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("newSmsOnSimInd: slotIndex %d", recordNumber);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->newSmsOnSim(
-                convertIntToRadioIndicationType(indicationType), recordNumber);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("newSmsOnSimInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::onUssdInd(int slotId, int indicationType,
-                     int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != 2 * sizeof(char *)) {
-            RLOGE("onUssdInd: invalid response");
-            return 0;
-        }
-        char **strings = (char **) response;
-        char *mode = strings[0];
-        hidl_string msg = convertCharPtrToHidlString(strings[1]);
-        UssdModeType modeType = (UssdModeType) atoi(mode);
-#if VDBG
-        RLOGD("onUssdInd: mode %s", mode);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->onUssd(
-                convertIntToRadioIndicationType(indicationType), modeType, msg);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("onUssdInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::nitzTimeReceivedInd(int slotId,
-                               int indicationType, int token, RIL_Errno e, void *response,
-                               size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("nitzTimeReceivedInd: invalid response");
-            return 0;
-        }
-        hidl_string nitzTime = convertCharPtrToHidlString((char *) response);
-#if VDBG
-        RLOGD("nitzTimeReceivedInd: nitzTime %s receivedTime %" PRId64, nitzTime.c_str(),
-                nitzTimeReceived[slotId]);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->nitzTimeReceived(
-                convertIntToRadioIndicationType(indicationType), nitzTime,
-                nitzTimeReceived[slotId]);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("nitzTimeReceivedInd: radioService[%d]->mRadioIndication == NULL", slotId);
-        return -1;
-    }
-
-    return 0;
-}
-
-void convertRilSignalStrengthToHal(void *response, size_t responseLen,
-        SignalStrength& signalStrength) {
-    RIL_SignalStrength_v10 *rilSignalStrength = (RIL_SignalStrength_v10 *) response;
-
-    // Fixup LTE for backwards compatibility
-    // signalStrength: -1 -> 99
-    if (rilSignalStrength->LTE_SignalStrength.signalStrength == -1) {
-        rilSignalStrength->LTE_SignalStrength.signalStrength = 99;
-    }
-    // rsrp: -1 -> INT_MAX all other negative value to positive.
-    // So remap here
-    if (rilSignalStrength->LTE_SignalStrength.rsrp == -1) {
-        rilSignalStrength->LTE_SignalStrength.rsrp = INT_MAX;
-    } else if (rilSignalStrength->LTE_SignalStrength.rsrp < -1) {
-        rilSignalStrength->LTE_SignalStrength.rsrp = -rilSignalStrength->LTE_SignalStrength.rsrp;
-    }
-    // rsrq: -1 -> INT_MAX
-    if (rilSignalStrength->LTE_SignalStrength.rsrq == -1) {
-        rilSignalStrength->LTE_SignalStrength.rsrq = INT_MAX;
-    }
-    // Not remapping rssnr is already using INT_MAX
-    // cqi: -1 -> INT_MAX
-    if (rilSignalStrength->LTE_SignalStrength.cqi == -1) {
-        rilSignalStrength->LTE_SignalStrength.cqi = INT_MAX;
-    }
-
-    signalStrength.gw.signalStrength = rilSignalStrength->GW_SignalStrength.signalStrength;
-    signalStrength.gw.bitErrorRate = rilSignalStrength->GW_SignalStrength.bitErrorRate;
-    // RIL_SignalStrength_v10 not support gw.timingAdvance. Set to INT_MAX as
-    // invalid value.
-    signalStrength.gw.timingAdvance = INT_MAX;
-
-    signalStrength.cdma.dbm = rilSignalStrength->CDMA_SignalStrength.dbm;
-    signalStrength.cdma.ecio = rilSignalStrength->CDMA_SignalStrength.ecio;
-    signalStrength.evdo.dbm = rilSignalStrength->EVDO_SignalStrength.dbm;
-    signalStrength.evdo.ecio = rilSignalStrength->EVDO_SignalStrength.ecio;
-    signalStrength.evdo.signalNoiseRatio =
-            rilSignalStrength->EVDO_SignalStrength.signalNoiseRatio;
-    signalStrength.lte.signalStrength = rilSignalStrength->LTE_SignalStrength.signalStrength;
-    signalStrength.lte.rsrp = rilSignalStrength->LTE_SignalStrength.rsrp;
-    signalStrength.lte.rsrq = rilSignalStrength->LTE_SignalStrength.rsrq;
-    signalStrength.lte.rssnr = rilSignalStrength->LTE_SignalStrength.rssnr;
-    signalStrength.lte.cqi = rilSignalStrength->LTE_SignalStrength.cqi;
-    signalStrength.lte.timingAdvance = rilSignalStrength->LTE_SignalStrength.timingAdvance;
-    signalStrength.tdScdma.rscp = rilSignalStrength->TD_SCDMA_SignalStrength.rscp;
-}
-
-int radio_1_5::currentSignalStrengthInd(int slotId,
-                                    int indicationType, int token, RIL_Errno e,
-                                    void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_SignalStrength_v10)) {
-            RLOGE("currentSignalStrengthInd: invalid response");
-            return 0;
-        }
-
-        SignalStrength signalStrength = {};
-        convertRilSignalStrengthToHal(response, responseLen, signalStrength);
-
-#if VDBG
-        RLOGD("currentSignalStrengthInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->currentSignalStrength(
-                convertIntToRadioIndicationType(indicationType), signalStrength);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("currentSignalStrengthInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
-        SetupDataCallResult& dcResult) {
-    dcResult.status = (DataCallFailCause) dcResponse->status;
-    dcResult.suggestedRetryTime = dcResponse->suggestedRetryTime;
-    dcResult.cid = dcResponse->cid;
-    dcResult.active = dcResponse->active;
-    dcResult.type = convertCharPtrToHidlString(dcResponse->type);
-    dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
-    dcResult.addresses = convertCharPtrToHidlString(dcResponse->addresses);
-    dcResult.dnses = convertCharPtrToHidlString(dcResponse->dnses);
-    dcResult.gateways = convertCharPtrToHidlString(dcResponse->gateways);
-    dcResult.pcscf = convertCharPtrToHidlString(dcResponse->pcscf);
-    dcResult.mtu = dcResponse->mtu;
-}
-
-hidl_vec<hidl_string> split(hidl_string str) {
-    std::vector<hidl_string> ret;
-    std::stringstream ss(static_cast<std::string>(str));
-
-    std::string tok;
-
-    while(getline(ss, tok, ' ')) {
-        ret.push_back(hidl_string(tok));
-    }
-
-    return ret;
-}
-
-::android::hardware::radio::V1_4::PdpProtocolType convertToPdpProtocolType(hidl_string str) {
-    if (strncmp("IP", str.c_str(), 2) == 0) {
-        return ::android::hardware::radio::V1_4::PdpProtocolType::IP;
-    } else if (strncmp("IPV6", str.c_str(), 4) == 0) {
-        return ::android::hardware::radio::V1_4::PdpProtocolType::IPV6;
-    } else if (strncmp("IPV4V6", str.c_str(), 6) == 0) {
-        return ::android::hardware::radio::V1_4::PdpProtocolType::IPV4V6;
-    } else if (strncmp("PPP", str.c_str(), 3) == 0) {
-        return ::android::hardware::radio::V1_4::PdpProtocolType::PPP;
-    } else if (strncmp("NON_IP", str.c_str(), 6) == 0) {
-        return ::android::hardware::radio::V1_4::PdpProtocolType::NON_IP;
-    } else if (strncmp("UNSTRUCTURED", str.c_str(), 12) == 0) {
-        return ::android::hardware::radio::V1_4::PdpProtocolType::UNSTRUCTURED;
-    } else {
-        return ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
-    }
-}
-
-void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
-        ::android::hardware::radio::V1_4::SetupDataCallResult& dcResult) {
-    dcResult.cause = (::android::hardware::radio::V1_4::DataCallFailCause) dcResponse->status;
-    dcResult.suggestedRetryTime = dcResponse->suggestedRetryTime;
-    dcResult.cid = dcResponse->cid;
-    dcResult.active = (::android::hardware::radio::V1_4::DataConnActiveStatus)dcResponse->active;
-    dcResult.type = convertToPdpProtocolType(convertCharPtrToHidlString(dcResponse->type));
-    dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
-    dcResult.addresses = split(convertCharPtrToHidlString(dcResponse->addresses));
-    dcResult.dnses = split(convertCharPtrToHidlString(dcResponse->dnses));
-    dcResult.gateways = split(convertCharPtrToHidlString(dcResponse->gateways));
-    dcResult.pcscf = split(convertCharPtrToHidlString(dcResponse->pcscf));
-    dcResult.mtu = dcResponse->mtu;
-}
-
-void convertRilDataCallToHal(RIL_Data_Call_Response_v12 *dcResponse,
-        ::android::hardware::radio::V1_5::SetupDataCallResult& dcResult) {
-    dcResult.cause = (::android::hardware::radio::V1_4::DataCallFailCause) dcResponse->status;
-    dcResult.suggestedRetryTime = dcResponse->suggestedRetryTime;
-    dcResult.cid = dcResponse->cid;
-    dcResult.active = (::android::hardware::radio::V1_4::DataConnActiveStatus)dcResponse->active;
-    dcResult.type = convertToPdpProtocolType(convertCharPtrToHidlString(dcResponse->type));
-    dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
-
-    std::vector<::android::hardware::radio::V1_5::LinkAddress> linkAddresses;
-    std::stringstream ss(static_cast<std::string>(dcResponse->addresses));
-    std::string tok;
-    while(getline(ss, tok, ' ')) {
-        ::android::hardware::radio::V1_5::LinkAddress la;
-        la.address = hidl_string(tok);
-        la.properties = 0;
-        la.deprecationTime = 0;
-        la.expirationTime = 0;
-        linkAddresses.push_back(la);
-    }
-
-    dcResult.addresses = linkAddresses;
-    dcResult.dnses = split(convertCharPtrToHidlString(dcResponse->dnses));
-    dcResult.gateways = split(convertCharPtrToHidlString(dcResponse->gateways));
-    dcResult.pcscf = split(convertCharPtrToHidlString(dcResponse->pcscf));
-    dcResult.mtuV4 = dcResponse->mtuV4;
-    dcResult.mtuV6 = dcResponse->mtuV6;
-}
-
-
-void convertRilDataCallListToHal(void *response, size_t responseLen,
-        hidl_vec<SetupDataCallResult>& dcResultList) {
-    int num = responseLen / sizeof(RIL_Data_Call_Response_v11);
-
-    RIL_Data_Call_Response_v11 *dcResponse = (RIL_Data_Call_Response_v11 *) response;
-    dcResultList.resize(num);
-    for (int i = 0; i < num; i++) {
-        convertRilDataCallToHal(&dcResponse[i], dcResultList[i]);
-    }
-}
-
-int radio_1_5::dataCallListChangedInd(int slotId,
-                                  int indicationType, int token, RIL_Errno e, void *response,
-                                  size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_Data_Call_Response_v11) != 0) {
-            RLOGE("dataCallListChangedInd: invalid response");
-            return 0;
-        }
-        hidl_vec<SetupDataCallResult> dcList;
-        convertRilDataCallListToHal(response, responseLen, dcList);
-#if VDBG
-        RLOGD("dataCallListChangedInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->dataCallListChanged(
-                convertIntToRadioIndicationType(indicationType), dcList);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("dataCallListChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::suppSvcNotifyInd(int slotId, int indicationType,
-                            int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_SuppSvcNotification)) {
-            RLOGE("suppSvcNotifyInd: invalid response");
-            return 0;
-        }
-
-        SuppSvcNotification suppSvc = {};
-        RIL_SuppSvcNotification *ssn = (RIL_SuppSvcNotification *) response;
-        suppSvc.isMT = ssn->notificationType;
-        suppSvc.code = ssn->code;
-        suppSvc.index = ssn->index;
-        suppSvc.type = ssn->type;
-        suppSvc.number = convertCharPtrToHidlString(ssn->number);
-
-#if VDBG
-        RLOGD("suppSvcNotifyInd: isMT %d code %d index %d type %d",
-                suppSvc.isMT, suppSvc.code, suppSvc.index, suppSvc.type);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->suppSvcNotify(
-                convertIntToRadioIndicationType(indicationType), suppSvc);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("suppSvcNotifyInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stkSessionEndInd(int slotId, int indicationType,
-                            int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("stkSessionEndInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkSessionEnd(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stkSessionEndInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stkProactiveCommandInd(int slotId,
-                                  int indicationType, int token, RIL_Errno e, void *response,
-                                  size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("stkProactiveCommandInd: invalid response");
-            return 0;
-        }
-#if VDBG
-        RLOGD("stkProactiveCommandInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkProactiveCommand(
-                convertIntToRadioIndicationType(indicationType),
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stkProactiveCommandInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stkEventNotifyInd(int slotId, int indicationType,
-                             int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("stkEventNotifyInd: invalid response");
-            return 0;
-        }
-#if VDBG
-        RLOGD("stkEventNotifyInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkEventNotify(
-                convertIntToRadioIndicationType(indicationType),
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stkEventNotifyInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stkCallSetupInd(int slotId, int indicationType,
-                           int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("stkCallSetupInd: invalid response");
-            return 0;
-        }
-        int32_t timeout = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("stkCallSetupInd: timeout %d", timeout);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkCallSetup(
-                convertIntToRadioIndicationType(indicationType), timeout);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stkCallSetupInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::simSmsStorageFullInd(int slotId,
-                                int indicationType, int token, RIL_Errno e, void *response,
-                                size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("simSmsStorageFullInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->simSmsStorageFull(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("simSmsStorageFullInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::simRefreshInd(int slotId, int indicationType,
-                         int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_SimRefreshResponse_v7)) {
-            RLOGE("simRefreshInd: invalid response");
-            return 0;
-        }
-
-        SimRefreshResult refreshResult = {};
-        RIL_SimRefreshResponse_v7 *simRefreshResponse = ((RIL_SimRefreshResponse_v7 *) response);
-        refreshResult.type =
-                (V1_0::SimRefreshType) simRefreshResponse->result;
-        refreshResult.efId = simRefreshResponse->ef_id;
-        refreshResult.aid = convertCharPtrToHidlString(simRefreshResponse->aid);
-
-#if VDBG
-        RLOGD("simRefreshInd: type %d efId %d", refreshResult.type, refreshResult.efId);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->simRefresh(
-                convertIntToRadioIndicationType(indicationType), refreshResult);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("simRefreshInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-void convertRilCdmaSignalInfoRecordToHal(RIL_CDMA_SignalInfoRecord *signalInfoRecord,
-        CdmaSignalInfoRecord& record) {
-    record.isPresent = signalInfoRecord->isPresent;
-    record.signalType = signalInfoRecord->signalType;
-    record.alertPitch = signalInfoRecord->alertPitch;
-    record.signal = signalInfoRecord->signal;
-}
-
-int radio_1_5::callRingInd(int slotId, int indicationType,
-                       int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        bool isGsm;
-        CdmaSignalInfoRecord record = {};
-        if (response == NULL || responseLen == 0) {
-            isGsm = true;
-        } else {
-            isGsm = false;
-            if (responseLen != sizeof (RIL_CDMA_SignalInfoRecord)) {
-                RLOGE("callRingInd: invalid response");
-                return 0;
-            }
-            convertRilCdmaSignalInfoRecordToHal((RIL_CDMA_SignalInfoRecord *) response, record);
-        }
-
-#if VDBG
-        RLOGD("callRingInd: isGsm %d", isGsm);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->callRing(
-                convertIntToRadioIndicationType(indicationType), isGsm, record);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("callRingInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::simStatusChangedInd(int slotId,
-                               int indicationType, int token, RIL_Errno e, void *response,
-                               size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("simStatusChangedInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->simStatusChanged(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("simStatusChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cdmaNewSmsInd(int slotId, int indicationType,
-                         int token, RIL_Errno e, void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_CDMA_SMS_Message)) {
-            RLOGE("cdmaNewSmsInd: invalid response");
-            return 0;
-        }
-
-        CdmaSmsMessage msg = {};
-        RIL_CDMA_SMS_Message *rilMsg = (RIL_CDMA_SMS_Message *) response;
-        msg.teleserviceId = rilMsg->uTeleserviceID;
-        msg.isServicePresent = rilMsg->bIsServicePresent;
-        msg.serviceCategory = rilMsg->uServicecategory;
-        msg.address.digitMode =
-                (V1_0::CdmaSmsDigitMode) rilMsg->sAddress.digit_mode;
-        msg.address.numberMode =
-                (V1_0::CdmaSmsNumberMode) rilMsg->sAddress.number_mode;
-        msg.address.numberType =
-                (V1_0::CdmaSmsNumberType) rilMsg->sAddress.number_type;
-        msg.address.numberPlan =
-                (V1_0::CdmaSmsNumberPlan) rilMsg->sAddress.number_plan;
-
-        int digitLimit = MIN((rilMsg->sAddress.number_of_digits), RIL_CDMA_SMS_ADDRESS_MAX);
-        msg.address.digits.setToExternal(rilMsg->sAddress.digits, digitLimit);
-
-        msg.subAddress.subaddressType = (V1_0::CdmaSmsSubaddressType)
-                rilMsg->sSubAddress.subaddressType;
-        msg.subAddress.odd = rilMsg->sSubAddress.odd;
-
-        digitLimit= MIN((rilMsg->sSubAddress.number_of_digits), RIL_CDMA_SMS_SUBADDRESS_MAX);
-        msg.subAddress.digits.setToExternal(rilMsg->sSubAddress.digits, digitLimit);
-
-        digitLimit = MIN((rilMsg->uBearerDataLen), RIL_CDMA_SMS_BEARER_DATA_MAX);
-        msg.bearerData.setToExternal(rilMsg->aBearerData, digitLimit);
-
-#if VDBG
-        RLOGD("cdmaNewSmsInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaNewSms(
-                convertIntToRadioIndicationType(indicationType), msg);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cdmaNewSmsInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::newBroadcastSmsInd(int slotId,
-                              int indicationType, int token, RIL_Errno e, void *response,
-                              size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("newBroadcastSmsInd: invalid response");
-            return 0;
-        }
-
-        hidl_vec<uint8_t> data;
-        data.setToExternal((uint8_t *) response, responseLen);
-#if VDBG
-        RLOGD("newBroadcastSmsInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->newBroadcastSms(
-                convertIntToRadioIndicationType(indicationType), data);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("newBroadcastSmsInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cdmaRuimSmsStorageFullInd(int slotId,
-                                     int indicationType, int token, RIL_Errno e, void *response,
-                                     size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("cdmaRuimSmsStorageFullInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaRuimSmsStorageFull(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cdmaRuimSmsStorageFullInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::restrictedStateChangedInd(int slotId,
-                                     int indicationType, int token, RIL_Errno e, void *response,
-                                     size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("restrictedStateChangedInd: invalid response");
-            return 0;
-        }
-        int32_t state = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("restrictedStateChangedInd: state %d", state);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->restrictedStateChanged(
-                convertIntToRadioIndicationType(indicationType), (PhoneRestrictedState) state);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("restrictedStateChangedInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::enterEmergencyCallbackModeInd(int slotId,
-                                         int indicationType, int token, RIL_Errno e, void *response,
-                                         size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("enterEmergencyCallbackModeInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->enterEmergencyCallbackMode(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("enterEmergencyCallbackModeInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cdmaCallWaitingInd(int slotId,
-                              int indicationType, int token, RIL_Errno e, void *response,
-                              size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_CDMA_CallWaiting_v6)) {
-            RLOGE("cdmaCallWaitingInd: invalid response");
-            return 0;
-        }
-
-        CdmaCallWaiting callWaitingRecord = {};
-        RIL_CDMA_CallWaiting_v6 *callWaitingRil = ((RIL_CDMA_CallWaiting_v6 *) response);
-        callWaitingRecord.number = convertCharPtrToHidlString(callWaitingRil->number);
-        callWaitingRecord.numberPresentation =
-                (CdmaCallWaitingNumberPresentation) callWaitingRil->numberPresentation;
-        callWaitingRecord.name = convertCharPtrToHidlString(callWaitingRil->name);
-        convertRilCdmaSignalInfoRecordToHal(&callWaitingRil->signalInfoRecord,
-                callWaitingRecord.signalInfoRecord);
-        callWaitingRecord.numberType = (CdmaCallWaitingNumberType) callWaitingRil->number_type;
-        callWaitingRecord.numberPlan = (CdmaCallWaitingNumberPlan) callWaitingRil->number_plan;
-
-#if VDBG
-        RLOGD("cdmaCallWaitingInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaCallWaiting(
-                convertIntToRadioIndicationType(indicationType), callWaitingRecord);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cdmaCallWaitingInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cdmaOtaProvisionStatusInd(int slotId,
-                                     int indicationType, int token, RIL_Errno e, void *response,
-                                     size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("cdmaOtaProvisionStatusInd: invalid response");
-            return 0;
-        }
-        int32_t status = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("cdmaOtaProvisionStatusInd: status %d", status);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaOtaProvisionStatus(
-                convertIntToRadioIndicationType(indicationType), (CdmaOtaProvisionStatus) status);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cdmaOtaProvisionStatusInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cdmaInfoRecInd(int slotId,
-                          int indicationType, int token, RIL_Errno e, void *response,
-                          size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_CDMA_InformationRecords)) {
-            RLOGE("cdmaInfoRecInd: invalid response");
-            return 0;
-        }
-
-        CdmaInformationRecords records = {};
-        RIL_CDMA_InformationRecords *recordsRil = (RIL_CDMA_InformationRecords *) response;
-
-        char* string8 = NULL;
-        int num = MIN(recordsRil->numberOfInfoRecs, RIL_CDMA_MAX_NUMBER_OF_INFO_RECS);
-        if (recordsRil->numberOfInfoRecs > RIL_CDMA_MAX_NUMBER_OF_INFO_RECS) {
-            RLOGE("cdmaInfoRecInd: received %d recs which is more than %d, dropping "
-                    "additional ones", recordsRil->numberOfInfoRecs,
-                    RIL_CDMA_MAX_NUMBER_OF_INFO_RECS);
-        }
-        records.infoRec.resize(num);
-        for (int i = 0 ; i < num ; i++) {
-            CdmaInformationRecord *record = &records.infoRec[i];
-            RIL_CDMA_InformationRecord *infoRec = &recordsRil->infoRec[i];
-            record->name = (CdmaInfoRecName) infoRec->name;
-            // All vectors should be size 0 except one which will be size 1. Set everything to
-            // size 0 initially.
-            record->display.resize(0);
-            record->number.resize(0);
-            record->signal.resize(0);
-            record->redir.resize(0);
-            record->lineCtrl.resize(0);
-            record->clir.resize(0);
-            record->audioCtrl.resize(0);
-            switch (infoRec->name) {
-                case RIL_CDMA_DISPLAY_INFO_REC:
-                case RIL_CDMA_EXTENDED_DISPLAY_INFO_REC: {
-                    if (infoRec->rec.display.alpha_len > CDMA_ALPHA_INFO_BUFFER_LENGTH) {
-                        RLOGE("cdmaInfoRecInd: invalid display info response length %d "
-                                "expected not more than %d", (int) infoRec->rec.display.alpha_len,
-                                CDMA_ALPHA_INFO_BUFFER_LENGTH);
-                        return 0;
-                    }
-                    string8 = (char*) malloc((infoRec->rec.display.alpha_len + 1) * sizeof(char));
-                    if (string8 == NULL) {
-                        RLOGE("cdmaInfoRecInd: Memory allocation failed for "
-                                "responseCdmaInformationRecords");
-                        return 0;
-                    }
-                    memcpy(string8, infoRec->rec.display.alpha_buf, infoRec->rec.display.alpha_len);
-                    string8[(int)infoRec->rec.display.alpha_len] = '\0';
-
-                    record->display.resize(1);
-                    record->display[0].alphaBuf = string8;
-                    free(string8);
-                    string8 = NULL;
-                    break;
-                }
-
-                case RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC:
-                case RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC:
-                case RIL_CDMA_CONNECTED_NUMBER_INFO_REC: {
-                    if (infoRec->rec.number.len > CDMA_NUMBER_INFO_BUFFER_LENGTH) {
-                        RLOGE("cdmaInfoRecInd: invalid display info response length %d "
-                                "expected not more than %d", (int) infoRec->rec.number.len,
-                                CDMA_NUMBER_INFO_BUFFER_LENGTH);
-                        return 0;
-                    }
-                    string8 = (char*) malloc((infoRec->rec.number.len + 1) * sizeof(char));
-                    if (string8 == NULL) {
-                        RLOGE("cdmaInfoRecInd: Memory allocation failed for "
-                                "responseCdmaInformationRecords");
-                        return 0;
-                    }
-                    memcpy(string8, infoRec->rec.number.buf, infoRec->rec.number.len);
-                    string8[(int)infoRec->rec.number.len] = '\0';
-
-                    record->number.resize(1);
-                    record->number[0].number = string8;
-                    free(string8);
-                    string8 = NULL;
-                    record->number[0].numberType = infoRec->rec.number.number_type;
-                    record->number[0].numberPlan = infoRec->rec.number.number_plan;
-                    record->number[0].pi = infoRec->rec.number.pi;
-                    record->number[0].si = infoRec->rec.number.si;
-                    break;
-                }
-
-                case RIL_CDMA_SIGNAL_INFO_REC: {
-                    record->signal.resize(1);
-                    record->signal[0].isPresent = infoRec->rec.signal.isPresent;
-                    record->signal[0].signalType = infoRec->rec.signal.signalType;
-                    record->signal[0].alertPitch = infoRec->rec.signal.alertPitch;
-                    record->signal[0].signal = infoRec->rec.signal.signal;
-                    break;
-                }
-
-                case RIL_CDMA_REDIRECTING_NUMBER_INFO_REC: {
-                    if (infoRec->rec.redir.redirectingNumber.len >
-                                                  CDMA_NUMBER_INFO_BUFFER_LENGTH) {
-                        RLOGE("cdmaInfoRecInd: invalid display info response length %d "
-                                "expected not more than %d\n",
-                                (int)infoRec->rec.redir.redirectingNumber.len,
-                                CDMA_NUMBER_INFO_BUFFER_LENGTH);
-                        return 0;
-                    }
-                    string8 = (char*) malloc((infoRec->rec.redir.redirectingNumber.len + 1) *
-                            sizeof(char));
-                    if (string8 == NULL) {
-                        RLOGE("cdmaInfoRecInd: Memory allocation failed for "
-                                "responseCdmaInformationRecords");
-                        return 0;
-                    }
-                    memcpy(string8, infoRec->rec.redir.redirectingNumber.buf,
-                            infoRec->rec.redir.redirectingNumber.len);
-                    string8[(int)infoRec->rec.redir.redirectingNumber.len] = '\0';
-
-                    record->redir.resize(1);
-                    record->redir[0].redirectingNumber.number = string8;
-                    free(string8);
-                    string8 = NULL;
-                    record->redir[0].redirectingNumber.numberType =
-                            infoRec->rec.redir.redirectingNumber.number_type;
-                    record->redir[0].redirectingNumber.numberPlan =
-                            infoRec->rec.redir.redirectingNumber.number_plan;
-                    record->redir[0].redirectingNumber.pi = infoRec->rec.redir.redirectingNumber.pi;
-                    record->redir[0].redirectingNumber.si = infoRec->rec.redir.redirectingNumber.si;
-                    record->redir[0].redirectingReason =
-                            (CdmaRedirectingReason) infoRec->rec.redir.redirectingReason;
-                    break;
-                }
-
-                case RIL_CDMA_LINE_CONTROL_INFO_REC: {
-                    record->lineCtrl.resize(1);
-                    record->lineCtrl[0].lineCtrlPolarityIncluded =
-                            infoRec->rec.lineCtrl.lineCtrlPolarityIncluded;
-                    record->lineCtrl[0].lineCtrlToggle = infoRec->rec.lineCtrl.lineCtrlToggle;
-                    record->lineCtrl[0].lineCtrlReverse = infoRec->rec.lineCtrl.lineCtrlReverse;
-                    record->lineCtrl[0].lineCtrlPowerDenial =
-                            infoRec->rec.lineCtrl.lineCtrlPowerDenial;
-                    break;
-                }
-
-                case RIL_CDMA_T53_CLIR_INFO_REC: {
-                    record->clir.resize(1);
-                    record->clir[0].cause = infoRec->rec.clir.cause;
-                    break;
-                }
-
-                case RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC: {
-                    record->audioCtrl.resize(1);
-                    record->audioCtrl[0].upLink = infoRec->rec.audioCtrl.upLink;
-                    record->audioCtrl[0].downLink = infoRec->rec.audioCtrl.downLink;
-                    break;
-                }
-
-                case RIL_CDMA_T53_RELEASE_INFO_REC:
-                    RLOGE("cdmaInfoRecInd: RIL_CDMA_T53_RELEASE_INFO_REC: INVALID");
-                    return 0;
-
-                default:
-                    RLOGE("cdmaInfoRecInd: Incorrect name value");
-                    return 0;
-            }
-        }
-
-#if VDBG
-        RLOGD("cdmaInfoRecInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaInfoRec(
-                convertIntToRadioIndicationType(indicationType), records);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cdmaInfoRecInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::indicateRingbackToneInd(int slotId,
-                                   int indicationType, int token, RIL_Errno e, void *response,
-                                   size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("indicateRingbackToneInd: invalid response");
-            return 0;
-        }
-        bool start = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("indicateRingbackToneInd: start %d", start);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->indicateRingbackTone(
-                convertIntToRadioIndicationType(indicationType), start);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("indicateRingbackToneInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::resendIncallMuteInd(int slotId,
-                               int indicationType, int token, RIL_Errno e, void *response,
-                               size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("resendIncallMuteInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->resendIncallMute(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("resendIncallMuteInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cdmaSubscriptionSourceChangedInd(int slotId,
-                                            int indicationType, int token, RIL_Errno e,
-                                            void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("cdmaSubscriptionSourceChangedInd: invalid response");
-            return 0;
-        }
-        int32_t cdmaSource = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("cdmaSubscriptionSourceChangedInd: cdmaSource %d", cdmaSource);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->
-                cdmaSubscriptionSourceChanged(convertIntToRadioIndicationType(indicationType),
-                (CdmaSubscriptionSource) cdmaSource);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cdmaSubscriptionSourceChangedInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::cdmaPrlChangedInd(int slotId,
-                             int indicationType, int token, RIL_Errno e, void *response,
-                             size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("cdmaPrlChangedInd: invalid response");
-            return 0;
-        }
-        int32_t version = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("cdmaPrlChangedInd: version %d", version);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaPrlChanged(
-                convertIntToRadioIndicationType(indicationType), version);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cdmaPrlChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::exitEmergencyCallbackModeInd(int slotId,
-                                        int indicationType, int token, RIL_Errno e, void *response,
-                                        size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("exitEmergencyCallbackModeInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->exitEmergencyCallbackMode(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("exitEmergencyCallbackModeInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::rilConnectedInd(int slotId,
-                           int indicationType, int token, RIL_Errno e, void *response,
-                           size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        RLOGD("rilConnectedInd");
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->rilConnected(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("rilConnectedInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::voiceRadioTechChangedInd(int slotId,
-                                    int indicationType, int token, RIL_Errno e, void *response,
-                                    size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("voiceRadioTechChangedInd: invalid response");
-            return 0;
-        }
-        int32_t rat = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("voiceRadioTechChangedInd: rat %d", rat);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->voiceRadioTechChanged(
-                convertIntToRadioIndicationType(indicationType), (RadioTechnology) rat);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("voiceRadioTechChangedInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-void convertRilCellInfoListToHal(void *response, size_t responseLen, hidl_vec<CellInfo>& records) {
-    int num = responseLen / sizeof(RIL_CellInfo_v12);
-    records.resize(num);
-
-    RIL_CellInfo_v12 *rillCellInfo = (RIL_CellInfo_v12 *) response;
-    for (int i = 0; i < num; i++) {
-        records[i].cellInfoType = (CellInfoType) rillCellInfo->cellInfoType;
-        records[i].registered = rillCellInfo->registered;
-        records[i].timeStampType = (TimeStampType) rillCellInfo->timeStampType;
-        records[i].timeStamp = rillCellInfo->timeStamp;
-        // All vectors should be size 0 except one which will be size 1. Set everything to
-        // size 0 initially.
-        records[i].gsm.resize(0);
-        records[i].wcdma.resize(0);
-        records[i].cdma.resize(0);
-        records[i].lte.resize(0);
-        records[i].tdscdma.resize(0);
-        switch(rillCellInfo->cellInfoType) {
-            case RIL_CELL_INFO_TYPE_GSM: {
-                records[i].gsm.resize(1);
-                CellInfoGsm *cellInfoGsm = &records[i].gsm[0];
-                cellInfoGsm->cellIdentityGsm.mcc =
-                        std::to_string(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mcc);
-                cellInfoGsm->cellIdentityGsm.mnc =
-                        ril::util::mnc::decode(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mnc);
-                cellInfoGsm->cellIdentityGsm.lac =
-                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.lac;
-                cellInfoGsm->cellIdentityGsm.cid =
-                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.cid;
-                cellInfoGsm->cellIdentityGsm.arfcn =
-                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.arfcn;
-                cellInfoGsm->cellIdentityGsm.bsic =
-                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.bsic;
-                cellInfoGsm->signalStrengthGsm.signalStrength =
-                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.signalStrength;
-                cellInfoGsm->signalStrengthGsm.bitErrorRate =
-                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.bitErrorRate;
-                cellInfoGsm->signalStrengthGsm.timingAdvance =
-                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.timingAdvance;
-                break;
-            }
-
-            case RIL_CELL_INFO_TYPE_WCDMA: {
-                records[i].wcdma.resize(1);
-                CellInfoWcdma *cellInfoWcdma = &records[i].wcdma[0];
-                cellInfoWcdma->cellIdentityWcdma.mcc =
-                        std::to_string(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mcc);
-                cellInfoWcdma->cellIdentityWcdma.mnc =
-                        ril::util::mnc::decode(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mnc);
-                cellInfoWcdma->cellIdentityWcdma.lac =
-                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.lac;
-                cellInfoWcdma->cellIdentityWcdma.cid =
-                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.cid;
-                cellInfoWcdma->cellIdentityWcdma.psc =
-                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.psc;
-                cellInfoWcdma->cellIdentityWcdma.uarfcn =
-                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.uarfcn;
-                cellInfoWcdma->signalStrengthWcdma.signalStrength =
-                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.signalStrength;
-                cellInfoWcdma->signalStrengthWcdma.bitErrorRate =
-                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.bitErrorRate;
-                break;
-            }
-
-            case RIL_CELL_INFO_TYPE_CDMA: {
-                records[i].cdma.resize(1);
-                CellInfoCdma *cellInfoCdma = &records[i].cdma[0];
-                cellInfoCdma->cellIdentityCdma.networkId =
-                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.networkId;
-                cellInfoCdma->cellIdentityCdma.systemId =
-                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.systemId;
-                cellInfoCdma->cellIdentityCdma.baseStationId =
-                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.basestationId;
-                cellInfoCdma->cellIdentityCdma.longitude =
-                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.longitude;
-                cellInfoCdma->cellIdentityCdma.latitude =
-                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.latitude;
-                cellInfoCdma->signalStrengthCdma.dbm =
-                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.dbm;
-                cellInfoCdma->signalStrengthCdma.ecio =
-                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.ecio;
-                cellInfoCdma->signalStrengthEvdo.dbm =
-                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.dbm;
-                cellInfoCdma->signalStrengthEvdo.ecio =
-                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.ecio;
-                cellInfoCdma->signalStrengthEvdo.signalNoiseRatio =
-                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.signalNoiseRatio;
-                break;
-            }
-
-            case RIL_CELL_INFO_TYPE_LTE: {
-                records[i].lte.resize(1);
-                CellInfoLte *cellInfoLte = &records[i].lte[0];
-                cellInfoLte->cellIdentityLte.mcc =
-                        std::to_string(rillCellInfo->CellInfo.lte.cellIdentityLte.mcc);
-                cellInfoLte->cellIdentityLte.mnc =
-                        ril::util::mnc::decode(rillCellInfo->CellInfo.lte.cellIdentityLte.mnc);
-                cellInfoLte->cellIdentityLte.ci =
-                        rillCellInfo->CellInfo.lte.cellIdentityLte.ci;
-                cellInfoLte->cellIdentityLte.pci =
-                        rillCellInfo->CellInfo.lte.cellIdentityLte.pci;
-                cellInfoLte->cellIdentityLte.tac =
-                        rillCellInfo->CellInfo.lte.cellIdentityLte.tac;
-                cellInfoLte->cellIdentityLte.earfcn =
-                        rillCellInfo->CellInfo.lte.cellIdentityLte.earfcn;
-                cellInfoLte->signalStrengthLte.signalStrength =
-                        rillCellInfo->CellInfo.lte.signalStrengthLte.signalStrength;
-                cellInfoLte->signalStrengthLte.rsrp =
-                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrp;
-                cellInfoLte->signalStrengthLte.rsrq =
-                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrq;
-                cellInfoLte->signalStrengthLte.rssnr =
-                        rillCellInfo->CellInfo.lte.signalStrengthLte.rssnr;
-                cellInfoLte->signalStrengthLte.cqi =
-                        rillCellInfo->CellInfo.lte.signalStrengthLte.cqi;
-                cellInfoLte->signalStrengthLte.timingAdvance =
-                        rillCellInfo->CellInfo.lte.signalStrengthLte.timingAdvance;
-                break;
-            }
-
-            case RIL_CELL_INFO_TYPE_TD_SCDMA: {
-                records[i].tdscdma.resize(1);
-                CellInfoTdscdma *cellInfoTdscdma = &records[i].tdscdma[0];
-                cellInfoTdscdma->cellIdentityTdscdma.mcc =
-                        std::to_string(rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mcc);
-                cellInfoTdscdma->cellIdentityTdscdma.mnc =
-                        ril::util::mnc::decode(
-                                rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mnc);
-                cellInfoTdscdma->cellIdentityTdscdma.lac =
-                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.lac;
-                cellInfoTdscdma->cellIdentityTdscdma.cid =
-                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cid;
-                cellInfoTdscdma->cellIdentityTdscdma.cpid =
-                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cpid;
-                cellInfoTdscdma->signalStrengthTdscdma.rscp =
-                        rillCellInfo->CellInfo.tdscdma.signalStrengthTdscdma.rscp;
-                break;
-            }
-            default: {
-                break;
-            }
-        }
-        rillCellInfo += 1;
-    }
-}
-
-int radio_1_5::cellInfoListInd(int slotId,
-                           int indicationType, int token, RIL_Errno e, void *response,
-                           size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if ((response == NULL && responseLen != 0) || responseLen % sizeof(RIL_CellInfo_v12) != 0) {
-            RLOGE("cellInfoListInd: invalid response");
-            return 0;
-        }
-
-        hidl_vec<CellInfo> records;
-        convertRilCellInfoListToHal(response, responseLen, records);
-
-#if VDBG
-        RLOGD("cellInfoListInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->cellInfoList(
-                convertIntToRadioIndicationType(indicationType), records);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("cellInfoListInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::imsNetworkStateChangedInd(int slotId,
-                                     int indicationType, int token, RIL_Errno e, void *response,
-                                     size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-#if VDBG
-        RLOGD("imsNetworkStateChangedInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->imsNetworkStateChanged(
-                convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("imsNetworkStateChangedInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::subscriptionStatusChangedInd(int slotId,
-                                        int indicationType, int token, RIL_Errno e, void *response,
-                                        size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("subscriptionStatusChangedInd: invalid response");
-            return 0;
-        }
-        bool activate = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("subscriptionStatusChangedInd: activate %d", activate);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->subscriptionStatusChanged(
-                convertIntToRadioIndicationType(indicationType), activate);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("subscriptionStatusChangedInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::srvccStateNotifyInd(int slotId,
-                               int indicationType, int token, RIL_Errno e, void *response,
-                               size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(int)) {
-            RLOGE("srvccStateNotifyInd: invalid response");
-            return 0;
-        }
-        int32_t state = ((int32_t *) response)[0];
-#if VDBG
-        RLOGD("srvccStateNotifyInd: rat %d", state);
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->srvccStateNotify(
-                convertIntToRadioIndicationType(indicationType), (SrvccState) state);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("srvccStateNotifyInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-void convertRilHardwareConfigListToHal(void *response, size_t responseLen,
-        hidl_vec<HardwareConfig>& records) {
-    int num = responseLen / sizeof(RIL_HardwareConfig);
-    records.resize(num);
-
-    RIL_HardwareConfig *rilHardwareConfig = (RIL_HardwareConfig *) response;
-    for (int i = 0; i < num; i++) {
-        records[i].type = (HardwareConfigType) rilHardwareConfig[i].type;
-        records[i].uuid = convertCharPtrToHidlString(rilHardwareConfig[i].uuid);
-        records[i].state = (HardwareConfigState) rilHardwareConfig[i].state;
-        switch (rilHardwareConfig[i].type) {
-            case RIL_HARDWARE_CONFIG_MODEM: {
-                records[i].modem.resize(1);
-                records[i].sim.resize(0);
-                HardwareConfigModem *hwConfigModem = &records[i].modem[0];
-                hwConfigModem->rat = rilHardwareConfig[i].cfg.modem.rat;
-                hwConfigModem->maxVoice = rilHardwareConfig[i].cfg.modem.maxVoice;
-                hwConfigModem->maxData = rilHardwareConfig[i].cfg.modem.maxData;
-                hwConfigModem->maxStandby = rilHardwareConfig[i].cfg.modem.maxStandby;
-                break;
-            }
-
-            case RIL_HARDWARE_CONFIG_SIM: {
-                records[i].sim.resize(1);
-                records[i].modem.resize(0);
-                records[i].sim[0].modemUuid =
-                        convertCharPtrToHidlString(rilHardwareConfig[i].cfg.sim.modemUuid);
-                break;
-            }
-        }
-    }
-}
-
-int radio_1_5::hardwareConfigChangedInd(int slotId,
-                                    int indicationType, int token, RIL_Errno e, void *response,
-                                    size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if ((response == NULL && responseLen != 0)
-                || responseLen % sizeof(RIL_HardwareConfig) != 0) {
-            RLOGE("hardwareConfigChangedInd: invalid response");
-            return 0;
-        }
-
-        hidl_vec<HardwareConfig> configs;
-        convertRilHardwareConfigListToHal(response, responseLen, configs);
-
-#if VDBG
-        RLOGD("hardwareConfigChangedInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->hardwareConfigChanged(
-                convertIntToRadioIndicationType(indicationType), configs);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("hardwareConfigChangedInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-void convertRilRadioCapabilityToHal(void *response, size_t responseLen, RadioCapability& rc) {
-    RIL_RadioCapability *rilRadioCapability = (RIL_RadioCapability *) response;
-    rc.session = rilRadioCapability->session;
-    rc.phase = (V1_0::RadioCapabilityPhase) rilRadioCapability->phase;
-    rc.raf = rilRadioCapability->rat;
-    rc.logicalModemUuid = convertCharPtrToHidlString(rilRadioCapability->logicalModemUuid);
-    rc.status = (V1_0::RadioCapabilityStatus) rilRadioCapability->status;
-}
-
-int radio_1_5::radioCapabilityIndicationInd(int slotId,
-                                        int indicationType, int token, RIL_Errno e, void *response,
-                                        size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_RadioCapability)) {
-            RLOGE("radioCapabilityIndicationInd: invalid response");
-            return 0;
-        }
-
-        RadioCapability rc = {};
-        convertRilRadioCapabilityToHal(response, responseLen, rc);
-
-#if VDBG
-        RLOGD("radioCapabilityIndicationInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->radioCapabilityIndication(
-                convertIntToRadioIndicationType(indicationType), rc);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("radioCapabilityIndicationInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-bool isServiceTypeCfQuery(RIL_SsServiceType serType, RIL_SsRequestType reqType) {
-    if ((reqType == SS_INTERROGATION) &&
-        (serType == SS_CFU ||
-         serType == SS_CF_BUSY ||
-         serType == SS_CF_NO_REPLY ||
-         serType == SS_CF_NOT_REACHABLE ||
-         serType == SS_CF_ALL ||
-         serType == SS_CF_ALL_CONDITIONAL)) {
-        return true;
-    }
-    return false;
-}
-
-int radio_1_5::onSupplementaryServiceIndicationInd(int slotId,
-                                               int indicationType, int token, RIL_Errno e,
-                                               void *response, size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_StkCcUnsolSsResponse)) {
-            RLOGE("onSupplementaryServiceIndicationInd: invalid response");
-            return 0;
-        }
-
-        RIL_StkCcUnsolSsResponse *rilSsResponse = (RIL_StkCcUnsolSsResponse *) response;
-        StkCcUnsolSsResult ss = {};
-        ss.serviceType = (SsServiceType) rilSsResponse->serviceType;
-        ss.requestType = (SsRequestType) rilSsResponse->requestType;
-        ss.teleserviceType = (SsTeleserviceType) rilSsResponse->teleserviceType;
-        ss.serviceClass = rilSsResponse->serviceClass;
-        ss.result = (RadioError) rilSsResponse->result;
-
-        if (isServiceTypeCfQuery(rilSsResponse->serviceType, rilSsResponse->requestType)) {
-#if VDBG
-            RLOGD("onSupplementaryServiceIndicationInd CF type, num of Cf elements %d",
-                    rilSsResponse->cfData.numValidIndexes);
-#endif
-            if (rilSsResponse->cfData.numValidIndexes > NUM_SERVICE_CLASSES) {
-                RLOGE("onSupplementaryServiceIndicationInd numValidIndexes is greater than "
-                        "max value %d, truncating it to max value", NUM_SERVICE_CLASSES);
-                rilSsResponse->cfData.numValidIndexes = NUM_SERVICE_CLASSES;
-            }
-
-            ss.cfData.resize(1);
-            ss.ssInfo.resize(0);
-
-            /* number of call info's */
-            ss.cfData[0].cfInfo.resize(rilSsResponse->cfData.numValidIndexes);
-
-            for (int i = 0; i < rilSsResponse->cfData.numValidIndexes; i++) {
-                 RIL_CallForwardInfo cf = rilSsResponse->cfData.cfInfo[i];
-                 CallForwardInfo *cfInfo = &ss.cfData[0].cfInfo[i];
-
-                 cfInfo->status = (CallForwardInfoStatus) cf.status;
-                 cfInfo->reason = cf.reason;
-                 cfInfo->serviceClass = cf.serviceClass;
-                 cfInfo->toa = cf.toa;
-                 cfInfo->number = convertCharPtrToHidlString(cf.number);
-                 cfInfo->timeSeconds = cf.timeSeconds;
-#if VDBG
-                 RLOGD("onSupplementaryServiceIndicationInd: "
-                        "Data: %d,reason=%d,cls=%d,toa=%d,num=%s,tout=%d],", cf.status,
-                        cf.reason, cf.serviceClass, cf.toa, (char*)cf.number, cf.timeSeconds);
-#endif
-            }
-        } else {
-            ss.ssInfo.resize(1);
-            ss.cfData.resize(0);
-
-            /* each int */
-            ss.ssInfo[0].ssInfo.resize(SS_INFO_MAX);
-            for (int i = 0; i < SS_INFO_MAX; i++) {
-#if VDBG
-                 RLOGD("onSupplementaryServiceIndicationInd: Data: %d",
-                        rilSsResponse->ssInfo[i]);
-#endif
-                 ss.ssInfo[0].ssInfo[i] = rilSsResponse->ssInfo[i];
-            }
-        }
-
-#if VDBG
-        RLOGD("onSupplementaryServiceIndicationInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->
-                onSupplementaryServiceIndication(convertIntToRadioIndicationType(indicationType),
-                ss);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("onSupplementaryServiceIndicationInd: "
-                "radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::stkCallControlAlphaNotifyInd(int slotId,
-                                        int indicationType, int token, RIL_Errno e, void *response,
-                                        size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("stkCallControlAlphaNotifyInd: invalid response");
-            return 0;
-        }
-#if VDBG
-        RLOGD("stkCallControlAlphaNotifyInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkCallControlAlphaNotify(
-                convertIntToRadioIndicationType(indicationType),
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("stkCallControlAlphaNotifyInd: radioService[%d]->mRadioIndication == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-void convertRilLceDataInfoToHal(void *response, size_t responseLen, LceDataInfo& lce) {
-    RIL_LceDataInfo *rilLceDataInfo = (RIL_LceDataInfo *)response;
-    lce.lastHopCapacityKbps = rilLceDataInfo->last_hop_capacity_kbps;
-    lce.confidenceLevel = rilLceDataInfo->confidence_level;
-    lce.lceSuspended = rilLceDataInfo->lce_suspended;
-}
-
-int radio_1_5::lceDataInd(int slotId,
-                      int indicationType, int token, RIL_Errno e, void *response,
-                      size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_LceDataInfo)) {
-            RLOGE("lceDataInd: invalid response");
-            return 0;
-        }
-
-        LceDataInfo lce = {};
-        convertRilLceDataInfoToHal(response, responseLen, lce);
-#if VDBG
-        RLOGD("lceDataInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->lceData(
-                convertIntToRadioIndicationType(indicationType), lce);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("lceDataInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::pcoDataInd(int slotId,
-                      int indicationType, int token, RIL_Errno e, void *response,
-                      size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen != sizeof(RIL_PCO_Data)) {
-            RLOGE("pcoDataInd: invalid response");
-            return 0;
-        }
-
-        PcoDataInfo pco = {};
-        RIL_PCO_Data *rilPcoData = (RIL_PCO_Data *)response;
-        pco.cid = rilPcoData->cid;
-        pco.bearerProto = convertCharPtrToHidlString(rilPcoData->bearer_proto);
-        pco.pcoId = rilPcoData->pco_id;
-        pco.contents.setToExternal((uint8_t *) rilPcoData->contents, rilPcoData->contents_length);
-
-#if VDBG
-        RLOGD("pcoDataInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->pcoData(
-                convertIntToRadioIndicationType(indicationType), pco);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("pcoDataInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::modemResetInd(int slotId,
-                         int indicationType, int token, RIL_Errno e, void *response,
-                         size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("modemResetInd: invalid response");
-            return 0;
-        }
-#if VDBG
-        RLOGD("modemResetInd");
-#endif
-        Return<void> retStatus = radioService[slotId]->mRadioIndication->modemReset(
-                convertIntToRadioIndicationType(indicationType),
-                convertCharPtrToHidlString((char *) response));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("modemResetInd: radioService[%d]->mRadioIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::networkScanResultInd(int slotId,
-                                int indicationType, int token, RIL_Errno e, void *response,
-                                size_t responseLen) {
-#if VDBG
-    RLOGD("networkScanResultInd");
-#endif
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndicationV1_4 != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("networkScanResultInd: invalid response");
-            return 0;
-        }
-        RLOGD("networkScanResultInd");
-
-#if VDBG
-        RLOGD("networkScanResultInd");
-#endif
-
-        RIL_NetworkScanResult *networkScanResult = (RIL_NetworkScanResult *) response;
-
-        V1_1::NetworkScanResult result;
-        result.status = (V1_1::ScanStatus) networkScanResult->status;
-        result.error = (RadioError) networkScanResult->error;
-        convertRilCellInfoListToHal(
-                networkScanResult->network_infos,
-                networkScanResult->network_infos_length * sizeof(RIL_CellInfo_v12),
-                result.networkInfos);
-
-        Return<void> retStatus = radioService[slotId]->mRadioIndicationV1_4->networkScanResult(
-                convertIntToRadioIndicationType(indicationType), result);
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("networkScanResultInd: radioService[%d]->mRadioIndicationV1_4 == NULL", slotId);
-    }
-    return 0;
-}
-
-int radio_1_5::carrierInfoForImsiEncryption(int slotId,
-                                  int indicationType, int token, RIL_Errno e, void *response,
-                                  size_t responseLen) {
-    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndicationV1_4 != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("carrierInfoForImsiEncryption: invalid response");
-            return 0;
-        }
-        RLOGD("carrierInfoForImsiEncryption");
-        Return<void> retStatus = radioService[slotId]->mRadioIndicationV1_4->
-                carrierInfoForImsiEncryption(convertIntToRadioIndicationType(indicationType));
-        radioService[slotId]->checkReturnStatus(retStatus);
-    } else {
-        RLOGE("carrierInfoForImsiEncryption: radioService[%d]->mRadioIndicationV1_4 == NULL",
-                slotId);
-    }
-
-    return 0;
-}
-
-int radio_1_5::keepaliveStatusInd(int slotId,
-                         int indicationType, int token, RIL_Errno e, void *response,
-                         size_t responseLen) {
-#if VDBG
-    RLOGD("%s(): token=%d", __FUNCTION__, token);
-#endif
-    if (radioService[slotId] == NULL || radioService[slotId]->mRadioIndication == NULL) {
-        RLOGE("%s: radioService[%d]->mRadioIndication == NULL", __FUNCTION__, slotId);
-        return 0;
-    }
-
-    auto ret = V1_1::IRadioIndication::castFrom(
-        radioService[slotId]->mRadioIndication);
-    if (!ret.isOk()) {
-        RLOGE("%s: ret.isOk() == false for radioService[%d]", __FUNCTION__, slotId);
-        return 0;
-    }
-    sp<V1_1::IRadioIndication> radioIndicationV1_1 = ret;
-
-    if (response == NULL || responseLen != sizeof(V1_1::KeepaliveStatus)) {
-        RLOGE("%s: invalid response", __FUNCTION__);
-        return 0;
-    }
-
-    V1_1::KeepaliveStatus ks;
-    convertRilKeepaliveStatusToHal(static_cast<RIL_KeepaliveStatus*>(response), ks);
-
-    Return<void> retStatus = radioIndicationV1_1->keepaliveStatus(
-            convertIntToRadioIndicationType(indicationType), ks);
-    radioService[slotId]->checkReturnStatus(retStatus);
-    return 0;
-}
-
-int radio_1_5::oemHookRawInd(int slotId,
-                         int indicationType, int token, RIL_Errno e, void *response,
-                         size_t responseLen) {
-    if (!kOemHookEnabled) return 0;
-
-    if (oemHookService[slotId] != NULL && oemHookService[slotId]->mOemHookIndication != NULL) {
-        if (response == NULL || responseLen == 0) {
-            RLOGE("oemHookRawInd: invalid response");
-            return 0;
-        }
-
-        hidl_vec<uint8_t> data;
-        data.setToExternal((uint8_t *) response, responseLen);
-#if VDBG
-        RLOGD("oemHookRawInd");
-#endif
-        Return<void> retStatus = oemHookService[slotId]->mOemHookIndication->oemHookRaw(
-                convertIntToRadioIndicationType(indicationType), data);
-        checkReturnStatus(slotId, retStatus, false);
-    } else {
-        RLOGE("oemHookRawInd: oemHookService[%d]->mOemHookIndication == NULL", slotId);
-    }
-
-    return 0;
-}
-
-void radio_1_5::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {
-    using namespace android::hardware;
-    int simCount = 1;
-    const char *serviceNames[] = {
-            android::RIL_getServiceName()
-            #if (SIM_COUNT >= 2)
-            , RIL2_SERVICE_NAME
-            #if (SIM_COUNT >= 3)
-            , RIL3_SERVICE_NAME
-            #if (SIM_COUNT >= 4)
-            , RIL4_SERVICE_NAME
-            #endif
-            #endif
-            #endif
-            };
-
-    #if (SIM_COUNT >= 2)
-    simCount = SIM_COUNT;
-    #endif
-
-    s_vendorFunctions = callbacks;
-    s_commands = commands;
-
-    configureRpcThreadpool(1, true /* callerWillJoin */);
-    for (int i = 0; i < simCount; i++) {
-        pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(i);
-        int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
-        assert(ret == 0);
-
-        RLOGD("sim i = %d registering ...", i);
-
-        radioService[i] = new RadioImpl_1_5;
-        radioService[i]->mSlotId = i;
-        RLOGD("registerService: starting android::hardware::radio::V1_5::IRadio %s for slot %d",
-                serviceNames[i], i);
-        android::status_t status = radioService[i]->registerAsService(serviceNames[i]);
-        LOG_ALWAYS_FATAL_IF(status != android::OK, "status %d", status);
-
-        RLOGD("registerService: OemHook is enabled = %s", kOemHookEnabled ? "true" : "false");
-        if (kOemHookEnabled) {
-            oemHookService[i] = new OemHookImpl;
-            oemHookService[i]->mSlotId = i;
-            // status = oemHookService[i]->registerAsService(serviceNames[i]);
-        }
-
-        ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
-        assert(ret == 0);
-    }
-}
-
-void rilc_thread_pool() {
-    joinRpcThreadpool();
-}
-
-pthread_rwlock_t * radio_1_5::getRadioServiceRwlock(int slotId) {
-    pthread_rwlock_t *radioServiceRwlockPtr = &radioServiceRwlock;
-
-    #if (SIM_COUNT >= 2)
-    if (slotId == 2) radioServiceRwlockPtr = &radioServiceRwlock2;
-    #if (SIM_COUNT >= 3)
-    if (slotId == 3) radioServiceRwlockPtr = &radioServiceRwlock3;
-    #if (SIM_COUNT >= 4)
-    if (slotId == 4) radioServiceRwlockPtr = &radioServiceRwlock4;
-    #endif
-    #endif
-    #endif
-
-    return radioServiceRwlockPtr;
-}
-
-// should acquire write lock for the corresponding service before calling this
-void radio_1_5::setNitzTimeReceived(int slotId, long timeReceived) {
-    nitzTimeReceived[slotId] = timeReceived;
-}
diff --git a/guest/hals/ril/libril/ril_service.h b/guest/hals/ril/libril/ril_service.h
deleted file mode 100644
index ded9776..0000000
--- a/guest/hals/ril/libril/ril_service.h
+++ /dev/null
@@ -1,799 +0,0 @@
-/*
- * Copyright (c) 2016 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.
- */
-
-#ifndef RIL_SERVICE_H
-#define RIL_SERVICE_H
-
-#include <guest/hals/ril/libril/ril.h>
-#include <ril_internal.h>
-
-namespace radio_1_5 {
-void registerService(RIL_RadioFunctions *callbacks, android::CommandInfo *commands);
-
-int getIccCardStatusResponse(int slotId, int responseType,
-                            int token, RIL_Errno e, void *response, size_t responselen);
-
-int supplyIccPinForAppResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int supplyIccPukForAppResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int supplyIccPin2ForAppResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e, void *response,
-                               size_t responselen);
-
-int supplyIccPuk2ForAppResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e, void *response,
-                               size_t responselen);
-
-int changeIccPinForAppResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int changeIccPin2ForAppResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e, void *response,
-                               size_t responselen);
-
-int supplyNetworkDepersonalizationResponse(int slotId,
-                                          int responseType, int serial, RIL_Errno e,
-                                          void *response, size_t responselen);
-
-int getCurrentCallsResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e, void *response,
-                           size_t responselen);
-
-int dialResponse(int slotId,
-                int responseType, int serial, RIL_Errno e, void *response, size_t responselen);
-
-int getIMSIForAppResponse(int slotId, int responseType,
-                         int serial, RIL_Errno e, void *response, size_t responselen);
-
-int hangupConnectionResponse(int slotId, int responseType,
-                            int serial, RIL_Errno e, void *response, size_t responselen);
-
-int hangupWaitingOrBackgroundResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int hangupForegroundResumeBackgroundResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responselen);
-
-int switchWaitingOrHoldingAndActiveResponse(int slotId,
-                                           int responseType, int serial, RIL_Errno e,
-                                           void *response, size_t responselen);
-
-int conferenceResponse(int slotId, int responseType,
-                      int serial, RIL_Errno e, void *response, size_t responselen);
-
-int rejectCallResponse(int slotId, int responseType,
-                      int serial, RIL_Errno e, void *response, size_t responselen);
-
-int getLastCallFailCauseResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e, void *response,
-                                size_t responselen);
-
-int getSignalStrengthResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responseLen);
-
-int getVoiceRegistrationStateResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int getDataRegistrationStateResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responselen);
-
-int getOperatorResponse(int slotId,
-                       int responseType, int serial, RIL_Errno e, void *response,
-                       size_t responselen);
-
-int setRadioPowerResponse(int slotId,
-                         int responseType, int serial, RIL_Errno e, void *response,
-                         size_t responselen);
-
-int sendDtmfResponse(int slotId,
-                    int responseType, int serial, RIL_Errno e, void *response,
-                    size_t responselen);
-
-int sendSmsResponse(int slotId,
-                   int responseType, int serial, RIL_Errno e, void *response,
-                   size_t responselen);
-
-int sendSMSExpectMoreResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e, void *response,
-                             size_t responselen);
-
-int setupDataCallResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responseLen);
-
-int iccIOForAppResponse(int slotId,
-                       int responseType, int serial, RIL_Errno e, void *response,
-                       size_t responselen);
-
-int sendUssdResponse(int slotId,
-                    int responseType, int serial, RIL_Errno e, void *response,
-                    size_t responselen);
-
-int cancelPendingUssdResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e, void *response,
-                             size_t responselen);
-
-int getClirResponse(int slotId,
-                   int responseType, int serial, RIL_Errno e, void *response, size_t responselen);
-
-int setClirResponse(int slotId,
-                   int responseType, int serial, RIL_Errno e, void *response, size_t responselen);
-
-int getCallForwardStatusResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e, void *response,
-                                size_t responselen);
-
-int setCallForwardResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responselen);
-
-int getCallWaitingResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responselen);
-
-int setCallWaitingResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responselen);
-
-int acknowledgeLastIncomingGsmSmsResponse(int slotId,
-                                         int responseType, int serial, RIL_Errno e, void *response,
-                                         size_t responselen);
-
-int acceptCallResponse(int slotId,
-                      int responseType, int serial, RIL_Errno e, void *response,
-                      size_t responselen);
-
-int deactivateDataCallResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int getFacilityLockForAppResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int setFacilityLockForAppResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int setBarringPasswordResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int getNetworkSelectionModeResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e, void *response,
-                                   size_t responselen);
-
-int setNetworkSelectionModeAutomaticResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responselen);
-
-int setNetworkSelectionModeManualResponse(int slotId,
-                                         int responseType, int serial, RIL_Errno e, void *response,
-                                         size_t responselen);
-
-int getAvailableNetworksResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e, void *response,
-                                size_t responselen);
-
-int startNetworkScanResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e, void *response,
-                             size_t responselen);
-
-int stopNetworkScanResponse(int slotId,
-                            int responseType, int serial, RIL_Errno e, void *response,
-                            size_t responselen);
-
-int startDtmfResponse(int slotId,
-                     int responseType, int serial, RIL_Errno e, void *response,
-                     size_t responselen);
-
-int stopDtmfResponse(int slotId,
-                    int responseType, int serial, RIL_Errno e, void *response,
-                    size_t responselen);
-
-int getBasebandVersionResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int separateConnectionResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int setMuteResponse(int slotId,
-                   int responseType, int serial, RIL_Errno e, void *response,
-                   size_t responselen);
-
-int getMuteResponse(int slotId,
-                   int responseType, int serial, RIL_Errno e, void *response,
-                   size_t responselen);
-
-int getClipResponse(int slotId,
-                   int responseType, int serial, RIL_Errno e, void *response,
-                   size_t responselen);
-
-int getDataCallListResponse(int slotId,
-                            int responseType, int serial, RIL_Errno e,
-                            void *response, size_t responseLen);
-
-int setSuppServiceNotificationsResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e, void *response,
-                                       size_t responselen);
-
-int writeSmsToSimResponse(int slotId,
-                         int responseType, int serial, RIL_Errno e, void *response,
-                         size_t responselen);
-
-int deleteSmsOnSimResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responselen);
-
-int setBandModeResponse(int slotId,
-                       int responseType, int serial, RIL_Errno e, void *response,
-                       size_t responselen);
-
-int getAvailableBandModesResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int sendEnvelopeResponse(int slotId,
-                        int responseType, int serial, RIL_Errno e, void *response,
-                        size_t responselen);
-
-int sendTerminalResponseToSimResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int handleStkCallSetupRequestFromSimResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responselen);
-
-int explicitCallTransferResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e, void *response,
-                                size_t responselen);
-
-int setPreferredNetworkTypeResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e, void *response,
-                                   size_t responselen);
-
-int getPreferredNetworkTypeResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e, void *response,
-                                   size_t responselen);
-
-int setPreferredNetworkTypeBitmapResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e, void *response,
-                                   size_t responselen);
-
-int getPreferredNetworkTypeBitmapResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e, void *response,
-                                   size_t responselen);
-
-int getNeighboringCidsResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int setLocationUpdatesResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int setCdmaSubscriptionSourceResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int setCdmaRoamingPreferenceResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responselen);
-
-int getCdmaRoamingPreferenceResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responselen);
-
-int setTTYModeResponse(int slotId,
-                      int responseType, int serial, RIL_Errno e, void *response,
-                      size_t responselen);
-
-int getTTYModeResponse(int slotId,
-                      int responseType, int serial, RIL_Errno e, void *response,
-                      size_t responselen);
-
-int setPreferredVoicePrivacyResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responselen);
-
-int getPreferredVoicePrivacyResponse(int slotId,
-                                    int responseType, int serial, RIL_Errno e, void *response,
-                                    size_t responselen);
-
-int sendCDMAFeatureCodeResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responselen);
-
-int sendBurstDtmfResponse(int slotId,
-                         int responseType, int serial, RIL_Errno e, void *response,
-                         size_t responselen);
-
-int sendCdmaSmsResponse(int slotId,
-                       int responseType, int serial, RIL_Errno e, void *response,
-                       size_t responselen);
-
-int acknowledgeLastIncomingCdmaSmsResponse(int slotId,
-                                          int responseType, int serial, RIL_Errno e, void *response,
-                                          size_t responselen);
-
-int getGsmBroadcastConfigResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int setGsmBroadcastConfigResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int setGsmBroadcastActivationResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int getCdmaBroadcastConfigResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e, void *response,
-                                  size_t responselen);
-
-int setCdmaBroadcastConfigResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e, void *response,
-                                  size_t responselen);
-
-int setCdmaBroadcastActivationResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responselen);
-
-int getCDMASubscriptionResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e, void *response,
-                               size_t responselen);
-
-int writeSmsToRuimResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responselen);
-
-int deleteSmsOnRuimResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e, void *response,
-                           size_t responselen);
-
-int getDeviceIdentityResponse(int slotId,
-                             int responseType, int serial, RIL_Errno e, void *response,
-                             size_t responselen);
-
-int exitEmergencyCallbackModeResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int getSmscAddressResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responselen);
-
-int setCdmaBroadcastActivationResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responselen);
-
-int setSmscAddressResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responselen);
-
-int reportSmsMemoryStatusResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responselen);
-
-int reportStkServiceIsRunningResponse(int slotId,
-                                      int responseType, int serial, RIL_Errno e,
-                                      void *response, size_t responseLen);
-
-int getCdmaSubscriptionSourceResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int requestIsimAuthenticationResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e, void *response,
-                                     size_t responselen);
-
-int acknowledgeIncomingGsmSmsWithPduResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responselen);
-
-int sendEnvelopeWithStatusResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e, void *response,
-                                  size_t responselen);
-
-int getVoiceRadioTechnologyResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responselen);
-
-int getCellInfoListResponse(int slotId,
-                            int responseType,
-                            int serial, RIL_Errno e, void *response,
-                            size_t responseLen);
-
-int setCellInfoListRateResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responselen);
-
-int setInitialAttachApnResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responselen);
-
-int getImsRegistrationStateResponse(int slotId,
-                                   int responseType, int serial, RIL_Errno e,
-                                   void *response, size_t responselen);
-
-int sendImsSmsResponse(int slotId, int responseType,
-                      int serial, RIL_Errno e, void *response, size_t responselen);
-
-int iccTransmitApduBasicChannelResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e,
-                                       void *response, size_t responselen);
-
-int iccOpenLogicalChannelResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e, void *response,
-                                  size_t responselen);
-
-
-int iccCloseLogicalChannelResponse(int slotId,
-                                  int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responselen);
-
-int iccTransmitApduLogicalChannelResponse(int slotId,
-                                         int responseType, int serial, RIL_Errno e,
-                                         void *response, size_t responselen);
-
-int nvReadItemResponse(int slotId,
-                      int responseType, int serial, RIL_Errno e,
-                      void *response, size_t responselen);
-
-
-int nvWriteItemResponse(int slotId,
-                       int responseType, int serial, RIL_Errno e,
-                       void *response, size_t responselen);
-
-int nvWriteCdmaPrlResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responselen);
-
-int nvResetConfigResponse(int slotId,
-                         int responseType, int serial, RIL_Errno e,
-                         void *response, size_t responselen);
-
-int setUiccSubscriptionResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responselen);
-
-int setDataAllowedResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responselen);
-
-int getHardwareConfigResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responseLen);
-
-int requestIccSimAuthenticationResponse(int slotId,
-                                       int responseType, int serial, RIL_Errno e,
-                                       void *response, size_t responselen);
-
-int setDataProfileResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responselen);
-
-int requestShutdownResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e,
-                           void *response, size_t responselen);
-
-int getRadioCapabilityResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen);
-
-int setRadioCapabilityResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen);
-
-int startLceServiceResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e,
-                           void *response, size_t responselen);
-
-int stopLceServiceResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responselen);
-
-int pullLceDataResponse(int slotId,
-                        int responseType, int serial, RIL_Errno e,
-                        void *response, size_t responseLen);
-
-int getModemActivityInfoResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e,
-                                void *response, size_t responselen);
-
-int getModemStackStatusResponse(int slotId,
-                                int responseType, int serial, RIL_Errno e,
-                                void *response, size_t responselen);
-
-int enableModemResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                void *response, size_t responselen);
-
-int setAllowedCarriersResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen);
-
-int getAllowedCarriersResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen);
-
-int sendDeviceStateResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen);
-
-int setIndicationFilterResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen);
-
-int setSimCardPowerResponse(int slotId,
-                              int responseType, int serial, RIL_Errno e,
-                              void *response, size_t responselen);
-
-int startKeepaliveResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e,
-                           void *response, size_t responselen);
-
-int stopKeepaliveResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responselen);
-
-void acknowledgeRequest(int slotId, int serial);
-
-int radioStateChangedInd(int slotId,
-                          int indicationType, int token, RIL_Errno e, void *response,
-                          size_t responseLen);
-
-int callStateChangedInd(int slotId, int indType, int token,
-                        RIL_Errno e, void *response, size_t responselen);
-
-int networkStateChangedInd(int slotId, int indType,
-                                int token, RIL_Errno e, void *response, size_t responselen);
-
-int newSmsInd(int slotId, int indicationType,
-              int token, RIL_Errno e, void *response, size_t responselen);
-
-int newSmsStatusReportInd(int slotId, int indicationType,
-                          int token, RIL_Errno e, void *response, size_t responselen);
-
-int newSmsOnSimInd(int slotId, int indicationType,
-                   int token, RIL_Errno e, void *response, size_t responselen);
-
-int onUssdInd(int slotId, int indicationType,
-              int token, RIL_Errno e, void *response, size_t responselen);
-
-int nitzTimeReceivedInd(int slotId, int indicationType,
-                        int token, RIL_Errno e, void *response, size_t responselen);
-
-int currentSignalStrengthInd(int slotId,
-                             int indicationType, int token, RIL_Errno e,
-                             void *response, size_t responselen);
-
-int dataCallListChangedInd(int slotId, int indicationType,
-                           int token, RIL_Errno e, void *response, size_t responselen);
-
-int suppSvcNotifyInd(int slotId, int indicationType,
-                     int token, RIL_Errno e, void *response, size_t responselen);
-
-int stkSessionEndInd(int slotId, int indicationType,
-                     int token, RIL_Errno e, void *response, size_t responselen);
-
-int stkProactiveCommandInd(int slotId, int indicationType,
-                           int token, RIL_Errno e, void *response, size_t responselen);
-
-int stkEventNotifyInd(int slotId, int indicationType,
-                      int token, RIL_Errno e, void *response, size_t responselen);
-
-int stkCallSetupInd(int slotId, int indicationType,
-                    int token, RIL_Errno e, void *response, size_t responselen);
-
-int simSmsStorageFullInd(int slotId, int indicationType,
-                         int token, RIL_Errno e, void *response, size_t responselen);
-
-int simRefreshInd(int slotId, int indicationType,
-                  int token, RIL_Errno e, void *response, size_t responselen);
-
-int callRingInd(int slotId, int indicationType,
-                int token, RIL_Errno e, void *response, size_t responselen);
-
-int simStatusChangedInd(int slotId, int indicationType,
-                        int token, RIL_Errno e, void *response, size_t responselen);
-
-int cdmaNewSmsInd(int slotId, int indicationType,
-                  int token, RIL_Errno e, void *response, size_t responselen);
-
-int newBroadcastSmsInd(int slotId,
-                       int indicationType, int token, RIL_Errno e, void *response,
-                       size_t responselen);
-
-int cdmaRuimSmsStorageFullInd(int slotId,
-                              int indicationType, int token, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int restrictedStateChangedInd(int slotId,
-                              int indicationType, int token, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int enterEmergencyCallbackModeInd(int slotId,
-                                  int indicationType, int token, RIL_Errno e, void *response,
-                                  size_t responselen);
-
-int cdmaCallWaitingInd(int slotId,
-                       int indicationType, int token, RIL_Errno e, void *response,
-                       size_t responselen);
-
-int cdmaOtaProvisionStatusInd(int slotId,
-                              int indicationType, int token, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int cdmaInfoRecInd(int slotId,
-                   int indicationType, int token, RIL_Errno e, void *response,
-                   size_t responselen);
-
-int oemHookRawInd(int slotId,
-                  int indicationType, int token, RIL_Errno e, void *response,
-                  size_t responselen);
-
-int indicateRingbackToneInd(int slotId,
-                            int indicationType, int token, RIL_Errno e, void *response,
-                            size_t responselen);
-
-int resendIncallMuteInd(int slotId,
-                        int indicationType, int token, RIL_Errno e, void *response,
-                        size_t responselen);
-
-int cdmaSubscriptionSourceChangedInd(int slotId,
-                                     int indicationType, int token, RIL_Errno e,
-                                     void *response, size_t responselen);
-
-int cdmaPrlChangedInd(int slotId,
-                      int indicationType, int token, RIL_Errno e, void *response,
-                      size_t responselen);
-
-int exitEmergencyCallbackModeInd(int slotId,
-                                 int indicationType, int token, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int rilConnectedInd(int slotId,
-                    int indicationType, int token, RIL_Errno e, void *response,
-                    size_t responselen);
-
-int voiceRadioTechChangedInd(int slotId,
-                             int indicationType, int token, RIL_Errno e, void *response,
-                             size_t responselen);
-
-int cellInfoListInd(int slotId,
-                    int indicationType, int token, RIL_Errno e, void *response,
-                    size_t responselen);
-
-int imsNetworkStateChangedInd(int slotId,
-                              int indicationType, int token, RIL_Errno e, void *response,
-                              size_t responselen);
-
-int subscriptionStatusChangedInd(int slotId,
-                                 int indicationType, int token, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int srvccStateNotifyInd(int slotId,
-                        int indicationType, int token, RIL_Errno e, void *response,
-                        size_t responselen);
-
-int hardwareConfigChangedInd(int slotId,
-                             int indicationType, int token, RIL_Errno e, void *response,
-                             size_t responselen);
-
-int radioCapabilityIndicationInd(int slotId,
-                                 int indicationType, int token, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int onSupplementaryServiceIndicationInd(int slotId,
-                                        int indicationType, int token, RIL_Errno e,
-                                        void *response, size_t responselen);
-
-int stkCallControlAlphaNotifyInd(int slotId,
-                                 int indicationType, int token, RIL_Errno e, void *response,
-                                 size_t responselen);
-
-int lceDataInd(int slotId,
-               int indicationType, int token, RIL_Errno e, void *response,
-               size_t responselen);
-
-int pcoDataInd(int slotId,
-               int indicationType, int token, RIL_Errno e, void *response,
-               size_t responselen);
-
-int modemResetInd(int slotId,
-                  int indicationType, int token, RIL_Errno e, void *response,
-                  size_t responselen);
-
-int networkScanResultInd(int slotId,
-                         int indicationType, int token, RIL_Errno e, void *response,
-                         size_t responselen);
-
-int keepaliveStatusInd(int slotId,
-                       int indicationType, int token, RIL_Errno e, void *response,
-                       size_t responselen);
-
-int sendRequestRawResponse(int slotId,
-                           int responseType, int serial, RIL_Errno e,
-                           void *response, size_t responseLen);
-
-int sendRequestStringsResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen);
-
-int setCarrierInfoForImsiEncryptionResponse(int slotId,
-                                            int responseType, int serial, RIL_Errno e,
-                                            void *response, size_t responseLen);
-
-int emergencyDialResponse(int slotId,
-                          int responseType, int serial, RIL_Errno e,
-                          void *response, size_t responselen);
-
-int carrierInfoForImsiEncryption(int slotId,
-                        int responseType, int serial, RIL_Errno e,
-                        void *response, size_t responseLen);
-
-int setSystemSelectionChannelsResponse(int slotId,
-                               int responseType, int serial, RIL_Errno e,
-                               void *response, size_t responseLen);
-
-int setSignalStrengthReportingCriteriaResponse(int slotId, int responseType, int serial,
-                                               RIL_Errno e, void *response, size_t responselen);
-
-int setLinkCapacityReportingCriteriaResponse(int slotId, int responseType, int serial,
-                                             RIL_Errno e, void *response, size_t responselen);
-
-int enableUiccApplicationsResponse(int slotId,
-                                 int responseType, int serial, RIL_Errno e,
-                                 void *response, size_t responselen);
-
-int areUiccApplicationsEnabledResponse(int slotId,
-                                     int responseType, int serial, RIL_Errno e,
-                                     void *response, size_t responselen);
-
-int setRadioPowerResponse(int slotId, int responseType, int serial, RIL_Errno e, void *response,
-                          size_t responselen);
-
-int getBarringInfoResponse(int slotId, int responseType, int serial, RIL_Errno e, void *response,
-                           size_t responselen);
-
-int sendCdmaSmsExpectMoreResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                  void *response, size_t responselen);
-
-int supplySimDepersonalizationResponse(int slotId, int responseType, int serial, RIL_Errno e,
-                                       void *response, size_t responselen);
-
-pthread_rwlock_t * getRadioServiceRwlock(int slotId);
-
-void setNitzTimeReceived(int slotId, long timeReceived);
-
-}   // namespace radio
-
-#endif  // RIL_SERVICE_H
diff --git a/guest/hals/ril/libril/ril_unsol_commands.h b/guest/hals/ril/libril/ril_unsol_commands.h
deleted file mode 100644
index 89c1f55..0000000
--- a/guest/hals/ril/libril/ril_unsol_commands.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* ///guest/hals/ril/libril/ril_unsol_commands.h
-**
-** Copyright 2006, 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.
-*/
-    {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio_1_5::radioStateChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio_1_5::callStateChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio_1_5::networkStateChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_NEW_SMS, radio_1_5::newSmsInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, radio_1_5::newSmsStatusReportInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, radio_1_5::newSmsOnSimInd, WAKE_PARTIAL},
-    {RIL_UNSOL_ON_USSD, radio_1_5::onUssdInd, WAKE_PARTIAL},
-    {RIL_UNSOL_ON_USSD_REQUEST, radio_1_5::onUssdInd, DONT_WAKE},
-    {RIL_UNSOL_NITZ_TIME_RECEIVED, radio_1_5::nitzTimeReceivedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_SIGNAL_STRENGTH, radio_1_5::currentSignalStrengthInd, DONT_WAKE},
-    {RIL_UNSOL_DATA_CALL_LIST_CHANGED, radio_1_5::dataCallListChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_SUPP_SVC_NOTIFICATION, radio_1_5::suppSvcNotifyInd, WAKE_PARTIAL},
-    {RIL_UNSOL_STK_SESSION_END, radio_1_5::stkSessionEndInd, WAKE_PARTIAL},
-    {RIL_UNSOL_STK_PROACTIVE_COMMAND, radio_1_5::stkProactiveCommandInd, WAKE_PARTIAL},
-    {RIL_UNSOL_STK_EVENT_NOTIFY, radio_1_5::stkEventNotifyInd, WAKE_PARTIAL},
-    {RIL_UNSOL_STK_CALL_SETUP, radio_1_5::stkCallSetupInd, WAKE_PARTIAL},
-    {RIL_UNSOL_SIM_SMS_STORAGE_FULL, radio_1_5::simSmsStorageFullInd, WAKE_PARTIAL},
-    {RIL_UNSOL_SIM_REFRESH, radio_1_5::simRefreshInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CALL_RING, radio_1_5::callRingInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, radio_1_5::simStatusChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, radio_1_5::cdmaNewSmsInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, radio_1_5::newBroadcastSmsInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, radio_1_5::cdmaRuimSmsStorageFullInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESTRICTED_STATE_CHANGED, radio_1_5::restrictedStateChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, radio_1_5::enterEmergencyCallbackModeInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CDMA_CALL_WAITING, radio_1_5::cdmaCallWaitingInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, radio_1_5::cdmaOtaProvisionStatusInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CDMA_INFO_REC, radio_1_5::cdmaInfoRecInd, WAKE_PARTIAL},
-    {RIL_UNSOL_OEM_HOOK_RAW, radio_1_5::oemHookRawInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RINGBACK_TONE, radio_1_5::indicateRingbackToneInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESEND_INCALL_MUTE, radio_1_5::resendIncallMuteInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, radio_1_5::cdmaSubscriptionSourceChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CDMA_PRL_CHANGED, radio_1_5::cdmaPrlChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, radio_1_5::exitEmergencyCallbackModeInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RIL_CONNECTED, radio_1_5::rilConnectedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, radio_1_5::voiceRadioTechChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CELL_INFO_LIST, radio_1_5::cellInfoListInd, WAKE_PARTIAL},
-    {RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED, radio_1_5::imsNetworkStateChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, radio_1_5::subscriptionStatusChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_SRVCC_STATE_NOTIFY, radio_1_5::srvccStateNotifyInd, WAKE_PARTIAL},
-    {RIL_UNSOL_HARDWARE_CONFIG_CHANGED, radio_1_5::hardwareConfigChangedInd, WAKE_PARTIAL},
-    {RIL_UNSOL_DC_RT_INFO_CHANGED, NULL, WAKE_PARTIAL},
-    {RIL_UNSOL_RADIO_CAPABILITY, radio_1_5::radioCapabilityIndicationInd, WAKE_PARTIAL},
-    {RIL_UNSOL_ON_SS, radio_1_5::onSupplementaryServiceIndicationInd, WAKE_PARTIAL},
-    {RIL_UNSOL_STK_CC_ALPHA_NOTIFY, radio_1_5::stkCallControlAlphaNotifyInd, WAKE_PARTIAL},
-    {RIL_UNSOL_LCEDATA_RECV, radio_1_5::lceDataInd, WAKE_PARTIAL},
-    {RIL_UNSOL_PCO_DATA, radio_1_5::pcoDataInd, WAKE_PARTIAL},
-    {RIL_UNSOL_MODEM_RESTART, radio_1_5::modemResetInd, WAKE_PARTIAL},
-    {RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, radio_1_5::carrierInfoForImsiEncryption, WAKE_PARTIAL},
-    {RIL_UNSOL_NETWORK_SCAN_RESULT, radio_1_5::networkScanResultInd, WAKE_PARTIAL},
diff --git a/guest/hals/ril/reference-libril/Android.bp b/guest/hals/ril/reference-libril/Android.bp
new file mode 100644
index 0000000..db265e3
--- /dev/null
+++ b/guest/hals/ril/reference-libril/Android.bp
@@ -0,0 +1,61 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+    name: "libril-modem-lib",
+    vendor: true,
+    cflags: [
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+    srcs: [
+        "ril.cpp",
+        "RilSapSocket.cpp",
+        "ril_config.cpp",
+        "ril_event.cpp",
+        "ril_service.cpp",
+        "sap_service.cpp",
+    ],
+    include_dirs: [
+        "device/google/cuttlefish",
+        "hardware/ril/include",
+    ],
+    shared_libs: [
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.4",
+        "android.hardware.radio@1.5",
+        "android.hardware.radio@1.6",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio.config@1.3",
+        "android.hardware.radio.deprecated@1.0",
+        "libcutils",
+        "libhardware_legacy",
+        "libhidlbase",
+        "liblog",
+        "librilutils",
+        "libutils",
+    ],
+    static_libs: [
+        "libprotobuf-c-nano-enable_malloc"
+    ],
+}
diff --git a/guest/hals/ril/reference-libril/RilSapSocket.cpp b/guest/hals/ril/reference-libril/RilSapSocket.cpp
new file mode 100644
index 0000000..7a76036
--- /dev/null
+++ b/guest/hals/ril/reference-libril/RilSapSocket.cpp
@@ -0,0 +1,295 @@
+/*
+* Copyright (C) 2014 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.
+*/
+
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+#define RIL_SHLIB
+#include "RilSapSocket.h"
+#include "pb_decode.h"
+#include "pb_encode.h"
+#undef LOG_TAG
+#define LOG_TAG "RIL_UIM_SOCKET"
+#include <utils/Log.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sap_service.h>
+#include <guest/hals/ril/reference-libril/ril.h>
+
+static RilSapSocket::RilSapSocketList *head = NULL;
+
+extern "C" void
+RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
+        const struct timeval *relativeTime);
+
+struct RIL_Env RilSapSocket::uimRilEnv = {
+        .OnRequestComplete = RilSapSocket::sOnRequestComplete,
+        .OnUnsolicitedResponse = RilSapSocket::sOnUnsolicitedResponse,
+        .RequestTimedCallback = RIL_requestTimedCallback
+};
+
+void RilSapSocket::sOnRequestComplete (RIL_Token t,
+        RIL_Errno e,
+        void *response,
+        size_t responselen) {
+    RilSapSocket *sap_socket;
+    SapSocketRequest *request = (SapSocketRequest*) t;
+
+    RLOGD("Socket id:%d", request->socketId);
+
+    sap_socket = getSocketById(request->socketId);
+
+    if (sap_socket) {
+        sap_socket->onRequestComplete(t,e,response,responselen);
+    } else {
+        RLOGE("Invalid socket id");
+        if (request->curr) {
+            free(request->curr);
+        }
+        free(request);
+    }
+}
+
+#if defined(ANDROID_MULTI_SIM)
+void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse,
+        const void *data,
+        size_t datalen,
+        RIL_SOCKET_ID socketId) {
+    RilSapSocket *sap_socket = getSocketById(socketId);
+    if (sap_socket) {
+        sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen);
+    }
+}
+#else
+void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse,
+       const void *data,
+       size_t datalen) {
+    RilSapSocket *sap_socket = getSocketById(RIL_SOCKET_1);
+    if(sap_socket){
+        sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen);
+    }
+}
+#endif
+
+void RilSapSocket::printList() {
+    RilSapSocketList *current = head;
+    RLOGD("Printing socket list");
+    while(NULL != current) {
+        RLOGD("SocketName:%s",current->socket->name);
+        RLOGD("Socket id:%d",current->socket->id);
+        current = current->next;
+    }
+}
+
+RilSapSocket *RilSapSocket::getSocketById(RIL_SOCKET_ID socketId) {
+    RilSapSocket *sap_socket;
+    RilSapSocketList *current = head;
+
+    RLOGD("Entered getSocketById");
+    printList();
+
+    while(NULL != current) {
+        if(socketId == current->socket->id) {
+            sap_socket = current->socket;
+            return sap_socket;
+        }
+        current = current->next;
+    }
+    return NULL;
+}
+
+void RilSapSocket::initSapSocket(const char *socketName,
+        const RIL_RadioFunctions *uimFuncs) {
+
+    if (strcmp(socketName, RIL1_SERVICE_NAME) == 0) {
+        if(!SocketExists(socketName)) {
+            addSocketToList(socketName, RIL_SOCKET_1, uimFuncs);
+        }
+    }
+
+#if (SIM_COUNT >= 2)
+    if (strcmp(socketName, RIL2_SERVICE_NAME) == 0) {
+        if(!SocketExists(socketName)) {
+            addSocketToList(socketName, RIL_SOCKET_2, uimFuncs);
+        }
+    }
+#endif
+
+#if (SIM_COUNT >= 3)
+    if (strcmp(socketName, RIL3_SERVICE_NAME) == 0) {
+        if(!SocketExists(socketName)) {
+            addSocketToList(socketName, RIL_SOCKET_3, uimFuncs);
+        }
+    }
+#endif
+
+#if (SIM_COUNT >= 4)
+    if (strcmp(socketName, RIL4_SERVICE_NAME) == 0) {
+        if(!SocketExists(socketName)) {
+            addSocketToList(socketName, RIL_SOCKET_4, uimFuncs);
+        }
+    }
+#endif
+}
+
+void RilSapSocket::addSocketToList(const char *socketName, RIL_SOCKET_ID socketid,
+        const RIL_RadioFunctions *uimFuncs) {
+    RilSapSocket* socket = NULL;
+    RilSapSocketList *current;
+
+    if(!SocketExists(socketName)) {
+        socket = new RilSapSocket(socketName, socketid, uimFuncs);
+        RilSapSocketList* listItem = (RilSapSocketList*)malloc(sizeof(RilSapSocketList));
+        if (!listItem) {
+            RLOGE("addSocketToList: OOM");
+            delete socket;
+            return;
+        }
+        listItem->socket = socket;
+        listItem->next = NULL;
+
+        RLOGD("Adding socket with id: %d", socket->id);
+
+        if(NULL == head) {
+            head = listItem;
+            head->next = NULL;
+        }
+        else {
+            current = head;
+            while(NULL != current->next) {
+                current = current->next;
+            }
+            current->next = listItem;
+        }
+    }
+}
+
+bool RilSapSocket::SocketExists(const char *socketName) {
+    RilSapSocketList* current = head;
+
+    while(NULL != current) {
+        if(strcmp(current->socket->name, socketName) == 0) {
+            return true;
+        }
+        current = current->next;
+    }
+    return false;
+}
+
+RilSapSocket::RilSapSocket(const char *socketName,
+        RIL_SOCKET_ID socketId,
+        const RIL_RadioFunctions *inputUimFuncs):
+        RilSocket(socketName, socketId) {
+    if (inputUimFuncs) {
+        uimFuncs = inputUimFuncs;
+    }
+}
+
+void RilSapSocket::dispatchRequest(MsgHeader *req) {
+    // SapSocketRequest will be deallocated in onRequestComplete()
+    SapSocketRequest* currRequest=(SapSocketRequest*)malloc(sizeof(SapSocketRequest));
+    if (!currRequest) {
+        RLOGE("dispatchRequest: OOM");
+        // Free MsgHeader allocated in pushRecord()
+        free(req);
+        return;
+    }
+    currRequest->token = req->token;
+    currRequest->curr = req;
+    currRequest->p_next = NULL;
+    currRequest->socketId = id;
+
+    pendingResponseQueue.enqueue(currRequest);
+
+    if (uimFuncs) {
+        RLOGI("RilSapSocket::dispatchRequest [%d] > SAP REQUEST type: %d. id: %d. error: %d, \
+                token 0x%p",
+                req->token,
+                req->type,
+                req->id,
+                req->error,
+                currRequest );
+
+#if defined(ANDROID_MULTI_SIM)
+        uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest, id);
+#else
+        uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest);
+#endif
+    }
+}
+
+void RilSapSocket::onRequestComplete(RIL_Token t, RIL_Errno e, void *response,
+        size_t response_len) {
+    SapSocketRequest* request= (SapSocketRequest*)t;
+
+    if (!request || !request->curr) {
+        RLOGE("RilSapSocket::onRequestComplete: request/request->curr is NULL");
+        return;
+    }
+
+    MsgHeader *hdr = request->curr;
+
+    MsgHeader rsp;
+    rsp.token = request->curr->token;
+    rsp.type = MsgType_RESPONSE;
+    rsp.id = request->curr->id;
+    rsp.error = (Error)e;
+    rsp.payload = (pb_bytes_array_t *)calloc(1, sizeof(pb_bytes_array_t) + response_len);
+    if (!rsp.payload) {
+        RLOGE("onRequestComplete: OOM");
+    } else {
+        if (response && response_len > 0) {
+            memcpy(rsp.payload->bytes, response, response_len);
+            rsp.payload->size = response_len;
+        } else {
+            rsp.payload->size = 0;
+        }
+
+        RLOGE("RilSapSocket::onRequestComplete: Token:%d, MessageId:%d ril token 0x%p",
+                hdr->token, hdr->id, t);
+
+        sap::processResponse(&rsp, this);
+        free(rsp.payload);
+    }
+
+    // Deallocate SapSocketRequest
+    if(!pendingResponseQueue.checkAndDequeue(hdr->id, hdr->token)) {
+        RLOGE("Token:%d, MessageId:%d", hdr->token, hdr->id);
+        RLOGE ("RilSapSocket::onRequestComplete: invalid Token or Message Id");
+    }
+
+    // Deallocate MsgHeader
+    free(hdr);
+}
+
+void RilSapSocket::onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) {
+    if (data && datalen > 0) {
+        pb_bytes_array_t *payload = (pb_bytes_array_t *)calloc(1,
+                sizeof(pb_bytes_array_t) + datalen);
+        if (!payload) {
+            RLOGE("onUnsolicitedResponse: OOM");
+            return;
+        }
+        memcpy(payload->bytes, data, datalen);
+        payload->size = datalen;
+        MsgHeader rsp;
+        rsp.payload = payload;
+        rsp.type = MsgType_UNSOL_RESPONSE;
+        rsp.id = (MsgId)unsolResponse;
+        rsp.error = Error_RIL_E_SUCCESS;
+        sap::processUnsolResponse(&rsp, this);
+        free(payload);
+    }
+}
diff --git a/guest/hals/ril/reference-libril/RilSapSocket.h b/guest/hals/ril/reference-libril/RilSapSocket.h
new file mode 100644
index 0000000..1a816c5
--- /dev/null
+++ b/guest/hals/ril/reference-libril/RilSapSocket.h
@@ -0,0 +1,200 @@
+/*
+* Copyright (C) 2014 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.
+*/
+
+#ifndef RIL_UIM_SOCKET_H_INCLUDED
+#define RIL_UIM_SOCKET_H_INCLUDED
+#define RIL_SHLIB
+#include "telephony/ril.h"
+#include "RilSocket.h"
+#include <hardware/ril/librilutils/proto/sap-api.pb.h>
+
+/**
+ * RilSapSocket is a derived class, derived from the RilSocket abstract
+ * class, representing sockets for communication between bluetooth SAP module and
+ * the ril daemon.
+ * <p>
+ * This class performs the following functions :
+ * <ul>
+ *     <li>Initialize the socket.
+ *     <li>Process the requests coming on the socket.
+ *     <li>Provide handlers for Unsolicited and request responses.
+ *     <li>Request and pending response queue handling.
+ * </ul>
+ */
+class RilSapSocket : public RilSocket {
+    /**
+     * Place holder for the radio functions returned by the initialization
+     * function. Currenty only onRequest handler is being used.
+     */
+    const RIL_RadioFunctions* uimFuncs;
+
+    /**
+     * Wrapper struct for handling the requests in the queue.
+     */
+    typedef struct SapSocketRequest {
+        int token;
+        MsgHeader* curr;
+        struct SapSocketRequest* p_next;
+        RIL_SOCKET_ID socketId;
+    } SapSocketRequest;
+
+    /**
+     * Queue for requests that are pending dispatch.
+     */
+    Ril_queue<SapSocketRequest> dispatchQueue;
+
+    /**
+     * Queue for requests that are dispatched but are pending response
+     */
+    Ril_queue<SapSocketRequest> pendingResponseQueue;
+
+    public:
+        /**
+         * Initialize the socket and add the socket to the list.
+         *
+         * @param Name of the socket.
+         * @param Radio functions to be used by the socket.
+         */
+        static void initSapSocket(const char *socketName,
+        const RIL_RadioFunctions *uimFuncs);
+
+        /**
+         * Ril envoronment variable that holds the request and
+         * unsol response handlers.
+         */
+        static struct RIL_Env uimRilEnv;
+
+        /**
+         * Function to print the socket list.
+         */
+        static void printList();
+
+        /**
+         * Dispatches the request to the lower layers.
+         * It calls the on request function.
+         *
+         * @param request The request message.
+         */
+        void dispatchRequest(MsgHeader *request);
+
+        /**
+         * Class method to get the socket from the socket list.
+         *
+         * @param socketId Socket id.
+         * @return the sap socket.
+         */
+        static RilSapSocket* getSocketById(RIL_SOCKET_ID socketId);
+
+        /**
+         * Datatype to handle the socket list.
+         */
+        typedef struct RilSapSocketList {
+            RilSapSocket* socket;
+            RilSapSocketList *next;
+        } RilSapSocketList;
+
+    protected:
+        /**
+         * Socket handler to be called when a request has
+         * been completed.
+         *
+         * @param Token associated with the request.
+         * @param Error, if any, while processing the request.
+         * @param The response payload.
+         * @param Response payload length.
+         */
+        void onRequestComplete(RIL_Token t,RIL_Errno e,
+        void *response, size_t response_len);
+
+        /**
+         * Socket handler to be called when there is an
+         * unsolicited response.
+         *
+         * @param Message id.
+         * @param Response data.
+         * @param Response data length.
+         */
+        void onUnsolicitedResponse(int unsolResponse,
+        void *data, size_t datalen);
+
+        /**
+         * Class method to add the sap socket to the list of sockets.
+         * Does nothing if the socket is already present in the list.
+         * Otherwise, calls the constructor of the parent class(To startlistening)
+         * and add socket to the socket list.
+         */
+        static void addSocketToList(const char *socketName, RIL_SOCKET_ID socketid,
+        const RIL_RadioFunctions *uimFuncs);
+
+        /**
+         * Check if a socket of the given name exists in the socket list.
+         *
+         * @param Socket name.
+         * @return true if exists, false otherwise.
+         */
+        static bool SocketExists(const char *socketName);
+
+    private:
+        /**
+         * Constructor.
+         *
+         * @param Socket name.
+         * @param Socket id.
+         * @param Radio functions.
+         */
+        RilSapSocket(const char *socketName,
+        RIL_SOCKET_ID socketId,
+        const RIL_RadioFunctions *inputUimFuncs);
+
+        /**
+         * Class method that selects the socket on which the onRequestComplete
+         * is called.
+         *
+         * @param Token associated with the request.
+         * @param Error, if any, while processing the request.
+         * @param The response payload.
+         * @param Response payload length.
+         */
+        static void sOnRequestComplete(RIL_Token t,
+        RIL_Errno e, void *response, size_t responselen);
+
+#if defined(ANDROID_MULTI_SIM)
+        /**
+         * Class method that selects the socket on which the onUnsolicitedResponse
+         * is called.
+         *
+         * @param Message id.
+         * @param Response data.
+         * @param Response data length.
+         * @param Socket id.
+         */
+        static void sOnUnsolicitedResponse(int unsolResponse, const void *data,
+        size_t datalen, RIL_SOCKET_ID socket_id);
+#else
+        /**
+         * Class method that selects the socket on which the onUnsolicitedResponse
+         * is called.
+         *
+         * @param Message id.
+         * @param Response data.
+         * @param Response data length.
+         */
+        static void sOnUnsolicitedResponse(int unsolResponse, const void *data,
+        size_t datalen);
+#endif
+};
+
+#endif /*RIL_UIM_SOCKET_H_INCLUDED*/
diff --git a/guest/hals/ril/reference-libril/RilSocket.h b/guest/hals/ril/reference-libril/RilSocket.h
new file mode 100644
index 0000000..53b00c9
--- /dev/null
+++ b/guest/hals/ril/reference-libril/RilSocket.h
@@ -0,0 +1,70 @@
+/*
+* Copyright (C) 2014 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.
+*/
+
+#ifndef RIL_SOCKET_H_INCLUDED
+#define RIL_SOCKET_H_INCLUDED
+#include <libril/ril_ex.h>
+#include "rilSocketQueue.h"
+#include <ril_event.h>
+
+/**
+ * Abstract socket class representing sockets in rild.
+ * <p>
+ * This class performs the following functions :
+ * <ul>
+ *     <li> Start socket listen.
+ *     <li> Handle socket listen and command callbacks.
+ * </ul>
+ */
+class RilSocket {
+    protected:
+
+        /**
+         * Socket name.
+         */
+        const char* name;
+
+        /**
+         * Socket id.
+         */
+        RIL_SOCKET_ID id;
+
+    public:
+
+        /**
+         * Constructor.
+         *
+         * @param Socket name.
+         * @param Socket id.
+         */
+        RilSocket(const char* socketName, RIL_SOCKET_ID socketId) {
+            name = socketName;
+            id = socketId;
+        }
+
+        /**
+         * Get socket id.
+         *
+         * @return RIL_SOCKET_ID socket id.
+         */
+        RIL_SOCKET_ID getSocketId(void) {
+            return id;
+        }
+
+        virtual ~RilSocket(){}
+};
+
+#endif
diff --git a/guest/hals/ril/reference-libril/ril.cpp b/guest/hals/ril/reference-libril/ril.cpp
new file mode 100644
index 0000000..9196ef4
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril.cpp
@@ -0,0 +1,1302 @@
+/* //guest/hals/ril/ril.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#define LOG_TAG "RILC"
+
+#include <hardware_legacy/power.h>
+#include <guest/hals/ril/reference-libril/ril.h>
+#include <telephony/ril_cdma_sms.h>
+#include <cutils/sockets.h>
+#include <telephony/record_stream.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/system_properties.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <netinet/in.h>
+#include <cutils/properties.h>
+#include <RilSapSocket.h>
+#include <guest/hals/ril/reference-libril/ril_service.h>
+#include <sap_service.h>
+
+extern "C" void
+RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen);
+
+extern "C" void
+RIL_onRequestAck(RIL_Token t);
+namespace android {
+
+#define PHONE_PROCESS "radio"
+#define BLUETOOTH_PROCESS "bluetooth"
+
+#define ANDROID_WAKE_LOCK_NAME "radio-interface"
+
+#define ANDROID_WAKE_LOCK_SECS 0
+#define ANDROID_WAKE_LOCK_USECS 200000
+
+#define PROPERTY_RIL_IMPL "gsm.version.ril-impl"
+
+// match with constant in RIL.java
+#define MAX_COMMAND_BYTES (8 * 1024)
+
+// Basically: memset buffers that the client library
+// shouldn't be using anymore in an attempt to find
+// memory usage issues sooner.
+#define MEMSET_FREED 1
+
+#define NUM_ELEMS(a)     (sizeof (a) / sizeof (a)[0])
+
+/* Negative values for private RIL errno's */
+#define RIL_ERRNO_INVALID_RESPONSE (-1)
+#define RIL_ERRNO_NO_MEMORY (-12)
+
+// request, response, and unsolicited msg print macro
+#define PRINTBUF_SIZE 8096
+
+enum WakeType {DONT_WAKE, WAKE_PARTIAL};
+
+typedef struct {
+    int requestNumber;
+    int (*responseFunction) (int slotId, int responseType, int token,
+            RIL_Errno e, void *response, size_t responselen);
+    WakeType wakeType;
+} UnsolResponseInfo;
+
+typedef struct UserCallbackInfo {
+    RIL_TimedCallback p_callback;
+    void *userParam;
+    struct ril_event event;
+    struct UserCallbackInfo *p_next;
+} UserCallbackInfo;
+
+extern "C" const char * failCauseToString(RIL_Errno);
+extern "C" const char * callStateToString(RIL_CallState);
+extern "C" const char * radioStateToString(RIL_RadioState);
+extern "C" const char * rilSocketIdToString(RIL_SOCKET_ID socket_id);
+
+extern "C"
+char ril_service_name_base[MAX_SERVICE_NAME_LENGTH] = RIL_SERVICE_NAME_BASE;
+extern "C"
+char ril_service_name[MAX_SERVICE_NAME_LENGTH] = RIL1_SERVICE_NAME;
+/*******************************************************************/
+
+RIL_RadioFunctions s_callbacks = {0, NULL, NULL, NULL, NULL, NULL};
+static int s_registerCalled = 0;
+
+static pthread_t s_tid_dispatch;
+static int s_started = 0;
+
+static int s_fdWakeupRead;
+static int s_fdWakeupWrite;
+
+int s_wakelock_count = 0;
+
+static struct ril_event s_wakeupfd_event;
+
+static pthread_mutex_t s_pendingRequestsMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t s_wakeLockCountMutex = PTHREAD_MUTEX_INITIALIZER;
+static RequestInfo *s_pendingRequests = NULL;
+
+#if (SIM_COUNT >= 2)
+static pthread_mutex_t s_pendingRequestsMutex_socket2  = PTHREAD_MUTEX_INITIALIZER;
+static RequestInfo *s_pendingRequests_socket2          = NULL;
+#endif
+
+#if (SIM_COUNT >= 3)
+static pthread_mutex_t s_pendingRequestsMutex_socket3  = PTHREAD_MUTEX_INITIALIZER;
+static RequestInfo *s_pendingRequests_socket3          = NULL;
+#endif
+
+#if (SIM_COUNT >= 4)
+static pthread_mutex_t s_pendingRequestsMutex_socket4  = PTHREAD_MUTEX_INITIALIZER;
+static RequestInfo *s_pendingRequests_socket4          = NULL;
+#endif
+
+static const struct timeval TIMEVAL_WAKE_TIMEOUT = {ANDROID_WAKE_LOCK_SECS,ANDROID_WAKE_LOCK_USECS};
+
+
+static pthread_mutex_t s_startupMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t s_startupCond = PTHREAD_COND_INITIALIZER;
+
+static UserCallbackInfo *s_last_wake_timeout_info = NULL;
+
+static void *s_lastNITZTimeData = NULL;
+static size_t s_lastNITZTimeDataSize;
+
+#if RILC_LOG
+    static char printBuf[PRINTBUF_SIZE];
+#endif
+
+/*******************************************************************/
+static void grabPartialWakeLock();
+void releaseWakeLock();
+static void wakeTimeoutCallback(void *);
+
+#ifdef RIL_SHLIB
+#if defined(ANDROID_MULTI_SIM)
+extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
+                                size_t datalen, RIL_SOCKET_ID socket_id);
+#else
+extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
+                                size_t datalen);
+#endif
+#endif
+
+#if defined(ANDROID_MULTI_SIM)
+#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c), (d))
+#else
+#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c))
+#endif
+
+static UserCallbackInfo * internalRequestTimedCallback
+    (RIL_TimedCallback callback, void *param,
+        const struct timeval *relativeTime);
+
+/** Index == requestNumber */
+static CommandInfo s_commands[] = {
+#include "./ril_commands.h"
+};
+
+static UnsolResponseInfo s_unsolResponses[] = {
+#include "./ril_unsol_commands.h"
+};
+
+/* Radio Config Request @{ */
+static CommandInfo s_configCommands[] = {
+#include "./ril_config_commands.h"
+};
+
+static UnsolResponseInfo s_configUnsolResponses[] = {
+#include "./ril_config_unsol_commands.h"
+};
+/* }@ */
+
+char * RIL_getServiceName() {
+    return ril_service_name;
+}
+
+RequestInfo *
+addRequestToList(int serial, int slotId, int request) {
+    RequestInfo *pRI = nullptr;
+    int ret;
+    RIL_SOCKET_ID socket_id = (RIL_SOCKET_ID) slotId;
+    /* Hook for current context */
+    /* pendingRequestsMutextHook refer to &s_pendingRequestsMutex */
+    pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex;
+    /* pendingRequestsHook refer to &s_pendingRequests */
+    RequestInfo**    pendingRequestsHook = &s_pendingRequests;
+
+#if (SIM_COUNT >= 2)
+    if (socket_id == RIL_SOCKET_2) {
+        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket2;
+        pendingRequestsHook = &s_pendingRequests_socket2;
+    }
+#if (SIM_COUNT >= 3)
+    else if (socket_id == RIL_SOCKET_3) {
+        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket3;
+        pendingRequestsHook = &s_pendingRequests_socket3;
+    }
+#endif
+#if (SIM_COUNT >= 4)
+    else if (socket_id == RIL_SOCKET_4) {
+        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket4;
+        pendingRequestsHook = &s_pendingRequests_socket4;
+    }
+#endif
+#endif
+
+    pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
+    if (pRI == NULL) {
+        RLOGE("Memory allocation failed for request %s", requestToString(request));
+        return NULL;
+    }
+
+    pRI->token = serial;
+    pRI->pCI = &(s_commands[request]);
+
+    if (request >= RIL_REQUEST_RADIO_CONFIG_BASE &&
+        request <= RIL_REQUEST_RADIO_CONFIG_LAST) {
+        request = request - RIL_REQUEST_RADIO_CONFIG_BASE;
+        pRI->pCI = &(s_configCommands[request]);
+    }
+
+    pRI->socket_id = socket_id;
+
+    ret = pthread_mutex_lock(pendingRequestsMutexHook);
+    assert (ret == 0);
+
+    pRI->p_next = *pendingRequestsHook;
+    *pendingRequestsHook = pRI;
+
+    ret = pthread_mutex_unlock(pendingRequestsMutexHook);
+    assert (ret == 0);
+
+    return pRI;
+}
+
+static void triggerEvLoop() {
+    int ret;
+    if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
+        /* trigger event loop to wakeup. No reason to do this,
+         * if we're in the event loop thread */
+         do {
+            ret = write (s_fdWakeupWrite, " ", 1);
+         } while (ret < 0 && errno == EINTR);
+    }
+}
+
+static void rilEventAddWakeup(struct ril_event *ev) {
+    ril_event_add(ev);
+    triggerEvLoop();
+}
+
+/**
+ * A write on the wakeup fd is done just to pop us out of select()
+ * We empty the buffer here and then ril_event will reset the timers on the
+ * way back down
+ */
+static void processWakeupCallback(int fd, short flags, void *param) {
+    char buff[16];
+    int ret;
+
+    RLOGV("processWakeupCallback");
+
+    /* empty our wakeup socket out */
+    do {
+        ret = read(s_fdWakeupRead, &buff, sizeof(buff));
+    } while (ret > 0 || (ret < 0 && errno == EINTR));
+}
+
+static void resendLastNITZTimeData(RIL_SOCKET_ID socket_id) {
+    if (s_lastNITZTimeData != NULL) {
+        int responseType = (s_callbacks.version >= 13)
+                           ? RESPONSE_UNSOLICITED_ACK_EXP
+                           : RESPONSE_UNSOLICITED;
+        // acquire read lock for the service before calling nitzTimeReceivedInd() since it reads
+        // nitzTimeReceived in ril_service
+        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock(
+                (int) socket_id);
+        int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+
+        int ret = radio_1_6::nitzTimeReceivedInd(
+            (int)socket_id, responseType, 0,
+            RIL_E_SUCCESS, s_lastNITZTimeData, s_lastNITZTimeDataSize);
+        if (ret == 0) {
+            free(s_lastNITZTimeData);
+            s_lastNITZTimeData = NULL;
+        }
+
+        rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+    }
+}
+
+void onNewCommandConnect(RIL_SOCKET_ID socket_id) {
+    // Inform we are connected and the ril version
+    int rilVer = s_callbacks.version;
+    RIL_UNSOL_RESPONSE(RIL_UNSOL_RIL_CONNECTED,
+                                    &rilVer, sizeof(rilVer), socket_id);
+
+    // implicit radio state changed
+    RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
+                                    NULL, 0, socket_id);
+
+    // Send last NITZ time data, in case it was missed
+    if (s_lastNITZTimeData != NULL) {
+        resendLastNITZTimeData(socket_id);
+    }
+
+    // Get version string
+    if (s_callbacks.getVersion != NULL) {
+        const char *version;
+        version = s_callbacks.getVersion();
+        RLOGI("RIL Daemon version: %s\n", version);
+
+        property_set(PROPERTY_RIL_IMPL, version);
+    } else {
+        RLOGI("RIL Daemon version: unavailable\n");
+        property_set(PROPERTY_RIL_IMPL, "unavailable");
+    }
+
+}
+
+static void userTimerCallback (int fd, short flags, void *param) {
+    UserCallbackInfo *p_info;
+
+    p_info = (UserCallbackInfo *)param;
+
+    p_info->p_callback(p_info->userParam);
+
+
+    // FIXME generalize this...there should be a cancel mechanism
+    if (s_last_wake_timeout_info != NULL && s_last_wake_timeout_info == p_info) {
+        s_last_wake_timeout_info = NULL;
+    }
+
+    free(p_info);
+}
+
+
+static void *
+eventLoop(void *param) {
+    int ret;
+    int filedes[2];
+
+    ril_event_init();
+
+    pthread_mutex_lock(&s_startupMutex);
+
+    s_started = 1;
+    pthread_cond_broadcast(&s_startupCond);
+
+    pthread_mutex_unlock(&s_startupMutex);
+
+    ret = pipe(filedes);
+
+    if (ret < 0) {
+        RLOGE("Error in pipe() errno:%d", errno);
+        return NULL;
+    }
+
+    s_fdWakeupRead = filedes[0];
+    s_fdWakeupWrite = filedes[1];
+
+    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
+
+    ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
+                processWakeupCallback, NULL);
+
+    rilEventAddWakeup (&s_wakeupfd_event);
+
+    // Only returns on error
+    ril_event_loop();
+    RLOGE ("error in event_loop_base errno:%d", errno);
+    // kill self to restart on error
+    kill(0, SIGKILL);
+
+    return NULL;
+}
+
+extern "C" void
+RIL_startEventLoop(void) {
+    /* spin up eventLoop thread and wait for it to get started */
+    s_started = 0;
+    pthread_mutex_lock(&s_startupMutex);
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
+    if (result != 0) {
+        RLOGE("Failed to create dispatch thread: %s", strerror(result));
+        goto done;
+    }
+
+    while (s_started == 0) {
+        pthread_cond_wait(&s_startupCond, &s_startupMutex);
+    }
+
+done:
+    pthread_mutex_unlock(&s_startupMutex);
+}
+
+// Used for testing purpose only.
+extern "C" void RIL_setcallbacks (const RIL_RadioFunctions *callbacks) {
+    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
+}
+
+extern "C" void
+RIL_register (const RIL_RadioFunctions *callbacks) {
+    RLOGI("SIM_COUNT: %d", SIM_COUNT);
+
+    if (callbacks == NULL) {
+        RLOGE("RIL_register: RIL_RadioFunctions * null");
+        return;
+    }
+    if (callbacks->version < RIL_VERSION_MIN) {
+        RLOGE("RIL_register: version %d is to old, min version is %d",
+             callbacks->version, RIL_VERSION_MIN);
+        return;
+    }
+
+    RLOGD("RIL_register: Vsoc RIL version %d", callbacks->version);
+
+    if (s_registerCalled > 0) {
+        RLOGE("RIL_register has been called more than once. "
+                "Subsequent call ignored");
+        return;
+    }
+
+    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
+
+    s_registerCalled = 1;
+
+    RLOGI("s_registerCalled flag set, %d", s_started);
+    // Little self-check
+
+    for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
+        assert(i == s_commands[i].requestNumber);
+    }
+
+    for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
+        assert(i + RIL_UNSOL_RESPONSE_BASE
+                == s_unsolResponses[i].requestNumber);
+    }
+
+    radio_1_6::registerService(&s_callbacks, s_commands);
+    RLOGI("RILHIDL called registerService");
+
+    /* Radio Config Request @{ */
+    for (int i = 1; i < (int)NUM_ELEMS(s_configCommands); i++) {
+        assert(i == s_configCommands[i].requestNumber -
+            RIL_REQUEST_RADIO_CONFIG_BASE);
+    }
+
+    for (int i = 0; i < (int)NUM_ELEMS(s_configUnsolResponses); i++) {
+        assert(i == s_configUnsolResponses[i].requestNumber -
+            RIL_UNSOL_RESPONSE_RADIO_CONFIG_BASE);
+    }
+    radio_1_6::registerConfigService(&s_callbacks, s_configCommands);
+    /* }@ */
+
+
+}
+
+extern "C" void
+RIL_register_socket (const RIL_RadioFunctions *(*Init)(const struct RIL_Env *, int, char **),
+        RIL_SOCKET_TYPE socketType, int argc, char **argv) {
+
+    const RIL_RadioFunctions* UimFuncs = NULL;
+
+    if(Init) {
+        UimFuncs = Init(&RilSapSocket::uimRilEnv, argc, argv);
+
+        switch(socketType) {
+            case RIL_SAP_SOCKET:
+                RilSapSocket::initSapSocket(RIL1_SERVICE_NAME, UimFuncs);
+
+#if (SIM_COUNT >= 2)
+                RilSapSocket::initSapSocket(RIL2_SERVICE_NAME, UimFuncs);
+#endif
+
+#if (SIM_COUNT >= 3)
+                RilSapSocket::initSapSocket(RIL3_SERVICE_NAME, UimFuncs);
+#endif
+
+#if (SIM_COUNT >= 4)
+                RilSapSocket::initSapSocket(RIL4_SERVICE_NAME, UimFuncs);
+#endif
+                break;
+            default:;
+        }
+
+        RLOGI("RIL_register_socket: calling registerService");
+        sap::registerService(UimFuncs);
+    }
+}
+
+// Check and remove RequestInfo if its a response and not just ack sent back
+static int
+checkAndDequeueRequestInfoIfAck(struct RequestInfo *pRI, bool isAck) {
+    int ret = 0;
+    /* Hook for current context
+       pendingRequestsMutextHook refer to &s_pendingRequestsMutex */
+    pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex;
+    /* pendingRequestsHook refer to &s_pendingRequests */
+    RequestInfo ** pendingRequestsHook = &s_pendingRequests;
+
+    if (pRI == NULL) {
+        return 0;
+    }
+
+#if (SIM_COUNT >= 2)
+    if (pRI->socket_id == RIL_SOCKET_2) {
+        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket2;
+        pendingRequestsHook = &s_pendingRequests_socket2;
+    }
+#if (SIM_COUNT >= 3)
+        if (pRI->socket_id == RIL_SOCKET_3) {
+            pendingRequestsMutexHook = &s_pendingRequestsMutex_socket3;
+            pendingRequestsHook = &s_pendingRequests_socket3;
+        }
+#endif
+#if (SIM_COUNT >= 4)
+    if (pRI->socket_id == RIL_SOCKET_4) {
+        pendingRequestsMutexHook = &s_pendingRequestsMutex_socket4;
+        pendingRequestsHook = &s_pendingRequests_socket4;
+    }
+#endif
+#endif
+    pthread_mutex_lock(pendingRequestsMutexHook);
+
+    for(RequestInfo **ppCur = pendingRequestsHook
+        ; *ppCur != NULL
+        ; ppCur = &((*ppCur)->p_next)
+    ) {
+        if (pRI == *ppCur) {
+            ret = 1;
+            if (isAck) { // Async ack
+                if (pRI->wasAckSent == 1) {
+                    RLOGD("Ack was already sent for %s", requestToString(pRI->pCI->requestNumber));
+                } else {
+                    pRI->wasAckSent = 1;
+                }
+            } else {
+                *ppCur = (*ppCur)->p_next;
+            }
+            break;
+        }
+    }
+
+    pthread_mutex_unlock(pendingRequestsMutexHook);
+
+    return ret;
+}
+
+extern "C" void
+RIL_onRequestAck(RIL_Token t) {
+    RequestInfo *pRI;
+
+    RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
+
+    pRI = (RequestInfo *)t;
+
+    if (!checkAndDequeueRequestInfoIfAck(pRI, true)) {
+        RLOGE ("RIL_onRequestAck: invalid RIL_Token");
+        return;
+    }
+
+    socket_id = pRI->socket_id;
+
+#if VDBG
+    RLOGD("Request Ack, %s", rilSocketIdToString(socket_id));
+#endif
+
+    appendPrintBuf("Ack [%04d]< %s", pRI->token, requestToString(pRI->pCI->requestNumber));
+
+    if (pRI->cancelled == 0) {
+        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock(
+                (int) socket_id);
+        int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+
+        radio_1_6::acknowledgeRequest((int) socket_id, pRI->token);
+
+        rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+    }
+}
+extern "C" void
+RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
+    RequestInfo *pRI;
+    int ret;
+    RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
+
+    pRI = (RequestInfo *)t;
+
+    if (!checkAndDequeueRequestInfoIfAck(pRI, false)) {
+        RLOGE ("RIL_onRequestComplete: invalid RIL_Token");
+        return;
+    }
+
+    socket_id = pRI->socket_id;
+
+#if VDBG
+    RLOGD("RequestComplete, %s", rilSocketIdToString(socket_id));
+#endif
+
+    if (pRI->local > 0) {
+        // Locally issued command...void only!
+        // response does not go back up the command socket
+        RLOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
+
+        free(pRI);
+        return;
+    }
+
+    appendPrintBuf("[%04d]< %s",
+        pRI->token, requestToString(pRI->pCI->requestNumber));
+
+    if (pRI->cancelled == 0) {
+        int responseType;
+        if (s_callbacks.version >= 13 && pRI->wasAckSent == 1) {
+            // If ack was already sent, then this call is an asynchronous response. So we need to
+            // send id indicating that we expect an ack from RIL.java as we acquire wakelock here.
+            responseType = RESPONSE_SOLICITED_ACK_EXP;
+            grabPartialWakeLock();
+        } else {
+            responseType = RESPONSE_SOLICITED;
+        }
+
+        // there is a response payload, no matter success or not.
+#if VDBG
+        RLOGE ("Calling responseFunction() for token %d", pRI->token);
+#endif
+
+        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock((int) socket_id);
+        int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+
+        ret = pRI->pCI->responseFunction((int) socket_id,
+                responseType, pRI->token, e, response, responselen);
+
+        rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+    }
+    free(pRI);
+}
+
+static void
+grabPartialWakeLock() {
+    if (s_callbacks.version >= 13) {
+        int ret;
+        ret = pthread_mutex_lock(&s_wakeLockCountMutex);
+        assert(ret == 0);
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, ANDROID_WAKE_LOCK_NAME);
+
+        UserCallbackInfo *p_info =
+                internalRequestTimedCallback(wakeTimeoutCallback, NULL, &TIMEVAL_WAKE_TIMEOUT);
+        if (p_info == NULL) {
+            release_wake_lock(ANDROID_WAKE_LOCK_NAME);
+        } else {
+            s_wakelock_count++;
+            if (s_last_wake_timeout_info != NULL) {
+                s_last_wake_timeout_info->userParam = (void *)1;
+            }
+            s_last_wake_timeout_info = p_info;
+        }
+        ret = pthread_mutex_unlock(&s_wakeLockCountMutex);
+        assert(ret == 0);
+    } else {
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, ANDROID_WAKE_LOCK_NAME);
+    }
+}
+
+void
+releaseWakeLock() {
+    if (s_callbacks.version >= 13) {
+        int ret;
+        ret = pthread_mutex_lock(&s_wakeLockCountMutex);
+        assert(ret == 0);
+
+        if (s_wakelock_count > 1) {
+            s_wakelock_count--;
+        } else {
+            s_wakelock_count = 0;
+            release_wake_lock(ANDROID_WAKE_LOCK_NAME);
+            if (s_last_wake_timeout_info != NULL) {
+                s_last_wake_timeout_info->userParam = (void *)1;
+            }
+        }
+
+        ret = pthread_mutex_unlock(&s_wakeLockCountMutex);
+        assert(ret == 0);
+    } else {
+        release_wake_lock(ANDROID_WAKE_LOCK_NAME);
+    }
+}
+
+/**
+ * Timer callback to put us back to sleep before the default timeout
+ */
+static void
+wakeTimeoutCallback (void *param) {
+    // We're using "param != NULL" as a cancellation mechanism
+    if (s_callbacks.version >= 13) {
+        if (param == NULL) {
+            int ret;
+            ret = pthread_mutex_lock(&s_wakeLockCountMutex);
+            assert(ret == 0);
+            s_wakelock_count = 0;
+            release_wake_lock(ANDROID_WAKE_LOCK_NAME);
+            ret = pthread_mutex_unlock(&s_wakeLockCountMutex);
+            assert(ret == 0);
+        }
+    } else {
+        if (param == NULL) {
+            releaseWakeLock();
+        }
+    }
+}
+
+#if defined(ANDROID_MULTI_SIM)
+extern "C"
+void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
+                                size_t datalen, RIL_SOCKET_ID socket_id)
+#else
+extern "C"
+void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
+                                size_t datalen)
+#endif
+{
+    int unsolResponseIndex;
+    int ret;
+    bool shouldScheduleTimeout = false;
+    RIL_SOCKET_ID soc_id = RIL_SOCKET_1;
+    UnsolResponseInfo *pURI = NULL;
+
+#if defined(ANDROID_MULTI_SIM)
+    soc_id = socket_id;
+#endif
+
+
+    if (s_registerCalled == 0) {
+        // Ignore RIL_onUnsolicitedResponse before RIL_register
+        RLOGW("RIL_onUnsolicitedResponse called before RIL_register");
+        return;
+    }
+
+    unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
+
+    if ((unsolResponse < RIL_UNSOL_RESPONSE_BASE)
+        || (unsolResponse > RIL_UNSOL_RESPONSE_LAST
+                && unsolResponse < RIL_UNSOL_RESPONSE_RADIO_CONFIG_BASE)
+        || (unsolResponse > RIL_UNSOL_RESPONSE_RADIO_CONFIG_LAST)) {
+        RLOGE("unsupported unsolicited response code %d", unsolResponse);
+        return;
+    }
+
+    if (unsolResponse >= RIL_UNSOL_RESPONSE_BASE
+            && unsolResponse <= RIL_UNSOL_RESPONSE_LAST) {
+        unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
+        pURI = &(s_unsolResponses[unsolResponseIndex]);
+    } else if (unsolResponse >= RIL_UNSOL_RESPONSE_RADIO_CONFIG_BASE
+            && unsolResponse <= RIL_UNSOL_RESPONSE_RADIO_CONFIG_LAST) {
+        unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_RADIO_CONFIG_BASE;
+        pURI = &(s_configUnsolResponses[unsolResponseIndex]);
+    }
+
+    // Grab a wake lock if needed for this reponse,
+    // as we exit we'll either release it immediately
+    // or set a timer to release it later.
+    switch (s_unsolResponses[unsolResponseIndex].wakeType) {
+        case WAKE_PARTIAL:
+            grabPartialWakeLock();
+            shouldScheduleTimeout = true;
+        break;
+
+        case DONT_WAKE:
+        default:
+            // No wake lock is grabed so don't set timeout
+            shouldScheduleTimeout = false;
+            break;
+    }
+
+    appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
+
+    int responseType;
+    if (s_callbacks.version >= 13
+                && s_unsolResponses[unsolResponseIndex].wakeType == WAKE_PARTIAL) {
+        responseType = RESPONSE_UNSOLICITED_ACK_EXP;
+    } else {
+        responseType = RESPONSE_UNSOLICITED;
+    }
+
+    pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock((int) soc_id);
+    int rwlockRet;
+
+    if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
+        // get a write lock in caes of NITZ since setNitzTimeReceived() is called
+        rwlockRet = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+        radio_1_6::setNitzTimeReceived((int) soc_id, android::elapsedRealtime());
+    } else {
+        rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
+        assert(rwlockRet == 0);
+    }
+
+    if (pURI != NULL && pURI->responseFunction != NULL) {
+        ret = pURI->responseFunction((int) soc_id, responseType, 0, RIL_E_SUCCESS,
+                const_cast<void*>(data), datalen);
+    } else {
+        RLOGW("No call responseFunction defined for UNSOLICITED");
+    }
+
+    rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
+    assert(rwlockRet == 0);
+
+    if (s_callbacks.version < 13) {
+        if (shouldScheduleTimeout) {
+            UserCallbackInfo *p_info = internalRequestTimedCallback(wakeTimeoutCallback, NULL,
+                    &TIMEVAL_WAKE_TIMEOUT);
+
+            if (p_info == NULL) {
+                goto error_exit;
+            } else {
+                // Cancel the previous request
+                if (s_last_wake_timeout_info != NULL) {
+                    s_last_wake_timeout_info->userParam = (void *)1;
+                }
+                s_last_wake_timeout_info = p_info;
+            }
+        }
+    }
+
+#if VDBG
+    RLOGI("%s UNSOLICITED: %s length:%zu", rilSocketIdToString(soc_id),
+            requestToString(unsolResponse), datalen);
+#endif
+
+    if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
+        // Unfortunately, NITZ time is not poll/update like everything
+        // else in the system. So, if the upstream client isn't connected,
+        // keep a copy of the last NITZ response (with receive time noted
+        // above) around so we can deliver it when it is connected
+
+        if (s_lastNITZTimeData != NULL) {
+            free(s_lastNITZTimeData);
+            s_lastNITZTimeData = NULL;
+        }
+
+        s_lastNITZTimeData = calloc(datalen, 1);
+        if (s_lastNITZTimeData == NULL) {
+            RLOGE("Memory allocation failed in RIL_onUnsolicitedResponse");
+            goto error_exit;
+        }
+        s_lastNITZTimeDataSize = datalen;
+        memcpy(s_lastNITZTimeData, data, datalen);
+    }
+
+    // Normal exit
+    return;
+
+error_exit:
+    if (shouldScheduleTimeout) {
+        releaseWakeLock();
+    }
+}
+
+/** FIXME generalize this if you track UserCAllbackInfo, clear it
+    when the callback occurs
+*/
+static UserCallbackInfo *
+internalRequestTimedCallback (RIL_TimedCallback callback, void *param,
+                                const struct timeval *relativeTime)
+{
+    struct timeval myRelativeTime;
+    UserCallbackInfo *p_info;
+
+    p_info = (UserCallbackInfo *) calloc(1, sizeof(UserCallbackInfo));
+    if (p_info == NULL) {
+        RLOGE("Memory allocation failed in internalRequestTimedCallback");
+        return p_info;
+
+    }
+
+    p_info->p_callback = callback;
+    p_info->userParam = param;
+
+    if (relativeTime == NULL) {
+        /* treat null parameter as a 0 relative time */
+        memset (&myRelativeTime, 0, sizeof(myRelativeTime));
+    } else {
+        /* FIXME I think event_add's tv param is really const anyway */
+        memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
+    }
+
+    ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);
+
+    ril_timer_add(&(p_info->event), &myRelativeTime);
+
+    triggerEvLoop();
+    return p_info;
+}
+
+
+extern "C" void
+RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
+                                const struct timeval *relativeTime) {
+    internalRequestTimedCallback (callback, param, relativeTime);
+}
+
+const char *
+failCauseToString(RIL_Errno e) {
+    switch(e) {
+        case RIL_E_SUCCESS: return "E_SUCCESS";
+        case RIL_E_RADIO_NOT_AVAILABLE: return "E_RADIO_NOT_AVAILABLE";
+        case RIL_E_GENERIC_FAILURE: return "E_GENERIC_FAILURE";
+        case RIL_E_PASSWORD_INCORRECT: return "E_PASSWORD_INCORRECT";
+        case RIL_E_SIM_PIN2: return "E_SIM_PIN2";
+        case RIL_E_SIM_PUK2: return "E_SIM_PUK2";
+        case RIL_E_REQUEST_NOT_SUPPORTED: return "E_REQUEST_NOT_SUPPORTED";
+        case RIL_E_CANCELLED: return "E_CANCELLED";
+        case RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL: return "E_OP_NOT_ALLOWED_DURING_VOICE_CALL";
+        case RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW: return "E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW";
+        case RIL_E_SMS_SEND_FAIL_RETRY: return "E_SMS_SEND_FAIL_RETRY";
+        case RIL_E_SIM_ABSENT:return "E_SIM_ABSENT";
+        case RIL_E_ILLEGAL_SIM_OR_ME:return "E_ILLEGAL_SIM_OR_ME";
+#ifdef FEATURE_MULTIMODE_ANDROID
+        case RIL_E_SUBSCRIPTION_NOT_AVAILABLE:return "E_SUBSCRIPTION_NOT_AVAILABLE";
+        case RIL_E_MODE_NOT_SUPPORTED:return "E_MODE_NOT_SUPPORTED";
+#endif
+        case RIL_E_FDN_CHECK_FAILURE: return "E_FDN_CHECK_FAILURE";
+        case RIL_E_MISSING_RESOURCE: return "E_MISSING_RESOURCE";
+        case RIL_E_NO_SUCH_ELEMENT: return "E_NO_SUCH_ELEMENT";
+        case RIL_E_DIAL_MODIFIED_TO_USSD: return "E_DIAL_MODIFIED_TO_USSD";
+        case RIL_E_DIAL_MODIFIED_TO_SS: return "E_DIAL_MODIFIED_TO_SS";
+        case RIL_E_DIAL_MODIFIED_TO_DIAL: return "E_DIAL_MODIFIED_TO_DIAL";
+        case RIL_E_USSD_MODIFIED_TO_DIAL: return "E_USSD_MODIFIED_TO_DIAL";
+        case RIL_E_USSD_MODIFIED_TO_SS: return "E_USSD_MODIFIED_TO_SS";
+        case RIL_E_USSD_MODIFIED_TO_USSD: return "E_USSD_MODIFIED_TO_USSD";
+        case RIL_E_SS_MODIFIED_TO_DIAL: return "E_SS_MODIFIED_TO_DIAL";
+        case RIL_E_SS_MODIFIED_TO_USSD: return "E_SS_MODIFIED_TO_USSD";
+        case RIL_E_SUBSCRIPTION_NOT_SUPPORTED: return "E_SUBSCRIPTION_NOT_SUPPORTED";
+        case RIL_E_SS_MODIFIED_TO_SS: return "E_SS_MODIFIED_TO_SS";
+        case RIL_E_LCE_NOT_SUPPORTED: return "E_LCE_NOT_SUPPORTED";
+        case RIL_E_NO_MEMORY: return "E_NO_MEMORY";
+        case RIL_E_INTERNAL_ERR: return "E_INTERNAL_ERR";
+        case RIL_E_SYSTEM_ERR: return "E_SYSTEM_ERR";
+        case RIL_E_MODEM_ERR: return "E_MODEM_ERR";
+        case RIL_E_INVALID_STATE: return "E_INVALID_STATE";
+        case RIL_E_NO_RESOURCES: return "E_NO_RESOURCES";
+        case RIL_E_SIM_ERR: return "E_SIM_ERR";
+        case RIL_E_INVALID_ARGUMENTS: return "E_INVALID_ARGUMENTS";
+        case RIL_E_INVALID_SIM_STATE: return "E_INVALID_SIM_STATE";
+        case RIL_E_INVALID_MODEM_STATE: return "E_INVALID_MODEM_STATE";
+        case RIL_E_INVALID_CALL_ID: return "E_INVALID_CALL_ID";
+        case RIL_E_NO_SMS_TO_ACK: return "E_NO_SMS_TO_ACK";
+        case RIL_E_NETWORK_ERR: return "E_NETWORK_ERR";
+        case RIL_E_REQUEST_RATE_LIMITED: return "E_REQUEST_RATE_LIMITED";
+        case RIL_E_SIM_BUSY: return "E_SIM_BUSY";
+        case RIL_E_SIM_FULL: return "E_SIM_FULL";
+        case RIL_E_NETWORK_REJECT: return "E_NETWORK_REJECT";
+        case RIL_E_OPERATION_NOT_ALLOWED: return "E_OPERATION_NOT_ALLOWED";
+        case RIL_E_EMPTY_RECORD: return "E_EMPTY_RECORD";
+        case RIL_E_INVALID_SMS_FORMAT: return "E_INVALID_SMS_FORMAT";
+        case RIL_E_ENCODING_ERR: return "E_ENCODING_ERR";
+        case RIL_E_INVALID_SMSC_ADDRESS: return "E_INVALID_SMSC_ADDRESS";
+        case RIL_E_NO_SUCH_ENTRY: return "E_NO_SUCH_ENTRY";
+        case RIL_E_NETWORK_NOT_READY: return "E_NETWORK_NOT_READY";
+        case RIL_E_NOT_PROVISIONED: return "E_NOT_PROVISIONED";
+        case RIL_E_NO_SUBSCRIPTION: return "E_NO_SUBSCRIPTION";
+        case RIL_E_NO_NETWORK_FOUND: return "E_NO_NETWORK_FOUND";
+        case RIL_E_DEVICE_IN_USE: return "E_DEVICE_IN_USE";
+        case RIL_E_ABORTED: return "E_ABORTED";
+        case RIL_E_INVALID_RESPONSE: return "INVALID_RESPONSE";
+        case RIL_E_OEM_ERROR_1: return "E_OEM_ERROR_1";
+        case RIL_E_OEM_ERROR_2: return "E_OEM_ERROR_2";
+        case RIL_E_OEM_ERROR_3: return "E_OEM_ERROR_3";
+        case RIL_E_OEM_ERROR_4: return "E_OEM_ERROR_4";
+        case RIL_E_OEM_ERROR_5: return "E_OEM_ERROR_5";
+        case RIL_E_OEM_ERROR_6: return "E_OEM_ERROR_6";
+        case RIL_E_OEM_ERROR_7: return "E_OEM_ERROR_7";
+        case RIL_E_OEM_ERROR_8: return "E_OEM_ERROR_8";
+        case RIL_E_OEM_ERROR_9: return "E_OEM_ERROR_9";
+        case RIL_E_OEM_ERROR_10: return "E_OEM_ERROR_10";
+        case RIL_E_OEM_ERROR_11: return "E_OEM_ERROR_11";
+        case RIL_E_OEM_ERROR_12: return "E_OEM_ERROR_12";
+        case RIL_E_OEM_ERROR_13: return "E_OEM_ERROR_13";
+        case RIL_E_OEM_ERROR_14: return "E_OEM_ERROR_14";
+        case RIL_E_OEM_ERROR_15: return "E_OEM_ERROR_15";
+        case RIL_E_OEM_ERROR_16: return "E_OEM_ERROR_16";
+        case RIL_E_OEM_ERROR_17: return "E_OEM_ERROR_17";
+        case RIL_E_OEM_ERROR_18: return "E_OEM_ERROR_18";
+        case RIL_E_OEM_ERROR_19: return "E_OEM_ERROR_19";
+        case RIL_E_OEM_ERROR_20: return "E_OEM_ERROR_20";
+        case RIL_E_OEM_ERROR_21: return "E_OEM_ERROR_21";
+        case RIL_E_OEM_ERROR_22: return "E_OEM_ERROR_22";
+        case RIL_E_OEM_ERROR_23: return "E_OEM_ERROR_23";
+        case RIL_E_OEM_ERROR_24: return "E_OEM_ERROR_24";
+        case RIL_E_OEM_ERROR_25: return "E_OEM_ERROR_25";
+        default: return "<unknown error>";
+    }
+}
+
+const char *
+radioStateToString(RIL_RadioState s) {
+    switch(s) {
+        case RADIO_STATE_OFF: return "RADIO_OFF";
+        case RADIO_STATE_UNAVAILABLE: return "RADIO_UNAVAILABLE";
+        case RADIO_STATE_ON:return"RADIO_ON";
+        default: return "<unknown state>";
+    }
+}
+
+const char *
+callStateToString(RIL_CallState s) {
+    switch(s) {
+        case RIL_CALL_ACTIVE : return "ACTIVE";
+        case RIL_CALL_HOLDING: return "HOLDING";
+        case RIL_CALL_DIALING: return "DIALING";
+        case RIL_CALL_ALERTING: return "ALERTING";
+        case RIL_CALL_INCOMING: return "INCOMING";
+        case RIL_CALL_WAITING: return "WAITING";
+        default: return "<unknown state>";
+    }
+}
+
+const char *
+requestToString(int request) {
+/*
+ cat guest/hals/ril/reference-libril/ril_commands.h \
+ | egrep "^ *{RIL_" \
+ | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/'
+
+
+ cat guest/hals/ril/reference-libril/ril_unsol_commands.h \
+ | egrep "^ *{RIL_" \
+ | sed -re 's/\{RIL_([^,]+),([^}]+).+/case RIL_\1: return "\1";/'
+
+*/
+    switch(request) {
+        case RIL_REQUEST_GET_SIM_STATUS: return "GET_SIM_STATUS";
+        case RIL_REQUEST_ENTER_SIM_PIN: return "ENTER_SIM_PIN";
+        case RIL_REQUEST_ENTER_SIM_PUK: return "ENTER_SIM_PUK";
+        case RIL_REQUEST_ENTER_SIM_PIN2: return "ENTER_SIM_PIN2";
+        case RIL_REQUEST_ENTER_SIM_PUK2: return "ENTER_SIM_PUK2";
+        case RIL_REQUEST_CHANGE_SIM_PIN: return "CHANGE_SIM_PIN";
+        case RIL_REQUEST_CHANGE_SIM_PIN2: return "CHANGE_SIM_PIN2";
+        case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: return "ENTER_NETWORK_DEPERSONALIZATION";
+        case RIL_REQUEST_GET_CURRENT_CALLS: return "GET_CURRENT_CALLS";
+        case RIL_REQUEST_DIAL: return "DIAL";
+        case RIL_REQUEST_GET_IMSI: return "GET_IMSI";
+        case RIL_REQUEST_HANGUP: return "HANGUP";
+        case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: return "HANGUP_WAITING_OR_BACKGROUND";
+        case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: return "HANGUP_FOREGROUND_RESUME_BACKGROUND";
+        case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: return "SWITCH_WAITING_OR_HOLDING_AND_ACTIVE";
+        case RIL_REQUEST_CONFERENCE: return "CONFERENCE";
+        case RIL_REQUEST_UDUB: return "UDUB";
+        case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: return "LAST_CALL_FAIL_CAUSE";
+        case RIL_REQUEST_SIGNAL_STRENGTH: return "SIGNAL_STRENGTH";
+        case RIL_REQUEST_VOICE_REGISTRATION_STATE: return "VOICE_REGISTRATION_STATE";
+        case RIL_REQUEST_DATA_REGISTRATION_STATE: return "DATA_REGISTRATION_STATE";
+        case RIL_REQUEST_OPERATOR: return "OPERATOR";
+        case RIL_REQUEST_RADIO_POWER: return "RADIO_POWER";
+        case RIL_REQUEST_DTMF: return "DTMF";
+        case RIL_REQUEST_SEND_SMS: return "SEND_SMS";
+        case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE";
+        case RIL_REQUEST_SETUP_DATA_CALL: return "SETUP_DATA_CALL";
+        case RIL_REQUEST_SIM_IO: return "SIM_IO";
+        case RIL_REQUEST_SEND_USSD: return "SEND_USSD";
+        case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD";
+        case RIL_REQUEST_GET_CLIR: return "GET_CLIR";
+        case RIL_REQUEST_SET_CLIR: return "SET_CLIR";
+        case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: return "QUERY_CALL_FORWARD_STATUS";
+        case RIL_REQUEST_SET_CALL_FORWARD: return "SET_CALL_FORWARD";
+        case RIL_REQUEST_QUERY_CALL_WAITING: return "QUERY_CALL_WAITING";
+        case RIL_REQUEST_SET_CALL_WAITING: return "SET_CALL_WAITING";
+        case RIL_REQUEST_SMS_ACKNOWLEDGE: return "SMS_ACKNOWLEDGE";
+        case RIL_REQUEST_GET_IMEI: return "GET_IMEI";
+        case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV";
+        case RIL_REQUEST_ANSWER: return "ANSWER";
+        case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "DEACTIVATE_DATA_CALL";
+        case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK";
+        case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK";
+        case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD";
+        case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: return "QUERY_NETWORK_SELECTION_MODE";
+        case RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS: return "RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS";
+        case RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS: return "RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS";
+        case RIL_REQUEST_START_NETWORK_SCAN: return "RIL_REQUEST_START_NETWORK_SCAN";
+        case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: return "SET_NETWORK_SELECTION_AUTOMATIC";
+        case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: return "SET_NETWORK_SELECTION_MANUAL";
+        case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: return "QUERY_AVAILABLE_NETWORKS";
+        case RIL_REQUEST_DTMF_START: return "DTMF_START";
+        case RIL_REQUEST_DTMF_STOP: return "DTMF_STOP";
+        case RIL_REQUEST_BASEBAND_VERSION: return "BASEBAND_VERSION";
+        case RIL_REQUEST_SEPARATE_CONNECTION: return "SEPARATE_CONNECTION";
+        case RIL_REQUEST_SET_MUTE: return "SET_MUTE";
+        case RIL_REQUEST_GET_MUTE: return "GET_MUTE";
+        case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP";
+        case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: return "LAST_DATA_CALL_FAIL_CAUSE";
+        case RIL_REQUEST_DATA_CALL_LIST: return "DATA_CALL_LIST";
+        case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO";
+        case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW";
+        case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS";
+        case RIL_REQUEST_SCREEN_STATE: return "SCREEN_STATE";
+        case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: return "SET_SUPP_SVC_NOTIFICATION";
+        case RIL_REQUEST_WRITE_SMS_TO_SIM: return "WRITE_SMS_TO_SIM";
+        case RIL_REQUEST_DELETE_SMS_ON_SIM: return "DELETE_SMS_ON_SIM";
+        case RIL_REQUEST_SET_BAND_MODE: return "SET_BAND_MODE";
+        case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: return "QUERY_AVAILABLE_BAND_MODE";
+        case RIL_REQUEST_STK_GET_PROFILE: return "STK_GET_PROFILE";
+        case RIL_REQUEST_STK_SET_PROFILE: return "STK_SET_PROFILE";
+        case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: return "STK_SEND_ENVELOPE_COMMAND";
+        case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: return "STK_SEND_TERMINAL_RESPONSE";
+        case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: return "STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM";
+        case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: return "EXPLICIT_CALL_TRANSFER";
+        case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: return "SET_PREFERRED_NETWORK_TYPE";
+        case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "GET_PREFERRED_NETWORK_TYPE";
+        case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "GET_NEIGHBORING_CELL_IDS";
+        case RIL_REQUEST_SET_LOCATION_UPDATES: return "SET_LOCATION_UPDATES";
+        case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: return "CDMA_SET_SUBSCRIPTION_SOURCE";
+        case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: return "CDMA_SET_ROAMING_PREFERENCE";
+        case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: return "CDMA_QUERY_ROAMING_PREFERENCE";
+        case RIL_REQUEST_SET_TTY_MODE: return "SET_TTY_MODE";
+        case RIL_REQUEST_QUERY_TTY_MODE: return "QUERY_TTY_MODE";
+        case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: return "CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE";
+        case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: return "CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE";
+        case RIL_REQUEST_CDMA_FLASH: return "CDMA_FLASH";
+        case RIL_REQUEST_CDMA_BURST_DTMF: return "CDMA_BURST_DTMF";
+        case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: return "CDMA_VALIDATE_AND_WRITE_AKEY";
+        case RIL_REQUEST_CDMA_SEND_SMS: return "CDMA_SEND_SMS";
+        case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: return "CDMA_SMS_ACKNOWLEDGE";
+        case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG: return "GSM_GET_BROADCAST_SMS_CONFIG";
+        case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG: return "GSM_SET_BROADCAST_SMS_CONFIG";
+        case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION: return "GSM_SMS_BROADCAST_ACTIVATION";
+        case RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG: return "CDMA_GET_BROADCAST_SMS_CONFIG";
+        case RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG: return "CDMA_SET_BROADCAST_SMS_CONFIG";
+        case RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION: return "CDMA_SMS_BROADCAST_ACTIVATION";
+        case RIL_REQUEST_CDMA_SUBSCRIPTION: return "CDMA_SUBSCRIPTION";
+        case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "CDMA_WRITE_SMS_TO_RUIM";
+        case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "CDMA_DELETE_SMS_ON_RUIM";
+        case RIL_REQUEST_DEVICE_IDENTITY: return "DEVICE_IDENTITY";
+        case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: return "EXIT_EMERGENCY_CALLBACK_MODE";
+        case RIL_REQUEST_GET_SMSC_ADDRESS: return "GET_SMSC_ADDRESS";
+        case RIL_REQUEST_SET_SMSC_ADDRESS: return "SET_SMSC_ADDRESS";
+        case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: return "REPORT_SMS_MEMORY_STATUS";
+        case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: return "REPORT_STK_SERVICE_IS_RUNNING";
+        case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE: return "CDMA_GET_SUBSCRIPTION_SOURCE";
+        case RIL_REQUEST_ISIM_AUTHENTICATION: return "ISIM_AUTHENTICATION";
+        case RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU: return "ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU";
+        case RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS: return "STK_SEND_ENVELOPE_WITH_STATUS";
+        case RIL_REQUEST_VOICE_RADIO_TECH: return "VOICE_RADIO_TECH";
+        case RIL_REQUEST_GET_CELL_INFO_LIST: return "GET_CELL_INFO_LIST";
+        case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE: return "SET_UNSOL_CELL_INFO_LIST_RATE";
+        case RIL_REQUEST_SET_INITIAL_ATTACH_APN: return "SET_INITIAL_ATTACH_APN";
+        case RIL_REQUEST_IMS_REGISTRATION_STATE: return "IMS_REGISTRATION_STATE";
+        case RIL_REQUEST_IMS_SEND_SMS: return "IMS_SEND_SMS";
+        case RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC: return "SIM_TRANSMIT_APDU_BASIC";
+        case RIL_REQUEST_SIM_OPEN_CHANNEL: return "SIM_OPEN_CHANNEL";
+        case RIL_REQUEST_SIM_CLOSE_CHANNEL: return "SIM_CLOSE_CHANNEL";
+        case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL: return "SIM_TRANSMIT_APDU_CHANNEL";
+        case RIL_REQUEST_NV_READ_ITEM: return "NV_READ_ITEM";
+        case RIL_REQUEST_NV_WRITE_ITEM: return "NV_WRITE_ITEM";
+        case RIL_REQUEST_NV_WRITE_CDMA_PRL: return "NV_WRITE_CDMA_PRL";
+        case RIL_REQUEST_NV_RESET_CONFIG: return "NV_RESET_CONFIG";
+        case RIL_REQUEST_SET_UICC_SUBSCRIPTION: return "SET_UICC_SUBSCRIPTION";
+        case RIL_REQUEST_ALLOW_DATA: return "ALLOW_DATA";
+        case RIL_REQUEST_GET_HARDWARE_CONFIG: return "GET_HARDWARE_CONFIG";
+        case RIL_REQUEST_SIM_AUTHENTICATION: return "SIM_AUTHENTICATION";
+        case RIL_REQUEST_GET_DC_RT_INFO: return "GET_DC_RT_INFO";
+        case RIL_REQUEST_SET_DC_RT_INFO_RATE: return "SET_DC_RT_INFO_RATE";
+        case RIL_REQUEST_SET_DATA_PROFILE: return "SET_DATA_PROFILE";
+        case RIL_REQUEST_SHUTDOWN: return "SHUTDOWN";
+        case RIL_REQUEST_GET_RADIO_CAPABILITY: return "GET_RADIO_CAPABILITY";
+        case RIL_REQUEST_SET_RADIO_CAPABILITY: return "SET_RADIO_CAPABILITY";
+        case RIL_REQUEST_START_LCE: return "START_LCE";
+        case RIL_REQUEST_STOP_LCE: return "STOP_LCE";
+        case RIL_REQUEST_PULL_LCEDATA: return "PULL_LCEDATA";
+        case RIL_REQUEST_GET_ACTIVITY_INFO: return "GET_ACTIVITY_INFO";
+        case RIL_REQUEST_SET_CARRIER_RESTRICTIONS: return "SET_CARRIER_RESTRICTIONS";
+        case RIL_REQUEST_GET_CARRIER_RESTRICTIONS: return "GET_CARRIER_RESTRICTIONS";
+        case RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION: return "SET_CARRIER_INFO_IMSI_ENCRYPTION";
+        case RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA: return "SET_SIGNAL_STRENGTH_REPORTING_CRITERIA";
+        case RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA: return "SET_LINK_CAPACITY_REPORTING_CRITERIA";
+        case RIL_REQUEST_ENABLE_UICC_APPLICATIONS: return "ENABLE_UICC_APPLICATIONS";
+        case RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED: return "ARE_UICC_APPLICATIONS_ENABLED";
+        case RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION: return "ENTER_SIM_DEPERSONALIZATION";
+        case RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE: return "CDMA_SEND_SMS_EXPECT_MORE";
+        case RIL_REQUEST_GET_BARRING_INFO: return "GET_BARRING_INFO";
+        case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP: return "SET_PREFERRED_NETWORK_TYPE_BITMAP";
+        case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP: return "GET_PREFERRED_NETWORK_TYPE_BITMAP";
+        case RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP: return "SET_ALLOWED_NETWORK_TYPES_BITMAP";
+        case RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP: return "GET_ALLOWED_NETWORK_TYPES_BITMAP";
+        case RIL_REQUEST_GET_SLICING_CONFIG: return "GET_SLICING_CONFIG";
+        case RIL_RESPONSE_ACKNOWLEDGEMENT: return "RESPONSE_ACKNOWLEDGEMENT";
+        case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
+        case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
+        case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED";
+        case RIL_UNSOL_RESPONSE_NEW_SMS: return "UNSOL_RESPONSE_NEW_SMS";
+        case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: return "UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT";
+        case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: return "UNSOL_RESPONSE_NEW_SMS_ON_SIM";
+        case RIL_UNSOL_ON_USSD: return "UNSOL_ON_USSD";
+        case RIL_UNSOL_ON_USSD_REQUEST: return "UNSOL_ON_USSD_REQUEST";
+        case RIL_UNSOL_NITZ_TIME_RECEIVED: return "UNSOL_NITZ_TIME_RECEIVED";
+        case RIL_UNSOL_SIGNAL_STRENGTH: return "UNSOL_SIGNAL_STRENGTH";
+        case RIL_UNSOL_DATA_CALL_LIST_CHANGED: return "UNSOL_DATA_CALL_LIST_CHANGED";
+        case RIL_UNSOL_SUPP_SVC_NOTIFICATION: return "UNSOL_SUPP_SVC_NOTIFICATION";
+        case RIL_UNSOL_STK_SESSION_END: return "UNSOL_STK_SESSION_END";
+        case RIL_UNSOL_STK_PROACTIVE_COMMAND: return "UNSOL_STK_PROACTIVE_COMMAND";
+        case RIL_UNSOL_STK_EVENT_NOTIFY: return "UNSOL_STK_EVENT_NOTIFY";
+        case RIL_UNSOL_STK_CALL_SETUP: return "UNSOL_STK_CALL_SETUP";
+        case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL";
+        case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH";
+        case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING";
+        case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: return "UNSOL_RESPONSE_SIM_STATUS_CHANGED";
+        case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: return "UNSOL_RESPONSE_CDMA_NEW_SMS";
+        case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: return "UNSOL_RESPONSE_NEW_BROADCAST_SMS";
+        case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: return "UNSOL_CDMA_RUIM_SMS_STORAGE_FULL";
+        case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "UNSOL_RESTRICTED_STATE_CHANGED";
+        case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: return "UNSOL_ENTER_EMERGENCY_CALLBACK_MODE";
+        case RIL_UNSOL_CDMA_CALL_WAITING: return "UNSOL_CDMA_CALL_WAITING";
+        case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: return "UNSOL_CDMA_OTA_PROVISION_STATUS";
+        case RIL_UNSOL_CDMA_INFO_REC: return "UNSOL_CDMA_INFO_REC";
+        case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW";
+        case RIL_UNSOL_RINGBACK_TONE: return "UNSOL_RINGBACK_TONE";
+        case RIL_UNSOL_RESEND_INCALL_MUTE: return "UNSOL_RESEND_INCALL_MUTE";
+        case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED: return "UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED";
+        case RIL_UNSOL_CDMA_PRL_CHANGED: return "UNSOL_CDMA_PRL_CHANGED";
+        case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: return "UNSOL_EXIT_EMERGENCY_CALLBACK_MODE";
+        case RIL_UNSOL_RIL_CONNECTED: return "UNSOL_RIL_CONNECTED";
+        case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED: return "UNSOL_VOICE_RADIO_TECH_CHANGED";
+        case RIL_UNSOL_CELL_INFO_LIST: return "UNSOL_CELL_INFO_LIST";
+        case RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED";
+        case RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED: return "UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED";
+        case RIL_UNSOL_SRVCC_STATE_NOTIFY: return "UNSOL_SRVCC_STATE_NOTIFY";
+        case RIL_UNSOL_HARDWARE_CONFIG_CHANGED: return "UNSOL_HARDWARE_CONFIG_CHANGED";
+        case RIL_UNSOL_DC_RT_INFO_CHANGED: return "UNSOL_DC_RT_INFO_CHANGED";
+        case RIL_UNSOL_RADIO_CAPABILITY: return "UNSOL_RADIO_CAPABILITY";
+        case RIL_UNSOL_MODEM_RESTART: return "UNSOL_MODEM_RESTART";
+        case RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION: return "UNSOL_CARRIER_INFO_IMSI_ENCRYPTION";
+        case RIL_UNSOL_ON_SS: return "UNSOL_ON_SS";
+        case RIL_UNSOL_STK_CC_ALPHA_NOTIFY: return "UNSOL_STK_CC_ALPHA_NOTIFY";
+        case RIL_UNSOL_LCEDATA_RECV: return "UNSOL_LCEDATA_RECV";
+        case RIL_UNSOL_PCO_DATA: return "UNSOL_PCO_DATA";
+        default: return "<unknown request>";
+    }
+}
+
+const char *
+rilSocketIdToString(RIL_SOCKET_ID socket_id)
+{
+    switch(socket_id) {
+        case RIL_SOCKET_1:
+            return "RIL_SOCKET_1";
+#if (SIM_COUNT >= 2)
+        case RIL_SOCKET_2:
+            return "RIL_SOCKET_2";
+#endif
+#if (SIM_COUNT >= 3)
+        case RIL_SOCKET_3:
+            return "RIL_SOCKET_3";
+#endif
+#if (SIM_COUNT >= 4)
+        case RIL_SOCKET_4:
+            return "RIL_SOCKET_4";
+#endif
+        default:
+            return "not a valid RIL";
+    }
+}
+
+} /* namespace android */
diff --git a/guest/hals/ril/reference-libril/ril.h b/guest/hals/ril/reference-libril/ril.h
new file mode 100644
index 0000000..586de42
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril.h
@@ -0,0 +1,8710 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef ANDROID_RIL_H
+#define ANDROID_RIL_H 1
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <telephony/ril_cdma_sms.h>
+#include <telephony/ril_nv_items.h>
+#include <telephony/ril_msim.h>
+
+#ifndef FEATURE_UNIT_TEST
+#include <sys/time.h>
+#endif /* !FEATURE_UNIT_TEST */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SIM_COUNT
+#if defined(ANDROID_SIM_COUNT_2)
+#define SIM_COUNT 2
+#elif defined(ANDROID_SIM_COUNT_3)
+#define SIM_COUNT 3
+#elif defined(ANDROID_SIM_COUNT_4)
+#define SIM_COUNT 4
+#else
+#define SIM_COUNT 1
+#endif
+
+#ifndef ANDROID_MULTI_SIM
+#define SIM_COUNT 1
+#endif
+#endif
+
+/*
+ * RIL version.
+ * Value of RIL_VERSION should not be changed in future. Here onwards,
+ * when a new change is supposed to be introduced  which could involve new
+ * schemes added like Wakelocks, data structures added/updated, etc, we would
+ * just document RIL version associated with that change below. When OEM updates
+ * its RIL with those changes, they would return that new RIL version during
+ * RIL_REGISTER. We should make use of the returned version by vendor to
+ * identify appropriate scheme or data structure version to use.
+ *
+ * Documentation of RIL version and associated changes
+ * RIL_VERSION = 12 : Updated data structures: RIL_Data_Call_Response_v11,
+ *                    RIL_SIM_IO_v6, RIL_CardStatus_v6,
+ *                    RIL_SimRefreshResponse_v7, RIL_CDMA_CallWaiting_v6,
+ *                    RIL_LTE_SignalStrength_v8, RIL_SignalStrength_v10,
+ *                    RIL_CellIdentityGsm_v12, RIL_CellIdentityWcdma_v12,
+ *                    RIL_CellIdentityLte_v12, RIL_CellInfoGsm_v12,
+ *                    RIL_CellInfoWcdma_v12, RIL_CellInfoLte_v12,
+ *                    RIL_CellInfo_v12
+ *
+ * RIL_VERSION = 13 : This version includes new wakelock semantics and as the
+ *                    first strongly versioned version it enforces structure
+ *                    use.
+ *
+ * RIL_VERSION = 14 : New commands added:
+ *                    RIL_REQUEST_SET_CARRIER_RESTRICTIONS,
+ *                    RIL_REQUEST_SET_CARRIER_RESTRICTIONS,
+ *                    RIL_UNSOL_PCO_DATA
+ *                    New data structures are added: RIL_CarrierMatchType,
+ *                    RIL_Carrier, RIL_CarrierRestrictions, RIL_PCO_Data
+ *
+ *
+ * RIL_VERSION = 15 : New commands added:
+ *                    RIL_UNSOL_MODEM_RESTART,
+ *                    RIL_REQUEST_SEND_DEVICE_STATE,
+ *                    RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER,
+ *                    RIL_REQUEST_SET_SIM_CARD_POWER,
+ *                    RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION,
+ *                    RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION
+ *                    RIL_REQUEST_START_NETWORK_SCAN
+ *                    RIL_REQUEST_STOP_NETWORK_SCAN
+ *                    RIL_UNSOL_NETWORK_SCAN_RESULT
+ *                    RIL_REQUEST_GET_MODEM_STACK_STATUS
+ *                    RIL_REQUEST_ENABLE_MODEM
+ *                    RIL_REQUEST_EMERGENCY_DIAL
+ *                    RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS
+ *                    RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA
+ *                    RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA
+ *                    RIL_REQUEST_ENABLE_UICC_APPLICATIONS
+ *                    RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED
+ *                    RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION
+ *                    RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE
+ *                    New parameters for RIL_REQUEST_SETUP_DATA_CALL
+ *                    Updated data structures: RIL_DataProfileInfo_v15,
+ *                    RIL_InitialAttachApn_v15, RIL_Data_Call_Response_v12
+ *                    New data structures: RIL_DataRegistrationStateResponse,
+ *                    RIL_OpenChannelParams,
+ *                    RIL_VoiceRegistrationStateResponse same is used in
+ *                    RIL_REQUEST_DATA_REGISTRATION_STATE and
+ *                    RIL_REQUEST_VOICE_REGISTRATION_STATE respectively.
+ * RIL_VERSION = 16 : New commands added:
+ *                    RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY
+ *                    RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED
+ *                    RIL_REQUEST_ALLOCATE_PDU_SESSION_ID
+ *                    RIL_REQUEST_RELEASE_PDU_SESSION_ID
+ *                    RIL_REQUEST_START_HANDOVER
+ *                    RIL_REQUEST_CANCEL_HANDOVER
+ *                    RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP
+ *                    RIL_REQUEST_SET_DATA_THROTTLING
+ *                    RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS
+ *                    RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP
+ *                    RIL_REQUEST_GET_SLICING_CONFIG
+ *                    New parameters for RIL_REQUEST_SETUP_DATA_CALL
+ *                    Updated data structures: RIL_CarrierInfoForImsiEncryption_v16
+ *                    New data structure: RIL_PublicKeyType
+ */
+#define RIL_VERSION 16
+#define LAST_IMPRECISE_RIL_VERSION 12 // Better self-documented name
+#define RIL_VERSION_MIN 6 /* Minimum RIL_VERSION supported */
+
+#define CDMA_ALPHA_INFO_BUFFER_LENGTH 64
+#define CDMA_NUMBER_INFO_BUFFER_LENGTH 81
+
+#define MAX_RILDS 3
+#define MAX_SERVICE_NAME_LENGTH 6
+#define MAX_CLIENT_ID_LENGTH 2
+#define MAX_DEBUG_SOCKET_NAME_LENGTH 12
+#define MAX_QEMU_PIPE_NAME_LENGTH  11
+#define MAX_UUID_LENGTH 64
+#define MAX_BANDS 8
+#define MAX_CHANNELS 32
+#define MAX_RADIO_ACCESS_NETWORKS 8
+#define MAX_BROADCAST_SMS_CONFIG_INFO 25
+
+#define RIL_RADIO_ACCESS_SPECIFIER_MAX_SIZE 8
+
+typedef void * RIL_Token;
+
+typedef enum {
+    RIL_SOCKET_1,
+#if (SIM_COUNT >= 2)
+    RIL_SOCKET_2,
+#if (SIM_COUNT >= 3)
+    RIL_SOCKET_3,
+#endif
+#if (SIM_COUNT >= 4)
+    RIL_SOCKET_4,
+#endif
+#endif
+    RIL_SOCKET_NUM
+} RIL_SOCKET_ID;
+
+
+typedef enum {
+    RIL_E_SUCCESS = 0,
+    RIL_E_RADIO_NOT_AVAILABLE = 1,     /* If radio did not start or is resetting */
+    RIL_E_GENERIC_FAILURE = 2,
+    RIL_E_PASSWORD_INCORRECT = 3,      /* for PIN/PIN2 methods only! */
+    RIL_E_SIM_PIN2 = 4,                /* Operation requires SIM PIN2 to be entered */
+    RIL_E_SIM_PUK2 = 5,                /* Operation requires SIM PIN2 to be entered */
+    RIL_E_REQUEST_NOT_SUPPORTED = 6,
+    RIL_E_CANCELLED = 7,
+    RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8, /* data ops are not allowed during voice
+                                                   call on a Class C GPRS device */
+    RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,  /* data ops are not allowed before device
+                                                   registers in network */
+    RIL_E_SMS_SEND_FAIL_RETRY = 10,             /* fail to send sms and need retry */
+    RIL_E_SIM_ABSENT = 11,                      /* fail to set the location where CDMA subscription
+                                                   shall be retrieved because of SIM or RUIM
+                                                   card absent */
+    RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,      /* fail to find CDMA subscription from specified
+                                                   location */
+    RIL_E_MODE_NOT_SUPPORTED = 13,              /* HW does not support preferred network type */
+    RIL_E_FDN_CHECK_FAILURE = 14,               /* command failed because recipient is not on FDN list */
+    RIL_E_ILLEGAL_SIM_OR_ME = 15,               /* network selection failed due to
+                                                   illegal SIM or ME */
+    RIL_E_MISSING_RESOURCE = 16,                /* no logical channel available */
+    RIL_E_NO_SUCH_ELEMENT = 17,                  /* application not found on SIM */
+    RIL_E_DIAL_MODIFIED_TO_USSD = 18,           /* DIAL request modified to USSD */
+    RIL_E_DIAL_MODIFIED_TO_SS = 19,             /* DIAL request modified to SS */
+    RIL_E_DIAL_MODIFIED_TO_DIAL = 20,           /* DIAL request modified to DIAL with different
+                                                   data */
+    RIL_E_USSD_MODIFIED_TO_DIAL = 21,           /* USSD request modified to DIAL */
+    RIL_E_USSD_MODIFIED_TO_SS = 22,             /* USSD request modified to SS */
+    RIL_E_USSD_MODIFIED_TO_USSD = 23,           /* USSD request modified to different USSD
+                                                   request */
+    RIL_E_SS_MODIFIED_TO_DIAL = 24,             /* SS request modified to DIAL */
+    RIL_E_SS_MODIFIED_TO_USSD = 25,             /* SS request modified to USSD */
+    RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,      /* Subscription not supported by RIL */
+    RIL_E_SS_MODIFIED_TO_SS = 27,               /* SS request modified to different SS request */
+    RIL_E_LCE_NOT_SUPPORTED = 36,               /* LCE service not supported(36 in RILConstants.java) */
+    RIL_E_NO_MEMORY = 37,                       /* Not sufficient memory to process the request */
+    RIL_E_INTERNAL_ERR = 38,                    /* Modem hit unexpected error scenario while handling
+                                                   this request */
+    RIL_E_SYSTEM_ERR = 39,                      /* Hit platform or system error */
+    RIL_E_MODEM_ERR = 40,                       /* Vendor RIL got unexpected or incorrect response
+                                                   from modem for this request */
+    RIL_E_INVALID_STATE = 41,                   /* Unexpected request for the current state */
+    RIL_E_NO_RESOURCES = 42,                    /* Not sufficient resource to process the request */
+    RIL_E_SIM_ERR = 43,                         /* Received error from SIM card */
+    RIL_E_INVALID_ARGUMENTS = 44,               /* Received invalid arguments in request */
+    RIL_E_INVALID_SIM_STATE = 45,               /* Can not process the request in current SIM state */
+    RIL_E_INVALID_MODEM_STATE = 46,             /* Can not process the request in current Modem state */
+    RIL_E_INVALID_CALL_ID = 47,                 /* Received invalid call id in request */
+    RIL_E_NO_SMS_TO_ACK = 48,                   /* ACK received when there is no SMS to ack */
+    RIL_E_NETWORK_ERR = 49,                     /* Received error from network */
+    RIL_E_REQUEST_RATE_LIMITED = 50,            /* Operation denied due to overly-frequent requests */
+    RIL_E_SIM_BUSY = 51,                        /* SIM is busy */
+    RIL_E_SIM_FULL = 52,                        /* The target EF is full */
+    RIL_E_NETWORK_REJECT = 53,                  /* Request is rejected by network */
+    RIL_E_OPERATION_NOT_ALLOWED = 54,           /* Not allowed the request now */
+    RIL_E_EMPTY_RECORD = 55,                    /* The request record is empty */
+    RIL_E_INVALID_SMS_FORMAT = 56,              /* Invalid sms format */
+    RIL_E_ENCODING_ERR = 57,                    /* Message not encoded properly */
+    RIL_E_INVALID_SMSC_ADDRESS = 58,            /* SMSC address specified is invalid */
+    RIL_E_NO_SUCH_ENTRY = 59,                   /* No such entry present to perform the request */
+    RIL_E_NETWORK_NOT_READY = 60,               /* Network is not ready to perform the request */
+    RIL_E_NOT_PROVISIONED = 61,                 /* Device doesnot have this value provisioned */
+    RIL_E_NO_SUBSCRIPTION = 62,                 /* Device doesnot have subscription */
+    RIL_E_NO_NETWORK_FOUND = 63,                /* Network cannot be found */
+    RIL_E_DEVICE_IN_USE = 64,                   /* Operation cannot be performed because the device
+                                                   is currently in use */
+    RIL_E_ABORTED = 65,                         /* Operation aborted */
+    RIL_E_INVALID_RESPONSE = 66,                /* Invalid response sent by vendor code */
+    // OEM specific error codes. To be used by OEM when they don't want to reveal
+    // specific error codes which would be replaced by Generic failure.
+    RIL_E_OEM_ERROR_1 = 501,
+    RIL_E_OEM_ERROR_2 = 502,
+    RIL_E_OEM_ERROR_3 = 503,
+    RIL_E_OEM_ERROR_4 = 504,
+    RIL_E_OEM_ERROR_5 = 505,
+    RIL_E_OEM_ERROR_6 = 506,
+    RIL_E_OEM_ERROR_7 = 507,
+    RIL_E_OEM_ERROR_8 = 508,
+    RIL_E_OEM_ERROR_9 = 509,
+    RIL_E_OEM_ERROR_10 = 510,
+    RIL_E_OEM_ERROR_11 = 511,
+    RIL_E_OEM_ERROR_12 = 512,
+    RIL_E_OEM_ERROR_13 = 513,
+    RIL_E_OEM_ERROR_14 = 514,
+    RIL_E_OEM_ERROR_15 = 515,
+    RIL_E_OEM_ERROR_16 = 516,
+    RIL_E_OEM_ERROR_17 = 517,
+    RIL_E_OEM_ERROR_18 = 518,
+    RIL_E_OEM_ERROR_19 = 519,
+    RIL_E_OEM_ERROR_20 = 520,
+    RIL_E_OEM_ERROR_21 = 521,
+    RIL_E_OEM_ERROR_22 = 522,
+    RIL_E_OEM_ERROR_23 = 523,
+    RIL_E_OEM_ERROR_24 = 524,
+    RIL_E_OEM_ERROR_25 = 525
+} RIL_Errno;
+
+typedef enum {
+    RIL_CALL_ACTIVE = 0,
+    RIL_CALL_HOLDING = 1,
+    RIL_CALL_DIALING = 2,    /* MO call only */
+    RIL_CALL_ALERTING = 3,   /* MO call only */
+    RIL_CALL_INCOMING = 4,   /* MT call only */
+    RIL_CALL_WAITING = 5     /* MT call only */
+} RIL_CallState;
+
+typedef enum {
+    RADIO_STATE_OFF = 0,                   /* Radio explictly powered off (eg CFUN=0) */
+    RADIO_STATE_UNAVAILABLE = 1,           /* Radio unavailable (eg, resetting or not booted) */
+    RADIO_STATE_ON = 10                    /* Radio is on */
+} RIL_RadioState;
+
+typedef enum {
+    RADIO_TECH_UNKNOWN = 0,
+    RADIO_TECH_GPRS = 1,
+    RADIO_TECH_EDGE = 2,
+    RADIO_TECH_UMTS = 3,
+    RADIO_TECH_IS95A = 4,
+    RADIO_TECH_IS95B = 5,
+    RADIO_TECH_1xRTT =  6,
+    RADIO_TECH_EVDO_0 = 7,
+    RADIO_TECH_EVDO_A = 8,
+    RADIO_TECH_HSDPA = 9,
+    RADIO_TECH_HSUPA = 10,
+    RADIO_TECH_HSPA = 11,
+    RADIO_TECH_EVDO_B = 12,
+    RADIO_TECH_EHRPD = 13,
+    RADIO_TECH_LTE = 14,
+    RADIO_TECH_HSPAP = 15, // HSPA+
+    RADIO_TECH_GSM = 16, // Only supports voice
+    RADIO_TECH_TD_SCDMA = 17,
+    RADIO_TECH_IWLAN = 18,
+    RADIO_TECH_LTE_CA = 19,
+    RADIO_TECH_NR = 20
+} RIL_RadioTechnology;
+
+typedef enum {
+    RAF_UNKNOWN =  (1 <<  RADIO_TECH_UNKNOWN),
+    RAF_GPRS = (1 << RADIO_TECH_GPRS),
+    RAF_EDGE = (1 << RADIO_TECH_EDGE),
+    RAF_UMTS = (1 << RADIO_TECH_UMTS),
+    RAF_IS95A = (1 << RADIO_TECH_IS95A),
+    RAF_IS95B = (1 << RADIO_TECH_IS95B),
+    RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
+    RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
+    RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
+    RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
+    RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
+    RAF_HSPA = (1 << RADIO_TECH_HSPA),
+    RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
+    RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
+    RAF_LTE = (1 << RADIO_TECH_LTE),
+    RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
+    RAF_GSM = (1 << RADIO_TECH_GSM),
+    RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
+    RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA),
+    RAF_NR = (1 << RADIO_TECH_NR)
+} RIL_RadioAccessFamily;
+
+typedef enum {
+    BAND_MODE_UNSPECIFIED = 0,      //"unspecified" (selected by baseband automatically)
+    BAND_MODE_EURO = 1,             //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
+    BAND_MODE_USA = 2,              //"US band" (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
+    BAND_MODE_JPN = 3,              //"JPN band" (WCDMA-800 / WCDMA-IMT-2000)
+    BAND_MODE_AUS = 4,              //"AUS band" (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
+    BAND_MODE_AUS_2 = 5,            //"AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
+    BAND_MODE_CELL_800 = 6,         //"Cellular" (800-MHz Band)
+    BAND_MODE_PCS = 7,              //"PCS" (1900-MHz Band)
+    BAND_MODE_JTACS = 8,            //"Band Class 3" (JTACS Band)
+    BAND_MODE_KOREA_PCS = 9,        //"Band Class 4" (Korean PCS Band)
+    BAND_MODE_5_450M = 10,          //"Band Class 5" (450-MHz Band)
+    BAND_MODE_IMT2000 = 11,         //"Band Class 6" (2-GMHz IMT2000 Band)
+    BAND_MODE_7_700M_2 = 12,        //"Band Class 7" (Upper 700-MHz Band)
+    BAND_MODE_8_1800M = 13,         //"Band Class 8" (1800-MHz Band)
+    BAND_MODE_9_900M = 14,          //"Band Class 9" (900-MHz Band)
+    BAND_MODE_10_800M_2 = 15,       //"Band Class 10" (Secondary 800-MHz Band)
+    BAND_MODE_EURO_PAMR_400M = 16,  //"Band Class 11" (400-MHz European PAMR Band)
+    BAND_MODE_AWS = 17,             //"Band Class 15" (AWS Band)
+    BAND_MODE_USA_2500M = 18        //"Band Class 16" (US 2.5-GHz Band)
+} RIL_RadioBandMode;
+
+typedef enum {
+    RC_PHASE_CONFIGURED = 0,  // LM is configured is initial value and value after FINISH completes
+    RC_PHASE_START      = 1,  // START is sent before Apply and indicates that an APPLY will be
+                              // forthcoming with these same parameters
+    RC_PHASE_APPLY      = 2,  // APPLY is sent after all LM's receive START and returned
+                              // RIL_RadioCapability.status = 0, if any START's fail no
+                              // APPLY will be sent
+    RC_PHASE_UNSOL_RSP  = 3,  // UNSOL_RSP is sent with RIL_UNSOL_RADIO_CAPABILITY
+    RC_PHASE_FINISH     = 4   // FINISH is sent after all commands have completed. If an error
+                              // occurs in any previous command the RIL_RadioAccessesFamily and
+                              // logicalModemUuid fields will be the prior configuration thus
+                              // restoring the configuration to the previous value. An error
+                              // returned by this command will generally be ignored or may
+                              // cause that logical modem to be removed from service.
+} RadioCapabilityPhase;
+
+typedef enum {
+    RC_STATUS_NONE       = 0, // This parameter has no meaning with RC_PHASE_START,
+                              // RC_PHASE_APPLY
+    RC_STATUS_SUCCESS    = 1, // Tell modem the action transaction of set radio
+                              // capability was success with RC_PHASE_FINISH
+    RC_STATUS_FAIL       = 2, // Tell modem the action transaction of set radio
+                              // capability is fail with RC_PHASE_FINISH.
+} RadioCapabilityStatus;
+
+#define RIL_RADIO_CAPABILITY_VERSION 1
+typedef struct {
+    int version;            // Version of structure, RIL_RADIO_CAPABILITY_VERSION
+    int session;            // Unique session value defined by framework returned in all "responses/unsol"
+    int phase;              // CONFIGURED, START, APPLY, FINISH
+    int rat;                // RIL_RadioAccessFamily for the radio
+    char logicalModemUuid[MAX_UUID_LENGTH]; // A UUID typically "com.xxxx.lmX where X is the logical modem.
+    int status;             // Return status and an input parameter for RC_PHASE_FINISH
+} RIL_RadioCapability;
+
+// Do we want to split Data from Voice and the use
+// RIL_RadioTechnology for get/setPreferredVoice/Data ?
+typedef enum {
+    PREF_NET_TYPE_GSM_WCDMA                = 0, /* GSM/WCDMA (WCDMA preferred) */
+    PREF_NET_TYPE_GSM_ONLY                 = 1, /* GSM only */
+    PREF_NET_TYPE_WCDMA                    = 2, /* WCDMA  */
+    PREF_NET_TYPE_GSM_WCDMA_AUTO           = 3, /* GSM/WCDMA (auto mode, according to PRL) */
+    PREF_NET_TYPE_CDMA_EVDO_AUTO           = 4, /* CDMA and EvDo (auto mode, according to PRL) */
+    PREF_NET_TYPE_CDMA_ONLY                = 5, /* CDMA only */
+    PREF_NET_TYPE_EVDO_ONLY                = 6, /* EvDo only */
+    PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7, /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) */
+    PREF_NET_TYPE_LTE_CDMA_EVDO            = 8, /* LTE, CDMA and EvDo */
+    PREF_NET_TYPE_LTE_GSM_WCDMA            = 9, /* LTE, GSM/WCDMA */
+    PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA  = 10, /* LTE, CDMA, EvDo, GSM/WCDMA */
+    PREF_NET_TYPE_LTE_ONLY                 = 11, /* LTE only */
+    PREF_NET_TYPE_LTE_WCDMA                = 12,  /* LTE/WCDMA */
+    PREF_NET_TYPE_TD_SCDMA_ONLY            = 13, /* TD-SCDMA only */
+    PREF_NET_TYPE_TD_SCDMA_WCDMA           = 14, /* TD-SCDMA and WCDMA */
+    PREF_NET_TYPE_TD_SCDMA_LTE             = 15, /* TD-SCDMA and LTE */
+    PREF_NET_TYPE_TD_SCDMA_GSM             = 16, /* TD-SCDMA and GSM */
+    PREF_NET_TYPE_TD_SCDMA_GSM_LTE         = 17, /* TD-SCDMA,GSM and LTE */
+    PREF_NET_TYPE_TD_SCDMA_GSM_WCDMA       = 18, /* TD-SCDMA, GSM/WCDMA */
+    PREF_NET_TYPE_TD_SCDMA_WCDMA_LTE       = 19, /* TD-SCDMA, WCDMA and LTE */
+    PREF_NET_TYPE_TD_SCDMA_GSM_WCDMA_LTE   = 20, /* TD-SCDMA, GSM/WCDMA and LTE */
+    PREF_NET_TYPE_TD_SCDMA_GSM_WCDMA_CDMA_EVDO_AUTO  = 21, /* TD-SCDMA, GSM/WCDMA, CDMA and EvDo */
+    PREF_NET_TYPE_TD_SCDMA_LTE_CDMA_EVDO_GSM_WCDMA   = 22  /* TD-SCDMA, LTE, CDMA, EvDo GSM/WCDMA */
+} RIL_PreferredNetworkType;
+
+/* Source for cdma subscription */
+typedef enum {
+   CDMA_SUBSCRIPTION_SOURCE_RUIM_SIM = 0,
+   CDMA_SUBSCRIPTION_SOURCE_NV = 1
+} RIL_CdmaSubscriptionSource;
+
+/* User-to-User signaling Info activation types derived from 3GPP 23.087 v8.0 */
+typedef enum {
+    RIL_UUS_TYPE1_IMPLICIT = 0,
+    RIL_UUS_TYPE1_REQUIRED = 1,
+    RIL_UUS_TYPE1_NOT_REQUIRED = 2,
+    RIL_UUS_TYPE2_REQUIRED = 3,
+    RIL_UUS_TYPE2_NOT_REQUIRED = 4,
+    RIL_UUS_TYPE3_REQUIRED = 5,
+    RIL_UUS_TYPE3_NOT_REQUIRED = 6
+} RIL_UUS_Type;
+
+/* User-to-User Signaling Information data coding schemes. Possible values for
+ * Octet 3 (Protocol Discriminator field) in the UUIE. The values have been
+ * specified in section 10.5.4.25 of 3GPP TS 24.008 */
+typedef enum {
+    RIL_UUS_DCS_USP = 0,          /* User specified protocol */
+    RIL_UUS_DCS_OSIHLP = 1,       /* OSI higher layer protocol */
+    RIL_UUS_DCS_X244 = 2,         /* X.244 */
+    RIL_UUS_DCS_RMCF = 3,         /* Reserved for system mangement
+                                     convergence function */
+    RIL_UUS_DCS_IA5c = 4          /* IA5 characters */
+} RIL_UUS_DCS;
+
+/* User-to-User Signaling Information defined in 3GPP 23.087 v8.0
+ * This data is passed in RIL_ExtensionRecord and rec contains this
+ * structure when type is RIL_UUS_INFO_EXT_REC */
+typedef struct {
+  RIL_UUS_Type    uusType;    /* UUS Type */
+  RIL_UUS_DCS     uusDcs;     /* UUS Data Coding Scheme */
+  int             uusLength;  /* Length of UUS Data */
+  char *          uusData;    /* UUS Data */
+} RIL_UUS_Info;
+
+/* CDMA Signal Information Record as defined in C.S0005 section 3.7.5.5 */
+typedef struct {
+  char isPresent;    /* non-zero if signal information record is present */
+  char signalType;   /* as defined 3.7.5.5-1 */
+  char alertPitch;   /* as defined 3.7.5.5-2 */
+  char signal;       /* as defined 3.7.5.5-3, 3.7.5.5-4 or 3.7.5.5-5 */
+} RIL_CDMA_SignalInfoRecord;
+
+typedef struct {
+    RIL_CallState   state;
+    int             index;      /* Connection Index for use with, eg, AT+CHLD */
+    int             toa;        /* type of address, eg 145 = intl */
+    char            isMpty;     /* nonzero if is mpty call */
+    char            isMT;       /* nonzero if call is mobile terminated */
+    char            als;        /* ALS line indicator if available
+                                   (0 = line 1) */
+    char            isVoice;    /* nonzero if this is is a voice call */
+    char            isVoicePrivacy;     /* nonzero if CDMA voice privacy mode is active */
+    char *          number;     /* Remote party number */
+    int             numberPresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown 3=Payphone */
+    char *          name;       /* Remote party name */
+    int             namePresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown 3=Payphone */
+    RIL_UUS_Info *  uusInfo;    /* NULL or Pointer to User-User Signaling Information */
+} RIL_Call;
+
+/* Deprecated, use RIL_Data_Call_Response_v6 */
+typedef struct {
+    int             cid;        /* Context ID, uniquely identifies this call */
+    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
+    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
+                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". */
+    char *          apn;        /* ignored */
+    char *          address;    /* An address, e.g., "192.0.1.3" or "2001:db8::1". */
+} RIL_Data_Call_Response_v4;
+
+/*
+ * Returned by RIL_REQUEST_SETUP_DATA_CALL, RIL_REQUEST_DATA_CALL_LIST
+ * and RIL_UNSOL_DATA_CALL_LIST_CHANGED, on error status != 0.
+ */
+typedef struct {
+    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
+    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
+                                           back-off timer value RIL wants to override the one
+                                           pre-configured in FW.
+                                           The unit is miliseconds.
+                                           The value < 0 means no value is suggested.
+                                           The value 0 means retry should be done ASAP.
+                                           The value of INT_MAX(0x7fffffff) means no retry. */
+    int             cid;        /* Context ID, uniquely identifies this call */
+    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
+    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
+                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
+                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
+                                   such as "IP" or "IPV6" */
+    char *          ifname;     /* The network interface name */
+    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix length,
+                                   e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
+                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
+                                   one of each. If the prefix length is absent the addresses
+                                   are assumed to be point to point with IPv4 having a prefix
+                                   length of 32 and IPv6 128. */
+    char *          dnses;      /* A space-delimited list of DNS server addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty. */
+    char *          gateways;   /* A space-delimited list of default gateway addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty in which case the addresses represent point
+                                   to point connections. */
+} RIL_Data_Call_Response_v6;
+
+typedef struct {
+    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
+    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
+                                           back-off timer value RIL wants to override the one
+                                           pre-configured in FW.
+                                           The unit is miliseconds.
+                                           The value < 0 means no value is suggested.
+                                           The value 0 means retry should be done ASAP.
+                                           The value of INT_MAX(0x7fffffff) means no retry. */
+    int             cid;        /* Context ID, uniquely identifies this call */
+    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
+    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
+                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
+                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
+                                   such as "IP" or "IPV6" */
+    char *          ifname;     /* The network interface name */
+    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix length,
+                                   e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
+                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
+                                   one of each. If the prefix length is absent the addresses
+                                   are assumed to be point to point with IPv4 having a prefix
+                                   length of 32 and IPv6 128. */
+    char *          dnses;      /* A space-delimited list of DNS server addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty. */
+    char *          gateways;   /* A space-delimited list of default gateway addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty in which case the addresses represent point
+                                   to point connections. */
+    char *          pcscf;    /* the Proxy Call State Control Function address
+                                 via PCO(Protocol Configuration Option) for IMS client. */
+} RIL_Data_Call_Response_v9;
+
+typedef struct {
+    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
+    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
+                                           back-off timer value RIL wants to override the one
+                                           pre-configured in FW.
+                                           The unit is miliseconds.
+                                           The value < 0 means no value is suggested.
+                                           The value 0 means retry should be done ASAP.
+                                           The value of INT_MAX(0x7fffffff) means no retry. */
+    int             cid;        /* Context ID, uniquely identifies this call */
+    int             active;     /* 0=inactive, 1=active/physical link down, 2=active/physical link up */
+    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
+                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
+                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
+                                   such as "IP" or "IPV6" */
+    char *          ifname;     /* The network interface name */
+    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix length,
+                                   e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
+                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
+                                   one of each. If the prefix length is absent the addresses
+                                   are assumed to be point to point with IPv4 having a prefix
+                                   length of 32 and IPv6 128. */
+    char *          dnses;      /* A space-delimited list of DNS server addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty. */
+    char *          gateways;   /* A space-delimited list of default gateway addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty in which case the addresses represent point
+                                   to point connections. */
+    char *          pcscf;    /* the Proxy Call State Control Function address
+                                 via PCO(Protocol Configuration Option) for IMS client. */
+    int             mtu;        /* MTU received from network
+                                   Value <= 0 means network has either not sent a value or
+                                   sent an invalid value */
+} RIL_Data_Call_Response_v11;
+
+typedef struct {
+    int             status;     /* A RIL_DataCallFailCause, 0 which is PDP_FAIL_NONE if no error */
+    int             suggestedRetryTime; /* If status != 0, this fields indicates the suggested retry
+                                           back-off timer value RIL wants to override the one
+                                           pre-configured in FW.
+                                           The unit is milliseconds.
+                                           The value < 0 means no value is suggested.
+                                           The value 0 means retry should be done ASAP.
+                                           The value of INT_MAX(0x7fffffff) means no retry. */
+    int             cid;        /* Context ID, uniquely identifies this call */
+    int             active;     /* 0=inactive, 1=active/physical link down,
+                                   2=active/physical link up */
+    char *          type;       /* One of the PDP_type values in TS 27.007 section 10.1.1.
+                                   For example, "IP", "IPV6", "IPV4V6", or "PPP". If status is
+                                   PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED this is the type supported
+                                   such as "IP" or "IPV6" */
+    char *          ifname;     /* The network interface name */
+    char *          addresses;  /* A space-delimited list of addresses with optional "/" prefix
+                                   length, e.g., "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64".
+                                   May not be empty, typically 1 IPv4 or 1 IPv6 or
+                                   one of each. If the prefix length is absent the addresses
+                                   are assumed to be point to point with IPv4 having a prefix
+                                   length of 32 and IPv6 128. */
+    char *          dnses;      /* A space-delimited list of DNS server addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty. */
+    char *          gateways;   /* A space-delimited list of default gateway addresses,
+                                   e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+                                   May be empty in which case the addresses represent point
+                                   to point connections. */
+    char *          pcscf;      /* the Proxy Call State Control Function address
+                                   via PCO(Protocol Configuration Option) for IMS client. */
+    int             mtuV4;      /* MTU received from network for IPv4.
+                                   Value <= 0 means network has either not sent a value or
+                                   sent an invalid value. */
+    int             mtuV6;      /* MTU received from network for IPv6.
+                                   Value <= 0 means network has either not sent a value or
+                                   sent an invalid value. */
+} RIL_Data_Call_Response_v12;
+
+typedef enum {
+    RADIO_TECH_3GPP = 1, /* 3GPP Technologies - GSM, WCDMA */
+    RADIO_TECH_3GPP2 = 2 /* 3GPP2 Technologies - CDMA */
+} RIL_RadioTechnologyFamily;
+
+typedef struct {
+    RIL_RadioTechnologyFamily tech;
+    unsigned char             retry;       /* 0 == not retry, nonzero == retry */
+    int                       messageRef;  /* Valid field if retry is set to nonzero.
+                                              Contains messageRef from RIL_SMS_Response
+                                              corresponding to failed MO SMS.
+                                            */
+
+    union {
+        /* Valid field if tech is RADIO_TECH_3GPP2. See RIL_REQUEST_CDMA_SEND_SMS */
+        RIL_CDMA_SMS_Message* cdmaMessage;
+
+        /* Valid field if tech is RADIO_TECH_3GPP. See RIL_REQUEST_SEND_SMS */
+        char**                gsmMessage;   /* This is an array of pointers where pointers
+                                               are contiguous but elements pointed by those pointers
+                                               are not contiguous
+                                            */
+    } message;
+} RIL_IMS_SMS_Message;
+
+typedef struct {
+    int messageRef;   /* TP-Message-Reference for GSM,
+                         and BearerData MessageId for CDMA
+                         (See 3GPP2 C.S0015-B, v2.0, table 4.5-1). */
+    char *ackPDU;     /* or NULL if n/a */
+    int errorCode;    /* See 3GPP 27.005, 3.2.5 for GSM/UMTS,
+                         3GPP2 N.S0005 (IS-41C) Table 171 for CDMA,
+                         -1 if unknown or not applicable*/
+} RIL_SMS_Response;
+
+/** Used by RIL_REQUEST_WRITE_SMS_TO_SIM */
+typedef struct {
+    int status;     /* Status of message.  See TS 27.005 3.1, "<stat>": */
+                    /*      0 = "REC UNREAD"    */
+                    /*      1 = "REC READ"      */
+                    /*      2 = "STO UNSENT"    */
+                    /*      3 = "STO SENT"      */
+    char * pdu;     /* PDU of message to write, as an ASCII hex string less the SMSC address,
+                       the TP-layer length is "strlen(pdu)/2". */
+    char * smsc;    /* SMSC address in GSM BCD format prefixed by a length byte
+                       (as expected by TS 27.005) or NULL for default SMSC */
+} RIL_SMS_WriteArgs;
+
+/** Used by RIL_REQUEST_DIAL */
+typedef struct {
+    char * address;
+    int clir;
+            /* (same as 'n' paremeter in TS 27.007 7.7 "+CLIR"
+             * clir == 0 on "use subscription default value"
+             * clir == 1 on "CLIR invocation" (restrict CLI presentation)
+             * clir == 2 on "CLIR suppression" (allow CLI presentation)
+             */
+    RIL_UUS_Info *  uusInfo;    /* NULL or Pointer to User-User Signaling Information */
+} RIL_Dial;
+
+typedef struct {
+    int command;    /* one of the commands listed for TS 27.007 +CRSM*/
+    int fileid;     /* EF id */
+    char *path;     /* "pathid" from TS 27.007 +CRSM command.
+                       Path is in hex asciii format eg "7f205f70"
+                       Path must always be provided.
+                     */
+    int p1;
+    int p2;
+    int p3;
+    char *data;     /* May be NULL*/
+    char *pin2;     /* May be NULL*/
+} RIL_SIM_IO_v5;
+
+typedef struct {
+    int command;    /* one of the commands listed for TS 27.007 +CRSM*/
+    int fileid;     /* EF id */
+    char *path;     /* "pathid" from TS 27.007 +CRSM command.
+                       Path is in hex asciii format eg "7f205f70"
+                       Path must always be provided.
+                     */
+    int p1;
+    int p2;
+    int p3;
+    char *data;     /* May be NULL*/
+    char *pin2;     /* May be NULL*/
+    char *aidPtr;   /* AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value. */
+} RIL_SIM_IO_v6;
+
+/* Used by RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL and
+ * RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC. */
+typedef struct {
+    int sessionid;  /* "sessionid" from TS 27.007 +CGLA command. Should be
+                       ignored for +CSIM command. */
+
+    /* Following fields are used to derive the APDU ("command" and "length"
+       values in TS 27.007 +CSIM and +CGLA commands). */
+    int cla;
+    int instruction;
+    int p1;
+    int p2;
+    int p3;         /* A negative P3 implies a 4 byte APDU. */
+    char *data;     /* May be NULL. In hex string format. */
+} RIL_SIM_APDU;
+
+typedef struct {
+    int sw1;
+    int sw2;
+    char *simResponse;  /* In hex string format ([a-fA-F0-9]*), except for SIM_AUTHENTICATION
+                           response for which it is in Base64 format, see 3GPP TS 31.102 7.1.2 */
+} RIL_SIM_IO_Response;
+
+/* See also com.android.internal.telephony.gsm.CallForwardInfo */
+
+typedef struct {
+    int             status;     /*
+                                 * For RIL_REQUEST_QUERY_CALL_FORWARD_STATUS
+                                 * status 1 = active, 0 = not active
+                                 *
+                                 * For RIL_REQUEST_SET_CALL_FORWARD:
+                                 * status is:
+                                 * 0 = disable
+                                 * 1 = enable
+                                 * 2 = interrogate
+                                 * 3 = registeration
+                                 * 4 = erasure
+                                 */
+
+    int             reason;      /* from TS 27.007 7.11 "reason" */
+    int             serviceClass;/* From 27.007 +CCFC/+CLCK "class"
+                                    See table for Android mapping from
+                                    MMI service code
+                                    0 means user doesn't input class */
+    int             toa;         /* "type" from TS 27.007 7.11 */
+    char *          number;      /* "number" from TS 27.007 7.11. May be NULL */
+    int             timeSeconds; /* for CF no reply only */
+}RIL_CallForwardInfo;
+
+typedef struct {
+   char * cid;         /* Combination of LAC and Cell Id in 32 bits in GSM.
+                        * Upper 16 bits is LAC and lower 16 bits
+                        * is CID (as described in TS 27.005)
+                        * Primary Scrambling Code (as described in TS 25.331)
+                        *         in 9 bits in UMTS
+                        * Valid values are hexadecimal 0x0000 - 0xffffffff.
+                        */
+   int    rssi;        /* Received RSSI in GSM,
+                        * Level index of CPICH Received Signal Code Power in UMTS
+                        */
+} RIL_NeighboringCell;
+
+typedef struct {
+  char lce_status;                 /* LCE service status:
+                                    * -1 = not supported;
+                                    * 0 = stopped;
+                                    * 1 = active.
+                                    */
+  unsigned int actual_interval_ms; /* actual LCE reporting interval,
+                                    * meaningful only if LCEStatus = 1.
+                                    */
+} RIL_LceStatusInfo;
+
+typedef struct {
+  unsigned int last_hop_capacity_kbps; /* last-hop cellular capacity: kilobits/second. */
+  unsigned char confidence_level;      /* capacity estimate confidence: 0-100 */
+  unsigned char lce_suspended;         /* LCE report going to be suspended? (e.g., radio
+                                        * moves to inactive state or network type change)
+                                        * 1 = suspended;
+                                        * 0 = not suspended.
+                                        */
+} RIL_LceDataInfo;
+
+typedef enum {
+    RIL_MATCH_ALL = 0,          /* Apply to all carriers with the same mcc/mnc */
+    RIL_MATCH_SPN = 1,          /* Use SPN and mcc/mnc to identify the carrier */
+    RIL_MATCH_IMSI_PREFIX = 2,  /* Use IMSI prefix and mcc/mnc to identify the carrier */
+    RIL_MATCH_GID1 = 3,         /* Use GID1 and mcc/mnc to identify the carrier */
+    RIL_MATCH_GID2 = 4,         /* Use GID2 and mcc/mnc to identify the carrier */
+} RIL_CarrierMatchType;
+
+typedef struct {
+    const char * mcc;
+    const char * mnc;
+    RIL_CarrierMatchType match_type;   /* Specify match type for the carrier.
+                                        * If it’s RIL_MATCH_ALL, match_data is null;
+                                        * otherwise, match_data is the value for the match type.
+                                        */
+    const char * match_data;
+} RIL_Carrier;
+
+typedef struct {
+  int32_t len_allowed_carriers;         /* length of array allowed_carriers */
+  int32_t len_excluded_carriers;        /* length of array excluded_carriers */
+  RIL_Carrier * allowed_carriers;       /* allowed carriers */
+  RIL_Carrier * excluded_carriers;      /* excluded carriers
+                                         * which match allowed_carriers. Eg. allowed_carriers match
+                                         * mcc/mnc, excluded_carriers has same mcc/mnc and gid1
+                                         * is ABCD. It means except the carrier whose gid1 is ABCD,
+                                         * all carriers with the same mcc/mnc are allowed.
+                                         */
+} RIL_CarrierRestrictions;
+
+typedef enum {
+    NO_MULTISIM_POLICY = 0,             /* configuration applies to each slot independently. */
+    ONE_VALID_SIM_MUST_BE_PRESENT = 1,  /* Any SIM card can be used as far as one valid card is
+                                         * present in the device.
+                                         */
+} RIL_SimLockMultiSimPolicy;
+
+typedef struct {
+  int32_t len_allowed_carriers;         /* length of array allowed_carriers */
+  int32_t len_excluded_carriers;        /* length of array excluded_carriers */
+  RIL_Carrier * allowed_carriers;       /* allowed carriers */
+  RIL_Carrier * excluded_carriers;      /* explicitly excluded carriers
+                                         * which match allowed_carriers. Eg. allowed_carriers match
+                                         * mcc/mnc, excluded_carriers has same mcc/mnc and gid1
+                                         * is ABCD. It means except the carrier whose gid1 is ABCD,
+                                         * all carriers with the same mcc/mnc are allowed.
+                                         */
+  int allowedCarriersPrioritized;       /* allowed list prioritized */
+  RIL_SimLockMultiSimPolicy multiSimPolicy; /* multisim policy */
+} RIL_CarrierRestrictionsWithPriority;
+
+typedef struct {
+  char * mcc;                         /* MCC of the Carrier. */
+  char * mnc ;                        /* MNC of the Carrier. */
+  uint8_t * carrierKey;               /* Public Key from the Carrier used to encrypt the
+                                       * IMSI/IMPI.
+                                       */
+  int32_t carrierKeyLength;            /* Length of the Public Key. */
+  char * keyIdentifier;               /* The keyIdentifier Attribute value pair that helps
+                                       * a server locate the private key to decrypt the
+                                       * permanent identity.
+                                       */
+  int64_t expirationTime;             /* Date-Time (in UTC) when the key will expire. */
+
+} RIL_CarrierInfoForImsiEncryption;
+
+/**
+ * Public key type from carrier certificate.
+ */
+typedef enum {
+    EPDG = 1, /* Key type to be used for ePDG */
+    WLAN = 2, /* Key type to be used for WLAN */
+} RIL_PublicKeyType;
+
+typedef struct {
+    char* mcc;                 /* MCC of the Carrier. */
+    char* mnc;                 /* MNC of the Carrier. */
+    uint8_t* carrierKey;       /* Public Key from the Carrier used to encrypt the
+                                * IMSI/IMPI.
+                                */
+    int32_t carrierKeyLength;  /* Length of the Public Key. */
+    char* keyIdentifier;       /* The keyIdentifier Attribute value pair that helps
+                                * a server locate the private key to decrypt the
+                                * permanent identity.
+                                */
+    int64_t expirationTime;    /* Date-Time (in UTC) when the key will expire. */
+    RIL_PublicKeyType keyType; /* Public key type */
+
+} RIL_CarrierInfoForImsiEncryption_v16;
+
+/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
+typedef enum {
+    CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
+    CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
+    CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
+    CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
+    CALL_FAIL_NORMAL = 16,
+    CALL_FAIL_BUSY = 17,
+    CALL_FAIL_NO_USER_RESPONDING = 18,
+    CALL_FAIL_NO_ANSWER_FROM_USER = 19,
+    CALL_FAIL_CALL_REJECTED = 21,
+    CALL_FAIL_NUMBER_CHANGED = 22,
+    CALL_FAIL_PREEMPTION = 25,
+    CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
+    CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
+    CALL_FAIL_FACILITY_REJECTED = 29,
+    CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
+    CALL_FAIL_NORMAL_UNSPECIFIED = 31,
+    CALL_FAIL_CONGESTION = 34,
+    CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
+    CALL_FAIL_TEMPORARY_FAILURE = 41,
+    CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
+    CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
+    CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
+    CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
+    CALL_FAIL_QOS_UNAVAILABLE = 49,
+    CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
+    CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
+    CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
+    CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
+    CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
+    CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
+    CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
+    CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
+    CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
+    CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
+    CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
+    CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
+    CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
+    CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
+    CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
+    CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
+    CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
+    CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
+    CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
+    CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
+    CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
+    CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
+    CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
+    CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
+    CALL_FAIL_CALL_BARRED = 240,
+    CALL_FAIL_FDN_BLOCKED = 241,
+    CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
+    CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
+    CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244, /* STK Call Control */
+    CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
+    CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
+    CALL_FAIL_RADIO_OFF = 247, /* Radio is OFF */
+    CALL_FAIL_OUT_OF_SERVICE = 248, /* No cellular coverage */
+    CALL_FAIL_NO_VALID_SIM = 249, /* No valid SIM is present */
+    CALL_FAIL_RADIO_INTERNAL_ERROR = 250, /* Internal error at Modem */
+    CALL_FAIL_NETWORK_RESP_TIMEOUT = 251, /* No response from network */
+    CALL_FAIL_NETWORK_REJECT = 252, /* Explicit network reject */
+    CALL_FAIL_RADIO_ACCESS_FAILURE = 253, /* RRC connection failure. Eg.RACH */
+    CALL_FAIL_RADIO_LINK_FAILURE = 254, /* Radio Link Failure */
+    CALL_FAIL_RADIO_LINK_LOST = 255, /* Radio link lost due to poor coverage */
+    CALL_FAIL_RADIO_UPLINK_FAILURE = 256, /* Radio uplink failure */
+    CALL_FAIL_RADIO_SETUP_FAILURE = 257, /* RRC connection setup failure */
+    CALL_FAIL_RADIO_RELEASE_NORMAL = 258, /* RRC connection release, normal */
+    CALL_FAIL_RADIO_RELEASE_ABNORMAL = 259, /* RRC connection release, abnormal */
+    CALL_FAIL_ACCESS_CLASS_BLOCKED = 260, /* Access class barring */
+    CALL_FAIL_NETWORK_DETACH = 261, /* Explicit network detach */
+    CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000,
+    CALL_FAIL_CDMA_DROP = 1001,
+    CALL_FAIL_CDMA_INTERCEPT = 1002,
+    CALL_FAIL_CDMA_REORDER = 1003,
+    CALL_FAIL_CDMA_SO_REJECT = 1004,
+    CALL_FAIL_CDMA_RETRY_ORDER = 1005,
+    CALL_FAIL_CDMA_ACCESS_FAILURE = 1006,
+    CALL_FAIL_CDMA_PREEMPTED = 1007,
+    CALL_FAIL_CDMA_NOT_EMERGENCY = 1008, /* For non-emergency number dialed
+                                            during emergency callback mode */
+    CALL_FAIL_CDMA_ACCESS_BLOCKED = 1009, /* CDMA network access probes blocked */
+
+    /* OEM specific error codes. Used to distinguish error from
+     * CALL_FAIL_ERROR_UNSPECIFIED and help assist debugging */
+    CALL_FAIL_OEM_CAUSE_1 = 0xf001,
+    CALL_FAIL_OEM_CAUSE_2 = 0xf002,
+    CALL_FAIL_OEM_CAUSE_3 = 0xf003,
+    CALL_FAIL_OEM_CAUSE_4 = 0xf004,
+    CALL_FAIL_OEM_CAUSE_5 = 0xf005,
+    CALL_FAIL_OEM_CAUSE_6 = 0xf006,
+    CALL_FAIL_OEM_CAUSE_7 = 0xf007,
+    CALL_FAIL_OEM_CAUSE_8 = 0xf008,
+    CALL_FAIL_OEM_CAUSE_9 = 0xf009,
+    CALL_FAIL_OEM_CAUSE_10 = 0xf00a,
+    CALL_FAIL_OEM_CAUSE_11 = 0xf00b,
+    CALL_FAIL_OEM_CAUSE_12 = 0xf00c,
+    CALL_FAIL_OEM_CAUSE_13 = 0xf00d,
+    CALL_FAIL_OEM_CAUSE_14 = 0xf00e,
+    CALL_FAIL_OEM_CAUSE_15 = 0xf00f,
+
+    CALL_FAIL_ERROR_UNSPECIFIED = 0xffff /* This error will be deprecated soon,
+                                            vendor code should make sure to map error
+                                            code to specific error */
+} RIL_LastCallFailCause;
+
+typedef struct {
+  RIL_LastCallFailCause cause_code;
+  char *                vendor_cause;
+} RIL_LastCallFailCauseInfo;
+
+/* See RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE */
+typedef enum {
+    PDP_FAIL_NONE = 0, /* No error, connection ok */
+
+    /* an integer cause code defined in TS 24.008
+       section 6.1.3.1.3 or TS 24.301 Release 8+ Annex B.
+       If the implementation does not have access to the exact cause codes,
+       then it should return one of the following values,
+       as the UI layer needs to distinguish these
+       cases for error notification and potential retries. */
+    PDP_FAIL_OPERATOR_BARRED = 0x08, /* no retry */
+    PDP_FAIL_NAS_SIGNALLING = 0x0E,
+    PDP_FAIL_LLC_SNDCP = 0x19,
+    PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
+    PDP_FAIL_MISSING_UNKNOWN_APN = 0x1B,      /* no retry */
+    PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C, /* no retry */
+    PDP_FAIL_USER_AUTHENTICATION = 0x1D,      /* no retry */
+    PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,   /* no retry */
+    PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
+    PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,  /* no retry */
+    PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21, /* no retry */
+    PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
+    PDP_FAIL_NSAPI_IN_USE = 0x23,         /* no retry */
+    PDP_FAIL_REGULAR_DEACTIVATION = 0x24, /* possibly restart radio,
+                                             based on framework config */
+    PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
+    PDP_FAIL_NETWORK_FAILURE = 0x26,
+    PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
+    PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
+    PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
+    PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
+    PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
+    PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
+    PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
+    PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
+    PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32, /* no retry */
+    PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33, /* no retry */
+    PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
+    PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
+    PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
+    PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
+    PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
+    PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
+    PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
+    PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
+    PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
+    PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
+    PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
+    PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
+    PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
+    PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
+    PDP_FAIL_PROTOCOL_ERRORS = 0x6F, /* no retry */
+    PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
+    PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
+    PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
+    PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
+    PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
+    PDP_FAIL_IFACE_MISMATCH = 0x75,
+    PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
+    PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
+    PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
+    PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
+    PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
+    // TODO: add new fail causes from IRadio 1.4 types.hal
+    PDP_FAIL_SLICE_REJECTED = 0x8CC,
+    PDP_FAIL_MATCH_ALL_RULE_NOT_ALLOWED = 0x8CD,
+    ALL_MATCHING_RULES_FAILED = 0x8CE,
+
+    // OEM specific error codes. To be used by OEMs when they don't want to
+    // reveal error code which would be replaced by PDP_FAIL_ERROR_UNSPECIFIED
+    PDP_FAIL_OEM_DCFAILCAUSE_1 = 0x1001,
+    PDP_FAIL_OEM_DCFAILCAUSE_2 = 0x1002,
+    PDP_FAIL_OEM_DCFAILCAUSE_3 = 0x1003,
+    PDP_FAIL_OEM_DCFAILCAUSE_4 = 0x1004,
+    PDP_FAIL_OEM_DCFAILCAUSE_5 = 0x1005,
+    PDP_FAIL_OEM_DCFAILCAUSE_6 = 0x1006,
+    PDP_FAIL_OEM_DCFAILCAUSE_7 = 0x1007,
+    PDP_FAIL_OEM_DCFAILCAUSE_8 = 0x1008,
+    PDP_FAIL_OEM_DCFAILCAUSE_9 = 0x1009,
+    PDP_FAIL_OEM_DCFAILCAUSE_10 = 0x100A,
+    PDP_FAIL_OEM_DCFAILCAUSE_11 = 0x100B,
+    PDP_FAIL_OEM_DCFAILCAUSE_12 = 0x100C,
+    PDP_FAIL_OEM_DCFAILCAUSE_13 = 0x100D,
+    PDP_FAIL_OEM_DCFAILCAUSE_14 = 0x100E,
+    PDP_FAIL_OEM_DCFAILCAUSE_15 = 0x100F,
+
+    /* Not mentioned in the specification */
+    PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
+    PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
+
+    /* reasons for data call drop - network/modem disconnect */
+    PDP_FAIL_SIGNAL_LOST = -3,
+    PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4, /* preferred technology has changed, should retry
+                                              with parameters appropriate for new technology */
+    PDP_FAIL_RADIO_POWER_OFF = -5,      /* data call was disconnected because radio was resetting,
+                                           powered off - no retry */
+    PDP_FAIL_TETHERED_CALL_ACTIVE = -6, /* data call was disconnected by modem because tethered
+                                           mode was up on same APN/data profile - no retry until
+                                           tethered call is off */
+
+    PDP_FAIL_ERROR_UNSPECIFIED = 0xffff, /* retry silently. Will be deprecated soon as
+                                            new error codes are added making this unnecessary */
+} RIL_DataCallFailCause;
+
+/* See RIL_REQUEST_SETUP_DATA_CALL */
+typedef enum {
+    RIL_DATA_PROFILE_DEFAULT    = 0,
+    RIL_DATA_PROFILE_TETHERED   = 1,
+    RIL_DATA_PROFILE_IMS        = 2,
+    RIL_DATA_PROFILE_FOTA       = 3,
+    RIL_DATA_PROFILE_CBS        = 4,
+    RIL_DATA_PROFILE_OEM_BASE   = 1000,    /* Start of OEM-specific profiles */
+    RIL_DATA_PROFILE_INVALID    = 0xFFFFFFFF
+} RIL_DataProfile;
+
+/* Used by RIL_UNSOL_SUPP_SVC_NOTIFICATION */
+typedef struct {
+    int     notificationType;   /*
+                                 * 0 = MO intermediate result code
+                                 * 1 = MT unsolicited result code
+                                 */
+    int     code;               /* See 27.007 7.17
+                                   "code1" for MO
+                                   "code2" for MT. */
+    int     index;              /* CUG index. See 27.007 7.17. */
+    int     type;               /* "type" from 27.007 7.17 (MT only). */
+    char *  number;             /* "number" from 27.007 7.17
+                                   (MT only, may be NULL). */
+} RIL_SuppSvcNotification;
+
+#define RIL_CARD_MAX_APPS     8
+
+typedef enum {
+    RIL_CARDSTATE_ABSENT     = 0,
+    RIL_CARDSTATE_PRESENT    = 1,
+    RIL_CARDSTATE_ERROR      = 2,
+    RIL_CARDSTATE_RESTRICTED = 3  /* card is present but not usable due to carrier restrictions.*/
+} RIL_CardState;
+
+typedef enum {
+    RIL_PERSOSUBSTATE_UNKNOWN                   = 0, /* initial state */
+    RIL_PERSOSUBSTATE_IN_PROGRESS               = 1, /* in between each lock transition */
+    RIL_PERSOSUBSTATE_READY                     = 2, /* when either SIM or RUIM Perso is finished
+                                                        since each app can only have 1 active perso
+                                                        involved */
+    RIL_PERSOSUBSTATE_SIM_NETWORK               = 3,
+    RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET        = 4,
+    RIL_PERSOSUBSTATE_SIM_CORPORATE             = 5,
+    RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER      = 6,
+    RIL_PERSOSUBSTATE_SIM_SIM                   = 7,
+    RIL_PERSOSUBSTATE_SIM_NETWORK_PUK           = 8, /* The corresponding perso lock is blocked */
+    RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK    = 9,
+    RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK         = 10,
+    RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK  = 11,
+    RIL_PERSOSUBSTATE_SIM_SIM_PUK               = 12,
+    RIL_PERSOSUBSTATE_RUIM_NETWORK1             = 13,
+    RIL_PERSOSUBSTATE_RUIM_NETWORK2             = 14,
+    RIL_PERSOSUBSTATE_RUIM_HRPD                 = 15,
+    RIL_PERSOSUBSTATE_RUIM_CORPORATE            = 16,
+    RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER     = 17,
+    RIL_PERSOSUBSTATE_RUIM_RUIM                 = 18,
+    RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK         = 19, /* The corresponding perso lock is blocked */
+    RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK         = 20,
+    RIL_PERSOSUBSTATE_RUIM_HRPD_PUK             = 21,
+    RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK        = 22,
+    RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
+    RIL_PERSOSUBSTATE_RUIM_RUIM_PUK             = 24
+} RIL_PersoSubstate;
+
+typedef enum {
+    RIL_APPSTATE_UNKNOWN               = 0,
+    RIL_APPSTATE_DETECTED              = 1,
+    RIL_APPSTATE_PIN                   = 2, /* If PIN1 or UPin is required */
+    RIL_APPSTATE_PUK                   = 3, /* If PUK1 or Puk for UPin is required */
+    RIL_APPSTATE_SUBSCRIPTION_PERSO    = 4, /* perso_substate should be look at
+                                               when app_state is assigned to this value */
+    RIL_APPSTATE_READY                 = 5
+} RIL_AppState;
+
+typedef enum {
+    RIL_PINSTATE_UNKNOWN              = 0,
+    RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
+    RIL_PINSTATE_ENABLED_VERIFIED     = 2,
+    RIL_PINSTATE_DISABLED             = 3,
+    RIL_PINSTATE_ENABLED_BLOCKED      = 4,
+    RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
+} RIL_PinState;
+
+typedef enum {
+  RIL_APPTYPE_UNKNOWN = 0,
+  RIL_APPTYPE_SIM     = 1,
+  RIL_APPTYPE_USIM    = 2,
+  RIL_APPTYPE_RUIM    = 3,
+  RIL_APPTYPE_CSIM    = 4,
+  RIL_APPTYPE_ISIM    = 5
+} RIL_AppType;
+
+/*
+ * Please note that registration state UNKNOWN is
+ * treated as "out of service" in the Android telephony.
+ * Registration state REG_DENIED must be returned if Location Update
+ * Reject (with cause 17 - Network Failure) is received
+ * repeatedly from the network, to facilitate
+ * "managed roaming"
+ */
+typedef enum {
+    RIL_NOT_REG_AND_NOT_SEARCHING = 0,           // Not registered, MT is not currently searching
+                                                 // a new operator to register
+    RIL_REG_HOME = 1,                            // Registered, home network
+    RIL_NOT_REG_AND_SEARCHING = 2,               // Not registered, but MT is currently searching
+                                                 // a new operator to register
+    RIL_REG_DENIED = 3,                          // Registration denied
+    RIL_UNKNOWN = 4,                             // Unknown
+    RIL_REG_ROAMING = 5,                         // Registered, roaming
+    RIL_NOT_REG_AND_EMERGENCY_AVAILABLE_AND_NOT_SEARCHING = 10,   // Same as
+                                                 // RIL_NOT_REG_AND_NOT_SEARCHING but indicates that
+                                                 // emergency calls are enabled.
+    RIL_NOT_REG_AND_EMERGENCY_AVAILABLE_AND_SEARCHING = 12,  // Same as RIL_NOT_REG_AND_SEARCHING
+                                                 // but indicates that
+                                                 // emergency calls are enabled.
+    RIL_REG_DENIED_AND_EMERGENCY_AVAILABLE = 13, // Same as REG_DENIED but indicates that
+                                                 // emergency calls are enabled.
+    RIL_UNKNOWN_AND_EMERGENCY_AVAILABLE = 14,    // Same as UNKNOWN but indicates that
+                                                 // emergency calls are enabled.
+} RIL_RegState;
+
+typedef struct
+{
+  RIL_AppType      app_type;
+  RIL_AppState     app_state;
+  RIL_PersoSubstate perso_substate; /* applicable only if app_state ==
+                                       RIL_APPSTATE_SUBSCRIPTION_PERSO */
+  char             *aid_ptr;        /* null terminated string, e.g., from 0xA0, 0x00 -> 0x41,
+                                       0x30, 0x30, 0x30 */
+  char             *app_label_ptr;  /* null terminated string */
+  int              pin1_replaced;   /* applicable to USIM, CSIM & ISIM */
+  RIL_PinState     pin1;
+  RIL_PinState     pin2;
+} RIL_AppStatus;
+
+/* Deprecated, use RIL_CardStatus_v6 */
+typedef struct
+{
+  RIL_CardState card_state;
+  RIL_PinState  universal_pin_state;             /* applicable to USIM and CSIM: RIL_PINSTATE_xxx */
+  int           gsm_umts_subscription_app_index; /* value < RIL_CARD_MAX_APPS, -1 if none */
+  int           cdma_subscription_app_index;     /* value < RIL_CARD_MAX_APPS, -1 if none */
+  int           num_applications;                /* value <= RIL_CARD_MAX_APPS */
+  RIL_AppStatus applications[RIL_CARD_MAX_APPS];
+} RIL_CardStatus_v5;
+
+typedef struct
+{
+  RIL_CardState card_state;
+  RIL_PinState  universal_pin_state;             /* applicable to USIM and CSIM: RIL_PINSTATE_xxx */
+  int           gsm_umts_subscription_app_index; /* value < RIL_CARD_MAX_APPS, -1 if none */
+  int           cdma_subscription_app_index;     /* value < RIL_CARD_MAX_APPS, -1 if none */
+  int           ims_subscription_app_index;      /* value < RIL_CARD_MAX_APPS, -1 if none */
+  int           num_applications;                /* value <= RIL_CARD_MAX_APPS */
+  RIL_AppStatus applications[RIL_CARD_MAX_APPS];
+} RIL_CardStatus_v6;
+
+typedef struct {
+    RIL_CardStatus_v6 base;
+
+    uint32_t physicalSlotId;
+    /**
+     * An Answer To Reset (ATR) is a message output by a Smart Card conforming to ISO/IEC 7816
+     * standards, following electrical reset of the card's chip. The ATR conveys information about
+     * the communication parameters proposed by the card, and the card's nature and state.
+     *
+     * This data is applicable only when cardState is CardState:PRESENT.
+     */
+    char *atr;
+    /**
+     * Integrated Circuit Card IDentifier (ICCID) is Unique Identifier of the SIM CARD. File is
+     * located in the SIM card at EFiccid (0x2FE2) as per ETSI 102.221. The ICCID is defined by
+     * the ITU-T recommendation E.118 ISO/IEC 7816.
+     *
+     * This data is applicable only when cardState is CardState:PRESENT.
+     */
+    char *iccid;
+} RIL_CardStatus_v1_2;
+
+typedef struct {
+    RIL_CardStatus_v1_2 base;
+    char *              eid;    /* The EID is the eUICC identifier. The EID shall be stored within the ECASD and can be
+                                 * retrieved by the Device at any time using the standard GlobalPlatform GET DATA command.
+                                 *
+                                 * This data is mandatory and applicable only when cardState is CardState:PRESENT and SIM card
+                                 * supports eUICC. */
+} RIL_CardStatus_v1_4;
+
+typedef enum {
+    RIL_PERSOSUBSTATE_UNKNOWN_1_5                   = 0, /* initial state */
+    RIL_PERSOSUBSTATE_IN_PROGRESS_1_5               = 1, /* in between each lock transition */
+    RIL_PERSOSUBSTATE_READY_1_5                     = 2, /* when either SIM or RUIM Perso is finished
+                                                        since each app can only have 1 active perso
+                                                        involved */
+    RIL_PERSOSUBSTATE_SIM_NETWORK_1_5               = 3,
+    RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_1_5        = 4,
+    RIL_PERSOSUBSTATE_SIM_CORPORATE_1_5             = 5,
+    RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_1_5      = 6,
+    RIL_PERSOSUBSTATE_SIM_SIM_1_5                   = 7,
+    RIL_PERSOSUBSTATE_SIM_NETWORK_PUK_1_5           = 8, /* The corresponding perso lock is blocked */
+    RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_1_5    = 9,
+    RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK_1_5         = 10,
+    RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_1_5  = 11,
+    RIL_PERSOSUBSTATE_SIM_SIM_PUK_1_5               = 12,
+    RIL_PERSOSUBSTATE_RUIM_NETWORK1_1_5             = 13,
+    RIL_PERSOSUBSTATE_RUIM_NETWORK2_1_5             = 14,
+    RIL_PERSOSUBSTATE_RUIM_HRPD_1_5                 = 15,
+    RIL_PERSOSUBSTATE_RUIM_CORPORATE_1_5            = 16,
+    RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_1_5     = 17,
+    RIL_PERSOSUBSTATE_RUIM_RUIM_1_5                 = 18,
+    RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK_1_5         = 19, /* The corresponding perso lock is blocked */
+    RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK_1_5         = 20,
+    RIL_PERSOSUBSTATE_RUIM_HRPD_PUK_1_5             = 21,
+    RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK_1_5        = 22,
+    RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_1_5 = 23,
+    RIL_PERSOSUBSTATE_RUIM_RUIM_PUK_1_5             = 24,
+    /**
+     * The device is personalized using the content of the Service Provider Name (SPN) in the SIM
+     * card.
+     */
+    RIL_PERSOSUBSTATE_SIM_SPN,
+    RIL_PERSOSUBSTATE_SIM_SPN_PUK,
+    /**
+     * Service Provider and Equivalent Home PLMN
+     * The device is personalized using both the content of the GID1 (equivalent to service provider
+     * personalization) and the content of the Equivalent Home PLMN (EHPLMN) in the SIM card.
+     * If the GID1 in the SIM is absent, then just the content of the Equivalent Home PLMN
+     * is matched.
+     */
+    RIL_PERSOSUBSTATE_SIM_SP_EHPLMN,
+    RIL_PERSOSUBSTATE_SIM_SP_EHPLMN_PUK,
+    /**
+     * Device is personalized using the first digits of the ICCID of the SIM card.
+     */
+    RIL_PERSOSUBSTATE_SIM_ICCID,
+    RIL_PERSOSUBSTATE_SIM_ICCID_PUK,
+    /**
+     * Device is personalized using the content of the IMPI in the ISIM.
+     */
+    RIL_PERSOSUBSTATE_SIM_IMPI,
+    RIL_PERSOSUBSTATE_SIM_IMPI_PUK,
+    /**
+      * Network Subset and Service Provider
+     * Device is personalized using both the content of GID1 (equivalent to service provider
+     * personalization) and the first digits of the IMSI (equivalent to network subset
+     * personalization).
+     */
+    RIL_PERSOSUBSTATE_SIM_NS_SP,
+    RIL_PERSOSUBSTATE_SIM_NS_SP_PUK,
+} RIL_PersoSubstateV1_5;
+
+typedef struct {
+    RIL_AppStatus base;
+    RIL_PersoSubstateV1_5 persoSubstate;
+} RIL_AppStatusV1_5;
+
+typedef struct {
+    RIL_CardStatus_v1_4 base;
+
+    /** size <= RadioConst::CARD_MAX_APPS */
+    RIL_AppStatusV1_5 applications[RIL_CARD_MAX_APPS];
+} RIL_CardStatus_v1_5;  // 1.5
+
+/** The result of a SIM refresh, returned in data[0] of RIL_UNSOL_SIM_REFRESH
+ *      or as part of RIL_SimRefreshResponse_v7
+ */
+typedef enum {
+    /* A file on SIM has been updated.  data[1] contains the EFID. */
+    SIM_FILE_UPDATE = 0,
+    /* SIM initialized.  All files should be re-read. */
+    SIM_INIT = 1,
+    /* SIM reset.  SIM power required, SIM may be locked and all files should be re-read. */
+    SIM_RESET = 2
+} RIL_SimRefreshResult;
+
+typedef struct {
+    RIL_SimRefreshResult result;
+    int                  ef_id; /* is the EFID of the updated file if the result is */
+                                /* SIM_FILE_UPDATE or 0 for any other result. */
+    char *               aid;   /* is AID(application ID) of the card application */
+                                /* See ETSI 102.221 8.1 and 101.220 4 */
+                                /*     For SIM_FILE_UPDATE result it can be set to AID of */
+                                /*         application in which updated EF resides or it can be */
+                                /*         NULL if EF is outside of an application. */
+                                /*     For SIM_INIT result this field is set to AID of */
+                                /*         application that caused REFRESH */
+                                /*     For SIM_RESET result it is NULL. */
+} RIL_SimRefreshResponse_v7;
+
+/* Deprecated, use RIL_CDMA_CallWaiting_v6 */
+typedef struct {
+    char *          number;             /* Remote party number */
+    int             numberPresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown */
+    char *          name;               /* Remote party name */
+    RIL_CDMA_SignalInfoRecord signalInfoRecord;
+} RIL_CDMA_CallWaiting_v5;
+
+typedef struct {
+    char *          number;             /* Remote party number */
+    int             numberPresentation; /* 0=Allowed, 1=Restricted, 2=Not Specified/Unknown */
+    char *          name;               /* Remote party name */
+    RIL_CDMA_SignalInfoRecord signalInfoRecord;
+    /* Number type/Number plan required to support International Call Waiting */
+    int             number_type;        /* 0=Unknown, 1=International, 2=National,
+                                           3=Network specific, 4=subscriber */
+    int             number_plan;        /* 0=Unknown, 1=ISDN, 3=Data, 4=Telex, 8=Nat'l, 9=Private */
+} RIL_CDMA_CallWaiting_v6;
+
+/**
+ * Which types of Cell Broadcast Message (CBM) are to be received by the ME
+ *
+ * uFromServiceID - uToServiceID defines a range of CBM message identifiers
+ * whose value is 0x0000 - 0xFFFF as defined in TS 23.041 9.4.1.2.2 for GMS
+ * and 9.4.4.2.2 for UMTS. All other values can be treated as empty
+ * CBM message ID.
+ *
+ * uFromCodeScheme - uToCodeScheme defines a range of CBM data coding schemes
+ * whose value is 0x00 - 0xFF as defined in TS 23.041 9.4.1.2.3 for GMS
+ * and 9.4.4.2.3 for UMTS.
+ * All other values can be treated as empty CBM data coding scheme.
+ *
+ * selected 0 means message types specified in <fromServiceId, toServiceId>
+ * and <fromCodeScheme, toCodeScheme>are not accepted, while 1 means accepted.
+ *
+ * Used by RIL_REQUEST_GSM_GET_BROADCAST_CONFIG and
+ * RIL_REQUEST_GSM_SET_BROADCAST_CONFIG.
+ */
+typedef struct {
+    int fromServiceId;
+    int toServiceId;
+    int fromCodeScheme;
+    int toCodeScheme;
+    unsigned char selected;
+} RIL_GSM_BroadcastSmsConfigInfo;
+
+/* No restriction at all including voice/SMS/USSD/SS/AV64 and packet data. */
+#define RIL_RESTRICTED_STATE_NONE           0x00
+/* Block emergency call due to restriction. But allow all normal voice/SMS/USSD/SS/AV64. */
+#define RIL_RESTRICTED_STATE_CS_EMERGENCY   0x01
+/* Block all normal voice/SMS/USSD/SS/AV64 due to restriction. Only Emergency call allowed. */
+#define RIL_RESTRICTED_STATE_CS_NORMAL      0x02
+/* Block all voice/SMS/USSD/SS/AV64 including emergency call due to restriction.*/
+#define RIL_RESTRICTED_STATE_CS_ALL         0x04
+/* Block packet data access due to restriction. */
+#define RIL_RESTRICTED_STATE_PS_ALL         0x10
+
+/* The status for an OTASP/OTAPA session */
+typedef enum {
+    CDMA_OTA_PROVISION_STATUS_SPL_UNLOCKED,
+    CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED,
+    CDMA_OTA_PROVISION_STATUS_A_KEY_EXCHANGED,
+    CDMA_OTA_PROVISION_STATUS_SSD_UPDATED,
+    CDMA_OTA_PROVISION_STATUS_NAM_DOWNLOADED,
+    CDMA_OTA_PROVISION_STATUS_MDN_DOWNLOADED,
+    CDMA_OTA_PROVISION_STATUS_IMSI_DOWNLOADED,
+    CDMA_OTA_PROVISION_STATUS_PRL_DOWNLOADED,
+    CDMA_OTA_PROVISION_STATUS_COMMITTED,
+    CDMA_OTA_PROVISION_STATUS_OTAPA_STARTED,
+    CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED,
+    CDMA_OTA_PROVISION_STATUS_OTAPA_ABORTED
+} RIL_CDMA_OTA_ProvisionStatus;
+
+typedef struct {
+    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
+    int bitErrorRate;    /* bit error rate (0-7, 99) as defined in TS 27.007 8.5 */
+} RIL_GW_SignalStrength;
+
+typedef struct {
+    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
+    int bitErrorRate;    /* bit error rate (0-7, 99) as defined in TS 27.007 8.5 */
+    int timingAdvance;   /* Timing Advance in bit periods. 1 bit period = 48/13 us.
+                          * INT_MAX denotes invalid value */
+} RIL_GSM_SignalStrength_v12;
+
+typedef struct {
+    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
+    int bitErrorRate;    /* bit error rate (0-7, 99) as defined in TS 27.007 8.5 */
+} RIL_SignalStrengthWcdma;
+
+typedef struct {
+    int dbm;  /* Valid values are positive integers.  This value is the actual RSSI value
+               * multiplied by -1.  Example: If the actual RSSI is -75, then this response
+               * value will be 75.
+               */
+    int ecio; /* Valid values are positive integers.  This value is the actual Ec/Io multiplied
+               * by -10.  Example: If the actual Ec/Io is -12.5 dB, then this response value
+               * will be 125.
+               */
+} RIL_CDMA_SignalStrength;
+
+typedef struct {
+    int dbm;  /* Valid values are positive integers.  This value is the actual RSSI value
+               * multiplied by -1.  Example: If the actual RSSI is -75, then this response
+               * value will be 75.
+               */
+    int ecio; /* Valid values are positive integers.  This value is the actual Ec/Io multiplied
+               * by -10.  Example: If the actual Ec/Io is -12.5 dB, then this response value
+               * will be 125.
+               */
+    int signalNoiseRatio; /* Valid values are 0-8.  8 is the highest signal to noise ratio. */
+} RIL_EVDO_SignalStrength;
+
+typedef struct {
+    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
+    int rsrp;            /* The current Reference Signal Receive Power in dBm multipled by -1.
+                          * Range: 44 to 140 dBm
+                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.133 9.1.4 */
+    int rsrq;            /* The current Reference Signal Receive Quality in dB multiplied by -1.
+                          * Range: 20 to 3 dB.
+                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.133 9.1.7 */
+    int rssnr;           /* The current reference signal signal-to-noise ratio in 0.1 dB units.
+                          * Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
+                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.101 8.1.1 */
+    int cqi;             /* The current Channel Quality Indicator.
+                          * Range: 0 to 15.
+                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.101 9.2, 9.3, A.4 */
+} RIL_LTE_SignalStrength;
+
+typedef struct {
+    int signalStrength;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
+    int rsrp;            /* The current Reference Signal Receive Power in dBm multipled by -1.
+                          * Range: 44 to 140 dBm
+                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.133 9.1.4 */
+    int rsrq;            /* The current Reference Signal Receive Quality in dB multiplied by -1.
+                          * Range: 20 to 3 dB.
+                          * INT_MAX: 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.133 9.1.7 */
+    int rssnr;           /* The current reference signal signal-to-noise ratio in 0.1 dB units.
+                          * Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
+                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.101 8.1.1 */
+    int cqi;             /* The current Channel Quality Indicator.
+                          * Range: 0 to 15.
+                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP TS 36.101 9.2, 9.3, A.4 */
+    int timingAdvance;   /* timing advance in micro seconds for a one way trip from cell to device.
+                          * Approximate distance can be calculated using 300m/us * timingAdvance.
+                          * Range: 0 to 0x7FFFFFFE
+                          * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                          * Reference: 3GPP 36.321 section 6.1.3.5
+                          * also: http://www.cellular-planningoptimization.com/2010/02/timing-advance-with-calculation.html */
+} RIL_LTE_SignalStrength_v8;
+
+typedef struct {
+    int rscp;    /* The Received Signal Code Power in dBm multipled by -1.
+                  * Range : 25 to 120
+                  * INT_MAX: 0x7FFFFFFF denotes invalid value.
+                  * Reference: 3GPP TS 25.123, section 9.1.1.1 */
+} RIL_TD_SCDMA_SignalStrength;
+
+typedef struct {
+  int32_t ssRsrp;   /* SS reference signal received power, multiplied by -1.
+                     * Reference: 3GPP TS 38.215.
+                     * Range [44, 140], INT_MAX means invalid/unreported. */
+  int32_t ssRsrq;   /* SS reference signal received quality, multiplied by -1.
+                     * Reference: 3GPP TS 38.215.
+                     * Range [3, 20], INT_MAX means invalid/unreported. */
+  int32_t ssSinr;   /* SS signal-to-noise and interference ratio.
+                     * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+                     * Range [-23, 40], INT_MAX means invalid/unreported. */
+  int32_t csiRsrp;  /* CSI reference signal received power, multiplied by -1.
+                     * Reference: 3GPP TS 38.215.
+                     * Range [44, 140], INT_MAX means invalid/unreported. */
+  int32_t csiRsrq;  /* CSI reference signal received quality, multiplied by -1.
+                     * Reference: 3GPP TS 38.215.
+                     * Range [3, 20], INT_MAX means invalid/unreported. */
+  int32_t csiSinr;  /* CSI signal-to-noise and interference ratio.
+                     * Reference: 3GPP TS 138.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+                     * Range [-23, 40], INT_MAX means invalid/unreported. */
+} RIL_NR_SignalStrength;
+
+/* Deprecated, use RIL_SignalStrength_v6 */
+typedef struct {
+    RIL_GW_SignalStrength   GW_SignalStrength;
+    RIL_CDMA_SignalStrength CDMA_SignalStrength;
+    RIL_EVDO_SignalStrength EVDO_SignalStrength;
+} RIL_SignalStrength_v5;
+
+typedef struct {
+    RIL_GW_SignalStrength   GW_SignalStrength;
+    RIL_CDMA_SignalStrength CDMA_SignalStrength;
+    RIL_EVDO_SignalStrength EVDO_SignalStrength;
+    RIL_LTE_SignalStrength  LTE_SignalStrength;
+} RIL_SignalStrength_v6;
+
+typedef struct {
+    RIL_GW_SignalStrength       GW_SignalStrength;
+    RIL_CDMA_SignalStrength     CDMA_SignalStrength;
+    RIL_EVDO_SignalStrength     EVDO_SignalStrength;
+    RIL_LTE_SignalStrength_v8   LTE_SignalStrength;
+} RIL_SignalStrength_v8;
+
+typedef struct {
+    RIL_GW_SignalStrength       GW_SignalStrength;
+    RIL_CDMA_SignalStrength     CDMA_SignalStrength;
+    RIL_EVDO_SignalStrength     EVDO_SignalStrength;
+    RIL_LTE_SignalStrength_v8   LTE_SignalStrength;
+    RIL_TD_SCDMA_SignalStrength TD_SCDMA_SignalStrength;
+} RIL_SignalStrength_v10;
+
+typedef struct {
+    RIL_GW_SignalStrength       GW_SignalStrength;
+    RIL_CDMA_SignalStrength     CDMA_SignalStrength;
+    RIL_EVDO_SignalStrength     EVDO_SignalStrength;
+    RIL_LTE_SignalStrength_v8   LTE_SignalStrength;
+    RIL_TD_SCDMA_SignalStrength TD_SCDMA_SignalStrength;
+    RIL_SignalStrengthWcdma     WCDMA_SignalStrength;
+    RIL_NR_SignalStrength       NR_SignalStrength;
+} RIL_SignalStrength_v12;
+
+/**
+ * Defining signal strength type.
+ */
+typedef enum {
+    /**
+     * Received Signal Strength Indication.
+     * Range: -113 dBm and -51 dBm
+     * Used RAN: GERAN, CDMA2000
+     * Reference: 3GPP TS 27.007 section 8.5.
+     */
+    RSSI = 1,
+    /**
+     * Received Signal Code Power.
+     * Range: -120 dBm to -25 dBm;
+     * Used RAN: UTRAN
+     * Reference: 3GPP TS 25.123, section 9.1.1.1
+     */
+    RSCP = 2,
+    /**
+     * Reference Signal Received Power.
+     * Range: -140 dBm to -44 dBm;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 9.1.4
+     */
+    RSRP = 3,
+    /**
+     * Reference Signal Received Quality
+     * Range: -34 dB to 3 dB;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 v12.6.0 section 9.1.7
+     */
+    RSRQ = 4,
+    /**
+     * Reference Signal Signal to Noise Ratio
+     * Range: -20 dB to 30 dB;
+     * Used RAN: EUTRAN
+     * Note: this field is optional; how to support it can be decided by the
+     * corresponding vendor. Though the response code is not enforced,
+     * vendor's implementation must ensure this interface not crashing.
+     */
+    RSSNR = 5,
+    /**
+     * 5G SS reference signal received power.
+     * Range: -140 dBm to -44 dBm.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    SSRSRP = 6,
+    /**
+     * 5G SS reference signal received quality.
+     * Range: -20 dB to -3 dB.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    SSRSRQ = 7,
+    /**
+     * 5G SS signal-to-noise and interference ratio.
+     * Range: -23 dB to 40 dB
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+     */
+    SSSINR = 8,
+} SignalMeasurementType;
+
+typedef enum {
+    RADIO_ACCESS_UNKNOWN = 0, /* Unknown access network */
+    RADIO_ACCESS_NET_GERAN = 1, /* GSM EDGE Radio Access Network */
+    RADIO_ACCESS_NET_UTRAN = 2, /* Universal Terrestrial Radio Access Network */
+    RADIO_ACCESS_NET_EUTRAN = 3, /* Evolved Universal Terrestrial Radio Access Network */
+    RADIO_ACCESS_NET_CDMA2000 = 4, /* CDMA 2000 network */
+    RADIO_ACCESS_NET_IWLAN = 5, /* Interworking Wireless LAN */
+    RADIO_ACCESS_NET_NGRAN = 6, /* Next-Generation Radio Access Network */
+/* the following definitions are extended in radio/1.4 */
+} RIL_RadioAccessNetworks_v1_5;
+
+typedef struct {
+    int32_t hysteresisMs;
+    int32_t hysteresisDb;
+    int32_t thresholdsDbmNumber;
+    int32_t *thresholdsDbm;
+    bool isEnabled;
+    SignalMeasurementType signalMeasurement;
+    RIL_RadioAccessNetworks_v1_5 accessNetwork;
+} RIL_SignalStrengthReportingCriteria_v1_5;
+
+typedef struct {
+    int32_t hysteresisMs;
+    int32_t hysteresisDlKbps;
+    int32_t hysteresisUlKbps;
+    int32_t thresholdsDownlinkKbpsLength;
+    int32_t *thresholdsDownlinkKbps;
+    int32_t thresholdsUplinkKbpsLength;
+    int32_t *thresholdsUplinkKbps;
+    RIL_RadioAccessNetworks_v1_5 accessNetwork;
+} RIL_LinkCapacityReportingCriteria;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
+                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
+                   INT_MAX if unknown */
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 16-bit GSM Cell Identity described in TS 27.007, 0..65535, INT_MAX if unknown  */
+} RIL_CellIdentityGsm;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
+                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
+                   INT_MAX if unknown */
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 16-bit GSM Cell Identity described in TS 27.007, 0..65535, INT_MAX if unknown  */
+    int arfcn;  /* 16-bit GSM Absolute RF channel number; this value must be reported */
+    uint8_t bsic; /* 6-bit Base Station Identity Code; 0xFF if unknown */
+} RIL_CellIdentityGsm_v12;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
+                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
+                   INT_MAX if unknown */
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
+    int psc;    /* 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511, INT_MAX if unknown */
+} RIL_CellIdentityWcdma;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
+                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
+                   INT_MAX if unknown */
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
+    int psc;    /* 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511; this value must be reported */
+    int uarfcn; /* 16-bit UMTS Absolute RF Channel Number; this value must be reported */
+} RIL_CellIdentityWcdma_v12;
+
+typedef struct {
+    int networkId;      /* Network Id 0..65535, INT_MAX if unknown */
+    int systemId;       /* CDMA System Id 0..32767, INT_MAX if unknown  */
+    int basestationId;  /* Base Station Id 0..65535, INT_MAX if unknown  */
+    int longitude;      /* Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+                         * It is represented in units of 0.25 seconds and ranges from -2592000
+                         * to 2592000, both values inclusive (corresponding to a range of -180
+                         * to +180 degrees). INT_MAX if unknown */
+
+    int latitude;       /* Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+                         * It is represented in units of 0.25 seconds and ranges from -1296000
+                         * to 1296000, both values inclusive (corresponding to a range of -90
+                         * to +90 degrees). INT_MAX if unknown */
+} RIL_CellIdentityCdma;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
+                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
+                   INT_MAX if unknown */
+    int ci;     /* 28-bit Cell Identity described in TS ???, INT_MAX if unknown */
+    int pci;    /* physical cell id 0..503, INT_MAX if unknown  */
+    int tac;    /* 16-bit tracking area code, INT_MAX if unknown  */
+} RIL_CellIdentityLte;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
+                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
+                   INT_MAX if unknown */
+    int ci;     /* 28-bit Cell Identity described in TS ???, INT_MAX if unknown */
+    int pci;    /* physical cell id 0..503; this value must be reported */
+    int tac;    /* 16-bit tracking area code, INT_MAX if unknown  */
+    int earfcn; /* 18-bit LTE Absolute RF Channel Number; this value must be reported */
+} RIL_CellIdentityLte_v12;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999;
+                   the most significant nibble encodes the number of digits - {2, 3, 0 (unset)};
+                   INT_MAX if unknown */
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
+    int cpid;    /* 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown */
+} RIL_CellIdentityTdscdma;
+
+typedef struct  {
+    char alphaLong[32];   /* Long alpha Operator Name String or Enhanced Operator Name String.*/
+    char alphaShort[32];  /* Short alpha Operator Name String or Enhanced Operator Name String */
+} RIL_CellIdentityOperatorNames;
+
+typedef struct {
+    int mcc;           /* 3-digit Mobile Country Code, in range[0, 999]; This value must
+                        * be valid for registered or camped cells; INT_MAX means invalid/unreported. */
+    int mnc;           /* 2 or 3-digit Mobile Network Code, in range [0, 999], This value must be valid for
+                        * registered or camped cells; INT_MAX means invalid/unreported. */
+    uint64_t nci;      /* NR Cell Identity in range [0, 68719476735] (36 bits) described in 3GPP TS 38.331, which
+                        * unambiguously identifies a cell within a PLMN. This value must be valid for registered or
+                        * camped cells; LONG_MAX (2^63-1) means invalid/unreported.*/
+    uint32_t pci;      /* Physical cell id in range [0, 1007] described in 3GPP TS 38.331. This value must be valid. */
+    int32_t tac;       /* 16-bit tracking area code, INT_MAX means invalid/unreported. */
+    int32_t nrarfcn;   /* NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
+                        * Reference: 3GPP TS 38.101-1 and 3GPP TS 38.101-2 section 5.4.2.1.
+                        * This value must be valid. */
+
+    RIL_CellIdentityOperatorNames operatorNames;
+} RIL_CellIdentityNr;
+
+typedef struct {
+  RIL_CellIdentityGsm   cellIdentityGsm;
+  RIL_GW_SignalStrength signalStrengthGsm;
+} RIL_CellInfoGsm;
+
+typedef struct {
+  RIL_CellIdentityGsm_v12   cellIdentityGsm;
+  RIL_GSM_SignalStrength_v12 signalStrengthGsm;
+} RIL_CellInfoGsm_v12;
+
+typedef struct {
+  RIL_CellIdentityWcdma cellIdentityWcdma;
+  RIL_SignalStrengthWcdma signalStrengthWcdma;
+} RIL_CellInfoWcdma;
+
+typedef struct {
+  RIL_CellIdentityWcdma_v12 cellIdentityWcdma;
+  RIL_SignalStrengthWcdma signalStrengthWcdma;
+} RIL_CellInfoWcdma_v12;
+
+typedef struct {
+  RIL_CellIdentityCdma      cellIdentityCdma;
+  RIL_CDMA_SignalStrength   signalStrengthCdma;
+  RIL_EVDO_SignalStrength   signalStrengthEvdo;
+} RIL_CellInfoCdma;
+
+typedef struct {
+  RIL_CellIdentityLte        cellIdentityLte;
+  RIL_LTE_SignalStrength_v8  signalStrengthLte;
+} RIL_CellInfoLte;
+
+typedef struct {
+  RIL_CellIdentityLte_v12    cellIdentityLte;
+  RIL_LTE_SignalStrength_v8  signalStrengthLte;
+} RIL_CellInfoLte_v12;
+
+typedef struct {
+  RIL_CellIdentityTdscdma     cellIdentityTdscdma;
+  RIL_TD_SCDMA_SignalStrength signalStrengthTdscdma;
+} RIL_CellInfoTdscdma;
+
+typedef struct {
+  RIL_CellIdentityNr          cellidentity;
+  RIL_NR_SignalStrength       signalStrength;
+} RIL_CellInfoNr;
+
+// Must be the same as CellInfo.TYPE_XXX
+typedef enum {
+  RIL_CELL_INFO_TYPE_NONE   = 0, /* indicates no cell information */
+  RIL_CELL_INFO_TYPE_GSM    = 1,
+  RIL_CELL_INFO_TYPE_CDMA   = 2,
+  RIL_CELL_INFO_TYPE_LTE    = 3,
+  RIL_CELL_INFO_TYPE_WCDMA  = 4,
+  RIL_CELL_INFO_TYPE_TD_SCDMA  = 5,
+  RIL_CELL_INFO_TYPE_NR        = 6
+} RIL_CellInfoType;
+
+// Must be the same as CellInfo.TIMESTAMP_TYPE_XXX
+typedef enum {
+    RIL_TIMESTAMP_TYPE_UNKNOWN = 0,
+    RIL_TIMESTAMP_TYPE_ANTENNA = 1,
+    RIL_TIMESTAMP_TYPE_MODEM = 2,
+    RIL_TIMESTAMP_TYPE_OEM_RIL = 3,
+    RIL_TIMESTAMP_TYPE_JAVA_RIL = 4,
+} RIL_TimeStampType;
+
+typedef enum {
+    CELL_CONNECTION_NONE = 0,           // Cell is not a serving cell.
+    CELL_CONNECTION_PRIMARY_SERVING,    // UE has connection to cell for signalling and
+                                        // possibly data (3GPP 36.331, 25.331).
+    CELL_CONNECTION_SECONDARY_SERVING,  // UE has connection to cell for data (3GPP 36.331, 25.331).
+} RIL_CellConnectionStatus;
+
+typedef struct {
+  RIL_CellInfoType  cellInfoType;   /* cell type for selecting from union CellInfo */
+  int               registered;     /* !0 if this cell is registered 0 if not registered */
+  RIL_TimeStampType timeStampType;  /* type of time stamp represented by timeStamp */
+  uint64_t          timeStamp;      /* Time in nanos as returned by ril_nano_time */
+  union {
+    RIL_CellInfoGsm     gsm;
+    RIL_CellInfoCdma    cdma;
+    RIL_CellInfoLte     lte;
+    RIL_CellInfoWcdma   wcdma;
+    RIL_CellInfoTdscdma tdscdma;
+  } CellInfo;
+} RIL_CellInfo;
+
+typedef struct {
+  RIL_CellInfoType  cellInfoType;   /* cell type for selecting from union CellInfo */
+  int               registered;     /* !0 if this cell is registered 0 if not registered */
+  RIL_TimeStampType timeStampType;  /* type of time stamp represented by timeStamp */
+  uint64_t          timeStamp;      /* Time in nanos as returned by ril_nano_time */
+  union {
+    RIL_CellInfoGsm_v12     gsm;
+    RIL_CellInfoCdma        cdma;
+    RIL_CellInfoLte_v12     lte;
+    RIL_CellInfoWcdma_v12   wcdma;
+    RIL_CellInfoTdscdma     tdscdma;
+  } CellInfo;
+} RIL_CellInfo_v12;
+
+typedef struct {
+  RIL_CellInfoType          cellInfoType;   /* cell type for selecting from union CellInfo */
+  int                       registered;     /* !0 if this cell is registered 0 if not registered */
+  RIL_CellConnectionStatus  connectionStatus;  /* Connection status for the cell. */
+  union {
+    RIL_CellInfoGsm_v12     gsm;
+    RIL_CellInfoCdma        cdma;
+    RIL_CellInfoLte_v12     lte;
+    RIL_CellInfoWcdma_v12   wcdma;
+    RIL_CellInfoTdscdma     tdscdma;
+    RIL_CellInfoNr          nr;
+  } CellInfo;
+} RIL_CellInfo_v16;
+
+typedef struct {
+  RIL_CellInfoType  cellInfoType;   /* cell type for selecting from union CellInfo */
+  union {
+    RIL_CellIdentityGsm_v12 cellIdentityGsm;
+    RIL_CellIdentityWcdma_v12 cellIdentityWcdma;
+    RIL_CellIdentityLte_v12 cellIdentityLte;
+    RIL_CellIdentityTdscdma cellIdentityTdscdma;
+    RIL_CellIdentityCdma cellIdentityCdma;
+  };
+}RIL_CellIdentity_v16;
+
+typedef struct {
+  RIL_CellInfoType  cellInfoType;   /* cell type for selecting from union CellInfo */
+  union {
+    RIL_CellIdentityGsm_v12 cellIdentityGsm;
+    RIL_CellIdentityWcdma_v12 cellIdentityWcdma;
+    RIL_CellIdentityLte_v12 cellIdentityLte;
+    RIL_CellIdentityTdscdma cellIdentityTdscdma;
+    RIL_CellIdentityCdma cellIdentityCdma;
+    RIL_CellIdentityNr cellIdentityNr;
+  };
+} RIL_CellIdentity_v20;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999, INT_MAX if unknown */
+    int mnc_digit;/*2 or 3-digit*/
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 16-bit GSM Cell Identity described in TS 27.007, 0..65535, INT_MAX if unknown  */
+    int arfcn;  /* 16-bit GSM Absolute RF channel number, INT_MAX if unknown */
+    uint8_t bsic;/* 6-bit Base Station Identity Code, 0xFF if unknown */
+
+    RIL_CellIdentityOperatorNames operatorNames;
+} RIL_CellIdentityGsm_v1_2;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999, INT_MAX if unknown  */
+    int mnc_digit;/*2 or 3-digit*/
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
+    int psc;    /* 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511, INT_MAX if unknown */
+    int uarfcn; /* 16-bit UMTS Absolute RF Channel Number, INT_MAX if unknown */
+
+    RIL_CellIdentityOperatorNames operatorNames;
+} RIL_CellIdentityWcdma_v1_2;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999, INT_MAX if unknown  */
+    int mnc_digit;/*2 or 3-digit*/
+    int ci;     /* 28-bit Cell Identity described in TS ???, INT_MAX if unknown */
+    int pci;    /* physical cell id 0..503; this value must be reported */
+    int tac;    /* 16-bit tracking area code, INT_MAX if unknown  */
+    int earfcn; /* 18-bit LTE Absolute RF Channel Number; this value must be reported */
+
+    RIL_CellIdentityOperatorNames operatorNames;
+    int32_t bandwidth;  /* Cell bandwidth, in kHz. */
+} RIL_CellIdentityLte_v1_2;
+
+typedef struct {
+    int mcc;    /* 3-digit Mobile Country Code, 0..999, INT_MAX if unknown  */
+    int mnc;    /* 2 or 3-digit Mobile Network Code, 0..999, INT_MAX if unknown  */
+    int mnc_digit;/*2 or 3-digit*/
+    int lac;    /* 16-bit Location Area Code, 0..65535, INT_MAX if unknown  */
+    int cid;    /* 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown  */
+    int cpid;    /* 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown */
+
+    int32_t uarfcn;  /* 16-bit UMTS Absolute RF Channel Number defined in TS 25.102 5.4.4; this value must be valid. */
+    RIL_CellIdentityOperatorNames operatorNames;
+} RIL_CellIdentityTdscdma_v1_2;
+
+typedef struct {
+    int networkId;      /* Network Id 0..65535, INT_MAX if unknown */
+    int systemId;       /* CDMA System Id 0..32767, INT_MAX if unknown  */
+    int basestationId;  /* Base Station Id 0..65535, INT_MAX if unknown  */
+    int longitude;      /* Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+                         * It is represented in units of 0.25 seconds and ranges from -2592000
+                         * to 2592000, both values inclusive (corresponding to a range of -180
+                         * to +180 degrees). INT_MAX if unknown */
+
+    int latitude;       /* Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+                         * It is represented in units of 0.25 seconds and ranges from -1296000
+                         * to 1296000, both values inclusive (corresponding to a range of -90
+                         * to +90 degrees). INT_MAX if unknown */
+
+    RIL_CellIdentityOperatorNames operatorNames;
+} RIL_CellIdentityCdma_v1_2;
+
+typedef struct {
+    /**
+     * Cell type for selecting from union CellInfo.
+     * Only one of the below vectors must be of size 1 based on a
+     * valid CellInfoType and others must be of size 0.
+     * If cell info type is NONE, then all the vectors must be of size 0.
+     */
+    RIL_CellInfoType cellInfoType;
+    union {
+      RIL_CellIdentityGsm_v1_2 cellIdentityGsm;
+      RIL_CellIdentityWcdma_v1_2 cellIdentityWcdma;
+      RIL_CellIdentityLte_v1_2 cellIdentityLte;
+      RIL_CellIdentityTdscdma_v1_2 cellIdentityTdscdma;
+      RIL_CellIdentityCdma_v1_2 cellIdentityCdma;
+    };
+} RIL_CellIdentity_v1_2;
+
+typedef struct {
+    RIL_RegState regState;                // Valid reg states are RIL_NOT_REG_AND_NOT_SEARCHING,
+                                          // REG_HOME, RIL_NOT_REG_AND_SEARCHING, REG_DENIED,
+                                          // UNKNOWN, REG_ROAMING defined in RegState
+    RIL_RadioTechnology rat;              // indicates the available voice radio technology,
+                                          // valid values as defined by RadioTechnology.
+    int32_t cssSupported;                 // concurrent services support indicator. if
+                                          // registered on a CDMA system.
+                                          // 0 - Concurrent services not supported,
+                                          // 1 - Concurrent services supported
+    int32_t roamingIndicator;             // TSB-58 Roaming Indicator if registered
+                                          // on a CDMA or EVDO system or -1 if not.
+                                          // Valid values are 0-255.
+    int32_t systemIsInPrl;                // indicates whether the current system is in the
+                                          // PRL if registered on a CDMA or EVDO system or -1 if
+                                          // not. 0=not in the PRL, 1=in the PRL
+    int32_t defaultRoamingIndicator;      // default Roaming Indicator from the PRL,
+                                          // if registered on a CDMA or EVDO system or -1 if not.
+                                          // Valid values are 0-255.
+    int32_t reasonForDenial;              // reasonForDenial if registration state is 3
+                                          // (Registration denied) this is an enumerated reason why
+                                          // registration was denied. See 3GPP TS 24.008,
+                                          // 10.5.3.6 and Annex G.
+                                          // 0 - General
+                                          // 1 - Authentication Failure
+                                          // 2 - IMSI unknown in HLR
+                                          // 3 - Illegal MS
+                                          // 4 - Illegal ME
+                                          // 5 - PLMN not allowed
+                                          // 6 - Location area not allowed
+                                          // 7 - Roaming not allowed
+                                          // 8 - No Suitable Cells in this Location Area
+                                          // 9 - Network failure
+                                          // 10 - Persistent location update reject
+                                          // 11 - PLMN not allowed
+                                          // 12 - Location area not allowed
+                                          // 13 - Roaming not allowed in this Location Area
+                                          // 15 - No Suitable Cells in this Location Area
+                                          // 17 - Network Failure
+                                          // 20 - MAC Failure
+                                          // 21 - Sync Failure
+                                          // 22 - Congestion
+                                          // 23 - GSM Authentication unacceptable
+                                          // 25 - Not Authorized for this CSG
+                                          // 32 - Service option not supported
+                                          // 33 - Requested service option not subscribed
+                                          // 34 - Service option temporarily out of order
+                                          // 38 - Call cannot be identified
+                                          // 48-63 - Retry upon entry into a new cell
+                                          // 95 - Semantically incorrect message
+                                          // 96 - Invalid mandatory information
+                                          // 97 - Message type non-existent or not implemented
+                                          // 98 - Message type not compatible with protocol state
+                                          // 99 - Information element non-existent or
+                                          //      not implemented
+                                          // 100 - Conditional IE error
+                                          // 101 - Message not compatible with protocol state;
+    RIL_CellIdentity_v16 cellIdentity;    // current cell information
+}RIL_VoiceRegistrationStateResponse;
+
+typedef struct {
+    RIL_RegState regState;                // Valid reg states are RIL_NOT_REG_AND_NOT_SEARCHING,
+                                          // REG_HOME, RIL_NOT_REG_AND_SEARCHING, REG_DENIED,
+                                          // UNKNOWN, REG_ROAMING defined in RegState
+    RIL_RadioTechnology rat;              // indicates the available data radio technology,
+                                          // valid values as defined by RadioTechnology.
+    int32_t reasonDataDenied;             // if registration state is 3 (Registration
+                                          // denied) this is an enumerated reason why
+                                          // registration was denied. See 3GPP TS 24.008,
+                                          // Annex G.6 "Additional cause codes for GMM".
+                                          // 7 == GPRS services not allowed
+                                          // 8 == GPRS services and non-GPRS services not allowed
+                                          // 9 == MS identity cannot be derived by the network
+                                          // 10 == Implicitly detached
+                                          // 14 == GPRS services not allowed in this PLMN
+                                          // 16 == MSC temporarily not reachable
+                                          // 40 == No PDP context activated
+    int32_t maxDataCalls;                 // The maximum number of simultaneous Data Calls that
+                                          // must be established using setupDataCall().
+    RIL_CellIdentity_v16 cellIdentity;    // Current cell information
+}RIL_DataRegistrationStateResponse;
+
+/* Names of the CDMA info records (C.S0005 section 3.7.5) */
+typedef enum {
+  RIL_CDMA_DISPLAY_INFO_REC,
+  RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC,
+  RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC,
+  RIL_CDMA_CONNECTED_NUMBER_INFO_REC,
+  RIL_CDMA_SIGNAL_INFO_REC,
+  RIL_CDMA_REDIRECTING_NUMBER_INFO_REC,
+  RIL_CDMA_LINE_CONTROL_INFO_REC,
+  RIL_CDMA_EXTENDED_DISPLAY_INFO_REC,
+  RIL_CDMA_T53_CLIR_INFO_REC,
+  RIL_CDMA_T53_RELEASE_INFO_REC,
+  RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC
+} RIL_CDMA_InfoRecName;
+
+/* Display Info Rec as defined in C.S0005 section 3.7.5.1
+   Extended Display Info Rec as defined in C.S0005 section 3.7.5.16
+   Note: the Extended Display info rec contains multiple records of the
+   form: display_tag, display_len, and display_len occurrences of the
+   chari field if the display_tag is not 10000000 or 10000001.
+   To save space, the records are stored consecutively in a byte buffer.
+   The display_tag, display_len and chari fields are all 1 byte.
+*/
+
+typedef struct {
+  char alpha_len;
+  char alpha_buf[CDMA_ALPHA_INFO_BUFFER_LENGTH];
+} RIL_CDMA_DisplayInfoRecord;
+
+/* Called Party Number Info Rec as defined in C.S0005 section 3.7.5.2
+   Calling Party Number Info Rec as defined in C.S0005 section 3.7.5.3
+   Connected Number Info Rec as defined in C.S0005 section 3.7.5.4
+*/
+
+typedef struct {
+  char len;
+  char buf[CDMA_NUMBER_INFO_BUFFER_LENGTH];
+  char number_type;
+  char number_plan;
+  char pi;
+  char si;
+} RIL_CDMA_NumberInfoRecord;
+
+/* Redirecting Number Information Record as defined in C.S0005 section 3.7.5.11 */
+typedef enum {
+  RIL_REDIRECTING_REASON_UNKNOWN = 0,
+  RIL_REDIRECTING_REASON_CALL_FORWARDING_BUSY = 1,
+  RIL_REDIRECTING_REASON_CALL_FORWARDING_NO_REPLY = 2,
+  RIL_REDIRECTING_REASON_CALLED_DTE_OUT_OF_ORDER = 9,
+  RIL_REDIRECTING_REASON_CALL_FORWARDING_BY_THE_CALLED_DTE = 10,
+  RIL_REDIRECTING_REASON_CALL_FORWARDING_UNCONDITIONAL = 15,
+  RIL_REDIRECTING_REASON_RESERVED
+} RIL_CDMA_RedirectingReason;
+
+typedef struct {
+  RIL_CDMA_NumberInfoRecord redirectingNumber;
+  /* redirectingReason is set to RIL_REDIRECTING_REASON_UNKNOWN if not included */
+  RIL_CDMA_RedirectingReason redirectingReason;
+} RIL_CDMA_RedirectingNumberInfoRecord;
+
+/* Line Control Information Record as defined in C.S0005 section 3.7.5.15 */
+typedef struct {
+  char lineCtrlPolarityIncluded;
+  char lineCtrlToggle;
+  char lineCtrlReverse;
+  char lineCtrlPowerDenial;
+} RIL_CDMA_LineControlInfoRecord;
+
+/* T53 CLIR Information Record */
+typedef struct {
+  char cause;
+} RIL_CDMA_T53_CLIRInfoRecord;
+
+/* T53 Audio Control Information Record */
+typedef struct {
+  char upLink;
+  char downLink;
+} RIL_CDMA_T53_AudioControlInfoRecord;
+
+typedef struct {
+
+  RIL_CDMA_InfoRecName name;
+
+  union {
+    /* Display and Extended Display Info Rec */
+    RIL_CDMA_DisplayInfoRecord           display;
+
+    /* Called Party Number, Calling Party Number, Connected Number Info Rec */
+    RIL_CDMA_NumberInfoRecord            number;
+
+    /* Signal Info Rec */
+    RIL_CDMA_SignalInfoRecord            signal;
+
+    /* Redirecting Number Info Rec */
+    RIL_CDMA_RedirectingNumberInfoRecord redir;
+
+    /* Line Control Info Rec */
+    RIL_CDMA_LineControlInfoRecord       lineCtrl;
+
+    /* T53 CLIR Info Rec */
+    RIL_CDMA_T53_CLIRInfoRecord          clir;
+
+    /* T53 Audio Control Info Rec */
+    RIL_CDMA_T53_AudioControlInfoRecord  audioCtrl;
+  } rec;
+} RIL_CDMA_InformationRecord;
+
+#define RIL_CDMA_MAX_NUMBER_OF_INFO_RECS 10
+
+typedef struct {
+  char numberOfInfoRecs;
+  RIL_CDMA_InformationRecord infoRec[RIL_CDMA_MAX_NUMBER_OF_INFO_RECS];
+} RIL_CDMA_InformationRecords;
+
+/* See RIL_REQUEST_NV_READ_ITEM */
+typedef struct {
+  RIL_NV_Item itemID;
+} RIL_NV_ReadItem;
+
+/* See RIL_REQUEST_NV_WRITE_ITEM */
+typedef struct {
+  RIL_NV_Item   itemID;
+  char *        value;
+} RIL_NV_WriteItem;
+
+typedef enum {
+    HANDOVER_STARTED = 0,
+    HANDOVER_COMPLETED = 1,
+    HANDOVER_FAILED = 2,
+    HANDOVER_CANCELED = 3
+} RIL_SrvccState;
+
+/* hardware configuration reported to RILJ. */
+typedef enum {
+   RIL_HARDWARE_CONFIG_MODEM = 0,
+   RIL_HARDWARE_CONFIG_SIM = 1,
+} RIL_HardwareConfig_Type;
+
+typedef enum {
+   RIL_HARDWARE_CONFIG_STATE_ENABLED = 0,
+   RIL_HARDWARE_CONFIG_STATE_STANDBY = 1,
+   RIL_HARDWARE_CONFIG_STATE_DISABLED = 2,
+} RIL_HardwareConfig_State;
+
+typedef struct {
+   int rilModel;
+   uint32_t rat; /* bitset - ref. RIL_RadioTechnology. */
+   int maxVoice;
+   int maxData;
+   int maxStandby;
+} RIL_HardwareConfig_Modem;
+
+typedef struct {
+   char modemUuid[MAX_UUID_LENGTH];
+} RIL_HardwareConfig_Sim;
+
+typedef struct {
+  RIL_HardwareConfig_Type type;
+  char uuid[MAX_UUID_LENGTH];
+  RIL_HardwareConfig_State state;
+  union {
+     RIL_HardwareConfig_Modem modem;
+     RIL_HardwareConfig_Sim sim;
+  } cfg;
+} RIL_HardwareConfig;
+
+typedef enum {
+  SS_CFU,
+  SS_CF_BUSY,
+  SS_CF_NO_REPLY,
+  SS_CF_NOT_REACHABLE,
+  SS_CF_ALL,
+  SS_CF_ALL_CONDITIONAL,
+  SS_CLIP,
+  SS_CLIR,
+  SS_COLP,
+  SS_COLR,
+  SS_WAIT,
+  SS_BAOC,
+  SS_BAOIC,
+  SS_BAOIC_EXC_HOME,
+  SS_BAIC,
+  SS_BAIC_ROAMING,
+  SS_ALL_BARRING,
+  SS_OUTGOING_BARRING,
+  SS_INCOMING_BARRING
+} RIL_SsServiceType;
+
+typedef enum {
+  SS_ACTIVATION,
+  SS_DEACTIVATION,
+  SS_INTERROGATION,
+  SS_REGISTRATION,
+  SS_ERASURE
+} RIL_SsRequestType;
+
+typedef enum {
+  SS_ALL_TELE_AND_BEARER_SERVICES,
+  SS_ALL_TELESEVICES,
+  SS_TELEPHONY,
+  SS_ALL_DATA_TELESERVICES,
+  SS_SMS_SERVICES,
+  SS_ALL_TELESERVICES_EXCEPT_SMS
+} RIL_SsTeleserviceType;
+
+#define SS_INFO_MAX 4
+#define NUM_SERVICE_CLASSES 7
+
+typedef struct {
+  int numValidIndexes; /* This gives the number of valid values in cfInfo.
+                       For example if voice is forwarded to one number and data
+                       is forwarded to a different one then numValidIndexes will be
+                       2 indicating total number of valid values in cfInfo.
+                       Similarly if all the services are forwarded to the same
+                       number then the value of numValidIndexes will be 1. */
+
+  RIL_CallForwardInfo cfInfo[NUM_SERVICE_CLASSES]; /* This is the response data
+                                                      for SS request to query call
+                                                      forward status. see
+                                                      RIL_REQUEST_QUERY_CALL_FORWARD_STATUS */
+} RIL_CfData;
+
+typedef struct {
+  RIL_SsServiceType serviceType;
+  RIL_SsRequestType requestType;
+  RIL_SsTeleserviceType teleserviceType;
+  int serviceClass;
+  RIL_Errno result;
+
+  union {
+    int ssInfo[SS_INFO_MAX]; /* This is the response data for most of the SS GET/SET
+                                RIL requests. E.g. RIL_REQUSET_GET_CLIR returns
+                                two ints, so first two values of ssInfo[] will be
+                                used for response if serviceType is SS_CLIR and
+                                requestType is SS_INTERROGATION */
+
+    RIL_CfData cfData;
+  };
+} RIL_StkCcUnsolSsResponse;
+
+/**
+ * Data connection power state
+ */
+typedef enum {
+    RIL_DC_POWER_STATE_LOW      = 1,        // Low power state
+    RIL_DC_POWER_STATE_MEDIUM   = 2,        // Medium power state
+    RIL_DC_POWER_STATE_HIGH     = 3,        // High power state
+    RIL_DC_POWER_STATE_UNKNOWN  = INT32_MAX // Unknown state
+} RIL_DcPowerStates;
+
+/**
+ * Data connection real time info
+ */
+typedef struct {
+    uint64_t                    time;       // Time in nanos as returned by ril_nano_time
+    RIL_DcPowerStates           powerState; // Current power state
+} RIL_DcRtInfo;
+
+/**
+ * Data profile to modem
+ */
+typedef struct {
+    /* id of the data profile */
+    int profileId;
+    /* the APN to connect to */
+    char* apn;
+    /** one of the PDP_type values in TS 27.007 section 10.1.1.
+     * For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     */
+    char* protocol;
+    /** authentication protocol used for this PDP context
+     * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
+     */
+    int authType;
+    /* the username for APN, or NULL */
+    char* user;
+    /* the password for APN, or NULL */
+    char* password;
+    /* the profile type, TYPE_COMMON-0, TYPE_3GPP-1, TYPE_3GPP2-2 */
+    int type;
+    /* the period in seconds to limit the maximum connections */
+    int maxConnsTime;
+    /* the maximum connections during maxConnsTime */
+    int maxConns;
+    /** the required wait time in seconds after a successful UE initiated
+     * disconnect of a given PDN connection before the device can send
+     * a new PDN connection request for that given PDN
+     */
+    int waitTime;
+    /* true to enable the profile, 0 to disable, 1 to enable */
+    int enabled;
+} RIL_DataProfileInfo;
+
+typedef struct {
+    /* id of the data profile */
+    int profileId;
+    /* the APN to connect to */
+    char* apn;
+    /** one of the PDP_type values in TS 27.007 section 10.1.1.
+     * For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     */
+    char* protocol;
+    /** one of the PDP_type values in TS 27.007 section 10.1.1 used on roaming network.
+     * For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     */
+    char *roamingProtocol;
+    /** authentication protocol used for this PDP context
+     * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
+     */
+    int authType;
+    /* the username for APN, or NULL */
+    char* user;
+    /* the password for APN, or NULL */
+    char* password;
+    /* the profile type, TYPE_COMMON-0, TYPE_3GPP-1, TYPE_3GPP2-2 */
+    int type;
+    /* the period in seconds to limit the maximum connections */
+    int maxConnsTime;
+    /* the maximum connections during maxConnsTime */
+    int maxConns;
+    /** the required wait time in seconds after a successful UE initiated
+     * disconnect of a given PDN connection before the device can send
+     * a new PDN connection request for that given PDN
+     */
+    int waitTime;
+    /* true to enable the profile, 0 to disable, 1 to enable */
+    int enabled;
+    /* supported APN types bitmask. See RIL_ApnTypes for the value of each bit. */
+    int supportedTypesBitmask;
+    /** the bearer bitmask. See RIL_RadioAccessFamily for the value of each bit. */
+    int bearerBitmask;
+    /** maximum transmission unit (MTU) size in bytes */
+    int mtu;
+    /** the MVNO type: possible values are "imsi", "gid", "spn" */
+    char *mvnoType;
+    /** MVNO match data. Can be anything defined by the carrier. For example,
+     *        SPN like: "A MOBILE", "BEN NL", etc...
+     *        IMSI like: "302720x94", "2060188", etc...
+     *        GID like: "4E", "33", etc...
+     */
+    char *mvnoMatchData;
+} RIL_DataProfileInfo_v15;
+
+/* Tx Power Levels */
+#define RIL_NUM_TX_POWER_LEVELS     5
+
+/**
+ * Aggregate modem activity information
+ */
+typedef struct {
+
+  /* total time (in ms) when modem is in a low power or
+   * sleep state
+   */
+  uint32_t sleep_mode_time_ms;
+
+  /* total time (in ms) when modem is awake but neither
+   * the transmitter nor receiver are active/awake */
+  uint32_t idle_mode_time_ms;
+
+  /* total time (in ms) during which the transmitter is active/awake,
+   * subdivided by manufacturer-defined device-specific
+   * contiguous increasing ranges of transmit power between
+   * 0 and the transmitter's maximum transmit power.
+   */
+  uint32_t tx_mode_time_ms[RIL_NUM_TX_POWER_LEVELS];
+
+  /* total time (in ms) for which receiver is active/awake and
+   * the transmitter is inactive */
+  uint32_t rx_mode_time_ms;
+} RIL_ActivityStatsInfo;
+
+typedef enum {
+    RIL_APN_TYPE_UNKNOWN      = 0x0,          // Unknown
+    RIL_APN_TYPE_DEFAULT      = 0x1,          // APN type for default data traffic
+    RIL_APN_TYPE_MMS          = 0x2,          // APN type for MMS traffic
+    RIL_APN_TYPE_SUPL         = 0x4,          // APN type for SUPL assisted GPS
+    RIL_APN_TYPE_DUN          = 0x8,          // APN type for DUN traffic
+    RIL_APN_TYPE_HIPRI        = 0x10,         // APN type for HiPri traffic
+    RIL_APN_TYPE_FOTA         = 0x20,         // APN type for FOTA
+    RIL_APN_TYPE_IMS          = 0x40,         // APN type for IMS
+    RIL_APN_TYPE_CBS          = 0x80,         // APN type for CBS
+    RIL_APN_TYPE_IA           = 0x100,        // APN type for IA Initial Attach APN
+    RIL_APN_TYPE_EMERGENCY    = 0x200,        // APN type for Emergency PDN. This is not an IA apn,
+                                              // but is used for access to carrier services in an
+                                              // emergency call situation.
+    RIL_APN_TYPE_MCX          = 0x400,        // APN type for Mission Critical Service
+    RIL_APN_TYPE_XCAP         = 0x800,        // APN type for XCAP
+    RIL_APN_TYPE_ALL          = 0xFFFFFFFF    // All APN types
+} RIL_ApnTypes;
+
+typedef enum {
+    RIL_DST_POWER_SAVE_MODE,        // Device power save mode (provided by PowerManager)
+                                    // True indicates the device is in power save mode.
+    RIL_DST_CHARGING_STATE,         // Device charging state (provided by BatteryManager)
+                                    // True indicates the device is charging.
+    RIL_DST_LOW_DATA_EXPECTED       // Low data expected mode. True indicates low data traffic
+                                    // is expected, for example, when the device is idle
+                                    // (e.g. not doing tethering in the background). Note
+                                    // this doesn't mean no data is expected.
+} RIL_DeviceStateType;
+
+typedef enum {
+    RIL_UR_SIGNAL_STRENGTH            = 0x01, // When this bit is set, modem should always send the
+                                              // signal strength update through
+                                              // RIL_UNSOL_SIGNAL_STRENGTH, otherwise suppress it.
+    RIL_UR_FULL_NETWORK_STATE         = 0x02, // When this bit is set, modem should always send
+                                              // RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
+                                              // when any field in
+                                              // RIL_REQUEST_VOICE_REGISTRATION_STATE or
+                                              // RIL_REQUEST_DATA_REGISTRATION_STATE changes. When
+                                              // this bit is not set, modem should suppress
+                                              // RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
+                                              // only when insignificant fields change
+                                              // (e.g. cell info).
+                                              // Modem should continue sending
+                                              // RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
+                                              // when significant fields are updated even when this
+                                              // bit is not set. The following fields are
+                                              // considered significant, registration state and
+                                              // radio technology.
+    RIL_UR_DATA_CALL_DORMANCY_CHANGED = 0x04  // When this bit is set, modem should send the data
+                                              // call list changed unsolicited response
+                                              // RIL_UNSOL_DATA_CALL_LIST_CHANGED whenever any
+                                              // field in RIL_Data_Call_Response changes.
+                                              // Otherwise modem should suppress the unsolicited
+                                              // response when the only changed field is 'active'
+                                              // (for data dormancy). For all other fields change,
+                                              // modem should continue sending
+                                              // RIL_UNSOL_DATA_CALL_LIST_CHANGED regardless this
+                                              // bit is set or not.
+} RIL_UnsolicitedResponseFilter;
+
+typedef struct {
+    char * aidPtr; /* AID value, See ETSI 102.221 and 101.220*/
+    int p2;        /* P2 parameter (described in ISO 7816-4)
+                      P2Constants:NO_P2 if to be ignored */
+} RIL_OpenChannelParams;
+
+typedef enum {
+    RIL_ONE_SHOT = 0x01, // Performs the scan only once
+    RIL_PERIODIC = 0x02  // Performs the scan periodically until cancelled
+} RIL_ScanType;
+
+typedef enum {
+    UNKNOWN = 0x00,     // Unknown Radio Access Network
+    GERAN = 0x01,       // GSM EDGE Radio Access Network
+    UTRAN = 0x02,       // Universal Terrestrial Radio Access Network
+    EUTRAN = 0x03,      // Evolved Universal Terrestrial Radio Access Network
+    NGRAN = 0x04,       // Next-Generation Radio Access Network
+    CDMA2000 = 0x05,    // CDMA 2000 Radio AccessNetwork
+} RIL_RadioAccessNetworks;
+
+typedef struct {
+  char *operatorNumeric;
+  RIL_RadioAccessNetworks act;
+} RIL_NetworkOperator;
+
+typedef enum {
+    GERAN_BAND_T380 = 1,
+    GERAN_BAND_T410 = 2,
+    GERAN_BAND_450 = 3,
+    GERAN_BAND_480 = 4,
+    GERAN_BAND_710 = 5,
+    GERAN_BAND_750 = 6,
+    GERAN_BAND_T810 = 7,
+    GERAN_BAND_850 = 8,
+    GERAN_BAND_P900 = 9,
+    GERAN_BAND_E900 = 10,
+    GERAN_BAND_R900 = 11,
+    GERAN_BAND_DCS1800 = 12,
+    GERAN_BAND_PCS1900 = 13,
+    GERAN_BAND_ER900 = 14,
+} RIL_GeranBands;
+
+typedef enum {
+    UTRAN_BAND_1 = 1,
+    UTRAN_BAND_2 = 2,
+    UTRAN_BAND_3 = 3,
+    UTRAN_BAND_4 = 4,
+    UTRAN_BAND_5 = 5,
+    UTRAN_BAND_6 = 6,
+    UTRAN_BAND_7 = 7,
+    UTRAN_BAND_8 = 8,
+    UTRAN_BAND_9 = 9,
+    UTRAN_BAND_10 = 10,
+    UTRAN_BAND_11 = 11,
+    UTRAN_BAND_12 = 12,
+    UTRAN_BAND_13 = 13,
+    UTRAN_BAND_14 = 14,
+    UTRAN_BAND_19 = 19,
+    UTRAN_BAND_20 = 20,
+    UTRAN_BAND_21 = 21,
+    UTRAN_BAND_22 = 22,
+    UTRAN_BAND_25 = 25,
+    UTRAN_BAND_26 = 26,
+} RIL_UtranBands;
+
+typedef enum {
+    EUTRAN_BAND_1 = 1,
+    EUTRAN_BAND_2 = 2,
+    EUTRAN_BAND_3 = 3,
+    EUTRAN_BAND_4 = 4,
+    EUTRAN_BAND_5 = 5,
+    EUTRAN_BAND_6 = 6,
+    EUTRAN_BAND_7 = 7,
+    EUTRAN_BAND_8 = 8,
+    EUTRAN_BAND_9 = 9,
+    EUTRAN_BAND_10 = 10,
+    EUTRAN_BAND_11 = 11,
+    EUTRAN_BAND_12 = 12,
+    EUTRAN_BAND_13 = 13,
+    EUTRAN_BAND_14 = 14,
+    EUTRAN_BAND_17 = 17,
+    EUTRAN_BAND_18 = 18,
+    EUTRAN_BAND_19 = 19,
+    EUTRAN_BAND_20 = 20,
+    EUTRAN_BAND_21 = 21,
+    EUTRAN_BAND_22 = 22,
+    EUTRAN_BAND_23 = 23,
+    EUTRAN_BAND_24 = 24,
+    EUTRAN_BAND_25 = 25,
+    EUTRAN_BAND_26 = 26,
+    EUTRAN_BAND_27 = 27,
+    EUTRAN_BAND_28 = 28,
+    EUTRAN_BAND_30 = 30,
+    EUTRAN_BAND_31 = 31,
+    EUTRAN_BAND_33 = 33,
+    EUTRAN_BAND_34 = 34,
+    EUTRAN_BAND_35 = 35,
+    EUTRAN_BAND_36 = 36,
+    EUTRAN_BAND_37 = 37,
+    EUTRAN_BAND_38 = 38,
+    EUTRAN_BAND_39 = 39,
+    EUTRAN_BAND_40 = 40,
+    EUTRAN_BAND_41 = 41,
+    EUTRAN_BAND_42 = 42,
+    EUTRAN_BAND_43 = 43,
+    EUTRAN_BAND_44 = 44,
+    EUTRAN_BAND_45 = 45,
+    EUTRAN_BAND_46 = 46,
+    EUTRAN_BAND_47 = 47,
+    EUTRAN_BAND_48 = 48,
+    EUTRAN_BAND_65 = 65,
+    EUTRAN_BAND_66 = 66,
+    EUTRAN_BAND_68 = 68,
+    EUTRAN_BAND_70 = 70,
+} RIL_EutranBands;
+
+typedef enum {
+    NGRAN_BAND_1 = 1,
+    NGRAN_BAND_2 = 2,
+    NGRAN_BAND_3 = 3,
+    NGRAN_BAND_5 = 5,
+    NGRAN_BAND_7 = 7,
+    NGRAN_BAND_8 = 8,
+    NGRAN_BAND_12 = 12,
+    NGRAN_BAND_20 = 20,
+    NGRAN_BAND_25 = 25,
+    NGRAN_BAND_28 = 28,
+    NGRAN_BAND_34 = 34,
+    NGRAN_BAND_38 = 38,
+    NGRAN_BAND_39 = 39,
+    NGRAN_BAND_40 = 40,
+    NGRAN_BAND_41 = 41,
+    NGRAN_BAND_50 = 50,
+    NGRAN_BAND_51 = 51,
+    NGRAN_BAND_66 = 66,
+    NGRAN_BAND_70 = 70,
+    NGRAN_BAND_71 = 71,
+    NGRAN_BAND_74 = 74,
+    NGRAN_BAND_75 = 75,
+    NGRAN_BAND_76 = 76,
+    NGRAN_BAND_77 = 77,
+    NGRAN_BAND_78 = 78,
+    NGRAN_BAND_79 = 79,
+    NGRAN_BAND_80 = 80,
+    NGRAN_BAND_81 = 81,
+    NGRAN_BAND_82 = 82,
+    NGRAN_BAND_83 = 83,
+    NGRAN_BAND_84 = 84,
+    NGRAN_BAND_86 = 86,
+    NGRAN_BAND_257 = 257,
+    NGRAN_BAND_258 = 258,
+    NGRAN_BAND_260 = 260,
+    NGRAN_BAND_261 = 261,
+} RIL_NgranBands;
+
+typedef struct {
+    RIL_RadioAccessNetworks radio_access_network; // The type of network to scan.
+    uint32_t bands_length;                        // Length of bands
+    union {
+        RIL_GeranBands geran_bands[MAX_BANDS];
+        RIL_UtranBands utran_bands[MAX_BANDS];
+        RIL_EutranBands eutran_bands[MAX_BANDS];
+        RIL_NgranBands ngran_bands[MAX_BANDS];
+    } bands;
+    uint32_t channels_length;                     // Length of channels
+    uint32_t channels[MAX_CHANNELS];              // Frequency channels to scan
+} RIL_RadioAccessSpecifier;
+
+typedef struct {
+    RIL_ScanType type;                                              // Type of the scan
+    int32_t interval;                                               // Time interval in seconds
+                                                                    // between periodic scans, only
+                                                                    // valid when type=RIL_PERIODIC
+    uint32_t specifiers_length;                                     // Length of specifiers
+    RIL_RadioAccessSpecifier specifiers[MAX_RADIO_ACCESS_NETWORKS]; // Radio access networks
+                                                                    // with bands/channels.
+} RIL_NetworkScanRequest;
+
+typedef struct {
+    RIL_RadioAccessNetworks_v1_5 radio_access_network; // The type of network to scan.
+    uint32_t bands_length; // Length of bands
+    union {
+        RIL_GeranBands geran_bands[MAX_BANDS];
+        RIL_UtranBands utran_bands[MAX_BANDS];
+        RIL_EutranBands eutran_bands[MAX_BANDS];
+        RIL_NgranBands ngran_bands[MAX_BANDS];
+    } bands;
+    uint32_t channels_length; // Length of channels
+    uint32_t channels[MAX_CHANNELS]; // Frequency channels to scan
+} RIL_RadioAccessSpecifier_v1_5;
+
+typedef struct {
+    RIL_ScanType type;
+
+    int32_t interval;
+
+    uint32_t specifiers_length;  // Length of specifiers
+
+    RIL_RadioAccessSpecifier_v1_5 specifiers[RIL_RADIO_ACCESS_SPECIFIER_MAX_SIZE];
+
+    int32_t maxSearchTime;
+
+    int32_t incrementalResults;
+
+    int32_t incrementalResultsPeriodicity;
+
+    uint32_t mccMncsNumbers;
+
+    char **mccMncs;
+} RIL_NetworkScanRequest_v1_5;
+
+typedef struct {
+    int                              specifyChannels;
+    uint32_t                         specifiers_length;  // Length of specifiers
+    RIL_RadioAccessSpecifier_v1_5    specifiers[RIL_RADIO_ACCESS_SPECIFIER_MAX_SIZE];  // Radio access networks with bands/channels.
+} RIL_SystemSelectionChannels_v1_5;
+
+typedef enum {
+    PARTIAL = 0x01,   // The result contains a part of the scan results
+    COMPLETE = 0x02,  // The result contains the last part of the scan results
+} RIL_ScanStatus;
+
+typedef struct {
+    RIL_ScanStatus status;              // The status of the scan
+    uint32_t network_infos_length;      // Total length of RIL_CellInfo
+    RIL_CellInfo_v12* network_infos;    // List of network information
+    RIL_Errno error;
+} RIL_NetworkScanResult;
+
+
+
+/*********************Structs and Enums Extended in 1.4************************/
+/**
+ * Defining Emergency Service Category as follows:
+ * - General emergency call, all categories;
+ * - Police;
+ * - Ambulance;
+ * - Fire Brigade;
+ * - Marine Guard;
+ * - Mountain Rescue;
+ * - Manually Initiated eCall (MIeC);
+ * - Automatically Initiated eCall (AIeC);
+ *
+ * Category UNSPECIFIED (General emergency call, all categories) indicates that no specific
+ * services are associated with this emergency number.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+typedef enum {
+    CATEGORY_UNSPECIFIED     = 0,        /* General emergency call, all categories */
+    CATEGORY_POLICE          = 1 << 0,
+    CATEGORY_AMBULANCE       = 1 << 1,
+    CATEGORY_FIRE_BRIGADE    = 1 << 2,
+    CATEGORY_MARINE_GUARD    = 1 << 3,
+    CATEGORY_MOUNTAIN_RESCUE = 1 << 4,
+    CATEGORY_MIEC            = 1 << 5,  /* Manually Initiated eCall (MIeC) */
+    CATEGORY_AIEC            = 1 << 6,  /* Automatically Initiated eCall (AIeC) */
+} RIL_EmergencyServiceCategory;
+
+/**
+ * The source to tell where the corresponding @1.4::EmergencyNumber comes from.
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+typedef enum {
+    SOURCE_NETWORK_SIGNALING   = 1 << 0,   /* Indicates the number is from the network signal. */
+    SOURCE_SIM                 = 1 << 1,   /* Indicates the number is from the sim card. */
+    SOURCE_MODEM_CONFIG        = 1 << 2,   /* Indicates the number is from the modem config. */
+    SOURCE_DEFAULT             = 1 << 3,   /* Indicates the number is available as default.
+                                            * Per the reference, 112, 911 must always be available;
+                                            * additionally, 000, 08, 110, 999, 118 and 119 must be available
+                                            * when sim is not present. */
+} RIL_EmergencyNumberSource;
+
+/**
+ * Indicates how the implementation should handle the emergency call if it is required by Android.
+ */
+typedef enum {
+    ROUTING_UNKNOWN    = 0,  /* Indicates Android does not require how to handle
+                                   * the corresponding emergency call; it is decided by implementation. */
+    ROUTING_MERGENCY   = 1,  /* Indicates the implementation must handle the call through emergency routing. */
+    ROUTING_NORMAL     = 2,  /* Indicates the implementation must handle the call through normal call routing. */
+} RIL_EmergencyCallRouting;
+
+/**
+ * Emergency number contains information of number, one or more service category(s), zero or more
+ * emergency uniform resource names, mobile country code (mcc), mobile network country (mnc) and
+ * source(s) that indicate where it comes from.
+ *
+ * If the emergency number is associated with country, field ‘mcc’ must be provided, otherwise
+ * field ‘mcc’ must be an empty string. If the emergency number is associated with network
+ * operator, field ‘mcc’ and 'mnc' must be provided, otherwise field ‘mnc’ must be an empty
+ * string. If the emergency number is specified with emergency service category(s), field
+ * 'categories' must be provided, otherwise field 'categories' must be
+ * @1.4::EmergencyServiceCategories::UNSPECIFIED. If the emergency number is specified with
+ * emergency uniform resource names (URN), field 'urns' must be provided, otherwise field 'urns'
+ * must be an empty list.
+ *
+ * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc', 'categories' and
+ * 'urns' fields. Multiple @1.4::EmergencyNumberSource should be merged into one 'sources' field
+ * via bitwise-OR combination for the same EmergencyNumber.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls;
+ *            3gpp 23.167, Section 6 - Functional description;
+ *            3gpp 24.503, Section 5.1.6.8.1 - General;
+ *            RFC 5031
+ */
+typedef struct {
+    RIL_Dial                     dialInfo;
+    RIL_EmergencyServiceCategory categories; /* The bitfield of @1.4::EmergencyServiceCategory(s).
+                                              * See RIL_EmergencyServiceCategory for the value of each bit. */
+    uint32_t                     urnsNumber;
+    char **                      urns;       /* The list of emergency Uniform Resource Names (URN). */
+    RIL_EmergencyNumberSource    sources;    /* The bitfield of @1.4::EmergencyNumberSource(s).
+                                              * See RIL_EmergencyNumberSource for the value of each bit. */
+    RIL_EmergencyCallRouting     routing;
+    bool                         fromEmergencyDialer;
+} RIL_EmergencyDial;
+
+/******************************************************************************/
+/* Radio Config structure @{ */
+typedef enum {
+    /* Physical slot is inactive*/
+    SLOT_STATE_INACTIVE  = 0x00,
+    /* Physical slot is active */
+    SLOT_STATE_ACTIVE    = 0x01,
+} RIL_SlotState;
+
+typedef struct {
+    /* Card state in the physical slot*/
+    RIL_CardState cardState;
+    /* Slot state Active/Inactive */
+    RIL_SlotState slotState;
+    /**
+      * An Answer To Reset (ATR) is a message output by a Smart Card conforming to ISO/IEC 7816
+      * standards, following electrical reset of the card's chip. The ATR conveys information about
+      * the communication parameters proposed by the card, and the card's nature and state.
+      * This data is applicable only when cardState is CardState:PRESENT.
+      */
+    char* atr;
+    int logicalSlotId;
+    /**
+      * Integrated Circuit Card IDentifier (ICCID) is Unique Identifier of the SIM CARD. File is
+      * located in the SIM card at EFiccid (0x2FE2) as per ETSI 102.221. The ICCID is defined by
+      * the ITU-T recommendation E.118 ISO/IEC 7816.
+      * This data is applicable only when cardState is CardState:PRESENT.
+      */
+    char* iccid;
+} RIL_SimSlotStatus;
+
+typedef struct {
+    RIL_SimSlotStatus base;
+    /**
+      * The EID is the eUICC identifier. The EID shall be stored within the ECASD and can be
+      * retrieved by the Device at any time using the standard GlobalPlatform GET DATA command.
+      *
+      * This data is mandatory and applicable only when cardState is CardState:PRESENT and SIM card
+      * supports eUICC.
+      */
+    char* eid;
+} RIL_SimSlotStatus_V1_2;
+
+#define MAX_LOGICAL_MODEM_NUM 4
+
+typedef struct {
+    /* Logical modem ID. */
+    int modemId;
+} RIL_ModemInfo;
+
+typedef struct {
+    /**
+     * maxActiveData defines how many logical modems can have
+     * PS attached simultaneously. For example, for L+L modem it
+     * should be 2.
+     */
+    int maxActiveData;
+    /**
+     * maxActiveData defines how many logical modems can have
+     * internet PDN connections simultaneously. For example, for L+L
+     * DSDS modem it’s 1, and for DSDA modem it’s 2.
+     */
+    int maxActiveInternetData;
+    /**
+     * Whether modem supports both internet PDN up so
+     * that we can do ping test before tearing down the
+     * other one.
+     */
+    int isInternetLingeringSupported;
+    /**
+     * List of logical modem information.
+     */
+    RIL_ModemInfo logicalModemList[MAX_LOGICAL_MODEM_NUM];
+} RIL_PhoneCapability;
+
+typedef struct {
+    int numOfLiveModems;
+} RIL_ModemConfig;
+/* }@ */
+
+typedef enum {
+    DATA_REQ_REASOPN_NORMAL    = 0x01,  // The reason of the data request is normal
+    DATA_REQ_REASOPN_SHUTDOWN  = 0x02,  // The reason of the data request is device shutdown
+    DATA_REQ_REASOPN_HANDOVER  = 0x03,  // The reason of the data request is IWLAN data handover
+                                        // to another transport (e.g. from cellular to wifi or vise versa)
+} RIL_DataRequestReason;
+
+/**
+ * RIL_REQUEST_GET_SIM_STATUS
+ *
+ * Requests status of the SIM interface and the SIM card
+ *
+ * "data" is NULL
+ *
+ * "response" is const RIL_CardStatus_v6 *
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_GET_SIM_STATUS 1
+
+/**
+ * RIL_REQUEST_ENTER_SIM_PIN
+ *
+ * Supplies SIM PIN. Only called if RIL_CardStatus has RIL_APPSTATE_PIN state
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is PIN value
+ * ((const char **)data)[1] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE (radio resetting)
+ * PASSWORD_INCORRECT
+ * INTERNAL_ERR
+ * NO_MEMORY
+ * NO_RESOURCES
+ * CANCELLED
+ * INVALID_ARGUMENTS
+ * INVALID_SIM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_ENTER_SIM_PIN 2
+
+/**
+ * RIL_REQUEST_ENTER_SIM_PUK
+ *
+ * Supplies SIM PUK and new PIN.
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is PUK value
+ * ((const char **)data)[1] is new PIN value
+ * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  PASSWORD_INCORRECT
+ *     (PUK is invalid)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_ARGUMENTS
+ *  INVALID_SIM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_ENTER_SIM_PUK 3
+
+/**
+ * RIL_REQUEST_ENTER_SIM_PIN2
+ *
+ * Supplies SIM PIN2. Only called following operation where SIM_PIN2 was
+ * returned as a a failure from a previous operation.
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is PIN2 value
+ * ((const char **)data)[1] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  PASSWORD_INCORRECT
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_ARGUMENTS
+ *  INVALID_SIM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_ENTER_SIM_PIN2 4
+
+/**
+ * RIL_REQUEST_ENTER_SIM_PUK2
+ *
+ * Supplies SIM PUK2 and new PIN2.
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is PUK2 value
+ * ((const char **)data)[1] is new PIN2 value
+ * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  PASSWORD_INCORRECT
+ *     (PUK2 is invalid)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_ARGUMENTS
+ *  INVALID_SIM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_ENTER_SIM_PUK2 5
+
+/**
+ * RIL_REQUEST_CHANGE_SIM_PIN
+ *
+ * Supplies old SIM PIN and new PIN.
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is old PIN value
+ * ((const char **)data)[1] is new PIN value
+ * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  PASSWORD_INCORRECT
+ *     (old PIN is invalid)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_ARGUMENTS
+ *  INVALID_SIM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_CHANGE_SIM_PIN 6
+
+
+/**
+ * RIL_REQUEST_CHANGE_SIM_PIN2
+ *
+ * Supplies old SIM PIN2 and new PIN2.
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is old PIN2 value
+ * ((const char **)data)[1] is new PIN2 value
+ * ((const char **)data)[2] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  PASSWORD_INCORRECT
+ *     (old PIN2 is invalid)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_ARGUMENTS
+ *  INVALID_SIM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+
+#define RIL_REQUEST_CHANGE_SIM_PIN2 7
+
+/**
+ * RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION
+ *
+ * Requests that network personlization be deactivated
+ *
+ * "data" is const char **
+ * ((const char **)(data))[0]] is network depersonlization code
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  PASSWORD_INCORRECT
+ *  SIM_ABSENT
+ *     (code is invalid)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
+
+/**
+ * RIL_REQUEST_GET_CURRENT_CALLS
+ *
+ * Requests current call list
+ *
+ * "data" is NULL
+ *
+ * "response" must be a "const RIL_Call **"
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *      (request will be made again in a few hundred msec)
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_GET_CURRENT_CALLS 9
+
+
+/**
+ * RIL_REQUEST_DIAL
+ *
+ * Initiate voice call
+ *
+ * "data" is const RIL_Dial *
+ * "response" is NULL
+ *
+ * This method is never used for supplementary service codes
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  DIAL_MODIFIED_TO_USSD
+ *  DIAL_MODIFIED_TO_SS
+ *  DIAL_MODIFIED_TO_DIAL
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  INVALID_STATE
+ *  NO_RESOURCES
+ *  INTERNAL_ERR
+ *  FDN_CHECK_FAILURE
+ *  MODEM_ERR
+ *  NO_SUBSCRIPTION
+ *  NO_NETWORK_FOUND
+ *  INVALID_CALL_ID
+ *  DEVICE_IN_USE
+ *  OPERATION_NOT_ALLOWED
+ *  ABORTED
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_DIAL 10
+
+/**
+ * RIL_REQUEST_GET_IMSI
+ *
+ * Get the SIM IMSI
+ *
+ * Only valid when radio state is "RADIO_STATE_ON"
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ * "response" is a const char * containing the IMSI
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_SIM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_GET_IMSI 11
+
+/**
+ * RIL_REQUEST_HANGUP
+ *
+ * Hang up a specific line (like AT+CHLD=1x)
+ *
+ * After this HANGUP request returns, RIL should show the connection is NOT
+ * active anymore in next RIL_REQUEST_GET_CURRENT_CALLS query.
+ *
+ * "data" is an int *
+ * (int *)data)[0] contains Connection index (value of 'x' in CHLD above)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  INVALID_STATE
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  INVALID_CALL_ID
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_HANGUP 12
+
+/**
+ * RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND
+ *
+ * Hang up waiting or held (like AT+CHLD=0)
+ *
+ * After this HANGUP request returns, RIL should show the connection is NOT
+ * active anymore in next RIL_REQUEST_GET_CURRENT_CALLS query.
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  INVALID_CALL_ID
+ *  NO_RESOURCES
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
+
+/**
+ * RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
+ *
+ * Hang up waiting or held (like AT+CHLD=1)
+ *
+ * After this HANGUP request returns, RIL should show the connection is NOT
+ * active anymore in next RIL_REQUEST_GET_CURRENT_CALLS query.
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
+
+/**
+ * RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE
+ *
+ * Switch waiting or holding call and active call (like AT+CHLD=2)
+ *
+ * State transitions should be is follows:
+ *
+ * If call 1 is waiting and call 2 is active, then if this re
+ *
+ *   BEFORE                               AFTER
+ * Call 1   Call 2                 Call 1       Call 2
+ * ACTIVE   HOLDING                HOLDING     ACTIVE
+ * ACTIVE   WAITING                HOLDING     ACTIVE
+ * HOLDING  WAITING                HOLDING     ACTIVE
+ * ACTIVE   IDLE                   HOLDING     IDLE
+ * IDLE     IDLE                   IDLE        IDLE
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  INVALID_CALL_ID
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE 15
+#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
+
+/**
+ * RIL_REQUEST_CONFERENCE
+ *
+ * Conference holding and active (like AT+CHLD=3)
+
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_STATE
+ *  INVALID_CALL_ID
+ *  INVALID_ARGUMENTS
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_CONFERENCE 16
+
+/**
+ * RIL_REQUEST_UDUB
+ *
+ * Send UDUB (user determined used busy) to ringing or
+ * waiting call answer)(RIL_BasicRequest r);
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_STATE
+ *  NO_RESOURCES
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_ARGUMENTS
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_UDUB 17
+
+/**
+ * RIL_REQUEST_LAST_CALL_FAIL_CAUSE
+ *
+ * Requests the failure cause code for the most recently terminated call
+ *
+ * "data" is NULL
+ * "response" is a const RIL_LastCallFailCauseInfo *
+ * RIL_LastCallFailCauseInfo contains LastCallFailCause and vendor cause.
+ * The vendor cause code must be used for debugging purpose only.
+ * The implementation must return one of the values of LastCallFailCause
+ * as mentioned below.
+ *
+ * GSM failure reasons codes for the cause codes defined in TS 24.008 Annex H
+ * where possible.
+ * CDMA failure reasons codes for the possible call failure scenarios
+ * described in the "CDMA IS-2000 Release A (C.S0005-A v6.0)" standard.
+ * Any of the following reason codes if the call is failed or dropped due to reason
+ * mentioned with in the braces.
+ *
+ *      CALL_FAIL_RADIO_OFF (Radio is OFF)
+ *      CALL_FAIL_OUT_OF_SERVICE (No cell coverage)
+ *      CALL_FAIL_NO_VALID_SIM (No valid SIM)
+ *      CALL_FAIL_RADIO_INTERNAL_ERROR (Modem hit unexpected error scenario)
+ *      CALL_FAIL_NETWORK_RESP_TIMEOUT (No response from network)
+ *      CALL_FAIL_NETWORK_REJECT (Explicit network reject)
+ *      CALL_FAIL_RADIO_ACCESS_FAILURE (RRC connection failure. Eg.RACH)
+ *      CALL_FAIL_RADIO_LINK_FAILURE (Radio Link Failure)
+ *      CALL_FAIL_RADIO_LINK_LOST (Radio link lost due to poor coverage)
+ *      CALL_FAIL_RADIO_UPLINK_FAILURE (Radio uplink failure)
+ *      CALL_FAIL_RADIO_SETUP_FAILURE (RRC connection setup failure)
+ *      CALL_FAIL_RADIO_RELEASE_NORMAL (RRC connection release, normal)
+ *      CALL_FAIL_RADIO_RELEASE_ABNORMAL (RRC connection release, abnormal)
+ *      CALL_FAIL_ACCESS_CLASS_BLOCKED (Access class barring)
+ *      CALL_FAIL_NETWORK_DETACH (Explicit network detach)
+ *
+ * OEM causes (CALL_FAIL_OEM_CAUSE_XX) must be used for debug purpose only
+ *
+ * If the implementation does not have access to the exact cause codes,
+ * then it should return one of the values listed in RIL_LastCallFailCause,
+ * as the UI layer needs to distinguish these cases for tone generation or
+ * error notification.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE
+ */
+#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
+
+/**
+ * RIL_REQUEST_SIGNAL_STRENGTH
+ *
+ * Requests current signal strength and associated information
+ *
+ * Must succeed if radio is on.
+ *
+ * "data" is NULL
+ *
+ * "response" is a const RIL_SignalStrength *
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SIGNAL_STRENGTH 19
+
+/**
+ * RIL_REQUEST_VOICE_REGISTRATION_STATE
+ *
+ * Request current registration state
+ *
+ * "data" is NULL
+ * "response" is a const RIL_VoiceRegistrationStateResponse *
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
+
+/**
+ * RIL_REQUEST_DATA_REGISTRATION_STATE
+ *
+ * Request current DATA registration state
+ *
+ * "data" is NULL
+ * "response" is a const RIL_DataRegistrationStateResponse *
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
+
+/**
+ * RIL_REQUEST_OPERATOR
+ *
+ * Request current operator ONS or EONS
+ *
+ * "data" is NULL
+ * "response" is a "const char **"
+ * ((const char **)response)[0] is long alpha ONS or EONS
+ *                                  or NULL if unregistered
+ *
+ * ((const char **)response)[1] is short alpha ONS or EONS
+ *                                  or NULL if unregistered
+ * ((const char **)response)[2] is 5 or 6 digit numeric code (MCC + MNC)
+ *                                  or NULL if unregistered
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_OPERATOR 22
+
+/**
+ * RIL_REQUEST_RADIO_POWER
+ *
+ * Toggle radio on and off (for "airplane" mode)
+ * If the radio is is turned off/on the radio modem subsystem
+ * is expected return to an initialized state. For instance,
+ * any voice and data calls will be terminated and all associated
+ * lists emptied.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is > 0 for "Radio On"
+ * ((int *)data)[0] is == 0 for "Radio Off"
+ *
+ * "response" is NULL
+ *
+ * Turn radio on if "on" > 0
+ * Turn radio off if "on" == 0
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  DEVICE_IN_USE
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_RADIO_POWER 23
+
+/**
+ * RIL_REQUEST_DTMF
+ *
+ * Send a DTMF tone
+ *
+ * If the implementation is currently playing a tone requested via
+ * RIL_REQUEST_DTMF_START, that tone should be cancelled and the new tone
+ * should be played instead
+ *
+ * "data" is a char * containing a single character with one of 12 values: 0-9,*,#
+ * "response" is NULL
+ *
+ * FIXME should this block/mute microphone?
+ * How does this interact with local DTMF feedback?
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_DTMF_STOP, RIL_REQUEST_DTMF_START
+ *
+ */
+#define RIL_REQUEST_DTMF 24
+
+/**
+ * RIL_REQUEST_SEND_SMS
+ *
+ * Send an SMS message
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is SMSC address in GSM BCD format prefixed
+ *      by a length byte (as expected by TS 27.005) or NULL for default SMSC
+ * ((const char **)data)[1] is SMS in PDU format as an ASCII hex string
+ *      less the SMSC address
+ *      TP-Layer-Length is be "strlen(((const char **)data)[1])/2"
+ *
+ * "response" is a const RIL_SMS_Response *
+ *
+ * Based on the return error, caller decides to resend if sending sms
+ * fails. SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SMS_SEND_FAIL_RETRY
+ *  FDN_CHECK_FAILURE
+ *  NETWORK_REJECT
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  INVALID_SMS_FORMAT
+ *  SYSTEM_ERR
+ *  ENCODING_ERR
+ *  INVALID_SMSC_ADDRESS
+ *  MODEM_ERR
+ *  NETWORK_ERR
+ *  OPERATION_NOT_ALLOWED
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  MODE_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ * FIXME how do we specify TP-Message-Reference if we need to resend?
+ */
+#define RIL_REQUEST_SEND_SMS 25
+
+
+/**
+ * RIL_REQUEST_SEND_SMS_EXPECT_MORE
+ *
+ * Send an SMS message. Identical to RIL_REQUEST_SEND_SMS,
+ * except that more messages are expected to be sent soon. If possible,
+ * keep SMS relay protocol link open (eg TS 27.005 AT+CMMS command)
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is SMSC address in GSM BCD format prefixed
+ *      by a length byte (as expected by TS 27.005) or NULL for default SMSC
+ * ((const char **)data)[1] is SMS in PDU format as an ASCII hex string
+ *      less the SMSC address
+ *      TP-Layer-Length is be "strlen(((const char **)data)[1])/2"
+ *
+ * "response" is a const RIL_SMS_Response *
+ *
+ * Based on the return error, caller decides to resend if sending sms
+ * fails. SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SMS_SEND_FAIL_RETRY
+ *  NETWORK_REJECT
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  INVALID_SMS_FORMAT
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+ *  FDN_CHECK_FAILURE
+ *  MODEM_ERR
+ *  NETWORK_ERR
+ *  ENCODING_ERR
+ *  INVALID_SMSC_ADDRESS
+ *  OPERATION_NOT_ALLOWED
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  MODE_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ */
+#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
+
+
+/**
+ * RIL_REQUEST_SETUP_DATA_CALL
+ *
+ * Setup a packet data connection. If RIL_Data_Call_Response_v6.status
+ * return success it is added to the list of data calls and a
+ * RIL_UNSOL_DATA_CALL_LIST_CHANGED is sent. The call remains in the
+ * list until RIL_REQUEST_DEACTIVATE_DATA_CALL is issued or the
+ * radio is powered off/on. This list is returned by RIL_REQUEST_DATA_CALL_LIST
+ * and RIL_UNSOL_DATA_CALL_LIST_CHANGED.
+ *
+ * The RIL is expected to:
+ *  - Create one data call context.
+ *  - Create and configure a dedicated interface for the context
+ *  - The interface must be point to point.
+ *  - The interface is configured with one or more addresses and
+ *    is capable of sending and receiving packets. The prefix length
+ *    of the addresses must be /32 for IPv4 and /128 for IPv6.
+ *  - Must NOT change the linux routing table.
+ *  - Support up to RIL_REQUEST_DATA_REGISTRATION_STATE response[5]
+ *    number of simultaneous data call contexts.
+ *
+ * "data" is a const char **
+ * ((const char **)data)[0] Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2...
+ *                          for values above 2 this is RIL_RadioTechnology + 2.
+ * ((const char **)data)[1] is a RIL_DataProfile (support is optional)
+ * ((const char **)data)[2] is the APN to connect to if radio technology is GSM/UMTS. This APN will
+ *                          override the one in the profile. NULL indicates no APN overrride.
+ * ((const char **)data)[3] is the username for APN, or NULL
+ * ((const char **)data)[4] is the password for APN, or NULL
+ * ((const char **)data)[5] is the PAP / CHAP auth type. Values:
+ *                          0 => PAP and CHAP is never performed.
+ *                          1 => PAP may be performed; CHAP is never performed.
+ *                          2 => CHAP may be performed; PAP is never performed.
+ *                          3 => PAP / CHAP may be performed - baseband dependent.
+ * ((const char **)data)[6] is the non-roaming/home connection type to request. Must be one of the
+ *                          PDP_type values in TS 27.007 section 10.1.1.
+ *                          For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ * ((const char **)data)[7] is the roaming connection type to request. Must be one of the
+ *                          PDP_type values in TS 27.007 section 10.1.1.
+ *                          For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ * ((const char **)data)[8] is the bitmask of APN type in decimal string format. The
+ *                          bitmask will encapsulate the following values:
+ *                          ia,mms,agps,supl,hipri,fota,dun,ims,default.
+ * ((const char **)data)[9] is the bearer bitmask in decimal string format. Each bit is a
+ *                          RIL_RadioAccessFamily. "0" or NULL indicates all RATs.
+ * ((const char **)data)[10] is the boolean in string format indicating the APN setting was
+ *                           sent to the modem through RIL_REQUEST_SET_DATA_PROFILE earlier.
+ * ((const char **)data)[11] is the mtu size in bytes of the mobile interface to which
+ *                           the apn is connected.
+ * ((const char **)data)[12] is the MVNO type:
+ *                           possible values are "imsi", "gid", "spn".
+ * ((const char **)data)[13] is MVNO match data in string. Can be anything defined by the carrier.
+ *                           For example,
+ *                           SPN like: "A MOBILE", "BEN NL", etc...
+ *                           IMSI like: "302720x94", "2060188", etc...
+ *                           GID like: "4E", "33", etc...
+ * ((const char **)data)[14] is the boolean string indicating data roaming is allowed or not. "1"
+ *                           indicates data roaming is enabled by the user, "0" indicates disabled.
+ *
+ * "response" is a RIL_Data_Call_Response_v11
+ *
+ * FIXME may need way to configure QoS settings
+ *
+ * Valid errors:
+ *  SUCCESS should be returned on both success and failure of setup with
+ *  the RIL_Data_Call_Response_v6.status containing the actual status.
+ *  For all other errors the RIL_Data_Call_Resonse_v6 is ignored.
+ *
+ *  Other errors could include:
+ *    RADIO_NOT_AVAILABLE, OP_NOT_ALLOWED_BEFORE_REG_TO_NW,
+ *    OP_NOT_ALLOWED_DURING_VOICE_CALL, REQUEST_NOT_SUPPORTED,
+ *    INVALID_ARGUMENTS, INTERNAL_ERR, NO_MEMORY, NO_RESOURCES,
+ *    CANCELLED and SIM_ABSENT
+ *
+ * See also: RIL_REQUEST_DEACTIVATE_DATA_CALL
+ */
+#define RIL_REQUEST_SETUP_DATA_CALL 27
+
+
+/**
+ * RIL_REQUEST_SIM_IO
+ *
+ * Request SIM I/O operation.
+ * This is similar to the TS 27.007 "restricted SIM" operation
+ * where it assumes all of the EF selection will be done by the
+ * callee.
+ *
+ * "data" is a const RIL_SIM_IO_v6 *
+ * Please note that RIL_SIM_IO has a "PIN2" field which may be NULL,
+ * or may specify a PIN2 for operations that require a PIN2 (eg
+ * updating FDN records)
+ *
+ * "response" is a const RIL_SIM_IO_Response *
+ *
+ * Arguments and responses that are unused for certain
+ * values of "command" should be ignored or set to NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_PIN2
+ *  SIM_PUK2
+ *  INVALID_SIM_STATE
+ *  SIM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SIM_IO 28
+
+/**
+ * RIL_REQUEST_SEND_USSD
+ *
+ * Send a USSD message
+ *
+ * If a USSD session already exists, the message should be sent in the
+ * context of that session. Otherwise, a new session should be created.
+ *
+ * The network reply should be reported via RIL_UNSOL_ON_USSD
+ *
+ * Only one USSD session may exist at a time, and the session is assumed
+ * to exist until:
+ *   a) The android system invokes RIL_REQUEST_CANCEL_USSD
+ *   b) The implementation sends a RIL_UNSOL_ON_USSD with a type code
+ *      of "0" (USSD-Notify/no further action) or "2" (session terminated)
+ *
+ * "data" is a const char * containing the USSD request in UTF-8 format
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  FDN_CHECK_FAILURE
+ *  USSD_MODIFIED_TO_DIAL
+ *  USSD_MODIFIED_TO_SS
+ *  USSD_MODIFIED_TO_USSD
+ *  SIM_BUSY
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  ABORTED
+ *  SYSTEM_ERR
+ *  INVALID_STATE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_CANCEL_USSD, RIL_UNSOL_ON_USSD
+ */
+
+#define RIL_REQUEST_SEND_USSD 29
+
+/**
+ * RIL_REQUEST_CANCEL_USSD
+ *
+ * Cancel the current USSD session if one exists
+ *
+ * "data" is null
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_BUSY
+ *  OPERATION_NOT_ALLOWED
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  INVALID_STATE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_CANCEL_USSD 30
+
+/**
+ * RIL_REQUEST_GET_CLIR
+ *
+ * Gets current CLIR status
+ * "data" is NULL
+ * "response" is int *
+ * ((int *)data)[0] is "n" parameter from TS 27.007 7.7
+ * ((int *)data)[1] is "m" parameter from TS 27.007 7.7
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  FDN_CHECK_FAILURE
+ *  SYSTEM_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_GET_CLIR 31
+
+/**
+ * RIL_REQUEST_SET_CLIR
+ *
+ * "data" is int *
+ * ((int *)data)[0] is "n" parameter from TS 27.007 7.7
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  INVALID_ARGUMENTS
+ *  SYSTEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SET_CLIR 32
+
+/**
+ * RIL_REQUEST_QUERY_CALL_FORWARD_STATUS
+ *
+ * "data" is const RIL_CallForwardInfo *
+ *
+ * "response" is const RIL_CallForwardInfo **
+ * "response" points to an array of RIL_CallForwardInfo *'s, one for
+ * each distinct registered phone number.
+ *
+ * For example, if data is forwarded to +18005551212 and voice is forwarded
+ * to +18005559999, then two separate RIL_CallForwardInfo's should be returned
+ *
+ * If, however, both data and voice are forwarded to +18005551212, then
+ * a single RIL_CallForwardInfo can be returned with the service class
+ * set to "data + voice = 3")
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  FDN_CHECK_FAILURE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
+
+
+/**
+ * RIL_REQUEST_SET_CALL_FORWARD
+ *
+ * Configure call forward rule
+ *
+ * "data" is const RIL_CallForwardInfo *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_STATE
+ *  FDN_CHECK_FAILURE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SET_CALL_FORWARD 34
+
+
+/**
+ * RIL_REQUEST_QUERY_CALL_WAITING
+ *
+ * Query current call waiting state
+ *
+ * "data" is const int *
+ * ((const int *)data)[0] is the TS 27.007 service class to query.
+ * "response" is a const int *
+ * ((const int *)response)[0] is 0 for "disabled" and 1 for "enabled"
+ *
+ * If ((const int *)response)[0] is = 1, then ((const int *)response)[1]
+ * must follow, with the TS 27.007 service class bit vector of services
+ * for which call waiting is enabled.
+ *
+ * For example, if ((const int *)response)[0]  is 1 and
+ * ((const int *)response)[1] is 3, then call waiting is enabled for data
+ * and voice and disabled for everything else
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  FDN_CHECK_FAILURE
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_QUERY_CALL_WAITING 35
+
+
+/**
+ * RIL_REQUEST_SET_CALL_WAITING
+ *
+ * Configure current call waiting state
+ *
+ * "data" is const int *
+ * ((const int *)data)[0] is 0 for "disabled" and 1 for "enabled"
+ * ((const int *)data)[1] is the TS 27.007 service class bit vector of
+ *                           services to modify
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_STATE
+ *  FDN_CHECK_FAILURE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SET_CALL_WAITING 36
+
+/**
+ * RIL_REQUEST_SMS_ACKNOWLEDGE
+ *
+ * Acknowledge successful or failed receipt of SMS previously indicated
+ * via RIL_UNSOL_RESPONSE_NEW_SMS
+ *
+ * "data" is int *
+ * ((int *)data)[0] is 1 on successful receipt
+ *                  (basically, AT+CNMA=1 from TS 27.005
+ *                  is 0 on failed receipt
+ *                  (basically, AT+CNMA=2 from TS 27.005)
+ * ((int *)data)[1] if data[0] is 0, this contains the failure cause as defined
+ *                  in TS 23.040, 9.2.3.22. Currently only 0xD3 (memory
+ *                  capacity exceeded) and 0xFF (unspecified error) are
+ *                  reported.
+ *
+ * "response" is NULL
+ *
+ * FIXME would like request that specified RP-ACK/RP-ERROR PDU
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SMS_ACKNOWLEDGE  37
+
+/**
+ * RIL_REQUEST_GET_IMEI - DEPRECATED
+ *
+ * Get the device IMEI, including check digit
+ *
+ * The request is DEPRECATED, use RIL_REQUEST_DEVICE_IDENTITY
+ * Valid when RadioState is not RADIO_STATE_UNAVAILABLE
+ *
+ * "data" is NULL
+ * "response" is a const char * containing the IMEI
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+
+#define RIL_REQUEST_GET_IMEI 38
+
+/**
+ * RIL_REQUEST_GET_IMEISV - DEPRECATED
+ *
+ * Get the device IMEISV, which should be two decimal digits
+ *
+ * The request is DEPRECATED, use RIL_REQUEST_DEVICE_IDENTITY
+ * Valid when RadioState is not RADIO_STATE_UNAVAILABLE
+ *
+ * "data" is NULL
+ * "response" is a const char * containing the IMEISV
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+
+#define RIL_REQUEST_GET_IMEISV 39
+
+
+/**
+ * RIL_REQUEST_ANSWER
+ *
+ * Answer incoming call
+ *
+ * Will not be called for WAITING calls.
+ * RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE will be used in this case
+ * instead
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_ANSWER 40
+
+/**
+ * RIL_REQUEST_DEACTIVATE_DATA_CALL
+ *
+ * Deactivate packet data connection and remove from the
+ * data call list if SUCCESS is returned. Any other return
+ * values should also try to remove the call from the list,
+ * but that may not be possible. In any event a
+ * RIL_REQUEST_RADIO_POWER off/on must clear the list. An
+ * RIL_UNSOL_DATA_CALL_LIST_CHANGED is not expected to be
+ * issued because of an RIL_REQUEST_DEACTIVATE_DATA_CALL.
+ *
+ * "data" is const char **
+ * ((char**)data)[0] indicating CID
+ * ((char**)data)[1] indicating Disconnect Reason
+ *                   0 => No specific reason specified
+ *                   1 => Radio shutdown requested
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_CALL_ID
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  REQUEST_NOT_SUPPORTED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  SIM_ABSENT
+ *
+ * See also: RIL_REQUEST_SETUP_DATA_CALL
+ */
+#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
+
+/**
+ * RIL_REQUEST_QUERY_FACILITY_LOCK
+ *
+ * Query the status of a facility lock state
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is the facility string code from TS 27.007 7.4
+ *                      (eg "AO" for BAOC, "SC" for SIM lock)
+ * ((const char **)data)[1] is the password, or "" if not required
+ * ((const char **)data)[2] is the TS 27.007 service class bit vector of
+ *                           services to query
+ * ((const char **)data)[3] is AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *                            This is only applicable in the case of Fixed Dialing Numbers
+ *                            (FDN) requests.
+ *
+ * "response" is an int *
+ * ((const int *)response) 0 is the TS 27.007 service class bit vector of
+ *                           services for which the specified barring facility
+ *                           is active. "0" means "disabled for all"
+ *
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  FDN_CHECK_FAILURE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
+
+/**
+ * RIL_REQUEST_SET_FACILITY_LOCK
+ *
+ * Enable/disable one facility lock
+ *
+ * "data" is const char **
+ *
+ * ((const char **)data)[0] = facility string code from TS 27.007 7.4
+ * (eg "AO" for BAOC)
+ * ((const char **)data)[1] = "0" for "unlock" and "1" for "lock"
+ * ((const char **)data)[2] = password
+ * ((const char **)data)[3] = string representation of decimal TS 27.007
+ *                            service class bit vector. Eg, the string
+ *                            "1" means "set this facility for voice services"
+ * ((const char **)data)[4] = AID value, See ETSI 102.221 8.1 and 101.220 4, NULL if no value.
+ *                            This is only applicable in the case of Fixed Dialing Numbers
+ *                            (FDN) requests.
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining, or -1 if unknown
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  INVALID_ARGUMENTS
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INVALID_STATE
+ *  FDN_CHECK_FAILURE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_SET_FACILITY_LOCK 43
+
+/**
+ * RIL_REQUEST_CHANGE_BARRING_PASSWORD
+ *
+ * Change call barring facility password
+ *
+ * "data" is const char **
+ *
+ * ((const char **)data)[0] = facility string code from TS 27.007 7.4
+ * (eg "AO" for BAOC)
+ * ((const char **)data)[1] = old password
+ * ((const char **)data)[2] = new password
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  FDN_CHECK_FAILURE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
+
+/**
+ * RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE
+ *
+ * Query current network selectin mode
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * ((const int *)response)[0] is
+ *     0 for automatic selection
+ *     1 for manual selection
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
+
+/**
+ * RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC
+ *
+ * Specify that the network should be selected automatically
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * This request must not respond until the new operator is selected
+ * and registered
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  ILLEGAL_SIM_OR_ME
+ *  OPERATION_NOT_ALLOWED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ * Note: Returns ILLEGAL_SIM_OR_ME when the failure is permanent and
+ *       no retries needed, such as illegal SIM or ME.
+ *
+ */
+#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
+
+/**
+ * RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL
+ *
+ * Manually select a specified network.
+ *
+ * "data" is const char * specifying MCCMNC of network to select (eg "310170")
+ * "response" is NULL
+ *
+ * This request must not respond until the new operator is selected
+ * and registered
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  ILLEGAL_SIM_OR_ME
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ * Note: Returns ILLEGAL_SIM_OR_ME when the failure is permanent and
+ *       no retries needed, such as illegal SIM or ME.
+ *
+ */
+#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
+
+/**
+ * RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
+ *
+ * Scans for available networks
+ *
+ * "data" is NULL
+ * "response" is const char ** that should be an array of n*4 strings, where
+ *    n is the number of available networks
+ * For each available network:
+ *
+ * ((const char **)response)[n+0] is long alpha ONS or EONS
+ * ((const char **)response)[n+1] is short alpha ONS or EONS
+ * ((const char **)response)[n+2] is 5 or 6 digit numeric code (MCC + MNC)
+ * ((const char **)response)[n+3] is a string value of the status:
+ *           "unknown"
+ *           "available"
+ *           "current"
+ *           "forbidden"
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  ABORTED
+ *  DEVICE_IN_USE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  CANCELLED
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
+
+/**
+ * RIL_REQUEST_DTMF_START
+ *
+ * Start playing a DTMF tone. Continue playing DTMF tone until
+ * RIL_REQUEST_DTMF_STOP is received
+ *
+ * If a RIL_REQUEST_DTMF_START is received while a tone is currently playing,
+ * it should cancel the previous tone and play the new one.
+ *
+ * "data" is a char *
+ * ((char *)data)[0] is a single character with one of 12 values: 0-9,*,#
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_DTMF, RIL_REQUEST_DTMF_STOP
+ */
+#define RIL_REQUEST_DTMF_START 49
+
+/**
+ * RIL_REQUEST_DTMF_STOP
+ *
+ * Stop playing a currently playing DTMF tone.
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  NO_MEMORY
+ *  INVALID_ARGUMENTS
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_DTMF, RIL_REQUEST_DTMF_START
+ */
+#define RIL_REQUEST_DTMF_STOP 50
+
+/**
+ * RIL_REQUEST_BASEBAND_VERSION
+ *
+ * Return string value indicating baseband version, eg
+ * response from AT+CGMR
+ *
+ * "data" is NULL
+ * "response" is const char * containing version string for log reporting
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  EMPTY_RECORD
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_BASEBAND_VERSION 51
+
+/**
+ * RIL_REQUEST_SEPARATE_CONNECTION
+ *
+ * Separate a party from a multiparty call placing the multiparty call
+ * (less the specified party) on hold and leaving the specified party
+ * as the only other member of the current (active) call
+ *
+ * Like AT+CHLD=2x
+ *
+ * See TS 22.084 1.3.8.2 (iii)
+ * TS 22.030 6.5.5 "Entering "2X followed by send"
+ * TS 27.007 "AT+CHLD=2x"
+ *
+ * "data" is an int *
+ * (int *)data)[0] contains Connection index (value of 'x' in CHLD above) "response" is NULL
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_ARGUMENTS
+ *  INVALID_STATE
+ *  NO_RESOURCES
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  INVALID_STATE
+ *  OPERATION_NOT_ALLOWED
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SEPARATE_CONNECTION 52
+
+
+/**
+ * RIL_REQUEST_SET_MUTE
+ *
+ * Turn on or off uplink (microphone) mute.
+ *
+ * Will only be sent while voice call is active.
+ * Will always be reset to "disable mute" when a new voice call is initiated
+ *
+ * "data" is an int *
+ * (int *)data)[0] is 1 for "enable mute" and 0 for "disable mute"
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_SET_MUTE 53
+
+/**
+ * RIL_REQUEST_GET_MUTE
+ *
+ * Queries the current state of the uplink mute setting
+ *
+ * "data" is NULL
+ * "response" is an int *
+ * (int *)response)[0] is 1 for "mute enabled" and 0 for "mute disabled"
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  SS_MODIFIED_TO_DIAL
+ *  SS_MODIFIED_TO_USSD
+ *  SS_MODIFIED_TO_SS
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_GET_MUTE 54
+
+/**
+ * RIL_REQUEST_QUERY_CLIP
+ *
+ * Queries the status of the CLIP supplementary service
+ *
+ * (for MMI code "*#30#")
+ *
+ * "data" is NULL
+ * "response" is an int *
+ * (int *)response)[0] is 1 for "CLIP provisioned"
+ *                           and 0 for "CLIP not provisioned"
+ *                           and 2 for "unknown, e.g. no network etc"
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  FDN_CHECK_FAILURE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_QUERY_CLIP 55
+
+/**
+ * RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE - Deprecated use the status
+ * field in RIL_Data_Call_Response_v6.
+ *
+ * Requests the failure cause code for the most recently failed PDP
+ * context or CDMA data connection active
+ * replaces RIL_REQUEST_LAST_PDP_FAIL_CAUSE
+ *
+ * "data" is NULL
+ *
+ * "response" is a "int *"
+ * ((int *)response)[0] is an integer cause code defined in TS 24.008
+ *   section 6.1.3.1.3 or close approximation
+ *
+ * If the implementation does not have access to the exact cause codes,
+ * then it should return one of the values listed in
+ * RIL_DataCallFailCause, as the UI layer needs to distinguish these
+ * cases for error notification
+ * and potential retries.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_LAST_CALL_FAIL_CAUSE
+ *
+ * Deprecated use the status field in RIL_Data_Call_Response_v6.
+ */
+
+#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
+
+/**
+ * RIL_REQUEST_DATA_CALL_LIST
+ *
+ * Returns the data call list. An entry is added when a
+ * RIL_REQUEST_SETUP_DATA_CALL is issued and removed on a
+ * RIL_REQUEST_DEACTIVATE_DATA_CALL. The list is emptied
+ * when RIL_REQUEST_RADIO_POWER off/on is issued.
+ *
+ * "data" is NULL
+ * "response" is an array of RIL_Data_Call_Response_v6
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ * See also: RIL_UNSOL_DATA_CALL_LIST_CHANGED
+ */
+
+#define RIL_REQUEST_DATA_CALL_LIST 57
+
+/**
+ * RIL_REQUEST_RESET_RADIO - DEPRECATED
+ *
+ * Request a radio reset. The RIL implementation may postpone
+ * the reset until after this request is responded to if the baseband
+ * is presently busy.
+ *
+ * The request is DEPRECATED, use RIL_REQUEST_RADIO_POWER
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_RESET_RADIO 58
+
+/**
+ * RIL_REQUEST_OEM_HOOK_RAW
+ *
+ * This request reserved for OEM-specific uses. It passes raw byte arrays
+ * back and forth.
+ *
+ * It can be invoked on the Java side from
+ * com.android.internal.telephony.Phone.invokeOemRilRequestRaw()
+ *
+ * "data" is a char * of bytes copied from the byte[] data argument in java
+ * "response" is a char * of bytes that will returned via the
+ * caller's "response" Message here:
+ * (byte[])(((AsyncResult)response.obj).result)
+ *
+ * An error response here will result in
+ * (((AsyncResult)response.obj).result) == null and
+ * (((AsyncResult)response.obj).exception) being an instance of
+ * com.android.internal.telephony.gsm.CommandException
+ *
+ * Valid errors:
+ *  All
+ */
+
+#define RIL_REQUEST_OEM_HOOK_RAW 59
+
+/**
+ * RIL_REQUEST_OEM_HOOK_STRINGS
+ *
+ * This request reserved for OEM-specific uses. It passes strings
+ * back and forth.
+ *
+ * It can be invoked on the Java side from
+ * com.android.internal.telephony.Phone.invokeOemRilRequestStrings()
+ *
+ * "data" is a const char **, representing an array of null-terminated UTF-8
+ * strings copied from the "String[] strings" argument to
+ * invokeOemRilRequestStrings()
+ *
+ * "response" is a const char **, representing an array of null-terminated UTF-8
+ * stings that will be returned via the caller's response message here:
+ *
+ * (String[])(((AsyncResult)response.obj).result)
+ *
+ * An error response here will result in
+ * (((AsyncResult)response.obj).result) == null and
+ * (((AsyncResult)response.obj).exception) being an instance of
+ * com.android.internal.telephony.gsm.CommandException
+ *
+ * Valid errors:
+ *  All
+ */
+
+#define RIL_REQUEST_OEM_HOOK_STRINGS 60
+
+/**
+ * RIL_REQUEST_SCREEN_STATE - DEPRECATED
+ *
+ * Indicates the current state of the screen.  When the screen is off, the
+ * RIL should notify the baseband to suppress certain notifications (eg,
+ * signal strength and changes in LAC/CID or BID/SID/NID/latitude/longitude)
+ * in an effort to conserve power.  These notifications should resume when the
+ * screen is on.
+ *
+ * Note this request is deprecated. Use RIL_REQUEST_SEND_DEVICE_STATE to report the device state
+ * to the modem and use RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER to turn on/off unsolicited
+ * response from the modem in different scenarios.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 1 for "Screen On"
+ * ((int *)data)[0] is == 0 for "Screen Off"
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SCREEN_STATE 61
+
+
+/**
+ * RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION
+ *
+ * Enables/disables supplementary service related notifications
+ * from the network.
+ *
+ * Notifications are reported via RIL_UNSOL_SUPP_SVC_NOTIFICATION.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 1 for notifications enabled
+ * ((int *)data)[0] is == 0 for notifications disabled
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_BUSY
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_UNSOL_SUPP_SVC_NOTIFICATION.
+ */
+#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
+
+/**
+ * RIL_REQUEST_WRITE_SMS_TO_SIM
+ *
+ * Stores a SMS message to SIM memory.
+ *
+ * "data" is RIL_SMS_WriteArgs *
+ *
+ * "response" is int *
+ * ((const int *)response)[0] is the record index where the message is stored.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  SIM_FULL
+ *  INVALID_ARGUMENTS
+ *  INVALID_SMS_FORMAT
+ *  INTERNAL_ERR
+ *  MODEM_ERR
+ *  ENCODING_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  INVALID_MODEM_STATE
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_SMSC_ADDRESS
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ */
+#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
+
+/**
+ * RIL_REQUEST_DELETE_SMS_ON_SIM
+ *
+ * Deletes a SMS message from SIM memory.
+ *
+ * "data" is int  *
+ * ((int *)data)[0] is the record index of the message to delete.
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  SIM_FULL
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NO_SUCH_ENTRY
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ */
+#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
+
+/**
+ * RIL_REQUEST_SET_BAND_MODE
+ *
+ * Assign a specified band for RF configuration.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is a RIL_RadioBandMode
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ * See also: RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE
+ */
+#define RIL_REQUEST_SET_BAND_MODE 65
+
+/**
+ * RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE
+ *
+ * Query the list of band mode supported by RF.
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * "response" points to an array of int's, the int[0] is the size of array;
+ * subsequent values are a list of RIL_RadioBandMode listing supported modes.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ * See also: RIL_REQUEST_SET_BAND_MODE
+ */
+#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
+
+/**
+ * RIL_REQUEST_STK_GET_PROFILE
+ *
+ * Requests the profile of SIM tool kit.
+ * The profile indicates the SAT/USAT features supported by ME.
+ * The SAT/USAT features refer to 3GPP TS 11.14 and 3GPP TS 31.111
+ *
+ * "data" is NULL
+ *
+ * "response" is a const char * containing SAT/USAT profile
+ * in hexadecimal format string starting with first byte of terminal profile
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_STK_GET_PROFILE 67
+
+/**
+ * RIL_REQUEST_STK_SET_PROFILE
+ *
+ * Download the STK terminal profile as part of SIM initialization
+ * procedure
+ *
+ * "data" is a const char * containing SAT/USAT profile
+ * in hexadecimal format string starting with first byte of terminal profile
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_STK_SET_PROFILE 68
+
+/**
+ * RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND
+ *
+ * Requests to send a SAT/USAT envelope command to SIM.
+ * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111
+ *
+ * "data" is a const char * containing SAT/USAT command
+ * in hexadecimal format string starting with command tag
+ *
+ * "response" is a const char * containing SAT/USAT response
+ * in hexadecimal format string starting with first byte of response
+ * (May be NULL)
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
+ *  SIM_BUSY
+ *  OPERATION_NOT_ALLOWED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
+
+/**
+ * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE
+ *
+ * Requests to send a terminal response to SIM for a received
+ * proactive command
+ *
+ * "data" is a const char * containing SAT/USAT response
+ * in hexadecimal format string starting with first byte of response data
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
+ *  RIL_E_OPERATION_NOT_ALLOWED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
+
+/**
+ * RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM
+ *
+ * When STK application gets RIL_UNSOL_STK_CALL_SETUP, the call actually has
+ * been initialized by ME already. (We could see the call has been in the 'call
+ * list') So, STK application needs to accept/reject the call according as user
+ * operations.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is > 0 for "accept" the call setup
+ * ((int *)data)[0] is == 0 for "reject" the call setup
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
+ *  RIL_E_OPERATION_NOT_ALLOWED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
+
+/**
+ * RIL_REQUEST_EXPLICIT_CALL_TRANSFER
+ *
+ * Connects the two calls and disconnects the subscriber from both calls.
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  INVALID_STATE
+ *  NO_RESOURCES
+ *  NO_MEMORY
+ *  INVALID_ARGUMENTS
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  INVALID_STATE
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
+
+/**
+ * RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
+ *
+ * Requests to set the preferred network type for searching and registering
+ * (CS/PS domain, RAT, and operation mode)
+ *
+ * "data" is int * which is RIL_PreferredNetworkType
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  OPERATION_NOT_ALLOWED
+ *  MODE_NOT_SUPPORTED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
+
+/**
+ * RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE
+ *
+ * Query the preferred network type (CS/PS domain, RAT, and operation mode)
+ * for searching and registering
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * ((int *)reponse)[0] is == RIL_PreferredNetworkType
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ * See also: RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
+ */
+#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
+
+/**
+ * RIL_REQUEST_NEIGHBORING_CELL_IDS
+ *
+ * Request neighboring cell id in GSM network
+ *
+ * "data" is NULL
+ * "response" must be a " const RIL_NeighboringCell** "
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NO_NETWORK_FOUND
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
+
+/**
+ * RIL_REQUEST_SET_LOCATION_UPDATES
+ *
+ * Enables/disables network state change notifications due to changes in
+ * LAC and/or CID (for GSM) or BID/SID/NID/latitude/longitude (for CDMA).
+ * Basically +CREG=2 vs. +CREG=1 (TS 27.007).
+ *
+ * Note:  The RIL implementation should default to "updates enabled"
+ * when the screen is on and "updates disabled" when the screen is off.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 1 for updates enabled (+CREG=2)
+ * ((int *)data)[0] is == 0 for updates disabled (+CREG=1)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ * See also: RIL_REQUEST_SCREEN_STATE, RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED
+ */
+#define RIL_REQUEST_SET_LOCATION_UPDATES 76
+
+/**
+ * RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE
+ *
+ * Request to set the location where the CDMA subscription shall
+ * be retrieved
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == RIL_CdmaSubscriptionSource
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_ABSENT
+ *  SUBSCRIPTION_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE
+ */
+#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
+
+/**
+ * RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE
+ *
+ * Request to set the roaming preferences in CDMA
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 0 for Home Networks only, as defined in PRL
+ * ((int *)data)[0] is == 1 for Roaming on Affiliated networks, as defined in PRL
+ * ((int *)data)[0] is == 2 for Roaming on Any Network, as defined in the PRL
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
+
+/**
+ * RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE
+ *
+ * Request the actual setting of the roaming preferences in CDMA in the modem
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * ((int *)response)[0] is == 0 for Home Networks only, as defined in PRL
+ * ((int *)response)[0] is == 1 for Roaming on Affiliated networks, as defined in PRL
+ * ((int *)response)[0] is == 2 for Roaming on Any Network, as defined in the PRL
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
+
+/**
+ * RIL_REQUEST_SET_TTY_MODE
+ *
+ * Request to set the TTY mode
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 0 for TTY off
+ * ((int *)data)[0] is == 1 for TTY Full
+ * ((int *)data)[0] is == 2 for TTY HCO (hearing carryover)
+ * ((int *)data)[0] is == 3 for TTY VCO (voice carryover)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SET_TTY_MODE 80
+
+/**
+ * RIL_REQUEST_QUERY_TTY_MODE
+ *
+ * Request the setting of TTY mode
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * ((int *)response)[0] is == 0 for TTY off
+ * ((int *)response)[0] is == 1 for TTY Full
+ * ((int *)response)[0] is == 2 for TTY HCO (hearing carryover)
+ * ((int *)response)[0] is == 3 for TTY VCO (voice carryover)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_QUERY_TTY_MODE 81
+
+/**
+ * RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE
+ *
+ * Request to set the preferred voice privacy mode used in voice
+ * scrambling
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 0 for Standard Privacy Mode (Public Long Code Mask)
+ * ((int *)data)[0] is == 1 for Enhanced Privacy Mode (Private Long Code Mask)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  INVALID_CALL_ID
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
+
+/**
+ * RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE
+ *
+ * Request the setting of preferred voice privacy mode
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * ((int *)response)[0] is == 0 for Standard Privacy Mode (Public Long Code Mask)
+ * ((int *)response)[0] is == 1 for Enhanced Privacy Mode (Private Long Code Mask)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
+
+/**
+ * RIL_REQUEST_CDMA_FLASH
+ *
+ * Send FLASH
+ *
+ * "data" is const char *
+ * ((const char *)data)[0] is a FLASH string
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  INVALID_STATE
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_CDMA_FLASH 84
+
+/**
+ * RIL_REQUEST_CDMA_BURST_DTMF
+ *
+ * Send DTMF string
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is a DTMF string
+ * ((const char **)data)[1] is the DTMF ON length in milliseconds, or 0 to use
+ *                          default
+ * ((const char **)data)[2] is the DTMF OFF length in milliseconds, or 0 to use
+ *                          default
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  INVALID_CALL_ID
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  OPERATION_NOT_ALLOWED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_CDMA_BURST_DTMF 85
+
+/**
+ * RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY
+ *
+ * Takes a 26 digit string (20 digit AKEY + 6 digit checksum).
+ * If the checksum is valid the 20 digit AKEY is written to NV,
+ * replacing the existing AKEY no matter what it was before.
+ *
+ * "data" is const char *
+ * ((const char *)data)[0] is a 26 digit string (ASCII digits '0'-'9')
+ *                         where the last 6 digits are a checksum of the
+ *                         first 20, as specified in TR45.AHAG
+ *                         "Common Cryptographic Algorithms, Revision D.1
+ *                         Section 2.2"
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
+
+/**
+ * RIL_REQUEST_CDMA_SEND_SMS
+ *
+ * Send a CDMA SMS message
+ *
+ * "data" is const RIL_CDMA_SMS_Message *
+ *
+ * "response" is a const RIL_SMS_Response *
+ *
+ * Based on the return error, caller decides to resend if sending sms
+ * fails. The CDMA error class is derived as follows,
+ * SUCCESS is error class 0 (no error)
+ * SMS_SEND_FAIL_RETRY is error class 2 (temporary failure)
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SMS_SEND_FAIL_RETRY
+ *  NETWORK_REJECT
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  INVALID_SMS_FORMAT
+ *  SYSTEM_ERR
+ *  FDN_CHECK_FAILURE
+ *  MODEM_ERR
+ *  NETWORK_ERR
+ *  ENCODING_ERR
+ *  INVALID_SMSC_ADDRESS
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  MODE_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ */
+#define RIL_REQUEST_CDMA_SEND_SMS 87
+
+/**
+ * RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE
+ *
+ * Acknowledge the success or failure in the receipt of SMS
+ * previously indicated via RIL_UNSOL_RESPONSE_CDMA_NEW_SMS
+ *
+ * "data" is const RIL_CDMA_SMS_Ack *
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  NO_SMS_TO_ACK
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INVALID_STATE
+ *  OPERATION_NOT_ALLOWED
+ *  NETWORK_NOT_READY
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
+
+/**
+ * RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG
+ *
+ * Request the setting of GSM/WCDMA Cell Broadcast SMS config.
+ *
+ * "data" is NULL
+ *
+ * "response" is a const RIL_GSM_BroadcastSmsConfigInfo **
+ * "responselen" is count * sizeof (RIL_GSM_BroadcastSmsConfigInfo *)
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  SYSTEM_ERR
+ *  NO_RESOURCES
+ *  MODEM_ERR
+ *  SYSTEM_ERR
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
+
+/**
+ * RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG
+ *
+ * Set GSM/WCDMA Cell Broadcast SMS config
+ *
+ * "data" is a const RIL_GSM_BroadcastSmsConfigInfo **
+ * "datalen" is count * sizeof(RIL_GSM_BroadcastSmsConfigInfo *)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+ *  MODEM_ERR
+ *  SYSTEM_ERR
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
+
+/**
+ * RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION
+ *
+* Enable or disable the reception of GSM/WCDMA Cell Broadcast SMS
+ *
+ * "data" is const int *
+ * (const int *)data[0] indicates to activate or turn off the
+ * reception of GSM/WCDMA Cell Broadcast SMS, 0-1,
+ *                       0 - Activate, 1 - Turn off
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+*   MODEM_ERR
+*   INTERNAL_ERR
+*   NO_RESOURCES
+*   CANCELLED
+*   INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
+
+/**
+ * RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG
+ *
+ * Request the setting of CDMA Broadcast SMS config
+ *
+ * "data" is NULL
+ *
+ * "response" is a const RIL_CDMA_BroadcastSmsConfigInfo **
+ * "responselen" is count * sizeof (RIL_CDMA_BroadcastSmsConfigInfo *)
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  SYSTEM_ERR
+ *  NO_RESOURCES
+ *  MODEM_ERR
+ *  SYSTEM_ERR
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
+
+/**
+ * RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG
+ *
+ * Set CDMA Broadcast SMS config
+ *
+ * "data" is a const RIL_CDMA_BroadcastSmsConfigInfo **
+ * "datalen" is count * sizeof(const RIL_CDMA_BroadcastSmsConfigInfo *)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+ *  MODEM_ERR
+ *  SYSTEM_ERR
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
+
+/**
+ * RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION
+ *
+ * Enable or disable the reception of CDMA Broadcast SMS
+ *
+ * "data" is const int *
+ * (const int *)data[0] indicates to activate or turn off the
+ * reception of CDMA Broadcast SMS, 0-1,
+ *                       0 - Activate, 1 - Turn off
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
+
+/**
+ * RIL_REQUEST_CDMA_SUBSCRIPTION
+ *
+ * Request the device MDN / H_SID / H_NID.
+ *
+ * The request is only allowed when CDMA subscription is available.  When CDMA
+ * subscription is changed, application layer should re-issue the request to
+ * update the subscription information.
+ *
+ * If a NULL value is returned for any of the device id, it means that error
+ * accessing the device.
+ *
+ * "response" is const char **
+ * ((const char **)response)[0] is MDN if CDMA subscription is available
+ * ((const char **)response)[1] is a comma separated list of H_SID (Home SID) if
+ *                              CDMA subscription is available, in decimal format
+ * ((const char **)response)[2] is a comma separated list of H_NID (Home NID) if
+ *                              CDMA subscription is available, in decimal format
+ * ((const char **)response)[3] is MIN (10 digits, MIN2+MIN1) if CDMA subscription is available
+ * ((const char **)response)[4] is PRL version if CDMA subscription is available
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RIL_E_SUBSCRIPTION_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+
+#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
+
+/**
+ * RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM
+ *
+ * Stores a CDMA SMS message to RUIM memory.
+ *
+ * "data" is RIL_CDMA_SMS_WriteArgs *
+ *
+ * "response" is int *
+ * ((const int *)response)[0] is the record index where the message is stored.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_FULL
+ *  INVALID_ARGUMENTS
+ *  INVALID_SMS_FORMAT
+ *  INTERNAL_ERR
+ *  MODEM_ERR
+ *  ENCODING_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  INVALID_MODEM_STATE
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_SMSC_ADDRESS
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ */
+#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
+
+/**
+ * RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM
+ *
+ * Deletes a CDMA SMS message from RUIM memory.
+ *
+ * "data" is int  *
+ * ((int *)data)[0] is the record index of the message to delete.
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NO_SUCH_ENTRY
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ */
+#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
+
+/**
+ * RIL_REQUEST_DEVICE_IDENTITY
+ *
+ * Request the device ESN / MEID / IMEI / IMEISV.
+ *
+ * The request is always allowed and contains GSM and CDMA device identity;
+ * it substitutes the deprecated requests RIL_REQUEST_GET_IMEI and
+ * RIL_REQUEST_GET_IMEISV.
+ *
+ * If a NULL value is returned for any of the device id, it means that error
+ * accessing the device.
+ *
+ * When CDMA subscription is changed the ESN/MEID may change.  The application
+ * layer should re-issue the request to update the device identity in this case.
+ *
+ * "response" is const char **
+ * ((const char **)response)[0] is IMEI if GSM subscription is available
+ * ((const char **)response)[1] is IMEISV if GSM subscription is available
+ * ((const char **)response)[2] is ESN if CDMA subscription is available
+ * ((const char **)response)[3] is MEID if CDMA subscription is available
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_DEVICE_IDENTITY 98
+
+/**
+ * RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE
+ *
+ * Request the radio's system selection module to exit emergency
+ * callback mode.  RIL will not respond with SUCCESS until the modem has
+ * completely exited from Emergency Callback Mode.
+ *
+ * "data" is NULL
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
+
+/**
+ * RIL_REQUEST_GET_SMSC_ADDRESS
+ *
+ * Queries the default Short Message Service Center address on the device.
+ *
+ * "data" is NULL
+ *
+ * "response" is const char * containing the SMSC address.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  SYSTEM_ERR
+ *  INTERNAL_ERR
+ *  MODEM_ERR
+ *  INVALID_ARGUMENTS
+ *  INVALID_MODEM_STATE
+ *  NOT_PROVISIONED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ *
+ */
+#define RIL_REQUEST_GET_SMSC_ADDRESS 100
+
+/**
+ * RIL_REQUEST_SET_SMSC_ADDRESS
+ *
+ * Sets the default Short Message Service Center address on the device.
+ *
+ * "data" is const char * containing the SMSC address.
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  INVALID_SMS_FORMAT
+ *  NO_MEMORY
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+ *  MODEM_ERR
+ *  NO_RESOURCES
+ *  INTERNAL_ERR
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ */
+#define RIL_REQUEST_SET_SMSC_ADDRESS 101
+
+/**
+ * RIL_REQUEST_REPORT_SMS_MEMORY_STATUS
+ *
+ * Indicates whether there is storage available for new SMS messages.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is 1 if memory is available for storing new messages
+ *                  is 0 if memory capacity is exceeded
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  INVALID_STATE
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+ *  MODEM_ERR
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
+
+/**
+ * RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING
+ *
+ * Indicates that the StkSerivce is running and is
+ * ready to receive RIL_UNSOL_STK_XXXXX commands.
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
+
+/**
+ * RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE
+ *
+ * Request to query the location where the CDMA subscription shall
+ * be retrieved
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * ((int *)data)[0] is == RIL_CdmaSubscriptionSource
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SUBSCRIPTION_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ * See also: RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE
+ */
+#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
+
+/**
+ * RIL_REQUEST_ISIM_AUTHENTICATION
+ *
+ * Request the ISIM application on the UICC to perform AKA
+ * challenge/response algorithm for IMS authentication
+ *
+ * "data" is a const char * containing the challenge string in Base64 format
+ * "response" is a const char * containing the response in Base64 format
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_ISIM_AUTHENTICATION 105
+
+/**
+ * RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU
+ *
+ * Acknowledge successful or failed receipt of SMS previously indicated
+ * via RIL_UNSOL_RESPONSE_NEW_SMS, including acknowledgement TPDU to send
+ * as the RP-User-Data element of the RP-ACK or RP-ERROR PDU.
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] is "1" on successful receipt (send RP-ACK)
+ *                          is "0" on failed receipt (send RP-ERROR)
+ * ((const char **)data)[1] is the acknowledgement TPDU in hexadecimal format
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
+
+/**
+ * RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS
+ *
+ * Requests to send a SAT/USAT envelope command to SIM.
+ * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111.
+ *
+ * This request has one difference from RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND:
+ * the SW1 and SW2 status bytes from the UICC response are returned along with
+ * the response data, using the same structure as RIL_REQUEST_SIM_IO.
+ *
+ * The RIL implementation shall perform the normal processing of a '91XX'
+ * response in SW1/SW2 to retrieve the pending proactive command and send it
+ * as an unsolicited response, as RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND does.
+ *
+ * "data" is a const char * containing the SAT/USAT command
+ * in hexadecimal format starting with command tag
+ *
+ * "response" is a const RIL_SIM_IO_Response *
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE (radio resetting)
+ *  SIM_BUSY
+ *  OPERATION_NOT_ALLOWED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ */
+#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
+
+/**
+ * RIL_REQUEST_VOICE_RADIO_TECH
+ *
+ * Query the radio technology type (3GPP/3GPP2) used for voice. Query is valid only
+ * when radio state is not RADIO_STATE_UNAVAILABLE
+ *
+ * "data" is NULL
+ * "response" is int *
+ * ((int *) response)[0] is of type const RIL_RadioTechnology
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_VOICE_RADIO_TECH 108
+
+/**
+ * RIL_REQUEST_GET_CELL_INFO_LIST
+ *
+ * Request all of the current cell information known to the radio. The radio
+ * must a list of all current cells, including the neighboring cells. If for a particular
+ * cell information isn't known then the appropriate unknown value will be returned.
+ * This does not cause or change the rate of RIL_UNSOL_CELL_INFO_LIST.
+ *
+ * "data" is NULL
+ *
+ * "response" is an array of  RIL_CellInfo_v12.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  NO_NETWORK_FOUND
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_GET_CELL_INFO_LIST 109
+
+/**
+ * RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE
+ *
+ * Sets the minimum time between when RIL_UNSOL_CELL_INFO_LIST should be invoked.
+ * A value of 0, means invoke RIL_UNSOL_CELL_INFO_LIST when any of the reported
+ * information changes. Setting the value to INT_MAX(0x7fffffff) means never issue
+ * a RIL_UNSOL_CELL_INFO_LIST.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is minimum time in milliseconds
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
+
+/**
+ * RIL_REQUEST_SET_INITIAL_ATTACH_APN
+ *
+ * Set an apn to initial attach network
+ *
+ * "data" is a const char **
+ * ((const char **)data)[0] is the APN to connect if radio technology is LTE
+ * ((const char **)data)[1] is the connection type to request must be one of the
+ *                          PDP_type values in TS 27.007 section 10.1.1.
+ *                          For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ * ((const char **)data)[2] is the PAP / CHAP auth type. Values:
+ *                          0 => PAP and CHAP is never performed.
+ *                          1 => PAP may be performed; CHAP is never performed.
+ *                          2 => CHAP may be performed; PAP is never performed.
+ *                          3 => PAP / CHAP may be performed - baseband dependent.
+ * ((const char **)data)[3] is the username for APN, or NULL
+ * ((const char **)data)[4] is the password for APN, or NULL
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  SUBSCRIPTION_NOT_AVAILABLE
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  NOT_PROVISIONED
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
+
+/**
+ * RIL_REQUEST_IMS_REGISTRATION_STATE
+ *
+ * This message is DEPRECATED and shall be removed in a future release (target: 2018);
+ * instead, provide IMS registration status via an IMS Service.
+ *
+ * Request current IMS registration state
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * ((int *)response)[0] is registration state:
+ *              0 - Not registered
+ *              1 - Registered
+ *
+ * If ((int*)response)[0] is = 1, then ((int *) response)[1]
+ * must follow with IMS SMS format:
+ *
+ * ((int *) response)[1] is of type RIL_RadioTechnologyFamily
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
+
+/**
+ * RIL_REQUEST_IMS_SEND_SMS
+ *
+ * Send a SMS message over IMS
+ *
+ * "data" is const RIL_IMS_SMS_Message *
+ *
+ * "response" is a const RIL_SMS_Response *
+ *
+ * Based on the return error, caller decides to resend if sending sms
+ * fails. SMS_SEND_FAIL_RETRY means retry, and other errors means no retry.
+ * In case of retry, data is encoded based on Voice Technology available.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SMS_SEND_FAIL_RETRY
+ *  FDN_CHECK_FAILURE
+ *  NETWORK_REJECT
+ *  INVALID_ARGUMENTS
+ *  INVALID_STATE
+ *  NO_MEMORY
+ *  INVALID_SMS_FORMAT
+ *  SYSTEM_ERR
+ *  REQUEST_RATE_LIMITED
+ *  MODEM_ERR
+ *  NETWORK_ERR
+ *  ENCODING_ERR
+ *  INVALID_SMSC_ADDRESS
+ *  OPERATION_NOT_ALLOWED
+ *  INTERNAL_ERR
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_IMS_SEND_SMS 113
+
+/**
+ * RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC
+ *
+ * Request APDU exchange on the basic channel. This command reflects TS 27.007
+ * "generic SIM access" operation (+CSIM). The modem must ensure proper function
+ * of GSM/CDMA, and filter commands appropriately. It should filter
+ * channel management and SELECT by DF name commands.
+ *
+ * "data" is a const RIL_SIM_APDU *
+ * "sessionid" field should be ignored.
+ *
+ * "response" is a const RIL_SIM_IO_Response *
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
+
+/**
+ * RIL_REQUEST_SIM_OPEN_CHANNEL
+ *
+ * Open a new logical channel and select the given application. This command
+ * reflects TS 27.007 "open logical channel" operation (+CCHO). This request
+ * also specifies the P2 parameter (described in ISO 7816-4).
+ *
+ * "data" is a const RIL_OpenChannelParam *
+ *
+ * "response" is int *
+ * ((int *)data)[0] contains the session id of the logical channel.
+ * ((int *)data)[1] onwards may optionally contain the select response for the
+ *     open channel command with one byte per integer.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  MISSING_RESOURCE
+ *  NO_SUCH_ELEMENT
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  SIM_ERR
+ *  INVALID_SIM_STATE
+ *  MISSING_RESOURCE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
+
+/**
+ * RIL_REQUEST_SIM_CLOSE_CHANNEL
+ *
+ * Close a previously opened logical channel. This command reflects TS 27.007
+ * "close logical channel" operation (+CCHC).
+ *
+ * "data" is int *
+ * ((int *)data)[0] is the session id of logical the channel to close.
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
+
+/**
+ * RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL
+ *
+ * Exchange APDUs with a UICC over a previously opened logical channel. This
+ * command reflects TS 27.007 "generic logical channel access" operation
+ * (+CGLA). The modem should filter channel management and SELECT by DF name
+ * commands.
+ *
+ * "data" is a const RIL_SIM_APDU*
+ *
+ * "response" is a const RIL_SIM_IO_Response *
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
+
+/**
+ * RIL_REQUEST_NV_READ_ITEM
+ *
+ * Read one of the radio NV items defined in RadioNVItems.java / ril_nv_items.h.
+ * This is used for device configuration by some CDMA operators.
+ *
+ * "data" is a const RIL_NV_ReadItem *
+ *
+ * "response" is const char * containing the contents of the NV item
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_NV_READ_ITEM 118
+
+/**
+ * RIL_REQUEST_NV_WRITE_ITEM
+ *
+ * Write one of the radio NV items defined in RadioNVItems.java / ril_nv_items.h.
+ * This is used for device configuration by some CDMA operators.
+ *
+ * "data" is a const RIL_NV_WriteItem *
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_NV_WRITE_ITEM 119
+
+/**
+ * RIL_REQUEST_NV_WRITE_CDMA_PRL
+ *
+ * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
+ * This is used for device configuration by some CDMA operators.
+ *
+ * "data" is a const char * containing the PRL as a byte array
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
+
+/**
+ * RIL_REQUEST_NV_RESET_CONFIG
+ *
+ * Reset the radio NV configuration to the factory state.
+ * This is used for device configuration by some CDMA operators.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is 1 to reload all NV items
+ * ((int *)data)[0] is 2 for erase NV reset (SCRTN)
+ * ((int *)data)[0] is 3 for factory reset (RTN)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_NV_RESET_CONFIG 121
+
+ /** RIL_REQUEST_SET_UICC_SUBSCRIPTION
+ * FIXME This API needs to have more documentation.
+ *
+ * Selection/de-selection of a subscription from a SIM card
+ * "data" is const  RIL_SelectUiccSub*
+
+ *
+ * "response" is NULL
+ *
+ *  Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  SUBSCRIPTION_NOT_SUPPORTED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_SET_UICC_SUBSCRIPTION  122
+
+/**
+ *  RIL_REQUEST_ALLOW_DATA
+ *
+ *  Tells the modem whether data calls are allowed or not
+ *
+ * "data" is int *
+ * FIXME slotId and aid will be added.
+ * ((int *)data)[0] is == 0 to allow data calls
+ * ((int *)data)[0] is == 1 to disallow data calls
+ *
+ * "response" is NULL
+ *
+ *  Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  MODEM_ERR
+ *  INVALID_ARGUMENTS
+ *  DEVICE_IN_USE
+ *  INVALID_MODEM_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_ALLOW_DATA  123
+
+/**
+ * RIL_REQUEST_GET_HARDWARE_CONFIG
+ *
+ * Request all of the current hardware (modem and sim) associated
+ * with the RIL.
+ *
+ * "data" is NULL
+ *
+ * "response" is an array of  RIL_HardwareConfig.
+ *
+ * Valid errors:
+ * RADIO_NOT_AVAILABLE
+ * REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
+
+/**
+ * RIL_REQUEST_SIM_AUTHENTICATION
+ *
+ * Returns the response of SIM Authentication through RIL to a
+ * challenge request.
+ *
+ * "data" Base64 encoded string containing challenge:
+ *      int   authContext;          P2 value of authentication command, see P2 parameter in
+ *                                  3GPP TS 31.102 7.1.2
+ *      char *authData;             the challenge string in Base64 format, see 3GPP
+ *                                  TS 31.102 7.1.2
+ *      char *aid;                  AID value, See ETSI 102.221 8.1 and 101.220 4,
+ *                                  NULL if no value
+ *
+ * "response" Base64 encoded strings containing response:
+ *      int   sw1;                  Status bytes per 3GPP TS 31.102 section 7.3
+ *      int   sw2;
+ *      char *simResponse;          Response in Base64 format, see 3GPP TS 31.102 7.1.2
+ *
+ *  Valid errors:
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  INVALID_MODEM_STATE
+ *  INVALID_ARGUMENTS
+ *  SIM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_SIM_AUTHENTICATION 125
+
+/**
+ * RIL_REQUEST_GET_DC_RT_INFO
+ *
+ * The request is DEPRECATED, use RIL_REQUEST_GET_ACTIVITY_INFO
+ * Requests the Data Connection Real Time Info
+ *
+ * "data" is NULL
+ *
+ * "response" is the most recent RIL_DcRtInfo
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  REQUEST_NOT_SUPPORTED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ * See also: RIL_UNSOL_DC_RT_INFO_CHANGED
+ */
+#define RIL_REQUEST_GET_DC_RT_INFO 126
+
+/**
+ * RIL_REQUEST_SET_DC_RT_INFO_RATE
+ *
+ * The request is DEPRECATED
+ * This is the minimum number of milliseconds between successive
+ * RIL_UNSOL_DC_RT_INFO_CHANGED messages and defines the highest rate
+ * at which RIL_UNSOL_DC_RT_INFO_CHANGED's will be sent. A value of
+ * 0 means send as fast as possible.
+ *
+ * "data" The number of milliseconds as an int
+ *
+ * "response" is null
+ *
+ * Valid errors:
+ *  SUCCESS must not fail
+ */
+#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
+
+/**
+ * RIL_REQUEST_SET_DATA_PROFILE
+ *
+ * Set data profile in modem
+ * Modem should erase existed profiles from framework, and apply new profiles
+ * "data" is a const RIL_DataProfileInfo **
+ * "datalen" is count * sizeof(const RIL_DataProfileInfo *)
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  SUBSCRIPTION_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ */
+#define RIL_REQUEST_SET_DATA_PROFILE 128
+
+/**
+ * RIL_REQUEST_SHUTDOWN
+ *
+ * Device is shutting down. All further commands are ignored
+ * and RADIO_NOT_AVAILABLE must be returned.
+ *
+ * "data" is null
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SHUTDOWN 129
+
+/**
+ * RIL_REQUEST_GET_RADIO_CAPABILITY
+ *
+ * Used to get phone radio capablility.
+ *
+ * "data" is the RIL_RadioCapability structure
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  INVALID_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
+
+/**
+ * RIL_REQUEST_SET_RADIO_CAPABILITY
+ *
+ * Used to set the phones radio capability. Be VERY careful
+ * using this request as it may cause some vendor modems to reset. Because
+ * of the possible modem reset any RIL commands after this one may not be
+ * processed.
+ *
+ * "data" is the RIL_RadioCapability structure
+ *
+ * "response" is the RIL_RadioCapability structure, used to feedback return status
+ *
+ * Valid errors:
+ *  SUCCESS means a RIL_UNSOL_RADIO_CAPABILITY will be sent within 30 seconds.
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  INVALID_STATE
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
+
+/**
+ * RIL_REQUEST_START_LCE
+ *
+ * Start Link Capacity Estimate (LCE) service if supported by the radio.
+ *
+ * "data" is const int *
+ * ((const int*)data)[0] specifies the desired reporting interval (ms).
+ * ((const int*)data)[1] specifies the LCE service mode. 1: PULL; 0: PUSH.
+ *
+ * "response" is the RIL_LceStatusInfo.
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * LCE_NOT_SUPPORTED
+ * INTERNAL_ERR
+ * REQUEST_NOT_SUPPORTED
+ * NO_MEMORY
+ * NO_RESOURCES
+ * CANCELLED
+ * SIM_ABSENT
+ */
+#define RIL_REQUEST_START_LCE 132
+
+/**
+ * RIL_REQUEST_STOP_LCE
+ *
+ * Stop Link Capacity Estimate (LCE) service, the STOP operation should be
+ * idempotent for the radio modem.
+ *
+ * "response" is the RIL_LceStatusInfo.
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * LCE_NOT_SUPPORTED
+ * INTERNAL_ERR
+ * NO_MEMORY
+ * NO_RESOURCES
+ * CANCELLED
+ * REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ */
+#define RIL_REQUEST_STOP_LCE 133
+
+/**
+ * RIL_REQUEST_PULL_LCEDATA
+ *
+ * Pull LCE service for capacity information.
+ *
+ * "response" is the RIL_LceDataInfo.
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * LCE_NOT_SUPPORTED
+ * INTERNAL_ERR
+ * NO_MEMORY
+ * NO_RESOURCES
+ * CANCELLED
+ * REQUEST_NOT_SUPPORTED
+ *  SIM_ABSENT
+ */
+#define RIL_REQUEST_PULL_LCEDATA 134
+
+/**
+ * RIL_REQUEST_GET_ACTIVITY_INFO
+ *
+ * Get modem activity information for power consumption estimation.
+ *
+ * Request clear-on-read statistics information that is used for
+ * estimating the per-millisecond power consumption of the cellular
+ * modem.
+ *
+ * "data" is null
+ * "response" is const RIL_ActivityStatsInfo *
+ *
+ * Valid errors:
+ *
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE (radio resetting)
+ * NO_MEMORY
+ * INTERNAL_ERR
+ * SYSTEM_ERR
+ * MODEM_ERR
+ * NOT_PROVISIONED
+ * REQUEST_NOT_SUPPORTED
+ * NO_RESOURCES CANCELLED
+ */
+#define RIL_REQUEST_GET_ACTIVITY_INFO 135
+
+/**
+ * RIL_REQUEST_SET_CARRIER_RESTRICTIONS
+ *
+ * Set carrier restrictions for this sim slot. Expected modem behavior:
+ *  If never receives this command
+ *  - Must allow all carriers
+ *  Receives this command with data being NULL
+ *  - Must allow all carriers. If a previously allowed SIM is present, modem must not reload
+ *    the SIM. If a previously disallowed SIM is present, reload the SIM and notify Android.
+ *  Receives this command with a list of carriers
+ *  - Only allow specified carriers, persist across power cycles and FDR. If a present SIM
+ *    is in the allowed list, modem must not reload the SIM. If a present SIM is *not* in
+ *    the allowed list, modem must detach from the registered network and only keep emergency
+ *    service, and notify Android SIM refresh reset with new SIM state being
+ *    RIL_CARDSTATE_RESTRICTED. Emergency service must be enabled.
+ *
+ * "data" is const RIL_CarrierRestrictions *
+ * A list of allowed carriers and possibly a list of excluded carriers.
+ * If data is NULL, means to clear previous carrier restrictions and allow all carriers
+ *
+ * "response" is int *
+ * ((int *)data)[0] contains the number of allowed carriers which have been set correctly.
+ * On success, it should match the length of list data->allowed_carriers.
+ * If data is NULL, the value must be 0.
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_INVALID_ARGUMENTS
+ *  RIL_E_RADIO_NOT_AVAILABLE
+ *  RIL_E_REQUEST_NOT_SUPPORTED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SET_CARRIER_RESTRICTIONS 136
+
+/**
+ * RIL_REQUEST_GET_CARRIER_RESTRICTIONS
+ *
+ * Get carrier restrictions for this sim slot. Expected modem behavior:
+ *  Return list of allowed carriers, or null if all carriers are allowed.
+ *
+ * "data" is NULL
+ *
+ * "response" is const RIL_CarrierRestrictions *.
+ * If response is NULL, it means all carriers are allowed.
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE
+ *  RIL_E_REQUEST_NOT_SUPPORTED
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_GET_CARRIER_RESTRICTIONS 137
+
+/**
+ * RIL_REQUEST_SEND_DEVICE_STATE
+ *
+ * Send the updated device state.
+ * Modem can perform power saving based on the provided device state.
+ * "data" is const int *
+ * ((const int*)data)[0] A RIL_DeviceStateType that specifies the device state type.
+ * ((const int*)data)[1] Specifies the state. See RIL_DeviceStateType for the definition of each
+ *                       type.
+ *
+ * "datalen" is count * sizeof(const RIL_DeviceState *)
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SEND_DEVICE_STATE 138
+
+/**
+ * RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER
+ *
+ * Set the unsolicited response filter
+ * This is used to prevent unnecessary application processor
+ * wake up for power saving purposes by suppressing the
+ * unsolicited responses in certain scenarios.
+ *
+ * "data" is an int *
+ *
+ * ((int *)data)[0] is a 32-bit bitmask of RIL_UnsolicitedResponseFilter
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  INVALID_ARGUMENTS (e.g. the requested filter doesn't exist)
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER 139
+
+ /**
+  * RIL_REQUEST_SET_SIM_CARD_POWER
+  *
+  * Set SIM card power up or down
+  *
+  * Request is equivalent to inserting and removing the card, with
+  * an additional effect where the ability to detect card removal/insertion
+  * is disabled when the SIM card is powered down.
+  *
+  * This will generate RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
+  * as if the SIM had been inserted or removed.
+  *
+  * "data" is int *
+  * ((int *)data)[0] is 1 for "SIM POWER UP"
+  * ((int *)data)[0] is 0 for "SIM POWER DOWN"
+  *
+  * "response" is NULL
+  *
+  * Valid errors:
+  *  SUCCESS
+  *  RADIO_NOT_AVAILABLE
+  *  REQUEST_NOT_SUPPORTED
+  *  SIM_ABSENT
+  *  INVALID_ARGUMENTS
+  *  INTERNAL_ERR
+  *  NO_MEMORY
+  *  NO_RESOURCES
+  *  CANCELLED
+  */
+#define RIL_REQUEST_SET_SIM_CARD_POWER 140
+
+/**
+ * RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION
+ *
+ * Provide Carrier specific information to the modem that will be used to
+ * encrypt the IMSI and IMPI. Sent by the framework during boot, carrier
+ * switch and everytime we receive a new certificate.
+ *
+ * "data" is the RIL_CarrierInfoForImsiEncryption * structure.
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  RIL_E_SUCCESS
+ *  RIL_E_RADIO_NOT_AVAILABLE
+ *  SIM_ABSENT
+ *  RIL_E_REQUEST_NOT_SUPPORTED
+ *  INVALID_ARGUMENTS
+ *  MODEM_INTERNAL_FAILURE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION 141
+
+/**
+ * RIL_REQUEST_START_NETWORK_SCAN
+ *
+ * Starts a new network scan
+ *
+ * Request to start a network scan with specified radio access networks with frequency bands and/or
+ * channels.
+ *
+ * "data" is a const RIL_NetworkScanRequest *.
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  OPERATION_NOT_ALLOWED
+ *  DEVICE_IN_USE
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  MODEM_ERR
+ *  INVALID_ARGUMENTS
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *
+ */
+#define RIL_REQUEST_START_NETWORK_SCAN 142
+
+/**
+ * RIL_REQUEST_STOP_NETWORK_SCAN
+ *
+ * Stops an ongoing network scan
+ *
+ * Request to stop the ongoing network scan. Since the modem can only perform one scan at a time,
+ * there is no parameter for this request.
+ *
+ * "data" is NULL
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  INTERNAL_ERR
+ *  MODEM_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *
+ */
+#define RIL_REQUEST_STOP_NETWORK_SCAN 143
+
+/**
+ * RIL_REQUEST_START_KEEPALIVE
+ *
+ * Start a keepalive session
+ *
+ * Request that the modem begin sending keepalive packets on a particular
+ * data call, with a specified source, destination, and format.
+ *
+ * "data" is a const RIL_RequestKeepalive
+ * "response" is RIL_KeepaliveStatus with a valid "handle"
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  NO_RESOURCES
+ *  INVALID_ARGUMENTS
+ *
+ */
+#define RIL_REQUEST_START_KEEPALIVE 144
+
+/**
+ * RIL_REQUEST_STOP_KEEPALIVE
+ *
+ * Stops an ongoing keepalive session
+ *
+ * Requests that a keepalive session with the given handle be stopped.
+ * there is no parameter for this request.
+ *
+ * "data" is an integer handle
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  INVALID_ARGUMENTS
+ *
+ */
+#define RIL_REQUEST_STOP_KEEPALIVE 145
+
+/**
+ * RIL_REQUEST_GET_MODEM_STACK_STATUS
+ *
+ * Request status of a logical modem
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  MODEM_ERR
+ *
+ */
+#define RIL_REQUEST_GET_MODEM_STACK_STATUS 146
+
+/**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param networkTypeBitmap a 32-bit bitmap of RadioAccessFamily.
+ *
+ * Valid errors returned:
+ *   RadioError:NONE
+ *   RadioError:RADIO_NOT_AVAILABLE
+ *   RadioError:INTERNAL_ERR
+ *   RadioError:INVALID_ARGUMENTS
+ *   RadioError:MODEM_ERR
+ *   RadioError:REQUEST_NOT_SUPPORTED
+ *   RadioError:NO_RESOURCES
+ */
+#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP 147
+
+/**
+ * Callback of IRadio.setPreferredNetworkTypeBitmap(int, bitfield<RadioAccessFamily>)
+ *
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ *   RadioError:NONE
+ *   RadioError:RADIO_NOT_AVAILABLE
+ *   RadioError:OPERATION_NOT_ALLOWED
+ *   RadioError:MODE_NOT_SUPPORTED
+ *   RadioError:INTERNAL_ERR
+ *   RadioError:INVALID_ARGUMENTS
+ *   RadioError:MODEM_ERR
+ *   RadioError:REQUEST_NOT_SUPPORTED
+ *   RadioError:NO_RESOURCES
+ */
+#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP 148
+
+/**
+ * RIL_REQUEST_EMERGENCY_DIAL
+ *
+ * Initiate emergency voice call, with zero or more emergency service category(s), zero or
+ * more emergency Uniform Resource Names (URN), and routing information for handling the call.
+ * Android uses this request to make its emergency call instead of using @1.0::IRadio.dial
+ * if the 'address' in the 'dialInfo' field is identified as an emergency number by Android.
+ *
+ * In multi-sim scenario, if the emergency number is from a specific subscription, this radio
+ * request is sent through the IRadio service that serves the subscription, no matter of the
+ * PUK/PIN state of the subscription and the service state of the radio.
+ *
+ * Some countries or carriers require some emergency numbers that must be handled with normal
+ * call routing or emergency routing. If the 'routing' field is specified as
+ * @1.4::EmergencyNumberRouting#NORMAL, the implementation must use normal call routing to
+ * handle the call; if it is specified as @1.4::EmergencyNumberRouting#EMERGENCY, the
+ * implementation must use emergency routing to handle the call; if it is
+ * @1.4::EmergencyNumberRouting#UNKNOWN, Android does not know how to handle the call.
+ *
+ * If the dialed emergency number does not have a specified emergency service category, the
+ * 'categories' field is set to @1.4::EmergencyServiceCategory#UNSPECIFIED; if the dialed
+ * emergency number does not have specified emergency Uniform Resource Names, the 'urns' field
+ * is set to an empty list. If the underlying technology used to request emergency services
+ * does not support the emergency service category or emergency uniform resource names, the
+ * field 'categories' or 'urns' may be ignored.
+ *
+ * 'fromEmergencyDialer' indicates if this request originated from emergency dialer/shortcut,
+ * which means an explicit intent from the user to dial an emergency number. The modem must
+ * treat this as an actual emergency dial and not try to disambiguate.
+ *
+ * If 'isTesting' is true, this request is for testing purpose, and must not be sent to a real
+ * emergency service; otherwise it's for a real emergency call request.
+ * Valid errors:
+ *  NONE
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  DIAL_MODIFIED_TO_USSD
+ *  DIAL_MODIFIED_TO_SS
+ *  DIAL_MODIFIED_TO_DIAL
+ *  INVALID_ARGUMENTS
+ *  NO_RESOURCES
+ *  INTERNAL_ERR
+ *  FDN_CHECK_FAILURE
+ *  MODEM_ERR
+ *  NO_SUBSCRIPTION
+ *  NO_NETWORK_FOUND
+ *  INVALID_CALL_ID
+ *  DEVICE_IN_USE
+ *  ABORTED
+ *  INVALID_MODEM_STATE
+ */
+#define RIL_REQUEST_EMERGENCY_DIAL 149
+
+/**
+ * Specify which bands modem's background scan must act on.
+ * If specifyChannels is true, it only scans bands specified in specifiers.
+ * If specifyChannels is false, it scans all bands.
+ *
+ * For example, CBRS is only on LTE band 48. By specifying this band,
+ * modem saves more power.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *
+ */
+#define RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS 150
+
+/**
+ * RIL_REQUEST_ENABLE_MODEM
+ *
+ * Enable a logical modem
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  MODEM_ERR
+ *
+ */
+#define RIL_REQUEST_ENABLE_MODEM 151
+
+/**
+ * RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA
+ *
+ * Sets the signal strength reporting criteria.
+ *
+ * The resulting reporting rules are the AND of all the supplied criteria. For each RAN
+ * The hysteresisDb apply to only the following measured quantities:
+ * -GERAN    - RSSI
+ * -CDMA2000 - RSSI
+ * -UTRAN    - RSCP
+ * -EUTRAN   - RSRP/RSRQ/RSSNR
+ *
+ * The thresholds apply to only the following measured quantities:
+ * -GERAN    - RSSI
+ * -CDMA2000 - RSSI
+ * -UTRAN    - RSCP
+ * -EUTRAN   - RSRP/RSRQ/RSSNR
+ * -NGRAN    - SSRSRP/SSRSRQ/SSSINR
+ *
+ * Note: Reporting criteria must be individually set for each RAN. For any unset reporting
+ * criteria, the value is implementation-defined.
+ *
+ * Note: @1.5::SignalThresholdInfo includes fields 'hysteresisDb', 'hysteresisMs',
+ * and 'thresholds'. As this mechanism generally only constrains reports based on one
+ * measured quantity per RAN, if multiple measured quantities must be used to trigger a report
+ * for a given RAN, the only valid field may be hysteresisMs: hysteresisDb and thresholds must
+ * be set to zero and length zero respectively. If either hysteresisDb or thresholds is set,
+ * then reports shall only be triggered by the respective measured quantity, subject to the
+ * applied constraints.
+ *
+ * Valid errors returned:
+ *   RadioError:NONE
+ *   RadioError:INVALID_ARGUMENTS
+ *   RadioError:RADIO_NOT_AVAILABLE
+ */
+#define RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA 152
+
+/**
+ * RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA
+ *
+ * Sets the link capacity reporting criteria. The resulting reporting criteria are the AND of
+ * all the supplied criteria.
+ *
+ * Note: Reporting criteria ust be individually set for each RAN. If unset, reporting criteria
+ * for that RAN are implementation-defined.
+ *
+ * Valid errors returned:
+ *   RadioError:NONE
+ *   RadioError:INVALID_ARGUMENTS
+ *   RadioError:RADIO_NOT_AVAILABLE
+ *   RadioError:INTERNAL_ERR
+ */
+#define RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA 153
+
+/**
+ * RIL_REQUEST_ENABLE_UICC_APPLICATIONS
+ *
+ * Enable or disable uicc applications.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_ABSENT
+ *  INTERNAL_ERR
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_ENABLE_UICC_APPLICATIONS 154
+
+/**
+ * RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED
+ *
+ * Whether uicc applications are enabled.
+ *
+ * Response: a boolean of enable or not.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_ABSENT
+ *  INTERNAL_ERR
+ *  REQUEST_NOT_SUPPORTED
+ */
+#define RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED 155
+
+/**
+ * RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION
+ *
+ * Requests that sim personlization be deactivated
+ *
+ * "data" is const char **
+ * ((const char **)(data))[0]] is  sim depersonlization code
+ *
+ * "response" is int *
+ * ((int *)response)[0] is the number of retries remaining,
+ * or -1 if number of retries are infinite.
+ *
+ * Valid errors:
+ *
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  PASSWORD_INCORRECT
+ *  SIM_ABSENT (code is invalid)
+ *  INTERNAL_ERR
+ *  NO_MEMORY
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ */
+
+#define RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION 156
+
+/**
+ * RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE
+ *
+ * Send a CDMA SMS message
+ *
+ * "data" is const RIL_CDMA_SMS_Message *
+ *
+ * "response" is a const RIL_SMS_Response *
+ *
+ * Based on the return error, caller decides to resend if sending sms
+ * fails. The CDMA error class is derived as follows,
+ * SUCCESS is error class 0 (no error)
+ * SMS_SEND_FAIL_RETRY is error class 2 (temporary failure)
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SMS_SEND_FAIL_RETRY
+ *  NETWORK_REJECT
+ *  INVALID_STATE
+ *  INVALID_ARGUMENTS
+ *  NO_MEMORY
+ *  REQUEST_RATE_LIMITED
+ *  INVALID_SMS_FORMAT
+ *  SYSTEM_ERR
+ *  FDN_CHECK_FAILURE
+ *  MODEM_ERR
+ *  NETWORK_ERR
+ *  ENCODING_ERR
+ *  INVALID_SMSC_ADDRESS
+ *  OPERATION_NOT_ALLOWED
+ *  NO_RESOURCES
+ *  CANCELLED
+ *  REQUEST_NOT_SUPPORTED
+ *  MODE_NOT_SUPPORTED
+ *  SIM_ABSENT
+ */
+#define RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE 157
+
+/**
+ * Get all the barring info for the current camped cell applicable to the current user.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getBarringInfoResponse()
+ */
+#define RIL_REQUEST_GET_BARRING_INFO 158
+
+/**
+ * RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY
+ *
+ * Enable or disable E-UTRA-NR dual connectivity.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_ABSENT
+ *  INTERNAL_ERR
+ */
+#define RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY 159
+
+/**
+ * RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED
+ *
+ * Whether E-UTRA-NR dual connectivity is enabled.
+ *
+ * Response: a boolean of enable or not.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  SIM_ABSENT
+ *  INTERNAL_ERR
+ */
+#define RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED 160
+
+/**
+ * Allocates a pdu session id
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.allocatePduSessionIdResponse()
+ */
+#define RIL_REQUEST_ALLOCATE_PDU_SESSION_ID 161
+
+/**
+ * Releases a pdu session id
+ *
+ * @param serial Serial number of request.
+ * @param id Pdu session id to release
+ *
+ * Response callback is IRadioResponse.releasePduSessionIdResponse()
+ */
+#define RIL_REQUEST_RELEASE_PDU_SESSION_ID 162
+
+/**
+ * Indicates that handover has begun
+ *
+ * @param serial Serial number of request.
+ * @param callId The unique identifier of the corresponding data call
+ *
+ * Response callback is IRadioResponse.startHandoverResponse()
+ */
+#define RIL_REQUEST_START_HANDOVER 163
+
+/**
+ * Indicates that a handover has been cancelled
+ *
+ * @param serial Serial number of request.
+ * @param callId The unique identifier of the corresponding data call
+ *
+ * Response callback is IRadioResponse.cancelHandoverResponse()
+ */
+#define RIL_REQUEST_CANCEL_HANDOVER 164
+
+/**
+ * RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP
+ *
+ * Instruct the radio to *only* accept the types of network provided. This
+ * is stronger than setPreferredNetworkType which is a suggestion.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  OPERATION_NOT_ALLOWED
+ *  MODE_NOT_SUPPORTED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP 165
+
+/**
+* RIL_REQUEST_SET_DATA_THROTTLING
+*
+* Set the data throttling on device.
+*
+* Response: an int enum of type ThermalMitigationResult as defined in
+* android.telephony.Annotation.
+*
+* Valid errors:
+*  SUCCESS
+*  RADIO_NOT_AVAILABLE
+*  MODEM_ERR
+*  INVALID_ARGUMENTS
+*/
+#define RIL_REQUEST_SET_DATA_THROTTLING 166
+
+/**
+ * Get which bands the modem's background scan is acting on.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  INTERNAL_ERR
+ *
+ */
+#define RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS 167
+
+/**
+ * RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP
+ *
+ * Request previously set allowed network types from the radio.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE (radio resetting)
+ *  OPERATION_NOT_ALLOWED
+ *  MODE_NOT_SUPPORTED
+ *  NO_MEMORY
+ *  INTERNAL_ERR
+ *  SYSTEM_ERR
+ *  INVALID_ARGUMENTS
+ *  MODEM_ERR
+ *  REQUEST_NOT_SUPPORTED
+ *  NO_RESOURCES
+ *  CANCELLED
+ */
+#define RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP 168
+
+/**
+ * RIL_REQUEST_GET_SLICING_CONFIG
+ *
+ * Request to get the current slicing configuration including URSP rules and
+ * NSSAIs (configured, allowed and rejected).
+ *
+ * Response callback is IRadioResponse.getSlicingConfigResponse()
+ */
+#define RIL_REQUEST_GET_SLICING_CONFIG 169
+
+#define RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS 170
+
+#define RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY 171
+
+#define RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORDS 172
+
+
+#define RIL_REQUEST_LAST RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORDS
+
+/***********************************************************************/
+
+/* Radio Config @{ */
+#define RIL_REQUEST_RADIO_CONFIG_BASE 600
+
+/**
+ * Get SIM Slot status.
+ *
+ * Request provides the slot status of all active and inactive SIM slots and whether card is
+ * present in the slots or not.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioConfigResponse.getSimSlotsStatusResponse()
+ */
+#define RIL_REQUEST_CONFIG_GET_SLOT_STATUS 601
+
+/**
+ * Set SIM Slot mapping.
+
+ * Maps the logical slots to the physical slots. Logical slot is the slot that is seen by modem.
+ * Physical slot is the actual physical slot. Request maps the physical slot to logical slot.
+ * Logical slots that are already mapped to the requested physical slot are not impacted.
+ *
+ * Example no. of logical slots 1 and physical slots 2:
+ * The only logical slot (index 0) can be mapped to first physical slot (value 0) or second
+ * physical slot(value 1), while the other physical slot remains unmapped and inactive.
+ * slotMap[0] = 1 or slotMap[0] = 0
+ *
+ * Example no. of logical slots 2 and physical slots 2:
+ * First logical slot (index 0) can be mapped to physical slot 1 or 2 and other logical slot
+ * can be mapped to other physical slot. Each logical slot must be mapped to a physical slot.
+ * slotMap[0] = 0 and slotMap[1] = 1 or slotMap[0] = 1 and slotMap[1] = 0
+ *
+ * @param serial Serial number of request
+ * @param slotMap Logical to physical slot mapping, size == no. of radio instances. Index is
+ *        mapping to logical slot and value to physical slot, need to provide all the slots
+ *        mapping when sending request in case of multi slot device.
+ *        EX: uint32_t slotMap[logical slot] = physical slot
+ *        index 0 is the first logical_slot number of logical slots is equal to number of Radio
+ *        instances and number of physical slots is equal to size of slotStatus in
+ *        getSimSlotsStatusResponse
+ *
+ * Response callback is IRadioConfigResponse.setSimSlotsMappingResponse()
+ */
+#define RIL_REQUEST_CONFIG_SET_SLOT_MAPPING 602
+
+/**
+ * Request current phone capability.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getPhoneCapabilityResponse() which
+ * will return <@1.1::PhoneCapability>.
+ */
+#define RIL_REQUEST_CONFIG_GET_PHONE_CAPABILITY 603
+
+/**
+ * Set preferred data modem Id.
+ * In a multi-SIM device, notify modem layer which logical modem will be used primarily
+ * for data. It helps modem with resource optimization and decisions of what data connections
+ * should be satisfied.
+ *
+ * @param serial Serial number of request.
+ * @param modem Id the logical modem ID, which should match one of modem IDs returned
+ * from getPhoneCapability().
+ *
+ * Response callback is IRadioConfigResponse.setPreferredDataModemResponse()
+ */
+#define RIL_REQUEST_CONFIG_SET_PREFER_DATA_MODEM 604
+
+/**
+ * Set modems configurations by specifying the number of live modems (i.e modems that are
+ * enabled and actively working as part of a working telephony stack).
+ *
+ * Example: this interface can be used to switch to single/multi sim mode by specifying
+ * the number of live modems as 1, 2, etc
+ *
+ * Note: by setting the number of live modems in this API, that number of modems will
+ * subsequently get enabled/disabled
+ *
+ * @param serial serial number of request.
+ * @param modemsConfig ModemsConfig object including the number of live modems
+ *
+ * Response callback is IRadioResponse.setModemsConfigResponse()
+ */
+#define RIL_REQUEST_CONFIG_SET_MODEM_CONFIG 605
+
+/**
+ * Get modems configurations. This interface is used to get modem configurations
+ * which includes the number of live modems (i.e modems that are
+ * enabled and actively working as part of a working telephony stack)
+ *
+ * Note: in order to get the overall number of modems available on the phone,
+ * refer to getPhoneCapability API
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getModemsConfigResponse() which
+ * will return <@1.1::ModemsConfig>.
+ */
+#define RIL_REQUEST_CONFIG_GET_MODEM_CONFIG 606
+
+#define RIL_REQUEST_CONFIG_GET_HAL_DEVICE_CAPABILITIES 607
+
+/* Make sure to update ril_config_commands.h when changing this constant. */
+#define RIL_REQUEST_RADIO_CONFIG_LAST    RIL_REQUEST_CONFIG_GET_HAL_DEVICE_CAPABILITIES
+/* }@ */
+
+/***********************************************************************/
+
+/**
+ * RIL_RESPONSE_ACKNOWLEDGEMENT
+ *
+ * This is used by Asynchronous solicited messages and Unsolicited messages
+ * to acknowledge the receipt of those messages in RIL.java so that the ack
+ * can be used to let ril.cpp to release wakelock.
+ *
+ * Valid errors
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ */
+
+#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
+
+/***********************************************************************/
+
+
+#define RIL_UNSOL_RESPONSE_BASE 1000
+
+/**
+ * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
+ *
+ * Indicate when value of RIL_RadioState has changed.
+ *
+ * Callee will invoke RIL_RadioStateRequest method on main thread
+ *
+ * "data" is NULL
+ */
+
+#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
+
+
+/**
+ * RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED
+ *
+ * Indicate when call state has changed
+ *
+ * Callee will invoke RIL_REQUEST_GET_CURRENT_CALLS on main thread
+ *
+ * "data" is NULL
+ *
+ * Response should be invoked on, for example,
+ * "RING", "BUSY", "NO CARRIER", and also call state
+ * transitions (DIALING->ALERTING ALERTING->ACTIVE)
+ *
+ * Redundent or extraneous invocations are tolerated
+ */
+#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
+
+
+/**
+ * RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
+ *
+ * Called when the voice network state changed
+ *
+ * Callee will invoke the following requests on main thread:
+ *
+ * RIL_REQUEST_VOICE_REGISTRATION_STATE
+ * RIL_REQUEST_OPERATOR
+ *
+ * "data" is NULL
+ *
+ * FIXME should this happen when SIM records are loaded? (eg, for
+ * EONS)
+ */
+#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
+
+/**
+ * RIL_UNSOL_RESPONSE_NEW_SMS
+ *
+ * Called when new SMS is received.
+ *
+ * "data" is const char *
+ * This is a pointer to a string containing the PDU of an SMS-DELIVER
+ * as an ascii string of hex digits. The PDU starts with the SMSC address
+ * per TS 27.005 (+CMT:)
+ *
+ * Callee will subsequently confirm the receipt of thei SMS with a
+ * RIL_REQUEST_SMS_ACKNOWLEDGE
+ *
+ * No new RIL_UNSOL_RESPONSE_NEW_SMS
+ * or RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT messages should be sent until a
+ * RIL_REQUEST_SMS_ACKNOWLEDGE has been received
+ */
+
+#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
+
+/**
+ * RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT
+ *
+ * Called when new SMS Status Report is received.
+ *
+ * "data" is const char *
+ * This is a pointer to a string containing the PDU of an SMS-STATUS-REPORT
+ * as an ascii string of hex digits. The PDU starts with the SMSC address
+ * per TS 27.005 (+CDS:).
+ *
+ * Callee will subsequently confirm the receipt of the SMS with a
+ * RIL_REQUEST_SMS_ACKNOWLEDGE
+ *
+ * No new RIL_UNSOL_RESPONSE_NEW_SMS
+ * or RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT messages should be sent until a
+ * RIL_REQUEST_SMS_ACKNOWLEDGE has been received
+ */
+
+#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
+
+/**
+ * RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM
+ *
+ * Called when new SMS has been stored on SIM card
+ *
+ * "data" is const int *
+ * ((const int *)data)[0] contains the slot index on the SIM that contains
+ * the new message
+ */
+
+#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
+
+/**
+ * RIL_UNSOL_ON_USSD
+ *
+ * Called when a new USSD message is received.
+ *
+ * "data" is const char **
+ * ((const char **)data)[0] points to a type code, which is
+ *  one of these string values:
+ *      "0"   USSD-Notify -- text in ((const char **)data)[1]
+ *      "1"   USSD-Request -- text in ((const char **)data)[1]
+ *      "2"   Session terminated by network
+ *      "3"   other local client (eg, SIM Toolkit) has responded
+ *      "4"   Operation not supported
+ *      "5"   Network timeout
+ *
+ * The USSD session is assumed to persist if the type code is "1", otherwise
+ * the current session (if any) is assumed to have terminated.
+ *
+ * ((const char **)data)[1] points to a message string if applicable, which
+ * should always be in UTF-8.
+ */
+#define RIL_UNSOL_ON_USSD 1006
+/* Previously #define RIL_UNSOL_ON_USSD_NOTIFY 1006   */
+
+/**
+ * RIL_UNSOL_ON_USSD_REQUEST
+ *
+ * Obsolete. Send via RIL_UNSOL_ON_USSD
+ */
+#define RIL_UNSOL_ON_USSD_REQUEST 1007
+
+/**
+ * RIL_UNSOL_NITZ_TIME_RECEIVED
+ *
+ * Called when radio has received a NITZ time message
+ *
+ * "data" is const char * pointing to NITZ time string
+ * in the form "yy/mm/dd,hh:mm:ss(+/-)tz,dt"
+ */
+#define RIL_UNSOL_NITZ_TIME_RECEIVED  1008
+
+/**
+ * RIL_UNSOL_SIGNAL_STRENGTH
+ *
+ * Radio may report signal strength rather han have it polled.
+ *
+ * "data" is a const RIL_SignalStrength *
+ */
+#define RIL_UNSOL_SIGNAL_STRENGTH  1009
+
+
+/**
+ * RIL_UNSOL_DATA_CALL_LIST_CHANGED
+ *
+ * "data" is an array of RIL_Data_Call_Response_v6 identical to that
+ * returned by RIL_REQUEST_DATA_CALL_LIST. It is the complete list
+ * of current data contexts including new contexts that have been
+ * activated. A data call is only removed from this list when the
+ * framework sends a RIL_REQUEST_DEACTIVATE_DATA_CALL or the radio
+ * is powered off/on.
+ *
+ * See also: RIL_REQUEST_DATA_CALL_LIST
+ */
+
+#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
+
+/**
+ * RIL_UNSOL_SUPP_SVC_NOTIFICATION
+ *
+ * Reports supplementary service related notification from the network.
+ *
+ * "data" is a const RIL_SuppSvcNotification *
+ *
+ */
+
+#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
+
+/**
+ * RIL_UNSOL_STK_SESSION_END
+ *
+ * Indicate when STK session is terminated by SIM.
+ *
+ * "data" is NULL
+ */
+#define RIL_UNSOL_STK_SESSION_END 1012
+
+/**
+ * RIL_UNSOL_STK_PROACTIVE_COMMAND
+ *
+ * Indicate when SIM issue a STK proactive command to applications
+ *
+ * "data" is a const char * containing SAT/USAT proactive command
+ * in hexadecimal format string starting with command tag
+ *
+ */
+#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
+
+/**
+ * RIL_UNSOL_STK_EVENT_NOTIFY
+ *
+ * Indicate when SIM notifies applcations some event happens.
+ * Generally, application does not need to have any feedback to
+ * SIM but shall be able to indicate appropriate messages to users.
+ *
+ * "data" is a const char * containing SAT/USAT commands or responses
+ * sent by ME to SIM or commands handled by ME, in hexadecimal format string
+ * starting with first byte of response data or command tag
+ *
+ */
+#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
+
+/**
+ * RIL_UNSOL_STK_CALL_SETUP
+ *
+ * Indicate when SIM wants application to setup a voice call.
+ *
+ * "data" is const int *
+ * ((const int *)data)[0] contains timeout value (in milliseconds)
+ */
+#define RIL_UNSOL_STK_CALL_SETUP 1015
+
+/**
+ * RIL_UNSOL_SIM_SMS_STORAGE_FULL
+ *
+ * Indicates that SMS storage on the SIM is full.  Sent when the network
+ * attempts to deliver a new SMS message.  Messages cannot be saved on the
+ * SIM until space is freed.  In particular, incoming Class 2 messages
+ * cannot be stored.
+ *
+ * "data" is null
+ *
+ */
+#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
+
+/**
+ * RIL_UNSOL_SIM_REFRESH
+ *
+ * Indicates that file(s) on the SIM have been updated, or the SIM
+ * has been reinitialized.
+ *
+ * In the case where RIL is version 6 or older:
+ * "data" is an int *
+ * ((int *)data)[0] is a RIL_SimRefreshResult.
+ * ((int *)data)[1] is the EFID of the updated file if the result is
+ * SIM_FILE_UPDATE or NULL for any other result.
+ *
+ * In the case where RIL is version 7:
+ * "data" is a RIL_SimRefreshResponse_v7 *
+ *
+ * Note: If the SIM state changes as a result of the SIM refresh (eg,
+ * SIM_READY -> SIM_LOCKED_OR_ABSENT), RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
+ * should be sent.
+ */
+#define RIL_UNSOL_SIM_REFRESH 1017
+
+/**
+ * RIL_UNSOL_CALL_RING
+ *
+ * Ring indication for an incoming call (eg, RING or CRING event).
+ * There must be at least one RIL_UNSOL_CALL_RING at the beginning
+ * of a call and sending multiple is optional. If the system property
+ * ro.telephony.call_ring.multiple is false then the upper layers
+ * will generate the multiple events internally. Otherwise the vendor
+ * ril must generate multiple RIL_UNSOL_CALL_RING if
+ * ro.telephony.call_ring.multiple is true or if it is absent.
+ *
+ * The rate of these events is controlled by ro.telephony.call_ring.delay
+ * and has a default value of 3000 (3 seconds) if absent.
+ *
+ * "data" is null for GSM
+ * "data" is const RIL_CDMA_SignalInfoRecord * if CDMA
+ */
+#define RIL_UNSOL_CALL_RING 1018
+
+/**
+ * RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
+ *
+ * Indicates that SIM state changes.
+ *
+ * Callee will invoke RIL_REQUEST_GET_SIM_STATUS on main thread
+
+ * "data" is null
+ */
+#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
+
+/**
+ * RIL_UNSOL_RESPONSE_CDMA_NEW_SMS
+ *
+ * Called when new CDMA SMS is received
+ *
+ * "data" is const RIL_CDMA_SMS_Message *
+ *
+ * Callee will subsequently confirm the receipt of the SMS with
+ * a RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE
+ *
+ * No new RIL_UNSOL_RESPONSE_CDMA_NEW_SMS should be sent until
+ * RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE has been received
+ *
+ */
+#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
+
+/**
+ * RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS
+ *
+ * Called when new Broadcast SMS is received
+ *
+ * "data" can be one of the following:
+ * If received from GSM network, "data" is const char of 88 bytes
+ * which indicates each page of a CBS Message sent to the MS by the
+ * BTS as coded in 3GPP 23.041 Section 9.4.1.2.
+ * If received from UMTS network, "data" is const char of 90 up to 1252
+ * bytes which contain between 1 and 15 CBS Message pages sent as one
+ * packet to the MS by the BTS as coded in 3GPP 23.041 Section 9.4.2.2.
+ *
+ */
+#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
+
+/**
+ * RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL
+ *
+ * Indicates that SMS storage on the RUIM is full.  Messages
+ * cannot be saved on the RUIM until space is freed.
+ *
+ * "data" is null
+ *
+ */
+#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
+
+/**
+ * RIL_UNSOL_RESTRICTED_STATE_CHANGED
+ *
+ * Indicates a restricted state change (eg, for Domain Specific Access Control).
+ *
+ * Radio need send this msg after radio off/on cycle no matter it is changed or not.
+ *
+ * "data" is an int *
+ * ((int *)data)[0] contains a bitmask of RIL_RESTRICTED_STATE_* values.
+ */
+#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
+
+/**
+ * RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE
+ *
+ * Indicates that the radio system selection module has
+ * autonomously entered emergency callback mode.
+ *
+ * "data" is null
+ *
+ */
+#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
+
+/**
+ * RIL_UNSOL_CDMA_CALL_WAITING
+ *
+ * Called when CDMA radio receives a call waiting indication.
+ *
+ * "data" is const RIL_CDMA_CallWaiting *
+ *
+ */
+#define RIL_UNSOL_CDMA_CALL_WAITING 1025
+
+/**
+ * RIL_UNSOL_CDMA_OTA_PROVISION_STATUS
+ *
+ * Called when CDMA radio receives an update of the progress of an
+ * OTASP/OTAPA call.
+ *
+ * "data" is const int *
+ *  For CDMA this is an integer OTASP/OTAPA status listed in
+ *  RIL_CDMA_OTA_ProvisionStatus.
+ *
+ */
+#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
+
+/**
+ * RIL_UNSOL_CDMA_INFO_REC
+ *
+ * Called when CDMA radio receives one or more info recs.
+ *
+ * "data" is const RIL_CDMA_InformationRecords *
+ *
+ */
+#define RIL_UNSOL_CDMA_INFO_REC 1027
+
+/**
+ * RIL_UNSOL_OEM_HOOK_RAW
+ *
+ * This is for OEM specific use.
+ *
+ * "data" is a byte[]
+ */
+#define RIL_UNSOL_OEM_HOOK_RAW 1028
+
+/**
+ * RIL_UNSOL_RINGBACK_TONE
+ *
+ * Indicates that nework doesn't have in-band information,  need to
+ * play out-band tone.
+ *
+ * "data" is an int *
+ * ((int *)data)[0] == 0 for stop play ringback tone.
+ * ((int *)data)[0] == 1 for start play ringback tone.
+ */
+#define RIL_UNSOL_RINGBACK_TONE 1029
+
+/**
+ * RIL_UNSOL_RESEND_INCALL_MUTE
+ *
+ * Indicates that framework/application need reset the uplink mute state.
+ *
+ * There may be situations where the mute state becomes out of sync
+ * between the application and device in some GSM infrastructures.
+ *
+ * "data" is null
+ */
+#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
+
+/**
+ * RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED
+ *
+ * Called when CDMA subscription source changed.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == RIL_CdmaSubscriptionSource
+ */
+#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
+
+/**
+ * RIL_UNSOL_CDMA_PRL_CHANGED
+ *
+ * Called when PRL (preferred roaming list) changes.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is PRL_VERSION as would be returned by RIL_REQUEST_CDMA_SUBSCRIPTION
+ */
+#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
+
+/**
+ * RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE
+ *
+ * Called when Emergency Callback Mode Ends
+ *
+ * Indicates that the radio system selection module has
+ * proactively exited emergency callback mode.
+ *
+ * "data" is NULL
+ *
+ */
+#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
+
+/**
+ * RIL_UNSOL_RIL_CONNECTED
+ *
+ * Called the ril connects and returns the version
+ *
+ * "data" is int *
+ * ((int *)data)[0] is RIL_VERSION
+ */
+#define RIL_UNSOL_RIL_CONNECTED 1034
+
+/**
+ * RIL_UNSOL_VOICE_RADIO_TECH_CHANGED
+ *
+ * Indicates that voice technology has changed. Contains new radio technology
+ * as a data in the message.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is of type const RIL_RadioTechnology
+ *
+ */
+#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
+
+/**
+ * RIL_UNSOL_CELL_INFO_LIST
+ *
+ * Same information as returned by RIL_REQUEST_GET_CELL_INFO_LIST, but returned
+ * at the rate no greater than specified by RIL_REQUEST_SET_UNSOL_CELL_INFO_RATE.
+ *
+ * "data" is NULL
+ *
+ * "response" is an array of RIL_CellInfo_v12.
+ */
+#define RIL_UNSOL_CELL_INFO_LIST 1036
+
+/**
+ * RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED
+ *
+ * This message is DEPRECATED and shall be removed in a future release (target: 2018);
+ * instead, provide IMS registration status via an IMS Service.
+ *
+ * Called when IMS registration state has changed
+ *
+ * To get IMS registration state and IMS SMS format, callee needs to invoke the
+ * following request on main thread:
+ *
+ * RIL_REQUEST_IMS_REGISTRATION_STATE
+ *
+ * "data" is NULL
+ *
+ */
+#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
+
+/**
+ * RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED
+ *
+ * Indicated when there is a change in subscription status.
+ * This event will be sent in the following scenarios
+ *  - subscription readiness at modem, which was selected by telephony layer
+ *  - when subscription is deactivated by modem due to UICC card removal
+ *  - When network invalidates the subscription i.e. attach reject due to authentication reject
+ *
+ * "data" is const int *
+ * ((const int *)data)[0] == 0 for Subscription Deactivated
+ * ((const int *)data)[0] == 1 for Subscription Activated
+ *
+ */
+#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
+
+/**
+ * RIL_UNSOL_SRVCC_STATE_NOTIFY
+ *
+ * Called when Single Radio Voice Call Continuity(SRVCC)
+ * progress state has changed
+ *
+ * "data" is int *
+ * ((int *)data)[0] is of type const RIL_SrvccState
+ *
+ */
+
+#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
+
+/**
+ * RIL_UNSOL_HARDWARE_CONFIG_CHANGED
+ *
+ * Called when the hardware configuration associated with the RILd changes
+ *
+ * "data" is an array of RIL_HardwareConfig
+ *
+ */
+#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
+
+/**
+ * RIL_UNSOL_DC_RT_INFO_CHANGED
+ *
+ * The message is DEPRECATED, use RIL_REQUEST_GET_ACTIVITY_INFO
+ * Sent when the DC_RT_STATE changes but the time
+ * between these messages must not be less than the
+ * value set by RIL_REQUEST_SET_DC_RT_RATE.
+ *
+ * "data" is the most recent RIL_DcRtInfo
+ *
+ */
+#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
+
+/**
+ * RIL_UNSOL_RADIO_CAPABILITY
+ *
+ * Sent when RIL_REQUEST_SET_RADIO_CAPABILITY completes.
+ * Returns the phone radio capability exactly as
+ * RIL_REQUEST_GET_RADIO_CAPABILITY and should be the
+ * same set as sent by RIL_REQUEST_SET_RADIO_CAPABILITY.
+ *
+ * "data" is the RIL_RadioCapability structure
+ */
+#define RIL_UNSOL_RADIO_CAPABILITY 1042
+
+/*
+ * RIL_UNSOL_ON_SS
+ *
+ * Called when SS response is received when DIAL/USSD/SS is changed to SS by
+ * call control.
+ *
+ * "data" is const RIL_StkCcUnsolSsResponse *
+ *
+ */
+#define RIL_UNSOL_ON_SS 1043
+
+/**
+ * RIL_UNSOL_STK_CC_ALPHA_NOTIFY
+ *
+ * Called when there is an ALPHA from UICC during Call Control.
+ *
+ * "data" is const char * containing ALPHA string from UICC in UTF-8 format.
+ *
+ */
+#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
+
+/**
+ * RIL_UNSOL_LCEDATA_RECV
+ *
+ * Called when there is an incoming Link Capacity Estimate (LCE) info report.
+ *
+ * "data" is the RIL_LceDataInfo structure.
+ *
+ */
+#define RIL_UNSOL_LCEDATA_RECV 1045
+
+ /**
+  * RIL_UNSOL_PCO_DATA
+  *
+  * Called when there is new Carrier PCO data received for a data call.  Ideally
+  * only new data will be forwarded, though this is not required.  Multiple
+  * boxes of carrier PCO data for a given call should result in a series of
+  * RIL_UNSOL_PCO_DATA calls.
+  *
+  * "data" is the RIL_PCO_Data structure.
+  *
+  */
+#define RIL_UNSOL_PCO_DATA 1046
+
+ /**
+  * RIL_UNSOL_MODEM_RESTART
+  *
+  * Called when there is a modem reset.
+  *
+  * "reason" is "const char *" containing the reason for the reset. It
+  * could be a crash signature if the restart was due to a crash or some
+  * string such as "user-initiated restart" or "AT command initiated
+  * restart" that explains the cause of the modem restart.
+  *
+  * When modem restarts, one of the following radio state transitions will happen
+  * 1) RADIO_STATE_ON->RADIO_STATE_UNAVAILABLE->RADIO_STATE_ON or
+  * 2) RADIO_STATE_OFF->RADIO_STATE_UNAVAILABLE->RADIO_STATE_OFF
+  * This message can be sent either just before the RADIO_STATE changes to RADIO_STATE_UNAVAILABLE
+  * or just after but should never be sent after the RADIO_STATE changes from UNAVAILABLE to
+  * AVAILABLE(RADIO_STATE_ON/RADIO_STATE_OFF) again.
+  *
+  * It should NOT be sent after the RADIO_STATE changes to AVAILABLE after the
+  * modem restart as that could be interpreted as a second modem reset by the
+  * framework.
+  */
+#define RIL_UNSOL_MODEM_RESTART 1047
+
+/**
+ * RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION
+ *
+ * Called when the modem needs Carrier specific information that will
+ * be used to encrypt IMSI and IMPI.
+ *
+ * "data" is NULL
+ *
+ */
+#define RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION 1048
+
+/**
+ * RIL_UNSOL_NETWORK_SCAN_RESULT
+ *
+ * Returns incremental result for the network scan which is started by
+ * RIL_REQUEST_START_NETWORK_SCAN, sent to report results, status, or errors.
+ *
+ * "data" is NULL
+ * "response" is a const RIL_NetworkScanResult *
+ */
+#define RIL_UNSOL_NETWORK_SCAN_RESULT 1049
+
+/**
+ * RIL_UNSOL_KEEPALIVE_STATUS
+ *
+ * "data" is NULL
+ * "response" is a const RIL_KeepaliveStatus *
+ */
+#define RIL_UNSOL_KEEPALIVE_STATUS 1050
+
+#define RIL_UNSOL_PHYSICAL_CHANNEL_CONFIGS 1051
+
+#define RIL_UNSOL_RESPONSE_LAST RIL_UNSOL_PHYSICAL_CHANNEL_CONFIGS
+
+/***********************************************************************/
+
+#define RIL_UNSOL_RESPONSE_RADIO_CONFIG_BASE 1100
+/**
+ * RIL_UNSOL_CONFIG_ICC_SLOT_STATUS
+ *
+ * "data" is the RIL_SimSlotStatus_V1_2 structure
+ */
+#define RIL_UNSOL_CONFIG_ICC_SLOT_STATUS 1052
+
+#define RIL_UNSOL_RESPONSE_RADIO_CONFIG_LAST RIL_UNSOL_CONFIG_ICC_SLOT_STATUS
+
+/***********************************************************************/
+
+
+#if defined(ANDROID_MULTI_SIM)
+/**
+ * RIL_Request Function pointer
+ *
+ * @param request is one of RIL_REQUEST_*
+ * @param data is pointer to data defined for that RIL_REQUEST_*
+ *        data is owned by caller, and should not be modified or freed by callee
+ *        structures passed as data may contain pointers to non-contiguous memory
+ * @param t should be used in subsequent call to RIL_onResponse
+ * @param datalen is the length of "data" which is defined as other argument. It may or may
+ *        not be equal to sizeof(data). Refer to the documentation of individual structures
+ *        to find if pointers listed in the structure are contiguous and counted in the datalen
+ *        length or not.
+ *        (Eg: RIL_IMS_SMS_Message where we don't have datalen equal to sizeof(data))
+ *
+ */
+typedef void (*RIL_RequestFunc) (int request, void *data,
+                                    size_t datalen, RIL_Token t, RIL_SOCKET_ID socket_id);
+
+/**
+ * This function should return the current radio state synchronously
+ */
+typedef RIL_RadioState (*RIL_RadioStateRequest)(RIL_SOCKET_ID socket_id);
+
+#else
+/* Backward compatible */
+
+/**
+ * RIL_Request Function pointer
+ *
+ * @param request is one of RIL_REQUEST_*
+ * @param data is pointer to data defined for that RIL_REQUEST_*
+ *        data is owned by caller, and should not be modified or freed by callee
+ *        structures passed as data may contain pointers to non-contiguous memory
+ * @param t should be used in subsequent call to RIL_onResponse
+ * @param datalen is the length of "data" which is defined as other argument. It may or may
+ *        not be equal to sizeof(data). Refer to the documentation of individual structures
+ *        to find if pointers listed in the structure are contiguous and counted in the datalen
+ *        length or not.
+ *        (Eg: RIL_IMS_SMS_Message where we don't have datalen equal to sizeof(data))
+ *
+ */
+typedef void (*RIL_RequestFunc) (int request, void *data,
+                                    size_t datalen, RIL_Token t);
+
+/**
+ * This function should return the current radio state synchronously
+ */
+typedef RIL_RadioState (*RIL_RadioStateRequest)();
+
+#endif
+
+
+/**
+ * This function returns "1" if the specified RIL_REQUEST code is
+ * supported and 0 if it is not
+ *
+ * @param requestCode is one of RIL_REQUEST codes
+ */
+
+typedef int (*RIL_Supports)(int requestCode);
+
+/**
+ * This function is called from a separate thread--not the
+ * thread that calls RIL_RequestFunc--and indicates that a pending
+ * request should be cancelled.
+ *
+ * On cancel, the callee should do its best to abandon the request and
+ * call RIL_onRequestComplete with RIL_Errno CANCELLED at some later point.
+ *
+ * Subsequent calls to  RIL_onRequestComplete for this request with
+ * other results will be tolerated but ignored. (That is, it is valid
+ * to ignore the cancellation request)
+ *
+ * RIL_Cancel calls should return immediately, and not wait for cancellation
+ *
+ * Please see ITU v.250 5.6.1 for how one might implement this on a TS 27.007
+ * interface
+ *
+ * @param t token wants to be canceled
+ */
+
+typedef void (*RIL_Cancel)(RIL_Token t);
+
+typedef void (*RIL_TimedCallback) (void *param);
+
+/**
+ * Return a version string for your RIL implementation
+ */
+typedef const char * (*RIL_GetVersion) (void);
+
+typedef struct {
+    int version;        /* set to RIL_VERSION */
+    RIL_RequestFunc onRequest;
+    RIL_RadioStateRequest onStateRequest;
+    RIL_Supports supports;
+    RIL_Cancel onCancel;
+    RIL_GetVersion getVersion;
+} RIL_RadioFunctions;
+
+typedef struct {
+    char *apn;                  /* the APN to connect to */
+    char *protocol;             /* one of the PDP_type values in TS 27.007 section 10.1.1 used on
+                                   roaming network. For example, "IP", "IPV6", "IPV4V6", or "PPP".*/
+    int authtype;               /* authentication protocol used for this PDP context
+                                   (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3) */
+    char *username;             /* the username for APN, or NULL */
+    char *password;             /* the password for APN, or NULL */
+} RIL_InitialAttachApn;
+
+typedef struct {
+    char *apn;                  /* the APN to connect to */
+    char *protocol;             /* one of the PDP_type values in TS 27.007 section 10.1.1 used on
+                                   home network. For example, "IP", "IPV6", "IPV4V6", or "PPP". */
+    char *roamingProtocol;      /* one of the PDP_type values in TS 27.007 section 10.1.1 used on
+                                   roaming network. For example, "IP", "IPV6", "IPV4V6", or "PPP".*/
+    int authtype;               /* authentication protocol used for this PDP context
+                                   (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3) */
+    char *username;             /* the username for APN, or NULL */
+    char *password;             /* the password for APN, or NULL */
+    int supportedTypesBitmask;  /* supported APN types bitmask. See RIL_ApnTypes for the value of
+                                   each bit. */
+    int bearerBitmask;          /* the bearer bitmask. See RIL_RadioAccessFamily for the value of
+                                   each bit. */
+    int modemCognitive;         /* indicating the APN setting was sent to the modem through
+                                   setDataProfile earlier. */
+    int mtu;                    /* maximum transmission unit (MTU) size in bytes */
+    char *mvnoType;             /* the MVNO type: possible values are "imsi", "gid", "spn" */
+    char *mvnoMatchData;        /* MVNO match data. Can be anything defined by the carrier.
+                                   For example,
+                                     SPN like: "A MOBILE", "BEN NL", etc...
+                                     IMSI like: "302720x94", "2060188", etc...
+                                     GID like: "4E", "33", etc... */
+} RIL_InitialAttachApn_v15;
+
+typedef struct {
+    int authContext;            /* P2 value of authentication command, see P2 parameter in
+                                   3GPP TS 31.102 7.1.2 */
+    char *authData;             /* the challenge string in Base64 format, see 3GPP
+                                   TS 31.102 7.1.2 */
+    char *aid;                  /* AID value, See ETSI 102.221 8.1 and 101.220 4,
+                                   NULL if no value. */
+} RIL_SimAuthentication;
+
+typedef struct {
+    int cid;                    /* Context ID, uniquely identifies this call */
+    char *bearer_proto;         /* One of the PDP_type values in TS 27.007 section 10.1.1.
+                                   For example, "IP", "IPV6", "IPV4V6". */
+    int pco_id;                 /* The protocol ID for this box.  Note that only IDs from
+                                   FF00H - FFFFH are accepted.  If more than one is included
+                                   from the network, multiple calls should be made to send all
+                                   of them. */
+    int contents_length;        /* The number of octets in the contents. */
+    char *contents;             /* Carrier-defined content.  It is binary, opaque and
+                                   loosely defined in LTE Layer 3 spec 24.008 */
+} RIL_PCO_Data;
+
+typedef enum {
+    NATT_IPV4 = 0,              /* Keepalive specified by RFC 3948 Sec. 2.3 using IPv4 */
+    NATT_IPV6 = 1               /* Keepalive specified by RFC 3948 Sec. 2.3 using IPv6 */
+} RIL_KeepaliveType;
+
+#define MAX_INADDR_LEN 16
+typedef struct {
+    RIL_KeepaliveType type;                  /* Type of keepalive packet */
+    char sourceAddress[MAX_INADDR_LEN];      /* Source address in network-byte order */
+    int sourcePort;                          /* Source port if applicable, or 0x7FFFFFFF;
+                                                the maximum value is 65535 */
+    char destinationAddress[MAX_INADDR_LEN]; /* Destination address in network-byte order */
+    int destinationPort;                     /* Destination port if applicable or 0x7FFFFFFF;
+                                                the maximum value is 65535 */
+    int maxKeepaliveIntervalMillis;          /* Maximum milliseconds between two packets */
+    int cid;                                 /* Context ID, uniquely identifies this call */
+} RIL_KeepaliveRequest;
+
+typedef enum {
+    KEEPALIVE_ACTIVE,                       /* Keepalive session is active */
+    KEEPALIVE_INACTIVE,                     /* Keepalive session is inactive */
+    KEEPALIVE_PENDING                       /* Keepalive session status not available */
+} RIL_KeepaliveStatusCode;
+
+typedef struct {
+    uint32_t sessionHandle;
+    RIL_KeepaliveStatusCode code;
+} RIL_KeepaliveStatus;
+
+#ifdef RIL_SHLIB
+struct RIL_Env {
+    /**
+     * "t" is parameter passed in on previous call to RIL_Notification
+     * routine.
+     *
+     * If "e" != SUCCESS, then response can be null/is ignored
+     *
+     * "response" is owned by caller, and should not be modified or
+     * freed by callee
+     *
+     * RIL_onRequestComplete will return as soon as possible
+     */
+    void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
+                           void *response, size_t responselen);
+
+#if defined(ANDROID_MULTI_SIM)
+    /**
+     * "unsolResponse" is one of RIL_UNSOL_RESPONSE_*
+     * "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_*
+     *
+     * "data" is owned by caller, and should not be modified or freed by callee
+     */
+    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id);
+#else
+    /**
+     * "unsolResponse" is one of RIL_UNSOL_RESPONSE_*
+     * "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_*
+     *
+     * "data" is owned by caller, and should not be modified or freed by callee
+     */
+    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen);
+#endif
+    /**
+     * Call user-specifed "callback" function on on the same thread that
+     * RIL_RequestFunc is called. If "relativeTime" is specified, then it specifies
+     * a relative time value at which the callback is invoked. If relativeTime is
+     * NULL or points to a 0-filled structure, the callback will be invoked as
+     * soon as possible
+     */
+
+    void (*RequestTimedCallback) (RIL_TimedCallback callback,
+                                   void *param, const struct timeval *relativeTime);
+   /**
+    * "t" is parameter passed in on previous call RIL_Notification routine
+    *
+    * RIL_onRequestAck will be called by vendor when an Async RIL request was received
+    * by them and an ack needs to be sent back to java ril.
+    */
+    void (*OnRequestAck) (RIL_Token t);
+};
+
+
+/**
+ *  RIL implementations must defined RIL_Init
+ *  argc and argv will be command line arguments intended for the RIL implementation
+ *  Return NULL on error
+ *
+ * @param env is environment point defined as RIL_Env
+ * @param argc number of arguments
+ * @param argv list fo arguments
+ *
+ */
+const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv);
+
+/**
+ *  If BT SAP(SIM Access Profile) is supported, then RIL implementations must define RIL_SAP_Init
+ *  for initializing RIL_RadioFunctions used for BT SAP communcations. It is called whenever RILD
+ *  starts or modem restarts. Returns handlers for SAP related request that are made on SAP
+ *  sepecific socket, analogous to the RIL_RadioFunctions returned by the call to RIL_Init
+ *  and used on the general RIL socket.
+ *  argc and argv will be command line arguments intended for the RIL implementation
+ *  Return NULL on error.
+ *
+ * @param env is environment point defined as RIL_Env
+ * @param argc number of arguments
+ * @param argv list fo arguments
+ *
+ */
+const RIL_RadioFunctions *RIL_SAP_Init(const struct RIL_Env *env, int argc, char **argv);
+
+#else /* RIL_SHLIB */
+
+/**
+ * Call this once at startup to register notification routine
+ *
+ * @param callbacks user-specifed callback function
+ */
+void RIL_register (const RIL_RadioFunctions *callbacks);
+
+void rilc_thread_pool();
+
+
+/**
+ *
+ * RIL_onRequestComplete will return as soon as possible
+ *
+ * @param t is parameter passed in on previous call to RIL_Notification
+ *          routine.
+ * @param e error code
+ *          if "e" != SUCCESS, then response can be null/is ignored
+ * @param response is owned by caller, and should not be modified or
+ *                 freed by callee
+ * @param responselen the length of response in byte
+ */
+void RIL_onRequestComplete(RIL_Token t, RIL_Errno e,
+                           void *response, size_t responselen);
+
+/**
+ * RIL_onRequestAck will be called by vendor when an Async RIL request was received by them and
+ * an ack needs to be sent back to java ril. This doesn't mark the end of the command or it's
+ * results, just that the command was received and will take a while. After sending this Ack
+ * its vendor's responsibility to make sure that AP is up whenever needed while command is
+ * being processed.
+ *
+ * @param t is parameter passed in on previous call to RIL_Notification
+ *          routine.
+ */
+void RIL_onRequestAck(RIL_Token t);
+
+#if defined(ANDROID_MULTI_SIM)
+/**
+ * @param unsolResponse is one of RIL_UNSOL_RESPONSE_*
+ * @param data is pointer to data defined for that RIL_UNSOL_RESPONSE_*
+ *     "data" is owned by caller, and should not be modified or freed by callee
+ * @param datalen the length of data in byte
+ */
+
+void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
+                                size_t datalen, RIL_SOCKET_ID socket_id);
+#else
+/**
+ * @param unsolResponse is one of RIL_UNSOL_RESPONSE_*
+ * @param data is pointer to data defined for that RIL_UNSOL_RESPONSE_*
+ *     "data" is owned by caller, and should not be modified or freed by callee
+ * @param datalen the length of data in byte
+ */
+
+void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
+                                size_t datalen);
+#endif
+
+/**
+ * Call user-specifed "callback" function on on the same thread that
+ * RIL_RequestFunc is called. If "relativeTime" is specified, then it specifies
+ * a relative time value at which the callback is invoked. If relativeTime is
+ * NULL or points to a 0-filled structure, the callback will be invoked as
+ * soon as possible
+ *
+ * @param callback user-specifed callback function
+ * @param param parameter list
+ * @param relativeTime a relative time value at which the callback is invoked
+ */
+
+void RIL_requestTimedCallback (RIL_TimedCallback callback,
+                               void *param, const struct timeval *relativeTime);
+
+#endif /* RIL_SHLIB */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*ANDROID_RIL_H*/
diff --git a/guest/hals/ril/reference-libril/rilSocketQueue.h b/guest/hals/ril/reference-libril/rilSocketQueue.h
new file mode 100644
index 0000000..eaa5155
--- /dev/null
+++ b/guest/hals/ril/reference-libril/rilSocketQueue.h
@@ -0,0 +1,167 @@
+/*
+* Copyright (C) 2014 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.
+*/
+
+#include "pb_decode.h"
+#include <pthread.h>
+#include <hardware/ril/librilutils/proto/sap-api.pb.h>
+#include <utils/Log.h>
+
+using namespace std;
+
+/**
+ * Template queue class to handling requests for a rild socket.
+ * <p>
+ * This class performs the following functions :
+ * <ul>
+ *     <li>Enqueue.
+ *     <li>Dequeue.
+ *     <li>Check and dequeue.
+ * </ul>
+ */
+
+template <typename T>
+class Ril_queue {
+
+   /**
+     * Mutex attribute used in queue mutex initialization.
+     */
+    pthread_mutexattr_t attr;
+
+   /**
+     * Queue mutex variable for synchronized queue access.
+     */
+    pthread_mutex_t mutex_instance;
+
+   /**
+     * Condition to be waited on for dequeuing.
+     */
+    pthread_cond_t cond;
+
+   /**
+     * Front of the queue.
+     */
+    T *front;
+
+    public:
+
+       /**
+         * Remove the first element of the queue.
+         *
+         * @return first element of the queue.
+         */
+        T* dequeue(void);
+
+       /**
+         * Add a request to the front of the queue.
+         *
+         * @param Request to be added.
+         */
+        void enqueue(T* request);
+
+       /**
+         * Check if the queue is empty.
+         */
+        int empty(void);
+
+       /**
+         * Check and remove an element with a particular message id and token.
+         *
+         * @param Request message id.
+         * @param Request token.
+         */
+        int checkAndDequeue( MsgId id, int token);
+
+       /**
+         * Queue constructor.
+         */
+        Ril_queue(void);
+};
+
+template <typename T>
+Ril_queue<T>::Ril_queue(void) {
+    pthread_mutexattr_init(&attr);
+    pthread_mutex_init(&mutex_instance, &attr);
+    cond = PTHREAD_COND_INITIALIZER;
+    front = NULL;
+}
+
+template <typename T>
+T* Ril_queue<T>::dequeue(void) {
+    T* temp = NULL;
+
+    pthread_mutex_lock(&mutex_instance);
+    while(empty()) {
+        pthread_cond_wait(&cond, &mutex_instance);
+    }
+    temp = this->front;
+    if(NULL != this->front->p_next) {
+        this->front = this->front->p_next;
+    } else {
+        this->front = NULL;
+    }
+    pthread_mutex_unlock(&mutex_instance);
+
+    return temp;
+}
+
+template <typename T>
+void Ril_queue<T>::enqueue(T* request) {
+
+    pthread_mutex_lock(&mutex_instance);
+
+    if(NULL == this->front) {
+        this->front = request;
+        request->p_next = NULL;
+    } else {
+        request->p_next = this->front;
+        this->front = request;
+    }
+    pthread_cond_broadcast(&cond);
+    pthread_mutex_unlock(&mutex_instance);
+}
+
+template <typename T>
+int Ril_queue<T>::checkAndDequeue(MsgId id, int token) {
+    int ret = 0;
+    T* temp;
+
+    pthread_mutex_lock(&mutex_instance);
+
+    for(T **ppCur = &(this->front); *ppCur != NULL; ppCur = &((*ppCur)->p_next)) {
+        if (token == (*ppCur)->token && id == (*ppCur)->curr->id) {
+            ret = 1;
+            temp = *ppCur;
+            *ppCur = (*ppCur)->p_next;
+            free(temp);
+            break;
+        }
+    }
+
+    pthread_mutex_unlock(&mutex_instance);
+
+    return ret;
+}
+
+
+template <typename T>
+int Ril_queue<T>::empty(void) {
+
+    if(this->front == NULL) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
diff --git a/guest/hals/ril/reference-libril/ril_commands.h b/guest/hals/ril/reference-libril/ril_commands.h
new file mode 100644
index 0000000..a100b48
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_commands.h
@@ -0,0 +1,189 @@
+/* //guest/hals/ril/reference-libril/ril_commands.h
+**
+** Copyright 2006, 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.
+*/
+    {0, NULL},                   //none
+    {RIL_REQUEST_GET_SIM_STATUS, radio_1_6::getIccCardStatusResponse},
+    {RIL_REQUEST_ENTER_SIM_PIN, radio_1_6::supplyIccPinForAppResponse},
+    {RIL_REQUEST_ENTER_SIM_PUK, radio_1_6::supplyIccPukForAppResponse},
+    {RIL_REQUEST_ENTER_SIM_PIN2, radio_1_6::supplyIccPin2ForAppResponse},
+    {RIL_REQUEST_ENTER_SIM_PUK2, radio_1_6::supplyIccPuk2ForAppResponse},
+    {RIL_REQUEST_CHANGE_SIM_PIN, radio_1_6::changeIccPinForAppResponse},
+    {RIL_REQUEST_CHANGE_SIM_PIN2, radio_1_6::changeIccPin2ForAppResponse},
+    {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, radio_1_6::supplyNetworkDepersonalizationResponse},
+    {RIL_REQUEST_GET_CURRENT_CALLS, radio_1_6::getCurrentCallsResponse},
+    {RIL_REQUEST_DIAL, radio_1_6::dialResponse},
+    {RIL_REQUEST_GET_IMSI, radio_1_6::getIMSIForAppResponse},
+    {RIL_REQUEST_HANGUP, radio_1_6::hangupConnectionResponse},
+    {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, radio_1_6::hangupWaitingOrBackgroundResponse},
+    {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, radio_1_6::hangupForegroundResumeBackgroundResponse},
+    {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, radio_1_6::switchWaitingOrHoldingAndActiveResponse},
+    {RIL_REQUEST_CONFERENCE, radio_1_6::conferenceResponse},
+    {RIL_REQUEST_UDUB, radio_1_6::rejectCallResponse},
+    {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, radio_1_6::getLastCallFailCauseResponse},
+    {RIL_REQUEST_SIGNAL_STRENGTH, radio_1_6::getSignalStrengthResponse},
+    {RIL_REQUEST_VOICE_REGISTRATION_STATE, radio_1_6::getVoiceRegistrationStateResponse},
+    {RIL_REQUEST_DATA_REGISTRATION_STATE, radio_1_6::getDataRegistrationStateResponse},
+    {RIL_REQUEST_OPERATOR, radio_1_6::getOperatorResponse},
+    {RIL_REQUEST_RADIO_POWER, radio_1_6::setRadioPowerResponse},
+    {RIL_REQUEST_DTMF, radio_1_6::sendDtmfResponse},
+    {RIL_REQUEST_SEND_SMS, radio_1_6::sendSmsResponse},
+    {RIL_REQUEST_SEND_SMS_EXPECT_MORE, radio_1_6::sendSmsExpectMoreResponse},
+    {RIL_REQUEST_SETUP_DATA_CALL, radio_1_6::setupDataCallResponse},
+    {RIL_REQUEST_SIM_IO, radio_1_6::iccIOForAppResponse},
+    {RIL_REQUEST_SEND_USSD, radio_1_6::sendUssdResponse},
+    {RIL_REQUEST_CANCEL_USSD, radio_1_6::cancelPendingUssdResponse},
+    {RIL_REQUEST_GET_CLIR, radio_1_6::getClirResponse},
+    {RIL_REQUEST_SET_CLIR, radio_1_6::setClirResponse},
+    {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, radio_1_6::getCallForwardStatusResponse},
+    {RIL_REQUEST_SET_CALL_FORWARD, radio_1_6::setCallForwardResponse},
+    {RIL_REQUEST_QUERY_CALL_WAITING, radio_1_6::getCallWaitingResponse},
+    {RIL_REQUEST_SET_CALL_WAITING, radio_1_6::setCallWaitingResponse},
+    {RIL_REQUEST_SMS_ACKNOWLEDGE, radio_1_6::acknowledgeLastIncomingGsmSmsResponse},
+    {RIL_REQUEST_GET_IMEI, NULL},
+    {RIL_REQUEST_GET_IMEISV, NULL},
+    {RIL_REQUEST_ANSWER, radio_1_6::acceptCallResponse},
+    {RIL_REQUEST_DEACTIVATE_DATA_CALL, radio_1_6::deactivateDataCallResponse},
+    {RIL_REQUEST_QUERY_FACILITY_LOCK, radio_1_6::getFacilityLockForAppResponse},
+    {RIL_REQUEST_SET_FACILITY_LOCK, radio_1_6::setFacilityLockForAppResponse},
+    {RIL_REQUEST_CHANGE_BARRING_PASSWORD, radio_1_6::setBarringPasswordResponse},
+    {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, radio_1_6::getNetworkSelectionModeResponse},
+    {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, radio_1_6::setNetworkSelectionModeAutomaticResponse},
+    {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, radio_1_6::setNetworkSelectionModeManualResponse},
+    {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , radio_1_6::getAvailableNetworksResponse},
+    {RIL_REQUEST_DTMF_START, radio_1_6::startDtmfResponse},
+    {RIL_REQUEST_DTMF_STOP, radio_1_6::stopDtmfResponse},
+    {RIL_REQUEST_BASEBAND_VERSION, radio_1_6::getBasebandVersionResponse},
+    {RIL_REQUEST_SEPARATE_CONNECTION, radio_1_6::separateConnectionResponse},
+    {RIL_REQUEST_SET_MUTE, radio_1_6::setMuteResponse},
+    {RIL_REQUEST_GET_MUTE, radio_1_6::getMuteResponse},
+    {RIL_REQUEST_QUERY_CLIP, radio_1_6::getClipResponse},
+    {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, NULL},
+    {RIL_REQUEST_DATA_CALL_LIST, radio_1_6::getDataCallListResponse},
+    {RIL_REQUEST_RESET_RADIO, NULL},
+    {RIL_REQUEST_OEM_HOOK_RAW, radio_1_6::sendRequestRawResponse},
+    {RIL_REQUEST_OEM_HOOK_STRINGS, radio_1_6::sendRequestStringsResponse},
+    {RIL_REQUEST_SCREEN_STATE, radio_1_6::sendDeviceStateResponse},   // Note the response function is different.
+    {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, radio_1_6::setSuppServiceNotificationsResponse},
+    {RIL_REQUEST_WRITE_SMS_TO_SIM, radio_1_6::writeSmsToSimResponse},
+    {RIL_REQUEST_DELETE_SMS_ON_SIM, radio_1_6::deleteSmsOnSimResponse},
+    {RIL_REQUEST_SET_BAND_MODE, radio_1_6::setBandModeResponse},
+    {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, radio_1_6::getAvailableBandModesResponse},
+    {RIL_REQUEST_STK_GET_PROFILE, NULL},
+    {RIL_REQUEST_STK_SET_PROFILE, NULL},
+    {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, radio_1_6::sendEnvelopeResponse},
+    {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, radio_1_6::sendTerminalResponseToSimResponse},
+    {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, radio_1_6::handleStkCallSetupRequestFromSimResponse},
+    {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, radio_1_6::explicitCallTransferResponse},
+    {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, radio_1_6::setPreferredNetworkTypeResponse},
+    {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, radio_1_6::getPreferredNetworkTypeResponse},
+    {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, radio_1_6::getNeighboringCidsResponse},
+    {RIL_REQUEST_SET_LOCATION_UPDATES, radio_1_6::setLocationUpdatesResponse},
+    {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, radio_1_6::setCdmaSubscriptionSourceResponse},
+    {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, radio_1_6::setCdmaRoamingPreferenceResponse},
+    {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, radio_1_6::getCdmaRoamingPreferenceResponse},
+    {RIL_REQUEST_SET_TTY_MODE, radio_1_6::setTTYModeResponse},
+    {RIL_REQUEST_QUERY_TTY_MODE, radio_1_6::getTTYModeResponse},
+    {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, radio_1_6::setPreferredVoicePrivacyResponse},
+    {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, radio_1_6::getPreferredVoicePrivacyResponse},
+    {RIL_REQUEST_CDMA_FLASH, radio_1_6::sendCDMAFeatureCodeResponse},
+    {RIL_REQUEST_CDMA_BURST_DTMF, radio_1_6::sendBurstDtmfResponse},
+    {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, NULL},
+    {RIL_REQUEST_CDMA_SEND_SMS, radio_1_6::sendCdmaSmsResponse},
+    {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, radio_1_6::acknowledgeLastIncomingCdmaSmsResponse},
+    {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, radio_1_6::getGsmBroadcastConfigResponse},
+    {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, radio_1_6::setGsmBroadcastConfigResponse},
+    {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, radio_1_6::setGsmBroadcastActivationResponse},
+    {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, radio_1_6::getCdmaBroadcastConfigResponse},
+    {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, radio_1_6::setCdmaBroadcastConfigResponse},
+    {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, radio_1_6::setCdmaBroadcastActivationResponse},
+    {RIL_REQUEST_CDMA_SUBSCRIPTION, radio_1_6::getCDMASubscriptionResponse},
+    {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, radio_1_6::writeSmsToRuimResponse},
+    {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, radio_1_6::deleteSmsOnRuimResponse},
+    {RIL_REQUEST_DEVICE_IDENTITY, radio_1_6::getDeviceIdentityResponse},
+    {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, radio_1_6::exitEmergencyCallbackModeResponse},
+    {RIL_REQUEST_GET_SMSC_ADDRESS, radio_1_6::getSmscAddressResponse},
+    {RIL_REQUEST_SET_SMSC_ADDRESS, radio_1_6::setSmscAddressResponse},
+    {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, radio_1_6::reportSmsMemoryStatusResponse},
+    {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, radio_1_6::reportStkServiceIsRunningResponse},
+    {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, radio_1_6::getCdmaSubscriptionSourceResponse},
+    {RIL_REQUEST_ISIM_AUTHENTICATION, radio_1_6::requestIsimAuthenticationResponse},
+    {RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, radio_1_6::acknowledgeIncomingGsmSmsWithPduResponse},
+    {RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, radio_1_6::sendEnvelopeWithStatusResponse},
+    {RIL_REQUEST_VOICE_RADIO_TECH, radio_1_6::getVoiceRadioTechnologyResponse},
+    {RIL_REQUEST_GET_CELL_INFO_LIST, radio_1_6::getCellInfoListResponse},
+    {RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, radio_1_6::setCellInfoListRateResponse},
+    {RIL_REQUEST_SET_INITIAL_ATTACH_APN, radio_1_6::setInitialAttachApnResponse},
+    {RIL_REQUEST_IMS_REGISTRATION_STATE, radio_1_6::getImsRegistrationStateResponse},
+    {RIL_REQUEST_IMS_SEND_SMS, radio_1_6::sendImsSmsResponse},
+    {RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC, radio_1_6::iccTransmitApduBasicChannelResponse},
+    {RIL_REQUEST_SIM_OPEN_CHANNEL, radio_1_6::iccOpenLogicalChannelResponse},
+    {RIL_REQUEST_SIM_CLOSE_CHANNEL, radio_1_6::iccCloseLogicalChannelResponse},
+    {RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, radio_1_6::iccTransmitApduLogicalChannelResponse},
+    {RIL_REQUEST_NV_READ_ITEM, radio_1_6::nvReadItemResponse},
+    {RIL_REQUEST_NV_WRITE_ITEM, radio_1_6::nvWriteItemResponse},
+    {RIL_REQUEST_NV_WRITE_CDMA_PRL, radio_1_6::nvWriteCdmaPrlResponse},
+    {RIL_REQUEST_NV_RESET_CONFIG, radio_1_6::nvResetConfigResponse},
+    {RIL_REQUEST_SET_UICC_SUBSCRIPTION, radio_1_6::setUiccSubscriptionResponse},
+    {RIL_REQUEST_ALLOW_DATA, radio_1_6::setDataAllowedResponse},
+    {RIL_REQUEST_GET_HARDWARE_CONFIG, radio_1_6::getHardwareConfigResponse},
+    {RIL_REQUEST_SIM_AUTHENTICATION, radio_1_6::requestIccSimAuthenticationResponse},
+    {RIL_REQUEST_GET_DC_RT_INFO, NULL},
+    {RIL_REQUEST_SET_DC_RT_INFO_RATE, NULL},
+    {RIL_REQUEST_SET_DATA_PROFILE, radio_1_6::setDataProfileResponse},
+    {RIL_REQUEST_SHUTDOWN, radio_1_6::requestShutdownResponse},
+    {RIL_REQUEST_GET_RADIO_CAPABILITY, radio_1_6::getRadioCapabilityResponse},
+    {RIL_REQUEST_SET_RADIO_CAPABILITY, radio_1_6::setRadioCapabilityResponse},
+    {RIL_REQUEST_START_LCE, radio_1_6::startLceServiceResponse},
+    {RIL_REQUEST_STOP_LCE, radio_1_6::stopLceServiceResponse},
+    {RIL_REQUEST_PULL_LCEDATA, radio_1_6::pullLceDataResponse},
+    {RIL_REQUEST_GET_ACTIVITY_INFO, radio_1_6::getModemActivityInfoResponse},
+    {RIL_REQUEST_SET_CARRIER_RESTRICTIONS, radio_1_6::setAllowedCarriersResponse},
+    {RIL_REQUEST_GET_CARRIER_RESTRICTIONS, radio_1_6::getAllowedCarriersResponse},
+    {RIL_REQUEST_SEND_DEVICE_STATE, radio_1_6::sendDeviceStateResponse},
+    {RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER, radio_1_6::setIndicationFilterResponse},
+    {RIL_REQUEST_SET_SIM_CARD_POWER, radio_1_6::setSimCardPowerResponse},
+    {RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION, radio_1_6::setCarrierInfoForImsiEncryptionResponse},
+    {RIL_REQUEST_START_NETWORK_SCAN, radio_1_6::startNetworkScanResponse},
+    {RIL_REQUEST_STOP_NETWORK_SCAN, radio_1_6::stopNetworkScanResponse},
+    {RIL_REQUEST_START_KEEPALIVE, radio_1_6::startKeepaliveResponse},
+    {RIL_REQUEST_STOP_KEEPALIVE, radio_1_6::stopKeepaliveResponse},
+    {RIL_REQUEST_GET_MODEM_STACK_STATUS, radio_1_6::getModemStackStatusResponse},
+    {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP, radio_1_6::getPreferredNetworkTypeBitmapResponse},
+    {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP, radio_1_6::setPreferredNetworkTypeBitmapResponse},
+    {RIL_REQUEST_EMERGENCY_DIAL, radio_1_6::emergencyDialResponse},
+    {RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS, radio_1_6::setSystemSelectionChannelsResponse},
+    {RIL_REQUEST_ENABLE_MODEM, radio_1_6::enableModemResponse},
+    {RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA, radio_1_6::setSignalStrengthReportingCriteriaResponse},
+    {RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA, radio_1_6::setLinkCapacityReportingCriteriaResponse},
+    {RIL_REQUEST_ENABLE_UICC_APPLICATIONS, radio_1_6::enableUiccApplicationsResponse},
+    {RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED, radio_1_6::areUiccApplicationsEnabledResponse},
+    {RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION, radio_1_6::supplySimDepersonalizationResponse},
+    {RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE, radio_1_6::sendCdmaSmsExpectMoreResponse},
+    {RIL_REQUEST_GET_BARRING_INFO, radio_1_6::getBarringInfoResponse},
+    {RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY, radio_1_6::setNrDualConnectivityStateResponse},
+    {RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED, radio_1_6::isNrDualConnectivityEnabledResponse},
+    {RIL_REQUEST_ALLOCATE_PDU_SESSION_ID, radio_1_6::allocatePduSessionIdResponse},
+    {RIL_REQUEST_RELEASE_PDU_SESSION_ID, radio_1_6::releasePduSessionIdResponse},
+    {RIL_REQUEST_START_HANDOVER, radio_1_6::startHandoverResponse},
+    {RIL_REQUEST_CANCEL_HANDOVER, radio_1_6::cancelHandoverResponse},
+    {RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP, radio_1_6::setAllowedNetworkTypesBitmapResponse},
+    {RIL_REQUEST_SET_DATA_THROTTLING, radio_1_6::setDataThrottlingResponse},
+    {RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS, radio_1_6::getSystemSelectionChannelsResponse},
+    {RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP, radio_1_6::getAllowedNetworkTypesBitmapResponse},
+    {RIL_REQUEST_GET_SLICING_CONFIG, radio_1_6::getSlicingConfigResponse},
+    {RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS, radio_1_6::getSimPhonebookRecordsResponse},
+    {RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY, radio_1_6::getSimPhonebookCapacityResponse},
+    {RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORDS, radio_1_6::updateSimPhonebookRecordsResponse}
diff --git a/guest/hals/ril/reference-libril/ril_config.cpp b/guest/hals/ril/reference-libril/ril_config.cpp
new file mode 100644
index 0000000..5a72db9
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_config.cpp
@@ -0,0 +1,574 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "RILC"
+
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+#include <android/hardware/radio/config/1.2/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.2/IRadioConfigIndication.h>
+#include <android/hardware/radio/1.1/types.h>
+
+#include <ril.h>
+#include <guest/hals/ril/reference-libril/ril_service.h>
+#include <hidl/HidlTransportSupport.h>
+
+using namespace android::hardware::radio::V1_0;
+using namespace android::hardware::radio::config;
+using namespace android::hardware::radio::config::V1_0;
+using namespace android::hardware::radio::config::V1_3;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Void;
+using android::CommandInfo;
+using android::RequestInfo;
+using android::requestToString;
+using android::sp;
+
+RIL_RadioFunctions *s_vendorFunctions_config = NULL;
+static CommandInfo *s_configCommands;
+struct RadioConfigImpl;
+sp<RadioConfigImpl> radioConfigService;
+volatile int32_t mCounterRadioConfig;
+
+#if defined (ANDROID_MULTI_SIM)
+#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c), (d))
+#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions_config->onRequest((a), (b), (c), (d), (e))
+#define CALL_ONSTATEREQUEST(a) s_vendorFunctions_config->onStateRequest(a)
+#else
+#define RIL_UNSOL_RESPONSE(a, b, c, d) RIL_onUnsolicitedResponse((a), (b), (c))
+#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions_config->onRequest((a), (b), (c), (d))
+#define CALL_ONSTATEREQUEST(a) s_vendorFunctions_config->onStateRequest()
+#endif
+
+extern void populateResponseInfo(RadioResponseInfo& responseInfo, int serial, int responseType,
+                RIL_Errno e);
+
+extern void populateResponseInfo_1_6(
+    ::android::hardware::radio::V1_6::RadioResponseInfo &responseInfo,
+    int serial, int responseType, RIL_Errno e);
+
+extern bool dispatchVoid(int serial, int slotId, int request);
+extern bool dispatchString(int serial, int slotId, int request, const char * str);
+extern bool dispatchStrings(int serial, int slotId, int request, bool allowEmpty,
+                int countStrings, ...);
+extern bool dispatchInts(int serial, int slotId, int request, int countInts, ...);
+extern hidl_string convertCharPtrToHidlString(const char *ptr);
+extern void sendErrorResponse(android::RequestInfo *pRI, RIL_Errno err);
+extern RadioIndicationType convertIntToRadioIndicationType(int indicationType);
+
+extern bool isChangeSlotId(int serviceId, int slotId);
+
+struct RadioConfigImpl : public V1_3::IRadioConfig {
+    int32_t mSlotId;
+    sp<V1_0::IRadioConfigResponse> mRadioConfigResponse;
+    sp<V1_0::IRadioConfigIndication> mRadioConfigIndication;
+    sp<V1_1::IRadioConfigResponse> mRadioConfigResponseV1_1;
+    sp<V1_2::IRadioConfigResponse> mRadioConfigResponseV1_2;
+    sp<V1_2::IRadioConfigIndication> mRadioConfigIndicationV1_2;
+    sp<V1_3::IRadioConfigResponse> mRadioConfigResponseV1_3;
+
+    Return<void> setResponseFunctions(
+            const ::android::sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+            const ::android::sp<V1_0::IRadioConfigIndication>& radioConfigIndication);
+
+    Return<void> getSimSlotsStatus(int32_t serial);
+
+    Return<void> setSimSlotsMapping(int32_t serial, const hidl_vec<uint32_t>& slotMap);
+
+    Return<void> getPhoneCapability(int32_t serial);
+
+    Return<void> setPreferredDataModem(int32_t serial, uint8_t modemId);
+
+    Return<void> setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig);
+
+    Return<void> getModemsConfig(int32_t serial);
+
+    Return<void> getHalDeviceCapabilities(int32_t serial);
+
+    void checkReturnStatus_config(Return<void>& ret);
+};
+Return<void> RadioConfigImpl::setResponseFunctions(
+        const ::android::sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+        const ::android::sp<V1_0::IRadioConfigIndication>& radioConfigIndication) {
+    pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock(RIL_SOCKET_1);
+    int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+
+    mRadioConfigResponse = radioConfigResponse;
+    mRadioConfigIndication = radioConfigIndication;
+
+
+    mRadioConfigResponseV1_1 =
+        V1_1::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    if (mRadioConfigResponseV1_1 == nullptr) {
+        mRadioConfigResponseV1_1 = nullptr;
+    }
+
+    mRadioConfigResponseV1_2 =
+        V1_2::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_2 =
+        V1_2::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_2 == nullptr || mRadioConfigIndicationV1_2 == nullptr) {
+        mRadioConfigResponseV1_2 = nullptr;
+        mRadioConfigIndicationV1_2 = nullptr;
+    }
+
+    mRadioConfigResponseV1_3 =
+        V1_3::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    if (mRadioConfigResponseV1_3 == nullptr || mRadioConfigResponseV1_3 == nullptr) {
+        mRadioConfigResponseV1_3 = nullptr;
+    }
+
+    mCounterRadioConfig++;
+
+    ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+
+    return Void();
+}
+
+Return<void> RadioConfigImpl::getSimSlotsStatus(int32_t serial) {
+#if VDBG
+    RLOGD("getSimSlotsStatus: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CONFIG_GET_SLOT_STATUS);
+
+    return Void();
+}
+
+Return<void> RadioConfigImpl::setSimSlotsMapping(int32_t serial, const hidl_vec<uint32_t>& slotMap) {
+#if VDBG
+    RLOGD("setSimSlotsMapping: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, RIL_SOCKET_1,
+        RIL_REQUEST_CONFIG_SET_SLOT_MAPPING);
+    if (pRI == NULL) {
+        return Void();
+    }
+    size_t slotNum = slotMap.size();
+
+    if (slotNum > RIL_SOCKET_NUM) {
+        RLOGE("setSimSlotsMapping: invalid parameter");
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    for (size_t socket_id = 0; socket_id < slotNum; socket_id++) {
+        if (slotMap[socket_id] >= RIL_SOCKET_NUM) {
+            RLOGE("setSimSlotsMapping: invalid parameter[%zu]", socket_id);
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            return Void();
+        }
+        // confirm logical id is not duplicate
+        for (size_t nextId = socket_id + 1; nextId < slotNum; nextId++) {
+            if (slotMap[socket_id] == slotMap[nextId]) {
+                RLOGE("setSimSlotsMapping: slot parameter is the same:[%zu] and [%zu]",
+                    socket_id, nextId);
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                return Void();
+            }
+        }
+    }
+    int *pSlotMap = (int *)calloc(slotNum, sizeof(int));
+
+    for (size_t socket_id = 0; socket_id < slotNum; socket_id++) {
+        pSlotMap[socket_id] = slotMap[socket_id];
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_CONFIG_SET_SLOT_MAPPING, pSlotMap,
+        slotNum * sizeof(int), pRI, pRI->socket_id);
+    if (pSlotMap != NULL) {
+        free(pSlotMap);
+    }
+
+    return Void();
+}
+
+Return<void> RadioConfigImpl::getPhoneCapability(int32_t serial) {
+#if VDBG
+    RLOGD("getPhoneCapability: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CONFIG_GET_PHONE_CAPABILITY);
+    return Void();
+}
+
+Return<void> RadioConfigImpl::setPreferredDataModem(int32_t serial, uint8_t modemId) {
+#if VDBG
+    RLOGD("setPreferredDataModem: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_CONFIG_SET_PREFER_DATA_MODEM, 1, modemId);
+    return Void();
+}
+
+Return<void> RadioConfigImpl::setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig) {
+#if VDBG
+    RLOGD("setModemsConfig: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+        RIL_REQUEST_CONFIG_SET_MODEM_CONFIG);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_ModemConfig mdConfig = {};
+
+    mdConfig.numOfLiveModems = modemsConfig.numOfLiveModems;
+
+
+    CALL_ONREQUEST(RIL_REQUEST_CONFIG_SET_MODEM_CONFIG, &mdConfig,
+        sizeof(RIL_ModemConfig), pRI, pRI->socket_id);
+
+    return Void();
+}
+
+Return<void> RadioConfigImpl::getModemsConfig(int32_t serial) {
+#if VDBG
+    RLOGD("getModemsConfig: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CONFIG_GET_MODEM_CONFIG);
+    return Void();
+}
+
+Return<void> RadioConfigImpl::getHalDeviceCapabilities(int32_t serial) {
+#if VDBG
+    RLOGD("getHalDeviceCapabilities: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CONFIG_GET_HAL_DEVICE_CAPABILITIES);
+    return Void();
+}
+
+void radio_1_6::registerConfigService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {
+    using namespace android::hardware;
+    RLOGD("Entry %s", __FUNCTION__);
+    const char *serviceNames = "default";
+
+    s_vendorFunctions_config = callbacks;
+    s_configCommands = commands;
+
+    int slotId = RIL_SOCKET_1;
+
+    pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(0);
+    int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+    RLOGD("registerConfigService: starting V1_2::IConfigRadio %s", serviceNames);
+    radioConfigService = new RadioConfigImpl;
+
+    radioConfigService->mSlotId = slotId;
+    radioConfigService->mRadioConfigResponse = NULL;
+    radioConfigService->mRadioConfigIndication = NULL;
+    radioConfigService->mRadioConfigResponseV1_1 = NULL;
+    radioConfigService->mRadioConfigResponseV1_2 = NULL;
+    radioConfigService->mRadioConfigResponseV1_3 = NULL;
+    radioConfigService->mRadioConfigIndicationV1_2 = NULL;
+    android::status_t status = radioConfigService->registerAsService(serviceNames);
+    RLOGD("registerConfigService registerService: status %d", status);
+    ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+}
+
+void checkReturnStatus(Return<void>& ret) {
+    if (ret.isOk() == false) {
+        RLOGE("checkReturnStatus_config: unable to call response/indication callback");
+        // Remote process hosting the callbacks must be dead. Reset the callback objects;
+        // there's no other recovery to be done here. When the client process is back up, it will
+        // call setResponseFunctions()
+
+        // Caller should already hold rdlock, release that first
+        // note the current counter to avoid overwriting updates made by another thread before
+        // write lock is acquired.
+        int counter = mCounterRadioConfig;
+        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock(0);
+        int ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+
+        // acquire wrlock
+        ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+
+        // make sure the counter value has not changed
+        if (counter == mCounterRadioConfig) {
+            radioConfigService->mRadioConfigResponse = NULL;
+            radioConfigService->mRadioConfigIndication = NULL;
+            radioConfigService->mRadioConfigResponseV1_1 = NULL;
+            radioConfigService->mRadioConfigResponseV1_2 = NULL;
+            radioConfigService->mRadioConfigResponseV1_3 = NULL;
+            radioConfigService->mRadioConfigIndicationV1_2 = NULL;
+            mCounterRadioConfig++;
+        } else {
+            RLOGE("checkReturnStatus_config: not resetting responseFunctions as they likely "
+                  "got updated on another thread");
+        }
+
+        // release wrlock
+        ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+
+        // Reacquire rdlock
+        ret = pthread_rwlock_rdlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+    }
+}
+
+void RadioConfigImpl::checkReturnStatus_config(Return<void>& ret) {
+    ::checkReturnStatus(ret);
+}
+
+int radio_1_6::getSimSlotsStatusResponse(int slotId, int responseType, int serial,
+                                     RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSimSlotsResponse: serial %d", serial);
+#endif
+
+    if (radioConfigService->mRadioConfigResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<SimSlotStatus> simSlotStatus = {};
+
+        if ((response == NULL) || (responseLen % sizeof(RIL_SimSlotStatus_V1_2) != 0)) {
+            RLOGE("getSimSlotsStatusResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            RIL_SimSlotStatus_V1_2 *psimSlotStatus = ((RIL_SimSlotStatus_V1_2 *) response);
+            int num = responseLen / sizeof(RIL_SimSlotStatus_V1_2);
+            simSlotStatus.resize(num);
+            for (int i = 0; i < num; i++) {
+                simSlotStatus[i].cardState = (CardState)psimSlotStatus->base.cardState;
+                simSlotStatus[i].slotState = (SlotState)psimSlotStatus->base.slotState;
+                simSlotStatus[i].atr = convertCharPtrToHidlString(psimSlotStatus->base.atr);
+                simSlotStatus[i].logicalSlotId = psimSlotStatus->base.logicalSlotId;
+                simSlotStatus[i].iccid = convertCharPtrToHidlString(psimSlotStatus->base.iccid);
+                psimSlotStatus += 1;
+            }
+        }
+        Return<void> retStatus = radioConfigService->mRadioConfigResponse->getSimSlotsStatusResponse(
+                responseInfo, simSlotStatus);
+        radioConfigService->checkReturnStatus_config(retStatus);
+    } else {
+        RLOGE("getSimSlotsResponse: radioConfigService->mRadioConfigResponse == NULL");
+    }
+
+    return 0;
+}
+
+int radio_1_6::setSimSlotsMappingResponse(int slotId, int responseType, int serial,
+                                      RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setSimSlotsMappingResponse: serial %d", serial);
+#endif
+
+    if (radioConfigService->mRadioConfigResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioConfigService->mRadioConfigResponse->setSimSlotsMappingResponse(
+                responseInfo);
+        radioConfigService->checkReturnStatus_config(retStatus);
+    } else {
+        RLOGE("setSimSlotsMappingResponse: radioConfigService->mRadioConfigResponse == NULL");
+    }
+
+    return 0;
+}
+
+int radio_1_6::getPhoneCapabilityResponse(int slotId, int responseType, int serial,
+                                      RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getPhoneCapabilityResponse: serial %d", serial);
+#endif
+
+    if (radioConfigService->mRadioConfigResponseV1_1 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        V1_1::PhoneCapability phoneCapability = {};
+        if ((response == NULL) || (responseLen % sizeof(RIL_PhoneCapability) != 0)) {
+            RLOGE("getPhoneCapabilityResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            RIL_PhoneCapability *pCapability = (RIL_PhoneCapability *)response;
+            phoneCapability.maxActiveData = pCapability->maxActiveData;
+            phoneCapability.maxActiveInternetData = pCapability->maxActiveInternetData;
+            phoneCapability.isInternetLingeringSupported = pCapability->isInternetLingeringSupported;
+            phoneCapability.logicalModemList.resize(SIM_COUNT);
+            for (int i = 0 ; i < SIM_COUNT; i++) {
+                RIL_ModemInfo logicalModemInfo = pCapability->logicalModemList[i];
+                phoneCapability.logicalModemList[i].modemId = logicalModemInfo.modemId;
+            }
+        }
+        Return<void> retStatus = radioConfigService->mRadioConfigResponseV1_1->getPhoneCapabilityResponse(
+                responseInfo, phoneCapability);
+        radioConfigService->checkReturnStatus_config(retStatus);
+    } else {
+        RLOGE("getPhoneCapabilityResponse: radioConfigService->mRadioConfigResponseV1_1 == NULL");
+    }
+
+    return 0;
+}
+
+int radio_1_6::setPreferredDataModemResponse(int slotId, int responseType, int serial,
+                                         RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setPreferredDataModemResponse: serial %d", serial);
+#endif
+
+    if (radioConfigService->mRadioConfigResponseV1_1 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioConfigService->mRadioConfigResponseV1_1->setPreferredDataModemResponse(
+                responseInfo);
+        radioConfigService->checkReturnStatus_config(retStatus);
+    } else {
+        RLOGE("setPreferredDataModemResponse: radioConfigService->mRadioConfigResponseV1_1 == NULL");
+    }
+
+    return 0;
+}
+
+int radio_1_6::setModemsConfigResponse(int slotId, int responseType, int serial,
+                                   RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setModemsConfigResponse: serial %d", serial);
+#endif
+
+    if (radioConfigService->mRadioConfigResponseV1_1 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioConfigService->mRadioConfigResponseV1_1->setModemsConfigResponse(
+                responseInfo);
+        radioConfigService->checkReturnStatus_config(retStatus);
+    } else {
+        RLOGE("setModemsConfigResponse: radioConfigService->mRadioConfigResponseV1_1 == NULL");
+    }
+
+    return 0;
+}
+
+int radio_1_6::getModemsConfigResponse(int slotId, int responseType, int serial,
+                                   RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getModemsConfigResponse: serial %d", serial);
+#endif
+
+    if (radioConfigService->mRadioConfigResponseV1_1 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        V1_1::ModemsConfig mdCfg = {};
+        RIL_ModemConfig *pMdCfg = (RIL_ModemConfig *)response;
+        if ((response == NULL) || (responseLen != sizeof(RIL_ModemConfig))) {
+            RLOGE("getModemsConfigResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            mdCfg.numOfLiveModems = pMdCfg->numOfLiveModems;
+        }
+        Return<void> retStatus = radioConfigService->mRadioConfigResponseV1_1->getModemsConfigResponse(
+                responseInfo, mdCfg);
+        radioConfigService->checkReturnStatus_config(retStatus);
+    } else {
+        RLOGE("getModemsConfigResponse: radioConfigService->mRadioConfigResponseV1_1 == NULL");
+    }
+
+    return 0;
+}
+
+int radio_1_6::getHalDeviceCapabilitiesResponse(int slotId, int responseType, int serial,
+                                   RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getHalDeviceCapabilitiesResponse: serial %d", serial);
+#endif
+
+    if (radioConfigService->mRadioConfigResponseV1_3 != NULL) {
+        ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo = {};
+        populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+        bool modemReducedFeatureSet1 = false;
+        if (response == NULL || responseLen != sizeof(bool)) {
+            RLOGE("getHalDeviceCapabilitiesResponse Invalid response.");
+        } else {
+            modemReducedFeatureSet1 = (*((bool *) response));
+        }
+
+        Return<void> retStatus = radioConfigService->mRadioConfigResponseV1_3->getHalDeviceCapabilitiesResponse(
+                responseInfo, modemReducedFeatureSet1);
+        radioConfigService->checkReturnStatus_config(retStatus);
+    } else {
+        RLOGE("getHalDeviceCapabilitiesResponse: radioConfigService->getHalDeviceCapabilities == NULL");
+    }
+
+    return 0;
+}
+
+int radio_1_6::simSlotsStatusChanged(int slotId, int indicationType, int token, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+    if (radioConfigService != NULL &&
+        (radioConfigService->mRadioConfigIndication != NULL ||
+         radioConfigService->mRadioConfigIndicationV1_2 != NULL)) {
+        if ((response == NULL) || (responseLen % sizeof(RIL_SimSlotStatus_V1_2) != 0)) {
+            RLOGE("simSlotsStatusChanged: invalid response");
+            return 0;
+        }
+
+        RIL_SimSlotStatus_V1_2 *psimSlotStatus = ((RIL_SimSlotStatus_V1_2 *)response);
+        int num = responseLen / sizeof(RIL_SimSlotStatus_V1_2);
+        if (radioConfigService->mRadioConfigIndication != NULL) {
+            hidl_vec<SimSlotStatus> simSlotStatus = {};
+            simSlotStatus.resize(num);
+            for (int i = 0; i < num; i++) {
+                simSlotStatus[i].cardState = (CardState) psimSlotStatus->base.cardState;
+                simSlotStatus[i].slotState = (SlotState) psimSlotStatus->base.slotState;
+                simSlotStatus[i].atr = convertCharPtrToHidlString(psimSlotStatus->base.atr);
+                simSlotStatus[i].logicalSlotId = psimSlotStatus->base.logicalSlotId;
+                simSlotStatus[i].iccid = convertCharPtrToHidlString(psimSlotStatus->base.iccid);
+#if VDBG
+                RLOGD("simSlotsStatusChanged: cardState %d slotState %d", simSlotStatus[i].cardState,
+                        simSlotStatus[i].slotState);
+#endif
+                psimSlotStatus += 1;
+            }
+
+            Return<void> retStatus = radioConfigService->mRadioConfigIndication->simSlotsStatusChanged(
+                    convertIntToRadioIndicationType(indicationType), simSlotStatus);
+            radioConfigService->checkReturnStatus_config(retStatus);
+        } else if (radioConfigService->mRadioConfigIndicationV1_2) {
+            hidl_vec<V1_2::SimSlotStatus> simSlotStatus;
+            simSlotStatus.resize(num);
+            for (int i = 0; i < num; i++) {
+                simSlotStatus[i].base.cardState = (CardState)(psimSlotStatus->base.cardState);
+                simSlotStatus[i].base.slotState = (SlotState) psimSlotStatus->base.slotState;
+                simSlotStatus[i].base.atr = convertCharPtrToHidlString(psimSlotStatus->base.atr);
+                simSlotStatus[i].base.logicalSlotId = psimSlotStatus->base.logicalSlotId;
+                simSlotStatus[i].base.iccid = convertCharPtrToHidlString(psimSlotStatus->base.iccid);
+                simSlotStatus[i].eid = convertCharPtrToHidlString(psimSlotStatus->eid);
+                psimSlotStatus += 1;
+#if VDBG
+            RLOGD("simSlotsStatusChanged_1_2: cardState %d slotState %d",
+                    simSlotStatus[i].base.cardState, simSlotStatus[i].base.slotState);
+#endif
+            }
+
+            Return<void> retStatus = radioConfigService->mRadioConfigIndicationV1_2->simSlotsStatusChanged_1_2(
+                    convertIntToRadioIndicationType(indicationType), simSlotStatus);
+            radioConfigService->checkReturnStatus_config(retStatus);
+        }
+    } else {
+        RLOGE("simSlotsStatusChanged: radioService->mRadioIndication == NULL");
+    }
+
+    return 0;
+}
diff --git a/guest/hals/ril/reference-libril/ril_config_commands.h b/guest/hals/ril/reference-libril/ril_config_commands.h
new file mode 100644
index 0000000..9606390
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_config_commands.h
@@ -0,0 +1,24 @@
+/*
+**
+** Copyright 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.
+*/
+    {0, NULL},                   // none
+    {RIL_REQUEST_CONFIG_GET_SLOT_STATUS, radio_1_6::getSimSlotsStatusResponse},
+    {RIL_REQUEST_CONFIG_SET_SLOT_MAPPING, radio_1_6::setSimSlotsMappingResponse},
+    {RIL_REQUEST_CONFIG_GET_PHONE_CAPABILITY, radio_1_6::getPhoneCapabilityResponse},
+    {RIL_REQUEST_CONFIG_SET_PREFER_DATA_MODEM, radio_1_6::setPreferredDataModemResponse},
+    {RIL_REQUEST_CONFIG_SET_MODEM_CONFIG, radio_1_6::setModemsConfigResponse},
+    {RIL_REQUEST_CONFIG_GET_MODEM_CONFIG, radio_1_6::getModemsConfigResponse},
+    {RIL_REQUEST_CONFIG_GET_HAL_DEVICE_CAPABILITIES, radio_1_6::getHalDeviceCapabilitiesResponse},
diff --git a/guest/hals/ril/reference-libril/ril_config_unsol_commands.h b/guest/hals/ril/reference-libril/ril_config_unsol_commands.h
new file mode 100644
index 0000000..1aee12f
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_config_unsol_commands.h
@@ -0,0 +1,17 @@
+/*
+**
+** Copyright 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.
+*/
+    {RIL_UNSOL_CONFIG_ICC_SLOT_STATUS, radio_1_6::simSlotsStatusChanged, WAKE_PARTIAL},
diff --git a/guest/hals/ril/libril/ril_event.cpp b/guest/hals/ril/reference-libril/ril_event.cpp
similarity index 100%
rename from guest/hals/ril/libril/ril_event.cpp
rename to guest/hals/ril/reference-libril/ril_event.cpp
diff --git a/guest/hals/ril/reference-libril/ril_event.h b/guest/hals/ril/reference-libril/ril_event.h
new file mode 100644
index 0000000..7ba231b
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_event.h
@@ -0,0 +1,52 @@
+/* //device/libs/telephony/ril_event.h
+**
+** Copyright 2008, 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.
+*/
+
+// Max number of fd's we watch at any one time.  Increase if necessary.
+#define MAX_FD_EVENTS 8
+
+typedef void (*ril_event_cb)(int fd, short events, void *userdata);
+
+struct ril_event {
+    struct ril_event *next;
+    struct ril_event *prev;
+
+    int fd;
+    int index;
+    bool persist;
+    struct timeval timeout;
+    ril_event_cb func;
+    void *param;
+};
+
+// Initialize internal data structs
+void ril_event_init();
+
+// Initialize an event
+void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);
+
+// Add event to watch list
+void ril_event_add(struct ril_event * ev);
+
+// Add timer event
+void ril_timer_add(struct ril_event * ev, struct timeval * tv);
+
+// Remove event from watch list
+void ril_event_del(struct ril_event * ev);
+
+// Event loop
+void ril_event_loop();
+
diff --git a/guest/hals/ril/reference-libril/ril_ex.h b/guest/hals/ril/reference-libril/ril_ex.h
new file mode 100644
index 0000000..bda7127
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_ex.h
@@ -0,0 +1,49 @@
+/*
+* Copyright (C) 2014 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.
+*/
+
+#ifndef RIL_EX_H_INCLUDED
+#define RIL_EX_H_INCLUDED
+
+#include <guest/hals/ril/reference-libril/ril.h>
+#include <telephony/record_stream.h>
+
+#define NUM_ELEMS_SOCKET(a)     (sizeof (a) / sizeof (a)[0])
+
+struct ril_event;
+
+void rilEventAddWakeup_helper(struct ril_event *ev);
+int blockingWrite_helper(int fd, void* data, size_t len);
+
+enum SocketWakeType {DONT_WAKE, WAKE_PARTIAL};
+
+typedef enum {
+    RIL_TELEPHONY_SOCKET,
+    RIL_SAP_SOCKET
+} RIL_SOCKET_TYPE;
+
+typedef struct SocketListenParam {
+    RIL_SOCKET_ID socket_id;
+    int fdListen;
+    int fdCommand;
+    const char* processName;
+    struct ril_event* commands_event;
+    struct ril_event* listen_event;
+    void (*processCommandsCallback)(int fd, short flags, void *param);
+    RecordStream *p_rs;
+    RIL_SOCKET_TYPE type;
+} SocketListenParam;
+
+#endif
diff --git a/guest/hals/ril/reference-libril/ril_internal.h b/guest/hals/ril/reference-libril/ril_internal.h
new file mode 100644
index 0000000..350791b
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_internal.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef ANDROID_RIL_INTERNAL_H
+#define ANDROID_RIL_INTERNAL_H
+
+namespace android {
+
+#define RIL_SERVICE_NAME_BASE "slot"
+#define RIL1_SERVICE_NAME "slot1"
+#define RIL2_SERVICE_NAME "slot2"
+#define RIL3_SERVICE_NAME "slot3"
+#define RIL4_SERVICE_NAME "slot4"
+
+/* Constants for response types */
+#define RESPONSE_SOLICITED 0
+#define RESPONSE_UNSOLICITED 1
+#define RESPONSE_SOLICITED_ACK 2
+#define RESPONSE_SOLICITED_ACK_EXP 3
+#define RESPONSE_UNSOLICITED_ACK_EXP 4
+
+// Enable verbose logging
+#define VDBG 0
+
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+// Enable RILC log
+#define RILC_LOG 0
+
+#if RILC_LOG
+    #define startRequest           sprintf(printBuf, "(")
+    #define closeRequest           sprintf(printBuf, "%s)", printBuf)
+    #define printRequest(token, req)           \
+            RLOGD("[%04d]> %s %s", token, requestToString(req), printBuf)
+
+    #define startResponse           sprintf(printBuf, "%s {", printBuf)
+    #define closeResponse           sprintf(printBuf, "%s}", printBuf)
+    #define printResponse           RLOGD("%s", printBuf)
+
+    #define clearPrintBuf           printBuf[0] = 0
+    #define removeLastChar          printBuf[strlen(printBuf)-1] = 0
+    #define appendPrintBuf(x...)    snprintf(printBuf, PRINTBUF_SIZE, x)
+#else
+    #define startRequest
+    #define closeRequest
+    #define printRequest(token, req)
+    #define startResponse
+    #define closeResponse
+    #define printResponse
+    #define clearPrintBuf
+    #define removeLastChar
+    #define appendPrintBuf(x...)
+#endif
+
+typedef struct CommandInfo CommandInfo;
+
+extern "C" const char * requestToString(int request);
+
+typedef struct RequestInfo {
+    int32_t token;      //this is not RIL_Token
+    CommandInfo *pCI;
+    struct RequestInfo *p_next;
+    char cancelled;
+    char local;         // responses to local commands do not go back to command process
+    RIL_SOCKET_ID socket_id;
+    int wasAckSent;    // Indicates whether an ack was sent earlier
+} RequestInfo;
+
+typedef struct CommandInfo {
+    int requestNumber;
+    int(*responseFunction) (int slotId, int responseType, int token,
+            RIL_Errno e, void *response, size_t responselen);
+} CommandInfo;
+
+RequestInfo * addRequestToList(int serial, int slotId, int request);
+
+char * RIL_getServiceName();
+
+void releaseWakeLock();
+
+void onNewCommandConnect(RIL_SOCKET_ID socket_id);
+
+}   // namespace android
+
+#endif //ANDROID_RIL_INTERNAL_H
diff --git a/guest/hals/ril/reference-libril/ril_service.cpp b/guest/hals/ril/reference-libril/ril_service.cpp
new file mode 100644
index 0000000..0d18ce8
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_service.cpp
@@ -0,0 +1,12654 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#define LOG_TAG "RILC"
+
+#include <android/hardware/radio/1.6/IRadio.h>
+#include <android/hardware/radio/1.6/IRadioIndication.h>
+#include <android/hardware/radio/1.6/IRadioResponse.h>
+#include <android/hardware/radio/1.6/types.h>
+
+#include <android/hardware/radio/deprecated/1.0/IOemHook.h>
+
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
+#include <guest/hals/ril/reference-libril/ril.h>
+#include <telephony/ril_mnc.h>
+#include <guest/hals/ril/reference-libril/ril_service.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/SystemClock.h>
+#include <inttypes.h>
+
+#define INVALID_HEX_CHAR 16
+
+using namespace android::hardware::radio;
+using namespace android::hardware::radio::V1_0;
+using namespace android::hardware::radio::deprecated::V1_0;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_array;
+using ::android::hardware::Void;
+using android::CommandInfo;
+using android::RequestInfo;
+using android::requestToString;
+using android::sp;
+
+using RegStateResultV1_6 = android::hardware::radio::V1_6::RegStateResult;
+using RegStateResultV1_5 = android::hardware::radio::V1_5::RegStateResult;
+using PhysicalChannelConfigV1_4 =
+    android::hardware::radio::V1_4::PhysicalChannelConfig;
+using RadioTechnologyV1_4 = android::hardware::radio::V1_4::RadioTechnology;
+
+#define BOOL_TO_INT(x) (x ? 1 : 0)
+#define ATOI_NULL_HANDLED(x) (x ? atoi(x) : -1)
+#define ATOI_NULL_HANDLED_DEF(x, defaultVal) (x ? atoi(x) : defaultVal)
+
+#if defined(ANDROID_MULTI_SIM)
+#define CALL_ONREQUEST(a, b, c, d, e) \
+        s_vendorFunctions->onRequest((a), (b), (c), (d), ((RIL_SOCKET_ID)(e)))
+#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest((RIL_SOCKET_ID)(a))
+#else
+#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), (c), (d))
+#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest()
+#endif
+
+#ifdef OEM_HOOK_DISABLED
+constexpr bool kOemHookEnabled = false;
+#else
+constexpr bool kOemHookEnabled = true;
+#endif
+
+RIL_RadioFunctions *s_vendorFunctions = NULL;
+static CommandInfo *s_commands;
+
+struct RadioImpl_1_6;
+struct OemHookImpl;
+
+#if (SIM_COUNT >= 2)
+sp<RadioImpl_1_6> radioService[SIM_COUNT];
+sp<OemHookImpl> oemHookService[SIM_COUNT];
+int64_t nitzTimeReceived[SIM_COUNT];
+// counter used for synchronization. It is incremented every time response callbacks are updated.
+volatile int32_t mCounterRadio[SIM_COUNT];
+volatile int32_t mCounterOemHook[SIM_COUNT];
+#else
+sp<RadioImpl_1_6> radioService[1];
+sp<OemHookImpl> oemHookService[1];
+int64_t nitzTimeReceived[1];
+// counter used for synchronization. It is incremented every time response callbacks are updated.
+volatile int32_t mCounterRadio[1];
+volatile int32_t mCounterOemHook[1];
+#endif
+
+static pthread_rwlock_t radioServiceRwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+#if (SIM_COUNT >= 2)
+static pthread_rwlock_t radioServiceRwlock2 = PTHREAD_RWLOCK_INITIALIZER;
+#if (SIM_COUNT >= 3)
+static pthread_rwlock_t radioServiceRwlock3 = PTHREAD_RWLOCK_INITIALIZER;
+#if (SIM_COUNT >= 4)
+static pthread_rwlock_t radioServiceRwlock4 = PTHREAD_RWLOCK_INITIALIZER;
+#endif
+#endif
+#endif
+
+void convertRilHardwareConfigListToHal(void *response, size_t responseLen,
+        hidl_vec<HardwareConfig>& records);
+
+void convertRilRadioCapabilityToHal(void *response, size_t responseLen, RadioCapability& rc);
+
+void convertRilLceDataInfoToHal(void *response, size_t responseLen, LceDataInfo& lce);
+
+void convertRilSignalStrengthToHal(void *response, size_t responseLen,
+        SignalStrength& signalStrength);
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
+        SetupDataCallResult& dcResult);
+
+void convertRilSignalStrengthToHal_1_4(void *response, size_t responseLen,
+        V1_4::SignalStrength& signalStrength);
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
+        ::android::hardware::radio::V1_4::SetupDataCallResult& dcResult);
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v12 *dcResponse,
+        ::android::hardware::radio::V1_5::SetupDataCallResult& dcResult);
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v12 *dcResponse,
+        ::android::hardware::radio::V1_6::SetupDataCallResult& dcResult);
+
+void convertRilDataCallListToHal(void *response, size_t responseLen,
+        hidl_vec<SetupDataCallResult>& dcResultList);
+
+void convertRilCellInfoListToHal(void *response, size_t responseLen, hidl_vec<CellInfo>& records);
+void convertRilCellInfoListToHal_1_2(void *response, size_t responseLen, hidl_vec<V1_2::CellInfo>& records);
+
+void populateResponseInfo(RadioResponseInfo& responseInfo, int serial, int responseType,
+                         RIL_Errno e);
+
+void populateResponseInfo_1_6(
+    ::android::hardware::radio::V1_6::RadioResponseInfo &responseInfo,
+    int serial, int responseType, RIL_Errno e);
+
+struct RadioImpl_1_6 : public V1_6::IRadio {
+    int32_t mSlotId;
+    V1_1::CardPowerState mSimCardPowerState;
+    sp<IRadioResponse> mRadioResponse;
+    sp<IRadioIndication> mRadioIndication;
+    sp<V1_1::IRadioResponse> mRadioResponseV1_1;
+    sp<V1_1::IRadioIndication> mRadioIndicationV1_1;
+    sp<V1_2::IRadioResponse> mRadioResponseV1_2;
+    sp<V1_2::IRadioIndication> mRadioIndicationV1_2;
+    sp<V1_3::IRadioResponse> mRadioResponseV1_3;
+    sp<V1_3::IRadioIndication> mRadioIndicationV1_3;
+    sp<V1_4::IRadioResponse> mRadioResponseV1_4;
+    sp<V1_4::IRadioIndication> mRadioIndicationV1_4;
+    sp<V1_5::IRadioResponse> mRadioResponseV1_5;
+    sp<V1_5::IRadioIndication> mRadioIndicationV1_5;
+    sp<V1_6::IRadioResponse> mRadioResponseV1_6;
+    sp<V1_6::IRadioIndication> mRadioIndicationV1_6;
+
+    Return<void> setResponseFunctions(
+            const ::android::sp<IRadioResponse>& radioResponse,
+            const ::android::sp<IRadioIndication>& radioIndication);
+
+    Return<void> getIccCardStatus(int32_t serial);
+
+    Return<void> supplyIccPinForApp(int32_t serial, const hidl_string& pin,
+            const hidl_string& aid);
+
+    Return<void> supplyIccPukForApp(int32_t serial, const hidl_string& puk,
+            const hidl_string& pin, const hidl_string& aid);
+
+    Return<void> supplyIccPin2ForApp(int32_t serial,
+            const hidl_string& pin2,
+            const hidl_string& aid);
+
+    Return<void> supplyIccPuk2ForApp(int32_t serial, const hidl_string& puk2,
+            const hidl_string& pin2, const hidl_string& aid);
+
+    Return<void> changeIccPinForApp(int32_t serial, const hidl_string& oldPin,
+            const hidl_string& newPin, const hidl_string& aid);
+
+    Return<void> changeIccPin2ForApp(int32_t serial, const hidl_string& oldPin2,
+            const hidl_string& newPin2, const hidl_string& aid);
+
+    Return<void> supplyNetworkDepersonalization(int32_t serial, const hidl_string& netPin);
+
+    Return<void> getCurrentCalls(int32_t serial);
+
+    Return<void> getCurrentCalls_1_6(int32_t serial);
+
+    Return<void> dial(int32_t serial, const Dial& dialInfo);
+
+    Return<void> getImsiForApp(int32_t serial,
+            const ::android::hardware::hidl_string& aid);
+
+    Return<void> hangup(int32_t serial, int32_t gsmIndex);
+
+    Return<void> hangupWaitingOrBackground(int32_t serial);
+
+    Return<void> hangupForegroundResumeBackground(int32_t serial);
+
+    Return<void> switchWaitingOrHoldingAndActive(int32_t serial);
+
+    Return<void> conference(int32_t serial);
+
+    Return<void> rejectCall(int32_t serial);
+
+    Return<void> getLastCallFailCause(int32_t serial);
+
+    Return<void> getSignalStrength(int32_t serial);
+
+    Return<void> getSignalStrength_1_6(int32_t serial);
+
+    Return<void> getVoiceRegistrationState(int32_t serial);
+
+    Return<void> getDataRegistrationState(int32_t serial);
+
+    Return<void> getOperator(int32_t serial);
+
+    Return<void> setRadioPower(int32_t serial, bool on);
+
+    Return<void> sendDtmf(int32_t serial,
+            const ::android::hardware::hidl_string& s);
+
+    Return<void> sendSms(int32_t serial, const GsmSmsMessage& message);
+
+    Return<void> sendSMSExpectMore(int32_t serial, const GsmSmsMessage& message);
+
+    Return<void> setupDataCall(int32_t serial,
+            RadioTechnology radioTechnology,
+            const DataProfileInfo& profileInfo,
+            bool modemCognitive,
+            bool roamingAllowed,
+            bool isRoaming);
+
+    Return<void> iccIOForApp(int32_t serial,
+            const IccIo& iccIo);
+
+    Return<void> sendUssd(int32_t serial,
+            const ::android::hardware::hidl_string& ussd);
+
+    Return<void> cancelPendingUssd(int32_t serial);
+
+    Return<void> getClir(int32_t serial);
+
+    Return<void> setClir(int32_t serial, int32_t status);
+
+    Return<void> getCallForwardStatus(int32_t serial,
+            const CallForwardInfo& callInfo);
+
+    Return<void> setCallForward(int32_t serial,
+            const CallForwardInfo& callInfo);
+
+    Return<void> getCallWaiting(int32_t serial, int32_t serviceClass);
+
+    Return<void> setCallWaiting(int32_t serial, bool enable, int32_t serviceClass);
+
+    Return<void> acknowledgeLastIncomingGsmSms(int32_t serial,
+            bool success, SmsAcknowledgeFailCause cause);
+
+    Return<void> acceptCall(int32_t serial);
+
+    Return<void> deactivateDataCall(int32_t serial,
+            int32_t cid, bool reasonRadioShutDown);
+
+    Return<void> getFacilityLockForApp(int32_t serial,
+            const ::android::hardware::hidl_string& facility,
+            const ::android::hardware::hidl_string& password,
+            int32_t serviceClass,
+            const ::android::hardware::hidl_string& appId);
+
+    Return<void> setFacilityLockForApp(int32_t serial,
+            const ::android::hardware::hidl_string& facility,
+            bool lockState,
+            const ::android::hardware::hidl_string& password,
+            int32_t serviceClass,
+            const ::android::hardware::hidl_string& appId);
+
+    Return<void> setBarringPassword(int32_t serial,
+            const ::android::hardware::hidl_string& facility,
+            const ::android::hardware::hidl_string& oldPassword,
+            const ::android::hardware::hidl_string& newPassword);
+
+    Return<void> getNetworkSelectionMode(int32_t serial);
+
+    Return<void> setNetworkSelectionModeAutomatic(int32_t serial);
+
+    Return<void> setNetworkSelectionModeManual(int32_t serial,
+            const ::android::hardware::hidl_string& operatorNumeric);
+
+    Return<void> getAvailableNetworks(int32_t serial);
+
+    Return<void> startNetworkScan(int32_t serial, const V1_1::NetworkScanRequest& request);
+
+    Return<void> stopNetworkScan(int32_t serial);
+
+    Return<void> startDtmf(int32_t serial,
+            const ::android::hardware::hidl_string& s);
+
+    Return<void> stopDtmf(int32_t serial);
+
+    Return<void> getBasebandVersion(int32_t serial);
+
+    Return<void> separateConnection(int32_t serial, int32_t gsmIndex);
+
+    Return<void> setMute(int32_t serial, bool enable);
+
+    Return<void> getMute(int32_t serial);
+
+    Return<void> getClip(int32_t serial);
+
+    Return<void> getDataCallList(int32_t serial);
+
+    Return<void> setSuppServiceNotifications(int32_t serial, bool enable);
+
+    Return<void> writeSmsToSim(int32_t serial,
+            const SmsWriteArgs& smsWriteArgs);
+
+    Return<void> deleteSmsOnSim(int32_t serial, int32_t index);
+
+    Return<void> setBandMode(int32_t serial, RadioBandMode mode);
+
+    Return<void> getAvailableBandModes(int32_t serial);
+
+    Return<void> sendEnvelope(int32_t serial,
+            const ::android::hardware::hidl_string& command);
+
+    Return<void> sendTerminalResponseToSim(int32_t serial,
+            const ::android::hardware::hidl_string& commandResponse);
+
+    Return<void> handleStkCallSetupRequestFromSim(int32_t serial, bool accept);
+
+    Return<void> explicitCallTransfer(int32_t serial);
+
+    Return<void> setPreferredNetworkType(int32_t serial, PreferredNetworkType nwType);
+
+    Return<void> getPreferredNetworkType(int32_t serial);
+
+    Return<void> getNeighboringCids(int32_t serial);
+
+    Return<void> setLocationUpdates(int32_t serial, bool enable);
+
+    Return<void> setCdmaSubscriptionSource(int32_t serial,
+            CdmaSubscriptionSource cdmaSub);
+
+    Return<void> setCdmaRoamingPreference(int32_t serial, CdmaRoamingType type);
+
+    Return<void> getCdmaRoamingPreference(int32_t serial);
+
+    Return<void> setTTYMode(int32_t serial, TtyMode mode);
+
+    Return<void> getTTYMode(int32_t serial);
+
+    Return<void> setPreferredVoicePrivacy(int32_t serial, bool enable);
+
+    Return<void> getPreferredVoicePrivacy(int32_t serial);
+
+    Return<void> sendCDMAFeatureCode(int32_t serial,
+            const ::android::hardware::hidl_string& featureCode);
+
+    Return<void> sendBurstDtmf(int32_t serial,
+            const ::android::hardware::hidl_string& dtmf,
+            int32_t on,
+            int32_t off);
+
+    Return<void> sendCdmaSms(int32_t serial, const CdmaSmsMessage& sms);
+
+    Return<void> acknowledgeLastIncomingCdmaSms(int32_t serial,
+            const CdmaSmsAck& smsAck);
+
+    Return<void> getGsmBroadcastConfig(int32_t serial);
+
+    Return<void> setGsmBroadcastConfig(int32_t serial,
+            const hidl_vec<GsmBroadcastSmsConfigInfo>& configInfo);
+
+    Return<void> setGsmBroadcastActivation(int32_t serial, bool activate);
+
+    Return<void> getCdmaBroadcastConfig(int32_t serial);
+
+    Return<void> setCdmaBroadcastConfig(int32_t serial,
+            const hidl_vec<CdmaBroadcastSmsConfigInfo>& configInfo);
+
+    Return<void> setCdmaBroadcastActivation(int32_t serial, bool activate);
+
+    Return<void> getCDMASubscription(int32_t serial);
+
+    Return<void> writeSmsToRuim(int32_t serial, const CdmaSmsWriteArgs& cdmaSms);
+
+    Return<void> deleteSmsOnRuim(int32_t serial, int32_t index);
+
+    Return<void> getDeviceIdentity(int32_t serial);
+
+    Return<void> exitEmergencyCallbackMode(int32_t serial);
+
+    Return<void> getSmscAddress(int32_t serial);
+
+    Return<void> setSmscAddress(int32_t serial,
+            const ::android::hardware::hidl_string& smsc);
+
+    Return<void> reportSmsMemoryStatus(int32_t serial, bool available);
+
+    Return<void> reportStkServiceIsRunning(int32_t serial);
+
+    Return<void> getCdmaSubscriptionSource(int32_t serial);
+
+    Return<void> requestIsimAuthentication(int32_t serial,
+            const ::android::hardware::hidl_string& challenge);
+
+    Return<void> acknowledgeIncomingGsmSmsWithPdu(int32_t serial,
+            bool success,
+            const ::android::hardware::hidl_string& ackPdu);
+
+    Return<void> sendEnvelopeWithStatus(int32_t serial,
+            const ::android::hardware::hidl_string& contents);
+
+    Return<void> getVoiceRadioTechnology(int32_t serial);
+
+    Return<void> getCellInfoList(int32_t serial);
+
+    Return<void> getCellInfoList_1_6(int32_t serial);
+
+    Return<void> setCellInfoListRate(int32_t serial, int32_t rate);
+
+    Return<void> setInitialAttachApn(int32_t serial, const DataProfileInfo& dataProfileInfo,
+            bool modemCognitive, bool isRoaming);
+
+    Return<void> getImsRegistrationState(int32_t serial);
+
+    Return<void> sendImsSms(int32_t serial, const ImsSmsMessage& message);
+
+    Return<void> iccTransmitApduBasicChannel(int32_t serial, const SimApdu& message);
+
+    Return<void> iccOpenLogicalChannel(int32_t serial,
+            const ::android::hardware::hidl_string& aid, int32_t p2);
+
+    Return<void> iccCloseLogicalChannel(int32_t serial, int32_t channelId);
+
+    Return<void> iccTransmitApduLogicalChannel(int32_t serial, const SimApdu& message);
+
+    Return<void> nvReadItem(int32_t serial, NvItem itemId);
+
+    Return<void> nvWriteItem(int32_t serial, const NvWriteItem& item);
+
+    Return<void> nvWriteCdmaPrl(int32_t serial,
+            const ::android::hardware::hidl_vec<uint8_t>& prl);
+
+    Return<void> nvResetConfig(int32_t serial, ResetNvType resetType);
+
+    Return<void> setUiccSubscription(int32_t serial, const SelectUiccSub& uiccSub);
+
+    Return<void> setDataAllowed(int32_t serial, bool allow);
+
+    Return<void> getHardwareConfig(int32_t serial);
+
+    Return<void> requestIccSimAuthentication(int32_t serial,
+            int32_t authContext,
+            const ::android::hardware::hidl_string& authData,
+            const ::android::hardware::hidl_string& aid);
+
+    Return<void> setDataProfile(int32_t serial,
+            const ::android::hardware::hidl_vec<DataProfileInfo>& profiles, bool isRoaming);
+
+    Return<void> requestShutdown(int32_t serial);
+
+    Return<void> getRadioCapability(int32_t serial);
+
+    Return<void> setRadioCapability(int32_t serial, const RadioCapability& rc);
+
+    Return<void> startLceService(int32_t serial, int32_t reportInterval, bool pullMode);
+
+    Return<void> stopLceService(int32_t serial);
+
+    Return<void> pullLceData(int32_t serial);
+
+    Return<void> getModemActivityInfo(int32_t serial);
+
+    Return<void> setAllowedCarriers(int32_t serial,
+            bool allAllowed,
+            const CarrierRestrictions& carriers);
+
+    Return<void> getAllowedCarriers(int32_t serial);
+
+    Return<void> sendDeviceState(int32_t serial, DeviceStateType deviceStateType, bool state);
+
+    Return<void> setIndicationFilter(int32_t serial, int32_t indicationFilter);
+
+    Return<void> startKeepalive(int32_t serial, const V1_1::KeepaliveRequest& keepalive);
+
+    Return<void> stopKeepalive(int32_t serial, int32_t sessionHandle);
+
+    Return<void> setSimCardPower(int32_t serial, bool powerUp);
+    Return<void> setSimCardPower_1_1(int32_t serial,
+            const V1_1::CardPowerState state);
+    Return<void> setSimCardPower_1_6(int32_t serial,
+            const V1_1::CardPowerState state);
+
+    Return<void> responseAcknowledgement();
+
+    Return<void> setCarrierInfoForImsiEncryption(int32_t serial,
+            const V1_1::ImsiEncryptionInfo& message);
+
+    void checkReturnStatus(Return<void>& ret);
+
+    // Methods from ::android::hardware::radio::V1_2::IRadio follow.
+    Return<void> startNetworkScan_1_2(int32_t serial,
+            const ::android::hardware::radio::V1_2::NetworkScanRequest& request);
+    Return<void> setIndicationFilter_1_2(int32_t serial,
+            hidl_bitfield<::android::hardware::radio::V1_2::IndicationFilter> indicationFilter);
+    Return<void> setSignalStrengthReportingCriteria(int32_t serial, int32_t hysteresisMs,
+            int32_t hysteresisDb, const hidl_vec<int32_t>& thresholdsDbm,
+            ::android::hardware::radio::V1_2::AccessNetwork accessNetwork);
+    Return<void> setLinkCapacityReportingCriteria(int32_t serial, int32_t hysteresisMs,
+            int32_t hysteresisDlKbps, int32_t hysteresisUlKbps,
+            const hidl_vec<int32_t>& thresholdsDownlinkKbps,
+            const hidl_vec<int32_t>& thresholdsUplinkKbps,
+            ::android::hardware::radio::V1_2::AccessNetwork accessNetwork);
+    Return<void> setupDataCall_1_2(int32_t serial,
+            ::android::hardware::radio::V1_2::AccessNetwork accessNetwork,
+            const ::android::hardware::radio::V1_0::DataProfileInfo& dataProfileInfo,
+            bool modemCognitive, bool roamingAllowed, bool isRoaming,
+            ::android::hardware::radio::V1_2::DataRequestReason reason,
+            const hidl_vec<hidl_string>& addresses, const hidl_vec<hidl_string>& dnses);
+    Return<void> deactivateDataCall_1_2(int32_t serial, int32_t cid,
+            ::android::hardware::radio::V1_2::DataRequestReason reason);
+
+    // Methods from ::android::hardware::radio::V1_3::IRadio follow.
+    Return<void> setSystemSelectionChannels(int32_t serial, bool specifyChannels,
+            const hidl_vec<::android::hardware::radio::V1_1::RadioAccessSpecifier>& specifiers);
+    Return<void> enableModem(int32_t serial, bool on);
+    Return<void> getModemStackStatus(int32_t serial);
+
+    // Methods from ::android::hardware::radio::V1_4::IRadio follow.
+    Return<void> setupDataCall_1_4(int32_t serial,
+            ::android::hardware::radio::V1_4::AccessNetwork accessNetwork,
+            const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo,
+            bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason reason,
+            const hidl_vec<hidl_string>& addresses, const hidl_vec<hidl_string>& dnses);
+    Return<void> setInitialAttachApn_1_4(int32_t serial,
+            const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo);
+    Return<void> setDataProfile_1_4(int32_t serial,
+            const hidl_vec<::android::hardware::radio::V1_4::DataProfileInfo>& profiles);
+    Return<void> emergencyDial(int32_t serial,
+            const ::android::hardware::radio::V1_0::Dial& dialInfo,
+            hidl_bitfield<android::hardware::radio::V1_4::EmergencyServiceCategory> categories,
+            const hidl_vec<hidl_string>& urns,
+            ::android::hardware::radio::V1_4::EmergencyCallRouting routing,
+            bool fromEmergencyDialer, bool isTesting);
+    Return<void> emergencyDial_1_6(int32_t serial,
+            const ::android::hardware::radio::V1_0::Dial& dialInfo,
+            hidl_bitfield<android::hardware::radio::V1_4::EmergencyServiceCategory> categories,
+            const hidl_vec<hidl_string>& urns,
+            ::android::hardware::radio::V1_4::EmergencyCallRouting routing,
+            bool fromEmergencyDialer, bool isTesting);
+    Return<void> startNetworkScan_1_4(int32_t serial,
+            const ::android::hardware::radio::V1_2::NetworkScanRequest& request);
+    Return<void> getPreferredNetworkTypeBitmap(int32_t serial);
+    Return<void> setPreferredNetworkTypeBitmap(
+            int32_t serial, hidl_bitfield<RadioAccessFamily> networkTypeBitmap);
+    Return<void> setAllowedCarriers_1_4(int32_t serial,
+            const ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority& carriers,
+            ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicy);
+    Return<void> getAllowedCarriers_1_4(int32_t serial);
+    Return<void> getSignalStrength_1_4(int32_t serial);
+
+    // Methods from ::android::hardware::radio::V1_5::IRadio follow.
+    Return<void> setSignalStrengthReportingCriteria_1_5(int32_t serial,
+            const ::android::hardware::radio::V1_5::SignalThresholdInfo& signalThresholdInfo,
+            const ::android::hardware::radio::V1_5::AccessNetwork accessNetwork);
+    Return<void> setLinkCapacityReportingCriteria_1_5(int32_t serial, int32_t hysteresisMs,
+            int32_t hysteresisDlKbps, int32_t hysteresisUlKbps,
+            const hidl_vec<int32_t>& thresholdsDownlinkKbps,
+            const hidl_vec<int32_t>& thresholdsUplinkKbps,
+            V1_5::AccessNetwork accessNetwork);
+    Return<void> enableUiccApplications(int32_t serial, bool detach);
+    Return<void> areUiccApplicationsEnabled(int32_t serial);
+    Return<void> setSystemSelectionChannels_1_5(int32_t serial, bool specifyChannels,
+            const hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier>& specifiers);
+    Return<void> startNetworkScan_1_5(int32_t serial,
+            const ::android::hardware::radio::V1_5::NetworkScanRequest& request);
+    Return<void> setupDataCall_1_5(int32_t serial,
+            ::android::hardware::radio::V1_5::AccessNetwork accessNetwork,
+            const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
+            bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason reason,
+            const hidl_vec<::android::hardware::radio::V1_5::LinkAddress>& addresses,
+            const hidl_vec<hidl_string>& dnses);
+    Return<void> setInitialAttachApn_1_5(int32_t serial,
+            const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo);
+    Return<void> setDataProfile_1_5(int32_t serial,
+            const hidl_vec<::android::hardware::radio::V1_5::DataProfileInfo>& profiles);
+    Return<void> setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+            bool preferredForEmergencyCall);
+    Return<void> setIndicationFilter_1_5(int32_t serial,
+            hidl_bitfield<::android::hardware::radio::V1_5::IndicationFilter> indicationFilter);
+    Return<void> getBarringInfo(int32_t serial);
+    Return<void> getVoiceRegistrationState_1_5(int32_t serial);
+    Return<void> getDataRegistrationState_1_5(int32_t serial);
+    Return<void> setNetworkSelectionModeManual_1_5(int32_t serial,
+            const hidl_string& operatorNumeric, V1_5::RadioAccessNetworks ran);
+    Return<void> sendCdmaSmsExpectMore(int32_t serial, const CdmaSmsMessage& sms);
+    Return<void> supplySimDepersonalization(int32_t serial, V1_5::PersoSubstate persoType,
+                                            const hidl_string& controlKey);
+    Return<void> setNrDualConnectivityState(int32_t serial,
+            V1_6::NrDualConnectivityState nrDualConnectivityState);
+    Return<void> isNrDualConnectivityEnabled(int32_t serial);
+
+    // Methods from ::android::hardware::radio::V1_6::IRadio follow.
+    Return<void> getDataCallList_1_6(int32_t serial);
+    Return<void> setupDataCall_1_6(int32_t serial,
+            ::android::hardware::radio::V1_5::AccessNetwork accessNetwork,
+            const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
+            bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason reason,
+            const hidl_vec<::android::hardware::radio::V1_5::LinkAddress>& addresses,
+            const hidl_vec<hidl_string>& dnses,
+            int32_t pduSessionId,
+            const ::android::hardware::radio::V1_6::OptionalSliceInfo& sliceInfo,
+            const ::android::hardware::radio::V1_6::OptionalTrafficDescriptor& trafficDescriptor,
+            bool matchAllRuleAllowed);
+    Return<void> sendSms_1_6(int32_t serial, const GsmSmsMessage& message);
+    Return<void> sendSmsExpectMore_1_6(int32_t serial, const GsmSmsMessage& message);
+    Return<void> sendCdmaSms_1_6(int32_t serial, const CdmaSmsMessage& sms);
+    Return<void> sendCdmaSmsExpectMore_1_6(int32_t serial, const CdmaSmsMessage& sms);
+    Return<void> setRadioPower_1_6(int32_t serial, bool powerOn, bool forEmergencyCall,
+            bool preferredForEmergencyCall);
+    Return<void> allocatePduSessionId(int32_t serial);
+    Return<void> releasePduSessionId(int32_t serial, int32_t id);
+    Return<void> startHandover(int32_t serial, int32_t callId);
+    Return<void> cancelHandover(int32_t serial, int32_t callId);
+    Return<void> setAllowedNetworkTypesBitmap(uint32_t serial,
+            hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily> networkTypeBitmap);
+    Return<void> setDataThrottling(int32_t serial,
+            V1_6::DataThrottlingAction dataThrottlingAction,
+            int64_t completionDurationMillis);
+    Return<void> getSystemSelectionChannels(int32_t serial);
+    Return<void> getVoiceRegistrationState_1_6(int32_t serial);
+    Return<void> getDataRegistrationState_1_6(int32_t serial);
+    Return<void> getAllowedNetworkTypesBitmap(int32_t serial);
+    Return<void> getSlicingConfig(int32_t serial);
+    Return<void> setCarrierInfoForImsiEncryption_1_6(
+            int32_t serial,
+            const ::android::hardware::radio::V1_6::ImsiEncryptionInfo& imsiEncryptionInfo);
+    Return<void> getSimPhonebookRecords(int32_t serial);
+    Return<void> getSimPhonebookCapacity(int32_t serial);
+    Return<void> updateSimPhonebookRecords(
+            int32_t serial,
+            const ::android::hardware::radio::V1_6::PhonebookRecordInfo& recordInfo);
+};
+
+struct OemHookImpl : public IOemHook {
+    int32_t mSlotId;
+    sp<IOemHookResponse> mOemHookResponse;
+    sp<IOemHookIndication> mOemHookIndication;
+
+    Return<void> setResponseFunctions(
+            const ::android::sp<IOemHookResponse>& oemHookResponse,
+            const ::android::sp<IOemHookIndication>& oemHookIndication);
+
+    Return<void> sendRequestRaw(int32_t serial,
+            const ::android::hardware::hidl_vec<uint8_t>& data);
+
+    Return<void> sendRequestStrings(int32_t serial,
+            const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
+};
+
+void memsetAndFreeStrings(int numPointers, ...) {
+    va_list ap;
+    va_start(ap, numPointers);
+    for (int i = 0; i < numPointers; i++) {
+        char *ptr = va_arg(ap, char *);
+        if (ptr) {
+#ifdef MEMSET_FREED
+#define MAX_STRING_LENGTH 4096
+            memset(ptr, 0, strnlen(ptr, MAX_STRING_LENGTH));
+#endif
+            free(ptr);
+        }
+    }
+    va_end(ap);
+}
+
+void sendErrorResponse(RequestInfo *pRI, RIL_Errno err) {
+    pRI->pCI->responseFunction((int) pRI->socket_id,
+            (int) RadioResponseType::SOLICITED, pRI->token, err, NULL, 0);
+}
+
+/**
+ * Copies over src to dest. If memory allocation fails, responseFunction() is called for the
+ * request with error RIL_E_NO_MEMORY. The size() method is used to determine the size of the
+ * destination buffer into which the HIDL string is copied. If there is a discrepancy between
+ * the string length reported by the size() method, and the length of the string returned by
+ * the c_str() method, the function will return false indicating a failure.
+ *
+ * Returns true on success, and false on failure.
+ */
+bool copyHidlStringToRil(char **dest, const hidl_string &src, RequestInfo *pRI, bool allowEmpty) {
+    size_t len = src.size();
+    if (len == 0 && !allowEmpty) {
+        *dest = NULL;
+        return true;
+    }
+    *dest = (char *) calloc(len + 1, sizeof(char));
+    if (*dest == NULL) {
+        RLOGE("Memory allocation failed for request %s", requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+        return false;
+    }
+    if (strlcpy(*dest, src.c_str(), len + 1) >= (len + 1)) {
+        RLOGE("Copy of the HIDL string has been truncated, as "
+              "the string length reported by size() does not "
+              "match the length of string returned by c_str().");
+        free(*dest);
+        *dest = NULL;
+        sendErrorResponse(pRI, RIL_E_INTERNAL_ERR);
+        return false;
+    }
+    return true;
+}
+
+bool copyHidlStringToRil(char **dest, const hidl_string &src, RequestInfo *pRI) {
+    return copyHidlStringToRil(dest, src, pRI, false);
+}
+
+hidl_string convertCharPtrToHidlString(const char *ptr) {
+    hidl_string ret;
+    if (ptr != NULL) {
+        // TODO: replace this with strnlen
+        ret.setToExternal(ptr, strlen(ptr));
+    }
+    return ret;
+}
+
+bool dispatchVoid(int serial, int slotId, int request) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+    CALL_ONREQUEST(request, NULL, 0, pRI, slotId);
+    return true;
+}
+
+bool dispatchString(int serial, int slotId, int request, const char * str) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+
+    char *pString;
+    if (!copyHidlStringToRil(&pString, str, pRI)) {
+        return false;
+    }
+
+    CALL_ONREQUEST(request, pString, sizeof(char *), pRI, slotId);
+
+    memsetAndFreeStrings(1, pString);
+    return true;
+}
+
+bool dispatchStrings(int serial, int slotId, int request, bool allowEmpty, int countStrings, ...) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+
+    char **pStrings;
+    pStrings = (char **)calloc(countStrings, sizeof(char *));
+    if (pStrings == NULL) {
+        RLOGE("Memory allocation failed for request %s", requestToString(request));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+        return false;
+    }
+    va_list ap;
+    va_start(ap, countStrings);
+    for (int i = 0; i < countStrings; i++) {
+        const char* str = va_arg(ap, const char *);
+        if (!copyHidlStringToRil(&pStrings[i], hidl_string(str), pRI, allowEmpty)) {
+            va_end(ap);
+            for (int j = 0; j < i; j++) {
+                memsetAndFreeStrings(1, pStrings[j]);
+            }
+            free(pStrings);
+            return false;
+        }
+    }
+    va_end(ap);
+
+    CALL_ONREQUEST(request, pStrings, countStrings * sizeof(char *), pRI, slotId);
+
+    if (pStrings != NULL) {
+        for (int i = 0 ; i < countStrings ; i++) {
+            memsetAndFreeStrings(1, pStrings[i]);
+        }
+
+#ifdef MEMSET_FREED
+        memset(pStrings, 0, countStrings * sizeof(char *));
+#endif
+        free(pStrings);
+    }
+    return true;
+}
+
+bool dispatchStrings(int serial, int slotId, int request, const hidl_vec<hidl_string>& data) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+
+    int countStrings = data.size();
+    char **pStrings;
+    pStrings = (char **)calloc(countStrings, sizeof(char *));
+    if (pStrings == NULL) {
+        RLOGE("Memory allocation failed for request %s", requestToString(request));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+        return false;
+    }
+
+    for (int i = 0; i < countStrings; i++) {
+        if (!copyHidlStringToRil(&pStrings[i], data[i], pRI)) {
+            for (int j = 0; j < i; j++) {
+                memsetAndFreeStrings(1, pStrings[j]);
+            }
+            free(pStrings);
+            return false;
+        }
+    }
+
+    CALL_ONREQUEST(request, pStrings, countStrings * sizeof(char *), pRI, slotId);
+
+    if (pStrings != NULL) {
+        for (int i = 0 ; i < countStrings ; i++) {
+            memsetAndFreeStrings(1, pStrings[i]);
+        }
+
+#ifdef MEMSET_FREED
+        memset(pStrings, 0, countStrings * sizeof(char *));
+#endif
+        free(pStrings);
+    }
+    return true;
+}
+
+bool dispatchInts(int serial, int slotId, int request, int countInts, ...) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+
+    int *pInts = (int *)calloc(countInts, sizeof(int));
+
+    if (pInts == NULL) {
+        RLOGE("Memory allocation failed for request %s", requestToString(request));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+        return false;
+    }
+    va_list ap;
+    va_start(ap, countInts);
+    for (int i = 0; i < countInts; i++) {
+        pInts[i] = va_arg(ap, int);
+    }
+    va_end(ap);
+
+    CALL_ONREQUEST(request, pInts, countInts * sizeof(int), pRI, slotId);
+
+    if (pInts != NULL) {
+#ifdef MEMSET_FREED
+        memset(pInts, 0, countInts * sizeof(int));
+#endif
+        free(pInts);
+    }
+    return true;
+}
+
+bool dispatchCallForwardStatus(int serial, int slotId, int request,
+                              const CallForwardInfo& callInfo) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+
+    RIL_CallForwardInfo cf;
+    cf.status = (int) callInfo.status;
+    cf.reason = callInfo.reason;
+    cf.serviceClass = callInfo.serviceClass;
+    cf.toa = callInfo.toa;
+    cf.timeSeconds = callInfo.timeSeconds;
+
+    if (!copyHidlStringToRil(&cf.number, callInfo.number, pRI)) {
+        return false;
+    }
+
+    CALL_ONREQUEST(request, &cf, sizeof(cf), pRI, slotId);
+
+    memsetAndFreeStrings(1, cf.number);
+
+    return true;
+}
+
+bool dispatchRaw(int serial, int slotId, int request, const hidl_vec<uint8_t>& rawBytes) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+
+    const uint8_t *uData = rawBytes.data();
+
+    CALL_ONREQUEST(request, (void *) uData, rawBytes.size(), pRI, slotId);
+
+    return true;
+}
+
+bool dispatchIccApdu(int serial, int slotId, int request, const SimApdu& message) {
+    RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
+    if (pRI == NULL) {
+        return false;
+    }
+
+    RIL_SIM_APDU apdu = {};
+
+    apdu.sessionid = message.sessionId;
+    apdu.cla = message.cla;
+    apdu.instruction = message.instruction;
+    apdu.p1 = message.p1;
+    apdu.p2 = message.p2;
+    apdu.p3 = message.p3;
+
+    if (!copyHidlStringToRil(&apdu.data, message.data, pRI)) {
+        return false;
+    }
+
+    CALL_ONREQUEST(request, &apdu, sizeof(apdu), pRI, slotId);
+
+    memsetAndFreeStrings(1, apdu.data);
+
+    return true;
+}
+
+void checkReturnStatus(int32_t slotId, Return<void>& ret, bool isRadioService) {
+    if (ret.isOk() == false) {
+        RLOGE("checkReturnStatus: unable to call response/indication callback");
+        // Remote process hosting the callbacks must be dead. Reset the callback objects;
+        // there's no other recovery to be done here. When the client process is back up, it will
+        // call setResponseFunctions()
+
+        // Caller should already hold rdlock, release that first
+        // note the current counter to avoid overwriting updates made by another thread before
+        // write lock is acquired.
+        int counter = isRadioService ? mCounterRadio[slotId] : mCounterOemHook[slotId];
+        pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock(slotId);
+        int ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+
+        // acquire wrlock
+        ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+
+        // make sure the counter value has not changed
+        if (counter == (isRadioService ? mCounterRadio[slotId] : mCounterOemHook[slotId])) {
+            if (isRadioService) {
+                radioService[slotId]->mRadioResponse = NULL;
+                radioService[slotId]->mRadioIndication = NULL;
+                radioService[slotId]->mRadioResponseV1_2 = NULL;
+                radioService[slotId]->mRadioIndicationV1_2 = NULL;
+                radioService[slotId]->mRadioResponseV1_3 = NULL;
+                radioService[slotId]->mRadioIndicationV1_3 = NULL;
+                radioService[slotId]->mRadioResponseV1_4 = NULL;
+                radioService[slotId]->mRadioIndicationV1_4 = NULL;
+                radioService[slotId]->mRadioResponseV1_5 = NULL;
+                radioService[slotId]->mRadioIndicationV1_5 = NULL;
+                radioService[slotId]->mRadioResponseV1_6 = NULL;
+                radioService[slotId]->mRadioIndicationV1_6 = NULL;
+            } else {
+                oemHookService[slotId]->mOemHookResponse = NULL;
+                oemHookService[slotId]->mOemHookIndication = NULL;
+            }
+            isRadioService ? mCounterRadio[slotId]++ : mCounterOemHook[slotId]++;
+        } else {
+            RLOGE("checkReturnStatus: not resetting responseFunctions as they likely "
+                    "got updated on another thread");
+        }
+
+        // release wrlock
+        ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+
+        // Reacquire rdlock
+        ret = pthread_rwlock_rdlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+    }
+}
+
+void RadioImpl_1_6::checkReturnStatus(Return<void>& ret) {
+    ::checkReturnStatus(mSlotId, ret, true);
+}
+
+Return<void> RadioImpl_1_6::setResponseFunctions(
+        const ::android::sp<IRadioResponse>& radioResponseParam,
+        const ::android::sp<IRadioIndication>& radioIndicationParam) {
+    RLOGD("setResponseFunctions");
+
+    pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock(mSlotId);
+    int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+
+    mRadioResponse = radioResponseParam;
+    mRadioIndication = radioIndicationParam;
+
+   mRadioResponseV1_6 = V1_6::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
+   mRadioIndicationV1_6 = V1_6::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
+   if (mRadioResponseV1_6 == nullptr || mRadioIndicationV1_6 == nullptr) {
+       mRadioResponseV1_6 = nullptr;
+       mRadioIndicationV1_6 = nullptr;
+   }
+
+   mRadioResponseV1_5 = V1_5::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
+   mRadioIndicationV1_5 = V1_5::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
+   if (mRadioResponseV1_5 == nullptr || mRadioIndicationV1_5 == nullptr) {
+       mRadioResponseV1_5 = nullptr;
+       mRadioIndicationV1_5 = nullptr;
+   }
+
+    mRadioResponseV1_4 = V1_4::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
+    mRadioIndicationV1_4 = V1_4::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
+    if (mRadioResponseV1_4 == nullptr || mRadioIndicationV1_4 == nullptr) {
+        mRadioResponseV1_4 = nullptr;
+        mRadioIndicationV1_4 = nullptr;
+    }
+
+    mRadioResponseV1_3 = V1_3::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
+    mRadioIndicationV1_3 = V1_3::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
+    if (mRadioResponseV1_3 == nullptr || mRadioIndicationV1_3 == nullptr) {
+        mRadioResponseV1_3 = nullptr;
+        mRadioIndicationV1_3 = nullptr;
+    }
+
+    mRadioResponseV1_2 = V1_2::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
+    mRadioIndicationV1_2 = V1_2::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
+    if (mRadioResponseV1_2 == nullptr || mRadioIndicationV1_2 == nullptr) {
+        mRadioResponseV1_2 = nullptr;
+        mRadioIndicationV1_2 = nullptr;
+    }
+
+    mRadioResponseV1_1 = V1_1::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
+    mRadioIndicationV1_1 = V1_1::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
+    if (mRadioResponseV1_1 == nullptr || mRadioIndicationV1_1 == nullptr) {
+        mRadioResponseV1_1 = nullptr;
+        mRadioIndicationV1_1 = nullptr;
+    }
+
+    mCounterRadio[mSlotId]++;
+
+    ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+
+    // client is connected. Send initial indications.
+    android::onNewCommandConnect((RIL_SOCKET_ID) mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getIccCardStatus(int32_t serial) {
+#if VDBG
+    RLOGD("getIccCardStatus: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SIM_STATUS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::supplyIccPinForApp(int32_t serial, const hidl_string& pin,
+        const hidl_string& aid) {
+#if VDBG
+    RLOGD("supplyIccPinForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PIN, true,
+            2, pin.c_str(), aid.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::supplyIccPukForApp(int32_t serial, const hidl_string& puk,
+                                           const hidl_string& pin, const hidl_string& aid) {
+#if VDBG
+    RLOGD("supplyIccPukForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PUK, true,
+            3, puk.c_str(), pin.c_str(), aid.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::supplyIccPin2ForApp(int32_t serial, const hidl_string& pin2,
+                                            const hidl_string& aid) {
+#if VDBG
+    RLOGD("supplyIccPin2ForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PIN2, true,
+            2, pin2.c_str(), aid.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::supplyIccPuk2ForApp(int32_t serial, const hidl_string& puk2,
+                                            const hidl_string& pin2, const hidl_string& aid) {
+#if VDBG
+    RLOGD("supplyIccPuk2ForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_PUK2, true,
+            3, puk2.c_str(), pin2.c_str(), aid.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::changeIccPinForApp(int32_t serial, const hidl_string& oldPin,
+                                           const hidl_string& newPin, const hidl_string& aid) {
+#if VDBG
+    RLOGD("changeIccPinForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_CHANGE_SIM_PIN, true,
+            3, oldPin.c_str(), newPin.c_str(), aid.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::changeIccPin2ForApp(int32_t serial, const hidl_string& oldPin2,
+                                            const hidl_string& newPin2, const hidl_string& aid) {
+#if VDBG
+    RLOGD("changeIccPin2ForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_CHANGE_SIM_PIN2, true,
+            3, oldPin2.c_str(), newPin2.c_str(), aid.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::supplyNetworkDepersonalization(int32_t serial,
+                                                       const hidl_string& netPin) {
+#if VDBG
+    RLOGD("supplyNetworkDepersonalization: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, true,
+            1, netPin.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCurrentCalls(int32_t serial) {
+#if VDBG
+    RLOGD("getCurrentCalls: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CURRENT_CALLS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCurrentCalls_1_6(int32_t serial) {
+#if VDBG
+    RLOGD("getCurrentCalls_1_6: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CURRENT_CALLS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::dial(int32_t serial, const Dial& dialInfo) {
+#if VDBG
+    RLOGD("dial: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_DIAL);
+    if (pRI == NULL) {
+        return Void();
+    }
+    RIL_Dial dial = {};
+    RIL_UUS_Info uusInfo = {};
+    int32_t sizeOfDial = sizeof(dial);
+
+    if (!copyHidlStringToRil(&dial.address, dialInfo.address, pRI)) {
+        return Void();
+    }
+    dial.clir = (int) dialInfo.clir;
+
+    if (dialInfo.uusInfo.size() != 0) {
+        uusInfo.uusType = (RIL_UUS_Type) dialInfo.uusInfo[0].uusType;
+        uusInfo.uusDcs = (RIL_UUS_DCS) dialInfo.uusInfo[0].uusDcs;
+
+        if (dialInfo.uusInfo[0].uusData.size() == 0) {
+            uusInfo.uusData = NULL;
+            uusInfo.uusLength = 0;
+        } else {
+            if (!copyHidlStringToRil(&uusInfo.uusData, dialInfo.uusInfo[0].uusData, pRI)) {
+                memsetAndFreeStrings(1, dial.address);
+                return Void();
+            }
+            uusInfo.uusLength = dialInfo.uusInfo[0].uusData.size();
+        }
+
+        dial.uusInfo = &uusInfo;
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_DIAL, &dial, sizeOfDial, pRI, mSlotId);
+
+    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getImsiForApp(int32_t serial, const hidl_string& aid) {
+#if VDBG
+    RLOGD("getImsiForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_GET_IMSI, false,
+            1, aid.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::hangup(int32_t serial, int32_t gsmIndex) {
+#if VDBG
+    RLOGD("hangup: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_HANGUP, 1, gsmIndex);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::hangupWaitingOrBackground(int32_t serial) {
+#if VDBG
+    RLOGD("hangupWaitingOrBackground: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::hangupForegroundResumeBackground(int32_t serial) {
+#if VDBG
+    RLOGD("hangupForegroundResumeBackground: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::switchWaitingOrHoldingAndActive(int32_t serial) {
+#if VDBG
+    RLOGD("switchWaitingOrHoldingAndActive: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::conference(int32_t serial) {
+#if VDBG
+    RLOGD("conference: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CONFERENCE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::rejectCall(int32_t serial) {
+#if VDBG
+    RLOGD("rejectCall: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_UDUB);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getLastCallFailCause(int32_t serial) {
+#if VDBG
+    RLOGD("getLastCallFailCause: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_LAST_CALL_FAIL_CAUSE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getSignalStrength(int32_t serial) {
+#if VDBG
+    RLOGD("getSignalStrength: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SIGNAL_STRENGTH);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getVoiceRegistrationState(int32_t serial) {
+#if VDBG
+    RLOGD("getVoiceRegistrationState: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_VOICE_REGISTRATION_STATE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getDataRegistrationState(int32_t serial) {
+#if VDBG
+    RLOGD("getDataRegistrationState: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_REGISTRATION_STATE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getOperator(int32_t serial) {
+#if VDBG
+    RLOGD("getOperator: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_OPERATOR);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setRadioPower(int32_t serial, bool on) {
+#if VDBG
+    RLOGD("setRadioPower: serial %d on %d", serial, on);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_RADIO_POWER, 1, BOOL_TO_INT(on));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendDtmf(int32_t serial, const hidl_string& s) {
+#if VDBG
+    RLOGD("sendDtmf: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_DTMF, s.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendSms(int32_t serial, const GsmSmsMessage& message) {
+#if VDBG
+    RLOGD("sendSms: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SEND_SMS, false,
+            2, message.smscPdu.c_str(), message.pdu.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendSms_1_6(int32_t serial, const GsmSmsMessage& message) {
+#if VDBG
+    RLOGD("sendSms: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SEND_SMS, false,
+            2, message.smscPdu.c_str(), message.pdu.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendSMSExpectMore(int32_t serial, const GsmSmsMessage& message) {
+#if VDBG
+    RLOGD("sendSmsExpectMore: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SEND_SMS_EXPECT_MORE, false,
+            2, message.smscPdu.c_str(), message.pdu.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendSmsExpectMore_1_6(int32_t serial, const GsmSmsMessage& message) {
+#if VDBG
+    RLOGD("sendSmsExpectMore: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SEND_SMS_EXPECT_MORE, false,
+            2, message.smscPdu.c_str(), message.pdu.c_str());
+    return Void();
+}
+
+static bool convertMvnoTypeToString(MvnoType type, char *&str) {
+    switch (type) {
+        case MvnoType::IMSI:
+            str = (char *)"imsi";
+            return true;
+        case MvnoType::GID:
+            str = (char *)"gid";
+            return true;
+        case MvnoType::SPN:
+            str = (char *)"spn";
+            return true;
+        case MvnoType::NONE:
+            str = (char *)"";
+            return true;
+    }
+    return false;
+}
+
+Return<void> RadioImpl_1_6::setupDataCall(int32_t serial, RadioTechnology radioTechnology,
+                                      const DataProfileInfo& dataProfileInfo, bool modemCognitive,
+                                      bool roamingAllowed, bool isRoaming) {
+
+#if VDBG
+    RLOGD("setupDataCall: serial %d", serial);
+#endif
+
+    if (s_vendorFunctions->version >= 4 && s_vendorFunctions->version <= 14) {
+        const hidl_string &protocol =
+                (isRoaming ? dataProfileInfo.roamingProtocol : dataProfileInfo.protocol);
+        dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 7,
+            std::to_string((int) radioTechnology + 2).c_str(),
+            std::to_string((int) dataProfileInfo.profileId).c_str(),
+            dataProfileInfo.apn.c_str(),
+            dataProfileInfo.user.c_str(),
+            dataProfileInfo.password.c_str(),
+            std::to_string((int) dataProfileInfo.authType).c_str(),
+            protocol.c_str());
+    } else if (s_vendorFunctions->version == 15) {
+        char *mvnoTypeStr = NULL;
+        if (!convertMvnoTypeToString(dataProfileInfo.mvnoType, mvnoTypeStr)) {
+            RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                    RIL_REQUEST_SETUP_DATA_CALL);
+            if (pRI != NULL) {
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            }
+            return Void();
+        }
+        dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 15,
+            std::to_string((int) radioTechnology + 2).c_str(),
+            std::to_string((int) dataProfileInfo.profileId).c_str(),
+            dataProfileInfo.apn.c_str(),
+            dataProfileInfo.user.c_str(),
+            dataProfileInfo.password.c_str(),
+            std::to_string((int) dataProfileInfo.authType).c_str(),
+            dataProfileInfo.protocol.c_str(),
+            dataProfileInfo.roamingProtocol.c_str(),
+            std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
+            std::to_string(dataProfileInfo.bearerBitmap).c_str(),
+            modemCognitive ? "1" : "0",
+            std::to_string(dataProfileInfo.mtu).c_str(),
+            mvnoTypeStr,
+            dataProfileInfo.mvnoMatchData.c_str(),
+            roamingAllowed ? "1" : "0");
+    } else if (s_vendorFunctions->version >= 16) {
+        char *mvnoTypeStr = NULL;
+        if (!convertMvnoTypeToString(dataProfileInfo.mvnoType, mvnoTypeStr)) {
+            RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                    RIL_REQUEST_SETUP_DATA_CALL);
+            if (pRI != NULL) {
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            }
+            return Void();
+        }
+        dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 16,
+            std::to_string((int) radioTechnology + 2).c_str(),
+            std::to_string((int) dataProfileInfo.profileId).c_str(),
+            dataProfileInfo.apn.c_str(),
+            dataProfileInfo.user.c_str(),
+            dataProfileInfo.password.c_str(),
+            std::to_string((int) dataProfileInfo.authType).c_str(),
+            dataProfileInfo.protocol.c_str(),
+            dataProfileInfo.roamingProtocol.c_str(),
+            std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
+            std::to_string(dataProfileInfo.bearerBitmap).c_str(),
+            modemCognitive ? "1" : "0",
+            std::to_string(dataProfileInfo.mtu).c_str(),
+            mvnoTypeStr,
+            dataProfileInfo.mvnoMatchData.c_str(),
+            roamingAllowed ? "1" : "0",
+            "-1",
+            "");
+    } else {
+        RLOGE("Unsupported RIL version %d, min version expected 4", s_vendorFunctions->version);
+        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                RIL_REQUEST_SETUP_DATA_CALL);
+        if (pRI != NULL) {
+            sendErrorResponse(pRI, RIL_E_REQUEST_NOT_SUPPORTED);
+        }
+    }
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::iccIOForApp(int32_t serial, const IccIo& iccIo) {
+#if VDBG
+    RLOGD("iccIOForApp: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SIM_IO);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_SIM_IO_v6 rilIccIo = {};
+    rilIccIo.command = iccIo.command;
+    rilIccIo.fileid = iccIo.fileId;
+    if (!copyHidlStringToRil(&rilIccIo.path, iccIo.path, pRI)) {
+        return Void();
+    }
+
+    rilIccIo.p1 = iccIo.p1;
+    rilIccIo.p2 = iccIo.p2;
+    rilIccIo.p3 = iccIo.p3;
+
+    if (!copyHidlStringToRil(&rilIccIo.data, iccIo.data, pRI)) {
+        memsetAndFreeStrings(1, rilIccIo.path);
+        return Void();
+    }
+
+    if (!copyHidlStringToRil(&rilIccIo.pin2, iccIo.pin2, pRI)) {
+        memsetAndFreeStrings(2, rilIccIo.path, rilIccIo.data);
+        return Void();
+    }
+
+    if (!copyHidlStringToRil(&rilIccIo.aidPtr, iccIo.aid, pRI)) {
+        memsetAndFreeStrings(3, rilIccIo.path, rilIccIo.data, rilIccIo.pin2);
+        return Void();
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_SIM_IO, &rilIccIo, sizeof(rilIccIo), pRI, mSlotId);
+
+    memsetAndFreeStrings(4, rilIccIo.path, rilIccIo.data, rilIccIo.pin2, rilIccIo.aidPtr);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendUssd(int32_t serial, const hidl_string& ussd) {
+#if VDBG
+    RLOGD("sendUssd: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_SEND_USSD, ussd.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::cancelPendingUssd(int32_t serial) {
+#if VDBG
+    RLOGD("cancelPendingUssd: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CANCEL_USSD);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getClir(int32_t serial) {
+#if VDBG
+    RLOGD("getClir: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CLIR);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setClir(int32_t serial, int32_t status) {
+#if VDBG
+    RLOGD("setClir: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_CLIR, 1, status);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCallForwardStatus(int32_t serial, const CallForwardInfo& callInfo) {
+#if VDBG
+    RLOGD("getCallForwardStatus: serial %d", serial);
+#endif
+    dispatchCallForwardStatus(serial, mSlotId, RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
+            callInfo);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCallForward(int32_t serial, const CallForwardInfo& callInfo) {
+#if VDBG
+    RLOGD("setCallForward: serial %d", serial);
+#endif
+    dispatchCallForwardStatus(serial, mSlotId, RIL_REQUEST_SET_CALL_FORWARD,
+            callInfo);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCallWaiting(int32_t serial, int32_t serviceClass) {
+#if VDBG
+    RLOGD("getCallWaiting: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_QUERY_CALL_WAITING, 1, serviceClass);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCallWaiting(int32_t serial, bool enable, int32_t serviceClass) {
+#if VDBG
+    RLOGD("setCallWaiting: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_CALL_WAITING, 2, BOOL_TO_INT(enable),
+            serviceClass);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::acknowledgeLastIncomingGsmSms(int32_t serial,
+                                                      bool success, SmsAcknowledgeFailCause cause) {
+#if VDBG
+    RLOGD("acknowledgeLastIncomingGsmSms: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SMS_ACKNOWLEDGE, 2, BOOL_TO_INT(success),
+            cause);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::acceptCall(int32_t serial) {
+#if VDBG
+    RLOGD("acceptCall: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_ANSWER);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::deactivateDataCall(int32_t serial,
+                                           int32_t cid, bool reasonRadioShutDown) {
+#if VDBG
+    RLOGD("deactivateDataCall: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_DEACTIVATE_DATA_CALL, false,
+            2, (std::to_string(cid)).c_str(), reasonRadioShutDown ? "1" : "0");
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getFacilityLockForApp(int32_t serial, const hidl_string& facility,
+                                              const hidl_string& password, int32_t serviceClass,
+                                              const hidl_string& appId) {
+#if VDBG
+    RLOGD("getFacilityLockForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_QUERY_FACILITY_LOCK, true,
+            4, facility.c_str(), password.c_str(),
+            (std::to_string(serviceClass)).c_str(), appId.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setFacilityLockForApp(int32_t serial, const hidl_string& facility,
+                                              bool lockState, const hidl_string& password,
+                                              int32_t serviceClass, const hidl_string& appId) {
+#if VDBG
+    RLOGD("setFacilityLockForApp: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SET_FACILITY_LOCK, true,
+            5, facility.c_str(), lockState ? "1" : "0", password.c_str(),
+            (std::to_string(serviceClass)).c_str(), appId.c_str() );
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setBarringPassword(int32_t serial, const hidl_string& facility,
+                                           const hidl_string& oldPassword,
+                                           const hidl_string& newPassword) {
+#if VDBG
+    RLOGD("setBarringPassword: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_CHANGE_BARRING_PASSWORD, true,
+            3, facility.c_str(), oldPassword.c_str(), newPassword.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getNetworkSelectionMode(int32_t serial) {
+#if VDBG
+    RLOGD("getNetworkSelectionMode: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setNetworkSelectionModeAutomatic(int32_t serial) {
+#if VDBG
+    RLOGD("setNetworkSelectionModeAutomatic: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setNetworkSelectionModeManual(int32_t serial,
+                                                      const hidl_string& operatorNumeric) {
+#if VDBG
+    RLOGD("setNetworkSelectionModeManual: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+        RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_NetworkOperator networkOperator = {};
+
+    networkOperator.act = UNKNOWN;
+    if (!copyHidlStringToRil(&networkOperator.operatorNumeric, operatorNumeric, pRI)) {
+        return Void();
+    }
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &networkOperator,
+        sizeof(networkOperator), pRI, mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getAvailableNetworks(int32_t serial) {
+#if VDBG
+    RLOGD("getAvailableNetworks: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::startNetworkScan(int32_t serial, const V1_1::NetworkScanRequest& request) {
+#if VDBG
+    RLOGD("startNetworkScan: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    if (request.specifiers.size() > MAX_RADIO_ACCESS_NETWORKS) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    RIL_NetworkScanRequest scan_request = {};
+
+    scan_request.type = (RIL_ScanType) request.type;
+    scan_request.interval = request.interval;
+    scan_request.specifiers_length = request.specifiers.size();
+    for (size_t i = 0; i < request.specifiers.size(); ++i) {
+        if (request.specifiers[i].geranBands.size() > MAX_BANDS ||
+            request.specifiers[i].utranBands.size() > MAX_BANDS ||
+            request.specifiers[i].eutranBands.size() > MAX_BANDS ||
+            request.specifiers[i].channels.size() > MAX_CHANNELS) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            return Void();
+        }
+        const V1_1::RadioAccessSpecifier& ras_from =
+                request.specifiers[i];
+        RIL_RadioAccessSpecifier& ras_to = scan_request.specifiers[i];
+
+        ras_to.radio_access_network = (RIL_RadioAccessNetworks) ras_from.radioAccessNetwork;
+        ras_to.channels_length = ras_from.channels.size();
+
+        std::copy(ras_from.channels.begin(), ras_from.channels.end(), ras_to.channels);
+        const std::vector<uint32_t> * bands = nullptr;
+        switch (request.specifiers[i].radioAccessNetwork) {
+            case V1_1::RadioAccessNetworks::GERAN:
+                ras_to.bands_length = ras_from.geranBands.size();
+                bands = (std::vector<uint32_t> *) &ras_from.geranBands;
+                break;
+            case V1_1::RadioAccessNetworks::UTRAN:
+                ras_to.bands_length = ras_from.utranBands.size();
+                bands = (std::vector<uint32_t> *) &ras_from.utranBands;
+                break;
+            case V1_1::RadioAccessNetworks::EUTRAN:
+                ras_to.bands_length = ras_from.eutranBands.size();
+                bands = (std::vector<uint32_t> *) &ras_from.eutranBands;
+                break;
+            default:
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                return Void();
+        }
+        // safe to copy to geran_bands because it's a union member
+        for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
+            ras_to.bands.geran_bands[idx] = (RIL_GeranBands) (*bands)[idx];
+        }
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
+            mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::stopNetworkScan(int32_t serial) {
+#if VDBG
+    RLOGD("stopNetworkScan: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_STOP_NETWORK_SCAN);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::startDtmf(int32_t serial, const hidl_string& s) {
+#if VDBG
+    RLOGD("startDtmf: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_DTMF_START,
+            s.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::stopDtmf(int32_t serial) {
+#if VDBG
+    RLOGD("stopDtmf: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_DTMF_STOP);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getBasebandVersion(int32_t serial) {
+#if VDBG
+    RLOGD("getBasebandVersion: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_BASEBAND_VERSION);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::separateConnection(int32_t serial, int32_t gsmIndex) {
+#if VDBG
+    RLOGD("separateConnection: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SEPARATE_CONNECTION, 1, gsmIndex);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setMute(int32_t serial, bool enable) {
+#if VDBG
+    RLOGD("setMute: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_MUTE, 1, BOOL_TO_INT(enable));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getMute(int32_t serial) {
+#if VDBG
+    RLOGD("getMute: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_MUTE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getClip(int32_t serial) {
+#if VDBG
+    RLOGD("getClip: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_CLIP);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getDataCallList(int32_t serial) {
+#if VDBG
+    RLOGD("getDataCallList: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_CALL_LIST);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getDataCallList_1_6(int32_t serial) {
+#if VDBG
+    RLOGD("getDataCallList_1_6: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_CALL_LIST);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::emergencyDial_1_6(int32_t serial,
+        const ::android::hardware::radio::V1_0::Dial& dialInfo,
+        hidl_bitfield<android::hardware::radio::V1_4::EmergencyServiceCategory> categories,
+        const hidl_vec<hidl_string>&  urns ,
+        ::android::hardware::radio::V1_4::EmergencyCallRouting routing,
+        bool fromEmergencyDialer, bool /* isTesting */) {
+#if VDBG
+    RLOGD("emergencyDial: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_EMERGENCY_DIAL);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_EmergencyDial eccDial = {};
+    RIL_Dial& dial = eccDial.dialInfo;
+    RIL_UUS_Info uusInfo = {};
+
+    if (!copyHidlStringToRil(&dial.address, dialInfo.address, pRI)) {
+        return Void();
+    }
+    dial.clir = (int) dialInfo.clir;
+
+    if (dialInfo.uusInfo.size() != 0) {
+        uusInfo.uusType = (RIL_UUS_Type) dialInfo.uusInfo[0].uusType;
+        uusInfo.uusDcs = (RIL_UUS_DCS) dialInfo.uusInfo[0].uusDcs;
+
+        if (dialInfo.uusInfo[0].uusData.size() == 0) {
+            uusInfo.uusData = NULL;
+            uusInfo.uusLength = 0;
+        } else {
+            if (!copyHidlStringToRil(&uusInfo.uusData, dialInfo.uusInfo[0].uusData, pRI)) {
+                memsetAndFreeStrings(1, dial.address);
+                return Void();
+            }
+            uusInfo.uusLength = dialInfo.uusInfo[0].uusData.size();
+        }
+
+        dial.uusInfo = &uusInfo;
+    }
+
+    eccDial.urnsNumber = urns.size();
+    if (eccDial.urnsNumber != 0) {
+        char **ppUrns = (char **)calloc(eccDial.urnsNumber, sizeof(char *));
+        if (ppUrns == NULL) {
+            RLOGE("Memory allocation failed for request %s",
+                    requestToString(pRI->pCI->requestNumber));
+            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+            memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
+            return Void();
+        }
+        for (uint32_t i = 0; i < eccDial.urnsNumber; i++) {
+            if (!copyHidlStringToRil(&ppUrns[i], hidl_string(urns[i]), pRI)) {
+                for (uint32_t j = 0; j < i; j++) {
+                    memsetAndFreeStrings(1, ppUrns[j]);
+                }
+                memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
+                free(ppUrns);
+                return Void();
+            }
+        }
+        eccDial.urns = ppUrns;
+    }
+
+    eccDial.categories = (RIL_EmergencyServiceCategory)categories;
+    eccDial.routing = (RIL_EmergencyCallRouting)routing;
+    eccDial.fromEmergencyDialer = fromEmergencyDialer;
+
+    CALL_ONREQUEST(RIL_REQUEST_EMERGENCY_DIAL, &eccDial, sizeof(RIL_EmergencyDial), pRI, mSlotId);
+
+    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
+    if (eccDial.urns != NULL) {
+        for (size_t i = 0; i < eccDial.urnsNumber; i++) {
+            memsetAndFreeStrings(1, eccDial.urns[i]);
+        }
+        free(eccDial.urns);
+    }
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setSuppServiceNotifications(int32_t serial, bool enable) {
+#if VDBG
+    RLOGD("setSuppServiceNotifications: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, 1,
+            BOOL_TO_INT(enable));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::writeSmsToSim(int32_t serial, const SmsWriteArgs& smsWriteArgs) {
+#if VDBG
+    RLOGD("writeSmsToSim: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_WRITE_SMS_TO_SIM);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_SMS_WriteArgs args;
+    args.status = (int) smsWriteArgs.status;
+
+    if (!copyHidlStringToRil(&args.pdu, smsWriteArgs.pdu, pRI)) {
+        return Void();
+    }
+
+    if (!copyHidlStringToRil(&args.smsc, smsWriteArgs.smsc, pRI)) {
+        memsetAndFreeStrings(1, args.pdu);
+        return Void();
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_WRITE_SMS_TO_SIM, &args, sizeof(args), pRI, mSlotId);
+
+    memsetAndFreeStrings(2, args.smsc, args.pdu);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::deleteSmsOnSim(int32_t serial, int32_t index) {
+#if VDBG
+    RLOGD("deleteSmsOnSim: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_DELETE_SMS_ON_SIM, 1, index);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setBandMode(int32_t serial, RadioBandMode mode) {
+#if VDBG
+    RLOGD("setBandMode: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_BAND_MODE, 1, mode);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getAvailableBandModes(int32_t serial) {
+#if VDBG
+    RLOGD("getAvailableBandModes: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendEnvelope(int32_t serial, const hidl_string& command) {
+#if VDBG
+    RLOGD("sendEnvelope: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND,
+            command.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendTerminalResponseToSim(int32_t serial,
+                                                  const hidl_string& commandResponse) {
+#if VDBG
+    RLOGD("sendTerminalResponseToSim: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE,
+            commandResponse.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::handleStkCallSetupRequestFromSim(int32_t serial, bool accept) {
+#if VDBG
+    RLOGD("handleStkCallSetupRequestFromSim: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM,
+            1, BOOL_TO_INT(accept));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::explicitCallTransfer(int32_t serial) {
+#if VDBG
+    RLOGD("explicitCallTransfer: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_EXPLICIT_CALL_TRANSFER);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setPreferredNetworkType(int32_t serial, PreferredNetworkType nwType) {
+#if VDBG
+    RLOGD("setPreferredNetworkType: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, 1, nwType);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getPreferredNetworkType(int32_t serial) {
+#if VDBG
+    RLOGD("getPreferredNetworkType: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getNeighboringCids(int32_t serial) {
+#if VDBG
+    RLOGD("getNeighboringCids: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_NEIGHBORING_CELL_IDS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setLocationUpdates(int32_t serial, bool enable) {
+#if VDBG
+    RLOGD("setLocationUpdates: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_LOCATION_UPDATES, 1, BOOL_TO_INT(enable));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCdmaSubscriptionSource(int32_t serial, CdmaSubscriptionSource cdmaSub) {
+#if VDBG
+    RLOGD("setCdmaSubscriptionSource: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, 1, cdmaSub);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCdmaRoamingPreference(int32_t serial, CdmaRoamingType type) {
+#if VDBG
+    RLOGD("setCdmaRoamingPreference: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, 1, type);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCdmaRoamingPreference(int32_t serial) {
+#if VDBG
+    RLOGD("getCdmaRoamingPreference: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setTTYMode(int32_t serial, TtyMode mode) {
+#if VDBG
+    RLOGD("setTTYMode: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_TTY_MODE, 1, mode);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getTTYMode(int32_t serial) {
+#if VDBG
+    RLOGD("getTTYMode: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_QUERY_TTY_MODE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setPreferredVoicePrivacy(int32_t serial, bool enable) {
+#if VDBG
+    RLOGD("setPreferredVoicePrivacy: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE,
+            1, BOOL_TO_INT(enable));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getPreferredVoicePrivacy(int32_t serial) {
+#if VDBG
+    RLOGD("getPreferredVoicePrivacy: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendCDMAFeatureCode(int32_t serial, const hidl_string& featureCode) {
+#if VDBG
+    RLOGD("sendCDMAFeatureCode: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_CDMA_FLASH,
+            featureCode.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendBurstDtmf(int32_t serial, const hidl_string& dtmf, int32_t on,
+                                      int32_t off) {
+#if VDBG
+    RLOGD("sendBurstDtmf: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_CDMA_BURST_DTMF, false,
+            3, dtmf.c_str(), (std::to_string(on)).c_str(),
+            (std::to_string(off)).c_str());
+    return Void();
+}
+
+void constructCdmaSms(RIL_CDMA_SMS_Message &rcsm, const CdmaSmsMessage& sms) {
+    rcsm.uTeleserviceID = sms.teleserviceId;
+    rcsm.bIsServicePresent = BOOL_TO_INT(sms.isServicePresent);
+    rcsm.uServicecategory = sms.serviceCategory;
+    rcsm.sAddress.digit_mode = (RIL_CDMA_SMS_DigitMode) sms.address.digitMode;
+    rcsm.sAddress.number_mode = (RIL_CDMA_SMS_NumberMode) sms.address.numberMode;
+    rcsm.sAddress.number_type = (RIL_CDMA_SMS_NumberType) sms.address.numberType;
+    rcsm.sAddress.number_plan = (RIL_CDMA_SMS_NumberPlan) sms.address.numberPlan;
+
+    rcsm.sAddress.number_of_digits = sms.address.digits.size();
+    int digitLimit= MIN((rcsm.sAddress.number_of_digits), RIL_CDMA_SMS_ADDRESS_MAX);
+    for (int i = 0; i < digitLimit; i++) {
+        rcsm.sAddress.digits[i] = sms.address.digits[i];
+    }
+
+    rcsm.sSubAddress.subaddressType = (RIL_CDMA_SMS_SubaddressType) sms.subAddress.subaddressType;
+    rcsm.sSubAddress.odd = BOOL_TO_INT(sms.subAddress.odd);
+
+    rcsm.sSubAddress.number_of_digits = sms.subAddress.digits.size();
+    digitLimit= MIN((rcsm.sSubAddress.number_of_digits), RIL_CDMA_SMS_SUBADDRESS_MAX);
+    for (int i = 0; i < digitLimit; i++) {
+        rcsm.sSubAddress.digits[i] = sms.subAddress.digits[i];
+    }
+
+    rcsm.uBearerDataLen = sms.bearerData.size();
+    digitLimit= MIN((rcsm.uBearerDataLen), RIL_CDMA_SMS_BEARER_DATA_MAX);
+    for (int i = 0; i < digitLimit; i++) {
+        rcsm.aBearerData[i] = sms.bearerData[i];
+    }
+}
+
+Return<void> RadioImpl_1_6::sendCdmaSms(int32_t serial, const CdmaSmsMessage& sms) {
+#if VDBG
+    RLOGD("sendCdmaSms: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_CDMA_SEND_SMS);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CDMA_SMS_Message rcsm = {};
+    constructCdmaSms(rcsm, sms);
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsm, sizeof(rcsm), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendCdmaSms_1_6(int32_t serial, const CdmaSmsMessage& sms) {
+#if VDBG
+    RLOGD("sendCdmaSms: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_CDMA_SEND_SMS);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CDMA_SMS_Message rcsm = {};
+    constructCdmaSms(rcsm, sms);
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsm, sizeof(rcsm), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::acknowledgeLastIncomingCdmaSms(int32_t serial, const CdmaSmsAck& smsAck) {
+#if VDBG
+    RLOGD("acknowledgeLastIncomingCdmaSms: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CDMA_SMS_Ack rcsa = {};
+
+    rcsa.uErrorClass = (RIL_CDMA_SMS_ErrorClass) smsAck.errorClass;
+    rcsa.uSMSCauseCode = smsAck.smsCauseCode;
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsa, sizeof(rcsa), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getGsmBroadcastConfig(int32_t serial) {
+#if VDBG
+    RLOGD("getGsmBroadcastConfig: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setGsmBroadcastConfig(int32_t serial,
+                                              const hidl_vec<GsmBroadcastSmsConfigInfo>&
+                                              configInfo) {
+#if VDBG
+    RLOGD("setGsmBroadcastConfig: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    int num = configInfo.size();
+    if (num > MAX_BROADCAST_SMS_CONFIG_INFO) {
+        RLOGE("setGsmBroadcastConfig: Invalid configInfo length %s",
+                requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return Void();
+    }
+    RIL_GSM_BroadcastSmsConfigInfo gsmBci[num];
+    RIL_GSM_BroadcastSmsConfigInfo *gsmBciPtrs[num];
+
+    for (int i = 0 ; i < num ; i++ ) {
+        gsmBciPtrs[i] = &gsmBci[i];
+        gsmBci[i].fromServiceId = configInfo[i].fromServiceId;
+        gsmBci[i].toServiceId = configInfo[i].toServiceId;
+        gsmBci[i].fromCodeScheme = configInfo[i].fromCodeScheme;
+        gsmBci[i].toCodeScheme = configInfo[i].toCodeScheme;
+        gsmBci[i].selected = BOOL_TO_INT(configInfo[i].selected);
+    }
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, gsmBciPtrs,
+            num * sizeof(RIL_GSM_BroadcastSmsConfigInfo *), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setGsmBroadcastActivation(int32_t serial, bool activate) {
+#if VDBG
+    RLOGD("setGsmBroadcastActivation: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
+            1, BOOL_TO_INT(!activate));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCdmaBroadcastConfig(int32_t serial) {
+#if VDBG
+    RLOGD("getCdmaBroadcastConfig: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCdmaBroadcastConfig(int32_t serial,
+                                               const hidl_vec<CdmaBroadcastSmsConfigInfo>&
+                                               configInfo) {
+#if VDBG
+    RLOGD("setCdmaBroadcastConfig: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    int num = configInfo.size();
+    if (num > MAX_BROADCAST_SMS_CONFIG_INFO) {
+        RLOGE("setCdmaBroadcastConfig: Invalid configInfo length %s",
+                requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return Void();
+    }
+    RIL_CDMA_BroadcastSmsConfigInfo cdmaBci[num];
+    RIL_CDMA_BroadcastSmsConfigInfo *cdmaBciPtrs[num];
+
+    for (int i = 0 ; i < num ; i++ ) {
+        cdmaBciPtrs[i] = &cdmaBci[i];
+        cdmaBci[i].service_category = configInfo[i].serviceCategory;
+        cdmaBci[i].language = configInfo[i].language;
+        cdmaBci[i].selected = BOOL_TO_INT(configInfo[i].selected);
+    }
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, cdmaBciPtrs,
+            num * sizeof(RIL_CDMA_BroadcastSmsConfigInfo *), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCdmaBroadcastActivation(int32_t serial, bool activate) {
+#if VDBG
+    RLOGD("setCdmaBroadcastActivation: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION,
+            1, BOOL_TO_INT(!activate));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCDMASubscription(int32_t serial) {
+#if VDBG
+    RLOGD("getCDMASubscription: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_SUBSCRIPTION);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::writeSmsToRuim(int32_t serial, const CdmaSmsWriteArgs& cdmaSms) {
+#if VDBG
+    RLOGD("writeSmsToRuim: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CDMA_SMS_WriteArgs rcsw = {};
+    rcsw.status = (int) cdmaSms.status;
+    constructCdmaSms(rcsw.message, cdmaSms.message);
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsw, sizeof(rcsw), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::deleteSmsOnRuim(int32_t serial, int32_t index) {
+#if VDBG
+    RLOGD("deleteSmsOnRuim: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, 1, index);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getDeviceIdentity(int32_t serial) {
+#if VDBG
+    RLOGD("getDeviceIdentity: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_DEVICE_IDENTITY);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::exitEmergencyCallbackMode(int32_t serial) {
+#if VDBG
+    RLOGD("exitEmergencyCallbackMode: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getSmscAddress(int32_t serial) {
+#if VDBG
+    RLOGD("getSmscAddress: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SMSC_ADDRESS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setSmscAddress(int32_t serial, const hidl_string& smsc) {
+#if VDBG
+    RLOGD("setSmscAddress: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_SET_SMSC_ADDRESS,
+            smsc.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::reportSmsMemoryStatus(int32_t serial, bool available) {
+#if VDBG
+    RLOGD("reportSmsMemoryStatus: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, 1,
+            BOOL_TO_INT(available));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::reportStkServiceIsRunning(int32_t serial) {
+#if VDBG
+    RLOGD("reportStkServiceIsRunning: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCdmaSubscriptionSource(int32_t serial) {
+#if VDBG
+    RLOGD("getCdmaSubscriptionSource: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::requestIsimAuthentication(int32_t serial, const hidl_string& challenge) {
+#if VDBG
+    RLOGD("requestIsimAuthentication: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_ISIM_AUTHENTICATION,
+            challenge.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::acknowledgeIncomingGsmSmsWithPdu(int32_t serial, bool success,
+                                                         const hidl_string& ackPdu) {
+#if VDBG
+    RLOGD("acknowledgeIncomingGsmSmsWithPdu: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, false,
+            2, success ? "1" : "0", ackPdu.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendEnvelopeWithStatus(int32_t serial, const hidl_string& contents) {
+#if VDBG
+    RLOGD("sendEnvelopeWithStatus: serial %d", serial);
+#endif
+    dispatchString(serial, mSlotId, RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS,
+            contents.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getVoiceRadioTechnology(int32_t serial) {
+#if VDBG
+    RLOGD("getVoiceRadioTechnology: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_VOICE_RADIO_TECH);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCellInfoList(int32_t serial) {
+#if VDBG
+    RLOGD("getCellInfoList: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CELL_INFO_LIST);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getCellInfoList_1_6(int32_t serial) {
+#if VDBG
+    RLOGD("getCellInfoList_1_6: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CELL_INFO_LIST);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCellInfoListRate(int32_t serial, int32_t rate) {
+#if VDBG
+    RLOGD("setCellInfoListRate: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, 1, rate);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setInitialAttachApn(int32_t serial, const DataProfileInfo& dataProfileInfo,
+                                            bool modemCognitive, bool isRoaming) {
+#if VDBG
+    RLOGD("setInitialAttachApn: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_INITIAL_ATTACH_APN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    if (s_vendorFunctions->version <= 14) {
+        RIL_InitialAttachApn iaa = {};
+
+        if (!copyHidlStringToRil(&iaa.apn, dataProfileInfo.apn, pRI, true)) {
+            return Void();
+        }
+
+        const hidl_string &protocol =
+                (isRoaming ? dataProfileInfo.roamingProtocol : dataProfileInfo.protocol);
+
+        if (!copyHidlStringToRil(&iaa.protocol, protocol, pRI)) {
+            memsetAndFreeStrings(1, iaa.apn);
+            return Void();
+        }
+        iaa.authtype = (int) dataProfileInfo.authType;
+        if (!copyHidlStringToRil(&iaa.username, dataProfileInfo.user, pRI)) {
+            memsetAndFreeStrings(2, iaa.apn, iaa.protocol);
+            return Void();
+        }
+        if (!copyHidlStringToRil(&iaa.password, dataProfileInfo.password, pRI)) {
+            memsetAndFreeStrings(3, iaa.apn, iaa.protocol, iaa.username);
+            return Void();
+        }
+
+        CALL_ONREQUEST(RIL_REQUEST_SET_INITIAL_ATTACH_APN, &iaa, sizeof(iaa), pRI, mSlotId);
+
+        memsetAndFreeStrings(4, iaa.apn, iaa.protocol, iaa.username, iaa.password);
+    } else {
+        RIL_InitialAttachApn_v15 iaa = {};
+
+        if (!copyHidlStringToRil(&iaa.apn, dataProfileInfo.apn, pRI, true)) {
+            return Void();
+        }
+
+        if (!copyHidlStringToRil(&iaa.protocol, dataProfileInfo.protocol, pRI)) {
+            memsetAndFreeStrings(1, iaa.apn);
+            return Void();
+        }
+        if (!copyHidlStringToRil(&iaa.roamingProtocol, dataProfileInfo.roamingProtocol, pRI)) {
+            memsetAndFreeStrings(2, iaa.apn, iaa.protocol);
+            return Void();
+        }
+        iaa.authtype = (int) dataProfileInfo.authType;
+        if (!copyHidlStringToRil(&iaa.username, dataProfileInfo.user, pRI)) {
+            memsetAndFreeStrings(3, iaa.apn, iaa.protocol, iaa.roamingProtocol);
+            return Void();
+        }
+        if (!copyHidlStringToRil(&iaa.password, dataProfileInfo.password, pRI)) {
+            memsetAndFreeStrings(4, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username);
+            return Void();
+        }
+        iaa.supportedTypesBitmask = dataProfileInfo.supportedApnTypesBitmap;
+        iaa.bearerBitmask = dataProfileInfo.bearerBitmap;
+        iaa.modemCognitive = BOOL_TO_INT(modemCognitive);
+        iaa.mtu = dataProfileInfo.mtu;
+
+        if (!convertMvnoTypeToString(dataProfileInfo.mvnoType, iaa.mvnoType)) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            memsetAndFreeStrings(5, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username,
+                    iaa.password);
+            return Void();
+        }
+
+        if (!copyHidlStringToRil(&iaa.mvnoMatchData, dataProfileInfo.mvnoMatchData, pRI)) {
+            memsetAndFreeStrings(5, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username,
+                    iaa.password);
+            return Void();
+        }
+
+        CALL_ONREQUEST(RIL_REQUEST_SET_INITIAL_ATTACH_APN, &iaa, sizeof(iaa), pRI, mSlotId);
+
+        memsetAndFreeStrings(6, iaa.apn, iaa.protocol, iaa.roamingProtocol, iaa.username,
+                iaa.password, iaa.mvnoMatchData);
+    }
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getImsRegistrationState(int32_t serial) {
+#if VDBG
+    RLOGD("getImsRegistrationState: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_IMS_REGISTRATION_STATE);
+    return Void();
+}
+
+bool dispatchImsGsmSms(const ImsSmsMessage& message, RequestInfo *pRI) {
+    RIL_IMS_SMS_Message rism = {};
+    char **pStrings;
+    int countStrings = 2;
+    int dataLen = sizeof(char *) * countStrings;
+
+    rism.tech = RADIO_TECH_3GPP;
+    rism.retry = BOOL_TO_INT(message.retry);
+    rism.messageRef = message.messageRef;
+
+    if (message.gsmMessage.size() != 1) {
+        RLOGE("dispatchImsGsmSms: Invalid len %s", requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return false;
+    }
+
+    pStrings = (char **)calloc(countStrings, sizeof(char *));
+    if (pStrings == NULL) {
+        RLOGE("dispatchImsGsmSms: Memory allocation failed for request %s",
+                requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+        return false;
+    }
+
+    if (!copyHidlStringToRil(&pStrings[0], message.gsmMessage[0].smscPdu, pRI)) {
+#ifdef MEMSET_FREED
+        memset(pStrings, 0, dataLen);
+#endif
+        free(pStrings);
+        return false;
+    }
+
+    if (!copyHidlStringToRil(&pStrings[1], message.gsmMessage[0].pdu, pRI)) {
+        memsetAndFreeStrings(1, pStrings[0]);
+#ifdef MEMSET_FREED
+        memset(pStrings, 0, dataLen);
+#endif
+        free(pStrings);
+        return false;
+    }
+
+    rism.message.gsmMessage = pStrings;
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rism, sizeof(RIL_RadioTechnologyFamily) +
+            sizeof(uint8_t) + sizeof(int32_t) + dataLen, pRI, pRI->socket_id);
+
+    for (int i = 0 ; i < countStrings ; i++) {
+        memsetAndFreeStrings(1, pStrings[i]);
+    }
+
+#ifdef MEMSET_FREED
+    memset(pStrings, 0, dataLen);
+#endif
+    free(pStrings);
+
+    return true;
+}
+
+struct ImsCdmaSms {
+    RIL_IMS_SMS_Message imsSms;
+    RIL_CDMA_SMS_Message cdmaSms;
+};
+
+bool dispatchImsCdmaSms(const ImsSmsMessage& message, RequestInfo *pRI) {
+    ImsCdmaSms temp = {};
+
+    if (message.cdmaMessage.size() != 1) {
+        RLOGE("dispatchImsCdmaSms: Invalid len %s", requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return false;
+    }
+
+    temp.imsSms.tech = RADIO_TECH_3GPP2;
+    temp.imsSms.retry = BOOL_TO_INT(message.retry);
+    temp.imsSms.messageRef = message.messageRef;
+    temp.imsSms.message.cdmaMessage = &temp.cdmaSms;
+
+    constructCdmaSms(temp.cdmaSms, message.cdmaMessage[0]);
+
+    // Vendor code expects payload length to include actual msg payload
+    // (sizeof(RIL_CDMA_SMS_Message)) instead of (RIL_CDMA_SMS_Message *) + size of other fields in
+    // RIL_IMS_SMS_Message
+    int payloadLen = sizeof(RIL_RadioTechnologyFamily) + sizeof(uint8_t) + sizeof(int32_t)
+            + sizeof(RIL_CDMA_SMS_Message);
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &temp.imsSms, payloadLen, pRI, pRI->socket_id);
+
+    return true;
+}
+
+Return<void> RadioImpl_1_6::sendImsSms(int32_t serial, const ImsSmsMessage& message) {
+#if VDBG
+    RLOGD("sendImsSms: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_IMS_SEND_SMS);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_RadioTechnologyFamily format = (RIL_RadioTechnologyFamily) message.tech;
+
+    if (RADIO_TECH_3GPP == format) {
+        dispatchImsGsmSms(message, pRI);
+    } else if (RADIO_TECH_3GPP2 == format) {
+        dispatchImsCdmaSms(message, pRI);
+    } else {
+        RLOGE("sendImsSms: Invalid radio tech %s",
+                requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+    }
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::iccTransmitApduBasicChannel(int32_t serial, const SimApdu& message) {
+#if VDBG
+    RLOGD("iccTransmitApduBasicChannel: serial %d", serial);
+#endif
+    dispatchIccApdu(serial, mSlotId, RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC, message);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::iccOpenLogicalChannel(int32_t serial, const hidl_string& aid, int32_t p2) {
+#if VDBG
+    RLOGD("iccOpenLogicalChannel: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SIM_OPEN_CHANNEL);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_OpenChannelParams params = {};
+
+    params.p2 = p2;
+
+    if (!copyHidlStringToRil(&params.aidPtr, aid, pRI)) {
+        return Void();
+    }
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &params, sizeof(params), pRI, mSlotId);
+
+    memsetAndFreeStrings(1, params.aidPtr);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::iccCloseLogicalChannel(int32_t serial, int32_t channelId) {
+#if VDBG
+    RLOGD("iccCloseLogicalChannel: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SIM_CLOSE_CHANNEL, 1, channelId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::iccTransmitApduLogicalChannel(int32_t serial, const SimApdu& message) {
+#if VDBG
+    RLOGD("iccTransmitApduLogicalChannel: serial %d", serial);
+#endif
+    dispatchIccApdu(serial, mSlotId, RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, message);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::nvReadItem(int32_t serial, NvItem itemId) {
+#if VDBG
+    RLOGD("nvReadItem: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_NV_READ_ITEM);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_NV_ReadItem nvri = {};
+    nvri.itemID = (RIL_NV_Item) itemId;
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &nvri, sizeof(nvri), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::nvWriteItem(int32_t serial, const NvWriteItem& item) {
+#if VDBG
+    RLOGD("nvWriteItem: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_NV_WRITE_ITEM);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_NV_WriteItem nvwi = {};
+
+    nvwi.itemID = (RIL_NV_Item) item.itemId;
+
+    if (!copyHidlStringToRil(&nvwi.value, item.value, pRI)) {
+        return Void();
+    }
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &nvwi, sizeof(nvwi), pRI, mSlotId);
+
+    memsetAndFreeStrings(1, nvwi.value);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::nvWriteCdmaPrl(int32_t serial, const hidl_vec<uint8_t>& prl) {
+#if VDBG
+    RLOGD("nvWriteCdmaPrl: serial %d", serial);
+#endif
+    dispatchRaw(serial, mSlotId, RIL_REQUEST_NV_WRITE_CDMA_PRL, prl);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::nvResetConfig(int32_t serial, ResetNvType resetType) {
+    int rilResetType = -1;
+#if VDBG
+    RLOGD("nvResetConfig: serial %d", serial);
+#endif
+    /* Convert ResetNvType to RIL.h values
+     * RIL_REQUEST_NV_RESET_CONFIG
+     * 1 - reload all NV items
+     * 2 - erase NV reset (SCRTN)
+     * 3 - factory reset (RTN)
+     */
+    switch(resetType) {
+      case ResetNvType::RELOAD:
+        rilResetType = 1;
+        break;
+      case ResetNvType::ERASE:
+        rilResetType = 2;
+        break;
+      case ResetNvType::FACTORY_RESET:
+        rilResetType = 3;
+        break;
+    }
+    dispatchInts(serial, mSlotId, RIL_REQUEST_NV_RESET_CONFIG, 1, rilResetType);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setUiccSubscription(int32_t serial, const SelectUiccSub& uiccSub) {
+#if VDBG
+    RLOGD("setUiccSubscription: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_UICC_SUBSCRIPTION);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_SelectUiccSub rilUiccSub = {};
+
+    rilUiccSub.slot = uiccSub.slot;
+    rilUiccSub.app_index = uiccSub.appIndex;
+    rilUiccSub.sub_type = (RIL_SubscriptionType) uiccSub.subType;
+    rilUiccSub.act_status = (RIL_UiccSubActStatus) uiccSub.actStatus;
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rilUiccSub, sizeof(rilUiccSub), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setDataAllowed(int32_t serial, bool allow) {
+#if VDBG
+    RLOGD("setDataAllowed: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_ALLOW_DATA, 1, BOOL_TO_INT(allow));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getHardwareConfig(int32_t serial) {
+#if VDBG
+    RLOGD("getHardwareConfig: serial %d", serial);
+#endif
+    RLOGD("getHardwareConfig: serial %d, mSlotId = %d", serial, mSlotId);
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_HARDWARE_CONFIG);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::requestIccSimAuthentication(int32_t serial, int32_t authContext,
+        const hidl_string& authData, const hidl_string& aid) {
+#if VDBG
+    RLOGD("requestIccSimAuthentication: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SIM_AUTHENTICATION);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_SimAuthentication pf = {};
+
+    pf.authContext = authContext;
+
+    if (!copyHidlStringToRil(&pf.authData, authData, pRI)) {
+        return Void();
+    }
+
+    if (!copyHidlStringToRil(&pf.aid, aid, pRI)) {
+        memsetAndFreeStrings(1, pf.authData);
+        return Void();
+    }
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &pf, sizeof(pf), pRI, mSlotId);
+
+    memsetAndFreeStrings(2, pf.authData, pf.aid);
+    return Void();
+}
+
+/**
+ * @param numProfiles number of data profile
+ * @param dataProfiles the pointer to the actual data profiles. The acceptable type is
+          RIL_DataProfileInfo or RIL_DataProfileInfo_v15.
+ * @param dataProfilePtrs the pointer to the pointers that point to each data profile structure
+ * @param numfields number of string-type member in the data profile structure
+ * @param ... the variadic parameters are pointers to each string-type member
+ **/
+template <typename T>
+void freeSetDataProfileData(int numProfiles, T *dataProfiles, T **dataProfilePtrs,
+                            int numfields, ...) {
+    va_list args;
+    va_start(args, numfields);
+
+    // Iterate through each string-type field that need to be free.
+    for (int i = 0; i < numfields; i++) {
+        // Iterate through each data profile and free that specific string-type field.
+        // The type 'char *T::*' is a type of pointer to a 'char *' member inside T structure.
+        char *T::*ptr = va_arg(args, char *T::*);
+        for (int j = 0; j < numProfiles; j++) {
+            memsetAndFreeStrings(1, dataProfiles[j].*ptr);
+        }
+    }
+
+    va_end(args);
+
+#ifdef MEMSET_FREED
+    memset(dataProfiles, 0, numProfiles * sizeof(T));
+    memset(dataProfilePtrs, 0, numProfiles * sizeof(T *));
+#endif
+    free(dataProfiles);
+    free(dataProfilePtrs);
+}
+
+Return<void> RadioImpl_1_6::setDataProfile(int32_t serial, const hidl_vec<DataProfileInfo>& profiles,
+                                       bool isRoaming) {
+#if VDBG
+    RLOGD("setDataProfile: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SET_DATA_PROFILE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    size_t num = profiles.size();
+    bool success = false;
+
+    if (s_vendorFunctions->version <= 14) {
+
+        RIL_DataProfileInfo *dataProfiles =
+            (RIL_DataProfileInfo *) calloc(num, sizeof(RIL_DataProfileInfo));
+
+        if (dataProfiles == NULL) {
+            RLOGE("Memory allocation failed for request %s",
+                    requestToString(pRI->pCI->requestNumber));
+            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+            return Void();
+        }
+
+        RIL_DataProfileInfo **dataProfilePtrs =
+            (RIL_DataProfileInfo **) calloc(num, sizeof(RIL_DataProfileInfo *));
+        if (dataProfilePtrs == NULL) {
+            RLOGE("Memory allocation failed for request %s",
+                    requestToString(pRI->pCI->requestNumber));
+            free(dataProfiles);
+            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+            return Void();
+        }
+
+        for (size_t i = 0; i < num; i++) {
+            dataProfilePtrs[i] = &dataProfiles[i];
+
+            success = copyHidlStringToRil(&dataProfiles[i].apn, profiles[i].apn, pRI, true);
+
+            const hidl_string &protocol =
+                    (isRoaming ? profiles[i].roamingProtocol : profiles[i].protocol);
+
+            if (success && !copyHidlStringToRil(&dataProfiles[i].protocol, protocol, pRI, true)) {
+                success = false;
+            }
+
+            if (success && !copyHidlStringToRil(&dataProfiles[i].user, profiles[i].user, pRI,
+                    true)) {
+                success = false;
+            }
+            if (success && !copyHidlStringToRil(&dataProfiles[i].password, profiles[i].password,
+                    pRI, true)) {
+                success = false;
+            }
+
+            if (!success) {
+                freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 4,
+                    &RIL_DataProfileInfo::apn, &RIL_DataProfileInfo::protocol,
+                    &RIL_DataProfileInfo::user, &RIL_DataProfileInfo::password);
+                return Void();
+            }
+
+            dataProfiles[i].profileId = (RIL_DataProfile) profiles[i].profileId;
+            dataProfiles[i].authType = (int) profiles[i].authType;
+            dataProfiles[i].type = (int) profiles[i].type;
+            dataProfiles[i].maxConnsTime = profiles[i].maxConnsTime;
+            dataProfiles[i].maxConns = profiles[i].maxConns;
+            dataProfiles[i].waitTime = profiles[i].waitTime;
+            dataProfiles[i].enabled = BOOL_TO_INT(profiles[i].enabled);
+        }
+
+        CALL_ONREQUEST(RIL_REQUEST_SET_DATA_PROFILE, dataProfilePtrs,
+                num * sizeof(RIL_DataProfileInfo *), pRI, mSlotId);
+
+        freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 4,
+                &RIL_DataProfileInfo::apn, &RIL_DataProfileInfo::protocol,
+                &RIL_DataProfileInfo::user, &RIL_DataProfileInfo::password);
+    } else {
+        RIL_DataProfileInfo_v15 *dataProfiles =
+            (RIL_DataProfileInfo_v15 *) calloc(num, sizeof(RIL_DataProfileInfo_v15));
+
+        if (dataProfiles == NULL) {
+            RLOGE("Memory allocation failed for request %s",
+                    requestToString(pRI->pCI->requestNumber));
+            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+            return Void();
+        }
+
+        RIL_DataProfileInfo_v15 **dataProfilePtrs =
+            (RIL_DataProfileInfo_v15 **) calloc(num, sizeof(RIL_DataProfileInfo_v15 *));
+        if (dataProfilePtrs == NULL) {
+            RLOGE("Memory allocation failed for request %s",
+                    requestToString(pRI->pCI->requestNumber));
+            free(dataProfiles);
+            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+            return Void();
+        }
+
+        for (size_t i = 0; i < num; i++) {
+            dataProfilePtrs[i] = &dataProfiles[i];
+
+            success = copyHidlStringToRil(&dataProfiles[i].apn, profiles[i].apn, pRI, true);
+            if (success && !copyHidlStringToRil(&dataProfiles[i].protocol, profiles[i].protocol,
+                    pRI)) {
+                success = false;
+            }
+            if (success && !copyHidlStringToRil(&dataProfiles[i].roamingProtocol,
+                    profiles[i].roamingProtocol, pRI, true)) {
+                success = false;
+            }
+            if (success && !copyHidlStringToRil(&dataProfiles[i].user, profiles[i].user, pRI,
+                    true)) {
+                success = false;
+            }
+            if (success && !copyHidlStringToRil(&dataProfiles[i].password, profiles[i].password,
+                    pRI, true)) {
+                success = false;
+            }
+            if (success && !copyHidlStringToRil(&dataProfiles[i].mvnoMatchData,
+                    profiles[i].mvnoMatchData, pRI, true)) {
+                success = false;
+            }
+
+            if (success && !convertMvnoTypeToString(profiles[i].mvnoType,
+                    dataProfiles[i].mvnoType)) {
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                success = false;
+            }
+
+            if (!success) {
+                freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 6,
+                    &RIL_DataProfileInfo_v15::apn, &RIL_DataProfileInfo_v15::protocol,
+                    &RIL_DataProfileInfo_v15::roamingProtocol, &RIL_DataProfileInfo_v15::user,
+                    &RIL_DataProfileInfo_v15::password, &RIL_DataProfileInfo_v15::mvnoMatchData);
+                return Void();
+            }
+
+            dataProfiles[i].profileId = (RIL_DataProfile) profiles[i].profileId;
+            dataProfiles[i].authType = (int) profiles[i].authType;
+            dataProfiles[i].type = (int) profiles[i].type;
+            dataProfiles[i].maxConnsTime = profiles[i].maxConnsTime;
+            dataProfiles[i].maxConns = profiles[i].maxConns;
+            dataProfiles[i].waitTime = profiles[i].waitTime;
+            dataProfiles[i].enabled = BOOL_TO_INT(profiles[i].enabled);
+            dataProfiles[i].supportedTypesBitmask = profiles[i].supportedApnTypesBitmap;
+            dataProfiles[i].bearerBitmask = profiles[i].bearerBitmap;
+            dataProfiles[i].mtu = profiles[i].mtu;
+        }
+
+        CALL_ONREQUEST(RIL_REQUEST_SET_DATA_PROFILE, dataProfilePtrs,
+                num * sizeof(RIL_DataProfileInfo_v15 *), pRI, mSlotId);
+
+        freeSetDataProfileData(num, dataProfiles, dataProfilePtrs, 6,
+                &RIL_DataProfileInfo_v15::apn, &RIL_DataProfileInfo_v15::protocol,
+                &RIL_DataProfileInfo_v15::roamingProtocol, &RIL_DataProfileInfo_v15::user,
+                &RIL_DataProfileInfo_v15::password, &RIL_DataProfileInfo_v15::mvnoMatchData);
+    }
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::requestShutdown(int32_t serial) {
+#if VDBG
+    RLOGD("requestShutdown: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SHUTDOWN);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getRadioCapability(int32_t serial) {
+#if VDBG
+    RLOGD("getRadioCapability: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_RADIO_CAPABILITY);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setRadioCapability(int32_t serial, const RadioCapability& rc) {
+#if VDBG
+    RLOGD("setRadioCapability: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_SET_RADIO_CAPABILITY);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_RadioCapability rilRc = {};
+
+    // TODO : set rilRc.version using HIDL version ?
+    rilRc.session = rc.session;
+    rilRc.phase = (int) rc.phase;
+    rilRc.rat = (int) rc.raf;
+    rilRc.status = (int) rc.status;
+    strlcpy(rilRc.logicalModemUuid, rc.logicalModemUuid.c_str(), sizeof(rilRc.logicalModemUuid));
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rilRc, sizeof(rilRc), pRI, mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::startLceService(int32_t serial, int32_t reportInterval, bool pullMode) {
+#if VDBG
+    RLOGD("startLceService: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_START_LCE, 2, reportInterval,
+            BOOL_TO_INT(pullMode));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::stopLceService(int32_t serial) {
+#if VDBG
+    RLOGD("stopLceService: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_STOP_LCE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::pullLceData(int32_t serial) {
+#if VDBG
+    RLOGD("pullLceData: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_PULL_LCEDATA);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getModemActivityInfo(int32_t serial) {
+#if VDBG
+    RLOGD("getModemActivityInfo: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_ACTIVITY_INFO);
+    return Void();
+}
+
+int prepareCarrierRestrictions(RIL_CarrierRestrictions &request, bool allAllowed,
+                               const hidl_vec<Carrier>& allowedList,
+                               const hidl_vec<Carrier>& excludedList,
+                               RequestInfo *pRI) {
+    RIL_Carrier *allowedCarriers = NULL;
+    RIL_Carrier *excludedCarriers = NULL;
+
+    request.len_allowed_carriers = allowedList.size();
+    allowedCarriers = (RIL_Carrier *)calloc(request.len_allowed_carriers, sizeof(RIL_Carrier));
+    if (allowedCarriers == NULL) {
+        RLOGE("prepareCarrierRestrictions: Memory allocation failed for request %s",
+                requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+        return -1;
+    }
+    request.allowed_carriers = allowedCarriers;
+
+    request.len_excluded_carriers = excludedList.size();
+    excludedCarriers = (RIL_Carrier *)calloc(request.len_excluded_carriers, sizeof(RIL_Carrier));
+    if (excludedCarriers == NULL) {
+        RLOGE("prepareCarrierRestrictions: Memory allocation failed for request %s",
+                requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+#ifdef MEMSET_FREED
+        memset(allowedCarriers, 0, request.len_allowed_carriers * sizeof(RIL_Carrier));
+#endif
+        free(allowedCarriers);
+        return -1;
+    }
+    request.excluded_carriers = excludedCarriers;
+
+    for (int i = 0; i < request.len_allowed_carriers; i++) {
+        allowedCarriers[i].mcc = allowedList[i].mcc.c_str();
+        allowedCarriers[i].mnc = allowedList[i].mnc.c_str();
+        allowedCarriers[i].match_type = (RIL_CarrierMatchType) allowedList[i].matchType;
+        allowedCarriers[i].match_data = allowedList[i].matchData.c_str();
+    }
+
+    for (int i = 0; i < request.len_excluded_carriers; i++) {
+        excludedCarriers[i].mcc = excludedList[i].mcc.c_str();
+        excludedCarriers[i].mnc = excludedList[i].mnc.c_str();
+        excludedCarriers[i].match_type =
+                (RIL_CarrierMatchType) excludedList[i].matchType;
+        excludedCarriers[i].match_data = excludedList[i].matchData.c_str();
+    }
+
+    return 0;
+}
+
+void freeCarrierRestrictions(RIL_CarrierRestrictions &request) {
+    if (request.allowed_carriers != NULL) {
+#ifdef MEMSET_FREED
+        memset(request.allowed_carriers, 0, request.len_allowed_carriers * sizeof(RIL_Carrier));
+#endif
+        free(request.allowed_carriers);
+    }
+    if (request.excluded_carriers != NULL) {
+#ifdef MEMSET_FREED
+        memset(request.excluded_carriers, 0, request.len_excluded_carriers * sizeof(RIL_Carrier));
+#endif
+        free(request.excluded_carriers);
+    }
+}
+
+Return<void> RadioImpl_1_6::setAllowedCarriers(int32_t serial, bool allAllowed,
+                                           const CarrierRestrictions& carriers) {
+#if VDBG
+    RLOGD("setAllowedCarriers: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_CARRIER_RESTRICTIONS);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CarrierRestrictions cr = {};
+    if (prepareCarrierRestrictions(cr, allAllowed, carriers.allowedCarriers,
+            carriers.excludedCarriers, pRI) < 0) {
+        return Void();
+    }
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &cr, sizeof(RIL_CarrierRestrictions), pRI, mSlotId);
+
+    freeCarrierRestrictions(cr);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getAllowedCarriers(int32_t serial) {
+#if VDBG
+    RLOGD("getAllowedCarriers: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CARRIER_RESTRICTIONS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendDeviceState(int32_t serial, DeviceStateType deviceStateType,
+                                        bool state) {
+#if VDBG
+    RLOGD("sendDeviceState: serial %d", serial);
+#endif
+    if (s_vendorFunctions->version < 15) {
+        if (deviceStateType ==  DeviceStateType::LOW_DATA_EXPECTED) {
+            RLOGD("sendDeviceState: calling screen state %d", BOOL_TO_INT(!state));
+            dispatchInts(serial, mSlotId, RIL_REQUEST_SCREEN_STATE, 1, BOOL_TO_INT(!state));
+        } else {
+            RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                    RIL_REQUEST_SEND_DEVICE_STATE);
+            sendErrorResponse(pRI, RIL_E_REQUEST_NOT_SUPPORTED);
+        }
+        return Void();
+    }
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SEND_DEVICE_STATE, 2, (int) deviceStateType,
+            BOOL_TO_INT(state));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setIndicationFilter(int32_t serial, int32_t indicationFilter) {
+#if VDBG
+    RLOGD("setIndicationFilter: serial %d", serial);
+#endif
+    if (s_vendorFunctions->version < 15) {
+        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER);
+        sendErrorResponse(pRI, RIL_E_REQUEST_NOT_SUPPORTED);
+        return Void();
+    }
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER, 1, indicationFilter);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setSimCardPower(int32_t serial, bool powerUp) {
+#if VDBG
+    RLOGD("setSimCardPower: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_SIM_CARD_POWER, 1, BOOL_TO_INT(powerUp));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setSimCardPower_1_1(int32_t serial, const V1_1::CardPowerState state) {
+#if VDBG
+    RLOGD("setSimCardPower_1_1: serial %d state %d", serial, state);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_SIM_CARD_POWER, 1, state);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setSimCardPower_1_6(int32_t serial, const V1_1::CardPowerState state) {
+#if VDBG
+    RLOGD("setSimCardPower_1_6: serial %d state %d", serial, state);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_SIM_CARD_POWER, 1, state);
+    mSimCardPowerState = state;
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCarrierInfoForImsiEncryption(int32_t serial,
+        const V1_1::ImsiEncryptionInfo& data) {
+#if VDBG
+    RLOGD("setCarrierInfoForImsiEncryption: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(
+            serial, mSlotId, RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CarrierInfoForImsiEncryption imsiEncryption = {};
+
+    if (!copyHidlStringToRil(&imsiEncryption.mnc, data.mnc, pRI)) {
+        return Void();
+    }
+    if (!copyHidlStringToRil(&imsiEncryption.mcc, data.mcc, pRI)) {
+        memsetAndFreeStrings(1, imsiEncryption.mnc);
+        return Void();
+    }
+    if (!copyHidlStringToRil(&imsiEncryption.keyIdentifier, data.keyIdentifier, pRI)) {
+        memsetAndFreeStrings(2, imsiEncryption.mnc, imsiEncryption.mcc);
+        return Void();
+    }
+    imsiEncryption.carrierKeyLength = data.carrierKey.size();
+    imsiEncryption.carrierKey = new uint8_t[imsiEncryption.carrierKeyLength];
+    memcpy(imsiEncryption.carrierKey, data.carrierKey.data(), imsiEncryption.carrierKeyLength);
+    imsiEncryption.expirationTime = data.expirationTime;
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &imsiEncryption,
+            sizeof(RIL_CarrierInfoForImsiEncryption), pRI, mSlotId);
+    delete(imsiEncryption.carrierKey);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::startKeepalive(int32_t serial, const V1_1::KeepaliveRequest& keepalive) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_KEEPALIVE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_KeepaliveRequest kaReq = {};
+
+    kaReq.type = static_cast<RIL_KeepaliveType>(keepalive.type);
+    switch(kaReq.type) {
+        case NATT_IPV4:
+            if (keepalive.sourceAddress.size() != 4 ||
+                    keepalive.destinationAddress.size() != 4) {
+                RLOGE("Invalid address for keepalive!");
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                return Void();
+            }
+            break;
+        case NATT_IPV6:
+            if (keepalive.sourceAddress.size() != 16 ||
+                    keepalive.destinationAddress.size() != 16) {
+                RLOGE("Invalid address for keepalive!");
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                return Void();
+            }
+            break;
+        default:
+            RLOGE("Unknown packet keepalive type!");
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            return Void();
+    }
+
+    ::memcpy(kaReq.sourceAddress, keepalive.sourceAddress.data(), keepalive.sourceAddress.size());
+    kaReq.sourcePort = keepalive.sourcePort;
+
+    ::memcpy(kaReq.destinationAddress,
+            keepalive.destinationAddress.data(), keepalive.destinationAddress.size());
+    kaReq.destinationPort = keepalive.destinationPort;
+
+    kaReq.maxKeepaliveIntervalMillis = keepalive.maxKeepaliveIntervalMillis;
+    kaReq.cid = keepalive.cid; // This is the context ID of the data call
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &kaReq, sizeof(RIL_KeepaliveRequest), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::stopKeepalive(int32_t serial, int32_t sessionHandle) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_STOP_KEEPALIVE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &sessionHandle, sizeof(uint32_t), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::responseAcknowledgement() {
+    android::releaseWakeLock();
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::V1_2::IRadio follow.
+int prepareNetworkScanRequest_1_2(RIL_NetworkScanRequest &scan_request,
+    const ::android::hardware::radio::V1_2::NetworkScanRequest& request,
+    RequestInfo *pRI) {
+
+    scan_request.type = (RIL_ScanType) request.type;
+    scan_request.interval = request.interval;
+    scan_request.specifiers_length = request.specifiers.size();
+
+    int intervalLow = static_cast<int>(::android::hardware::radio::V1_2::ScanIntervalRange::MIN);
+    int intervalHigh = static_cast<int>(::android::hardware::radio::V1_2::ScanIntervalRange::MAX);
+    int maxSearchTimeLow =
+        static_cast<int>(::android::hardware::radio::V1_2::MaxSearchTimeRange::MIN);
+    int maxSearchTimeHigh =
+        static_cast<int>(::android::hardware::radio::V1_2::MaxSearchTimeRange::MAX);
+    int incrementalResultsPeriodicityRangeLow =
+        static_cast<int>(::android::hardware::radio::V1_2::IncrementalResultsPeriodicityRange::MIN);
+    int incrementalResultsPeriodicityRangeHigh =
+        static_cast<int>(::android::hardware::radio::V1_2::IncrementalResultsPeriodicityRange::MAX);
+    uint maxSpecifierSize =
+        static_cast<uint>(::android::hardware::radio::V1_2::RadioConst
+            ::RADIO_ACCESS_SPECIFIER_MAX_SIZE);
+
+    if (request.interval < intervalLow || request.interval > intervalHigh) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+    // If defined, must fall in correct range.
+    if (request.maxSearchTime != 0
+        && (request.maxSearchTime < maxSearchTimeLow
+            || request.maxSearchTime > maxSearchTimeHigh)) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+    if (request.maxSearchTime != 0
+        && (request.incrementalResultsPeriodicity < incrementalResultsPeriodicityRangeLow
+            || request.incrementalResultsPeriodicity > incrementalResultsPeriodicityRangeHigh
+            || request.incrementalResultsPeriodicity > request.maxSearchTime)) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+    if (request.specifiers.size() == 0 || request.specifiers.size() > maxSpecifierSize) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+
+    for (size_t i = 0; i < request.specifiers.size(); ++i) {
+        if (request.specifiers[i].geranBands.size() > MAX_BANDS ||
+            request.specifiers[i].utranBands.size() > MAX_BANDS ||
+            request.specifiers[i].eutranBands.size() > MAX_BANDS ||
+            request.specifiers[i].channels.size() > MAX_CHANNELS) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            return -1;
+        }
+        const V1_1::RadioAccessSpecifier& ras_from =
+                request.specifiers[i];
+        RIL_RadioAccessSpecifier& ras_to = scan_request.specifiers[i];
+
+        ras_to.radio_access_network = (RIL_RadioAccessNetworks) ras_from.radioAccessNetwork;
+        ras_to.channels_length = ras_from.channels.size();
+
+        std::copy(ras_from.channels.begin(), ras_from.channels.end(), ras_to.channels);
+        const std::vector<uint32_t> * bands = nullptr;
+        switch (request.specifiers[i].radioAccessNetwork) {
+            case V1_1::RadioAccessNetworks::GERAN:
+                ras_to.bands_length = ras_from.geranBands.size();
+                bands = (std::vector<uint32_t> *) &ras_from.geranBands;
+                break;
+            case V1_1::RadioAccessNetworks::UTRAN:
+                ras_to.bands_length = ras_from.utranBands.size();
+                bands = (std::vector<uint32_t> *) &ras_from.utranBands;
+                break;
+            case V1_1::RadioAccessNetworks::EUTRAN:
+                ras_to.bands_length = ras_from.eutranBands.size();
+                bands = (std::vector<uint32_t> *) &ras_from.eutranBands;
+                break;
+            default:
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                return -1;
+        }
+        // safe to copy to geran_bands because it's a union member
+        for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
+            ras_to.bands.geran_bands[idx] = (RIL_GeranBands) (*bands)[idx];
+        }
+    }
+
+    return 0;
+}
+
+Return<void> RadioImpl_1_6::startNetworkScan_1_2(int32_t serial,
+        const ::android::hardware::radio::V1_2::NetworkScanRequest& request) {
+#if VDBG
+    RLOGD("startNetworkScan_1_2: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_NetworkScanRequest scan_request = {};
+
+    if (prepareNetworkScanRequest_1_2(scan_request, request, pRI) < 0) {
+        return Void();
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
+            mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setIndicationFilter_1_2(int32_t serial,
+        ::android::hardware::hidl_bitfield<V1_2::IndicationFilter> indicationFilter) {
+#if VDBG
+    RLOGD("setIndicationFilter_1_2: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER);
+    sendErrorResponse(pRI, RIL_E_SUCCESS);  // TODO: for vts
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setSignalStrengthReportingCriteria(int32_t serial,
+        int32_t hysteresisMs, int32_t hysteresisDb,
+        const hidl_vec<int32_t>& thresholdsDbm,
+        ::android::hardware::radio::V1_2::AccessNetwork  accessNetwork) {
+#if VDBG
+    RLOGD("setSignalStrengthReportingCriteria: %d", serial);
+#endif
+    RIL_Errno e;
+    if (radioService[mSlotId]->mRadioResponseV1_2 != NULL) {
+         RadioResponseInfo responseInfo = {};
+         if (hysteresisDb >= 10) {
+             e = RIL_E_INVALID_ARGUMENTS;
+         } else {
+             e = RIL_E_SUCCESS;
+         }
+         populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, e);
+         Return<void> retStatus
+                   = radioService[mSlotId]->mRadioResponseV1_2->setSignalStrengthReportingCriteriaResponse(responseInfo);
+         radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setIndicationFilterResponse: radioService[%d]->mRadioResponse == NULL",
+           mSlotId);
+    }
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setLinkCapacityReportingCriteria(int32_t serial,
+       int32_t hysteresisMs, int32_t hysteresisDlKbps, int32_t hysteresisUlKbps,
+       const hidl_vec<int32_t>& thresholdsDownlinkKbps,
+        const hidl_vec<int32_t>& thresholdsUplinkKbps,
+        V1_2::AccessNetwork accessNetwork) {
+#if VDBG
+    RLOGE("[%04d]< %s", serial, "Method is not implemented");
+    RLOGD("setLinkCapacityReportingCriteria: %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA);
+    if (pRI == NULL) {
+        return Void();
+    }
+    // TODO: for vts. hysteresisDlKbps and hysteresisUlKbps range not confirmed
+    if (hysteresisDlKbps >= 5000 || hysteresisUlKbps >= 1000) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return Void();
+    } else {
+        sendErrorResponse(pRI, RIL_E_SUCCESS);
+    }
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setupDataCall_1_2(int32_t serial, V1_2::AccessNetwork accessNetwork,
+        const V1_0::DataProfileInfo& dataProfileInfo, bool modemCognitive,
+        bool roamingAllowed, bool isRoaming, V1_2::DataRequestReason reason,
+        const hidl_vec<hidl_string>& addresses, const hidl_vec<hidl_string>& dnses) {
+#if VDBG
+    RLOGE("[%04d]< %s", serial, "Method is not implemented");
+    RLOGD("setupDataCall_1_2: serial %d", serial);
+#endif
+
+    if (s_vendorFunctions->version >= 4 && s_vendorFunctions->version <= 14) {
+        const hidl_string &protocol =
+                (isRoaming ? dataProfileInfo.roamingProtocol : dataProfileInfo.protocol);
+        dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 7,
+            std::to_string((int)accessNetwork).c_str(),
+            std::to_string((int)dataProfileInfo.profileId).c_str(),
+            dataProfileInfo.apn.c_str(),
+            dataProfileInfo.user.c_str(),
+            dataProfileInfo.password.c_str(),
+            std::to_string((int)dataProfileInfo.authType).c_str(),
+            protocol.c_str());
+    } else if (s_vendorFunctions->version >= 15) {
+        char *mvnoTypeStr = NULL;
+        if (!convertMvnoTypeToString(dataProfileInfo.mvnoType, mvnoTypeStr)) {
+            RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                    RIL_REQUEST_SETUP_DATA_CALL);
+            if (pRI != NULL) {
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            }
+            return Void();
+        }
+        dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 15,
+            std::to_string((int)accessNetwork).c_str(),
+            std::to_string((int)dataProfileInfo.profileId).c_str(),
+            dataProfileInfo.apn.c_str(),
+            dataProfileInfo.user.c_str(),
+            dataProfileInfo.password.c_str(),
+            std::to_string((int) dataProfileInfo.authType).c_str(),
+            dataProfileInfo.protocol.c_str(),
+            dataProfileInfo.roamingProtocol.c_str(),
+            std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
+            std::to_string(dataProfileInfo.bearerBitmap).c_str(),
+            modemCognitive ? "1" : "0",
+            std::to_string(dataProfileInfo.mtu).c_str(),
+            mvnoTypeStr,
+            dataProfileInfo.mvnoMatchData.c_str(),
+            roamingAllowed ? "1" : "0");
+    } else {
+        RLOGE("Unsupported RIL version %d, min version expected 4", s_vendorFunctions->version);
+        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                RIL_REQUEST_SETUP_DATA_CALL);
+        if (pRI != NULL) {
+            sendErrorResponse(pRI, RIL_E_REQUEST_NOT_SUPPORTED);
+        }
+    }
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::deactivateDataCall_1_2(int32_t serial, int32_t cid,
+        ::android::hardware::radio::V1_2::DataRequestReason reason) {
+#if VDBG
+    RLOGD("deactivateDataCall_1_2: serial %d", serial);
+#endif
+
+    RIL_DataRequestReason dataRequestReason = (RIL_DataRequestReason)reason;
+    const char *reasonStr = NULL;
+    switch (dataRequestReason) {
+        case DATA_REQ_REASOPN_NORMAL:
+            reasonStr = "normal";
+            break;
+        case DATA_REQ_REASOPN_SHUTDOWN:
+            reasonStr = "shutdown";
+            break;
+        case DATA_REQ_REASOPN_HANDOVER:
+            reasonStr = "handover";
+            break;
+        default:
+            reasonStr = "unknown";
+            break;
+    }
+
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_DEACTIVATE_DATA_CALL, false,
+            2, (std::to_string(cid)).c_str(), reasonStr);
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::V1_3::IRadio follow.
+Return<void> RadioImpl_1_6::setSystemSelectionChannels(int32_t serial, bool /* specifyChannels */,
+        const hidl_vec<::android::hardware::radio::V1_1::RadioAccessSpecifier>& /* specifiers */) {
+#if VDBG
+    RLOGD("setSystemSelectionChannels: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::enableModem(int32_t serial, bool /* on */) {
+#if VDBG
+    RLOGE("enableModem: serial = %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_ENABLE_MODEM);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getModemStackStatus(int32_t serial) {
+#if VDBG
+    RLOGD("getModemStackStatus: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_MODEM_STACK_STATUS);
+    return Void();
+}
+
+const char * getProtocolString(const ::android::hardware::radio::V1_4::PdpProtocolType protocolVal) {
+    switch(protocolVal) {
+        case ::android::hardware::radio::V1_4::PdpProtocolType::IP:
+            return "IP";
+        case ::android::hardware::radio::V1_4::PdpProtocolType::IPV6:
+            return "IPV6";
+        case ::android::hardware::radio::V1_4::PdpProtocolType::IPV4V6:
+            return "IPV4V6";
+        case ::android::hardware::radio::V1_4::PdpProtocolType::PPP:
+            return "PPP";
+        case ::android::hardware::radio::V1_4::PdpProtocolType::NON_IP:
+            return "NON_IP";
+        case ::android::hardware::radio::V1_4::PdpProtocolType::UNSTRUCTURED:
+            return "UNSTRUCTURED";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+// Methods from ::android::hardware::radio::V1_4::IRadio follow.
+Return<void> RadioImpl_1_6::setAllowedCarriers_1_4(int32_t  serial,
+        const V1_4::CarrierRestrictionsWithPriority& carriers,
+        V1_4::SimLockMultiSimPolicy multiSimPolicy) {
+#if VDBG
+    RLOGD("setAllowedCarriers_1_4: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_CARRIER_RESTRICTIONS);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    // Prepare legacy structure (defined in IRadio 1.0) to re-use existing code.
+    RIL_CarrierRestrictions cr = {};
+    if (prepareCarrierRestrictions(cr, false, carriers.allowedCarriers, carriers.excludedCarriers,
+            pRI) < 0) {
+        return Void();
+    }
+    // Copy the legacy structure into the new structure (defined in IRadio 1.4)
+    RIL_CarrierRestrictionsWithPriority crExt = {};
+    crExt.len_allowed_carriers = cr.len_allowed_carriers;
+    crExt.allowed_carriers = cr.allowed_carriers;
+    crExt.len_excluded_carriers = cr.len_excluded_carriers;
+    crExt.excluded_carriers = cr.excluded_carriers;
+    crExt.allowedCarriersPrioritized = BOOL_TO_INT(carriers.allowedCarriersPrioritized);
+    crExt.multiSimPolicy = (RIL_SimLockMultiSimPolicy)multiSimPolicy;
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &crExt, sizeof(RIL_CarrierRestrictionsWithPriority),
+            pRI, mSlotId);
+
+    freeCarrierRestrictions(cr);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getAllowedCarriers_1_4(int32_t serial) {
+#if VDBG
+    RLOGD("getAllowedCarriers_1_4: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_CARRIER_RESTRICTIONS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setupDataCall_1_4(int32_t serial ,
+        ::android::hardware::radio::V1_4::AccessNetwork /* accessNetwork */,
+        const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo,
+        bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
+        const hidl_vec<hidl_string>& /* addresses */, const hidl_vec<hidl_string>& /* dnses */) {
+
+#if VDBG
+    RLOGD("setupDataCall_1_4: serial %d", serial);
+#endif
+
+    char *mvnoTypeStr = NULL;
+    if (!convertMvnoTypeToString(MvnoType::IMSI, mvnoTypeStr)) {
+        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                RIL_REQUEST_SETUP_DATA_CALL);
+        if (pRI != NULL) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        }
+        return Void();
+    }
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 16,
+        std::to_string((int) RadioTechnology::UNKNOWN + 2).c_str(),
+        std::to_string((int) dataProfileInfo.profileId).c_str(),
+        dataProfileInfo.apn.c_str(),
+        dataProfileInfo.user.c_str(),
+        dataProfileInfo.password.c_str(),
+        std::to_string((int) dataProfileInfo.authType).c_str(),
+        getProtocolString(dataProfileInfo.protocol),
+        getProtocolString(dataProfileInfo.roamingProtocol),
+        std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
+        std::to_string(dataProfileInfo.bearerBitmap).c_str(),
+        dataProfileInfo.persistent ? "1" : "0",
+        std::to_string(dataProfileInfo.mtu).c_str(),
+        mvnoTypeStr,
+        "302720x94",
+        roamingAllowed ? "1" : "0",
+        "-1");
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setInitialAttachApn_1_4(int32_t  serial ,
+        const ::android::hardware::radio::V1_4::DataProfileInfo& dataProfileInfo) {
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_INITIAL_ATTACH_APN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
+
+    if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_4->setInitialAttachApnResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponse->setInitialAttachApnResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setInitialAttachApnResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
+    }
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setDataProfile_1_4(int32_t  serial ,
+        const hidl_vec<::android::hardware::radio::V1_4::DataProfileInfo>& /* profiles */) {
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_DATA_PROFILE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
+
+    if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_4->setDataProfileResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponse->setDataProfileResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setDataProfileResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
+    }
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::emergencyDial(int32_t serial,
+        const ::android::hardware::radio::V1_0::Dial& dialInfo,
+        hidl_bitfield<android::hardware::radio::V1_4::EmergencyServiceCategory> categories,
+        const hidl_vec<hidl_string>&  urns ,
+        ::android::hardware::radio::V1_4::EmergencyCallRouting routing,
+        bool fromEmergencyDialer, bool /* isTesting */) {
+#if VDBG
+    RLOGD("emergencyDial: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_EMERGENCY_DIAL);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_EmergencyDial eccDial = {};
+    RIL_Dial& dial = eccDial.dialInfo;
+    RIL_UUS_Info uusInfo = {};
+
+    if (!copyHidlStringToRil(&dial.address, dialInfo.address, pRI)) {
+        return Void();
+    }
+    dial.clir = (int) dialInfo.clir;
+
+    if (dialInfo.uusInfo.size() != 0) {
+        uusInfo.uusType = (RIL_UUS_Type) dialInfo.uusInfo[0].uusType;
+        uusInfo.uusDcs = (RIL_UUS_DCS) dialInfo.uusInfo[0].uusDcs;
+
+        if (dialInfo.uusInfo[0].uusData.size() == 0) {
+            uusInfo.uusData = NULL;
+            uusInfo.uusLength = 0;
+        } else {
+            if (!copyHidlStringToRil(&uusInfo.uusData, dialInfo.uusInfo[0].uusData, pRI)) {
+                memsetAndFreeStrings(1, dial.address);
+                return Void();
+            }
+            uusInfo.uusLength = dialInfo.uusInfo[0].uusData.size();
+        }
+
+        dial.uusInfo = &uusInfo;
+    }
+
+    eccDial.urnsNumber = urns.size();
+    if (eccDial.urnsNumber != 0) {
+        char **ppUrns = (char **)calloc(eccDial.urnsNumber, sizeof(char *));
+        if (ppUrns == NULL) {
+            RLOGE("Memory allocation failed for request %s",
+                    requestToString(pRI->pCI->requestNumber));
+            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+            memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
+            return Void();
+        }
+        for (uint32_t i = 0; i < eccDial.urnsNumber; i++) {
+            if (!copyHidlStringToRil(&ppUrns[i], hidl_string(urns[i]), pRI)) {
+                for (uint32_t j = 0; j < i; j++) {
+                    memsetAndFreeStrings(1, ppUrns[j]);
+                }
+                memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
+                free(ppUrns);
+                return Void();
+            }
+        }
+        eccDial.urns = ppUrns;
+    }
+
+    eccDial.categories = (RIL_EmergencyServiceCategory)categories;
+    eccDial.routing = (RIL_EmergencyCallRouting)routing;
+    eccDial.fromEmergencyDialer = fromEmergencyDialer;
+
+    CALL_ONREQUEST(RIL_REQUEST_EMERGENCY_DIAL, &eccDial, sizeof(RIL_EmergencyDial), pRI, mSlotId);
+
+    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
+    if (eccDial.urns != NULL) {
+        for (size_t i = 0; i < eccDial.urnsNumber; i++) {
+            memsetAndFreeStrings(1, eccDial.urns[i]);
+        }
+        free(eccDial.urns);
+    }
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::startNetworkScan_1_4(int32_t serial,
+        const ::android::hardware::radio::V1_2::NetworkScanRequest& request) {
+#if VDBG
+    RLOGD("startNetworkScan_1_4: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_NetworkScanRequest scan_request = {};
+
+    if (prepareNetworkScanRequest_1_2(scan_request, request, pRI) < 0) {
+        return Void();
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
+            mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getPreferredNetworkTypeBitmap(int32_t serial ) {
+#if VDBG
+    RLOGD("getPreferredNetworkTypeBitmap: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setPreferredNetworkTypeBitmap(
+        int32_t serial, hidl_bitfield<RadioAccessFamily> networkTypeBitmap) {
+#if VDBG
+    RLOGD("setPreferredNetworkTypeBitmap: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP, 1, networkTypeBitmap);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setAllowedNetworkTypesBitmap(
+        uint32_t serial, hidl_bitfield<RadioAccessFamily> networkTypeBitmap) {
+#if VDBG
+    RLOGD("setAllowedNetworkTypesBitmap: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP, 1, networkTypeBitmap);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getAllowedNetworkTypesBitmap(int32_t serial) {
+#if VDBG
+    RLOGD("getAllowedNetworkTypesBitmap: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getSignalStrength_1_4(int32_t serial) {
+#if VDBG
+    RLOGD("getSignalStrength_1_4: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SIGNAL_STRENGTH);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getSignalStrength_1_6(int32_t serial) {
+#if VDBG
+    RLOGD("getSignalStrength_1_6: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SIGNAL_STRENGTH);
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::V1_5::IRadio follow.
+Return<void> RadioImpl_1_6::setSignalStrengthReportingCriteria_1_5(int32_t serial,
+        const V1_5::SignalThresholdInfo& signalThresholdInfo,
+        V1_5::AccessNetwork accessNetwork) {
+#if VDBG
+    RLOGD("setSignalStrengthReportingCriteria_1_5: %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    if (signalThresholdInfo.hysteresisDb >= 10) {  // TODO: for vts. hysteresisDb range not checked
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    RIL_SignalStrengthReportingCriteria_v1_5 *criteria = (RIL_SignalStrengthReportingCriteria_v1_5 *)
+            calloc(1, sizeof(RIL_SignalStrengthReportingCriteria_v1_5));
+    if (criteria == NULL) {
+        RLOGE("Memory allocation failed for request %s",
+                requestToString(pRI->pCI->requestNumber));
+        sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+        return Void();
+    }
+
+    criteria->signalMeasurement = (SignalMeasurementType)signalThresholdInfo.signalMeasurement;
+    criteria->isEnabled = signalThresholdInfo.isEnabled;
+    criteria->hysteresisMs = signalThresholdInfo.hysteresisMs;
+    criteria->hysteresisDb = signalThresholdInfo.hysteresisDb;
+    criteria->thresholdsDbmNumber = signalThresholdInfo.thresholds.size();
+    criteria->thresholdsDbm = new int32_t[criteria->thresholdsDbmNumber];
+    memcpy(criteria->thresholdsDbm, signalThresholdInfo.thresholds.data(),
+            criteria->thresholdsDbmNumber * sizeof(int32_t));
+    criteria->accessNetwork = (RIL_RadioAccessNetworks_v1_5)accessNetwork;
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, criteria,
+            sizeof(RIL_SignalStrengthReportingCriteria_v1_5), pRI, mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setLinkCapacityReportingCriteria_1_5(int32_t serial,
+    int32_t hysteresisMs, int32_t hysteresisDlKbps, int32_t hysteresisUlKbps,
+     const hidl_vec<int32_t>& thresholdsDownlinkKbps,
+     const hidl_vec<int32_t>& thresholdsUplinkKbps,
+     V1_5::AccessNetwork accessNetwork) {
+#if VDBG
+ RLOGD("setLinkCapacityReportingCriteria_1_5: %d", serial);
+#endif
+
+     RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+             RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA);
+     if (pRI == NULL) {
+         return Void();
+     }
+     // TODO: for vts. hysteresisDlKbps and hysteresisUlKbps range not confirmed
+     if (hysteresisDlKbps >= 5000 || hysteresisUlKbps >= 1000) {
+         sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+         return Void();
+     }
+
+     RIL_LinkCapacityReportingCriteria *criteria = (RIL_LinkCapacityReportingCriteria *)
+             calloc(1, sizeof(RIL_LinkCapacityReportingCriteria));
+     if (criteria == NULL) {
+         RLOGE("Memory allocation failed for request %s",
+                 requestToString(pRI->pCI->requestNumber));
+         sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+         return Void();
+     }
+
+     criteria->hysteresisMs = hysteresisMs;
+     criteria->hysteresisDlKbps = hysteresisDlKbps;
+     criteria->hysteresisUlKbps = hysteresisUlKbps;
+     criteria->thresholdsDownlinkKbpsLength = thresholdsDownlinkKbps.size();
+     criteria->thresholdsUplinkKbpsLength = thresholdsUplinkKbps.size();
+     criteria->thresholdsDownlinkKbps = new int32_t[criteria->thresholdsDownlinkKbpsLength];
+     criteria->thresholdsUplinkKbps = new int32_t[criteria->thresholdsUplinkKbpsLength];
+     memcpy(criteria->thresholdsDownlinkKbps, thresholdsDownlinkKbps.data(),
+             criteria->thresholdsDownlinkKbpsLength * sizeof(int32_t));
+     memcpy(criteria->thresholdsUplinkKbps, thresholdsUplinkKbps.data(),
+             criteria->thresholdsUplinkKbpsLength * sizeof(int32_t));
+     criteria->accessNetwork = (RIL_RadioAccessNetworks_v1_5)accessNetwork;
+
+     CALL_ONREQUEST(pRI->pCI->requestNumber, criteria,
+             sizeof(RIL_LinkCapacityReportingCriteria), pRI, pRI->socket_id);
+
+     return Void();
+}
+
+Return<void> RadioImpl_1_6::enableUiccApplications(int32_t serial, bool enable) {
+#if VDBG
+    RLOGD("enableUiccApplications: serial %d enable %d", serial, enable);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_ENABLE_UICC_APPLICATIONS, 1, BOOL_TO_INT(enable));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+                                          bool preferredForEmergencyCall) {
+#if VDBG
+    RLOGD("setRadioPower_1_6: serial %d powerOn %d forEmergency %d preferredForEmergencyCall %d",
+        serial, powerOn, forEmergencyCall, preferredForEmergencyCall);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_RADIO_POWER, 1, BOOL_TO_INT(powerOn));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setRadioPower_1_6(int32_t serial, bool powerOn, bool forEmergencyCall,
+                                          bool preferredForEmergencyCall) {
+#if VDBG
+    RLOGD("setRadioPower_1_6: serial %d powerOn %d forEmergency %d preferredForEmergencyCall %d",
+        serial, powerOn, forEmergencyCall, preferredForEmergencyCall);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_RADIO_POWER, 1, BOOL_TO_INT(powerOn));
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::areUiccApplicationsEnabled(int32_t serial) {
+#if VDBG
+    RLOGD("areUiccApplicationsEnabled: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getVoiceRegistrationState_1_5(int32_t serial) {
+#if VDBG
+    RLOGD("getVoiceRegistrationState_1_5: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_VOICE_REGISTRATION_STATE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getDataRegistrationState_1_5(int32_t serial) {
+#if VDBG
+    RLOGD("getDataRegistrationState_1_5: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_REGISTRATION_STATE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getVoiceRegistrationState_1_6(int32_t serial) {
+#if VDBG
+    RLOGD("getVoiceRegistrationState_1_6: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_VOICE_REGISTRATION_STATE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getDataRegistrationState_1_6(int32_t serial) {
+#if VDBG
+    RLOGD("getDataRegistrationState_1_6: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_DATA_REGISTRATION_STATE);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setSystemSelectionChannels_1_5(int32_t serial,
+        bool specifyChannels, const hidl_vec<V1_5::RadioAccessSpecifier>& specifiers) {
+
+#if VDBG
+RLOGD("setSystemSelectionChannels_1_5: %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                  RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS);
+    if (pRI == NULL) {
+      return Void();
+    }
+
+    if (specifiers.size() > RIL_RADIO_ACCESS_SPECIFIER_MAX_SIZE) {
+      sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+      return Void();
+    }
+
+    RIL_SystemSelectionChannels_v1_5 *sysSelectionChannels =
+          (RIL_SystemSelectionChannels_v1_5 *)calloc(1, sizeof(RIL_SystemSelectionChannels_v1_5));
+    if (sysSelectionChannels == NULL) {
+      RLOGE("Memory allocation failed for request %s",
+              requestToString(pRI->pCI->requestNumber));
+      sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+      return Void();
+    }
+    sysSelectionChannels->specifyChannels = specifyChannels;
+    sysSelectionChannels->specifiers_length = specifiers.size();
+    for (size_t i = 0; i < specifiers.size(); ++i) {
+      const V1_5::RadioAccessSpecifier& ras_from = specifiers[i];
+      RIL_RadioAccessSpecifier_v1_5 &ras_to = sysSelectionChannels->specifiers[i];
+
+      ras_to.radio_access_network = (RIL_RadioAccessNetworks_v1_5)ras_from.radioAccessNetwork;
+      ras_to.channels_length = ras_from.channels.size();
+
+      std::copy(ras_from.channels.begin(), ras_from.channels.end(), ras_to.channels);
+      const std::vector<uint32_t> * bands = nullptr;
+      switch (specifiers[i].radioAccessNetwork) {
+          case V1_5::RadioAccessNetworks::GERAN:
+              ras_to.bands_length = ras_from.bands.geranBands().size();
+              bands = (std::vector<uint32_t> *) &ras_from.bands.geranBands();
+              break;
+          case V1_5::RadioAccessNetworks::UTRAN:
+              ras_to.bands_length = ras_from.bands.utranBands().size();
+              bands = (std::vector<uint32_t> *) &ras_from.bands.utranBands();
+              break;
+          case V1_5::RadioAccessNetworks::EUTRAN:
+              ras_to.bands_length = ras_from.bands.eutranBands().size();
+              bands = (std::vector<uint32_t> *) &ras_from.bands.eutranBands();
+              break;
+          case V1_5::RadioAccessNetworks::NGRAN:
+              ras_to.bands_length = ras_from.bands.ngranBands().size();
+              bands = (std::vector<uint32_t> *) &ras_from.bands.ngranBands();
+              break;
+          default: {
+              sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+              free(sysSelectionChannels);
+              return Void();
+          }
+      }
+      // safe to copy to geran_bands because it's a union member
+      for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
+          ras_to.bands.geran_bands[idx] = (RIL_GeranBands)(*bands)[idx];
+      }
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS, sysSelectionChannels,
+          sizeof(RIL_SystemSelectionChannels_v1_5), pRI, mSlotId);
+
+    return Void();
+}
+
+int prepareNetworkScanRequest_1_5(RIL_NetworkScanRequest_v1_5 &scan_request,
+        const V1_5::NetworkScanRequest& request, RequestInfo *pRI) {
+    scan_request.type = (RIL_ScanType) request.type;
+    scan_request.interval = request.interval;
+    scan_request.specifiers_length = request.specifiers.size();
+    scan_request.maxSearchTime = request.maxSearchTime;
+    scan_request.incrementalResults = request.incrementalResults;
+    scan_request.incrementalResultsPeriodicity = request.incrementalResultsPeriodicity;
+    scan_request.mccMncsNumbers = request.mccMncs.size();
+
+    int intervalLow = static_cast<int>(V1_2::ScanIntervalRange::MIN);
+    int intervalHigh = static_cast<int>(V1_2::ScanIntervalRange::MAX);
+    int maxSearchTimeLow = static_cast<int>(V1_2::MaxSearchTimeRange::MIN);
+    int maxSearchTimeHigh = static_cast<int>(V1_2::MaxSearchTimeRange::MAX);
+    int incrementalResultsPeriodicityRangeLow =
+            static_cast<int>(V1_2::IncrementalResultsPeriodicityRange::MIN);
+    int incrementalResultsPeriodicityRangeHigh =
+            static_cast<int>(V1_2::IncrementalResultsPeriodicityRange::MAX);
+    uint maxSpecifierSize = static_cast<uint>(V1_2::RadioConst::RADIO_ACCESS_SPECIFIER_MAX_SIZE);
+
+    if (request.interval < intervalLow || request.interval > intervalHigh) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+    // If defined, must fall in correct range.
+    if (request.maxSearchTime != 0 && (request.maxSearchTime < maxSearchTimeLow
+            || request.maxSearchTime > maxSearchTimeHigh)) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+    if (request.maxSearchTime != 0
+            && (request.incrementalResultsPeriodicity < incrementalResultsPeriodicityRangeLow
+            || request.incrementalResultsPeriodicity > incrementalResultsPeriodicityRangeHigh
+            || request.incrementalResultsPeriodicity > request.maxSearchTime)) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+    if (request.specifiers.size() == 0 || request.specifiers.size() > maxSpecifierSize) {
+        sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        return -1;
+    }
+
+    for (size_t i = 0; i < request.specifiers.size(); ++i) {
+        if (request.specifiers[i].channels.size() > MAX_CHANNELS) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            return -1;
+        }
+        switch (request.specifiers[i].bands.getDiscriminator()) {
+            case V1_5::RadioAccessSpecifier::Bands::hidl_discriminator::geranBands:
+                if (request.specifiers[i].bands.geranBands().size() > MAX_BANDS) {
+                  sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                  return -1;
+                }
+                break;
+            case V1_5::RadioAccessSpecifier::Bands::hidl_discriminator::utranBands:
+                if (request.specifiers[i].bands.utranBands().size() > MAX_BANDS) {
+                  sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                  return -1;
+                }
+                break;
+            case V1_5::RadioAccessSpecifier::Bands::hidl_discriminator::eutranBands:
+                if (request.specifiers[i].bands.eutranBands().size() > MAX_BANDS) {
+                  sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                  return -1;
+                }
+                break;
+            case V1_5::RadioAccessSpecifier::Bands::hidl_discriminator::ngranBands:
+                if (request.specifiers[i].bands.ngranBands().size() > MAX_BANDS) {
+                  sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                  return -1;
+                }
+                break;
+            default:
+              sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+              return -1;
+        }
+
+        if (request.specifiers[i].channels.size() > MAX_CHANNELS) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+            return -1;
+        }
+
+        const V1_5::RadioAccessSpecifier& ras_from = request.specifiers[i];
+        RIL_RadioAccessSpecifier_v1_5& ras_to = scan_request.specifiers[i];
+
+        ras_to.radio_access_network = (RIL_RadioAccessNetworks_v1_5) ras_from.radioAccessNetwork;
+        ras_to.channels_length = ras_from.channels.size();
+
+        std::copy(ras_from.channels.begin(), ras_from.channels.end(), ras_to.channels);
+        const std::vector<uint32_t> * bands = nullptr;
+        switch (request.specifiers[i].radioAccessNetwork) {
+            case V1_5::RadioAccessNetworks::GERAN:
+                ras_to.bands_length = ras_from.bands.geranBands().size();
+
+                bands = (std::vector<uint32_t> *) &ras_from.bands.geranBands();
+                // safe to copy to geran_bands because it's a union member
+                for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
+                    ras_to.bands.geran_bands[idx] = (RIL_GeranBands) (*bands)[idx];
+                }
+                break;
+            case V1_5::RadioAccessNetworks::UTRAN:
+                ras_to.bands_length = ras_from.bands.utranBands().size();
+                bands = (std::vector<uint32_t> *) &ras_from.bands;
+                // safe to copy to geran_bands because it's a union member
+                for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
+                    ras_to.bands.utran_bands[idx] = (RIL_UtranBands) (*bands)[idx];
+                }
+                break;
+            case V1_5::RadioAccessNetworks::EUTRAN:
+                ras_to.bands_length = ras_from.bands.eutranBands().size();
+                bands = (std::vector<uint32_t> *) &ras_from.bands;
+                // safe to copy to geran_bands because it's a union member
+                for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
+                    ras_to.bands.eutran_bands[idx] = (RIL_EutranBands) (*bands)[idx];
+                }
+                break;
+            case V1_5::RadioAccessNetworks::NGRAN:
+                ras_to.bands_length = ras_from.bands.ngranBands().size();
+                bands = (std::vector<uint32_t> *) &ras_from.bands;
+                // safe to copy to geran_bands because it's a union member
+                for (size_t idx = 0; idx < ras_to.bands_length; ++idx) {
+                    ras_to.bands.ngran_bands[idx] = (RIL_NgranBands) (*bands)[idx];
+                }
+                break;
+            default:
+                sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+                return -1;
+        }
+    }
+    if (scan_request.mccMncsNumbers != 0) {
+        char **pStrings = (char **)calloc(scan_request.mccMncsNumbers, sizeof(char *));
+        if (pStrings == NULL) {
+            RLOGE("Memory allocation failed for request %s",
+                    requestToString(pRI->pCI->requestNumber));
+            sendErrorResponse(pRI, RIL_E_NO_MEMORY);
+            return -1;
+        }
+        for (size_t i = 0; i < request.mccMncs.size(); ++i) {
+            if (!copyHidlStringToRil(&pStrings[i], hidl_string(request.mccMncs[i]), pRI)) {
+                for (size_t j = 0; j < i; j++) {
+                    memsetAndFreeStrings(1, pStrings[j]);
+                }
+                free(pStrings);
+                return -1;
+            }
+        }
+        scan_request.mccMncs = pStrings;
+    }
+    return 0;
+}
+
+Return<void> RadioImpl_1_6::startNetworkScan_1_5(int32_t serial,
+        const ::android::hardware::radio::V1_5::NetworkScanRequest& request) {
+#if VDBG
+    RLOGD("startNetworkScan_1_6: serial %d", serial);
+#endif
+
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_START_NETWORK_SCAN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_NetworkScanRequest_v1_5 scan_request = {};
+
+    if (prepareNetworkScanRequest_1_5(scan_request, request, pRI) < 0) {
+        return Void();
+    }
+
+    CALL_ONREQUEST(RIL_REQUEST_START_NETWORK_SCAN, &scan_request, sizeof(scan_request), pRI,
+            mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setupDataCall_1_5(int32_t serial ,
+        ::android::hardware::radio::V1_5::AccessNetwork /* accessNetwork */,
+        const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
+        bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
+        const hidl_vec<::android::hardware::radio::V1_5::LinkAddress>& /* addresses */,
+        const hidl_vec<hidl_string>& /* dnses */) {
+
+#if VDBG
+    RLOGD("setupDataCall_1_5: serial %d", serial);
+#endif
+
+    char *mvnoTypeStr = NULL;
+    if (!convertMvnoTypeToString(MvnoType::IMSI, mvnoTypeStr)) {
+        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                RIL_REQUEST_SETUP_DATA_CALL);
+        if (pRI != NULL) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        }
+        return Void();
+    }
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 15,
+        std::to_string((int) RadioTechnology::UNKNOWN + 2).c_str(),
+        std::to_string((int) dataProfileInfo.profileId).c_str(),
+        dataProfileInfo.apn.c_str(),
+        dataProfileInfo.user.c_str(),
+        dataProfileInfo.password.c_str(),
+        std::to_string((int) dataProfileInfo.authType).c_str(),
+        getProtocolString(dataProfileInfo.protocol),
+        getProtocolString(dataProfileInfo.roamingProtocol),
+        std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
+        std::to_string(dataProfileInfo.bearerBitmap).c_str(),
+        dataProfileInfo.persistent ? "1" : "0",
+        std::to_string(dataProfileInfo.mtuV4).c_str(),
+        std::to_string(dataProfileInfo.mtuV6).c_str(),
+        mvnoTypeStr,
+        "302720x94",
+        roamingAllowed ? "1" : "0");
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setupDataCall_1_6(int32_t serial ,
+        ::android::hardware::radio::V1_5::AccessNetwork /* accessNetwork */,
+        const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
+        bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
+        const hidl_vec<::android::hardware::radio::V1_5::LinkAddress>& /* addresses */,
+        const hidl_vec<hidl_string>& /* dnses */,
+        int32_t /* pduSessionId */,
+        const ::android::hardware::radio::V1_6::OptionalSliceInfo& /* sliceInfo */,
+        const ::android::hardware::radio::V1_6::OptionalTrafficDescriptor& /*trafficDescriptor*/,
+        bool matchAllRuleAllowed) {
+
+#if VDBG
+    RLOGD("setupDataCall_1_6: serial %d", serial);
+#endif
+
+    char *mvnoTypeStr = NULL;
+    if (!convertMvnoTypeToString(MvnoType::IMSI, mvnoTypeStr)) {
+        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                RIL_REQUEST_SETUP_DATA_CALL);
+        if (pRI != NULL) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        }
+        return Void();
+    }
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 16,
+        std::to_string((int) RadioTechnology::UNKNOWN + 2).c_str(),
+        std::to_string((int) dataProfileInfo.profileId).c_str(),
+        dataProfileInfo.apn.c_str(),
+        dataProfileInfo.user.c_str(),
+        dataProfileInfo.password.c_str(),
+        std::to_string((int) dataProfileInfo.authType).c_str(),
+        getProtocolString(dataProfileInfo.protocol),
+        getProtocolString(dataProfileInfo.roamingProtocol),
+        std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
+        std::to_string(dataProfileInfo.bearerBitmap).c_str(),
+        dataProfileInfo.persistent ? "1" : "0",
+        std::to_string(dataProfileInfo.mtuV4).c_str(),
+        std::to_string(dataProfileInfo.mtuV6).c_str(),
+        mvnoTypeStr,
+        "302720x94",
+        roamingAllowed ? "1" : "0");
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setInitialAttachApn_1_5(int32_t  serial ,
+        const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo) {
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_INITIAL_ATTACH_APN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
+
+    if (radioService[mSlotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_5->setInitialAttachApnResponse(responseInfo);
+    } else if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_4->setInitialAttachApnResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponse->setInitialAttachApnResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setInitialAttachApnResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
+    }
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setDataProfile_1_5(int32_t  serial ,
+        const hidl_vec<::android::hardware::radio::V1_5::DataProfileInfo>& /* profiles */) {
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_DATA_PROFILE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
+
+    if (radioService[mSlotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_5->setDataProfileResponse(responseInfo);
+    } else if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_4->setDataProfileResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponse->setDataProfileResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setDataProfileResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
+    }
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setIndicationFilter_1_5(int32_t /* serial */,
+        hidl_bitfield<::android::hardware::radio::V1_5::IndicationFilter> /* indicationFilter */) {
+    // TODO implement
+#if VDBG
+    RLOGE("setIndicationFilter_1_5: Method is not implemented");
+#endif
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getBarringInfo(int32_t serial) {
+#if VDBG
+    RLOGD("getBarringInfo: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_BARRING_INFO);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setNetworkSelectionModeManual_1_5(int32_t serial,
+        const hidl_string& operatorNumeric, V1_5::RadioAccessNetworks ran) {
+#if VDBG
+    RLOGD("setNetworkSelectionModeManual_1_6: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+        RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_NetworkOperator networkOperator = {};
+
+    networkOperator.act = (RIL_RadioAccessNetworks)ran;
+    if (!copyHidlStringToRil(&networkOperator.operatorNumeric, operatorNumeric, pRI)) {
+        return Void();
+    }
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &networkOperator,
+        sizeof(networkOperator), pRI, mSlotId);
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::sendCdmaSmsExpectMore(int32_t serial, const CdmaSmsMessage& sms) {
+#if VDBG
+    RLOGD("sendCdmaSmsExpectMore: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CDMA_SMS_Message rcsm = {};
+    constructCdmaSms(rcsm, sms);
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsm, sizeof(rcsm), pRI, mSlotId);
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::V1_6::IRadio follow.
+Return<void> RadioImpl_1_6::sendCdmaSmsExpectMore_1_6(int32_t serial, const CdmaSmsMessage& sms) {
+#if VDBG
+    RLOGD("sendCdmaSmsExpectMore: serial %d", serial);
+#endif
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CDMA_SMS_Message rcsm = {};
+    constructCdmaSms(rcsm, sms);
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &rcsm, sizeof(rcsm), pRI, mSlotId);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::supplySimDepersonalization(int32_t serial,
+        V1_5::PersoSubstate persoType, const hidl_string& controlKey) {
+#if VDBG
+    RLOGD("supplySimDepersonalization: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION, true, 1,
+            controlKey.c_str());
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setNrDualConnectivityState(int32_t serial,
+        V1_6::NrDualConnectivityState nrDualConnectivityState) {
+#if VDBG
+    RLOGD("setNrDualConnectivityState: serial %d", serial);
+#endif
+    dispatchInts(serial, mSlotId, RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY, 1,
+            nrDualConnectivityState);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::isNrDualConnectivityEnabled(int32_t serial) {
+#if VDBG
+    RLOGD("isNrDualConnectivityEnabled: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::allocatePduSessionId(int32_t serial) {
+#if VDBG
+    RLOGD("allocatePduSessionId: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_ALLOCATE_PDU_SESSION_ID);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::releasePduSessionId(int32_t serial, int32_t id) {
+#if VDBG
+    RLOGD("releasePduSessionId: serial %d, pduSessionId: %d", serial, id);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_RELEASE_PDU_SESSION_ID);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::startHandover(int32_t serial, int32_t callId) {
+#if VDBG
+    RLOGD("startHandover: serial %d, callId: %d", serial, callId);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_START_HANDOVER);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::cancelHandover(int32_t serial, int32_t callId) {
+#if VDBG
+    RLOGD("cancelHandover: serial %d, callId: %d", serial, callId);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_CANCEL_HANDOVER);
+    return Void();
+}
+
+
+Return<void> RadioImpl_1_6::setDataThrottling(int32_t serial, V1_6::DataThrottlingAction dataThrottlingAction, int64_t completionDurationMillis) {
+   #if VDBG
+       RLOGD("OemHookImpl::sendRequestRaw: serial %d", serial);
+   #endif
+       dispatchInts(serial, mSlotId, RIL_REQUEST_SET_DATA_THROTTLING, 2,
+          dataThrottlingAction, completionDurationMillis);
+       return Void();
+}
+
+Return<void> RadioImpl_1_6::getSystemSelectionChannels(int32_t serial) {
+#if VDBG
+    RLOGD("getSystemSelectionChannels: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getSlicingConfig(int32_t serial) {
+#if VDBG
+    RLOGD("getSlicingConfig: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SLICING_CONFIG);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::setCarrierInfoForImsiEncryption_1_6(
+        int32_t serial, const V1_6::ImsiEncryptionInfo& data) {
+#if VDBG
+    RLOGD("setCarrierInfoForImsiEncryption_1_6: serial %d", serial);
+#endif
+    RequestInfo* pRI = android::addRequestToList(serial, mSlotId,
+                                                 RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RIL_CarrierInfoForImsiEncryption_v16 imsiEncryption = {};
+
+    if (!copyHidlStringToRil(&imsiEncryption.mnc, data.base.mnc, pRI)) {
+        return Void();
+    }
+    if (!copyHidlStringToRil(&imsiEncryption.mcc, data.base.mcc, pRI)) {
+        memsetAndFreeStrings(1, imsiEncryption.mnc);
+        return Void();
+    }
+    if (!copyHidlStringToRil(&imsiEncryption.keyIdentifier, data.base.keyIdentifier, pRI)) {
+        memsetAndFreeStrings(2, imsiEncryption.mnc, imsiEncryption.mcc);
+        return Void();
+    }
+    imsiEncryption.carrierKeyLength = data.base.carrierKey.size();
+    imsiEncryption.carrierKey = new uint8_t[imsiEncryption.carrierKeyLength];
+    memcpy(imsiEncryption.carrierKey, data.base.carrierKey.data(), imsiEncryption.carrierKeyLength);
+    imsiEncryption.expirationTime = data.base.expirationTime;
+    imsiEncryption.keyType = (RIL_PublicKeyType)data.keyType;
+
+    CALL_ONREQUEST(pRI->pCI->requestNumber, &imsiEncryption,
+                   sizeof(RIL_CarrierInfoForImsiEncryption_v16), pRI, mSlotId);
+    delete (imsiEncryption.carrierKey);
+    return Void();
+}
+
+
+Return<void> RadioImpl_1_6::getSimPhonebookRecords(int32_t serial) {
+#if VDBG
+    RLOGD("getSimPhonebookRecords: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::getSimPhonebookCapacity(int32_t serial) {
+#if VDBG
+    RLOGD("getSimPhonebookCapacity: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY);
+    return Void();
+}
+
+Return<void> RadioImpl_1_6::updateSimPhonebookRecords(
+    int32_t serial,
+    const ::android::hardware::radio::V1_6::PhonebookRecordInfo& recordInfo) {
+#if VDBG
+    RLOGD("updateSimPhonebookRecords: serial %d", serial);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORDS);
+    return Void();
+}
+
+
+// OEM hook methods:
+Return<void> OemHookImpl::setResponseFunctions(
+        const ::android::sp<IOemHookResponse>& oemHookResponseParam,
+        const ::android::sp<IOemHookIndication>& oemHookIndicationParam) {
+#if VDBG
+    RLOGD("OemHookImpl::setResponseFunctions");
+#endif
+
+    pthread_rwlock_t *radioServiceRwlockPtr = radio_1_6::getRadioServiceRwlock(mSlotId);
+    int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+
+    mOemHookResponse = oemHookResponseParam;
+    mOemHookIndication = oemHookIndicationParam;
+    mCounterOemHook[mSlotId]++;
+
+    ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+    assert(ret == 0);
+
+    return Void();
+}
+
+Return<void> OemHookImpl::sendRequestRaw(int32_t serial, const hidl_vec<uint8_t>& data) {
+#if VDBG
+    RLOGD("OemHookImpl::sendRequestRaw: serial %d", serial);
+#endif
+    dispatchRaw(serial, mSlotId, RIL_REQUEST_OEM_HOOK_RAW, data);
+    return Void();
+}
+
+Return<void> OemHookImpl::sendRequestStrings(int32_t serial,
+        const hidl_vec<hidl_string>& data) {
+#if VDBG
+    RLOGD("OemHookImpl::sendRequestStrings: serial %d", serial);
+#endif
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_OEM_HOOK_STRINGS, data);
+    return Void();
+}
+
+/***************************************************************************************************
+ * RESPONSE FUNCTIONS
+ * Functions above are used for requests going from framework to vendor code. The ones below are
+ * responses for those requests coming back from the vendor code.
+ **************************************************************************************************/
+
+void radio_1_6::acknowledgeRequest(int slotId, int serial) {
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->acknowledgeRequest(serial);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("acknowledgeRequest: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+}
+
+void populateResponseInfo(RadioResponseInfo& responseInfo, int serial, int responseType,
+                         RIL_Errno e) {
+    responseInfo.serial = serial;
+    switch (responseType) {
+        case RESPONSE_SOLICITED:
+            responseInfo.type = RadioResponseType::SOLICITED;
+            break;
+        case RESPONSE_SOLICITED_ACK_EXP:
+            responseInfo.type = RadioResponseType::SOLICITED_ACK_EXP;
+            break;
+    }
+    responseInfo.error = (RadioError) e;
+}
+
+void populateResponseInfo_1_6(
+    ::android::hardware::radio::V1_6::RadioResponseInfo &responseInfo,
+    int serial, int responseType, RIL_Errno e) {
+  responseInfo.serial = serial;
+  switch (responseType) {
+    case RESPONSE_SOLICITED:
+      responseInfo.type = RadioResponseType::SOLICITED;
+      break;
+    case RESPONSE_SOLICITED_ACK_EXP:
+      responseInfo.type = RadioResponseType::SOLICITED_ACK_EXP;
+      break;
+  }
+  responseInfo.error = (::android::hardware::radio::V1_6::RadioError)e;
+}
+
+int responseIntOrEmpty(RadioResponseInfo& responseInfo, int serial, int responseType, RIL_Errno e,
+               void *response, size_t responseLen) {
+    populateResponseInfo(responseInfo, serial, responseType, e);
+    int ret = -1;
+
+    if (response == NULL && responseLen == 0) {
+        // Earlier RILs did not send a response for some cases although the interface
+        // expected an integer as response. Do not return error if response is empty. Instead
+        // Return -1 in those cases to maintain backward compatibility.
+    } else if (response == NULL || responseLen != sizeof(int)) {
+        RLOGE("responseIntOrEmpty: Invalid response");
+        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+    } else {
+        int *p_int = (int *) response;
+        ret = p_int[0];
+    }
+    return ret;
+}
+
+int responseInt(RadioResponseInfo& responseInfo, int serial, int responseType, RIL_Errno e,
+               void *response, size_t responseLen) {
+    populateResponseInfo(responseInfo, serial, responseType, e);
+    int ret = -1;
+
+    if (response == NULL || responseLen != sizeof(int)) {
+        RLOGE("responseInt: Invalid response");
+        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+    } else {
+        int *p_int = (int *) response;
+        ret = p_int[0];
+    }
+    return ret;
+}
+
+int responseInt_1_6(::android::hardware::radio::V1_6::RadioResponseInfo &responseInfo, int serial, int responseType, RIL_Errno e,
+               void *response, size_t responseLen) {
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+    int ret = -1;
+
+    if (response == NULL || responseLen != sizeof(int)) {
+        RLOGE("responseInt_1_6: Invalid response");
+        if (e == RIL_E_SUCCESS) responseInfo.error = ::android::hardware::radio::V1_6::RadioError::INVALID_RESPONSE;
+    } else {
+        int *p_int = (int *) response;
+        ret = p_int[0];
+    }
+    return ret;
+}
+
+int radio_1_6::getIccCardStatusResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getIccCardStatusResponse: serial %d", serial);
+#endif
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL
+        || radioService[slotId]->mRadioResponseV1_4 != NULL
+        || radioService[slotId]->mRadioResponseV1_2 != NULL
+        || radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        CardStatus cardStatus = {CardState::ABSENT, PinState::UNKNOWN, -1, -1, -1, {}};
+        RIL_AppStatus *rilAppStatus = NULL;
+        RIL_CardStatus_v1_5 *p_cur = ((RIL_CardStatus_v1_5 *) response);
+        if (response == NULL || responseLen != sizeof(RIL_CardStatus_v1_5)
+                || p_cur->base.base.base.gsm_umts_subscription_app_index >= p_cur->base.base.base.num_applications
+                || p_cur->base.base.base.cdma_subscription_app_index >= p_cur->base.base.base.num_applications
+                || p_cur->base.base.base.ims_subscription_app_index >= p_cur->base.base.base.num_applications) {
+            RLOGE("getIccCardStatusResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            cardStatus.cardState = (CardState) p_cur->base.base.base.card_state;
+            cardStatus.universalPinState = (PinState) p_cur->base.base.base.universal_pin_state;
+            cardStatus.gsmUmtsSubscriptionAppIndex = p_cur->base.base.base.gsm_umts_subscription_app_index;
+            cardStatus.cdmaSubscriptionAppIndex = p_cur->base.base.base.cdma_subscription_app_index;
+            cardStatus.imsSubscriptionAppIndex = p_cur->base.base.base.ims_subscription_app_index;
+            rilAppStatus = p_cur->base.base.base.applications;
+            cardStatus.applications.resize(p_cur->base.base.base.num_applications);
+            AppStatus *appStatus = cardStatus.applications.data();
+#if VDBG
+            RLOGD("getIccCardStatusResponse: num_applications %d", p_cur->base.base.base.num_applications);
+#endif
+            for (int i = 0; i < p_cur->base.base.base.num_applications; i++) {
+                appStatus[i].appType = (AppType) rilAppStatus[i].app_type;
+                appStatus[i].appState = (AppState) rilAppStatus[i].app_state;
+                appStatus[i].persoSubstate = (PersoSubstate) rilAppStatus[i].perso_substate;
+                appStatus[i].aidPtr = convertCharPtrToHidlString(rilAppStatus[i].aid_ptr);
+                appStatus[i].appLabelPtr = convertCharPtrToHidlString(
+                        rilAppStatus[i].app_label_ptr);
+                appStatus[i].pin1Replaced = rilAppStatus[i].pin1_replaced;
+                appStatus[i].pin1 = (PinState) rilAppStatus[i].pin1;
+                appStatus[i].pin2 = (PinState) rilAppStatus[i].pin2;
+            }
+        }
+        if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+            ::android::hardware::radio::V1_2::CardStatus cardStatusV1_2;
+            ::android::hardware::radio::V1_4::CardStatus cardStatusV1_4;
+            ::android::hardware::radio::V1_5::CardStatus cardStatusV1_5;
+            cardStatusV1_2.base = cardStatus;
+            cardStatusV1_2.physicalSlotId = -1;
+            cardStatusV1_2.iccid = convertCharPtrToHidlString(p_cur->base.base.iccid);
+            cardStatusV1_4.base = cardStatusV1_2;
+            cardStatusV1_5.base = cardStatusV1_4;
+            cardStatusV1_5.applications.resize(p_cur->base.base.base.num_applications);
+            for (int i = 0; i < p_cur->base.base.base.num_applications; i++) {
+                cardStatusV1_5.applications[i].base.appType = (AppType) rilAppStatus[i].app_type;
+                cardStatusV1_5.applications[i].base.appState = (AppState) rilAppStatus[i].app_state;
+                cardStatusV1_5.applications[i].base.persoSubstate = (PersoSubstate) rilAppStatus[i].perso_substate;
+                cardStatusV1_5.applications[i].base.aidPtr = convertCharPtrToHidlString(rilAppStatus[i].aid_ptr);
+                cardStatusV1_5.applications[i].base.appLabelPtr = convertCharPtrToHidlString(
+                        rilAppStatus[i].app_label_ptr);
+                cardStatusV1_5.applications[i].base.pin1Replaced = rilAppStatus[i].pin1_replaced;
+                cardStatusV1_5.applications[i].base.pin1 = (PinState) rilAppStatus[i].pin1;
+                cardStatusV1_5.applications[i].base.pin2 = (PinState) rilAppStatus[i].pin2;
+                cardStatusV1_5.applications[i].persoSubstate = (V1_5::PersoSubstate)rilAppStatus[i].perso_substate;
+            }
+
+            // If POWER_DOWN then set applications to empty
+            if (radioService[slotId]->mSimCardPowerState == V1_1::CardPowerState::POWER_DOWN) {
+                RLOGD("getIccCardStatusResponse: state is POWER_DOWN so clearing apps");
+                cardStatusV1_5.applications = {};
+            }
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5->
+                    getIccCardStatusResponse_1_5(responseInfo, cardStatusV1_5);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+            ::android::hardware::radio::V1_2::CardStatus cardStatusV1_2;
+            ::android::hardware::radio::V1_4::CardStatus cardStatusV1_4;
+            cardStatusV1_2.base = cardStatus;
+            cardStatusV1_2.physicalSlotId = -1;
+            cardStatusV1_2.iccid = convertCharPtrToHidlString(p_cur->base.base.iccid);
+            cardStatusV1_4.base = cardStatusV1_2;
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->
+                    getIccCardStatusResponse_1_4(responseInfo, cardStatusV1_4);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else if (radioService[slotId]->mRadioResponseV1_3 != NULL) {
+            ::android::hardware::radio::V1_2::CardStatus cardStatusV1_2;
+            cardStatusV1_2.base = cardStatus;
+            cardStatusV1_2.physicalSlotId = -1;
+            cardStatusV1_2.iccid = convertCharPtrToHidlString(p_cur->base.base.iccid);
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_3->
+                    getIccCardStatusResponse_1_2(responseInfo, cardStatusV1_2);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
+            ::android::hardware::radio::V1_2::CardStatus cardStatusV1_2;
+            cardStatusV1_2.base = cardStatus;
+            cardStatusV1_2.physicalSlotId = -1;
+            cardStatusV1_2.iccid = convertCharPtrToHidlString(p_cur->base.base.iccid);
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2->
+                    getIccCardStatusResponse_1_2(responseInfo, cardStatusV1_2);
+            radioService[slotId]->checkReturnStatus(retStatus);
+            // TODO: add 1.1 if needed.
+        } else {
+            Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                    getIccCardStatusResponse(responseInfo, cardStatus);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        }
+    } else {
+        RLOGE("getIccCardStatusResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+    return 0;
+}
+
+int radio_1_6::supplyIccPinForAppResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("supplyIccPinForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                supplyIccPinForAppResponse(responseInfo, ret);
+        RLOGE("supplyIccPinForAppResponse: amit ret %d", ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("supplyIccPinForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::supplyIccPukForAppResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("supplyIccPukForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->supplyIccPukForAppResponse(
+                responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("supplyIccPukForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::supplyIccPin2ForAppResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("supplyIccPin2ForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                supplyIccPin2ForAppResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("supplyIccPin2ForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::supplyIccPuk2ForAppResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("supplyIccPuk2ForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                supplyIccPuk2ForAppResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("supplyIccPuk2ForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::changeIccPinForAppResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("changeIccPinForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                changeIccPinForAppResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("changeIccPinForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::changeIccPin2ForAppResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("changeIccPin2ForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                changeIccPin2ForAppResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("changeIccPin2ForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::supplyNetworkDepersonalizationResponse(int slotId,
+                                                 int responseType, int serial, RIL_Errno e,
+                                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("supplyNetworkDepersonalizationResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                supplyNetworkDepersonalizationResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("supplyNetworkDepersonalizationResponse: radioService[%d]->mRadioResponse == "
+                "NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCurrentCallsResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getCurrentCallsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        hidl_vec<Call> calls;
+        if ((response == NULL && responseLen != 0)
+                || (responseLen % sizeof(RIL_Call *)) != 0) {
+            RLOGE("getCurrentCallsResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int num = responseLen / sizeof(RIL_Call *);
+            calls.resize(num);
+
+            for (int i = 0 ; i < num ; i++) {
+                RIL_Call *p_cur = ((RIL_Call **) response)[i];
+                /* each call info */
+                calls[i].state = (CallState) p_cur->state;
+                calls[i].index = p_cur->index;
+                calls[i].toa = p_cur->toa;
+                calls[i].isMpty = p_cur->isMpty;
+                calls[i].isMT = p_cur->isMT;
+                calls[i].als = p_cur->als;
+                calls[i].isVoice = p_cur->isVoice;
+                calls[i].isVoicePrivacy = p_cur->isVoicePrivacy;
+                calls[i].number = convertCharPtrToHidlString(p_cur->number);
+                calls[i].numberPresentation = (CallPresentation) p_cur->numberPresentation;
+                calls[i].name = convertCharPtrToHidlString(p_cur->name);
+                calls[i].namePresentation = (CallPresentation) p_cur->namePresentation;
+                if (p_cur->uusInfo != NULL && p_cur->uusInfo->uusData != NULL) {
+                    RIL_UUS_Info *uusInfo = p_cur->uusInfo;
+                    calls[i].uusInfo.resize(1);
+                    calls[i].uusInfo[0].uusType = (UusType) uusInfo->uusType;
+                    calls[i].uusInfo[0].uusDcs = (UusDcs) uusInfo->uusDcs;
+                    // convert uusInfo->uusData to a null-terminated string
+                    char *nullTermStr = strndup(uusInfo->uusData, uusInfo->uusLength);
+                    calls[i].uusInfo[0].uusData = nullTermStr;
+                    free(nullTermStr);
+                }
+            }
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                getCurrentCallsResponse(responseInfo, calls);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getCurrentCallsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::dialResponse(int slotId,
+                       int responseType, int serial, RIL_Errno e, void *response,
+                       size_t responseLen) {
+#if VDBG
+    RLOGD("dialResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->dialResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("dialResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getIMSIForAppResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e, void *response,
+                                size_t responseLen) {
+#if VDBG
+    RLOGD("getIMSIForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getIMSIForAppResponse(
+                responseInfo, convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getIMSIForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::hangupConnectionResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("hangupConnectionResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->hangupConnectionResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("hangupConnectionResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::hangupWaitingOrBackgroundResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("hangupWaitingOrBackgroundResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus =
+                radioService[slotId]->mRadioResponse->hangupWaitingOrBackgroundResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("hangupWaitingOrBackgroundResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::hangupForegroundResumeBackgroundResponse(int slotId, int responseType, int serial,
+                                                    RIL_Errno e, void *response,
+                                                    size_t responseLen) {
+#if VDBG
+    RLOGD("hangupWaitingOrBackgroundResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus =
+                radioService[slotId]->mRadioResponse->hangupWaitingOrBackgroundResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("hangupWaitingOrBackgroundResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::switchWaitingOrHoldingAndActiveResponse(int slotId, int responseType, int serial,
+                                                   RIL_Errno e, void *response,
+                                                   size_t responseLen) {
+#if VDBG
+    RLOGD("switchWaitingOrHoldingAndActiveResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus =
+                radioService[slotId]->mRadioResponse->switchWaitingOrHoldingAndActiveResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("switchWaitingOrHoldingAndActiveResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::conferenceResponse(int slotId, int responseType,
+                             int serial, RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("conferenceResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->conferenceResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("conferenceResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::rejectCallResponse(int slotId, int responseType,
+                             int serial, RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("rejectCallResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->rejectCallResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("rejectCallResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getLastCallFailCauseResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e, void *response,
+                                       size_t responseLen) {
+#if VDBG
+    RLOGD("getLastCallFailCauseResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        LastCallFailCauseInfo info = {};
+        info.vendorCause = hidl_string();
+        if (response == NULL) {
+            RLOGE("getCurrentCallsResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else if (responseLen == sizeof(int)) {
+            int *pInt = (int *) response;
+            info.causeCode = (LastCallFailCause) pInt[0];
+        } else if (responseLen == sizeof(RIL_LastCallFailCauseInfo))  {
+            RIL_LastCallFailCauseInfo *pFailCauseInfo = (RIL_LastCallFailCauseInfo *) response;
+            info.causeCode = (LastCallFailCause) pFailCauseInfo->cause_code;
+            info.vendorCause = convertCharPtrToHidlString(pFailCauseInfo->vendor_cause);
+        } else {
+            RLOGE("getCurrentCallsResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getLastCallFailCauseResponse(
+                responseInfo, info);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getLastCallFailCauseResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getSignalStrengthResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSignalStrengthResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        ::android::hardware::radio::V1_4::SignalStrength signalStrength_1_4 = {};
+        if (response == NULL || responseLen != sizeof(RIL_SignalStrength_v12)) {
+            RLOGE("getSignalStrengthResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            convertRilSignalStrengthToHal_1_4(response, responseLen, signalStrength_1_4);
+        }
+
+        //TODO: future implementation needs to fill tdScdma, wcdma and nr signal strength.
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->
+                getSignalStrengthResponse_1_4(responseInfo, signalStrength_1_4);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        SignalStrength signalStrength = {};
+        if (response == NULL || responseLen != sizeof(RIL_SignalStrength_v12)) {
+            RLOGE("getSignalStrengthResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            convertRilSignalStrengthToHal(response, responseLen, signalStrength);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getSignalStrengthResponse(
+                responseInfo, signalStrength);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getSignalStrengthResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+RIL_CellInfoType getCellInfoTypeRadioTechnology(char *rat) {
+    if (rat == NULL) {
+        return RIL_CELL_INFO_TYPE_NONE;
+    }
+
+    int radioTech = atoi(rat);
+
+    switch(radioTech) {
+
+        case RADIO_TECH_GPRS:
+        case RADIO_TECH_EDGE:
+        case RADIO_TECH_GSM: {
+            return RIL_CELL_INFO_TYPE_GSM;
+        }
+
+        case RADIO_TECH_UMTS:
+        case RADIO_TECH_HSDPA:
+        case RADIO_TECH_HSUPA:
+        case RADIO_TECH_HSPA:
+        case RADIO_TECH_HSPAP: {
+            return RIL_CELL_INFO_TYPE_WCDMA;
+        }
+
+        case RADIO_TECH_IS95A:
+        case RADIO_TECH_IS95B:
+        case RADIO_TECH_1xRTT:
+        case RADIO_TECH_EVDO_0:
+        case RADIO_TECH_EVDO_A:
+        case RADIO_TECH_EVDO_B:
+        case RADIO_TECH_EHRPD: {
+            return RIL_CELL_INFO_TYPE_CDMA;
+        }
+
+        case RADIO_TECH_LTE:
+        case RADIO_TECH_LTE_CA: {
+            return RIL_CELL_INFO_TYPE_LTE;
+        }
+
+        case RADIO_TECH_TD_SCDMA: {
+            return RIL_CELL_INFO_TYPE_TD_SCDMA;
+        }
+
+        default: {
+            break;
+        }
+    }
+
+    return RIL_CELL_INFO_TYPE_NONE;
+
+}
+
+void fillCellIdentityResponse(CellIdentity &cellIdentity, RIL_CellIdentity_v16 &rilCellIdentity) {
+
+    cellIdentity.cellIdentityGsm.resize(0);
+    cellIdentity.cellIdentityWcdma.resize(0);
+    cellIdentity.cellIdentityCdma.resize(0);
+    cellIdentity.cellIdentityTdscdma.resize(0);
+    cellIdentity.cellIdentityLte.resize(0);
+    cellIdentity.cellInfoType = (CellInfoType)rilCellIdentity.cellInfoType;
+    switch(rilCellIdentity.cellInfoType) {
+
+        case RIL_CELL_INFO_TYPE_GSM: {
+            cellIdentity.cellIdentityGsm.resize(1);
+            cellIdentity.cellIdentityGsm[0].mcc =
+                    std::to_string(rilCellIdentity.cellIdentityGsm.mcc);
+            cellIdentity.cellIdentityGsm[0].mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityGsm.mnc);
+            cellIdentity.cellIdentityGsm[0].lac = rilCellIdentity.cellIdentityGsm.lac;
+            cellIdentity.cellIdentityGsm[0].cid = rilCellIdentity.cellIdentityGsm.cid;
+            cellIdentity.cellIdentityGsm[0].arfcn = rilCellIdentity.cellIdentityGsm.arfcn;
+            cellIdentity.cellIdentityGsm[0].bsic = rilCellIdentity.cellIdentityGsm.bsic;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            cellIdentity.cellIdentityWcdma.resize(1);
+            cellIdentity.cellIdentityWcdma[0].mcc =
+                    std::to_string(rilCellIdentity.cellIdentityWcdma.mcc);
+            cellIdentity.cellIdentityWcdma[0].mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityWcdma.mnc);
+            cellIdentity.cellIdentityWcdma[0].lac = rilCellIdentity.cellIdentityWcdma.lac;
+            cellIdentity.cellIdentityWcdma[0].cid = rilCellIdentity.cellIdentityWcdma.cid;
+            cellIdentity.cellIdentityWcdma[0].psc = rilCellIdentity.cellIdentityWcdma.psc;
+            cellIdentity.cellIdentityWcdma[0].uarfcn = rilCellIdentity.cellIdentityWcdma.uarfcn;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_CDMA: {
+            cellIdentity.cellIdentityCdma.resize(1);
+            cellIdentity.cellIdentityCdma[0].networkId = rilCellIdentity.cellIdentityCdma.networkId;
+            cellIdentity.cellIdentityCdma[0].systemId = rilCellIdentity.cellIdentityCdma.systemId;
+            cellIdentity.cellIdentityCdma[0].baseStationId =
+                    rilCellIdentity.cellIdentityCdma.basestationId;
+            cellIdentity.cellIdentityCdma[0].longitude = rilCellIdentity.cellIdentityCdma.longitude;
+            cellIdentity.cellIdentityCdma[0].latitude = rilCellIdentity.cellIdentityCdma.latitude;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_LTE: {
+            cellIdentity.cellIdentityLte.resize(1);
+            cellIdentity.cellIdentityLte[0].mcc =
+                    std::to_string(rilCellIdentity.cellIdentityLte.mcc);
+            cellIdentity.cellIdentityLte[0].mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityLte.mnc);
+            cellIdentity.cellIdentityLte[0].ci = rilCellIdentity.cellIdentityLte.ci;
+            cellIdentity.cellIdentityLte[0].pci = rilCellIdentity.cellIdentityLte.pci;
+            cellIdentity.cellIdentityLte[0].tac = rilCellIdentity.cellIdentityLte.tac;
+            cellIdentity.cellIdentityLte[0].earfcn = rilCellIdentity.cellIdentityLte.earfcn;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_TD_SCDMA: {
+            cellIdentity.cellIdentityTdscdma.resize(1);
+            cellIdentity.cellIdentityTdscdma[0].mcc =
+                    std::to_string(rilCellIdentity.cellIdentityTdscdma.mcc);
+            cellIdentity.cellIdentityTdscdma[0].mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityTdscdma.mnc);
+            cellIdentity.cellIdentityTdscdma[0].lac = rilCellIdentity.cellIdentityTdscdma.lac;
+            cellIdentity.cellIdentityTdscdma[0].cid = rilCellIdentity.cellIdentityTdscdma.cid;
+            cellIdentity.cellIdentityTdscdma[0].cpid = rilCellIdentity.cellIdentityTdscdma.cpid;
+            break;
+        }
+
+        default: {
+            break;
+        }
+    }
+}
+
+void fillCellIdentityResponse_1_5(V1_5::CellIdentity &cellIdentity,
+                                  RIL_CellIdentity_v16 &rilCellIdentity) {
+
+    switch (rilCellIdentity.cellInfoType) {
+        case RIL_CELL_INFO_TYPE_GSM: {
+            V1_5::CellIdentityGsm gsm;
+            gsm.base.base.mcc = std::to_string(rilCellIdentity.cellIdentityGsm.mcc);
+            gsm.base.base.mnc = ril::util::mnc::decode(rilCellIdentity.cellIdentityGsm.mnc);
+            if (gsm.base.base.mcc == "-1") {
+                gsm.base.base.mcc = "";
+            }
+            gsm.base.base.lac = rilCellIdentity.cellIdentityGsm.lac;
+            gsm.base.base.cid = rilCellIdentity.cellIdentityGsm.cid;
+            gsm.base.base.arfcn = rilCellIdentity.cellIdentityGsm.arfcn;
+            gsm.base.base.bsic = rilCellIdentity.cellIdentityGsm.bsic;
+            cellIdentity.gsm(gsm);
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            V1_5::CellIdentityWcdma wcdma;
+            wcdma.base.base.mcc = std::to_string(rilCellIdentity.cellIdentityGsm.mcc);
+            wcdma.base.base.mnc = ril::util::mnc::decode(rilCellIdentity.cellIdentityWcdma.mnc);
+            if (wcdma.base.base.mcc == "-1") {
+                wcdma.base.base.mcc = "";
+            }
+            wcdma.base.base.lac = rilCellIdentity.cellIdentityWcdma.lac;
+            wcdma.base.base.cid = rilCellIdentity.cellIdentityWcdma.cid;
+            wcdma.base.base.psc = rilCellIdentity.cellIdentityWcdma.psc;
+            wcdma.base.base.uarfcn = rilCellIdentity.cellIdentityWcdma.uarfcn;
+            cellIdentity.wcdma(wcdma);
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_CDMA: {
+            V1_2::CellIdentityCdma cdma;
+            cdma.base.networkId = rilCellIdentity.cellIdentityCdma.networkId;
+            cdma.base.systemId = rilCellIdentity.cellIdentityCdma.systemId;
+            cdma.base.baseStationId =
+                    rilCellIdentity.cellIdentityCdma.basestationId;
+            cdma.base.longitude = rilCellIdentity.cellIdentityCdma.longitude;
+            cdma.base.latitude = rilCellIdentity.cellIdentityCdma.latitude;
+            cellIdentity.cdma(cdma);
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_LTE: {
+            V1_5::CellIdentityLte lte;
+            lte.base.base.mcc = std::to_string(rilCellIdentity.cellIdentityGsm.mcc);
+            lte.base.base.mnc = ril::util::mnc::decode(rilCellIdentity.cellIdentityLte.mnc);
+            if (lte.base.base.mcc == "-1") {
+                lte.base.base.mcc = "";
+            }
+            lte.base.base.ci = rilCellIdentity.cellIdentityLte.ci;
+            lte.base.base.pci = rilCellIdentity.cellIdentityLte.pci;
+            lte.base.base.tac = rilCellIdentity.cellIdentityLte.tac;
+            lte.base.base.earfcn = rilCellIdentity.cellIdentityLte.earfcn;
+            cellIdentity.lte(lte);
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_TD_SCDMA: {
+            V1_5::CellIdentityTdscdma tdscdma;
+            tdscdma.base.base.mcc = std::to_string(rilCellIdentity.cellIdentityGsm.mcc);
+            tdscdma.base.base.mnc = ril::util::mnc::decode(rilCellIdentity.cellIdentityTdscdma.mnc);
+            if (tdscdma.base.base.mcc == "-1") {
+                tdscdma.base.base.mcc = "";
+            }
+            tdscdma.base.base.lac = rilCellIdentity.cellIdentityTdscdma.lac;
+            tdscdma.base.base.cid = rilCellIdentity.cellIdentityTdscdma.cid;
+            tdscdma.base.base.cpid = rilCellIdentity.cellIdentityTdscdma.cpid;
+            cellIdentity.tdscdma(tdscdma);
+            break;
+        }
+
+        default: {
+            break;
+        }
+    }
+}
+
+void fillCellIdentityResponse_1_2(V1_2::CellIdentity &cellIdentity,
+                                  RIL_CellIdentity_v1_2 &rilCellIdentity) {
+    cellIdentity.cellIdentityGsm.resize(0);
+    cellIdentity.cellIdentityWcdma.resize(0);
+    cellIdentity.cellIdentityCdma.resize(0);
+    cellIdentity.cellIdentityTdscdma.resize(0);
+    cellIdentity.cellIdentityLte.resize(0);
+    cellIdentity.cellInfoType = (CellInfoType)rilCellIdentity.cellInfoType;
+    switch(rilCellIdentity.cellInfoType) {
+
+        case RIL_CELL_INFO_TYPE_GSM: {
+            cellIdentity.cellIdentityGsm.resize(1);
+            cellIdentity.cellIdentityGsm[0].base.mcc =
+                std::to_string(rilCellIdentity.cellIdentityGsm.mcc);
+            cellIdentity.cellIdentityGsm[0].base.mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityGsm.mnc);
+
+            if (cellIdentity.cellIdentityGsm[0].base.mcc == "-1") {
+                cellIdentity.cellIdentityGsm[0].base.mcc = "";
+            }
+
+            cellIdentity.cellIdentityGsm[0].base.lac = rilCellIdentity.cellIdentityGsm.lac;
+            cellIdentity.cellIdentityGsm[0].base.cid = rilCellIdentity.cellIdentityGsm.cid;
+            cellIdentity.cellIdentityGsm[0].base.arfcn = rilCellIdentity.cellIdentityGsm.arfcn;
+            cellIdentity.cellIdentityGsm[0].base.bsic = rilCellIdentity.cellIdentityGsm.bsic;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            cellIdentity.cellIdentityWcdma.resize(1);
+            cellIdentity.cellIdentityWcdma[0].base.mcc =
+                std::to_string(rilCellIdentity.cellIdentityWcdma.mcc);
+            cellIdentity.cellIdentityWcdma[0].base.mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityWcdma.mnc);
+
+            if (cellIdentity.cellIdentityWcdma[0].base.mcc == "-1") {
+                cellIdentity.cellIdentityWcdma[0].base.mcc = "";
+            }
+
+            cellIdentity.cellIdentityWcdma[0].base.lac = rilCellIdentity.cellIdentityWcdma.lac;
+            cellIdentity.cellIdentityWcdma[0].base.cid = rilCellIdentity.cellIdentityWcdma.cid;
+            cellIdentity.cellIdentityWcdma[0].base.psc = rilCellIdentity.cellIdentityWcdma.psc;
+            cellIdentity.cellIdentityWcdma[0].base.uarfcn = rilCellIdentity.cellIdentityWcdma.uarfcn;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_CDMA: {
+            cellIdentity.cellIdentityCdma.resize(1);
+            cellIdentity.cellIdentityCdma[0].base.networkId = rilCellIdentity.cellIdentityCdma.networkId;
+            cellIdentity.cellIdentityCdma[0].base.systemId = rilCellIdentity.cellIdentityCdma.systemId;
+            cellIdentity.cellIdentityCdma[0].base.baseStationId =
+                    rilCellIdentity.cellIdentityCdma.basestationId;
+            cellIdentity.cellIdentityCdma[0].base.longitude = rilCellIdentity.cellIdentityCdma.longitude;
+            cellIdentity.cellIdentityCdma[0].base.latitude = rilCellIdentity.cellIdentityCdma.latitude;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_LTE: {
+            cellIdentity.cellIdentityLte.resize(1);
+            cellIdentity.cellIdentityLte[0].base.mcc =
+                std::to_string(rilCellIdentity.cellIdentityLte.mcc);
+            cellIdentity.cellIdentityLte[0].base.mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityLte.mnc);
+
+            if (cellIdentity.cellIdentityLte[0].base.mcc == "-1") {
+                cellIdentity.cellIdentityLte[0].base.mcc = "";
+            }
+
+            cellIdentity.cellIdentityLte[0].base.ci = rilCellIdentity.cellIdentityLte.ci;
+            cellIdentity.cellIdentityLte[0].base.pci = rilCellIdentity.cellIdentityLte.pci;
+            cellIdentity.cellIdentityLte[0].base.tac = rilCellIdentity.cellIdentityLte.tac;
+            cellIdentity.cellIdentityLte[0].base.earfcn = rilCellIdentity.cellIdentityLte.earfcn;
+            cellIdentity.cellIdentityLte[0].bandwidth = rilCellIdentity.cellIdentityLte.bandwidth;
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_TD_SCDMA: {
+            cellIdentity.cellIdentityTdscdma.resize(1);
+            cellIdentity.cellIdentityTdscdma[0].base.mcc =
+                std::to_string(rilCellIdentity.cellIdentityTdscdma.mcc);
+            cellIdentity.cellIdentityTdscdma[0].base.mnc =
+                    ril::util::mnc::decode(rilCellIdentity.cellIdentityTdscdma.mnc);
+
+            if (cellIdentity.cellIdentityTdscdma[0].base.mcc == "-1") {
+                cellIdentity.cellIdentityTdscdma[0].base.mcc = "";
+            }
+
+            cellIdentity.cellIdentityTdscdma[0].base.lac = rilCellIdentity.cellIdentityTdscdma.lac;
+            cellIdentity.cellIdentityTdscdma[0].base.cid = rilCellIdentity.cellIdentityTdscdma.cid;
+            cellIdentity.cellIdentityTdscdma[0].base.cpid = rilCellIdentity.cellIdentityTdscdma.cpid;
+            cellIdentity.cellIdentityTdscdma[0].uarfcn = rilCellIdentity.cellIdentityTdscdma.uarfcn;
+            break;
+        }
+
+        default: {
+            break;
+        }
+    }
+}
+
+int convertResponseStringEntryToInt(char **response, int index, int numStrings) {
+    if ((response != NULL) &&  (numStrings > index) && (response[index] != NULL)) {
+        return atoi(response[index]);
+    }
+
+    return -1;
+}
+
+int convertResponseHexStringEntryToInt(char **response, int index, int numStrings) {
+    const int hexBase = 16;
+    if ((response != NULL) &&  (numStrings > index) && (response[index] != NULL)) {
+        return strtol(response[index], NULL, hexBase);
+    }
+
+    return -1;
+}
+
+/* Fill Cell Identity info from Voice Registration State Response.
+ * This fucntion is applicable only for RIL Version < 15.
+ * Response is a  "char **".
+ * First and Second entries are in hex string format
+ * and rest are integers represented in ascii format. */
+void fillCellIdentityFromVoiceRegStateResponseString(V1_5::CellIdentity &cellIdentity,
+        int numStrings, char** response) {
+
+    RIL_CellIdentity_v16 rilCellIdentity;
+    memset(&rilCellIdentity, -1, sizeof(RIL_CellIdentity_v16));
+
+    rilCellIdentity.cellInfoType = getCellInfoTypeRadioTechnology(response[3]);
+    switch(rilCellIdentity.cellInfoType) {
+
+        case RIL_CELL_INFO_TYPE_GSM: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityGsm.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityGsm.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityWcdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityWcdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+            rilCellIdentity.cellIdentityWcdma.psc =
+                    convertResponseStringEntryToInt(response, 14, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_TD_SCDMA:{
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityTdscdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityTdscdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_CDMA:{
+            rilCellIdentity.cellIdentityCdma.basestationId =
+                    convertResponseStringEntryToInt(response, 4, numStrings);
+            /* Order of Lat. and Long. swapped between RIL and HIDL interface versions. */
+            rilCellIdentity.cellIdentityCdma.latitude =
+                    convertResponseStringEntryToInt(response, 5, numStrings);
+            rilCellIdentity.cellIdentityCdma.longitude =
+                    convertResponseStringEntryToInt(response, 6, numStrings);
+            rilCellIdentity.cellIdentityCdma.systemId =
+                    convertResponseStringEntryToInt(response, 8, numStrings);
+            rilCellIdentity.cellIdentityCdma.networkId =
+                    convertResponseStringEntryToInt(response, 9, numStrings);
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_LTE:{
+            /* valid TAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityLte.tac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityLte.ci =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            break;
+        }
+
+        default: {
+            break;
+        }
+    }
+
+    fillCellIdentityResponse_1_5(cellIdentity, rilCellIdentity);
+}
+
+void fillCellIdentityFromVoiceRegStateResponseString_1_2(V1_2::CellIdentity &cellIdentity,
+        int numStrings, char** response) {
+    RIL_CellIdentity_v1_2 rilCellIdentity;
+    memset(&rilCellIdentity, -1, sizeof(RIL_CellIdentity_v1_2));
+
+    rilCellIdentity.cellInfoType = getCellInfoTypeRadioTechnology(response[3]);
+
+    switch(rilCellIdentity.cellInfoType) {
+        case RIL_CELL_INFO_TYPE_GSM: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityGsm.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityGsm.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityWcdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityWcdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+            rilCellIdentity.cellIdentityWcdma.psc =
+                    convertResponseStringEntryToInt(response, 14, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityWcdma.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityWcdma.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_TD_SCDMA:{
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityTdscdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityTdscdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityTdscdma.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityTdscdma.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_CDMA:{
+            rilCellIdentity.cellIdentityCdma.basestationId =
+                    convertResponseStringEntryToInt(response, 4, numStrings);
+            /* Order of Lat. and Long. swapped between RIL and HIDL interface versions. */
+            rilCellIdentity.cellIdentityCdma.latitude =
+                    convertResponseStringEntryToInt(response, 5, numStrings);
+            rilCellIdentity.cellIdentityCdma.longitude =
+                    convertResponseStringEntryToInt(response, 6, numStrings);
+            rilCellIdentity.cellIdentityCdma.systemId =
+                    convertResponseStringEntryToInt(response, 8, numStrings);
+            rilCellIdentity.cellIdentityCdma.networkId =
+                    convertResponseStringEntryToInt(response, 9, numStrings);
+            break;
+        }
+
+        case RIL_CELL_INFO_TYPE_LTE:{
+            /* valid TAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityLte.tac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityLte.ci =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings > 15) {
+                rilCellIdentity.cellIdentityLte.mcc =
+                        convertResponseStringEntryToInt(response, 15, numStrings);
+
+                rilCellIdentity.cellIdentityLte.mnc =
+                        convertResponseStringEntryToInt(response, 16, numStrings);
+            }
+            rilCellIdentity.cellIdentityLte.bandwidth = INT_MAX;
+            break;
+        }
+
+        default: {
+            break;
+        }
+    }
+
+    fillCellIdentityResponse_1_2(cellIdentity, rilCellIdentity);
+}
+
+/* Fill Cell Identity info from Data Registration State Response.
+ * This fucntion is applicable only for RIL Version < 15.
+ * Response is a  "char **".
+ * First and Second entries are in hex string format
+ * and rest are integers represented in ascii format. */
+void fillCellIdentityFromDataRegStateResponseString_1_5(V1_5::CellIdentity &cellIdentity,
+        int numStrings, char** response) {
+
+    RIL_CellIdentity_v16 rilCellIdentity;
+    memset(&rilCellIdentity, -1, sizeof(RIL_CellIdentity_v16));
+
+    rilCellIdentity.cellInfoType = getCellInfoTypeRadioTechnology(response[3]);
+    switch(rilCellIdentity.cellInfoType) {
+        case RIL_CELL_INFO_TYPE_GSM: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityGsm.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityGsm.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityGsm.mnc = 0;
+                rilCellIdentity.cellIdentityGsm.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityWcdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityWcdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityWcdma.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityWcdma.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityWcdma.mnc = 0;
+                rilCellIdentity.cellIdentityWcdma.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_TD_SCDMA:{
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityTdscdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityTdscdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityTdscdma.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityTdscdma.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityTdscdma.mnc = 0;
+                rilCellIdentity.cellIdentityTdscdma.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_LTE: {
+            rilCellIdentity.cellIdentityLte.tac =
+                    convertResponseStringEntryToInt(response, 6, numStrings);
+            rilCellIdentity.cellIdentityLte.pci =
+                    convertResponseStringEntryToInt(response, 7, numStrings);
+            rilCellIdentity.cellIdentityLte.ci =
+                    convertResponseStringEntryToInt(response, 8, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityLte.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityLte.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityLte.mnc = 0;
+                rilCellIdentity.cellIdentityLte.mcc = 0;
+            }
+            break;
+        }
+        default: {
+            break;
+        }
+    }
+
+    fillCellIdentityResponse_1_5(cellIdentity, rilCellIdentity);
+}
+
+void fillCellIdentityFromDataRegStateResponseString_1_2(V1_2::CellIdentity &cellIdentity,
+        int numStrings, char** response) {
+
+    RIL_CellIdentity_v1_2 rilCellIdentity;
+    memset(&rilCellIdentity, -1, sizeof(RIL_CellIdentity_v1_2));
+
+    rilCellIdentity.cellInfoType = getCellInfoTypeRadioTechnology(response[3]);
+    switch(rilCellIdentity.cellInfoType) {
+        case RIL_CELL_INFO_TYPE_GSM: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityGsm.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityGsm.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityGsm.mnc = 0;
+                rilCellIdentity.cellIdentityGsm.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityWcdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityWcdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityWcdma.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityWcdma.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityWcdma.mnc = 0;
+                rilCellIdentity.cellIdentityWcdma.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_TD_SCDMA: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityTdscdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityTdscdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityTdscdma.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityTdscdma.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityTdscdma.mnc = 0;
+                rilCellIdentity.cellIdentityTdscdma.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_LTE: {
+            rilCellIdentity.cellIdentityLte.tac =
+                    convertResponseStringEntryToInt(response, 6, numStrings);
+            rilCellIdentity.cellIdentityLte.pci =
+                    convertResponseStringEntryToInt(response, 7, numStrings);
+            rilCellIdentity.cellIdentityLte.ci =
+                    convertResponseStringEntryToInt(response, 8, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityLte.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityLte.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityLte.mnc = 0;
+                rilCellIdentity.cellIdentityLte.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_CDMA: {
+            break;
+        }
+        default: {
+            break;
+        }
+    }
+
+    fillCellIdentityResponse_1_2(cellIdentity, rilCellIdentity);
+}
+
+void fillCellIdentityFromDataRegStateResponseString(CellIdentity &cellIdentity,
+        int numStrings, char** response) {
+
+    RIL_CellIdentity_v16 rilCellIdentity;
+    memset(&rilCellIdentity, -1, sizeof(RIL_CellIdentity_v16));
+
+    rilCellIdentity.cellInfoType = getCellInfoTypeRadioTechnology(response[3]);
+    switch(rilCellIdentity.cellInfoType) {
+        case RIL_CELL_INFO_TYPE_GSM: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityGsm.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityGsm.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityGsm.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityGsm.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityGsm.mnc = 0;
+                rilCellIdentity.cellIdentityGsm.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_WCDMA: {
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityWcdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityWcdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityWcdma.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityWcdma.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityWcdma.mnc = 0;
+                rilCellIdentity.cellIdentityWcdma.mcc = 0;
+            }
+
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_TD_SCDMA:{
+            /* valid LAC are hexstrings in the range 0x0000 - 0xffff */
+            rilCellIdentity.cellIdentityTdscdma.lac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+
+            /* valid CID are hexstrings in the range 0x00000000 - 0xffffffff */
+            rilCellIdentity.cellIdentityTdscdma.cid =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityTdscdma.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityTdscdma.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityTdscdma.mnc = 0;
+                rilCellIdentity.cellIdentityTdscdma.mcc = 0;
+            }
+            break;
+        }
+        case RIL_CELL_INFO_TYPE_LTE: {
+            rilCellIdentity.cellIdentityLte.tac =
+                    convertResponseHexStringEntryToInt(response, 1, numStrings);
+            rilCellIdentity.cellIdentityLte.ci =
+                    convertResponseHexStringEntryToInt(response, 2, numStrings);
+
+            if (numStrings >= 13) {
+                rilCellIdentity.cellIdentityLte.mcc =
+                        convertResponseStringEntryToInt(response, 11, numStrings);
+
+                rilCellIdentity.cellIdentityLte.mnc =
+                        convertResponseStringEntryToInt(response, 12, numStrings);
+            } else {
+                /* vts check the mcc [0, 999] and mnc [0, 999]. */
+                rilCellIdentity.cellIdentityLte.mnc = 0;
+                rilCellIdentity.cellIdentityLte.mcc = 0;
+            }
+            break;
+        }
+        // TODO add CDMA
+        default: {
+            break;
+        }
+    }
+
+    fillCellIdentityResponse(cellIdentity, rilCellIdentity);
+}
+
+int radio_1_6::getVoiceRegistrationStateResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getVoiceRegistrationStateResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL ||
+        radioService[slotId]->mRadioResponseV1_2 != NULL ||
+        radioService[slotId]->mRadioResponseV1_5 != NULL ||
+        radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        VoiceRegStateResult voiceRegResponse = {};
+        int numStrings = responseLen / sizeof(char *);
+        if (response == NULL) {
+               RLOGE("getVoiceRegistrationStateResponse Invalid response: NULL");
+               if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else if (s_vendorFunctions->version >= 15 &&
+                   radioService[slotId]->mRadioResponseV1_6 != NULL) {
+            ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+            populateResponseInfo_1_6(responseInfo_1_6, serial, responseType, e);
+            RegStateResultV1_6 regResponse = {};
+            if (numStrings != 18) {
+                RLOGE("getVoiceRegistrationStateResponse_1_6 Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo_1_6.error =
+                        ::android::hardware::radio::V1_6::RadioError::INVALID_RESPONSE;
+            } else {
+                char **resp = (char **) response;
+                regResponse.regState = (RegState)ATOI_NULL_HANDLED_DEF(resp[0], 4);
+                int rat = ATOI_NULL_HANDLED_DEF(resp[3], 0);
+                regResponse.rat = (V1_4::RadioTechnology)rat;
+                if (rat == RADIO_TECH_EVDO_0 || rat == RADIO_TECH_EVDO_A ||
+                    rat == RADIO_TECH_EVDO_B || rat == RADIO_TECH_1xRTT ||
+                    rat == RADIO_TECH_IS95A || rat == RADIO_TECH_IS95B ||
+                    rat == RADIO_TECH_EHRPD) {
+                    V1_5::RegStateResult::AccessTechnologySpecificInfo::
+                            Cdma2000RegistrationInfo cdmaInfo;
+                    cdmaInfo.cssSupported = ATOI_NULL_HANDLED_DEF(resp[7], 0);
+                    cdmaInfo.roamingIndicator = ATOI_NULL_HANDLED(resp[10]);
+                    cdmaInfo.systemIsInPrl = (V1_5::PrlIndicator)ATOI_NULL_HANDLED_DEF(resp[11], 0);
+                    cdmaInfo.defaultRoamingIndicator= ATOI_NULL_HANDLED_DEF(resp[12], 0);
+                    regResponse.accessTechnologySpecificInfo.cdmaInfo(cdmaInfo);
+                } else if (rat == RADIO_TECH_NR) {
+                    // rat is NR only for NR SA
+                    V1_6::NrVopsInfo nrVopsInfo;
+                    nrVopsInfo.vopsSupported =
+                            ::android::hardware::radio::V1_6::VopsIndicator::VOPS_NOT_SUPPORTED;
+                    nrVopsInfo.emcSupported =
+                            ::android::hardware::radio::V1_6::EmcIndicator::EMC_NOT_SUPPORTED;
+                    nrVopsInfo.emfSupported =
+                            ::android::hardware::radio::V1_6::EmfIndicator::EMF_NOT_SUPPORTED;
+                    regResponse.accessTechnologySpecificInfo.ngranNrVopsInfo(nrVopsInfo);
+
+                } else {
+                    V1_5::RegStateResult::AccessTechnologySpecificInfo::
+                        EutranRegistrationInfo eutranInfo;
+                    if (rat == RADIO_TECH_LTE || rat == RADIO_TECH_LTE_CA) {
+                        eutranInfo.lteVopsInfo.isVopsSupported = false;
+                        eutranInfo.lteVopsInfo.isEmcBearerSupported = false;
+                    }
+                    eutranInfo.nrIndicators.isEndcAvailable = false;
+                    eutranInfo.nrIndicators.isDcNrRestricted = false;
+                    eutranInfo.nrIndicators.isEndcAvailable = false;
+                    regResponse.accessTechnologySpecificInfo.eutranInfo(eutranInfo);
+                }
+                regResponse.reasonForDenial = (V1_5::RegistrationFailCause)
+                        ATOI_NULL_HANDLED_DEF(resp[13], 0);
+                regResponse.registeredPlmn = convertCharPtrToHidlString(resp[17]);
+
+                fillCellIdentityFromVoiceRegStateResponseString(regResponse.cellIdentity,
+                        numStrings, resp);
+
+                Return<void> retStatus =
+                    radioService[slotId]
+                        ->mRadioResponseV1_6
+                        ->getVoiceRegistrationStateResponse_1_6(
+                            responseInfo_1_6, regResponse);
+                radioService[slotId]->checkReturnStatus(retStatus);
+            }
+        } else if (s_vendorFunctions->version <= 14 &&
+                   radioService[slotId]->mRadioResponseV1_5 != NULL) {
+            RegStateResultV1_5 regResponse = {};
+            if (numStrings != 18) {
+                RLOGE("getVoiceRegistrationStateResponse_1_5 Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            } else {
+                char **resp = (char **) response;
+                regResponse.regState = (RegState)ATOI_NULL_HANDLED_DEF(resp[0], 4);
+                int rat = ATOI_NULL_HANDLED_DEF(resp[3], 0);
+                regResponse.rat = (V1_4::RadioTechnology)rat;
+                if (rat == RADIO_TECH_EVDO_0 || rat == RADIO_TECH_EVDO_A ||
+                    rat == RADIO_TECH_EVDO_B || rat == RADIO_TECH_1xRTT ||
+                    rat == RADIO_TECH_IS95A || rat == RADIO_TECH_IS95B ||
+                    rat == RADIO_TECH_EHRPD) {
+                    V1_5::RegStateResult::AccessTechnologySpecificInfo::
+                            Cdma2000RegistrationInfo cdmaInfo;
+                    cdmaInfo.cssSupported = ATOI_NULL_HANDLED_DEF(resp[7], 0);
+                    cdmaInfo.roamingIndicator = ATOI_NULL_HANDLED(resp[10]);
+                    cdmaInfo.systemIsInPrl = (V1_5::PrlIndicator)ATOI_NULL_HANDLED_DEF(resp[11], 0);
+                    cdmaInfo.defaultRoamingIndicator= ATOI_NULL_HANDLED_DEF(resp[12], 0);
+                    regResponse.accessTechnologySpecificInfo.cdmaInfo(cdmaInfo);
+                } else {
+                    V1_5::RegStateResult::AccessTechnologySpecificInfo::
+                        EutranRegistrationInfo eutranInfo;
+                    if (rat == RADIO_TECH_LTE || rat == RADIO_TECH_LTE_CA ||
+                        rat == RADIO_TECH_NR) {
+                        eutranInfo.lteVopsInfo.isVopsSupported = false;
+                        eutranInfo.lteVopsInfo.isEmcBearerSupported = false;
+                    }
+                    eutranInfo.nrIndicators.isEndcAvailable = false;
+                    eutranInfo.nrIndicators.isDcNrRestricted = false;
+                    eutranInfo.nrIndicators.isEndcAvailable = false;
+                    regResponse.accessTechnologySpecificInfo.eutranInfo(eutranInfo);
+                }
+                regResponse.reasonForDenial = (V1_5::RegistrationFailCause)
+                        ATOI_NULL_HANDLED_DEF(resp[13], 0);
+                regResponse.registeredPlmn = convertCharPtrToHidlString(resp[17]);
+
+                fillCellIdentityFromVoiceRegStateResponseString(regResponse.cellIdentity,
+                        numStrings, resp);
+
+                Return<void> retStatus =
+                    radioService[slotId]
+                        ->mRadioResponseV1_5
+                        ->getVoiceRegistrationStateResponse_1_5(
+                            responseInfo, regResponse);
+                radioService[slotId]->checkReturnStatus(retStatus);
+            }
+        } else if (s_vendorFunctions->version <= 14 &&
+                      radioService[slotId]->mRadioResponseV1_2 != NULL) {
+            V1_2::VoiceRegStateResult voiceRegResponse = {};
+            int numStrings = responseLen / sizeof(char *);
+            if (numStrings != 18) {
+                RLOGE("getVoiceRegistrationStateResponse_1_21 Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            } else {
+                char **resp = (char **) response;
+                voiceRegResponse.regState = (RegState) ATOI_NULL_HANDLED_DEF(resp[0], 4);
+                voiceRegResponse.rat = ATOI_NULL_HANDLED_DEF(resp[3], 0);
+                voiceRegResponse.cssSupported = ATOI_NULL_HANDLED_DEF(resp[7], 0);
+                voiceRegResponse.roamingIndicator = ATOI_NULL_HANDLED(resp[10]);
+                voiceRegResponse.systemIsInPrl = ATOI_NULL_HANDLED_DEF(resp[11], 0);
+                voiceRegResponse.defaultRoamingIndicator = ATOI_NULL_HANDLED_DEF(resp[12], 0);
+                voiceRegResponse.reasonForDenial = ATOI_NULL_HANDLED_DEF(resp[13], 0);
+                fillCellIdentityFromVoiceRegStateResponseString_1_2(
+                        voiceRegResponse.cellIdentity, numStrings, resp);
+              }
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2->
+                    getVoiceRegistrationStateResponse_1_2(responseInfo, voiceRegResponse);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else {
+              RIL_VoiceRegistrationStateResponse *voiceRegState =
+                    (RIL_VoiceRegistrationStateResponse *)response;
+              if (responseLen != sizeof(RIL_VoiceRegistrationStateResponse)) {
+                  RLOGE("getVoiceRegistrationStateResponse Invalid response: NULL");
+                  if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+              } else {
+                  voiceRegResponse.regState = (RegState) voiceRegState->regState;
+                  voiceRegResponse.rat = voiceRegState->rat;;
+                  voiceRegResponse.cssSupported = voiceRegState->cssSupported;
+                  voiceRegResponse.roamingIndicator = voiceRegState->roamingIndicator;
+                  voiceRegResponse.systemIsInPrl = voiceRegState->systemIsInPrl;
+                  voiceRegResponse.defaultRoamingIndicator = voiceRegState->defaultRoamingIndicator;
+                  voiceRegResponse.reasonForDenial = voiceRegState->reasonForDenial;
+                  fillCellIdentityResponse(voiceRegResponse.cellIdentity,
+                          voiceRegState->cellIdentity);
+              }
+              Return<void> retStatus =
+                      radioService[slotId]->mRadioResponse->getVoiceRegistrationStateResponse(
+                      responseInfo, voiceRegResponse);
+              radioService[slotId]->checkReturnStatus(retStatus);
+        }
+
+    } else {
+        RLOGE("getVoiceRegistrationStateResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+    return 0;
+}
+
+int radio_1_6::getDataRegistrationStateResponse(int slotId,
+                                           int responseType, int serial, RIL_Errno e,
+                                           void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getDataRegistrationStateResponse: serial %d", serial);
+#endif
+    if (radioService[slotId]->mRadioResponse != NULL ||
+        radioService[slotId]->mRadioResponseV1_2 != NULL ||
+        radioService[slotId]->mRadioResponseV1_5 != NULL ||
+        radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        DataRegStateResult dataRegResponse = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        if (response == NULL) {
+            RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else if (s_vendorFunctions->version >= 15 &&
+                   radioService[slotId]->mRadioResponseV1_6 != NULL) {
+            ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+            populateResponseInfo_1_6(responseInfo_1_6, serial, responseType, e);
+            RegStateResultV1_6 regResponse = {};
+            int numStrings = responseLen / sizeof(char *);
+            if ((numStrings != 6) && (numStrings != 11) && (numStrings != 14)) {
+                RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo_1_6.error =
+                        ::android::hardware::radio::V1_6::RadioError::INVALID_RESPONSE;
+            } else {
+                char **resp = (char **) response;
+                int rat = ATOI_NULL_HANDLED_DEF(resp[3], 0);
+                regResponse.regState = (RegState)ATOI_NULL_HANDLED_DEF(resp[0], 4);
+                regResponse.rat = (V1_4::RadioTechnology)rat;
+                regResponse.reasonForDenial =
+                        (V1_5::RegistrationFailCause)ATOI_NULL_HANDLED(resp[4]);
+                if (numStrings > 13) {
+                    regResponse.registeredPlmn = convertCharPtrToHidlString(resp[13]);
+                }
+
+                fillCellIdentityFromDataRegStateResponseString_1_5(regResponse.cellIdentity,
+                        numStrings, resp);
+                if (rat == RADIO_TECH_NR) {
+                    // rat is NR only for NR SA
+                    V1_6::NrVopsInfo nrVopsInfo;
+                    nrVopsInfo.vopsSupported =
+                            ::android::hardware::radio::V1_6::VopsIndicator::VOPS_NOT_SUPPORTED;
+                    nrVopsInfo.emcSupported =
+                            ::android::hardware::radio::V1_6::EmcIndicator::EMC_NOT_SUPPORTED;
+                    nrVopsInfo.emfSupported =
+                            ::android::hardware::radio::V1_6::EmfIndicator::EMF_NOT_SUPPORTED;
+                    regResponse.accessTechnologySpecificInfo.ngranNrVopsInfo(nrVopsInfo);
+
+                } else {
+                    V1_5::RegStateResult::AccessTechnologySpecificInfo::
+                            EutranRegistrationInfo eutranInfo;
+                    if (rat == RADIO_TECH_LTE || rat == RADIO_TECH_LTE_CA) {
+                        eutranInfo.lteVopsInfo.isVopsSupported = false;
+                        eutranInfo.lteVopsInfo.isEmcBearerSupported = false;
+                    }
+                    eutranInfo.nrIndicators.isEndcAvailable = false;
+                    eutranInfo.nrIndicators.isDcNrRestricted = false;
+                    eutranInfo.nrIndicators.isEndcAvailable = false;
+                    regResponse.accessTechnologySpecificInfo.eutranInfo(eutranInfo);
+                }
+
+                Return<void> retStatus =
+                    radioService[slotId]
+                        ->mRadioResponseV1_6
+                        ->getVoiceRegistrationStateResponse_1_6(
+                            responseInfo_1_6, regResponse);
+                radioService[slotId]->checkReturnStatus(retStatus);
+            }
+        } else if (s_vendorFunctions->version <= 14 &&
+                   radioService[slotId]->mRadioResponseV1_5 != NULL) {
+            RegStateResultV1_5 regResponse = {};
+            int numStrings = responseLen / sizeof(char *);
+            if ((numStrings != 6) && (numStrings != 11) && (numStrings != 14)) {
+                RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            } else {
+                char **resp = (char **) response;
+                int rat = ATOI_NULL_HANDLED_DEF(resp[3], 0);
+                regResponse.regState = (RegState)ATOI_NULL_HANDLED_DEF(resp[0], 4);
+                regResponse.rat = (V1_4::RadioTechnology)rat;
+                regResponse.reasonForDenial =
+                        (V1_5::RegistrationFailCause)ATOI_NULL_HANDLED(resp[4]);
+                if (numStrings > 13) {
+                    regResponse.registeredPlmn = convertCharPtrToHidlString(resp[13]);
+                }
+
+                V1_5::RegStateResult::AccessTechnologySpecificInfo::
+                        EutranRegistrationInfo eutranInfo;
+                if (rat == RADIO_TECH_LTE || rat == RADIO_TECH_LTE_CA ||
+                    rat == RADIO_TECH_NR) {
+                    eutranInfo.lteVopsInfo.isVopsSupported = false;
+                    eutranInfo.lteVopsInfo.isEmcBearerSupported = false;
+                }
+                eutranInfo.nrIndicators.isEndcAvailable = false;
+                eutranInfo.nrIndicators.isDcNrRestricted = false;
+                eutranInfo.nrIndicators.isEndcAvailable = false;
+                regResponse.accessTechnologySpecificInfo.eutranInfo(eutranInfo);
+
+                fillCellIdentityFromDataRegStateResponseString_1_5(regResponse.cellIdentity,
+                        numStrings, resp);
+
+                Return<void> retStatus =
+                    radioService[slotId]
+                        ->mRadioResponseV1_5
+                        ->getDataRegistrationStateResponse_1_5(
+                            responseInfo, regResponse);
+                radioService[slotId]->checkReturnStatus(retStatus);
+            }
+        } else if (s_vendorFunctions->version <= 14 &&
+                    radioService[slotId]->mRadioResponseV1_2 != NULL) {
+            V1_2::DataRegStateResult dataRegResponse = {};
+            int numStrings = responseLen / sizeof(char *);
+            if ((numStrings != 11) && (numStrings != 13) && (numStrings != 14)) {
+                RLOGE("getDataRegistrationStateResponse_1_2 Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            } else {
+                char **resp = (char **)response;
+                dataRegResponse.regState = (RegState)ATOI_NULL_HANDLED_DEF(resp[0], 4);
+                dataRegResponse.rat =  ATOI_NULL_HANDLED_DEF(resp[3], 0);
+                dataRegResponse.reasonDataDenied =  ATOI_NULL_HANDLED(resp[4]);
+                dataRegResponse.maxDataCalls =  ATOI_NULL_HANDLED_DEF(resp[5], 1);
+                fillCellIdentityFromDataRegStateResponseString_1_2(dataRegResponse.cellIdentity,
+                        numStrings, resp);
+                Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2->
+                        getDataRegistrationStateResponse_1_2(responseInfo, dataRegResponse);
+                radioService[slotId]->checkReturnStatus(retStatus);
+            }
+      } else if (s_vendorFunctions->version <= 14) {
+            int numStrings = responseLen / sizeof(char *);
+            if ((numStrings != 11) && (numStrings != 13) && (numStrings != 14)) {
+                RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            } else {
+                char **resp = (char **) response;
+                dataRegResponse.regState = (RegState) ATOI_NULL_HANDLED_DEF(resp[0], 4);
+                dataRegResponse.rat =  ATOI_NULL_HANDLED_DEF(resp[3], 0);
+                dataRegResponse.reasonDataDenied =  ATOI_NULL_HANDLED(resp[4]);
+                dataRegResponse.maxDataCalls =  ATOI_NULL_HANDLED_DEF(resp[5], 1);
+                fillCellIdentityFromDataRegStateResponseString(dataRegResponse.cellIdentity,
+                        numStrings, resp);
+            }
+        } else {
+            RIL_DataRegistrationStateResponse *dataRegState =
+                    (RIL_DataRegistrationStateResponse *)response;
+
+            if (responseLen != sizeof(RIL_DataRegistrationStateResponse)) {
+                RLOGE("getDataRegistrationStateResponse Invalid response: NULL");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            } else {
+                dataRegResponse.regState = (RegState) dataRegState->regState;
+                dataRegResponse.rat = dataRegState->rat;
+                dataRegResponse.reasonDataDenied = dataRegState->reasonDataDenied;
+                dataRegResponse.maxDataCalls = dataRegState->maxDataCalls;
+                fillCellIdentityResponse(dataRegResponse.cellIdentity, dataRegState->cellIdentity);
+            }
+        }
+
+        Return<void> retStatus =
+                radioService[slotId]->mRadioResponse->getDataRegistrationStateResponse(
+                        responseInfo, dataRegResponse);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getDataRegistrationStateResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getOperatorResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responseLen) {
+#if VDBG
+    RLOGD("getOperatorResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_string longName;
+        hidl_string shortName;
+        hidl_string numeric;
+        int numStrings = responseLen / sizeof(char *);
+        if (response == NULL || numStrings != 3) {
+            RLOGE("getOperatorResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+
+        } else {
+            char **resp = (char **) response;
+            longName = convertCharPtrToHidlString(resp[0]);
+            shortName = convertCharPtrToHidlString(resp[1]);
+            numeric = convertCharPtrToHidlString(resp[2]);
+        }
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getOperatorResponse(
+                responseInfo, longName, shortName, numeric);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getOperatorResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setRadioPowerResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e, void *response,
+                                size_t responseLen) {
+#if VDBG
+    RLOGD("setRadioPowerResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+    populateResponseInfo_1_6(responseInfo_1_6, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6
+                ->setRadioPowerResponse_1_6(responseInfo_1_6);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->setRadioPowerResponse_1_5(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponse
+                ->setRadioPowerResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setRadioPowerResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendDtmfResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e, void *response,
+                           size_t responseLen) {
+#if VDBG
+    RLOGD("sendDtmfResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendDtmfResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendDtmfResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+SendSmsResult makeSendSmsResult(RadioResponseInfo& responseInfo, int serial, int responseType,
+                                RIL_Errno e, void *response, size_t responseLen) {
+    populateResponseInfo(responseInfo, serial, responseType, e);
+    SendSmsResult result = {};
+
+    if (response == NULL || responseLen != sizeof(RIL_SMS_Response)) {
+        RLOGE("Invalid response: NULL");
+        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        result.ackPDU = hidl_string();
+    } else {
+        RIL_SMS_Response *resp = (RIL_SMS_Response *) response;
+        result.messageRef = resp->messageRef;
+        result.ackPDU = convertCharPtrToHidlString(resp->ackPDU);
+        result.errorCode = resp->errorCode;
+    }
+    return result;
+}
+
+SendSmsResult makeSendSmsResult_1_6(
+        ::android::hardware::radio::V1_6::RadioResponseInfo &responseInfo, int serial,
+        int responseType, RIL_Errno e, void *response, size_t responseLen) {
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+    SendSmsResult result = {};
+
+    if (response == NULL || responseLen != sizeof(RIL_SMS_Response)) {
+        RLOGE("Invalid response: NULL");
+        if (e == RIL_E_SUCCESS) {
+            responseInfo.error = ::android::hardware::radio::V1_6::RadioError::INVALID_RESPONSE;
+        }
+        result.ackPDU = hidl_string();
+    } else {
+        RIL_SMS_Response *resp = (RIL_SMS_Response *) response;
+        result.messageRef = resp->messageRef;
+        result.ackPDU = convertCharPtrToHidlString(resp->ackPDU);
+        result.errorCode = resp->errorCode;
+    }
+    return result;
+}
+
+int radio_1_6::sendSmsResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responseLen) {
+#if VDBG
+    RLOGD("sendSmsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+        SendSmsResult result = makeSendSmsResult_1_6(responseInfo_1_6, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6
+                ->sendSmsResponse_1_6(responseInfo_1_6, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendSmsResponse(responseInfo,
+                result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendSmsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendSmsExpectMoreResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responseLen) {
+#if VDBG
+    RLOGD("sendSmsExpectMoreResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+        SendSmsResult result = makeSendSmsResult_1_6(responseInfo_1_6, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6
+                ->sendSmsExpectMoreResponse_1_6(responseInfo_1_6, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendSMSExpectMoreResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendSMSExpectMoreResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setupDataCallResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responseLen) {
+#if VDBG
+    RLOGD("setupDataCallResponse: serial %d", serial);
+#endif
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+        populateResponseInfo_1_6(responseInfo_1_6, serial, responseType, e);
+        ::android::hardware::radio::V1_6::SetupDataCallResult result;
+        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
+            if (response != NULL) {
+                RLOGE("setupDataCallResponse_1_6: Invalid response");
+                if (e == RIL_E_SUCCESS) responseInfo_1_6.error =
+                        ::android::hardware::radio::V1_6::RadioError::INVALID_RESPONSE;
+            }
+            result.cause = ::android::hardware::radio::V1_6::DataCallFailCause::ERROR_UNSPECIFIED;
+            result.type = ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
+            result.ifname = hidl_string();
+            result.addresses = hidl_vec<::android::hardware::radio::V1_5::LinkAddress>();
+            result.dnses = hidl_vec<hidl_string>();
+            result.gateways = hidl_vec<hidl_string>();
+            result.pcscf = hidl_vec<hidl_string>();
+            result.trafficDescriptors =
+                    hidl_vec<::android::hardware::radio::V1_6::TrafficDescriptor>();
+        } else {
+            convertRilDataCallToHal((RIL_Data_Call_Response_v12 *) response, result);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6->setupDataCallResponse_1_6(
+                responseInfo_1_6, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        ::android::hardware::radio::V1_5::SetupDataCallResult result;
+        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
+            if (response != NULL) {
+                RLOGE("setupDataCallResponse_1_5: Invalid response");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            }
+            result.cause = ::android::hardware::radio::V1_4::DataCallFailCause::ERROR_UNSPECIFIED;
+            result.type = ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
+            result.ifname = hidl_string();
+            result.addresses = hidl_vec<::android::hardware::radio::V1_5::LinkAddress>();
+            result.dnses = hidl_vec<hidl_string>();
+            result.gateways = hidl_vec<hidl_string>();
+            result.pcscf = hidl_vec<hidl_string>();
+        } else {
+            convertRilDataCallToHal((RIL_Data_Call_Response_v12 *) response, result);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5->setupDataCallResponse_1_5(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        ::android::hardware::radio::V1_4::SetupDataCallResult result;
+        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
+            if (response != NULL) {
+                RLOGE("setupDataCallResponse_1_4: Invalid response");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            }
+            result.cause = ::android::hardware::radio::V1_4::DataCallFailCause::ERROR_UNSPECIFIED;
+            result.type = ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
+            result.ifname = hidl_string();
+            result.addresses = hidl_vec<hidl_string>();
+            result.dnses = hidl_vec<hidl_string>();
+            result.gateways = hidl_vec<hidl_string>();
+            result.pcscf = hidl_vec<hidl_string>();
+        } else {
+            convertRilDataCallToHal((RIL_Data_Call_Response_v11 *) response, result);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4->setupDataCallResponse_1_4(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        SetupDataCallResult result = {};
+        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
+           if (response != NULL) {
+               RLOGE("setupDataCallResponse: Invalid response");
+               if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+           }
+           result.status = DataCallFailCause::ERROR_UNSPECIFIED;
+           result.type = hidl_string();
+           result.ifname = hidl_string();
+           result.addresses = hidl_string();
+           result.dnses = hidl_string();
+           result.gateways = hidl_string();
+           result.pcscf = hidl_string();
+        } else {
+           convertRilDataCallToHal((RIL_Data_Call_Response_v11 *) response, result);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->setupDataCallResponse(
+               responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setupDataCallResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+IccIoResult responseIccIo(RadioResponseInfo& responseInfo, int serial, int responseType,
+                           RIL_Errno e, void *response, size_t responseLen) {
+    populateResponseInfo(responseInfo, serial, responseType, e);
+    IccIoResult result = {};
+
+    if (response == NULL || responseLen != sizeof(RIL_SIM_IO_Response)) {
+        RLOGE("Invalid response: NULL");
+        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        result.simResponse = hidl_string();
+    } else {
+        RIL_SIM_IO_Response *resp = (RIL_SIM_IO_Response *) response;
+        result.sw1 = resp->sw1;
+        result.sw2 = resp->sw2;
+        result.simResponse = convertCharPtrToHidlString(resp->simResponse);
+    }
+    return result;
+}
+
+int radio_1_6::iccIOForAppResponse(int slotId,
+                      int responseType, int serial, RIL_Errno e, void *response,
+                      size_t responseLen) {
+#if VDBG
+    RLOGD("iccIOForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->iccIOForAppResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("iccIOForAppResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendUssdResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e, void *response,
+                           size_t responseLen) {
+#if VDBG
+    RLOGD("sendUssdResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->sendUssdResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendUssdResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cancelPendingUssdResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responseLen) {
+#if VDBG
+    RLOGD("cancelPendingUssdResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->cancelPendingUssdResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cancelPendingUssdResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getClirResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responseLen) {
+#if VDBG
+    RLOGD("getClirResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        int n = -1, m = -1;
+        int numInts = responseLen / sizeof(int);
+        if (response == NULL || numInts != 2) {
+            RLOGE("getClirResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            n = pInt[0];
+            m = pInt[1];
+        }
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getClirResponse(responseInfo,
+                n, m);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getClirResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setClirResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responseLen) {
+#if VDBG
+    RLOGD("setClirResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->setClirResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setClirResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCallForwardStatusResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e,
+                                       void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getCallForwardStatusResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<CallForwardInfo> callForwardInfos;
+
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_CallForwardInfo *) != 0) {
+            RLOGE("getCallForwardStatusResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int num = responseLen / sizeof(RIL_CallForwardInfo *);
+            callForwardInfos.resize(num);
+            for (int i = 0 ; i < num; i++) {
+                RIL_CallForwardInfo *resp = ((RIL_CallForwardInfo **) response)[i];
+                callForwardInfos[i].status = (CallForwardInfoStatus) resp->status;
+                callForwardInfos[i].reason = resp->reason;
+                callForwardInfos[i].serviceClass = resp->serviceClass;
+                callForwardInfos[i].toa = resp->toa;
+                callForwardInfos[i].number = convertCharPtrToHidlString(resp->number);
+                callForwardInfos[i].timeSeconds = resp->timeSeconds;
+            }
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getCallForwardStatusResponse(
+                responseInfo, callForwardInfos);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getCallForwardStatusResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCallForwardResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responseLen) {
+#if VDBG
+    RLOGD("setCallForwardResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->setCallForwardResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setCallForwardResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCallWaitingResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responseLen) {
+#if VDBG
+    RLOGD("getCallWaitingResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        bool enable = false;
+        int serviceClass = -1;
+        int numInts = responseLen / sizeof(int);
+        if (response == NULL || numInts != 2) {
+            RLOGE("getCallWaitingResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            enable = pInt[0] == 1 ? true : false;
+            serviceClass = pInt[1];
+        }
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getCallWaitingResponse(
+                responseInfo, enable, serviceClass);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getCallWaitingResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCallWaitingResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responseLen) {
+#if VDBG
+    RLOGD("setCallWaitingResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->setCallWaitingResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setCallWaitingResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::acknowledgeLastIncomingGsmSmsResponse(int slotId,
+                                                int responseType, int serial, RIL_Errno e,
+                                                void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("acknowledgeLastIncomingGsmSmsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus =
+                radioService[slotId]->mRadioResponse->acknowledgeLastIncomingGsmSmsResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("acknowledgeLastIncomingGsmSmsResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::acceptCallResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e,
+                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("acceptCallResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->acceptCallResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("acceptCallResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::deactivateDataCallResponse(int slotId,
+                                                int responseType, int serial, RIL_Errno e,
+                                                void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("deactivateDataCallResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->deactivateDataCallResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("deactivateDataCallResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getFacilityLockForAppResponse(int slotId,
+                                        int responseType, int serial, RIL_Errno e,
+                                        void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getFacilityLockForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                getFacilityLockForAppResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getFacilityLockForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setFacilityLockForAppResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setFacilityLockForAppResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseIntOrEmpty(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setFacilityLockForAppResponse(responseInfo,
+                ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setFacilityLockForAppResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setBarringPasswordResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e,
+                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("acceptCallResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setBarringPasswordResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setBarringPasswordResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getNetworkSelectionModeResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e, void *response,
+                                          size_t responseLen) {
+#if VDBG
+    RLOGD("getNetworkSelectionModeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        bool manual = false;
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("getNetworkSelectionModeResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            manual = pInt[0] == 1 ? true : false;
+        }
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getNetworkSelectionModeResponse(
+                responseInfo,
+                manual);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getNetworkSelectionModeResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setNetworkSelectionModeAutomaticResponse(int slotId, int responseType, int serial,
+                                                    RIL_Errno e, void *response,
+                                                    size_t responseLen) {
+#if VDBG
+    RLOGD("setNetworkSelectionModeAutomaticResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setNetworkSelectionModeAutomaticResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setNetworkSelectionModeAutomaticResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setNetworkSelectionModeManualResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e,
+                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setNetworkSelectionModeManualResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->setNetworkSelectionModeManualResponse_1_5(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponse
+                ->setNetworkSelectionModeManualResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("acceptCallResponse: radioService[%d]->setNetworkSelectionModeManualResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int convertOperatorStatusToInt(const char *str) {
+    if (strncmp("unknown", str, 9) == 0) {
+        return (int) OperatorStatus::UNKNOWN;
+    } else if (strncmp("available", str, 9) == 0) {
+        return (int) OperatorStatus::AVAILABLE;
+    } else if (strncmp("current", str, 9) == 0) {
+        return (int) OperatorStatus::CURRENT;
+    } else if (strncmp("forbidden", str, 9) == 0) {
+        return (int) OperatorStatus::FORBIDDEN;
+    } else {
+        return -1;
+    }
+}
+
+int radio_1_6::getAvailableNetworksResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responseLen) {
+#if VDBG
+    RLOGD("getAvailableNetworksResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<OperatorInfo> networks;
+        if ((response == NULL && responseLen != 0)
+                || responseLen % (4 * sizeof(char *))!= 0) {
+            RLOGE("getAvailableNetworksResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            char **resp = (char **) response;
+            int numStrings = responseLen / sizeof(char *);
+            networks.resize(numStrings/4);
+            for (int i = 0, j = 0; i < numStrings; i = i + 4, j++) {
+                networks[j].alphaLong = convertCharPtrToHidlString(resp[i]);
+                networks[j].alphaShort = convertCharPtrToHidlString(resp[i + 1]);
+                networks[j].operatorNumeric = convertCharPtrToHidlString(resp[i + 2]);
+                int status = convertOperatorStatusToInt(resp[i + 3]);
+                if (status == -1) {
+                    if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+                } else {
+                    networks[j].status = (OperatorStatus) status;
+                }
+            }
+        }
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getAvailableNetworksResponse(responseInfo,
+                networks);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getAvailableNetworksResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::startDtmfResponse(int slotId,
+                            int responseType, int serial, RIL_Errno e,
+                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("startDtmfResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->startDtmfResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("startDtmfResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::stopDtmfResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e,
+                           void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("stopDtmfResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->stopDtmfResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stopDtmfResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getBasebandVersionResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getBasebandVersionResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getBasebandVersionResponse(responseInfo,
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getBasebandVersionResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::separateConnectionResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("separateConnectionResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->separateConnectionResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("separateConnectionResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setMuteResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setMuteResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setMuteResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setMuteResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getMuteResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responseLen) {
+#if VDBG
+    RLOGD("getMuteResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        bool enable = false;
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("getMuteResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            enable = pInt[0] == 1 ? true : false;
+        }
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getMuteResponse(responseInfo,
+                enable);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getMuteResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getClipResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getClipResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getClipResponse(responseInfo,
+                (ClipStatus) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getClipResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getDataCallListResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getDataCallListResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        hidl_vec<SetupDataCallResult> ret;
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_Data_Call_Response_v11) != 0) {
+            RLOGE("getDataCallListResponse: invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            convertRilDataCallListToHal(response, responseLen, ret);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getDataCallListResponse(
+                responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getDataCallListResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setSuppServiceNotificationsResponse(int slotId,
+                                              int responseType, int serial, RIL_Errno e,
+                                              void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setSuppServiceNotificationsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setSuppServiceNotificationsResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setSuppServiceNotificationsResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::deleteSmsOnSimResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("deleteSmsOnSimResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->deleteSmsOnSimResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("deleteSmsOnSimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setBandModeResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setBandModeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setBandModeResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setBandModeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::writeSmsToSimResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e,
+                                void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("writeSmsToSimResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->writeSmsToSimResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("writeSmsToSimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getAvailableBandModesResponse(int slotId,
+                                        int responseType, int serial, RIL_Errno e, void *response,
+                                        size_t responseLen) {
+#if VDBG
+    RLOGD("getAvailableBandModesResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<RadioBandMode> modes;
+        if ((response == NULL && responseLen != 0)|| responseLen % sizeof(int) != 0) {
+            RLOGE("getAvailableBandModesResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            int numInts = responseLen / sizeof(int);
+            modes.resize(numInts);
+            for (int i = 0; i < numInts; i++) {
+                modes[i] = (RadioBandMode) pInt[i];
+            }
+        }
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getAvailableBandModesResponse(responseInfo,
+                modes);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getAvailableBandModesResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendEnvelopeResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("sendEnvelopeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendEnvelopeResponse(responseInfo,
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendEnvelopeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendTerminalResponseToSimResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("sendTerminalResponseToSimResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendTerminalResponseToSimResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendTerminalResponseToSimResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::handleStkCallSetupRequestFromSimResponse(int slotId,
+                                                   int responseType, int serial,
+                                                   RIL_Errno e, void *response,
+                                                   size_t responseLen) {
+#if VDBG
+    RLOGD("handleStkCallSetupRequestFromSimResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->handleStkCallSetupRequestFromSimResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("handleStkCallSetupRequestFromSimResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::explicitCallTransferResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e,
+                                       void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("explicitCallTransferResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->explicitCallTransferResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("explicitCallTransferResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setPreferredNetworkTypeResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setPreferredNetworkTypeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setPreferredNetworkTypeResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setPreferredNetworkTypeResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setAllowedNetworkTypesBitmapResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setAllowedNetworkTypesBitmapResponse: serial %d", serial);
+#endif
+
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_6->setAllowedNetworkTypesBitmapResponse(
+            responseInfo);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::getAllowedNetworkTypesBitmapResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e,
+                                          void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getAllowedNetworkTypesBitmapResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+      V1_6::RadioResponseInfo responseInfo = {};
+        int ret = responseInt_1_6(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_6->getAllowedNetworkTypesBitmapResponse(
+                responseInfo,
+                (const ::android::hardware::hidl_bitfield<
+                ::android::hardware::radio::V1_4::RadioAccessFamily>) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getAllowedNetworkTypesBitmapResponse: radioService[%d]->mRadioResponseV1_6 == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getPreferredNetworkTypeResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e,
+                                          void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getPreferredNetworkTypeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getPreferredNetworkTypeResponse(
+                responseInfo, (PreferredNetworkType) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getPreferredNetworkTypeResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setPreferredNetworkTypeBitmapResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setPreferredNetworkTypeBitmapResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_4->setPreferredNetworkTypeBitmapResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setPreferredNetworkTypeBitmapResponse: radioService[%d]->mRadioResponseV1_4 == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+
+int radio_1_6::getPreferredNetworkTypeBitmapResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e,
+                                          void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getPreferredNetworkTypeBitmapResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_4->getPreferredNetworkTypeBitmapResponse(
+                responseInfo,
+                (const ::android::hardware::hidl_bitfield<
+                ::android::hardware::radio::V1_4::RadioAccessFamily>) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getPreferredNetworkTypeBitmapResponse: radioService[%d]->mRadioResponseV1_4 == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getNeighboringCidsResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getNeighboringCidsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<NeighboringCell> cells;
+
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_NeighboringCell *) != 0) {
+            RLOGE("getNeighboringCidsResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int num = responseLen / sizeof(RIL_NeighboringCell *);
+            cells.resize(num);
+            for (int i = 0 ; i < num; i++) {
+                RIL_NeighboringCell *resp = ((RIL_NeighboringCell **) response)[i];
+                cells[i].cid = convertCharPtrToHidlString(resp->cid);
+                cells[i].rssi = resp->rssi;
+            }
+        }
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getNeighboringCidsResponse(responseInfo,
+                cells);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getNeighboringCidsResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setLocationUpdatesResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setLocationUpdatesResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setLocationUpdatesResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setLocationUpdatesResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCdmaSubscriptionSourceResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setCdmaSubscriptionSourceResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setCdmaSubscriptionSourceResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setCdmaSubscriptionSourceResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCdmaRoamingPreferenceResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setCdmaRoamingPreferenceResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setCdmaRoamingPreferenceResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setCdmaRoamingPreferenceResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCdmaRoamingPreferenceResponse(int slotId,
+                                           int responseType, int serial, RIL_Errno e,
+                                           void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getCdmaRoamingPreferenceResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getCdmaRoamingPreferenceResponse(
+                responseInfo, (CdmaRoamingType) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getCdmaRoamingPreferenceResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setTTYModeResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e,
+                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setTTYModeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setTTYModeResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setTTYModeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getTTYModeResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e,
+                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getTTYModeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getTTYModeResponse(responseInfo,
+                (TtyMode) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getTTYModeResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setPreferredVoicePrivacyResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setPreferredVoicePrivacyResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setPreferredVoicePrivacyResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setPreferredVoicePrivacyResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getPreferredVoicePrivacyResponse(int slotId,
+                                           int responseType, int serial, RIL_Errno e,
+                                           void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getPreferredVoicePrivacyResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        bool enable = false;
+        int numInts = responseLen / sizeof(int);
+        if (response == NULL || numInts != 1) {
+            RLOGE("getPreferredVoicePrivacyResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            enable = pInt[0] == 1 ? true : false;
+        }
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getPreferredVoicePrivacyResponse(
+                responseInfo, enable);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getPreferredVoicePrivacyResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendCDMAFeatureCodeResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("sendCDMAFeatureCodeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendCDMAFeatureCodeResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendCDMAFeatureCodeResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendBurstDtmfResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("sendBurstDtmfResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendBurstDtmfResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendBurstDtmfResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendCdmaSmsResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responseLen) {
+#if VDBG
+    RLOGD("sendCdmaSmsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+        SendSmsResult result = makeSendSmsResult_1_6(responseInfo_1_6, serial, responseType, e,
+                response, responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6
+                ->sendCdmaSmsResponse_1_6(responseInfo_1_6, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendCdmaSmsResponse(responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendCdmaSmsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::acknowledgeLastIncomingCdmaSmsResponse(int slotId,
+                                                 int responseType, int serial, RIL_Errno e,
+                                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("acknowledgeLastIncomingCdmaSmsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->acknowledgeLastIncomingCdmaSmsResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("acknowledgeLastIncomingCdmaSmsResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getGsmBroadcastConfigResponse(int slotId,
+                                        int responseType, int serial, RIL_Errno e,
+                                        void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getGsmBroadcastConfigResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<GsmBroadcastSmsConfigInfo> configs;
+
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_GSM_BroadcastSmsConfigInfo *) != 0) {
+            RLOGE("getGsmBroadcastConfigResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int num = responseLen / sizeof(RIL_GSM_BroadcastSmsConfigInfo *);
+            configs.resize(num);
+            for (int i = 0 ; i < num; i++) {
+                RIL_GSM_BroadcastSmsConfigInfo *resp =
+                        ((RIL_GSM_BroadcastSmsConfigInfo **) response)[i];
+                configs[i].fromServiceId = resp->fromServiceId;
+                configs[i].toServiceId = resp->toServiceId;
+                configs[i].fromCodeScheme = resp->fromCodeScheme;
+                configs[i].toCodeScheme = resp->toCodeScheme;
+                configs[i].selected = resp->selected == 1 ? true : false;
+            }
+        }
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getGsmBroadcastConfigResponse(responseInfo,
+                configs);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getGsmBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setGsmBroadcastConfigResponse(int slotId,
+                                        int responseType, int serial, RIL_Errno e,
+                                        void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setGsmBroadcastConfigResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setGsmBroadcastConfigResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setGsmBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setGsmBroadcastActivationResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setGsmBroadcastActivationResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setGsmBroadcastActivationResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setGsmBroadcastActivationResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCdmaBroadcastConfigResponse(int slotId,
+                                         int responseType, int serial, RIL_Errno e,
+                                         void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getCdmaBroadcastConfigResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<CdmaBroadcastSmsConfigInfo> configs;
+
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_CDMA_BroadcastSmsConfigInfo *) != 0) {
+            RLOGE("getCdmaBroadcastConfigResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int num = responseLen / sizeof(RIL_CDMA_BroadcastSmsConfigInfo *);
+            configs.resize(num);
+            for (int i = 0 ; i < num; i++) {
+                RIL_CDMA_BroadcastSmsConfigInfo *resp =
+                        ((RIL_CDMA_BroadcastSmsConfigInfo **) response)[i];
+                configs[i].serviceCategory = resp->service_category;
+                configs[i].language = resp->language;
+                configs[i].selected = resp->selected == 1 ? true : false;
+            }
+        }
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getCdmaBroadcastConfigResponse(responseInfo,
+                configs);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getCdmaBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCdmaBroadcastConfigResponse(int slotId,
+                                         int responseType, int serial, RIL_Errno e,
+                                         void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setCdmaBroadcastConfigResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setCdmaBroadcastConfigResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setCdmaBroadcastConfigResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCdmaBroadcastActivationResponse(int slotId,
+                                             int responseType, int serial, RIL_Errno e,
+                                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setCdmaBroadcastActivationResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setCdmaBroadcastActivationResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setCdmaBroadcastActivationResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCDMASubscriptionResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e, void *response,
+                                      size_t responseLen) {
+#if VDBG
+    RLOGD("getCDMASubscriptionResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        int numStrings = responseLen / sizeof(char *);
+        hidl_string emptyString;
+        if (response == NULL || numStrings != 5) {
+            RLOGE("getOperatorResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            Return<void> retStatus
+                    = radioService[slotId]->mRadioResponse->getCDMASubscriptionResponse(
+                    responseInfo, emptyString, emptyString, emptyString, emptyString, emptyString);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else {
+            char **resp = (char **) response;
+            Return<void> retStatus
+                    = radioService[slotId]->mRadioResponse->getCDMASubscriptionResponse(
+                    responseInfo,
+                    convertCharPtrToHidlString(resp[0]),
+                    convertCharPtrToHidlString(resp[1]),
+                    convertCharPtrToHidlString(resp[2]),
+                    convertCharPtrToHidlString(resp[3]),
+                    convertCharPtrToHidlString(resp[4]));
+            radioService[slotId]->checkReturnStatus(retStatus);
+        }
+    } else {
+        RLOGE("getCDMASubscriptionResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::writeSmsToRuimResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("writeSmsToRuimResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->writeSmsToRuimResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("writeSmsToRuimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::deleteSmsOnRuimResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("deleteSmsOnRuimResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->deleteSmsOnRuimResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("deleteSmsOnRuimResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getDeviceIdentityResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responseLen) {
+#if VDBG
+    RLOGD("getDeviceIdentityResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        int numStrings = responseLen / sizeof(char *);
+        hidl_string emptyString;
+        if (response == NULL || numStrings != 4) {
+            RLOGE("getDeviceIdentityResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            Return<void> retStatus
+                    = radioService[slotId]->mRadioResponse->getDeviceIdentityResponse(responseInfo,
+                    emptyString, emptyString, emptyString, emptyString);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else {
+            char **resp = (char **) response;
+            Return<void> retStatus
+                    = radioService[slotId]->mRadioResponse->getDeviceIdentityResponse(responseInfo,
+                    convertCharPtrToHidlString(resp[0]),
+                    convertCharPtrToHidlString(resp[1]),
+                    convertCharPtrToHidlString(resp[2]),
+                    convertCharPtrToHidlString(resp[3]));
+            radioService[slotId]->checkReturnStatus(retStatus);
+        }
+    } else {
+        RLOGE("getDeviceIdentityResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::exitEmergencyCallbackModeResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("exitEmergencyCallbackModeResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->exitEmergencyCallbackModeResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("exitEmergencyCallbackModeResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getSmscAddressResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSmscAddressResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getSmscAddressResponse(responseInfo,
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getSmscAddressResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setSmscAddressResponse(int slotId,
+                                             int responseType, int serial, RIL_Errno e,
+                                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setSmscAddressResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setSmscAddressResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setSmscAddressResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::reportSmsMemoryStatusResponse(int slotId,
+                                        int responseType, int serial, RIL_Errno e,
+                                        void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("reportSmsMemoryStatusResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->reportSmsMemoryStatusResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("reportSmsMemoryStatusResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::reportStkServiceIsRunningResponse(int slotId,
+                                             int responseType, int serial, RIL_Errno e,
+                                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("reportStkServiceIsRunningResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->
+                reportStkServiceIsRunningResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("reportStkServiceIsRunningResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCdmaSubscriptionSourceResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getCdmaSubscriptionSourceResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getCdmaSubscriptionSourceResponse(
+                responseInfo, (CdmaSubscriptionSource) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getCdmaSubscriptionSourceResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::requestIsimAuthenticationResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("requestIsimAuthenticationResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->requestIsimAuthenticationResponse(
+                responseInfo,
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("requestIsimAuthenticationResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::acknowledgeIncomingGsmSmsWithPduResponse(int slotId,
+                                                   int responseType,
+                                                   int serial, RIL_Errno e, void *response,
+                                                   size_t responseLen) {
+#if VDBG
+    RLOGD("acknowledgeIncomingGsmSmsWithPduResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->acknowledgeIncomingGsmSmsWithPduResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("acknowledgeIncomingGsmSmsWithPduResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendEnvelopeWithStatusResponse(int slotId,
+                                         int responseType, int serial, RIL_Errno e, void *response,
+                                         size_t responseLen) {
+#if VDBG
+    RLOGD("sendEnvelopeWithStatusResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e,
+                response, responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendEnvelopeWithStatusResponse(responseInfo,
+                result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendEnvelopeWithStatusResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getVoiceRadioTechnologyResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e,
+                                          void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getVoiceRadioTechnologyResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getVoiceRadioTechnologyResponse(
+                responseInfo, (RadioTechnology) ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getVoiceRadioTechnologyResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getCellInfoListResponse(int slotId,
+                                   int responseType,
+                                   int serial, RIL_Errno e, void *response,
+                                   size_t responseLen) {
+#if VDBG
+    RLOGD("getCellInfoListResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL ||
+        radioService[slotId]->mRadioResponseV1_2 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        Return<void> retStatus;
+        hidl_vec<CellInfo> ret;
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_CellInfo_v12) != 0) {
+            RLOGE("getCellInfoListResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+
+            if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
+                hidl_vec<V1_2::CellInfo> ret;
+                retStatus = radioService[slotId]->mRadioResponseV1_2->
+                        getCellInfoListResponse_1_2(responseInfo, ret);
+            } else {
+                hidl_vec<CellInfo> ret;
+                retStatus = radioService[slotId]->mRadioResponse->
+                        getCellInfoListResponse(responseInfo, ret);
+            }
+        } else {
+            if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
+                hidl_vec<V1_2::CellInfo> ret;
+                convertRilCellInfoListToHal_1_2(response, responseLen, ret);
+                retStatus = radioService[slotId]->mRadioResponseV1_2->
+                        getCellInfoListResponse_1_2(responseInfo, ret);
+            } else {
+                hidl_vec<CellInfo> ret;
+                convertRilCellInfoListToHal(response, responseLen, ret);
+                retStatus = radioService[slotId]->mRadioResponse->
+                        getCellInfoListResponse(responseInfo, ret);
+            }
+        }
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getCellInfoListResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCellInfoListRateResponse(int slotId,
+                                       int responseType,
+                                       int serial, RIL_Errno e, void *response,
+                                       size_t responseLen) {
+#if VDBG
+    RLOGD("setCellInfoListRateResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setCellInfoListRateResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setCellInfoListRateResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setInitialAttachApnResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e,
+                                       void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setInitialAttachApnResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_5->setInitialAttachApnResponse_1_5(
+                responseInfo);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setInitialAttachApnResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setInitialAttachApnResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getImsRegistrationStateResponse(int slotId,
+                                           int responseType, int serial, RIL_Errno e,
+                                           void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getImsRegistrationStateResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        bool isRegistered = false;
+        int ratFamily = 0;
+        int numInts = responseLen / sizeof(int);
+        if (response == NULL || numInts != 2) {
+            RLOGE("getImsRegistrationStateResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            isRegistered = pInt[0] == 1 ? true : false;
+            ratFamily = pInt[1];
+        }
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getImsRegistrationStateResponse(
+                responseInfo, isRegistered, (RadioTechnologyFamily) ratFamily);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getImsRegistrationStateResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendImsSmsResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responseLen) {
+#if VDBG
+    RLOGD("sendImsSmsResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendImsSmsResponse(responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendSmsResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::iccTransmitApduBasicChannelResponse(int slotId,
+                                               int responseType, int serial, RIL_Errno e,
+                                               void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("iccTransmitApduBasicChannelResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->iccTransmitApduBasicChannelResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("iccTransmitApduBasicChannelResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::iccOpenLogicalChannelResponse(int slotId,
+                                         int responseType, int serial, RIL_Errno e, void *response,
+                                         size_t responseLen) {
+#if VDBG
+    RLOGD("iccOpenLogicalChannelResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        int channelId = -1;
+        hidl_vec<int8_t> selectResponse;
+        int numInts = responseLen / sizeof(int);
+        if (response == NULL || responseLen % sizeof(int) != 0) {
+            RLOGE("iccOpenLogicalChannelResponse Invalid response: NULL");
+            if (response != NULL) {
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            }
+        } else {
+            int *pInt = (int *) response;
+            channelId = pInt[0];
+            selectResponse.resize(numInts - 1);
+            for (int i = 1; i < numInts; i++) {
+                selectResponse[i - 1] = (int8_t) pInt[i];
+            }
+        }
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->iccOpenLogicalChannelResponse(responseInfo,
+                channelId, selectResponse);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("iccOpenLogicalChannelResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::iccCloseLogicalChannelResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e,
+                                          void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("iccCloseLogicalChannelResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->iccCloseLogicalChannelResponse(
+                responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("iccCloseLogicalChannelResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::iccTransmitApduLogicalChannelResponse(int slotId,
+                                                 int responseType, int serial, RIL_Errno e,
+                                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("iccTransmitApduLogicalChannelResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->iccTransmitApduLogicalChannelResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("iccTransmitApduLogicalChannelResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::nvReadItemResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("nvReadItemResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->nvReadItemResponse(
+                responseInfo,
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("nvReadItemResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::nvWriteItemResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("nvWriteItemResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->nvWriteItemResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("nvWriteItemResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::nvWriteCdmaPrlResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("nvWriteCdmaPrlResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->nvWriteCdmaPrlResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("nvWriteCdmaPrlResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::nvResetConfigResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("nvResetConfigResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->nvResetConfigResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("nvResetConfigResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setUiccSubscriptionResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e,
+                                       void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setUiccSubscriptionResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setUiccSubscriptionResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setUiccSubscriptionResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setDataAllowedResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setDataAllowedResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setDataAllowedResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setDataAllowedResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getHardwareConfigResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getHardwareConfigResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        hidl_vec<HardwareConfig> result;
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_HardwareConfig) != 0) {
+            RLOGE("hardwareConfigChangedInd: invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            convertRilHardwareConfigListToHal(response, responseLen, result);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getHardwareConfigResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getHardwareConfigResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::requestIccSimAuthenticationResponse(int slotId,
+                                               int responseType, int serial, RIL_Errno e,
+                                               void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("requestIccSimAuthenticationResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        IccIoResult result = responseIccIo(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->requestIccSimAuthenticationResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("requestIccSimAuthenticationResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setDataProfileResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setDataProfileResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_5->setDataProfileResponse_1_5(
+                responseInfo);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->setDataProfileResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setDataProfileResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::requestShutdownResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("requestShutdownResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->requestShutdownResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("requestShutdownResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+void responseRadioCapability(RadioResponseInfo& responseInfo, int serial,
+        int responseType, RIL_Errno e, void *response, size_t responseLen, RadioCapability& rc) {
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    if (response == NULL || responseLen != sizeof(RIL_RadioCapability)) {
+        RLOGE("responseRadioCapability: Invalid response");
+        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        rc.logicalModemUuid = hidl_string();
+    } else {
+        convertRilRadioCapabilityToHal(response, responseLen, rc);
+    }
+}
+
+int radio_1_6::getRadioCapabilityResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getRadioCapabilityResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        RadioCapability result = {};
+        responseRadioCapability(responseInfo, serial, responseType, e, response, responseLen,
+                result);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->getRadioCapabilityResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getRadioCapabilityResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setRadioCapabilityResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setRadioCapabilityResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        RadioCapability result = {};
+        responseRadioCapability(responseInfo, serial, responseType, e, response, responseLen,
+                result);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->setRadioCapabilityResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setRadioCapabilityResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+LceStatusInfo responseLceStatusInfo(RadioResponseInfo& responseInfo, int serial, int responseType,
+                                    RIL_Errno e, void *response, size_t responseLen) {
+    populateResponseInfo(responseInfo, serial, responseType, e);
+    LceStatusInfo result = {};
+
+    if (response == NULL || responseLen != sizeof(RIL_LceStatusInfo)) {
+        RLOGE("Invalid response: NULL");
+        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+    } else {
+        RIL_LceStatusInfo *resp = (RIL_LceStatusInfo *) response;
+        result.lceStatus = (LceStatus) resp->lce_status;
+        result.actualIntervalMs = (uint8_t) resp->actual_interval_ms;
+    }
+    return result;
+}
+
+int radio_1_6::startLceServiceResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("startLceServiceResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        LceStatusInfo result = responseLceStatusInfo(responseInfo, serial, responseType, e,
+                response, responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->startLceServiceResponse(responseInfo,
+                result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("startLceServiceResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::stopLceServiceResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("stopLceServiceResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        LceStatusInfo result = responseLceStatusInfo(responseInfo, serial, responseType, e,
+                response, responseLen);
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->stopLceServiceResponse(responseInfo,
+                result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stopLceServiceResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::pullLceDataResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("pullLceDataResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        LceDataInfo result = {};
+        if (response == NULL || responseLen != sizeof(RIL_LceDataInfo)) {
+            RLOGE("pullLceDataResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            convertRilLceDataInfoToHal(response, responseLen, result);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse->pullLceDataResponse(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("pullLceDataResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getModemActivityInfoResponse(int slotId,
+                                        int responseType, int serial, RIL_Errno e,
+                                        void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getModemActivityInfoResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        ActivityStatsInfo info;
+        if (response == NULL || responseLen != sizeof(RIL_ActivityStatsInfo)) {
+            RLOGE("getModemActivityInfoResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            RIL_ActivityStatsInfo *resp = (RIL_ActivityStatsInfo *)response;
+            info.sleepModeTimeMs = resp->sleep_mode_time_ms;
+            info.idleModeTimeMs = resp->idle_mode_time_ms;
+            for(int i = 0; i < RIL_NUM_TX_POWER_LEVELS; i++) {
+                info.txmModetimeMs[i] = resp->tx_mode_time_ms[i];
+            }
+            info.rxModeTimeMs = resp->rx_mode_time_ms;
+        }
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->getModemActivityInfoResponse(responseInfo,
+                info);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getModemActivityInfoResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setAllowedCarriersResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setAllowedCarriersResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+
+    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4
+                ->setAllowedCarriersResponse_1_4(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        int ret = responseInt(responseInfo, serial, responseType, e, response, responseLen);
+        Return<void> retStatus = radioService[slotId]->mRadioResponse
+                ->setAllowedCarriersResponse(responseInfo, ret);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setAllowedCarriersResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+void prepareCarrierRestrictionsResponse(hidl_vec<Carrier>& allowedCarriers,
+                                       hidl_vec<Carrier>& excludedCarriers,
+                                       bool& allAllowed,
+                                       const RIL_CarrierRestrictions* pCr) {
+    if (pCr->len_allowed_carriers > 0 || pCr->len_excluded_carriers > 0) {
+        allAllowed = false;
+    }
+    allowedCarriers.resize(pCr->len_allowed_carriers);
+    for(int i = 0; i < pCr->len_allowed_carriers; i++) {
+        RIL_Carrier *carrier = pCr->allowed_carriers + i;
+        allowedCarriers[i].mcc = convertCharPtrToHidlString(carrier->mcc);
+        allowedCarriers[i].mnc = convertCharPtrToHidlString(carrier->mnc);
+        allowedCarriers[i].matchType = (CarrierMatchType) carrier->match_type;
+        allowedCarriers[i].matchData =
+                convertCharPtrToHidlString(carrier->match_data);
+    }
+
+    excludedCarriers.resize(pCr->len_excluded_carriers);
+    for(int i = 0; i < pCr->len_excluded_carriers; i++) {
+        RIL_Carrier *carrier = pCr->excluded_carriers + i;
+        excludedCarriers[i].mcc = convertCharPtrToHidlString(carrier->mcc);
+        excludedCarriers[i].mnc = convertCharPtrToHidlString(carrier->mnc);
+        excludedCarriers[i].matchType = (CarrierMatchType) carrier->match_type;
+        excludedCarriers[i].matchData =
+                convertCharPtrToHidlString(carrier->match_data);
+    }
+}
+
+int radio_1_6::getAllowedCarriersResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getAllowedCarriersResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        V1_4::CarrierRestrictionsWithPriority carrierInfo = {};
+        V1_4::SimLockMultiSimPolicy multiSimPolicy =
+                V1_4::SimLockMultiSimPolicy::NO_MULTISIM_POLICY;
+        bool allAllowed = true;
+
+        if (response == NULL) {
+#if VDBG
+            RLOGD("getAllowedCarriersResponse response is NULL: all allowed");
+#endif
+            carrierInfo.allowedCarriers.resize(0);
+            carrierInfo.excludedCarriers.resize(0);
+            carrierInfo.allowedCarriersPrioritized = false;
+        } else if (responseLen != sizeof(RIL_CarrierRestrictionsWithPriority)) {
+            RLOGE("getAllowedCarriersResponse Invalid response");
+            if (e == RIL_E_SUCCESS) {
+                responseInfo.error = RadioError::INVALID_RESPONSE;
+            }
+        } else {
+            RIL_CarrierRestrictionsWithPriority *pCrExt =
+                    (RIL_CarrierRestrictionsWithPriority *)response;
+
+            // Convert into the structure used in IRadio 1.0 to re-use existing code
+            RIL_CarrierRestrictions cr = {};
+            cr.len_allowed_carriers = pCrExt->len_allowed_carriers;
+            cr.len_excluded_carriers = pCrExt->len_excluded_carriers;
+            cr.allowed_carriers = pCrExt->allowed_carriers;
+            cr.excluded_carriers = pCrExt->excluded_carriers;
+            prepareCarrierRestrictionsResponse(carrierInfo.allowedCarriers,
+                    carrierInfo.excludedCarriers, allAllowed, &cr);
+
+            carrierInfo.allowedCarriersPrioritized = (bool)pCrExt->allowedCarriersPrioritized;
+            multiSimPolicy = (V1_4::SimLockMultiSimPolicy)pCrExt->multiSimPolicy;
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4
+                ->getAllowedCarriersResponse_1_4(responseInfo, carrierInfo, multiSimPolicy);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        CarrierRestrictions carrierInfo = {};
+        bool allAllowed = true;
+        if (response == NULL) {
+#if VDBG
+            RLOGD("getAllowedCarriersResponse response is NULL: all allowed");
+#endif
+            carrierInfo.allowedCarriers.resize(0);
+            carrierInfo.excludedCarriers.resize(0);
+        } else if (responseLen != sizeof(RIL_CarrierRestrictions)) {
+            RLOGE("getAllowedCarriersResponse Invalid response");
+            if (e == RIL_E_SUCCESS) {
+                responseInfo.error = RadioError::INVALID_RESPONSE;
+            }
+        } else {
+            RIL_CarrierRestrictions *pCr = (RIL_CarrierRestrictions *)response;
+            prepareCarrierRestrictionsResponse(carrierInfo.allowedCarriers,
+                    carrierInfo.excludedCarriers, allAllowed, pCr);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponse
+                ->getAllowedCarriersResponse(responseInfo, allAllowed, carrierInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getAllowedCarriersResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendDeviceStateResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen) {
+#if VDBG
+    RLOGD("sendDeviceStateResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponse->sendDeviceStateResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendDeviceStateResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setCarrierInfoForImsiEncryptionResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responseLen) {
+  RLOGD("setCarrierInfoForImsiEncryptionResponse: serial %d", serial);
+  if (radioService[slotId]->mRadioResponseV1_1 != NULL) {
+      RadioResponseInfo responseInfo = {};
+      populateResponseInfo(responseInfo, serial, responseType, e);
+      Return<void> retStatus = radioService[slotId]->mRadioResponseV1_1->
+              setCarrierInfoForImsiEncryptionResponse(responseInfo);
+      radioService[slotId]->checkReturnStatus(retStatus);
+  } else {
+      RLOGE("setCarrierInfoForImsiEncryptionResponse: radioService[%d]->mRadioResponseV1_1 == "
+              "NULL", slotId);
+  }
+  return 0;
+}
+
+int radio_1_6::setIndicationFilterResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen) {
+#if VDBG
+    RLOGD("setIndicationFilterResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->setIndicationFilterResponse_1_5(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponse
+                ->setIndicationFilterResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setIndicationFilterResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setSimCardPowerResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("setSimCardPowerResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL
+            || radioService[slotId]->mRadioResponseV1_1 != NULL
+            || radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+            ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo = {};
+            populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6->
+                    setSimCardPowerResponse_1_6(responseInfo);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else if (radioService[slotId]->mRadioResponseV1_1 != NULL) {
+            RLOGD("setSimCardPowerResponse: radioService[%d]->mRadioResponseV1_6 == NULL", slotId);
+            RadioResponseInfo responseInfo = {};
+            populateResponseInfo(responseInfo, serial, responseType, e);
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_1->
+                    setSimCardPowerResponse_1_1(responseInfo);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else {
+            RLOGD("setSimCardPowerResponse: radioService[%d]->mRadioResponseV1_6 and V1_1 == NULL",
+                    slotId);
+            RadioResponseInfo responseInfo = {};
+            populateResponseInfo(responseInfo, serial, responseType, e);
+            Return<void> retStatus = radioService[slotId]->mRadioResponse
+                    ->setSimCardPowerResponse(responseInfo);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        }
+    } else {
+        RLOGE("setSimCardPowerResponse: radioService[%d]->mRadioResponse == NULL && "
+                "radioService[%d]->mRadioResponseV1_1 and V1_6 == NULL", slotId, slotId);
+    }
+    return 0;
+}
+
+int radio_1_6::startNetworkScanResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                        void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("startNetworkScanResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_1 != NULL ||
+          radioService[slotId]->mRadioResponseV1_2 != NULL ||
+          radioService[slotId]->mRadioResponseV1_4 != NULL ||
+          radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+
+        if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6
+                    ->startNetworkScanResponse_1_5(responseInfo);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_4
+                    ->startNetworkScanResponse_1_4(responseInfo);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
+            Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2
+                    ->startNetworkScanResponse(responseInfo);
+            radioService[slotId]->checkReturnStatus(retStatus);
+        }  else if (radioService[slotId]->mRadioResponseV1_1 != NULL) {
+          Return<void> retStatus = radioService[slotId]->mRadioResponseV1_1
+                  ->startNetworkScanResponse(responseInfo);
+          radioService[slotId]->checkReturnStatus(retStatus);
+        } else {
+            RLOGE("startNetworkScanResponse: radioService[%d]->mRadioResponseV1_1 == NULL or "
+                    "radioService[%d]->mRadioResponseV1_4 == NULL", slotId, slotId);
+        }
+    }
+
+    return 0;
+}
+
+int radio_1_6::stopNetworkScanResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("stopNetworkScanResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_1 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_1->stopNetworkScanResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stopNetworkScanResponse: radioService[%d]->mRadioResponseV1_1 == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::emergencyDialResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                    void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("emergencyDialResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_4->emergencyDialResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("emergencyDialResponse: radioService[%d]->mRadioResponseV1_4 == NULL", slotId);
+    }
+    return 0;
+}
+
+void convertRilKeepaliveStatusToHal(const RIL_KeepaliveStatus *rilStatus,
+        V1_1::KeepaliveStatus& halStatus) {
+    halStatus.sessionHandle = rilStatus->sessionHandle;
+    halStatus.code = static_cast<V1_1::KeepaliveStatusCode>(rilStatus->code);
+}
+
+int radio_1_6::startKeepaliveResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                    void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_1 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_1 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    V1_1::KeepaliveStatus ks = {};
+    if (response == NULL || responseLen != sizeof(V1_1::KeepaliveStatus)) {
+        RLOGE("%s: invalid response - %d", __FUNCTION__, static_cast<int>(e));
+        if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+    } else {
+        convertRilKeepaliveStatusToHal(static_cast<RIL_KeepaliveStatus*>(response), ks);
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_1->startKeepaliveResponse(responseInfo, ks);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::stopKeepaliveResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                    void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_1 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_1 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_1->stopKeepaliveResponse(responseInfo);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::getModemStackStatusResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                    void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_3 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_3 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_3->getModemStackStatusResponse(
+            responseInfo, true);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::enableModemResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                    void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_3 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_3 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_3->enableModemResponse(responseInfo);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::sendRequestRawResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responseLen) {
+#if VDBG
+   RLOGD("sendRequestRawResponse: serial %d", serial);
+#endif
+
+    if (!kOemHookEnabled) return 0;
+
+    if (oemHookService[slotId]->mOemHookResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<uint8_t> data;
+
+        if (response == NULL) {
+            RLOGE("sendRequestRawResponse: Invalid response");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            data.setToExternal((uint8_t *) response, responseLen);
+        }
+        Return<void> retStatus = oemHookService[slotId]->mOemHookResponse->
+                sendRequestRawResponse(responseInfo, data);
+        checkReturnStatus(slotId, retStatus, false);
+    } else {
+        RLOGE("sendRequestRawResponse: oemHookService[%d]->mOemHookResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::sendRequestStringsResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("sendRequestStringsResponse: serial %d", serial);
+#endif
+
+    if (!kOemHookEnabled) return 0;
+
+    if (oemHookService[slotId]->mOemHookResponse != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        hidl_vec<hidl_string> data;
+
+        if ((response == NULL && responseLen != 0) || responseLen % sizeof(char *) != 0) {
+            RLOGE("sendRequestStringsResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            char **resp = (char **) response;
+            int numStrings = responseLen / sizeof(char *);
+            data.resize(numStrings);
+            for (int i = 0; i < numStrings; i++) {
+                data[i] = convertCharPtrToHidlString(resp[i]);
+            }
+        }
+        Return<void> retStatus
+                = oemHookService[slotId]->mOemHookResponse->sendRequestStringsResponse(
+                responseInfo, data);
+        checkReturnStatus(slotId, retStatus, false);
+    } else {
+        RLOGE("sendRequestStringsResponse: oemHookService[%d]->mOemHookResponse == "
+                "NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setSystemSelectionChannelsResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("setSystemSelectionChannelsResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->setSystemSelectionChannelsResponse_1_5(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_3 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_3
+                ->setSystemSelectionChannelsResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setSystemSelectionChannelsResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getSystemSelectionChannelsResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSystemSelectionChannelsResponse: serial %d", serial);
+#endif
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+      hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier> ret;
+      Return<void> retStatus =
+          radioService[slotId]
+              ->mRadioResponseV1_6->getSystemSelectionChannelsResponse(
+                  responseInfo, ret);
+      radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getSystemSelectionChannelsResponse: radioService[%d]->mRadioResponse == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setSignalStrengthReportingCriteriaResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("setSignalStrengthReportingCriteriaResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->setSignalStrengthReportingCriteriaResponse_1_5(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2
+                ->setSignalStrengthReportingCriteriaResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setSignalStrengthReportingCriteriaResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setLinkCapacityReportingCriteriaResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("setLinkCapacityReportingCriteriaResponse: serial %d", serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->setLinkCapacityReportingCriteriaResponse_1_5(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_2 != NULL) {
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_2
+                ->setLinkCapacityReportingCriteriaResponse(responseInfo);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setLinkCapacityReportingCriteriaResponse: radioService[%d]->mRadioResponse "
+                "== NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::enableUiccApplicationsResponse(int slotId, int responseType, int serial,
+                                    RIL_Errno e, void* /* response */, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_5 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_5 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_5->enableUiccApplicationsResponse(
+            responseInfo);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::areUiccApplicationsEnabledResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_5 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_5 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    bool enable = false;
+    if (response == NULL || responseLen != sizeof(bool)) {
+        RLOGE("isSimDetachedFromNetwork Invalid response.");
+    } else {
+        enable = (*((bool *) response));
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_5->areUiccApplicationsEnabledResponse(
+            responseInfo, enable);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::getBarringInfoResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen) {
+#if VDBG
+    RLOGD("getBarringInfoResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        ::android::hardware::radio::V1_5::CellIdentity cellIdentity;
+        hidl_vec<::android::hardware::radio::V1_5::BarringInfo> barringInfos = {};
+
+        if (response == NULL) { /* data for vts */
+            V1_5::BarringInfo barringInfo = {};
+            barringInfo.serviceType = V1_5::BarringInfo::ServiceType::CS_SERVICE;
+            barringInfo.barringType = V1_5::BarringInfo::BarringType::NONE;
+
+            V1_5::CellIdentityLte cellIdentityLte = {};
+            cellIdentity.lte(cellIdentityLte);
+            barringInfos.resize(1);
+            barringInfos[0] = barringInfo;
+
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_5->
+                        getBarringInfoResponse(responseInfo, cellIdentity, barringInfos);
+        radioService[slotId]->checkReturnStatus(retStatus);
+      } else {
+          RLOGE("getBarringInfoResponse: radioService[%d]->mRadioResponse == NULL",
+                  slotId);
+      }
+    }
+    return 0;
+}
+
+int radio_1_6::sendCdmaSmsExpectMoreResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                             void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("sendCdmaSmsExpectMoreResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_6 != NULL) {
+        ::android::hardware::radio::V1_6::RadioResponseInfo responseInfo_1_6 = {};
+        SendSmsResult result = makeSendSmsResult_1_6(responseInfo_1_6, serial, responseType, e,
+                response, responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6
+                ->sendCdmaSmsExpectMoreResponse_1_6(responseInfo_1_6, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        SendSmsResult result = makeSendSmsResult(responseInfo, serial, responseType, e, response,
+                responseLen);
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->sendCdmaSmsExpectMoreResponse(responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("sendCdmaSmsExpectMoreResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::supplySimDepersonalizationResponse(int slotId, int responseType, int serial,
+                                                  RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("supplySimDepersonalizationResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        int persoType = -1, remainingRetries = -1;
+        int numInts = responseLen / sizeof(int);
+        if (response == NULL || numInts != 2) {
+            RLOGE("getClirResponse Invalid response: NULL");
+            if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+        } else {
+            int *pInt = (int *) response;
+            persoType = pInt[0];
+            remainingRetries = pInt[1];
+        }
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5
+                ->supplySimDepersonalizationResponse(responseInfo, (V1_5::PersoSubstate) persoType,
+                remainingRetries);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("supplySimDepersonalizationResponse: radioService[%d]->mRadioResponseV1_5 == "
+                "NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::setNrDualConnectivityStateResponse(int slotId, int responseType, int serial,
+                                    RIL_Errno e, void* /* response */, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_6->setNrDualConnectivityStateResponse(
+            responseInfo);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::isNrDualConnectivityEnabledResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    bool enable = false;
+    if (response == NULL || responseLen != sizeof(bool)) {
+        RLOGE("isNrDualConnectivityEnabledResponseInvalid response.");
+    } else {
+        enable = (*((bool *) response));
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_6->isNrDualConnectivityEnabledResponse(
+            responseInfo, enable);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::allocatePduSessionIdResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+      RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+      return 0;
+    }
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_6->allocatePduSessionIdResponse(responseInfo, -1);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::releasePduSessionIdResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_6->releasePduSessionIdResponse(responseInfo);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::startHandoverResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_6->startHandoverResponse(responseInfo);
+
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    return 0;
+}
+
+int radio_1_6::cancelHandoverResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+    V1_6::RadioResponseInfo responseInfo = {};
+    populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_6->cancelHandoverResponse(responseInfo);
+
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    return 0;
+}
+
+
+int radio_1_6::setDataThrottlingResponse(int slotId, int responseType,
+                   int serial, RIL_Errno e, void *response, size_t responselen) {
+#if VDBG
+    RLOGD("setDataThrottlingResponse: serial %d", serial);
+#endif
+
+   if (radioService[slotId]->mRadioResponseV1_6 == NULL) {
+       RLOGE("%s: radioService[%d]->mRadioResponseV1_6 == NULL", __FUNCTION__, slotId);
+       return 0;
+   }
+
+   V1_6::RadioResponseInfo responseInfo = {};
+   populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+
+   Return<void> retstatus =
+        radioService[slotId]->mRadioResponseV1_6->setDataThrottlingResponse(
+                    responseInfo);
+   radioService[slotId]->checkReturnStatus(retstatus);
+   return 0;
+}
+
+int radio_1_6::getSlicingConfigResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSlicingConfigResponse: serial %d", serial);
+#endif
+
+    if (radioService[slotId]->mRadioResponse != NULL) {
+        V1_6::RadioResponseInfo responseInfo = {};
+        populateResponseInfo_1_6(responseInfo, serial, responseType, e);
+
+        V1_6::SlicingConfig slicingConfig = {};
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_6->
+                getSlicingConfigResponse(responseInfo, slicingConfig);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("getSlicingConfigResponse: radioService[%d]->mRadioResponse == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::getSimPhonebookRecordsResponse(int slotId, int responseType, int serial,
+                             RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSimPhonebookRecordsResponse: serial %d", serial);
+#endif
+    return 0;
+}
+
+int radio_1_6::getSimPhonebookCapacityResponse(int slotId, int responseType, int serial,
+                             RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSimPhonebookRecordsResponse: serial %d", serial);
+#endif
+    return 0;
+}
+
+int radio_1_6::updateSimPhonebookRecordsResponse(int slotId, int responseType, int serial,
+                             RIL_Errno e, void *response, size_t responseLen) {
+#if VDBG
+    RLOGD("getSimPhonebookRecordsResponse: serial %d", serial);
+#endif
+    return 0;
+}
+
+/***************************************************************************************************
+ * INDICATION FUNCTIONS
+ * The below function handle unsolicited messages coming from the Radio
+ * (messages for which there is no pending request)
+ **************************************************************************************************/
+
+RadioIndicationType convertIntToRadioIndicationType(int indicationType) {
+    return indicationType == RESPONSE_UNSOLICITED ? (RadioIndicationType::UNSOLICITED) :
+            (RadioIndicationType::UNSOLICITED_ACK_EXP);
+}
+
+int radio_1_6::radioStateChangedInd(int slotId,
+                                 int indicationType, int token, RIL_Errno e, void *response,
+                                 size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        RadioState radioState =
+                (RadioState) CALL_ONSTATEREQUEST(slotId);
+        RLOGD("radioStateChangedInd: radioState %d", radioState);
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->radioStateChanged(
+                convertIntToRadioIndicationType(indicationType), radioState);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("radioStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::callStateChangedInd(int slotId,
+                               int indicationType, int token, RIL_Errno e, void *response,
+                               size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("callStateChangedInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->callStateChanged(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("callStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::networkStateChangedInd(int slotId,
+                                  int indicationType, int token, RIL_Errno e, void *response,
+                                  size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("networkStateChangedInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->networkStateChanged(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("networkStateChangedInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+extern "C" uint8_t hexCharToInt(uint8_t c) {
+    if (c >= '0' && c <= '9') return (c - '0');
+    if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+    if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+
+    return INVALID_HEX_CHAR;
+}
+
+extern "C" uint8_t * convertHexStringToBytes(void *response, size_t responseLen) {
+    if (responseLen % 2 != 0) {
+        return NULL;
+    }
+
+    uint8_t *bytes = (uint8_t *)calloc(responseLen/2, sizeof(uint8_t));
+    if (bytes == NULL) {
+        RLOGE("convertHexStringToBytes: cannot allocate memory for bytes string");
+        return NULL;
+    }
+    uint8_t *hexString = (uint8_t *)response;
+
+    for (size_t i = 0; i < responseLen; i += 2) {
+        uint8_t hexChar1 = hexCharToInt(hexString[i]);
+        uint8_t hexChar2 = hexCharToInt(hexString[i + 1]);
+
+        if (hexChar1 == INVALID_HEX_CHAR || hexChar2 == INVALID_HEX_CHAR) {
+            RLOGE("convertHexStringToBytes: invalid hex char %d %d",
+                    hexString[i], hexString[i + 1]);
+            free(bytes);
+            return NULL;
+        }
+        bytes[i/2] = ((hexChar1 << 4) | hexChar2);
+    }
+
+    return bytes;
+}
+
+int radio_1_6::newSmsInd(int slotId, int indicationType,
+                     int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("newSmsInd: invalid response");
+            return 0;
+        }
+
+        uint8_t *bytes = convertHexStringToBytes(response, responseLen);
+        if (bytes == NULL) {
+            RLOGE("newSmsInd: convertHexStringToBytes failed");
+            return 0;
+        }
+
+        hidl_vec<uint8_t> pdu;
+        pdu.setToExternal(bytes, responseLen/2);
+#if VDBG
+        RLOGD("newSmsInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->newSms(
+                convertIntToRadioIndicationType(indicationType), pdu);
+        radioService[slotId]->checkReturnStatus(retStatus);
+        free(bytes);
+    } else {
+        RLOGE("newSmsInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::newSmsStatusReportInd(int slotId,
+                                 int indicationType, int token, RIL_Errno e, void *response,
+                                 size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("newSmsStatusReportInd: invalid response");
+            return 0;
+        }
+
+        uint8_t *bytes = convertHexStringToBytes(response, responseLen);
+        if (bytes == NULL) {
+            RLOGE("newSmsStatusReportInd: convertHexStringToBytes failed");
+            return 0;
+        }
+
+        hidl_vec<uint8_t> pdu;
+        pdu.setToExternal(bytes, responseLen/2);
+#if VDBG
+        RLOGD("newSmsStatusReportInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->newSmsStatusReport(
+                convertIntToRadioIndicationType(indicationType), pdu);
+        radioService[slotId]->checkReturnStatus(retStatus);
+        free(bytes);
+    } else {
+        RLOGE("newSmsStatusReportInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::newSmsOnSimInd(int slotId, int indicationType,
+                          int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("newSmsOnSimInd: invalid response");
+            return 0;
+        }
+        int32_t recordNumber = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("newSmsOnSimInd: slotIndex %d", recordNumber);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->newSmsOnSim(
+                convertIntToRadioIndicationType(indicationType), recordNumber);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("newSmsOnSimInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::onUssdInd(int slotId, int indicationType,
+                     int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != 2 * sizeof(char *)) {
+            RLOGE("onUssdInd: invalid response");
+            return 0;
+        }
+        char **strings = (char **) response;
+        char *mode = strings[0];
+        hidl_string msg = convertCharPtrToHidlString(strings[1]);
+        UssdModeType modeType = (UssdModeType) atoi(mode);
+#if VDBG
+        RLOGD("onUssdInd: mode %s", mode);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->onUssd(
+                convertIntToRadioIndicationType(indicationType), modeType, msg);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("onUssdInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::nitzTimeReceivedInd(int slotId,
+                               int indicationType, int token, RIL_Errno e, void *response,
+                               size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("nitzTimeReceivedInd: invalid response");
+            return 0;
+        }
+        hidl_string nitzTime = convertCharPtrToHidlString((char *) response);
+#if VDBG
+        RLOGD("nitzTimeReceivedInd: nitzTime %s receivedTime %" PRId64, nitzTime.c_str(),
+                nitzTimeReceived[slotId]);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->nitzTimeReceived(
+                convertIntToRadioIndicationType(indicationType), nitzTime,
+                nitzTimeReceived[slotId]);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("nitzTimeReceivedInd: radioService[%d]->mRadioIndication == NULL", slotId);
+        return -1;
+    }
+
+    return 0;
+}
+
+void convertRilSignalStrengthToHal(void *response, size_t responseLen,
+        SignalStrength& signalStrength) {
+    RIL_SignalStrength_v12 *rilSignalStrength = (RIL_SignalStrength_v12 *) response;
+
+    // Fixup LTE for backwards compatibility
+    // signalStrength: -1 -> 99
+    if (rilSignalStrength->LTE_SignalStrength.signalStrength == -1) {
+        rilSignalStrength->LTE_SignalStrength.signalStrength = 99;
+    }
+    // rsrp: -1 -> INT_MAX all other negative value to positive.
+    // So remap here
+    if (rilSignalStrength->LTE_SignalStrength.rsrp == -1) {
+        rilSignalStrength->LTE_SignalStrength.rsrp = INT_MAX;
+    } else if (rilSignalStrength->LTE_SignalStrength.rsrp < -1) {
+        rilSignalStrength->LTE_SignalStrength.rsrp = -rilSignalStrength->LTE_SignalStrength.rsrp;
+    }
+    // rsrq: -1 -> INT_MAX
+    if (rilSignalStrength->LTE_SignalStrength.rsrq == -1) {
+        rilSignalStrength->LTE_SignalStrength.rsrq = INT_MAX;
+    }
+    // Not remapping rssnr is already using INT_MAX
+    // cqi: -1 -> INT_MAX
+    if (rilSignalStrength->LTE_SignalStrength.cqi == -1) {
+        rilSignalStrength->LTE_SignalStrength.cqi = INT_MAX;
+    }
+
+    signalStrength.gw.signalStrength = rilSignalStrength->GW_SignalStrength.signalStrength;
+    signalStrength.gw.bitErrorRate = rilSignalStrength->GW_SignalStrength.bitErrorRate;
+    // RIL_SignalStrength_v10 not support gw.timingAdvance. Set to INT_MAX as
+    // invalid value.
+    signalStrength.gw.timingAdvance = INT_MAX;
+
+    signalStrength.cdma.dbm = rilSignalStrength->CDMA_SignalStrength.dbm;
+    signalStrength.cdma.ecio = rilSignalStrength->CDMA_SignalStrength.ecio;
+    signalStrength.evdo.dbm = rilSignalStrength->EVDO_SignalStrength.dbm;
+    signalStrength.evdo.ecio = rilSignalStrength->EVDO_SignalStrength.ecio;
+    signalStrength.evdo.signalNoiseRatio =
+            rilSignalStrength->EVDO_SignalStrength.signalNoiseRatio;
+    signalStrength.lte.signalStrength = rilSignalStrength->LTE_SignalStrength.signalStrength;
+    signalStrength.lte.rsrp = rilSignalStrength->LTE_SignalStrength.rsrp;
+    signalStrength.lte.rsrq = rilSignalStrength->LTE_SignalStrength.rsrq;
+    signalStrength.lte.rssnr = rilSignalStrength->LTE_SignalStrength.rssnr;
+    signalStrength.lte.cqi = rilSignalStrength->LTE_SignalStrength.cqi;
+    signalStrength.lte.timingAdvance = rilSignalStrength->LTE_SignalStrength.timingAdvance;
+    signalStrength.tdScdma.rscp = rilSignalStrength->TD_SCDMA_SignalStrength.rscp;
+}
+
+void convertRilSignalStrengthToHal_1_4(void *response, size_t responseLen,
+        V1_4::SignalStrength& signalStrength_1_4) {
+    SignalStrength signalStrength = {};
+    convertRilSignalStrengthToHal(response, responseLen, signalStrength);
+    signalStrength_1_4.gsm = signalStrength.gw;
+    signalStrength_1_4.cdma = signalStrength.cdma;
+    signalStrength_1_4.evdo = signalStrength.evdo;
+    signalStrength_1_4.lte = signalStrength.lte;
+
+    RIL_SignalStrength_v12 *rilSignalStrength = (RIL_SignalStrength_v12 *) response;
+    signalStrength_1_4.wcdma.base.signalStrength =
+        rilSignalStrength->WCDMA_SignalStrength.signalStrength;
+    signalStrength_1_4.wcdma.base.bitErrorRate =
+        rilSignalStrength->WCDMA_SignalStrength.bitErrorRate;
+    signalStrength_1_4.wcdma.rscp = INT_MAX;
+    signalStrength_1_4.wcdma.ecno = INT_MAX;
+
+    signalStrength_1_4.tdscdma.signalStrength = INT_MAX;
+    signalStrength_1_4.tdscdma.bitErrorRate = INT_MAX;
+    signalStrength_1_4.tdscdma.rscp = INT_MAX;
+
+    signalStrength_1_4.nr.ssRsrp = rilSignalStrength->NR_SignalStrength.ssRsrp;
+    signalStrength_1_4.nr.ssRsrq = rilSignalStrength->NR_SignalStrength.ssRsrq;
+    signalStrength_1_4.nr.ssSinr = rilSignalStrength->NR_SignalStrength.ssSinr;
+    signalStrength_1_4.nr.csiRsrp = rilSignalStrength->NR_SignalStrength.csiRsrp;
+    signalStrength_1_4.nr.csiRsrq = rilSignalStrength->NR_SignalStrength.csiRsrq;
+    signalStrength_1_4.nr.csiSinr = rilSignalStrength->NR_SignalStrength.ssSinr;
+}
+
+int radio_1_6::currentSignalStrengthInd(int slotId,
+                                    int indicationType, int token, RIL_Errno e,
+                                    void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL &&
+       (radioService[slotId]->mRadioIndication != NULL ||
+        radioService[slotId]->mRadioIndicationV1_4 != NULL)) {
+        if (response == NULL || responseLen != sizeof(RIL_SignalStrength_v12)) {
+            RLOGE("currentSignalStrengthInd: invalid response");
+            return 0;
+        }
+
+#if VDBG
+        RLOGD("currentSignalStrengthInd");
+#endif
+        Return<void> retStatus;
+        if (radioService[slotId]->mRadioIndicationV1_4 != NULL) {
+          V1_4::SignalStrength signalStrength_1_4 = {};
+          convertRilSignalStrengthToHal_1_4(response, responseLen, signalStrength_1_4);
+          retStatus = radioService[slotId]->mRadioIndicationV1_4->currentSignalStrength_1_4(
+                          convertIntToRadioIndicationType(indicationType), signalStrength_1_4);
+        } else {
+          SignalStrength signalStrength = {};
+          convertRilSignalStrengthToHal(response, responseLen, signalStrength);
+          retStatus = radioService[slotId]->mRadioIndication->currentSignalStrength(
+                          convertIntToRadioIndicationType(indicationType), signalStrength);
+        }
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("currentSignalStrengthInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
+        SetupDataCallResult& dcResult) {
+    dcResult.status = (DataCallFailCause) dcResponse->status;
+    dcResult.suggestedRetryTime = dcResponse->suggestedRetryTime;
+    dcResult.cid = dcResponse->cid;
+    dcResult.active = dcResponse->active;
+    dcResult.type = convertCharPtrToHidlString(dcResponse->type);
+    dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
+    dcResult.addresses = convertCharPtrToHidlString(dcResponse->addresses);
+    dcResult.dnses = convertCharPtrToHidlString(dcResponse->dnses);
+    dcResult.gateways = convertCharPtrToHidlString(dcResponse->gateways);
+    dcResult.pcscf = convertCharPtrToHidlString(dcResponse->pcscf);
+    dcResult.mtu = dcResponse->mtu;
+}
+
+hidl_vec<hidl_string> split(hidl_string str) {
+    std::vector<hidl_string> ret;
+    std::stringstream ss(static_cast<std::string>(str));
+
+    std::string tok;
+
+    while(getline(ss, tok, ' ')) {
+        ret.push_back(hidl_string(tok));
+    }
+
+    return ret;
+}
+
+::android::hardware::radio::V1_4::PdpProtocolType convertToPdpProtocolType(hidl_string str) {
+    if (strncmp("IP", str.c_str(), 2) == 0) {
+        return ::android::hardware::radio::V1_4::PdpProtocolType::IP;
+    } else if (strncmp("IPV6", str.c_str(), 4) == 0) {
+        return ::android::hardware::radio::V1_4::PdpProtocolType::IPV6;
+    } else if (strncmp("IPV4V6", str.c_str(), 6) == 0) {
+        return ::android::hardware::radio::V1_4::PdpProtocolType::IPV4V6;
+    } else if (strncmp("PPP", str.c_str(), 3) == 0) {
+        return ::android::hardware::radio::V1_4::PdpProtocolType::PPP;
+    } else if (strncmp("NON_IP", str.c_str(), 6) == 0) {
+        return ::android::hardware::radio::V1_4::PdpProtocolType::NON_IP;
+    } else if (strncmp("UNSTRUCTURED", str.c_str(), 12) == 0) {
+        return ::android::hardware::radio::V1_4::PdpProtocolType::UNSTRUCTURED;
+    } else {
+        return ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
+    }
+}
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v11 *dcResponse,
+        ::android::hardware::radio::V1_4::SetupDataCallResult& dcResult) {
+    dcResult.cause = (::android::hardware::radio::V1_4::DataCallFailCause) dcResponse->status;
+    dcResult.suggestedRetryTime = dcResponse->suggestedRetryTime;
+    dcResult.cid = dcResponse->cid;
+    dcResult.active = (::android::hardware::radio::V1_4::DataConnActiveStatus)dcResponse->active;
+    dcResult.type = convertToPdpProtocolType(convertCharPtrToHidlString(dcResponse->type));
+    dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
+    dcResult.addresses = split(convertCharPtrToHidlString(dcResponse->addresses));
+    dcResult.dnses = split(convertCharPtrToHidlString(dcResponse->dnses));
+    dcResult.gateways = split(convertCharPtrToHidlString(dcResponse->gateways));
+    dcResult.pcscf = split(convertCharPtrToHidlString(dcResponse->pcscf));
+    dcResult.mtu = dcResponse->mtu;
+}
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v12 *dcResponse,
+        ::android::hardware::radio::V1_5::SetupDataCallResult& dcResult) {
+    dcResult.cause = (::android::hardware::radio::V1_4::DataCallFailCause) dcResponse->status;
+    dcResult.suggestedRetryTime = dcResponse->suggestedRetryTime;
+    dcResult.cid = dcResponse->cid;
+    dcResult.active = (::android::hardware::radio::V1_4::DataConnActiveStatus)dcResponse->active;
+    dcResult.type = convertToPdpProtocolType(convertCharPtrToHidlString(dcResponse->type));
+    dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
+
+    std::vector<::android::hardware::radio::V1_5::LinkAddress> linkAddresses;
+    std::stringstream ss(static_cast<std::string>(dcResponse->addresses));
+    std::string tok;
+    while(getline(ss, tok, ' ')) {
+        ::android::hardware::radio::V1_5::LinkAddress la;
+        la.address = hidl_string(tok);
+        la.properties = 0;
+        la.deprecationTime = 0;
+        la.expirationTime = 0;
+        linkAddresses.push_back(la);
+    }
+
+    dcResult.addresses = linkAddresses;
+    dcResult.dnses = split(convertCharPtrToHidlString(dcResponse->dnses));
+    dcResult.gateways = split(convertCharPtrToHidlString(dcResponse->gateways));
+    dcResult.pcscf = split(convertCharPtrToHidlString(dcResponse->pcscf));
+    dcResult.mtuV4 = dcResponse->mtuV4;
+    dcResult.mtuV6 = dcResponse->mtuV6;
+}
+
+void convertRilDataCallToHal(RIL_Data_Call_Response_v12 *dcResponse,
+        ::android::hardware::radio::V1_6::SetupDataCallResult& dcResult) {
+    dcResult.cause = (::android::hardware::radio::V1_6::DataCallFailCause) dcResponse->status;
+    dcResult.suggestedRetryTime = dcResponse->suggestedRetryTime;
+    dcResult.cid = dcResponse->cid;
+    dcResult.active = (::android::hardware::radio::V1_4::DataConnActiveStatus)dcResponse->active;
+    dcResult.type = convertToPdpProtocolType(convertCharPtrToHidlString(dcResponse->type));
+    dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
+
+    std::vector<::android::hardware::radio::V1_5::LinkAddress> linkAddresses;
+    std::stringstream ss(static_cast<std::string>(dcResponse->addresses));
+    std::string tok;
+    while(getline(ss, tok, ' ')) {
+        ::android::hardware::radio::V1_5::LinkAddress la;
+        la.address = hidl_string(tok);
+        la.properties = 0;
+        la.deprecationTime = 0;
+        la.expirationTime = 0;
+        linkAddresses.push_back(la);
+    }
+
+    dcResult.addresses = linkAddresses;
+    dcResult.dnses = split(convertCharPtrToHidlString(dcResponse->dnses));
+    dcResult.gateways = split(convertCharPtrToHidlString(dcResponse->gateways));
+    dcResult.pcscf = split(convertCharPtrToHidlString(dcResponse->pcscf));
+    dcResult.mtuV4 = dcResponse->mtuV4;
+    dcResult.mtuV6 = dcResponse->mtuV6;
+
+    std::vector<::android::hardware::radio::V1_6::TrafficDescriptor> trafficDescriptors;
+    ::android::hardware::radio::V1_6::TrafficDescriptor trafficDescriptor;
+    ::android::hardware::radio::V1_6::OsAppId osAppId;
+
+    osAppId.osAppId = 1;
+    trafficDescriptor.osAppId.value(osAppId);
+    trafficDescriptors.push_back(trafficDescriptor);
+    dcResult.trafficDescriptors = trafficDescriptors;
+}
+
+void convertRilDataCallListToHal(void *response, size_t responseLen,
+        hidl_vec<SetupDataCallResult>& dcResultList) {
+    int num = responseLen / sizeof(RIL_Data_Call_Response_v11);
+
+    RIL_Data_Call_Response_v11 *dcResponse = (RIL_Data_Call_Response_v11 *) response;
+    dcResultList.resize(num);
+    for (int i = 0; i < num; i++) {
+        convertRilDataCallToHal(&dcResponse[i], dcResultList[i]);
+    }
+}
+
+int radio_1_6::dataCallListChangedInd(int slotId,
+                                  int indicationType, int token, RIL_Errno e, void *response,
+                                  size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_Data_Call_Response_v11) != 0) {
+            RLOGE("dataCallListChangedInd: invalid response");
+            return 0;
+        }
+        hidl_vec<SetupDataCallResult> dcList;
+        convertRilDataCallListToHal(response, responseLen, dcList);
+#if VDBG
+        RLOGD("dataCallListChangedInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->dataCallListChanged(
+                convertIntToRadioIndicationType(indicationType), dcList);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("dataCallListChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::suppSvcNotifyInd(int slotId, int indicationType,
+                            int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_SuppSvcNotification)) {
+            RLOGE("suppSvcNotifyInd: invalid response");
+            return 0;
+        }
+
+        SuppSvcNotification suppSvc = {};
+        RIL_SuppSvcNotification *ssn = (RIL_SuppSvcNotification *) response;
+        suppSvc.isMT = ssn->notificationType;
+        suppSvc.code = ssn->code;
+        suppSvc.index = ssn->index;
+        suppSvc.type = ssn->type;
+        suppSvc.number = convertCharPtrToHidlString(ssn->number);
+
+#if VDBG
+        RLOGD("suppSvcNotifyInd: isMT %d code %d index %d type %d",
+                suppSvc.isMT, suppSvc.code, suppSvc.index, suppSvc.type);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->suppSvcNotify(
+                convertIntToRadioIndicationType(indicationType), suppSvc);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("suppSvcNotifyInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::stkSessionEndInd(int slotId, int indicationType,
+                            int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("stkSessionEndInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkSessionEnd(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stkSessionEndInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::stkProactiveCommandInd(int slotId,
+                                  int indicationType, int token, RIL_Errno e, void *response,
+                                  size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("stkProactiveCommandInd: invalid response");
+            return 0;
+        }
+#if VDBG
+        RLOGD("stkProactiveCommandInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkProactiveCommand(
+                convertIntToRadioIndicationType(indicationType),
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stkProactiveCommandInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::stkEventNotifyInd(int slotId, int indicationType,
+                             int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("stkEventNotifyInd: invalid response");
+            return 0;
+        }
+#if VDBG
+        RLOGD("stkEventNotifyInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkEventNotify(
+                convertIntToRadioIndicationType(indicationType),
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stkEventNotifyInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::stkCallSetupInd(int slotId, int indicationType,
+                           int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("stkCallSetupInd: invalid response");
+            return 0;
+        }
+        int32_t timeout = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("stkCallSetupInd: timeout %d", timeout);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkCallSetup(
+                convertIntToRadioIndicationType(indicationType), timeout);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stkCallSetupInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::simSmsStorageFullInd(int slotId,
+                                int indicationType, int token, RIL_Errno e, void *response,
+                                size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("simSmsStorageFullInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->simSmsStorageFull(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("simSmsStorageFullInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::simRefreshInd(int slotId, int indicationType,
+                         int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_SimRefreshResponse_v7)) {
+            RLOGE("simRefreshInd: invalid response");
+            return 0;
+        }
+
+        SimRefreshResult refreshResult = {};
+        RIL_SimRefreshResponse_v7 *simRefreshResponse = ((RIL_SimRefreshResponse_v7 *) response);
+        refreshResult.type =
+                (V1_0::SimRefreshType) simRefreshResponse->result;
+        refreshResult.efId = simRefreshResponse->ef_id;
+        refreshResult.aid = convertCharPtrToHidlString(simRefreshResponse->aid);
+
+#if VDBG
+        RLOGD("simRefreshInd: type %d efId %d", refreshResult.type, refreshResult.efId);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->simRefresh(
+                convertIntToRadioIndicationType(indicationType), refreshResult);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("simRefreshInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+void convertRilCdmaSignalInfoRecordToHal(RIL_CDMA_SignalInfoRecord *signalInfoRecord,
+        CdmaSignalInfoRecord& record) {
+    record.isPresent = signalInfoRecord->isPresent;
+    record.signalType = signalInfoRecord->signalType;
+    record.alertPitch = signalInfoRecord->alertPitch;
+    record.signal = signalInfoRecord->signal;
+}
+
+int radio_1_6::callRingInd(int slotId, int indicationType,
+                       int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        bool isGsm;
+        CdmaSignalInfoRecord record = {};
+        if (response == NULL || responseLen == 0) {
+            isGsm = true;
+        } else {
+            isGsm = false;
+            if (responseLen != sizeof (RIL_CDMA_SignalInfoRecord)) {
+                RLOGE("callRingInd: invalid response");
+                return 0;
+            }
+            convertRilCdmaSignalInfoRecordToHal((RIL_CDMA_SignalInfoRecord *) response, record);
+        }
+
+#if VDBG
+        RLOGD("callRingInd: isGsm %d", isGsm);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->callRing(
+                convertIntToRadioIndicationType(indicationType), isGsm, record);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("callRingInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::simStatusChangedInd(int slotId,
+                               int indicationType, int token, RIL_Errno e, void *response,
+                               size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("simStatusChangedInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->simStatusChanged(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("simStatusChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cdmaNewSmsInd(int slotId, int indicationType,
+                         int token, RIL_Errno e, void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_CDMA_SMS_Message)) {
+            RLOGE("cdmaNewSmsInd: invalid response");
+            return 0;
+        }
+
+        CdmaSmsMessage msg = {};
+        RIL_CDMA_SMS_Message *rilMsg = (RIL_CDMA_SMS_Message *) response;
+        msg.teleserviceId = rilMsg->uTeleserviceID;
+        msg.isServicePresent = rilMsg->bIsServicePresent;
+        msg.serviceCategory = rilMsg->uServicecategory;
+        msg.address.digitMode =
+                (V1_0::CdmaSmsDigitMode) rilMsg->sAddress.digit_mode;
+        msg.address.numberMode =
+                (V1_0::CdmaSmsNumberMode) rilMsg->sAddress.number_mode;
+        msg.address.numberType =
+                (V1_0::CdmaSmsNumberType) rilMsg->sAddress.number_type;
+        msg.address.numberPlan =
+                (V1_0::CdmaSmsNumberPlan) rilMsg->sAddress.number_plan;
+
+        int digitLimit = MIN((rilMsg->sAddress.number_of_digits), RIL_CDMA_SMS_ADDRESS_MAX);
+        msg.address.digits.setToExternal(rilMsg->sAddress.digits, digitLimit);
+
+        msg.subAddress.subaddressType = (V1_0::CdmaSmsSubaddressType)
+                rilMsg->sSubAddress.subaddressType;
+        msg.subAddress.odd = rilMsg->sSubAddress.odd;
+
+        digitLimit= MIN((rilMsg->sSubAddress.number_of_digits), RIL_CDMA_SMS_SUBADDRESS_MAX);
+        msg.subAddress.digits.setToExternal(rilMsg->sSubAddress.digits, digitLimit);
+
+        digitLimit = MIN((rilMsg->uBearerDataLen), RIL_CDMA_SMS_BEARER_DATA_MAX);
+        msg.bearerData.setToExternal(rilMsg->aBearerData, digitLimit);
+
+#if VDBG
+        RLOGD("cdmaNewSmsInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaNewSms(
+                convertIntToRadioIndicationType(indicationType), msg);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cdmaNewSmsInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::newBroadcastSmsInd(int slotId,
+                              int indicationType, int token, RIL_Errno e, void *response,
+                              size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("newBroadcastSmsInd: invalid response");
+            return 0;
+        }
+
+        hidl_vec<uint8_t> data;
+        data.setToExternal((uint8_t *) response, responseLen);
+#if VDBG
+        RLOGD("newBroadcastSmsInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->newBroadcastSms(
+                convertIntToRadioIndicationType(indicationType), data);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("newBroadcastSmsInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cdmaRuimSmsStorageFullInd(int slotId,
+                                     int indicationType, int token, RIL_Errno e, void *response,
+                                     size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("cdmaRuimSmsStorageFullInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaRuimSmsStorageFull(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cdmaRuimSmsStorageFullInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::restrictedStateChangedInd(int slotId,
+                                     int indicationType, int token, RIL_Errno e, void *response,
+                                     size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("restrictedStateChangedInd: invalid response");
+            return 0;
+        }
+        int32_t state = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("restrictedStateChangedInd: state %d", state);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->restrictedStateChanged(
+                convertIntToRadioIndicationType(indicationType), (PhoneRestrictedState) state);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("restrictedStateChangedInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::enterEmergencyCallbackModeInd(int slotId,
+                                         int indicationType, int token, RIL_Errno e, void *response,
+                                         size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("enterEmergencyCallbackModeInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->enterEmergencyCallbackMode(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("enterEmergencyCallbackModeInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cdmaCallWaitingInd(int slotId,
+                              int indicationType, int token, RIL_Errno e, void *response,
+                              size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_CDMA_CallWaiting_v6)) {
+            RLOGE("cdmaCallWaitingInd: invalid response");
+            return 0;
+        }
+
+        CdmaCallWaiting callWaitingRecord = {};
+        RIL_CDMA_CallWaiting_v6 *callWaitingRil = ((RIL_CDMA_CallWaiting_v6 *) response);
+        callWaitingRecord.number = convertCharPtrToHidlString(callWaitingRil->number);
+        callWaitingRecord.numberPresentation =
+                (CdmaCallWaitingNumberPresentation) callWaitingRil->numberPresentation;
+        callWaitingRecord.name = convertCharPtrToHidlString(callWaitingRil->name);
+        convertRilCdmaSignalInfoRecordToHal(&callWaitingRil->signalInfoRecord,
+                callWaitingRecord.signalInfoRecord);
+        callWaitingRecord.numberType = (CdmaCallWaitingNumberType) callWaitingRil->number_type;
+        callWaitingRecord.numberPlan = (CdmaCallWaitingNumberPlan) callWaitingRil->number_plan;
+
+#if VDBG
+        RLOGD("cdmaCallWaitingInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaCallWaiting(
+                convertIntToRadioIndicationType(indicationType), callWaitingRecord);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cdmaCallWaitingInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cdmaOtaProvisionStatusInd(int slotId,
+                                     int indicationType, int token, RIL_Errno e, void *response,
+                                     size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("cdmaOtaProvisionStatusInd: invalid response");
+            return 0;
+        }
+        int32_t status = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("cdmaOtaProvisionStatusInd: status %d", status);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaOtaProvisionStatus(
+                convertIntToRadioIndicationType(indicationType), (CdmaOtaProvisionStatus) status);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cdmaOtaProvisionStatusInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cdmaInfoRecInd(int slotId,
+                          int indicationType, int token, RIL_Errno e, void *response,
+                          size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_CDMA_InformationRecords)) {
+            RLOGE("cdmaInfoRecInd: invalid response");
+            return 0;
+        }
+
+        CdmaInformationRecords records = {};
+        RIL_CDMA_InformationRecords *recordsRil = (RIL_CDMA_InformationRecords *) response;
+
+        char* string8 = NULL;
+        int num = MIN(recordsRil->numberOfInfoRecs, RIL_CDMA_MAX_NUMBER_OF_INFO_RECS);
+        if (recordsRil->numberOfInfoRecs > RIL_CDMA_MAX_NUMBER_OF_INFO_RECS) {
+            RLOGE("cdmaInfoRecInd: received %d recs which is more than %d, dropping "
+                    "additional ones", recordsRil->numberOfInfoRecs,
+                    RIL_CDMA_MAX_NUMBER_OF_INFO_RECS);
+        }
+        records.infoRec.resize(num);
+        for (int i = 0 ; i < num ; i++) {
+            CdmaInformationRecord *record = &records.infoRec[i];
+            RIL_CDMA_InformationRecord *infoRec = &recordsRil->infoRec[i];
+            record->name = (CdmaInfoRecName) infoRec->name;
+            // All vectors should be size 0 except one which will be size 1. Set everything to
+            // size 0 initially.
+            record->display.resize(0);
+            record->number.resize(0);
+            record->signal.resize(0);
+            record->redir.resize(0);
+            record->lineCtrl.resize(0);
+            record->clir.resize(0);
+            record->audioCtrl.resize(0);
+            switch (infoRec->name) {
+                case RIL_CDMA_DISPLAY_INFO_REC:
+                case RIL_CDMA_EXTENDED_DISPLAY_INFO_REC: {
+                    if (infoRec->rec.display.alpha_len > CDMA_ALPHA_INFO_BUFFER_LENGTH) {
+                        RLOGE("cdmaInfoRecInd: invalid display info response length %d "
+                                "expected not more than %d", (int) infoRec->rec.display.alpha_len,
+                                CDMA_ALPHA_INFO_BUFFER_LENGTH);
+                        return 0;
+                    }
+                    string8 = (char*) malloc((infoRec->rec.display.alpha_len + 1) * sizeof(char));
+                    if (string8 == NULL) {
+                        RLOGE("cdmaInfoRecInd: Memory allocation failed for "
+                                "responseCdmaInformationRecords");
+                        return 0;
+                    }
+                    memcpy(string8, infoRec->rec.display.alpha_buf, infoRec->rec.display.alpha_len);
+                    string8[(int)infoRec->rec.display.alpha_len] = '\0';
+
+                    record->display.resize(1);
+                    record->display[0].alphaBuf = string8;
+                    free(string8);
+                    string8 = NULL;
+                    break;
+                }
+
+                case RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC:
+                case RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC:
+                case RIL_CDMA_CONNECTED_NUMBER_INFO_REC: {
+                    if (infoRec->rec.number.len > CDMA_NUMBER_INFO_BUFFER_LENGTH) {
+                        RLOGE("cdmaInfoRecInd: invalid display info response length %d "
+                                "expected not more than %d", (int) infoRec->rec.number.len,
+                                CDMA_NUMBER_INFO_BUFFER_LENGTH);
+                        return 0;
+                    }
+                    string8 = (char*) malloc((infoRec->rec.number.len + 1) * sizeof(char));
+                    if (string8 == NULL) {
+                        RLOGE("cdmaInfoRecInd: Memory allocation failed for "
+                                "responseCdmaInformationRecords");
+                        return 0;
+                    }
+                    memcpy(string8, infoRec->rec.number.buf, infoRec->rec.number.len);
+                    string8[(int)infoRec->rec.number.len] = '\0';
+
+                    record->number.resize(1);
+                    record->number[0].number = string8;
+                    free(string8);
+                    string8 = NULL;
+                    record->number[0].numberType = infoRec->rec.number.number_type;
+                    record->number[0].numberPlan = infoRec->rec.number.number_plan;
+                    record->number[0].pi = infoRec->rec.number.pi;
+                    record->number[0].si = infoRec->rec.number.si;
+                    break;
+                }
+
+                case RIL_CDMA_SIGNAL_INFO_REC: {
+                    record->signal.resize(1);
+                    record->signal[0].isPresent = infoRec->rec.signal.isPresent;
+                    record->signal[0].signalType = infoRec->rec.signal.signalType;
+                    record->signal[0].alertPitch = infoRec->rec.signal.alertPitch;
+                    record->signal[0].signal = infoRec->rec.signal.signal;
+                    break;
+                }
+
+                case RIL_CDMA_REDIRECTING_NUMBER_INFO_REC: {
+                    if (infoRec->rec.redir.redirectingNumber.len >
+                                                  CDMA_NUMBER_INFO_BUFFER_LENGTH) {
+                        RLOGE("cdmaInfoRecInd: invalid display info response length %d "
+                                "expected not more than %d\n",
+                                (int)infoRec->rec.redir.redirectingNumber.len,
+                                CDMA_NUMBER_INFO_BUFFER_LENGTH);
+                        return 0;
+                    }
+                    string8 = (char*) malloc((infoRec->rec.redir.redirectingNumber.len + 1) *
+                            sizeof(char));
+                    if (string8 == NULL) {
+                        RLOGE("cdmaInfoRecInd: Memory allocation failed for "
+                                "responseCdmaInformationRecords");
+                        return 0;
+                    }
+                    memcpy(string8, infoRec->rec.redir.redirectingNumber.buf,
+                            infoRec->rec.redir.redirectingNumber.len);
+                    string8[(int)infoRec->rec.redir.redirectingNumber.len] = '\0';
+
+                    record->redir.resize(1);
+                    record->redir[0].redirectingNumber.number = string8;
+                    free(string8);
+                    string8 = NULL;
+                    record->redir[0].redirectingNumber.numberType =
+                            infoRec->rec.redir.redirectingNumber.number_type;
+                    record->redir[0].redirectingNumber.numberPlan =
+                            infoRec->rec.redir.redirectingNumber.number_plan;
+                    record->redir[0].redirectingNumber.pi = infoRec->rec.redir.redirectingNumber.pi;
+                    record->redir[0].redirectingNumber.si = infoRec->rec.redir.redirectingNumber.si;
+                    record->redir[0].redirectingReason =
+                            (CdmaRedirectingReason) infoRec->rec.redir.redirectingReason;
+                    break;
+                }
+
+                case RIL_CDMA_LINE_CONTROL_INFO_REC: {
+                    record->lineCtrl.resize(1);
+                    record->lineCtrl[0].lineCtrlPolarityIncluded =
+                            infoRec->rec.lineCtrl.lineCtrlPolarityIncluded;
+                    record->lineCtrl[0].lineCtrlToggle = infoRec->rec.lineCtrl.lineCtrlToggle;
+                    record->lineCtrl[0].lineCtrlReverse = infoRec->rec.lineCtrl.lineCtrlReverse;
+                    record->lineCtrl[0].lineCtrlPowerDenial =
+                            infoRec->rec.lineCtrl.lineCtrlPowerDenial;
+                    break;
+                }
+
+                case RIL_CDMA_T53_CLIR_INFO_REC: {
+                    record->clir.resize(1);
+                    record->clir[0].cause = infoRec->rec.clir.cause;
+                    break;
+                }
+
+                case RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC: {
+                    record->audioCtrl.resize(1);
+                    record->audioCtrl[0].upLink = infoRec->rec.audioCtrl.upLink;
+                    record->audioCtrl[0].downLink = infoRec->rec.audioCtrl.downLink;
+                    break;
+                }
+
+                case RIL_CDMA_T53_RELEASE_INFO_REC:
+                    RLOGE("cdmaInfoRecInd: RIL_CDMA_T53_RELEASE_INFO_REC: INVALID");
+                    return 0;
+
+                default:
+                    RLOGE("cdmaInfoRecInd: Incorrect name value");
+                    return 0;
+            }
+        }
+
+#if VDBG
+        RLOGD("cdmaInfoRecInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaInfoRec(
+                convertIntToRadioIndicationType(indicationType), records);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cdmaInfoRecInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::indicateRingbackToneInd(int slotId,
+                                   int indicationType, int token, RIL_Errno e, void *response,
+                                   size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("indicateRingbackToneInd: invalid response");
+            return 0;
+        }
+        bool start = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("indicateRingbackToneInd: start %d", start);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->indicateRingbackTone(
+                convertIntToRadioIndicationType(indicationType), start);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("indicateRingbackToneInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::resendIncallMuteInd(int slotId,
+                               int indicationType, int token, RIL_Errno e, void *response,
+                               size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("resendIncallMuteInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->resendIncallMute(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("resendIncallMuteInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cdmaSubscriptionSourceChangedInd(int slotId,
+                                            int indicationType, int token, RIL_Errno e,
+                                            void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("cdmaSubscriptionSourceChangedInd: invalid response");
+            return 0;
+        }
+        int32_t cdmaSource = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("cdmaSubscriptionSourceChangedInd: cdmaSource %d", cdmaSource);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->
+                cdmaSubscriptionSourceChanged(convertIntToRadioIndicationType(indicationType),
+                (CdmaSubscriptionSource) cdmaSource);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cdmaSubscriptionSourceChangedInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::cdmaPrlChangedInd(int slotId,
+                             int indicationType, int token, RIL_Errno e, void *response,
+                             size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("cdmaPrlChangedInd: invalid response");
+            return 0;
+        }
+        int32_t version = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("cdmaPrlChangedInd: version %d", version);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->cdmaPrlChanged(
+                convertIntToRadioIndicationType(indicationType), version);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cdmaPrlChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::exitEmergencyCallbackModeInd(int slotId,
+                                        int indicationType, int token, RIL_Errno e, void *response,
+                                        size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("exitEmergencyCallbackModeInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->exitEmergencyCallbackMode(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("exitEmergencyCallbackModeInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::rilConnectedInd(int slotId,
+                           int indicationType, int token, RIL_Errno e, void *response,
+                           size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        RLOGD("rilConnectedInd");
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->rilConnected(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("rilConnectedInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::voiceRadioTechChangedInd(int slotId,
+                                    int indicationType, int token, RIL_Errno e, void *response,
+                                    size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("voiceRadioTechChangedInd: invalid response");
+            return 0;
+        }
+        int32_t rat = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("voiceRadioTechChangedInd: rat %d", rat);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->voiceRadioTechChanged(
+                convertIntToRadioIndicationType(indicationType), (RadioTechnology) rat);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("voiceRadioTechChangedInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+void convertRilCellInfoListToHal(void *response, size_t responseLen, hidl_vec<CellInfo>& records) {
+    int num = responseLen / sizeof(RIL_CellInfo_v12);
+    records.resize(num);
+
+    RIL_CellInfo_v12 *rillCellInfo = (RIL_CellInfo_v12 *) response;
+    for (int i = 0; i < num; i++) {
+        records[i].cellInfoType = (CellInfoType) rillCellInfo->cellInfoType;
+        records[i].registered = rillCellInfo->registered;
+        records[i].timeStampType = (TimeStampType) rillCellInfo->timeStampType;
+        records[i].timeStamp = rillCellInfo->timeStamp;
+        // All vectors should be size 0 except one which will be size 1. Set everything to
+        // size 0 initially.
+        records[i].gsm.resize(0);
+        records[i].wcdma.resize(0);
+        records[i].cdma.resize(0);
+        records[i].lte.resize(0);
+        records[i].tdscdma.resize(0);
+        switch(rillCellInfo->cellInfoType) {
+            case RIL_CELL_INFO_TYPE_GSM: {
+                records[i].gsm.resize(1);
+                CellInfoGsm *cellInfoGsm = &records[i].gsm[0];
+                cellInfoGsm->cellIdentityGsm.mcc =
+                        std::to_string(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mcc);
+                cellInfoGsm->cellIdentityGsm.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mnc);
+                cellInfoGsm->cellIdentityGsm.lac =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.lac;
+                cellInfoGsm->cellIdentityGsm.cid =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.cid;
+                cellInfoGsm->cellIdentityGsm.arfcn =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.arfcn;
+                cellInfoGsm->cellIdentityGsm.bsic =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.bsic;
+                cellInfoGsm->signalStrengthGsm.signalStrength =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.signalStrength;
+                cellInfoGsm->signalStrengthGsm.bitErrorRate =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.bitErrorRate;
+                cellInfoGsm->signalStrengthGsm.timingAdvance =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.timingAdvance;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_WCDMA: {
+                records[i].wcdma.resize(1);
+                CellInfoWcdma *cellInfoWcdma = &records[i].wcdma[0];
+                cellInfoWcdma->cellIdentityWcdma.mcc =
+                        std::to_string(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mcc);
+                cellInfoWcdma->cellIdentityWcdma.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mnc);
+                cellInfoWcdma->cellIdentityWcdma.lac =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.lac;
+                cellInfoWcdma->cellIdentityWcdma.cid =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.cid;
+                cellInfoWcdma->cellIdentityWcdma.psc =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.psc;
+                cellInfoWcdma->cellIdentityWcdma.uarfcn =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.uarfcn;
+                cellInfoWcdma->signalStrengthWcdma.signalStrength =
+                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.signalStrength;
+                cellInfoWcdma->signalStrengthWcdma.bitErrorRate =
+                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.bitErrorRate;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_CDMA: {
+                records[i].cdma.resize(1);
+                CellInfoCdma *cellInfoCdma = &records[i].cdma[0];
+                cellInfoCdma->cellIdentityCdma.networkId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.networkId;
+                cellInfoCdma->cellIdentityCdma.systemId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.systemId;
+                cellInfoCdma->cellIdentityCdma.baseStationId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.basestationId;
+                cellInfoCdma->cellIdentityCdma.longitude =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.longitude;
+                cellInfoCdma->cellIdentityCdma.latitude =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.latitude;
+                cellInfoCdma->signalStrengthCdma.dbm =
+                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.dbm;
+                cellInfoCdma->signalStrengthCdma.ecio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.ecio;
+                cellInfoCdma->signalStrengthEvdo.dbm =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.dbm;
+                cellInfoCdma->signalStrengthEvdo.ecio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.ecio;
+                cellInfoCdma->signalStrengthEvdo.signalNoiseRatio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.signalNoiseRatio;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_LTE: {
+                records[i].lte.resize(1);
+                CellInfoLte *cellInfoLte = &records[i].lte[0];
+                cellInfoLte->cellIdentityLte.mcc =
+                        std::to_string(rillCellInfo->CellInfo.lte.cellIdentityLte.mcc);
+                cellInfoLte->cellIdentityLte.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.lte.cellIdentityLte.mnc);
+                cellInfoLte->cellIdentityLte.ci =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.ci;
+                cellInfoLte->cellIdentityLte.pci =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.pci;
+                cellInfoLte->cellIdentityLte.tac =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.tac;
+                cellInfoLte->cellIdentityLte.earfcn =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.earfcn;
+                cellInfoLte->signalStrengthLte.signalStrength =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.signalStrength;
+                cellInfoLte->signalStrengthLte.rsrp =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrp;
+                cellInfoLte->signalStrengthLte.rsrq =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrq;
+                cellInfoLte->signalStrengthLte.rssnr =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rssnr;
+                cellInfoLte->signalStrengthLte.cqi =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.cqi;
+                cellInfoLte->signalStrengthLte.timingAdvance =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.timingAdvance;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_TD_SCDMA: {
+                records[i].tdscdma.resize(1);
+                CellInfoTdscdma *cellInfoTdscdma = &records[i].tdscdma[0];
+                cellInfoTdscdma->cellIdentityTdscdma.mcc =
+                        std::to_string(rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mcc);
+                cellInfoTdscdma->cellIdentityTdscdma.mnc =
+                        ril::util::mnc::decode(
+                                rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mnc);
+                cellInfoTdscdma->cellIdentityTdscdma.lac =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.lac;
+                cellInfoTdscdma->cellIdentityTdscdma.cid =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cid;
+                cellInfoTdscdma->cellIdentityTdscdma.cpid =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cpid;
+                cellInfoTdscdma->signalStrengthTdscdma.rscp =
+                        rillCellInfo->CellInfo.tdscdma.signalStrengthTdscdma.rscp;
+                break;
+            }
+            default: {
+                break;
+            }
+        }
+        rillCellInfo += 1;
+    }
+}
+
+void convertRilCellInfoListToHal_1_2(void *response, size_t responseLen, hidl_vec<V1_2::CellInfo>& records) {
+    int num = responseLen / sizeof(RIL_CellInfo_v12);
+    records.resize(num);
+    RIL_CellInfo_v12 *rillCellInfo = (RIL_CellInfo_v12 *) response;
+    for (int i = 0; i < num; i++) {
+        records[i].cellInfoType = (CellInfoType) rillCellInfo->cellInfoType;
+        records[i].registered = rillCellInfo->registered;
+        records[i].timeStampType = (TimeStampType) rillCellInfo->timeStampType;
+        records[i].timeStamp = rillCellInfo->timeStamp;
+        records[i].connectionStatus =(V1_2::CellConnectionStatus)0;
+        // All vectors should be size 0 except one which will be size 1. Set everything to
+        // size 0 initially.
+        records[i].gsm.resize(0);
+        records[i].wcdma.resize(0);
+        records[i].cdma.resize(0);
+        records[i].lte.resize(0);
+        records[i].tdscdma.resize(0);
+        switch(rillCellInfo->cellInfoType) {
+            case RIL_CELL_INFO_TYPE_GSM: {
+                records[i].gsm.resize(1);
+                V1_2::CellInfoGsm *cellInfoGsm = &records[i].gsm[0];
+                cellInfoGsm->cellIdentityGsm.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mcc);
+                cellInfoGsm->cellIdentityGsm.base.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mnc);
+                cellInfoGsm->cellIdentityGsm.base.lac =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.lac;
+                cellInfoGsm->cellIdentityGsm.base.cid =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.cid;
+                cellInfoGsm->cellIdentityGsm.base.arfcn =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.arfcn;
+                cellInfoGsm->cellIdentityGsm.base.bsic =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.bsic;
+                cellInfoGsm->signalStrengthGsm.signalStrength =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.signalStrength;
+                cellInfoGsm->signalStrengthGsm.bitErrorRate =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.bitErrorRate;
+                cellInfoGsm->signalStrengthGsm.timingAdvance =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.timingAdvance;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_WCDMA: {
+                records[i].wcdma.resize(1);
+                V1_2::CellInfoWcdma *cellInfoWcdma = &records[i].wcdma[0];
+                cellInfoWcdma->cellIdentityWcdma.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mcc);
+                cellInfoWcdma->cellIdentityWcdma.base.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mnc);
+                cellInfoWcdma->cellIdentityWcdma.base.lac =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.lac;
+                cellInfoWcdma->cellIdentityWcdma.base.cid =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.cid;
+                cellInfoWcdma->cellIdentityWcdma.base.psc =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.psc;
+                cellInfoWcdma->cellIdentityWcdma.base.uarfcn =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.uarfcn;
+                cellInfoWcdma->signalStrengthWcdma.base.signalStrength =
+                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.signalStrength;
+                cellInfoWcdma->signalStrengthWcdma.base.bitErrorRate =
+                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.bitErrorRate;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_CDMA: {
+                records[i].cdma.resize(1);
+                V1_2::CellInfoCdma *cellInfoCdma = &records[i].cdma[0];
+                cellInfoCdma->cellIdentityCdma.base.networkId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.networkId;
+                cellInfoCdma->cellIdentityCdma.base.systemId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.systemId;
+                cellInfoCdma->cellIdentityCdma.base.baseStationId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.basestationId;
+                cellInfoCdma->cellIdentityCdma.base.longitude =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.longitude;
+                cellInfoCdma->cellIdentityCdma.base.latitude =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.latitude;
+                cellInfoCdma->signalStrengthCdma.dbm =
+                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.dbm;
+                cellInfoCdma->signalStrengthCdma.ecio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.ecio;
+                cellInfoCdma->signalStrengthEvdo.dbm =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.dbm;
+                cellInfoCdma->signalStrengthEvdo.ecio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.ecio;
+                cellInfoCdma->signalStrengthEvdo.signalNoiseRatio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.signalNoiseRatio;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_LTE: {
+                records[i].lte.resize(1);
+                V1_2::CellInfoLte *cellInfoLte = &records[i].lte[0];
+                cellInfoLte->cellIdentityLte.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.lte.cellIdentityLte.mcc);
+                cellInfoLte->cellIdentityLte.base.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.lte.cellIdentityLte.mnc);
+                cellInfoLte->cellIdentityLte.base.ci =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.ci;
+                cellInfoLte->cellIdentityLte.base.pci =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.pci;
+                cellInfoLte->cellIdentityLte.base.tac =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.tac;
+                cellInfoLte->cellIdentityLte.base.earfcn =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.earfcn;
+                cellInfoLte->signalStrengthLte.signalStrength =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.signalStrength;
+                cellInfoLte->signalStrengthLte.rsrp =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrp;
+                cellInfoLte->signalStrengthLte.rsrq =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrq;
+                cellInfoLte->signalStrengthLte.rssnr =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rssnr;
+                cellInfoLte->signalStrengthLte.cqi =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.cqi;
+                cellInfoLte->signalStrengthLte.timingAdvance =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.timingAdvance;
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_TD_SCDMA: {
+                records[i].tdscdma.resize(1);
+                V1_2::CellInfoTdscdma *cellInfoTdscdma = &records[i].tdscdma[0];
+                cellInfoTdscdma->cellIdentityTdscdma.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mcc);
+                cellInfoTdscdma->cellIdentityTdscdma.base.mnc =
+                        ril::util::mnc::decode(
+                                rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mnc);
+                cellInfoTdscdma->cellIdentityTdscdma.base.lac =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.lac;
+                cellInfoTdscdma->cellIdentityTdscdma.base.cid =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cid;
+                cellInfoTdscdma->cellIdentityTdscdma.base.cpid =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cpid;
+                cellInfoTdscdma->signalStrengthTdscdma.rscp =
+                        rillCellInfo->CellInfo.tdscdma.signalStrengthTdscdma.rscp;
+                break;
+            }
+            default: {
+                break;
+            }
+        }
+        rillCellInfo += 1;
+    }
+}
+
+void convertRilCellInfoListToHal_1_4(void *response, size_t responseLen, hidl_vec<V1_4::CellInfo>& records) {
+    int num = responseLen / sizeof(RIL_CellInfo_v16);
+    records.resize(num);
+    RIL_CellInfo_v16 *rillCellInfo = (RIL_CellInfo_v16 *) response;
+    for (int i = 0; i < num; i++) {
+        records[i].isRegistered = rillCellInfo->registered;
+        records[i].connectionStatus = (V1_2::CellConnectionStatus)rillCellInfo->connectionStatus;
+
+        switch(rillCellInfo->cellInfoType) {
+            case RIL_CELL_INFO_TYPE_GSM: {
+                V1_2::CellInfoGsm cellInfoGsm;
+                cellInfoGsm.cellIdentityGsm.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mcc);
+                cellInfoGsm.cellIdentityGsm.base.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.gsm.cellIdentityGsm.mnc);
+                cellInfoGsm.cellIdentityGsm.base.lac =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.lac;
+                cellInfoGsm.cellIdentityGsm.base.cid =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.cid;
+                cellInfoGsm.cellIdentityGsm.base.arfcn =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.arfcn;
+                cellInfoGsm.cellIdentityGsm.base.bsic =
+                        rillCellInfo->CellInfo.gsm.cellIdentityGsm.bsic;
+                cellInfoGsm.signalStrengthGsm.signalStrength =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.signalStrength;
+                cellInfoGsm.signalStrengthGsm.bitErrorRate =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.bitErrorRate;
+                cellInfoGsm.signalStrengthGsm.timingAdvance =
+                        rillCellInfo->CellInfo.gsm.signalStrengthGsm.timingAdvance;
+                records[i].info.gsm(cellInfoGsm);
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_WCDMA: {
+                V1_2::CellInfoWcdma cellInfoWcdma;
+                cellInfoWcdma.cellIdentityWcdma.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mcc);
+                cellInfoWcdma.cellIdentityWcdma.base.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.mnc);
+                cellInfoWcdma.cellIdentityWcdma.base.lac =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.lac;
+                cellInfoWcdma.cellIdentityWcdma.base.cid =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.cid;
+                cellInfoWcdma.cellIdentityWcdma.base.psc =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.psc;
+                cellInfoWcdma.cellIdentityWcdma.base.uarfcn =
+                        rillCellInfo->CellInfo.wcdma.cellIdentityWcdma.uarfcn;
+                cellInfoWcdma.signalStrengthWcdma.base.signalStrength =
+                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.signalStrength;
+                cellInfoWcdma.signalStrengthWcdma.base.bitErrorRate =
+                        rillCellInfo->CellInfo.wcdma.signalStrengthWcdma.bitErrorRate;
+                records[i].info.wcdma(cellInfoWcdma);
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_CDMA: {
+                V1_2::CellInfoCdma cellInfoCdma;
+                cellInfoCdma.cellIdentityCdma.base.networkId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.networkId;
+                cellInfoCdma.cellIdentityCdma.base.systemId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.systemId;
+                cellInfoCdma.cellIdentityCdma.base.baseStationId =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.basestationId;
+                cellInfoCdma.cellIdentityCdma.base.longitude =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.longitude;
+                cellInfoCdma.cellIdentityCdma.base.latitude =
+                        rillCellInfo->CellInfo.cdma.cellIdentityCdma.latitude;
+                cellInfoCdma.signalStrengthCdma.dbm =
+                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.dbm;
+                cellInfoCdma.signalStrengthCdma.ecio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthCdma.ecio;
+                cellInfoCdma.signalStrengthEvdo.dbm =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.dbm;
+                cellInfoCdma.signalStrengthEvdo.ecio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.ecio;
+                cellInfoCdma.signalStrengthEvdo.signalNoiseRatio =
+                        rillCellInfo->CellInfo.cdma.signalStrengthEvdo.signalNoiseRatio;
+                records[i].info.cdma(cellInfoCdma);
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_LTE: {
+                V1_4::CellInfoLte cellInfoLte;
+                cellInfoLte.base.cellIdentityLte.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.lte.cellIdentityLte.mcc);
+                cellInfoLte.base.cellIdentityLte.base.mnc =
+                        ril::util::mnc::decode(rillCellInfo->CellInfo.lte.cellIdentityLte.mnc);
+                cellInfoLte.base.cellIdentityLte.base.ci =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.ci;
+                cellInfoLte.base.cellIdentityLte.base.pci =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.pci;
+                cellInfoLte.base.cellIdentityLte.base.tac =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.tac;
+                cellInfoLte.base.cellIdentityLte.base.earfcn =
+                        rillCellInfo->CellInfo.lte.cellIdentityLte.earfcn;
+                cellInfoLte.base.signalStrengthLte.signalStrength =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.signalStrength;
+                cellInfoLte.base.signalStrengthLte.rsrp =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrp;
+                cellInfoLte.base.signalStrengthLte.rsrq =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rsrq;
+                cellInfoLte.base.signalStrengthLte.rssnr =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.rssnr;
+                cellInfoLte.base.signalStrengthLte.cqi =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.cqi;
+                cellInfoLte.base.signalStrengthLte.timingAdvance =
+                        rillCellInfo->CellInfo.lte.signalStrengthLte.timingAdvance;
+                records[i].info.lte(cellInfoLte);
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_TD_SCDMA: {
+                V1_2::CellInfoTdscdma cellInfoTdscdma;
+                cellInfoTdscdma.cellIdentityTdscdma.base.mcc =
+                        std::to_string(rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mcc);
+                cellInfoTdscdma.cellIdentityTdscdma.base.mnc =
+                        ril::util::mnc::decode(
+                                rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.mnc);
+                cellInfoTdscdma.cellIdentityTdscdma.base.lac =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.lac;
+                cellInfoTdscdma.cellIdentityTdscdma.base.cid =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cid;
+                cellInfoTdscdma.cellIdentityTdscdma.base.cpid =
+                        rillCellInfo->CellInfo.tdscdma.cellIdentityTdscdma.cpid;
+                cellInfoTdscdma.signalStrengthTdscdma.rscp =
+                        rillCellInfo->CellInfo.tdscdma.signalStrengthTdscdma.rscp;
+                records[i].info.tdscdma(cellInfoTdscdma);
+                break;
+            }
+
+            case RIL_CELL_INFO_TYPE_NR: {
+                V1_4::CellInfoNr cellInfoNr;
+                cellInfoNr.cellidentity.mcc =
+                        std::to_string(rillCellInfo->CellInfo.nr.cellidentity.mcc);
+                cellInfoNr.cellidentity.mnc =
+                        ril::util::mnc::decode(
+                                rillCellInfo->CellInfo.nr.cellidentity.mnc);
+                cellInfoNr.cellidentity.nci =
+                        rillCellInfo->CellInfo.nr.cellidentity.nci;
+                cellInfoNr.cellidentity.pci =
+                        rillCellInfo->CellInfo.nr.cellidentity.pci;
+                cellInfoNr.cellidentity.tac =
+                        rillCellInfo->CellInfo.nr.cellidentity.tac;
+                cellInfoNr.cellidentity.nrarfcn =
+                        rillCellInfo->CellInfo.nr.cellidentity.nrarfcn;
+                cellInfoNr.cellidentity.operatorNames.alphaLong =
+                        convertCharPtrToHidlString(rillCellInfo->CellInfo.nr.cellidentity.operatorNames.alphaLong);
+                cellInfoNr.cellidentity.operatorNames.alphaShort =
+                        convertCharPtrToHidlString(rillCellInfo->CellInfo.nr.cellidentity.operatorNames.alphaShort);
+
+                cellInfoNr.signalStrength.ssRsrp =
+                        rillCellInfo->CellInfo.nr.signalStrength.ssRsrp;
+                cellInfoNr.signalStrength.ssRsrq =
+                        rillCellInfo->CellInfo.nr.signalStrength.ssRsrq;
+                cellInfoNr.signalStrength.ssSinr =
+                        rillCellInfo->CellInfo.nr.signalStrength.ssSinr;
+                cellInfoNr.signalStrength.csiRsrp =
+                        rillCellInfo->CellInfo.nr.signalStrength.csiRsrp;
+                cellInfoNr.signalStrength.csiRsrq =
+                        rillCellInfo->CellInfo.nr.signalStrength.csiRsrq;
+                cellInfoNr.signalStrength.csiSinr =
+                        rillCellInfo->CellInfo.nr.signalStrength.csiSinr;
+                records[i].info.nr(cellInfoNr);
+                break;
+            }
+            default: {
+                break;
+            }
+        }
+        rillCellInfo += 1;
+    }
+}
+
+int radio_1_6::cellInfoListInd(int slotId,
+                           int indicationType, int token, RIL_Errno e, void *response,
+                           size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if ((response == NULL && responseLen != 0) || responseLen % sizeof(RIL_CellInfo_v12) != 0) {
+            RLOGE("cellInfoListInd: invalid response");
+            return 0;
+        }
+
+        hidl_vec<CellInfo> records;
+        convertRilCellInfoListToHal(response, responseLen, records);
+
+#if VDBG
+        RLOGD("cellInfoListInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->cellInfoList(
+                convertIntToRadioIndicationType(indicationType), records);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("cellInfoListInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::imsNetworkStateChangedInd(int slotId,
+                                     int indicationType, int token, RIL_Errno e, void *response,
+                                     size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+#if VDBG
+        RLOGD("imsNetworkStateChangedInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->imsNetworkStateChanged(
+                convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("imsNetworkStateChangedInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::subscriptionStatusChangedInd(int slotId,
+                                        int indicationType, int token, RIL_Errno e, void *response,
+                                        size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("subscriptionStatusChangedInd: invalid response");
+            return 0;
+        }
+        bool activate = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("subscriptionStatusChangedInd: activate %d", activate);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->subscriptionStatusChanged(
+                convertIntToRadioIndicationType(indicationType), activate);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("subscriptionStatusChangedInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::srvccStateNotifyInd(int slotId,
+                               int indicationType, int token, RIL_Errno e, void *response,
+                               size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(int)) {
+            RLOGE("srvccStateNotifyInd: invalid response");
+            return 0;
+        }
+        int32_t state = ((int32_t *) response)[0];
+#if VDBG
+        RLOGD("srvccStateNotifyInd: rat %d", state);
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->srvccStateNotify(
+                convertIntToRadioIndicationType(indicationType), (SrvccState) state);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("srvccStateNotifyInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+void convertRilHardwareConfigListToHal(void *response, size_t responseLen,
+        hidl_vec<HardwareConfig>& records) {
+    int num = responseLen / sizeof(RIL_HardwareConfig);
+    records.resize(num);
+
+    RIL_HardwareConfig *rilHardwareConfig = (RIL_HardwareConfig *) response;
+    for (int i = 0; i < num; i++) {
+        records[i].type = (HardwareConfigType) rilHardwareConfig[i].type;
+        records[i].uuid = convertCharPtrToHidlString(rilHardwareConfig[i].uuid);
+        records[i].state = (HardwareConfigState) rilHardwareConfig[i].state;
+        switch (rilHardwareConfig[i].type) {
+            case RIL_HARDWARE_CONFIG_MODEM: {
+                records[i].modem.resize(1);
+                records[i].sim.resize(0);
+                HardwareConfigModem *hwConfigModem = &records[i].modem[0];
+                hwConfigModem->rat = rilHardwareConfig[i].cfg.modem.rat;
+                hwConfigModem->maxVoice = rilHardwareConfig[i].cfg.modem.maxVoice;
+                hwConfigModem->maxData = rilHardwareConfig[i].cfg.modem.maxData;
+                hwConfigModem->maxStandby = rilHardwareConfig[i].cfg.modem.maxStandby;
+                break;
+            }
+
+            case RIL_HARDWARE_CONFIG_SIM: {
+                records[i].sim.resize(1);
+                records[i].modem.resize(0);
+                records[i].sim[0].modemUuid =
+                        convertCharPtrToHidlString(rilHardwareConfig[i].cfg.sim.modemUuid);
+                break;
+            }
+        }
+    }
+}
+
+int radio_1_6::hardwareConfigChangedInd(int slotId,
+                                    int indicationType, int token, RIL_Errno e, void *response,
+                                    size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if ((response == NULL && responseLen != 0)
+                || responseLen % sizeof(RIL_HardwareConfig) != 0) {
+            RLOGE("hardwareConfigChangedInd: invalid response");
+            return 0;
+        }
+
+        hidl_vec<HardwareConfig> configs;
+        convertRilHardwareConfigListToHal(response, responseLen, configs);
+
+#if VDBG
+        RLOGD("hardwareConfigChangedInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->hardwareConfigChanged(
+                convertIntToRadioIndicationType(indicationType), configs);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("hardwareConfigChangedInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+void convertRilRadioCapabilityToHal(void *response, size_t responseLen, RadioCapability& rc) {
+    RIL_RadioCapability *rilRadioCapability = (RIL_RadioCapability *) response;
+    rc.session = rilRadioCapability->session;
+    rc.phase = (V1_0::RadioCapabilityPhase) rilRadioCapability->phase;
+    rc.raf = rilRadioCapability->rat;
+    rc.logicalModemUuid = convertCharPtrToHidlString(rilRadioCapability->logicalModemUuid);
+    rc.status = (V1_0::RadioCapabilityStatus) rilRadioCapability->status;
+}
+
+int radio_1_6::radioCapabilityIndicationInd(int slotId,
+                                        int indicationType, int token, RIL_Errno e, void *response,
+                                        size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_RadioCapability)) {
+            RLOGE("radioCapabilityIndicationInd: invalid response");
+            return 0;
+        }
+
+        RadioCapability rc = {};
+        convertRilRadioCapabilityToHal(response, responseLen, rc);
+
+#if VDBG
+        RLOGD("radioCapabilityIndicationInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->radioCapabilityIndication(
+                convertIntToRadioIndicationType(indicationType), rc);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("radioCapabilityIndicationInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+bool isServiceTypeCfQuery(RIL_SsServiceType serType, RIL_SsRequestType reqType) {
+    if ((reqType == SS_INTERROGATION) &&
+        (serType == SS_CFU ||
+         serType == SS_CF_BUSY ||
+         serType == SS_CF_NO_REPLY ||
+         serType == SS_CF_NOT_REACHABLE ||
+         serType == SS_CF_ALL ||
+         serType == SS_CF_ALL_CONDITIONAL)) {
+        return true;
+    }
+    return false;
+}
+
+int radio_1_6::onSupplementaryServiceIndicationInd(int slotId,
+                                               int indicationType, int token, RIL_Errno e,
+                                               void *response, size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_StkCcUnsolSsResponse)) {
+            RLOGE("onSupplementaryServiceIndicationInd: invalid response");
+            return 0;
+        }
+
+        RIL_StkCcUnsolSsResponse *rilSsResponse = (RIL_StkCcUnsolSsResponse *) response;
+        StkCcUnsolSsResult ss = {};
+        ss.serviceType = (SsServiceType) rilSsResponse->serviceType;
+        ss.requestType = (SsRequestType) rilSsResponse->requestType;
+        ss.teleserviceType = (SsTeleserviceType) rilSsResponse->teleserviceType;
+        ss.serviceClass = rilSsResponse->serviceClass;
+        ss.result = (RadioError) rilSsResponse->result;
+
+        if (isServiceTypeCfQuery(rilSsResponse->serviceType, rilSsResponse->requestType)) {
+#if VDBG
+            RLOGD("onSupplementaryServiceIndicationInd CF type, num of Cf elements %d",
+                    rilSsResponse->cfData.numValidIndexes);
+#endif
+            if (rilSsResponse->cfData.numValidIndexes > NUM_SERVICE_CLASSES) {
+                RLOGE("onSupplementaryServiceIndicationInd numValidIndexes is greater than "
+                        "max value %d, truncating it to max value", NUM_SERVICE_CLASSES);
+                rilSsResponse->cfData.numValidIndexes = NUM_SERVICE_CLASSES;
+            }
+
+            ss.cfData.resize(1);
+            ss.ssInfo.resize(0);
+
+            /* number of call info's */
+            ss.cfData[0].cfInfo.resize(rilSsResponse->cfData.numValidIndexes);
+
+            for (int i = 0; i < rilSsResponse->cfData.numValidIndexes; i++) {
+                 RIL_CallForwardInfo cf = rilSsResponse->cfData.cfInfo[i];
+                 CallForwardInfo *cfInfo = &ss.cfData[0].cfInfo[i];
+
+                 cfInfo->status = (CallForwardInfoStatus) cf.status;
+                 cfInfo->reason = cf.reason;
+                 cfInfo->serviceClass = cf.serviceClass;
+                 cfInfo->toa = cf.toa;
+                 cfInfo->number = convertCharPtrToHidlString(cf.number);
+                 cfInfo->timeSeconds = cf.timeSeconds;
+#if VDBG
+                 RLOGD("onSupplementaryServiceIndicationInd: "
+                        "Data: %d,reason=%d,cls=%d,toa=%d,num=%s,tout=%d],", cf.status,
+                        cf.reason, cf.serviceClass, cf.toa, (char*)cf.number, cf.timeSeconds);
+#endif
+            }
+        } else {
+            ss.ssInfo.resize(1);
+            ss.cfData.resize(0);
+
+            /* each int */
+            ss.ssInfo[0].ssInfo.resize(SS_INFO_MAX);
+            for (int i = 0; i < SS_INFO_MAX; i++) {
+#if VDBG
+                 RLOGD("onSupplementaryServiceIndicationInd: Data: %d",
+                        rilSsResponse->ssInfo[i]);
+#endif
+                 ss.ssInfo[0].ssInfo[i] = rilSsResponse->ssInfo[i];
+            }
+        }
+
+#if VDBG
+        RLOGD("onSupplementaryServiceIndicationInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->
+                onSupplementaryServiceIndication(convertIntToRadioIndicationType(indicationType),
+                ss);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("onSupplementaryServiceIndicationInd: "
+                "radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::stkCallControlAlphaNotifyInd(int slotId,
+                                        int indicationType, int token, RIL_Errno e, void *response,
+                                        size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("stkCallControlAlphaNotifyInd: invalid response");
+            return 0;
+        }
+#if VDBG
+        RLOGD("stkCallControlAlphaNotifyInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->stkCallControlAlphaNotify(
+                convertIntToRadioIndicationType(indicationType),
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("stkCallControlAlphaNotifyInd: radioService[%d]->mRadioIndication == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+void convertRilLceDataInfoToHal(void *response, size_t responseLen, LceDataInfo& lce) {
+    RIL_LceDataInfo *rilLceDataInfo = (RIL_LceDataInfo *)response;
+    lce.lastHopCapacityKbps = rilLceDataInfo->last_hop_capacity_kbps;
+    lce.confidenceLevel = rilLceDataInfo->confidence_level;
+    lce.lceSuspended = rilLceDataInfo->lce_suspended;
+}
+
+int radio_1_6::lceDataInd(int slotId,
+                      int indicationType, int token, RIL_Errno e, void *response,
+                      size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_LceDataInfo)) {
+            RLOGE("lceDataInd: invalid response");
+            return 0;
+        }
+
+        LceDataInfo lce = {};
+        convertRilLceDataInfoToHal(response, responseLen, lce);
+#if VDBG
+        RLOGD("lceDataInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->lceData(
+                convertIntToRadioIndicationType(indicationType), lce);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("lceDataInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::pcoDataInd(int slotId,
+                      int indicationType, int token, RIL_Errno e, void *response,
+                      size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen != sizeof(RIL_PCO_Data)) {
+            RLOGE("pcoDataInd: invalid response");
+            return 0;
+        }
+
+        PcoDataInfo pco = {};
+        RIL_PCO_Data *rilPcoData = (RIL_PCO_Data *)response;
+        pco.cid = rilPcoData->cid;
+        pco.bearerProto = convertCharPtrToHidlString(rilPcoData->bearer_proto);
+        pco.pcoId = rilPcoData->pco_id;
+        pco.contents.setToExternal((uint8_t *) rilPcoData->contents, rilPcoData->contents_length);
+
+#if VDBG
+        RLOGD("pcoDataInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->pcoData(
+                convertIntToRadioIndicationType(indicationType), pco);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("pcoDataInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::modemResetInd(int slotId,
+                         int indicationType, int token, RIL_Errno e, void *response,
+                         size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("modemResetInd: invalid response");
+            return 0;
+        }
+#if VDBG
+        RLOGD("modemResetInd");
+#endif
+        Return<void> retStatus = radioService[slotId]->mRadioIndication->modemReset(
+                convertIntToRadioIndicationType(indicationType),
+                convertCharPtrToHidlString((char *) response));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("modemResetInd: radioService[%d]->mRadioIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::networkScanResultInd(int slotId,
+                                int indicationType, int token, RIL_Errno e, void *response,
+                                size_t responseLen) {
+#if VDBG
+    RLOGD("networkScanResultInd");
+#endif
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndicationV1_4 != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("networkScanResultInd: invalid response");
+            return 0;
+        }
+        RLOGD("networkScanResultInd");
+
+#if VDBG
+        RLOGD("networkScanResultInd");
+#endif
+
+        RIL_NetworkScanResult *networkScanResult = (RIL_NetworkScanResult *) response;
+
+        V1_1::NetworkScanResult result;
+        result.status = (V1_1::ScanStatus) networkScanResult->status;
+        result.error = (RadioError) networkScanResult->error;
+        convertRilCellInfoListToHal(
+                networkScanResult->network_infos,
+                networkScanResult->network_infos_length * sizeof(RIL_CellInfo_v12),
+                result.networkInfos);
+
+        Return<void> retStatus = radioService[slotId]->mRadioIndicationV1_4->networkScanResult(
+                convertIntToRadioIndicationType(indicationType), result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("networkScanResultInd: radioService[%d]->mRadioIndicationV1_4 == NULL", slotId);
+    }
+    return 0;
+}
+
+int radio_1_6::carrierInfoForImsiEncryption(int slotId,
+                                  int indicationType, int token, RIL_Errno e, void *response,
+                                  size_t responseLen) {
+    if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndicationV1_4 != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("carrierInfoForImsiEncryption: invalid response");
+            return 0;
+        }
+        RLOGD("carrierInfoForImsiEncryption");
+        Return<void> retStatus = radioService[slotId]->mRadioIndicationV1_4->
+                carrierInfoForImsiEncryption(convertIntToRadioIndicationType(indicationType));
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("carrierInfoForImsiEncryption: radioService[%d]->mRadioIndicationV1_4 == NULL",
+                slotId);
+    }
+
+    return 0;
+}
+
+int radio_1_6::reportPhysicalChannelConfigs(int slotId, int indicationType,
+                                            int token, RIL_Errno e,
+                                            void *response,
+                                            size_t responseLen) {
+    if (radioService[slotId] != NULL &&
+        radioService[slotId]->mRadioIndicationV1_4 != NULL) {
+      int *configs = (int *)response;
+      ::android::hardware::hidl_vec<PhysicalChannelConfigV1_4> physChanConfig;
+      physChanConfig.resize(1);
+      physChanConfig[0].base.status =
+          (::android::hardware::radio::V1_2::CellConnectionStatus)configs[0];
+      physChanConfig[0].base.cellBandwidthDownlink = configs[1];
+      physChanConfig[0].rat =
+          (::android::hardware::radio::V1_4::RadioTechnology)configs[2];
+      physChanConfig[0].rfInfo.range(
+          (::android::hardware::radio::V1_4::FrequencyRange)configs[3]);
+      physChanConfig[0].contextIds.resize(1);
+      physChanConfig[0].contextIds[0] = configs[4];
+      RLOGD("reportPhysicalChannelConfigs: %d %d %d %d %d", configs[0],
+            configs[1], configs[2], configs[3], configs[4]);
+      Return<void> retStatus = radioService[slotId]
+          ->mRadioIndicationV1_4->currentPhysicalChannelConfigs_1_4(
+              RadioIndicationType::UNSOLICITED, physChanConfig);
+      radioService[slotId]->checkReturnStatus(retStatus);
+    } else {
+      RLOGE(
+          "reportPhysicalChannelConfigs: radioService[%d]->mRadioIndicationV1_4 "
+          "== NULL",
+          slotId);
+      return -1;
+    }
+
+  return 0;
+}
+
+int radio_1_6::keepaliveStatusInd(int slotId,
+                         int indicationType, int token, RIL_Errno e, void *response,
+                         size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): token=%d", __FUNCTION__, token);
+#endif
+    if (radioService[slotId] == NULL || radioService[slotId]->mRadioIndication == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioIndication == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    auto ret = V1_1::IRadioIndication::castFrom(
+        radioService[slotId]->mRadioIndication);
+    if (!ret.isOk()) {
+        RLOGE("%s: ret.isOk() == false for radioService[%d]", __FUNCTION__, slotId);
+        return 0;
+    }
+    sp<V1_1::IRadioIndication> radioIndicationV1_1 = ret;
+
+    if (response == NULL || responseLen != sizeof(V1_1::KeepaliveStatus)) {
+        RLOGE("%s: invalid response", __FUNCTION__);
+        return 0;
+    }
+
+    V1_1::KeepaliveStatus ks;
+    convertRilKeepaliveStatusToHal(static_cast<RIL_KeepaliveStatus*>(response), ks);
+
+    Return<void> retStatus = radioIndicationV1_1->keepaliveStatus(
+            convertIntToRadioIndicationType(indicationType), ks);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
+int radio_1_6::oemHookRawInd(int slotId,
+                         int indicationType, int token, RIL_Errno e, void *response,
+                         size_t responseLen) {
+    if (!kOemHookEnabled) return 0;
+
+    if (oemHookService[slotId] != NULL && oemHookService[slotId]->mOemHookIndication != NULL) {
+        if (response == NULL || responseLen == 0) {
+            RLOGE("oemHookRawInd: invalid response");
+            return 0;
+        }
+
+        hidl_vec<uint8_t> data;
+        data.setToExternal((uint8_t *) response, responseLen);
+#if VDBG
+        RLOGD("oemHookRawInd");
+#endif
+        Return<void> retStatus = oemHookService[slotId]->mOemHookIndication->oemHookRaw(
+                convertIntToRadioIndicationType(indicationType), data);
+        checkReturnStatus(slotId, retStatus, false);
+    } else {
+        RLOGE("oemHookRawInd: oemHookService[%d]->mOemHookIndication == NULL", slotId);
+    }
+
+    return 0;
+}
+
+void radio_1_6::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {
+    using namespace android::hardware;
+    int simCount = 1;
+    const char *serviceNames[] = {
+            android::RIL_getServiceName()
+            #if (SIM_COUNT >= 2)
+            , RIL2_SERVICE_NAME
+            #if (SIM_COUNT >= 3)
+            , RIL3_SERVICE_NAME
+            #if (SIM_COUNT >= 4)
+            , RIL4_SERVICE_NAME
+            #endif
+            #endif
+            #endif
+            };
+
+    #if (SIM_COUNT >= 2)
+    simCount = SIM_COUNT;
+    #endif
+
+    s_vendorFunctions = callbacks;
+    s_commands = commands;
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+    for (int i = 0; i < simCount; i++) {
+        pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(i);
+        int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+
+        RLOGD("sim i = %d registering ...", i);
+
+        radioService[i] = new RadioImpl_1_6;
+        radioService[i]->mSlotId = i;
+        RLOGD("registerService: initializing power state to POWER_UP");
+        radioService[i]->mSimCardPowerState = V1_1::CardPowerState::POWER_UP;
+        RLOGD("registerService: starting android::hardware::radio::V1_6::IRadio %s for slot %d",
+                serviceNames[i], i);
+        android::status_t status = radioService[i]->registerAsService(serviceNames[i]);
+        LOG_ALWAYS_FATAL_IF(status != android::OK, "status %d", status);
+
+        RLOGD("registerService: OemHook is enabled = %s", kOemHookEnabled ? "true" : "false");
+        if (kOemHookEnabled) {
+            oemHookService[i] = new OemHookImpl;
+            oemHookService[i]->mSlotId = i;
+            // status = oemHookService[i]->registerAsService(serviceNames[i]);
+        }
+
+        ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
+        assert(ret == 0);
+    }
+}
+
+void rilc_thread_pool() {
+    joinRpcThreadpool();
+}
+
+pthread_rwlock_t * radio_1_6::getRadioServiceRwlock(int slotId) {
+    pthread_rwlock_t *radioServiceRwlockPtr = &radioServiceRwlock;
+
+    #if (SIM_COUNT >= 2)
+    if (slotId == 2) radioServiceRwlockPtr = &radioServiceRwlock2;
+    #if (SIM_COUNT >= 3)
+    if (slotId == 3) radioServiceRwlockPtr = &radioServiceRwlock3;
+    #if (SIM_COUNT >= 4)
+    if (slotId == 4) radioServiceRwlockPtr = &radioServiceRwlock4;
+    #endif
+    #endif
+    #endif
+
+    return radioServiceRwlockPtr;
+}
+
+// should acquire write lock for the corresponding service before calling this
+void radio_1_6::setNitzTimeReceived(int slotId, long timeReceived) {
+    nitzTimeReceived[slotId] = timeReceived;
+}
diff --git a/guest/hals/ril/reference-libril/ril_service.h b/guest/hals/ril/reference-libril/ril_service.h
new file mode 100644
index 0000000..6821f2c
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_service.h
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef RIL_SERVICE_H
+#define RIL_SERVICE_H
+
+#include <guest/hals/ril/reference-libril/ril.h>
+#include <ril_internal.h>
+
+namespace radio_1_6 {
+void registerService(RIL_RadioFunctions *callbacks, android::CommandInfo *commands);
+
+int getIccCardStatusResponse(int slotId, int responseType,
+                            int token, RIL_Errno e, void *response, size_t responselen);
+
+int supplyIccPinForAppResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int supplyIccPukForAppResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int supplyIccPin2ForAppResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e, void *response,
+                               size_t responselen);
+
+int supplyIccPuk2ForAppResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e, void *response,
+                               size_t responselen);
+
+int changeIccPinForAppResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int changeIccPin2ForAppResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e, void *response,
+                               size_t responselen);
+
+int supplyNetworkDepersonalizationResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e,
+                                          void *response, size_t responselen);
+
+int getCurrentCallsResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e, void *response,
+                           size_t responselen);
+
+int dialResponse(int slotId,
+                int responseType, int serial, RIL_Errno e, void *response, size_t responselen);
+
+int getIMSIForAppResponse(int slotId, int responseType,
+                         int serial, RIL_Errno e, void *response, size_t responselen);
+
+int hangupConnectionResponse(int slotId, int responseType,
+                            int serial, RIL_Errno e, void *response, size_t responselen);
+
+int hangupWaitingOrBackgroundResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int hangupForegroundResumeBackgroundResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responselen);
+
+int switchWaitingOrHoldingAndActiveResponse(int slotId,
+                                           int responseType, int serial, RIL_Errno e,
+                                           void *response, size_t responselen);
+
+int conferenceResponse(int slotId, int responseType,
+                      int serial, RIL_Errno e, void *response, size_t responselen);
+
+int rejectCallResponse(int slotId, int responseType,
+                      int serial, RIL_Errno e, void *response, size_t responselen);
+
+int getLastCallFailCauseResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e, void *response,
+                                size_t responselen);
+
+int getSignalStrengthResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responseLen);
+
+int getVoiceRegistrationStateResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int getDataRegistrationStateResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responselen);
+
+int getOperatorResponse(int slotId,
+                       int responseType, int serial, RIL_Errno e, void *response,
+                       size_t responselen);
+
+int setRadioPowerResponse(int slotId,
+                         int responseType, int serial, RIL_Errno e, void *response,
+                         size_t responselen);
+
+int sendDtmfResponse(int slotId,
+                    int responseType, int serial, RIL_Errno e, void *response,
+                    size_t responselen);
+
+int sendSmsResponse(int slotId,
+                   int responseType, int serial, RIL_Errno e, void *response,
+                   size_t responselen);
+
+int sendSmsExpectMoreResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e, void *response,
+                             size_t responselen);
+
+int setupDataCallResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responseLen);
+
+int iccIOForAppResponse(int slotId,
+                       int responseType, int serial, RIL_Errno e, void *response,
+                       size_t responselen);
+
+int sendUssdResponse(int slotId,
+                    int responseType, int serial, RIL_Errno e, void *response,
+                    size_t responselen);
+
+int cancelPendingUssdResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e, void *response,
+                             size_t responselen);
+
+int getClirResponse(int slotId,
+                   int responseType, int serial, RIL_Errno e, void *response, size_t responselen);
+
+int setClirResponse(int slotId,
+                   int responseType, int serial, RIL_Errno e, void *response, size_t responselen);
+
+int getCallForwardStatusResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e, void *response,
+                                size_t responselen);
+
+int setCallForwardResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responselen);
+
+int getCallWaitingResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responselen);
+
+int setCallWaitingResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responselen);
+
+int acknowledgeLastIncomingGsmSmsResponse(int slotId,
+                                         int responseType, int serial, RIL_Errno e, void *response,
+                                         size_t responselen);
+
+int acceptCallResponse(int slotId,
+                      int responseType, int serial, RIL_Errno e, void *response,
+                      size_t responselen);
+
+int deactivateDataCallResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int getFacilityLockForAppResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int setFacilityLockForAppResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int setBarringPasswordResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int getNetworkSelectionModeResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e, void *response,
+                                   size_t responselen);
+
+int setNetworkSelectionModeAutomaticResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responselen);
+
+int setNetworkSelectionModeManualResponse(int slotId,
+                                         int responseType, int serial, RIL_Errno e, void *response,
+                                         size_t responselen);
+
+int getAvailableNetworksResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e, void *response,
+                                size_t responselen);
+
+int startNetworkScanResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e, void *response,
+                             size_t responselen);
+
+int stopNetworkScanResponse(int slotId,
+                            int responseType, int serial, RIL_Errno e, void *response,
+                            size_t responselen);
+
+int startDtmfResponse(int slotId,
+                     int responseType, int serial, RIL_Errno e, void *response,
+                     size_t responselen);
+
+int stopDtmfResponse(int slotId,
+                    int responseType, int serial, RIL_Errno e, void *response,
+                    size_t responselen);
+
+int getBasebandVersionResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int separateConnectionResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int setMuteResponse(int slotId,
+                   int responseType, int serial, RIL_Errno e, void *response,
+                   size_t responselen);
+
+int getMuteResponse(int slotId,
+                   int responseType, int serial, RIL_Errno e, void *response,
+                   size_t responselen);
+
+int getClipResponse(int slotId,
+                   int responseType, int serial, RIL_Errno e, void *response,
+                   size_t responselen);
+
+int getDataCallListResponse(int slotId,
+                            int responseType, int serial, RIL_Errno e,
+                            void *response, size_t responseLen);
+
+int setSuppServiceNotificationsResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e, void *response,
+                                       size_t responselen);
+
+int writeSmsToSimResponse(int slotId,
+                         int responseType, int serial, RIL_Errno e, void *response,
+                         size_t responselen);
+
+int deleteSmsOnSimResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responselen);
+
+int setBandModeResponse(int slotId,
+                       int responseType, int serial, RIL_Errno e, void *response,
+                       size_t responselen);
+
+int getAvailableBandModesResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int sendEnvelopeResponse(int slotId,
+                        int responseType, int serial, RIL_Errno e, void *response,
+                        size_t responselen);
+
+int sendTerminalResponseToSimResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int handleStkCallSetupRequestFromSimResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responselen);
+
+int explicitCallTransferResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e, void *response,
+                                size_t responselen);
+
+int setPreferredNetworkTypeResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e, void *response,
+                                   size_t responselen);
+
+int getPreferredNetworkTypeResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e, void *response,
+                                   size_t responselen);
+
+int setPreferredNetworkTypeBitmapResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e, void *response,
+                                   size_t responselen);
+
+int getPreferredNetworkTypeBitmapResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e, void *response,
+                                   size_t responselen);
+
+int getNeighboringCidsResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int setLocationUpdatesResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int setCdmaSubscriptionSourceResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int setCdmaRoamingPreferenceResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responselen);
+
+int getCdmaRoamingPreferenceResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responselen);
+
+int setTTYModeResponse(int slotId,
+                      int responseType, int serial, RIL_Errno e, void *response,
+                      size_t responselen);
+
+int getTTYModeResponse(int slotId,
+                      int responseType, int serial, RIL_Errno e, void *response,
+                      size_t responselen);
+
+int setPreferredVoicePrivacyResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responselen);
+
+int getPreferredVoicePrivacyResponse(int slotId,
+                                    int responseType, int serial, RIL_Errno e, void *response,
+                                    size_t responselen);
+
+int sendCDMAFeatureCodeResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responselen);
+
+int sendBurstDtmfResponse(int slotId,
+                         int responseType, int serial, RIL_Errno e, void *response,
+                         size_t responselen);
+
+int sendCdmaSmsResponse(int slotId,
+                       int responseType, int serial, RIL_Errno e, void *response,
+                       size_t responselen);
+
+int acknowledgeLastIncomingCdmaSmsResponse(int slotId,
+                                          int responseType, int serial, RIL_Errno e, void *response,
+                                          size_t responselen);
+
+int getGsmBroadcastConfigResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int setGsmBroadcastConfigResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int setGsmBroadcastActivationResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int getCdmaBroadcastConfigResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e, void *response,
+                                  size_t responselen);
+
+int setCdmaBroadcastConfigResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e, void *response,
+                                  size_t responselen);
+
+int setCdmaBroadcastActivationResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responselen);
+
+int getCDMASubscriptionResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e, void *response,
+                               size_t responselen);
+
+int writeSmsToRuimResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responselen);
+
+int deleteSmsOnRuimResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e, void *response,
+                           size_t responselen);
+
+int getDeviceIdentityResponse(int slotId,
+                             int responseType, int serial, RIL_Errno e, void *response,
+                             size_t responselen);
+
+int exitEmergencyCallbackModeResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int getSmscAddressResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responselen);
+
+int setCdmaBroadcastActivationResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responselen);
+
+int setSmscAddressResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responselen);
+
+int reportSmsMemoryStatusResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responselen);
+
+int reportStkServiceIsRunningResponse(int slotId,
+                                      int responseType, int serial, RIL_Errno e,
+                                      void *response, size_t responseLen);
+
+int getCdmaSubscriptionSourceResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int requestIsimAuthenticationResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e, void *response,
+                                     size_t responselen);
+
+int acknowledgeIncomingGsmSmsWithPduResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responselen);
+
+int sendEnvelopeWithStatusResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e, void *response,
+                                  size_t responselen);
+
+int getVoiceRadioTechnologyResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responselen);
+
+int getCellInfoListResponse(int slotId,
+                            int responseType,
+                            int serial, RIL_Errno e, void *response,
+                            size_t responseLen);
+
+int setCellInfoListRateResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responselen);
+
+int setInitialAttachApnResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responselen);
+
+int getImsRegistrationStateResponse(int slotId,
+                                   int responseType, int serial, RIL_Errno e,
+                                   void *response, size_t responselen);
+
+int sendImsSmsResponse(int slotId, int responseType,
+                      int serial, RIL_Errno e, void *response, size_t responselen);
+
+int iccTransmitApduBasicChannelResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e,
+                                       void *response, size_t responselen);
+
+int iccOpenLogicalChannelResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e, void *response,
+                                  size_t responselen);
+
+
+int iccCloseLogicalChannelResponse(int slotId,
+                                  int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responselen);
+
+int iccTransmitApduLogicalChannelResponse(int slotId,
+                                         int responseType, int serial, RIL_Errno e,
+                                         void *response, size_t responselen);
+
+int nvReadItemResponse(int slotId,
+                      int responseType, int serial, RIL_Errno e,
+                      void *response, size_t responselen);
+
+
+int nvWriteItemResponse(int slotId,
+                       int responseType, int serial, RIL_Errno e,
+                       void *response, size_t responselen);
+
+int nvWriteCdmaPrlResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responselen);
+
+int nvResetConfigResponse(int slotId,
+                         int responseType, int serial, RIL_Errno e,
+                         void *response, size_t responselen);
+
+int setUiccSubscriptionResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responselen);
+
+int setDataAllowedResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responselen);
+
+int getHardwareConfigResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responseLen);
+
+int requestIccSimAuthenticationResponse(int slotId,
+                                       int responseType, int serial, RIL_Errno e,
+                                       void *response, size_t responselen);
+
+int setDataProfileResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responselen);
+
+int requestShutdownResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e,
+                           void *response, size_t responselen);
+
+int getRadioCapabilityResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responseLen);
+
+int setRadioCapabilityResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responseLen);
+
+int startLceServiceResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e,
+                           void *response, size_t responselen);
+
+int stopLceServiceResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responselen);
+
+int pullLceDataResponse(int slotId,
+                        int responseType, int serial, RIL_Errno e,
+                        void *response, size_t responseLen);
+
+int getModemActivityInfoResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e,
+                                void *response, size_t responselen);
+
+int getModemStackStatusResponse(int slotId,
+                                int responseType, int serial, RIL_Errno e,
+                                void *response, size_t responselen);
+
+int enableModemResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                void *response, size_t responselen);
+
+int setAllowedCarriersResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen);
+
+int getAllowedCarriersResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen);
+
+int sendDeviceStateResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen);
+
+int setIndicationFilterResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen);
+
+int setSimCardPowerResponse(int slotId,
+                              int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen);
+
+int startKeepaliveResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e,
+                           void *response, size_t responselen);
+
+int stopKeepaliveResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responselen);
+
+void acknowledgeRequest(int slotId, int serial);
+
+int radioStateChangedInd(int slotId,
+                          int indicationType, int token, RIL_Errno e, void *response,
+                          size_t responseLen);
+
+int callStateChangedInd(int slotId, int indType, int token,
+                        RIL_Errno e, void *response, size_t responselen);
+
+int networkStateChangedInd(int slotId, int indType,
+                                int token, RIL_Errno e, void *response, size_t responselen);
+
+int newSmsInd(int slotId, int indicationType,
+              int token, RIL_Errno e, void *response, size_t responselen);
+
+int newSmsStatusReportInd(int slotId, int indicationType,
+                          int token, RIL_Errno e, void *response, size_t responselen);
+
+int newSmsOnSimInd(int slotId, int indicationType,
+                   int token, RIL_Errno e, void *response, size_t responselen);
+
+int onUssdInd(int slotId, int indicationType,
+              int token, RIL_Errno e, void *response, size_t responselen);
+
+int nitzTimeReceivedInd(int slotId, int indicationType,
+                        int token, RIL_Errno e, void *response, size_t responselen);
+
+int currentSignalStrengthInd(int slotId,
+                             int indicationType, int token, RIL_Errno e,
+                             void *response, size_t responselen);
+
+int dataCallListChangedInd(int slotId, int indicationType,
+                           int token, RIL_Errno e, void *response, size_t responselen);
+
+int suppSvcNotifyInd(int slotId, int indicationType,
+                     int token, RIL_Errno e, void *response, size_t responselen);
+
+int stkSessionEndInd(int slotId, int indicationType,
+                     int token, RIL_Errno e, void *response, size_t responselen);
+
+int stkProactiveCommandInd(int slotId, int indicationType,
+                           int token, RIL_Errno e, void *response, size_t responselen);
+
+int stkEventNotifyInd(int slotId, int indicationType,
+                      int token, RIL_Errno e, void *response, size_t responselen);
+
+int stkCallSetupInd(int slotId, int indicationType,
+                    int token, RIL_Errno e, void *response, size_t responselen);
+
+int simSmsStorageFullInd(int slotId, int indicationType,
+                         int token, RIL_Errno e, void *response, size_t responselen);
+
+int simRefreshInd(int slotId, int indicationType,
+                  int token, RIL_Errno e, void *response, size_t responselen);
+
+int callRingInd(int slotId, int indicationType,
+                int token, RIL_Errno e, void *response, size_t responselen);
+
+int simStatusChangedInd(int slotId, int indicationType,
+                        int token, RIL_Errno e, void *response, size_t responselen);
+
+int cdmaNewSmsInd(int slotId, int indicationType,
+                  int token, RIL_Errno e, void *response, size_t responselen);
+
+int newBroadcastSmsInd(int slotId,
+                       int indicationType, int token, RIL_Errno e, void *response,
+                       size_t responselen);
+
+int cdmaRuimSmsStorageFullInd(int slotId,
+                              int indicationType, int token, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int restrictedStateChangedInd(int slotId,
+                              int indicationType, int token, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int enterEmergencyCallbackModeInd(int slotId,
+                                  int indicationType, int token, RIL_Errno e, void *response,
+                                  size_t responselen);
+
+int cdmaCallWaitingInd(int slotId,
+                       int indicationType, int token, RIL_Errno e, void *response,
+                       size_t responselen);
+
+int cdmaOtaProvisionStatusInd(int slotId,
+                              int indicationType, int token, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int cdmaInfoRecInd(int slotId,
+                   int indicationType, int token, RIL_Errno e, void *response,
+                   size_t responselen);
+
+int oemHookRawInd(int slotId,
+                  int indicationType, int token, RIL_Errno e, void *response,
+                  size_t responselen);
+
+int indicateRingbackToneInd(int slotId,
+                            int indicationType, int token, RIL_Errno e, void *response,
+                            size_t responselen);
+
+int resendIncallMuteInd(int slotId,
+                        int indicationType, int token, RIL_Errno e, void *response,
+                        size_t responselen);
+
+int cdmaSubscriptionSourceChangedInd(int slotId,
+                                     int indicationType, int token, RIL_Errno e,
+                                     void *response, size_t responselen);
+
+int cdmaPrlChangedInd(int slotId,
+                      int indicationType, int token, RIL_Errno e, void *response,
+                      size_t responselen);
+
+int exitEmergencyCallbackModeInd(int slotId,
+                                 int indicationType, int token, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int rilConnectedInd(int slotId,
+                    int indicationType, int token, RIL_Errno e, void *response,
+                    size_t responselen);
+
+int voiceRadioTechChangedInd(int slotId,
+                             int indicationType, int token, RIL_Errno e, void *response,
+                             size_t responselen);
+
+int cellInfoListInd(int slotId,
+                    int indicationType, int token, RIL_Errno e, void *response,
+                    size_t responselen);
+
+int imsNetworkStateChangedInd(int slotId,
+                              int indicationType, int token, RIL_Errno e, void *response,
+                              size_t responselen);
+
+int subscriptionStatusChangedInd(int slotId,
+                                 int indicationType, int token, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int srvccStateNotifyInd(int slotId,
+                        int indicationType, int token, RIL_Errno e, void *response,
+                        size_t responselen);
+
+int hardwareConfigChangedInd(int slotId,
+                             int indicationType, int token, RIL_Errno e, void *response,
+                             size_t responselen);
+
+int radioCapabilityIndicationInd(int slotId,
+                                 int indicationType, int token, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int onSupplementaryServiceIndicationInd(int slotId,
+                                        int indicationType, int token, RIL_Errno e,
+                                        void *response, size_t responselen);
+
+int stkCallControlAlphaNotifyInd(int slotId,
+                                 int indicationType, int token, RIL_Errno e, void *response,
+                                 size_t responselen);
+
+int lceDataInd(int slotId,
+               int indicationType, int token, RIL_Errno e, void *response,
+               size_t responselen);
+
+int pcoDataInd(int slotId,
+               int indicationType, int token, RIL_Errno e, void *response,
+               size_t responselen);
+
+int modemResetInd(int slotId,
+                  int indicationType, int token, RIL_Errno e, void *response,
+                  size_t responselen);
+
+int networkScanResultInd(int slotId,
+                         int indicationType, int token, RIL_Errno e, void *response,
+                         size_t responselen);
+
+int reportPhysicalChannelConfigs(int slotId, int indicationType,
+                        int token, RIL_Errno e, void *response, size_t responselen);
+
+int keepaliveStatusInd(int slotId,
+                       int indicationType, int token, RIL_Errno e, void *response,
+                       size_t responselen);
+
+int sendRequestRawResponse(int slotId,
+                           int responseType, int serial, RIL_Errno e,
+                           void *response, size_t responseLen);
+
+int sendRequestStringsResponse(int slotId,
+                               int responseType, int serial, RIL_Errno e,
+                               void *response, size_t responseLen);
+
+int setCarrierInfoForImsiEncryptionResponse(int slotId,
+                                            int responseType, int serial, RIL_Errno e,
+                                            void *response, size_t responseLen);
+
+int emergencyDialResponse(int slotId,
+                          int responseType, int serial, RIL_Errno e,
+                          void *response, size_t responselen);
+
+int carrierInfoForImsiEncryption(int slotId,
+                        int responseType, int serial, RIL_Errno e,
+                        void *response, size_t responseLen);
+
+int setSystemSelectionChannelsResponse(int slotId, int responseType, int serial,
+                                       RIL_Errno e, void *response, size_t responseLen);
+
+int getSystemSelectionChannelsResponse(int slotId, int responseType, int serial,
+                                       RIL_Errno e, void *response, size_t responseLen);
+
+int setSignalStrengthReportingCriteriaResponse(int slotId, int responseType, int serial,
+                                               RIL_Errno e, void *response, size_t responselen);
+
+int setLinkCapacityReportingCriteriaResponse(int slotId, int responseType, int serial,
+                                             RIL_Errno e, void *response, size_t responselen);
+
+int enableUiccApplicationsResponse(int slotId,
+                                 int responseType, int serial, RIL_Errno e,
+                                 void *response, size_t responselen);
+
+int areUiccApplicationsEnabledResponse(int slotId,
+                                     int responseType, int serial, RIL_Errno e,
+                                     void *response, size_t responselen);
+
+int setRadioPowerResponse(int slotId, int responseType, int serial, RIL_Errno e, void *response,
+                          size_t responselen);
+
+int getBarringInfoResponse(int slotId, int responseType, int serial, RIL_Errno e, void *response,
+                           size_t responselen);
+
+int sendCdmaSmsExpectMoreResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                  void *response, size_t responselen);
+
+int supplySimDepersonalizationResponse(int slotId, int responseType, int serial, RIL_Errno e,
+                                       void *response, size_t responselen);
+
+int setNrDualConnectivityStateResponse(int slotId, int responseType, int serial,
+                                    RIL_Errno e, void* /* response */, size_t responseLen);
+int isNrDualConnectivityEnabledResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen);
+
+int allocatePduSessionIdResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen);
+int releasePduSessionIdResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen);
+int startHandoverResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen);
+int cancelHandoverResponse(int slotId, int responseType, int serial,
+                                        RIL_Errno e, void* response, size_t responseLen);
+
+int setAllowedNetworkTypesBitmapResponse(int slotId, int responseType, int serial,
+                                  RIL_Errno e, void *response, size_t responselen);
+
+int setDataThrottlingResponse(int slotId, int responseType, int serial,
+                              RIL_Errno e, void *response, size_t responselen);
+
+int getAllowedNetworkTypesBitmapResponse(int slotId, int responseType, int serial,
+                                  RIL_Errno e, void *response, size_t responselen);
+
+int getSlicingConfigResponse(int slotId, int responseType, int serial,
+                             RIL_Errno e, void *response, size_t responseLen);
+
+int getSimPhonebookRecordsResponse(int slotId, int responseType, int serial,
+                             RIL_Errno e, void *response, size_t responseLen);
+
+int getSimPhonebookCapacityResponse(int slotId, int responseType, int serial,
+                             RIL_Errno e, void *response, size_t responseLen);
+
+int updateSimPhonebookRecordsResponse(int slotId, int responseType, int serial,
+                             RIL_Errno e, void *response, size_t responseLen);
+
+
+pthread_rwlock_t * getRadioServiceRwlock(int slotId);
+
+void setNitzTimeReceived(int slotId, long timeReceived);
+
+/******************************************************************************/
+/*          Radio Config interfaces' corresponding responseFunction           */
+/******************************************************************************/
+void registerConfigService(RIL_RadioFunctions *callbacks, android::CommandInfo *commands);
+
+int getSimSlotsStatusResponse(int slotId, int responseType, int serial,
+                              RIL_Errno e, void *response, size_t responseLen);
+
+int setSimSlotsMappingResponse(int slotId, int responseType, int serial,
+                               RIL_Errno e, void *response, size_t responseLen);
+
+int getPhoneCapabilityResponse(int slotId, int responseType, int serial,
+                               RIL_Errno e, void *response, size_t responseLen);
+
+int setPreferredDataModemResponse(int slotId, int responseType, int serial,
+                                  RIL_Errno e, void *response, size_t responseLen);
+
+int setModemsConfigResponse(int slotId, int responseType, int serial,
+                            RIL_Errno e, void *response, size_t responseLen);
+
+int getModemsConfigResponse(int slotId, int responseType, int serial,
+                            RIL_Errno e, void *response, size_t responseLen);
+
+int getHalDeviceCapabilitiesResponse(int slotId, int responseType, int serial,
+                            RIL_Errno e, void *response, size_t responseLen);
+
+/******************************************************************************/
+/*    Radio Config unsolicited interfaces' corresponding responseFunction     */
+/******************************************************************************/
+int simSlotsStatusChanged(int slotId, int indicationType, int token,
+                          RIL_Errno e, void *response, size_t responseLen);
+
+}   // namespace radio
+
+#endif  // RIL_SERVICE_H
diff --git a/guest/hals/ril/reference-libril/ril_unsol_commands.h b/guest/hals/ril/reference-libril/ril_unsol_commands.h
new file mode 100644
index 0000000..62dd40c
--- /dev/null
+++ b/guest/hals/ril/reference-libril/ril_unsol_commands.h
@@ -0,0 +1,68 @@
+/* ///guest/hals/ril/reference-libril/ril_unsol_commands.h
+**
+** Copyright 2006, 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.
+*/
+    {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio_1_6::radioStateChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio_1_6::callStateChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio_1_6::networkStateChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_NEW_SMS, radio_1_6::newSmsInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, radio_1_6::newSmsStatusReportInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, radio_1_6::newSmsOnSimInd, WAKE_PARTIAL},
+    {RIL_UNSOL_ON_USSD, radio_1_6::onUssdInd, WAKE_PARTIAL},
+    {RIL_UNSOL_ON_USSD_REQUEST, radio_1_6::onUssdInd, DONT_WAKE},
+    {RIL_UNSOL_NITZ_TIME_RECEIVED, radio_1_6::nitzTimeReceivedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_SIGNAL_STRENGTH, radio_1_6::currentSignalStrengthInd, DONT_WAKE},
+    {RIL_UNSOL_DATA_CALL_LIST_CHANGED, radio_1_6::dataCallListChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_SUPP_SVC_NOTIFICATION, radio_1_6::suppSvcNotifyInd, WAKE_PARTIAL},
+    {RIL_UNSOL_STK_SESSION_END, radio_1_6::stkSessionEndInd, WAKE_PARTIAL},
+    {RIL_UNSOL_STK_PROACTIVE_COMMAND, radio_1_6::stkProactiveCommandInd, WAKE_PARTIAL},
+    {RIL_UNSOL_STK_EVENT_NOTIFY, radio_1_6::stkEventNotifyInd, WAKE_PARTIAL},
+    {RIL_UNSOL_STK_CALL_SETUP, radio_1_6::stkCallSetupInd, WAKE_PARTIAL},
+    {RIL_UNSOL_SIM_SMS_STORAGE_FULL, radio_1_6::simSmsStorageFullInd, WAKE_PARTIAL},
+    {RIL_UNSOL_SIM_REFRESH, radio_1_6::simRefreshInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CALL_RING, radio_1_6::callRingInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, radio_1_6::simStatusChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, radio_1_6::cdmaNewSmsInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, radio_1_6::newBroadcastSmsInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, radio_1_6::cdmaRuimSmsStorageFullInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESTRICTED_STATE_CHANGED, radio_1_6::restrictedStateChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, radio_1_6::enterEmergencyCallbackModeInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CDMA_CALL_WAITING, radio_1_6::cdmaCallWaitingInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, radio_1_6::cdmaOtaProvisionStatusInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CDMA_INFO_REC, radio_1_6::cdmaInfoRecInd, WAKE_PARTIAL},
+    {RIL_UNSOL_OEM_HOOK_RAW, radio_1_6::oemHookRawInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RINGBACK_TONE, radio_1_6::indicateRingbackToneInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESEND_INCALL_MUTE, radio_1_6::resendIncallMuteInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, radio_1_6::cdmaSubscriptionSourceChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CDMA_PRL_CHANGED, radio_1_6::cdmaPrlChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, radio_1_6::exitEmergencyCallbackModeInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RIL_CONNECTED, radio_1_6::rilConnectedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, radio_1_6::voiceRadioTechChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CELL_INFO_LIST, radio_1_6::cellInfoListInd, WAKE_PARTIAL},
+    {RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED, radio_1_6::imsNetworkStateChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, radio_1_6::subscriptionStatusChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_SRVCC_STATE_NOTIFY, radio_1_6::srvccStateNotifyInd, WAKE_PARTIAL},
+    {RIL_UNSOL_HARDWARE_CONFIG_CHANGED, radio_1_6::hardwareConfigChangedInd, WAKE_PARTIAL},
+    {RIL_UNSOL_DC_RT_INFO_CHANGED, NULL, WAKE_PARTIAL},
+    {RIL_UNSOL_RADIO_CAPABILITY, radio_1_6::radioCapabilityIndicationInd, WAKE_PARTIAL},
+    {RIL_UNSOL_ON_SS, radio_1_6::onSupplementaryServiceIndicationInd, WAKE_PARTIAL},
+    {RIL_UNSOL_STK_CC_ALPHA_NOTIFY, radio_1_6::stkCallControlAlphaNotifyInd, WAKE_PARTIAL},
+    {RIL_UNSOL_LCEDATA_RECV, radio_1_6::lceDataInd, WAKE_PARTIAL},
+    {RIL_UNSOL_PCO_DATA, radio_1_6::pcoDataInd, WAKE_PARTIAL},
+    {RIL_UNSOL_MODEM_RESTART, radio_1_6::modemResetInd, WAKE_PARTIAL},
+    {RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, radio_1_6::carrierInfoForImsiEncryption, WAKE_PARTIAL},
+    {RIL_UNSOL_NETWORK_SCAN_RESULT, radio_1_6::networkScanResultInd, WAKE_PARTIAL},
+    {RIL_UNSOL_KEEPALIVE_STATUS, radio_1_6::keepaliveStatusInd, WAKE_PARTIAL},
+    {RIL_UNSOL_PHYSICAL_CHANNEL_CONFIGS, radio_1_6::reportPhysicalChannelConfigs, WAKE_PARTIAL},
diff --git a/guest/hals/ril/libril/sap_service.cpp b/guest/hals/ril/reference-libril/sap_service.cpp
similarity index 100%
rename from guest/hals/ril/libril/sap_service.cpp
rename to guest/hals/ril/reference-libril/sap_service.cpp
diff --git a/guest/hals/ril/reference-libril/sap_service.h b/guest/hals/ril/reference-libril/sap_service.h
new file mode 100644
index 0000000..cb5ae10
--- /dev/null
+++ b/guest/hals/ril/reference-libril/sap_service.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef SAP_SERVICE_H
+#define SAP_SERVICE_H
+
+#include <telephony/ril.h>
+#include <ril_internal.h>
+#include <RilSapSocket.h>
+#include <hardware/ril/librilutils/proto/sap-api.pb.h>
+
+namespace sap {
+
+void registerService(const RIL_RadioFunctions *callbacks);
+void processResponse(MsgHeader *rsp, RilSapSocket *sapSocket);
+void processUnsolResponse(MsgHeader *rsp, RilSapSocket *sapSocket);
+
+}   // namespace android
+
+#endif  // RIL_SERVICE_H
diff --git a/guest/hals/ril/reference-ril/Android.bp b/guest/hals/ril/reference-ril/Android.bp
new file mode 100644
index 0000000..de01ae1
--- /dev/null
+++ b/guest/hals/ril/reference-ril/Android.bp
@@ -0,0 +1,67 @@
+// 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.
+
+package {
+    default_applicable_licenses: [
+        "device_google_cuttlefish_guest_hals_ril_reference-ril_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "device_google_cuttlefish_guest_hals_ril_reference-ril_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
+cc_library {
+    name: "libcuttlefish-ril-2",
+    vendor: true,
+    cflags: [
+        "-D_GNU_SOURCE",
+        "-DCUTTLEFISH_ENABLE",
+        "-DRIL_SHLIB",
+        "-Wall",
+        "-Wextra",
+        "-Wno-unused-variable",
+        "-Wno-unused-function",
+        "-Werror",
+    ],
+    srcs: [
+        "atchannel.c",
+        "at_tok.c",
+        "base64util.cpp",
+        "misc.c",
+        "reference-ril.c",
+    ],
+    include_dirs: [
+        "device/google/cuttlefish",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "liblog",
+        "librilutils",
+        "libril-modem-lib",
+        "libutils",
+    ],
+}
diff --git a/guest/hals/ril/reference-ril/MODULE_LICENSE_APACHE2 b/guest/hals/ril/reference-ril/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/guest/hals/ril/reference-ril/MODULE_LICENSE_APACHE2
diff --git a/guest/hals/ril/reference-ril/NOTICE b/guest/hals/ril/reference-ril/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/guest/hals/ril/reference-ril/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/guest/hals/ril/reference-ril/OWNERS b/guest/hals/ril/reference-ril/OWNERS
new file mode 100644
index 0000000..98dba3e
--- /dev/null
+++ b/guest/hals/ril/reference-ril/OWNERS
@@ -0,0 +1,9 @@
+amitmahajan@google.com
+jackyu@google.com
+rgreenwalt@google.com
+fionaxu@google.com
+jminjie@google.com
+mpq@google.com
+shuoq@google.com
+refuhoo@google.com
+bohu@google.com
diff --git a/guest/hals/ril/reference-ril/at_tok.c b/guest/hals/ril/reference-ril/at_tok.c
new file mode 100644
index 0000000..7dec7d1
--- /dev/null
+++ b/guest/hals/ril/reference-ril/at_tok.c
@@ -0,0 +1,190 @@
+/* //device/system/reference-ril/at_tok.c
+**
+** Copyright 2006, 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.
+*/
+
+#include "at_tok.h"
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/**
+ * Starts tokenizing an AT response string
+ * returns -1 if this is not a valid response string, 0 on success.
+ * updates *p_cur with current position
+ */
+int at_tok_start(char **p_cur)
+{
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    // skip prefix
+    // consume "^[^:]:"
+
+    *p_cur = strchr(*p_cur, ':');
+
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    (*p_cur)++;
+
+    return 0;
+}
+
+static void skipWhiteSpace(char **p_cur)
+{
+    if (*p_cur == NULL) return;
+
+    while (**p_cur != '\0' && isspace(**p_cur)) {
+        (*p_cur)++;
+    }
+}
+
+void skipNextComma(char **p_cur)
+{
+    if (*p_cur == NULL) return;
+
+    while (**p_cur != '\0' && **p_cur != ',') {
+        (*p_cur)++;
+    }
+
+    if (**p_cur == ',') {
+        (*p_cur)++;
+    }
+}
+
+static char * nextTok(char **p_cur)
+{
+    char *ret = NULL;
+
+    skipWhiteSpace(p_cur);
+
+    if (*p_cur == NULL) {
+        ret = NULL;
+    } else if (**p_cur == '"') {
+        (*p_cur)++;
+        ret = strsep(p_cur, "\"");
+        skipNextComma(p_cur);
+    } else {
+        ret = strsep(p_cur, ",");
+    }
+
+    return ret;
+}
+
+
+/**
+ * Parses the next integer in the AT response line and places it in *p_out
+ * returns 0 on success and -1 on fail
+ * updates *p_cur
+ * "base" is the same as the base param in strtol
+ */
+
+static int at_tok_nextint_base(char **p_cur, int *p_out, int base, int  uns)
+{
+    char *ret;
+
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    ret = nextTok(p_cur);
+
+    if (ret == NULL) {
+        return -1;
+    } else {
+        long l;
+        char *end;
+
+        if (uns)
+            l = strtoul(ret, &end, base);
+        else
+            l = strtol(ret, &end, base);
+
+        *p_out = (int)l;
+
+        if (end == ret) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Parses the next base 10 integer in the AT response line
+ * and places it in *p_out
+ * returns 0 on success and -1 on fail
+ * updates *p_cur
+ */
+int at_tok_nextint(char **p_cur, int *p_out)
+{
+    return at_tok_nextint_base(p_cur, p_out, 10, 0);
+}
+
+/**
+ * Parses the next base 16 integer in the AT response line
+ * and places it in *p_out
+ * returns 0 on success and -1 on fail
+ * updates *p_cur
+ */
+int at_tok_nexthexint(char **p_cur, int *p_out)
+{
+    return at_tok_nextint_base(p_cur, p_out, 16, 1);
+}
+
+int at_tok_nextbool(char **p_cur, char *p_out)
+{
+    int ret;
+    int result;
+
+    ret = at_tok_nextint(p_cur, &result);
+
+    if (ret < 0) {
+        return -1;
+    }
+
+    // booleans should be 0 or 1
+    if (!(result == 0 || result == 1)) {
+        return -1;
+    }
+
+    if (p_out != NULL) {
+        *p_out = (char)result;
+    }
+
+    return ret;
+}
+
+int at_tok_nextstr(char **p_cur, char **p_out)
+{
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    *p_out = nextTok(p_cur);
+
+    return 0;
+}
+
+/** returns 1 on "has more tokens" and 0 if no */
+int at_tok_hasmore(char **p_cur)
+{
+    return ! (*p_cur == NULL || **p_cur == '\0');
+}
+
+
diff --git a/guest/hals/ril/reference-ril/at_tok.h b/guest/hals/ril/reference-ril/at_tok.h
new file mode 100644
index 0000000..b6a0aad
--- /dev/null
+++ b/guest/hals/ril/reference-ril/at_tok.h
@@ -0,0 +1,32 @@
+/* //device/system/reference-ril/at_tok.h
+**
+** Copyright 2006, 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.
+*/
+
+#ifndef AT_TOK_H
+#define AT_TOK_H 1
+
+int at_tok_start(char **p_cur);
+int at_tok_nextint(char **p_cur, int *p_out);
+int at_tok_nexthexint(char **p_cur, int *p_out);
+
+int at_tok_nextbool(char **p_cur, char *p_out);
+int at_tok_nextstr(char **p_cur, char **out);
+
+int at_tok_hasmore(char **p_cur);
+
+void skipNextComma(char **p_cur);
+
+#endif /*AT_TOK_H */
diff --git a/guest/hals/ril/reference-ril/atchannel.c b/guest/hals/ril/reference-ril/atchannel.c
new file mode 100644
index 0000000..6ea051f
--- /dev/null
+++ b/guest/hals/ril/reference-ril/atchannel.c
@@ -0,0 +1,972 @@
+/* //device/system/reference-ril/atchannel.c
+**
+** Copyright 2006, 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.
+*/
+
+#include "atchannel.h"
+#include "at_tok.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AT"
+#include <utils/Log.h>
+
+#include "misc.h"
+
+
+#define NUM_ELEMS(x) (sizeof(x)/sizeof((x)[0]))
+
+#define MAX_AT_RESPONSE (8 * 1024)
+#define HANDSHAKE_RETRY_COUNT 8
+#define HANDSHAKE_TIMEOUT_MSEC 250
+
+static pthread_t s_tid_reader;
+static int s_fd = -1;    /* fd of the AT channel */
+static ATUnsolHandler s_unsolHandler;
+
+/* for input buffering */
+
+static char s_ATBuffer[MAX_AT_RESPONSE+1];
+static char *s_ATBufferCur = s_ATBuffer;
+
+#if AT_DEBUG
+void  AT_DUMP(const char*  prefix __unused, const char*  buff, int  len)
+{
+    if (len < 0)
+        len = strlen(buff);
+    RLOGD("%.*s", len, buff);
+}
+#endif
+
+/*
+ * There is one reader thread |s_tid_reader| and potentially multiple writer
+ * threads. |s_commandmutex| and |s_commandcond| are used to maintain the
+ * condition that the writer thread will not read from |sp_response| until the
+ * reader thread has signaled itself is finished, etc. |s_writeMutex| is used to
+ * prevent multiple writer threads from calling at_send_command_full_nolock
+ * function at the same time.
+ */
+
+static pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t s_writeMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static ATCommandType s_type;
+static const char *s_responsePrefix = NULL;
+static const char *s_smsPDU = NULL;
+static ATResponse *sp_response = NULL;
+
+static void (*s_onTimeout)(void) = NULL;
+static void (*s_onReaderClosed)(void) = NULL;
+static int s_readerClosed;
+
+static void onReaderClosed();
+static int writeCtrlZ (const char *s);
+static int writeline (const char *s);
+
+#define NS_PER_S 1000000000
+static void setTimespecRelative(struct timespec *p_ts, long long msec)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, (struct timezone *) NULL);
+
+    p_ts->tv_sec = tv.tv_sec + (msec / 1000);
+    p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
+    /* assuming tv.tv_usec < 10^6 */
+    if (p_ts->tv_nsec >= NS_PER_S) {
+        p_ts->tv_sec++;
+        p_ts->tv_nsec -= NS_PER_S;
+    }
+}
+
+static void sleepMsec(long long msec)
+{
+    struct timespec ts;
+    int err;
+
+    ts.tv_sec = (msec / 1000);
+    ts.tv_nsec = (msec % 1000) * 1000 * 1000;
+
+    do {
+        err = nanosleep (&ts, &ts);
+    } while (err < 0 && errno == EINTR);
+}
+
+
+
+/** add an intermediate response to sp_response*/
+static void addIntermediate(const char *line)
+{
+    ATLine *p_new;
+
+    p_new = (ATLine  *) malloc(sizeof(ATLine));
+
+    p_new->line = strdup(line);
+
+    /* note: this adds to the head of the list, so the list
+       will be in reverse order of lines received. the order is flipped
+       again before passing on to the command issuer */
+    p_new->p_next = sp_response->p_intermediates;
+    sp_response->p_intermediates = p_new;
+}
+
+
+/**
+ * returns 1 if line is a final response indicating error
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static const char * s_finalResponsesError[] = {
+    "ERROR",
+    "+CMS ERROR:",
+    "+CME ERROR:",
+    "NO CARRIER", /* sometimes! */
+    "NO ANSWER",
+    "NO DIALTONE",
+};
+static int isFinalResponseError(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < NUM_ELEMS(s_finalResponsesError) ; i++) {
+        if (strStartsWith(line, s_finalResponsesError[i])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * returns 1 if line is a final response indicating success
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static const char * s_finalResponsesSuccess[] = {
+    "OK",
+    "CONNECT"       /* some stacks start up data on another channel */
+};
+static int isFinalResponseSuccess(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) {
+        if (strStartsWith(line, s_finalResponsesSuccess[i])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * returns 1 if line is a final response, either  error or success
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static int isFinalResponse(const char *line)
+{
+    return isFinalResponseSuccess(line) || isFinalResponseError(line);
+}
+
+
+/**
+ * returns 1 if line is the first line in (what will be) a two-line
+ * SMS unsolicited response
+ */
+static const char * s_smsUnsoliciteds[] = {
+    "+CMT:",
+    "+CDS:",
+    "+CBM:"
+};
+static int isSMSUnsolicited(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) {
+        if (strStartsWith(line, s_smsUnsoliciteds[i])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+
+/** assumes s_commandmutex is held */
+static void handleFinalResponse(const char *line)
+{
+    sp_response->finalResponse = strdup(line);
+
+    pthread_cond_signal(&s_commandcond);
+}
+
+static void handleUnsolicited(const char *line)
+{
+    if (s_unsolHandler != NULL) {
+        s_unsolHandler(line, NULL);
+    }
+}
+
+static void processLine(const char *line)
+{
+    pthread_mutex_lock(&s_commandmutex);
+
+    if (sp_response == NULL) {
+        /* no command pending */
+        handleUnsolicited(line);
+    } else if (isFinalResponseSuccess(line)) {
+        sp_response->success = 1;
+        handleFinalResponse(line);
+    } else if (isFinalResponseError(line)) {
+        sp_response->success = 0;
+        handleFinalResponse(line);
+    } else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
+        // See eg. TS 27.005 4.3
+        // Commands like AT+CMGS have a "> " prompt
+        writeCtrlZ(s_smsPDU);
+        s_smsPDU = NULL;
+    } else switch (s_type) {
+        case NO_RESULT:
+            handleUnsolicited(line);
+            break;
+        case NUMERIC:
+            if (sp_response->p_intermediates == NULL
+                && isdigit(line[0])
+            ) {
+                addIntermediate(line);
+            } else {
+                /* either we already have an intermediate response or
+                   the line doesn't begin with a digit */
+                handleUnsolicited(line);
+            }
+            break;
+        case SINGLELINE:
+            if (sp_response->p_intermediates == NULL
+                && strStartsWith (line, s_responsePrefix)
+            ) {
+                addIntermediate(line);
+            } else {
+                /* we already have an intermediate response */
+                handleUnsolicited(line);
+            }
+            break;
+        case MULTILINE:
+            if (strStartsWith (line, s_responsePrefix)) {
+                addIntermediate(line);
+            } else {
+                handleUnsolicited(line);
+            }
+        break;
+
+        default: /* this should never be reached */
+            RLOGE("Unsupported AT command type %d\n", s_type);
+            handleUnsolicited(line);
+        break;
+    }
+
+    pthread_mutex_unlock(&s_commandmutex);
+}
+
+
+/**
+ * Returns a pointer to the end of the next line
+ * special-cases the "> " SMS prompt
+ *
+ * returns NULL if there is no complete line
+ */
+static char * findNextEOL(char *cur)
+{
+    if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0') {
+        /* SMS prompt character...not \r terminated */
+        return cur+2;
+    }
+
+    // Find next newline
+    while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
+
+    return *cur == '\0' ? NULL : cur;
+}
+
+
+/**
+ * Reads a line from the AT channel, returns NULL on timeout.
+ * Assumes it has exclusive read access to the FD
+ *
+ * This line is valid only until the next call to readline
+ *
+ * This function exists because as of writing, android libc does not
+ * have buffered stdio.
+ */
+
+static const char *readline()
+{
+    ssize_t count;
+
+    char *p_read = NULL;
+    char *p_eol = NULL;
+    char *ret;
+
+    /* this is a little odd. I use *s_ATBufferCur == 0 to
+     * mean "buffer consumed completely". If it points to a character, than
+     * the buffer continues until a \0
+     */
+    if (*s_ATBufferCur == '\0') {
+        /* empty buffer */
+        s_ATBufferCur = s_ATBuffer;
+        *s_ATBufferCur = '\0';
+        p_read = s_ATBuffer;
+    } else {   /* *s_ATBufferCur != '\0' */
+        /* there's data in the buffer from the last read */
+
+        // skip over leading newlines
+        while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
+            s_ATBufferCur++;
+
+        p_eol = findNextEOL(s_ATBufferCur);
+
+        if (p_eol == NULL) {
+            /* a partial line. move it up and prepare to read more */
+            size_t len;
+
+            len = strlen(s_ATBufferCur);
+
+            memmove(s_ATBuffer, s_ATBufferCur, len + 1);
+            p_read = s_ATBuffer + len;
+            s_ATBufferCur = s_ATBuffer;
+        }
+        /* Otherwise, (p_eol !- NULL) there is a complete line  */
+        /* that will be returned the while () loop below        */
+    }
+
+    while (p_eol == NULL) {
+        if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) {
+            RLOGE("ERROR: Input line exceeded buffer\n");
+            /* ditch buffer and start over again */
+            s_ATBufferCur = s_ATBuffer;
+            *s_ATBufferCur = '\0';
+            p_read = s_ATBuffer;
+        }
+
+        do {
+            count = read(s_fd, p_read,
+                            MAX_AT_RESPONSE - (p_read - s_ATBuffer));
+        } while (count < 0 && errno == EINTR);
+
+        if (count > 0) {
+            AT_DUMP( "<< ", p_read, count );
+
+            p_read[count] = '\0';
+
+            // skip over leading newlines
+            while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
+                s_ATBufferCur++;
+
+            p_eol = findNextEOL(s_ATBufferCur);
+            p_read += count;
+        } else if (count <= 0) {
+            /* read error encountered or EOF reached */
+            if(count == 0) {
+                RLOGD("atchannel: EOF reached");
+            } else {
+                RLOGD("atchannel: read error %s", strerror(errno));
+            }
+            return NULL;
+        }
+    }
+
+    /* a full line in the buffer. Place a \0 over the \r and return */
+
+    ret = s_ATBufferCur;
+    *p_eol = '\0';
+    s_ATBufferCur = p_eol + 1; /* this will always be <= p_read,    */
+                              /* and there will be a \0 at *p_read */
+
+    RLOGD("AT< %s\n", ret);
+    return ret;
+}
+
+
+static void onReaderClosed()
+{
+    if (s_onReaderClosed != NULL && s_readerClosed == 0) {
+
+        pthread_mutex_lock(&s_commandmutex);
+
+        s_readerClosed = 1;
+
+        pthread_cond_signal(&s_commandcond);
+
+        pthread_mutex_unlock(&s_commandmutex);
+
+        s_onReaderClosed();
+    }
+}
+
+
+static void *readerLoop(void *arg __unused)
+{
+    for (;;) {
+        const char * line;
+
+        line = readline();
+
+        if (line == NULL) {
+            break;
+        }
+
+        if(isSMSUnsolicited(line)) {
+            char *line1;
+            const char *line2;
+
+            // The scope of string returned by 'readline()' is valid only
+            // till next call to 'readline()' hence making a copy of line
+            // before calling readline again.
+            line1 = strdup(line);
+            line2 = readline();
+
+            if (line2 == NULL) {
+                free(line1);
+                break;
+            }
+
+            if (s_unsolHandler != NULL) {
+                s_unsolHandler (line1, line2);
+            }
+            free(line1);
+        } else {
+            processLine(line);
+        }
+    }
+
+    onReaderClosed();
+
+    return NULL;
+}
+
+/**
+ * Sends string s to the radio with a \r appended.
+ * Returns AT_ERROR_* on error, 0 on success
+ *
+ * This function exists because as of writing, android libc does not
+ * have buffered stdio.
+ */
+static int writeline (const char *s)
+{
+    size_t cur = 0;
+    size_t len = strlen(s);
+    ssize_t written;
+
+    if (s_fd < 0 || s_readerClosed > 0) {
+        return AT_ERROR_CHANNEL_CLOSED;
+    }
+
+    RLOGD("AT> %s\n", s);
+
+    AT_DUMP( ">> ", s, strlen(s) );
+
+    /* the main string */
+    while (cur < len) {
+        do {
+            written = write (s_fd, s + cur, len - cur);
+        } while (written < 0 && errno == EINTR);
+
+        if (written < 0) {
+            return AT_ERROR_GENERIC;
+        }
+
+        cur += written;
+    }
+
+    /* the \r  */
+
+    do {
+        written = write (s_fd, "\r" , 1);
+    } while ((written < 0 && errno == EINTR) || (written == 0));
+
+    if (written < 0) {
+        return AT_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+static int writeCtrlZ (const char *s)
+{
+    size_t cur = 0;
+    size_t len = strlen(s);
+    ssize_t written;
+
+    if (s_fd < 0 || s_readerClosed > 0) {
+        return AT_ERROR_CHANNEL_CLOSED;
+    }
+
+    RLOGD("AT> %s^Z\n", s);
+
+    AT_DUMP( ">* ", s, strlen(s) );
+
+    /* the main string */
+    while (cur < len) {
+        do {
+            written = write (s_fd, s + cur, len - cur);
+        } while (written < 0 && errno == EINTR);
+
+        if (written < 0) {
+            return AT_ERROR_GENERIC;
+        }
+
+        cur += written;
+    }
+
+    /* the ^Z  */
+
+    do {
+        written = write (s_fd, "\032" , 1);
+    } while ((written < 0 && errno == EINTR) || (written == 0));
+
+    if (written < 0) {
+        return AT_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+
+static void clearPendingCommand()
+{
+    if (sp_response != NULL) {
+        at_response_free(sp_response);
+    }
+
+    sp_response = NULL;
+    s_responsePrefix = NULL;
+    s_smsPDU = NULL;
+}
+
+
+/**
+ * Starts AT handler on stream "fd'
+ * returns 0 on success, -1 on error
+ */
+int at_open(int fd, ATUnsolHandler h)
+{
+    int ret;
+    pthread_t tid;
+    pthread_attr_t attr;
+
+    s_fd = fd;
+    s_unsolHandler = h;
+    s_readerClosed = 0;
+
+    s_responsePrefix = NULL;
+    s_smsPDU = NULL;
+    sp_response = NULL;
+
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
+
+    if (ret < 0) {
+        perror ("pthread_create");
+        return -1;
+    }
+
+
+    return 0;
+}
+
+/* FIXME is it ok to call this from the reader and the command thread? */
+void at_close()
+{
+    if (s_fd >= 0) {
+        close(s_fd);
+    }
+    s_fd = -1;
+
+    pthread_mutex_lock(&s_commandmutex);
+
+    s_readerClosed = 1;
+
+    pthread_cond_signal(&s_commandcond);
+
+    pthread_mutex_unlock(&s_commandmutex);
+
+    /* the reader thread should eventually die */
+}
+
+static ATResponse * at_response_new()
+{
+    return (ATResponse *) calloc(1, sizeof(ATResponse));
+}
+
+void at_response_free(ATResponse *p_response)
+{
+    ATLine *p_line;
+
+    if (p_response == NULL) return;
+
+    p_line = p_response->p_intermediates;
+
+    while (p_line != NULL) {
+        ATLine *p_toFree;
+
+        p_toFree = p_line;
+        p_line = p_line->p_next;
+
+        free(p_toFree->line);
+        free(p_toFree);
+    }
+
+    free (p_response->finalResponse);
+    free (p_response);
+}
+
+/**
+ * The line reader places the intermediate responses in reverse order
+ * here we flip them back
+ */
+static void reverseIntermediates(ATResponse *p_response)
+{
+    ATLine *pcur,*pnext;
+
+    pcur = p_response->p_intermediates;
+    p_response->p_intermediates = NULL;
+
+    while (pcur != NULL) {
+        pnext = pcur->p_next;
+        pcur->p_next = p_response->p_intermediates;
+        p_response->p_intermediates = pcur;
+        pcur = pnext;
+    }
+}
+
+/**
+ * Internal send_command implementation
+ * Doesn't lock or call the timeout callback
+ *
+ * timeoutMsec == 0 means infinite timeout
+ */
+
+static int at_send_command_full_nolock (const char *command, ATCommandType type,
+                    const char *responsePrefix, const char *smspdu,
+                    long long timeoutMsec, ATResponse **pp_outResponse)
+{
+    int err = 0;
+    struct timespec ts;
+
+    if(sp_response != NULL) {
+        err = AT_ERROR_COMMAND_PENDING;
+        goto error;
+    }
+
+    err = writeline (command);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    s_type = type;
+    s_responsePrefix = responsePrefix;
+    s_smsPDU = smspdu;
+    sp_response = at_response_new();
+
+    if (timeoutMsec != 0) {
+        setTimespecRelative(&ts, timeoutMsec);
+    }
+
+    while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
+        if (timeoutMsec != 0) {
+            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
+        } else {
+            err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
+        }
+
+        if (err == ETIMEDOUT) {
+            err = AT_ERROR_TIMEOUT;
+            goto error;
+        }
+    }
+
+    if (pp_outResponse == NULL) {
+        at_response_free(sp_response);
+    } else {
+        /* line reader stores intermediate responses in reverse order */
+        reverseIntermediates(sp_response);
+        *pp_outResponse = sp_response;
+    }
+
+    sp_response = NULL;
+
+    if(s_readerClosed > 0) {
+        err = AT_ERROR_CHANNEL_CLOSED;
+        goto error;
+    }
+
+    err = 0;
+error:
+    clearPendingCommand();
+
+    return err;
+}
+
+/**
+ * Internal send_command implementation
+ *
+ * timeoutMsec == 0 means infinite timeout
+ */
+static int at_send_command_full (const char *command, ATCommandType type,
+                    const char *responsePrefix, const char *smspdu,
+                    long long timeoutMsec, ATResponse **pp_outResponse)
+{
+    int err;
+    bool inEmulator;
+
+    if (0 != pthread_equal(s_tid_reader, pthread_self())) {
+        /* cannot be called from reader thread */
+        return AT_ERROR_INVALID_THREAD;
+    }
+
+    pthread_mutex_lock(&s_writeMutex);
+    pthread_mutex_lock(&s_commandmutex);
+
+    err = at_send_command_full_nolock(command, type,
+                    responsePrefix, smspdu,
+                    timeoutMsec, pp_outResponse);
+
+    pthread_mutex_unlock(&s_commandmutex);
+    pthread_mutex_unlock(&s_writeMutex);
+
+
+    if (err == AT_ERROR_TIMEOUT && s_onTimeout != NULL) {
+        s_onTimeout();
+    }
+
+    return err;
+}
+
+
+/**
+ * Issue a single normal AT command with no intermediate response expected
+ *
+ * "command" should not include \r
+ * pp_outResponse can be NULL
+ *
+ * if non-NULL, the resulting ATResponse * must be eventually freed with
+ * at_response_free
+ */
+int at_send_command (const char *command, ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, NO_RESULT, NULL,
+                                    NULL, 0, pp_outResponse);
+
+    return err;
+}
+
+
+int at_send_command_singleline (const char *command,
+                                const char *responsePrefix,
+                                 ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                    NULL, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+    ) {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+int at_send_command_numeric (const char *command,
+                                 ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, NUMERIC, NULL,
+                                    NULL, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+    ) {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+int at_send_command_sms (const char *command,
+                                const char *pdu,
+                                const char *responsePrefix,
+                                 ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                    pdu, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+    ) {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+int at_send_command_multiline (const char *command,
+                                const char *responsePrefix,
+                                 ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, MULTILINE, responsePrefix,
+                                    NULL, 0, pp_outResponse);
+
+    return err;
+}
+
+
+/** This callback is invoked on the command thread */
+void at_set_on_timeout(void (*onTimeout)(void))
+{
+    s_onTimeout = onTimeout;
+}
+
+/**
+ *  This callback is invoked on the reader thread (like ATUnsolHandler)
+ *  when the input stream closes before you call at_close
+ *  (not when you call at_close())
+ *  You should still call at_close()
+ */
+
+void at_set_on_reader_closed(void (*onClose)(void))
+{
+    s_onReaderClosed = onClose;
+}
+
+
+/**
+ * Periodically issue an AT command and wait for a response.
+ * Used to ensure channel has start up and is active
+ */
+
+int at_handshake()
+{
+    int i;
+    int err = 0;
+    bool inEmulator;
+
+    if (0 != pthread_equal(s_tid_reader, pthread_self())) {
+        /* cannot be called from reader thread */
+        return AT_ERROR_INVALID_THREAD;
+    }
+    inEmulator = isInEmulator();
+    if (inEmulator) {
+        pthread_mutex_lock(&s_writeMutex);
+    }
+    pthread_mutex_lock(&s_commandmutex);
+
+    for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++) {
+        /* some stacks start with verbose off */
+        err = at_send_command_full_nolock ("ATE0Q0V1", NO_RESULT,
+                    NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
+
+        if (err == 0) {
+            break;
+        }
+    }
+
+    if (err == 0) {
+        /* pause for a bit to let the input buffer drain any unmatched OK's
+           (they will appear as extraneous unsolicited responses) */
+
+        sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
+    }
+
+    pthread_mutex_unlock(&s_commandmutex);
+    if (inEmulator) {
+        pthread_mutex_unlock(&s_writeMutex);
+    }
+
+    return err;
+}
+
+/**
+ * Returns error code from response
+ * Assumes AT+CMEE=1 (numeric) mode
+ */
+AT_CME_Error at_get_cme_error(const ATResponse *p_response)
+{
+    int ret;
+    int err;
+    char *p_cur;
+
+    if (p_response->success > 0) {
+        return CME_SUCCESS;
+    }
+
+    if (p_response->finalResponse == NULL
+        || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
+    ) {
+        return CME_ERROR_NON_CME;
+    }
+
+    p_cur = p_response->finalResponse;
+    err = at_tok_start(&p_cur);
+
+    if (err < 0) {
+        return CME_ERROR_NON_CME;
+    }
+
+    err = at_tok_nextint(&p_cur, &ret);
+
+    if (err < 0) {
+        return CME_ERROR_NON_CME;
+    }
+
+    return (AT_CME_Error) ret;
+}
+
diff --git a/guest/hals/ril/reference-ril/atchannel.h b/guest/hals/ril/reference-ril/atchannel.h
new file mode 100644
index 0000000..9282915
--- /dev/null
+++ b/guest/hals/ril/reference-ril/atchannel.h
@@ -0,0 +1,124 @@
+/* //device/system/reference-ril/atchannel.h
+**
+** Copyright 2006, 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.
+*/
+
+#ifndef ATCHANNEL_H
+#define ATCHANNEL_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* define AT_DEBUG to send AT traffic to /tmp/radio-at.log" */
+#define AT_DEBUG  0
+
+#if AT_DEBUG
+extern void  AT_DUMP(const char* prefix, const char*  buff, int  len);
+#else
+#define  AT_DUMP(prefix,buff,len)  do{}while(0)
+#endif
+
+#define AT_ERROR_GENERIC          (-1)
+#define AT_ERROR_COMMAND_PENDING  (-2)
+#define AT_ERROR_CHANNEL_CLOSED   (-3)
+#define AT_ERROR_TIMEOUT          (-4)
+#define AT_ERROR_INVALID_THREAD   (-5) /* AT commands may not be issued from
+                                          reader thread (or unsolicited response
+                                          callback */
+#define AT_ERROR_INVALID_RESPONSE (-6) /* eg an at_send_command_singleline that
+                                          did not get back an intermediate
+                                          response */
+
+
+typedef enum {
+    NO_RESULT,   /* no intermediate response expected */
+    NUMERIC,     /* a single intermediate response starting with a 0-9 */
+    SINGLELINE,  /* a single intermediate response starting with a prefix */
+    MULTILINE    /* multiple line intermediate response
+                    starting with a prefix */
+} ATCommandType;
+
+/** a singly-lined list of intermediate responses */
+typedef struct ATLine  {
+    struct ATLine *p_next;
+    char *line;
+} ATLine;
+
+/** Free this with at_response_free() */
+typedef struct {
+    int success;              /* true if final response indicates
+                                    success (eg "OK") */
+    char *finalResponse;      /* eg OK, ERROR */
+    ATLine  *p_intermediates; /* any intermediate responses */
+} ATResponse;
+
+/**
+ * a user-provided unsolicited response handler function
+ * this will be called from the reader thread, so do not block
+ * "s" is the line, and "sms_pdu" is either NULL or the PDU response
+ * for multi-line TS 27.005 SMS PDU responses (eg +CMT:)
+ */
+typedef void (*ATUnsolHandler)(const char *s, const char *sms_pdu);
+
+int at_open(int fd, ATUnsolHandler h);
+void at_close();
+
+/* This callback is invoked on the command thread.
+   You should reset or handshake here to avoid getting out of sync */
+void at_set_on_timeout(void (*onTimeout)(void));
+/* This callback is invoked on the reader thread (like ATUnsolHandler)
+   when the input stream closes before you call at_close
+   (not when you call at_close())
+   You should still call at_close()
+   It may also be invoked immediately from the current thread if the read
+   channel is already closed */
+void at_set_on_reader_closed(void (*onClose)(void));
+
+int at_send_command_singleline (const char *command,
+                                const char *responsePrefix,
+                                 ATResponse **pp_outResponse);
+
+int at_send_command_numeric (const char *command,
+                                 ATResponse **pp_outResponse);
+
+int at_send_command_multiline (const char *command,
+                                const char *responsePrefix,
+                                 ATResponse **pp_outResponse);
+
+
+int at_handshake();
+
+int at_send_command (const char *command, ATResponse **pp_outResponse);
+
+int at_send_command_sms (const char *command, const char *pdu,
+                            const char *responsePrefix,
+                            ATResponse **pp_outResponse);
+
+void at_response_free(ATResponse *p_response);
+
+typedef enum {
+    CME_ERROR_NON_CME = -1,
+    CME_SUCCESS = 0,
+    CME_SIM_NOT_INSERTED = 10
+} AT_CME_Error;
+
+AT_CME_Error at_get_cme_error(const ATResponse *p_response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*ATCHANNEL_H*/
diff --git a/guest/hals/ril/reference-ril/base64util.cpp b/guest/hals/ril/reference-ril/base64util.cpp
new file mode 100644
index 0000000..c75e80e
--- /dev/null
+++ b/guest/hals/ril/reference-ril/base64util.cpp
@@ -0,0 +1,59 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include "base64util.h"
+
+#include <vector>
+
+#include "common/libs/utils/base64.h"
+
+extern "C" {
+
+int base64_decode(const char *base64input, unsigned char *bindata) {
+  if (!base64input || !bindata) {
+    return 0;
+  }
+
+  std::vector<uint8_t> output;
+  std::string input(base64input);
+  bool success = cuttlefish::DecodeBase64(input, &output);
+  if (!success) {
+    return 0;
+  }
+  memcpy(bindata, reinterpret_cast<unsigned char *>(output.data()),
+         output.size());
+  return output.size();
+}
+
+char *base64_encode(const unsigned char *bindata, char *base64output,
+                    int binlength) {
+  if (!base64output || !bindata || binlength <= 0) {
+    return NULL;
+  }
+
+  std::string output;
+  bool success = cuttlefish::EncodeBase64(
+      bindata, static_cast<size_t>(binlength), &output);
+
+  if (!success) {
+    return NULL;
+  }
+
+  memcpy(base64output, output.data(), output.size());
+  return base64output;
+}
+}
diff --git a/guest/hals/ril/reference-ril/base64util.h b/guest/hals/ril/reference-ril/base64util.h
new file mode 100644
index 0000000..a448fe0
--- /dev/null
+++ b/guest/hals/ril/reference-ril/base64util.h
@@ -0,0 +1,29 @@
+/*
+**
+** Copyright 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** decode base64, returns the encoded output */
+int base64_decode(const char *base64, unsigned char *bindata);
+/** encode base64, returns the number of bytes decoded */
+char *base64_encode(const unsigned char *bindata, char *base64, int binlength);
+#ifdef __cplusplus
+}
+#endif
diff --git a/guest/hals/ril/reference-ril/misc.c b/guest/hals/ril/reference-ril/misc.c
new file mode 100644
index 0000000..25fdc2f
--- /dev/null
+++ b/guest/hals/ril/reference-ril/misc.c
@@ -0,0 +1,50 @@
+/* //device/system/reference-ril/misc.c
+**
+** Copyright 2006, 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.
+*/
+#include <sys/system_properties.h>
+
+#include <fcntl.h>
+#include "misc.h"
+/** returns 1 if line starts with prefix, 0 if it does not */
+int strStartsWith(const char *line, const char *prefix)
+{
+    for ( ; *line != '\0' && *prefix != '\0' ; line++, prefix++) {
+        if (*line != *prefix) {
+            return 0;
+        }
+    }
+
+    return *prefix == '\0';
+}
+
+// Returns true iff running this process in an emulator VM
+bool isInEmulator(void) {
+  static int inQemu = -1;
+  if (inQemu < 0) {
+      char propValue[PROP_VALUE_MAX];
+      inQemu = (__system_property_get("ro.boot.qemu", propValue) != 0);
+  }
+  return inQemu == 1;
+}
+
+int qemu_open_modem_port() {
+    char propValue[PROP_VALUE_MAX];
+    if (__system_property_get("vendor.qemu.vport.modem", propValue) <= 0) {
+        return -1;
+    }
+    int fd = open(propValue, O_RDWR);
+    return fd;
+}
diff --git a/guest/hals/ril/reference-ril/misc.h b/guest/hals/ril/reference-ril/misc.h
new file mode 100644
index 0000000..ed62c69
--- /dev/null
+++ b/guest/hals/ril/reference-ril/misc.h
@@ -0,0 +1,24 @@
+/* //device/system/reference-ril/misc.h
+**
+** Copyright 2006, 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.
+*/
+#include <stdbool.h>
+
+/** returns 1 if line starts with prefix, 0 if it does not */
+int strStartsWith(const char *line, const char *prefix);
+/** Returns true iff running this process in an emulator VM */
+bool isInEmulator(void);
+/** open the modem port inside emulator VM; -1 if fails */
+int qemu_open_modem_port();
diff --git a/guest/hals/ril/reference-ril/reference-ril.c b/guest/hals/ril/reference-ril/reference-ril.c
new file mode 100644
index 0000000..04cdfce
--- /dev/null
+++ b/guest/hals/ril/reference-ril/reference-ril.c
@@ -0,0 +1,6246 @@
+/* //device/system/reference-ril/reference-ril.c
+**
+** Copyright 2006, 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.
+*/
+
+#include <telephony/ril_cdma_sms.h>
+#include <telephony/librilutils.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <alloca.h>
+#include "atchannel.h"
+#include "at_tok.h"
+#include "base64util.h"
+#include "misc.h"
+#include <getopt.h>
+#include <sys/socket.h>
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+#include <termios.h>
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/vm_sockets.h>
+#include <arpa/inet.h>
+
+#include "guest/hals/ril/reference-libril/ril.h"
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+
+static void *noopRemoveWarning( void *a ) { return a; }
+#define RIL_UNUSED_PARM(a) noopRemoveWarning((void *)&(a));
+
+#define MAX_AT_RESPONSE 0x1000
+
+#define MAX_PDP         3
+
+/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
+// This is used if Wifi is not supported, plain old eth0
+#ifdef CUTTLEFISH_ENABLE
+#define PPP_TTY_PATH_ETH0 "rmnet0"
+#else
+#define PPP_TTY_PATH_ETH0 "eth0"
+#endif
+// This is used for emulator
+#define EMULATOR_RADIO_INTERFACE "eth0"
+
+// for sim
+#define AUTH_CONTEXT_EAP_SIM                    128
+#define AUTH_CONTEXT_EAP_AKA                    129
+#define SIM_AUTH_RESPONSE_SUCCESS               0
+#define SIM_AUTH_RESPONSE_SYNC_FAILURE          3
+
+// Default MTU value
+#define DEFAULT_MTU 1500
+
+#ifdef USE_TI_COMMANDS
+
+// Enable a workaround
+// 1) Make incoming call, do not answer
+// 2) Hangup remote end
+// Expected: call should disappear from CLCC line
+// Actual: Call shows as "ACTIVE" before disappearing
+#define WORKAROUND_ERRONEOUS_ANSWER 1
+
+// Some variants of the TI stack do not support the +CGEV unsolicited
+// response. However, they seem to send an unsolicited +CME ERROR: 150
+#define WORKAROUND_FAKE_CGEV 1
+#endif
+
+/* Modem Technology bits */
+#define MDM_GSM         0x01
+#define MDM_WCDMA       0x02
+#define MDM_CDMA        0x04
+#define MDM_EVDO        0x08
+#define MDM_TDSCDMA     0x10
+#define MDM_LTE         0x20
+#define MDM_NR          0x40
+
+typedef struct {
+    int supportedTechs; // Bitmask of supported Modem Technology bits
+    int currentTech;    // Technology the modem is currently using (in the format used by modem)
+    int isMultimode;
+
+    // Preferred mode bitmask. This is actually 4 byte-sized bitmasks with different priority values,
+    // in which the byte number from LSB to MSB give the priority.
+    //
+    //          |MSB|   |   |LSB
+    // value:   |00 |00 |00 |00
+    // byte #:  |3  |2  |1  |0
+    //
+    // Higher byte order give higher priority. Thus, a value of 0x0000000f represents
+    // a preferred mode of GSM, WCDMA, CDMA, and EvDo in which all are equally preferrable, whereas
+    // 0x00000201 represents a mode with GSM and WCDMA, in which WCDMA is preferred over GSM
+    int32_t preferredNetworkMode;
+    int subscription_source;
+
+} ModemInfo;
+
+static ModemInfo *sMdmInfo;
+// TECH returns the current technology in the format used by the modem.
+// It can be used as an l-value
+#define TECH(mdminfo)                 ((mdminfo)->currentTech)
+// TECH_BIT returns the bitmask equivalent of the current tech
+#define TECH_BIT(mdminfo)            (1 << ((mdminfo)->currentTech))
+#define IS_MULTIMODE(mdminfo)         ((mdminfo)->isMultimode)
+#define TECH_SUPPORTED(mdminfo, tech) ((mdminfo)->supportedTechs & (tech))
+#define PREFERRED_NETWORK(mdminfo)    ((mdminfo)->preferredNetworkMode)
+// CDMA Subscription Source
+#define SSOURCE(mdminfo)              ((mdminfo)->subscription_source)
+
+static int net2modem[] = {
+    MDM_GSM | MDM_WCDMA,                                 // 0  - GSM / WCDMA Pref
+    MDM_GSM,                                             // 1  - GSM only
+    MDM_WCDMA,                                           // 2  - WCDMA only
+    MDM_GSM | MDM_WCDMA,                                 // 3  - GSM / WCDMA Auto
+    MDM_CDMA | MDM_EVDO,                                 // 4  - CDMA / EvDo Auto
+    MDM_CDMA,                                            // 5  - CDMA only
+    MDM_EVDO,                                            // 6  - EvDo only
+    MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO,           // 7  - GSM/WCDMA, CDMA, EvDo
+    MDM_LTE | MDM_CDMA | MDM_EVDO,                       // 8  - LTE, CDMA and EvDo
+    MDM_LTE | MDM_GSM | MDM_WCDMA,                       // 9  - LTE, GSM/WCDMA
+    MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
+    MDM_LTE,                                             // 11 - LTE only
+    MDM_LTE | MDM_WCDMA,                                 // 12 - LTE and WCDMA
+    MDM_TDSCDMA,                                         // 13 - TD-SCDMA only
+    MDM_WCDMA | MDM_TDSCDMA,                             // 14 - TD-SCDMA and WCDMA
+    MDM_LTE | MDM_TDSCDMA,                               // 15 - LTE and TD-SCDMA
+    MDM_TDSCDMA | MDM_GSM,                               // 16 - TD-SCDMA and GSM
+    MDM_LTE | MDM_TDSCDMA | MDM_GSM,                     // 17 - TD-SCDMA, GSM and LTE
+    MDM_WCDMA | MDM_TDSCDMA | MDM_GSM,                   // 18 - TD-SCDMA, GSM and WCDMA
+    MDM_LTE | MDM_WCDMA | MDM_TDSCDMA,                   // 19 - LTE, TD-SCDMA and WCDMA
+    MDM_LTE | MDM_WCDMA | MDM_TDSCDMA | MDM_GSM,         // 20 - LTE, TD-SCDMA, GSM, and WCDMA
+    MDM_EVDO | MDM_CDMA | MDM_WCDMA | MDM_TDSCDMA | MDM_GSM,            // 21 - TD-SCDMA, CDMA, EVDO, GSM and WCDMA
+    MDM_LTE | MDM_TDSCDMA | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM,  // 22 - LTE, TDCSDMA, CDMA, EVDO, GSM and WCDMA
+    MDM_NR,                                                             // 23 - NR 5G only mode
+    MDM_NR | MDM_LTE,                                                   // 24 - NR 5G, LTE
+    MDM_NR | MDM_LTE | MDM_CDMA | MDM_EVDO,                             // 25 - NR 5G, LTE, CDMA and EvDo
+    MDM_NR | MDM_LTE | MDM_WCDMA | MDM_GSM,                             // 26 - NR 5G, LTE, GSM and WCDMA
+    MDM_NR | MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM,       // 27 - NR 5G, LTE, CDMA, EvDo, GSM and WCDMA
+    MDM_NR | MDM_LTE | MDM_WCDMA,                                       // 28 - NR 5G, LTE and WCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA,                                     // 29 - NR 5G, LTE and TDSCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_GSM,                           // 30 - NR 5G, LTE, TD-SCDMA and GSM
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_WCDMA,                         // 31 - NR 5G, LTE, TD-SCDMA, WCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_WCDMA | MDM_GSM,               // 32 - NR 5G, LTE, TD-SCDMA, GSM and WCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM,  // 33 - NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA
+};
+
+static int32_t net2pmask[] = {
+    MDM_GSM | (MDM_WCDMA << 8),                          // 0  - GSM / WCDMA Pref
+    MDM_GSM,                                             // 1  - GSM only
+    MDM_WCDMA,                                           // 2  - WCDMA only
+    MDM_GSM | MDM_WCDMA,                                 // 3  - GSM / WCDMA Auto
+    MDM_CDMA | MDM_EVDO,                                 // 4  - CDMA / EvDo Auto
+    MDM_CDMA,                                            // 5  - CDMA only
+    MDM_EVDO,                                            // 6  - EvDo only
+    MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO,           // 7  - GSM/WCDMA, CDMA, EvDo
+    MDM_LTE | MDM_CDMA | MDM_EVDO,                       // 8  - LTE, CDMA and EvDo
+    MDM_LTE | MDM_GSM | MDM_WCDMA,                       // 9  - LTE, GSM/WCDMA
+    MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
+    MDM_LTE,                                             // 11 - LTE only
+    MDM_LTE | MDM_WCDMA,                                 // 12 - LTE and WCDMA
+    MDM_TDSCDMA,                                         // 13 - TD-SCDMA only
+    MDM_WCDMA | MDM_TDSCDMA,                             // 14 - TD-SCDMA and WCDMA
+    MDM_LTE | MDM_TDSCDMA,                               // 15 - LTE and TD-SCDMA
+    MDM_TDSCDMA | MDM_GSM,                               // 16 - TD-SCDMA and GSM
+    MDM_LTE | MDM_TDSCDMA | MDM_GSM,                     // 17 - TD-SCDMA, GSM and LTE
+    MDM_WCDMA | MDM_TDSCDMA | MDM_GSM,                   // 18 - TD-SCDMA, GSM and WCDMA
+    MDM_LTE | MDM_WCDMA | MDM_TDSCDMA,                   // 19 - LTE, TD-SCDMA and WCDMA
+    MDM_LTE | MDM_WCDMA | MDM_TDSCDMA | MDM_GSM,         // 20 - LTE, TD-SCDMA, GSM, and WCDMA
+    MDM_EVDO | MDM_CDMA | MDM_WCDMA | MDM_TDSCDMA | MDM_GSM,            // 21 - TD-SCDMA, CDMA, EVDO, GSM and WCDMA
+    MDM_LTE | MDM_TDSCDMA | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM,  // 22 - LTE, TDCSDMA, CDMA, EVDO, GSM and WCDMA
+    MDM_NR,                                                             // 23 - NR 5G only mode
+    MDM_NR | MDM_LTE,                                                   // 24 - NR 5G, LTE
+    MDM_NR | MDM_LTE | MDM_CDMA | MDM_EVDO,                             // 25 - NR 5G, LTE, CDMA and EvDo
+    MDM_NR | MDM_LTE | MDM_WCDMA | MDM_GSM,                             // 26 - NR 5G, LTE, GSM and WCDMA
+    MDM_NR | MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM,       // 27 - NR 5G, LTE, CDMA, EvDo, GSM and WCDMA
+    MDM_NR | MDM_LTE | MDM_WCDMA,                                       // 28 - NR 5G, LTE and WCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA,                                     // 29 - NR 5G, LTE and TDSCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_GSM,                           // 30 - NR 5G, LTE, TD-SCDMA and GSM
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_WCDMA,                         // 31 - NR 5G, LTE, TD-SCDMA, WCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_WCDMA | MDM_GSM,               // 32 - NR 5G, LTE, TD-SCDMA, GSM and WCDMA
+    MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM,  // 33 - NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA
+};
+
+#define GSM   (RAF_GSM | RAF_GPRS | RAF_EDGE)
+#define CDMA  (RAF_IS95A | RAF_IS95B | RAF_1xRTT)
+#define EVDO  (RAF_EVDO_0 | RAF_EVDO_A | RAF_EVDO_B | RAF_EHRPD)
+#define WCDMA (RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP | RAF_UMTS)
+#define LTE   (RAF_LTE | RAF_LTE_CA)
+#define NR    (RAF_NR)
+
+typedef struct {
+    int bitmap;
+    int type;
+} NetworkTypeBitmap;
+
+static NetworkTypeBitmap s_networkMask[] = {
+    {WCDMA | GSM,                     MDM_GSM | (MDM_WCDMA << 8)},                // 0 - GSM / WCDMA Pref
+    {GSM,                             MDM_GSM},                                   // 1 - GSM only
+    {WCDMA,                           MDM_WCDMA},                                 // 2 - WCDMA only
+    {WCDMA | GSM,                     MDM_GSM | MDM_WCDMA},                       // 3 - GSM / WCDMA Auto
+    {CDMA | EVDO,                     MDM_CDMA | MDM_EVDO},                       // 4 - CDMA / EvDo Auto
+    {CDMA,                            MDM_CDMA},                                  // 5 - CDMA only
+    {EVDO,                            MDM_EVDO},                                  // 6 - EvDo only
+    {GSM | WCDMA | CDMA | EVDO,       MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO}, // 7 - GSM/WCDMA, CDMA, EvDo
+    {LTE | CDMA | EVDO,               MDM_LTE | MDM_CDMA | MDM_EVDO},             // 8 - LTE, CDMA and EvDo
+    {LTE | GSM | WCDMA,               MDM_LTE | MDM_GSM | MDM_WCDMA},             // 9 - LTE, GSM/WCDMA
+    {LTE | CDMA | EVDO | GSM | WCDMA, MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA}, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
+    {LTE,                             MDM_LTE},                                             // 11 - LTE only
+    {LTE | WCDMA,                     MDM_LTE | MDM_WCDMA},                                 // 12 - LTE and WCDMA
+    {RAF_TD_SCDMA,                    MDM_TDSCDMA},                                         // 13 - TD-SCDMA only
+    {RAF_TD_SCDMA | WCDMA,            MDM_WCDMA | MDM_TDSCDMA},                             // 14 - TD-SCDMA and WCDMA
+    {LTE | RAF_TD_SCDMA,              MDM_LTE | MDM_TDSCDMA},                               // 15 - LTE and TD-SCDMA
+    {RAF_TD_SCDMA | GSM,              MDM_TDSCDMA | MDM_GSM},                               // 16 - TD-SCDMA and GSM
+    {LTE | RAF_TD_SCDMA | GSM,        MDM_LTE | MDM_TDSCDMA | MDM_GSM},                     // 17 - TD-SCDMA, GSM and LTE
+    {RAF_TD_SCDMA | GSM | WCDMA,      MDM_WCDMA | MDM_TDSCDMA | MDM_GSM},                   // 18 - TD-SCDMA, GSM and WCDMA
+    {LTE | RAF_TD_SCDMA | WCDMA,      MDM_LTE | MDM_WCDMA | MDM_TDSCDMA},                   // 19 - LTE, TD-SCDMA and WCDMA
+    {LTE | RAF_TD_SCDMA | GSM | WCDMA,MDM_LTE | MDM_WCDMA | MDM_TDSCDMA | MDM_GSM},         // 20 - LTE, TD-SCDMA, GSM, and WCDMA
+    {RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA,  MDM_EVDO | MDM_CDMA | MDM_WCDMA | MDM_TDSCDMA | MDM_GSM},            // 21 - TD-SCDMA, CDMA, EVDO, GSM and WCDMA
+    {LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA, MDM_LTE | MDM_TDSCDMA | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM},  // 22 - LTE, TDCSDMA, CDMA, EVDO, GSM and WCDMA
+    {NR,                              MDM_NR},                                                             // 23 - NR 5G only mode
+    {NR | LTE,                        MDM_NR | MDM_LTE},                                                   // 24 - NR 5G, LTE
+    {NR | LTE | CDMA | EVDO,          MDM_NR | MDM_LTE | MDM_CDMA | MDM_EVDO},                             // 25 - NR 5G, LTE, CDMA and EvDo
+    {NR | LTE | GSM | WCDMA,          MDM_NR | MDM_LTE | MDM_WCDMA | MDM_GSM},                             // 26 - NR 5G, LTE, GSM and WCDMA
+    {NR | LTE | CDMA | EVDO | GSM | WCDMA, MDM_NR | MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM},  // 27 - NR 5G, LTE, CDMA, EvDo, GSM and WCDMA
+    {NR | LTE | WCDMA,                MDM_NR | MDM_LTE | MDM_WCDMA},                                       // 28 - NR 5G, LTE and WCDMA
+    {NR | LTE | RAF_TD_SCDMA,         MDM_NR | MDM_LTE | MDM_TDSCDMA},                                     // 29 - NR 5G, LTE and TDSCDMA
+    {NR | LTE | RAF_TD_SCDMA | GSM,   MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_GSM},                           // 30 - NR 5G, LTE, TD-SCDMA and GSM
+    {NR | LTE | RAF_TD_SCDMA | WCDMA, MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_WCDMA},                         // 31 - NR 5G, LTE, TD-SCDMA, WCDMA
+    {NR | LTE | RAF_TD_SCDMA | GSM | WCDMA, MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_WCDMA | MDM_GSM},         // 32 - NR 5G, LTE, TD-SCDMA, GSM and WCDMA
+    {NR | LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA, MDM_NR | MDM_LTE | MDM_TDSCDMA | MDM_CDMA | MDM_EVDO | MDM_WCDMA | MDM_GSM},  // 33 - NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA
+};
+
+static int is3gpp2(int radioTech) {
+    switch (radioTech) {
+        case RADIO_TECH_IS95A:
+        case RADIO_TECH_IS95B:
+        case RADIO_TECH_1xRTT:
+        case RADIO_TECH_EVDO_0:
+        case RADIO_TECH_EVDO_A:
+        case RADIO_TECH_EVDO_B:
+        case RADIO_TECH_EHRPD:
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+typedef enum {
+    SIM_ABSENT = 0,
+    SIM_NOT_READY = 1,
+    SIM_READY = 2,
+    SIM_PIN = 3,
+    SIM_PUK = 4,
+    SIM_NETWORK_PERSONALIZATION = 5,
+    RUIM_ABSENT = 6,
+    RUIM_NOT_READY = 7,
+    RUIM_READY = 8,
+    RUIM_PIN = 9,
+    RUIM_PUK = 10,
+    RUIM_NETWORK_PERSONALIZATION = 11,
+    ISIM_ABSENT = 12,
+    ISIM_NOT_READY = 13,
+    ISIM_READY = 14,
+    ISIM_PIN = 15,
+    ISIM_PUK = 16,
+    ISIM_NETWORK_PERSONALIZATION = 17,
+} SIM_Status;
+
+static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
+static RIL_RadioState currentState();
+static int onSupports (int requestCode);
+static void onCancel (RIL_Token t);
+static const char *getVersion();
+static int isRadioOn();
+static SIM_Status getSIMStatus();
+static int getCardStatus(RIL_CardStatus_v1_5 **pp_card_status);
+static void freeCardStatus(RIL_CardStatus_v1_5 *p_card_status);
+static void onDataCallListChanged(void *param);
+bool areUiccApplicationsEnabled = true;
+
+extern const char * requestToString(int request);
+extern uint8_t hexCharToInt(uint8_t c);
+extern uint8_t * convertHexStringToBytes(void *response, size_t responseLen);
+
+/*** Static Variables ***/
+static const RIL_RadioFunctions s_callbacks = {
+    RIL_VERSION,
+    onRequest,
+    currentState,
+    onSupports,
+    onCancel,
+    getVersion
+};
+
+#ifdef RIL_SHLIB
+static const struct RIL_Env *s_rilenv;
+
+#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
+#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
+#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
+#endif
+
+static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
+static bool isNrDualConnectivityEnabled = true;
+
+static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
+
+static int s_port = -1;
+static const char * s_device_path = NULL;
+static int          s_device_socket = 0;
+static uint32_t s_modem_simulator_port = -1;
+
+/* trigger change to this with s_state_cond */
+static int s_closed = 0;
+
+static int sFD;     /* file desc of AT channel */
+static char sATBuffer[MAX_AT_RESPONSE+1];
+static char *sATBufferCur = NULL;
+
+static const struct timeval TIMEVAL_SIMPOLL = {1,0};
+static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
+static const struct timeval TIMEVAL_0 = {0,0};
+
+static int s_ims_registered  = 0;        // 0==unregistered
+static int s_ims_services    = 1;        // & 0x1 == sms over ims supported
+static int s_ims_format    = 1;          // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
+static int s_ims_cause_retry = 0;        // 1==causes sms over ims to temp fail
+static int s_ims_cause_perm_failure = 0; // 1==causes sms over ims to permanent fail
+static int s_ims_gsm_retry   = 0;        // 1==causes sms over gsm to temp fail
+static int s_ims_gsm_fail    = 0;        // 1==causes sms over gsm to permanent fail
+
+#ifdef WORKAROUND_ERRONEOUS_ANSWER
+// Max number of times we'll try to repoll when we think
+// we have a AT+CLCC race condition
+#define REPOLL_CALLS_COUNT_MAX 4
+
+// Line index that was incoming or waiting at last poll, or -1 for none
+static int s_incomingOrWaitingLine = -1;
+// Number of times we've asked for a repoll of AT+CLCC
+static int s_repollCallsCount = 0;
+// Should we expect a call to be answered in the next CLCC?
+static int s_expectAnswer = 0;
+#endif /* WORKAROUND_ERRONEOUS_ANSWER */
+
+
+static int s_cell_info_rate_ms = INT_MAX;
+static int s_mcc = 0;
+static int s_mnc = 0;
+static int s_mncLength = 2;
+static int s_lac = 0;
+static int s_cid = 0;
+
+// STK
+static bool s_stkServiceRunning = false;
+static char *s_stkUnsolResponse = NULL;
+
+typedef enum {
+    STK_UNSOL_EVENT_UNKNOWN,
+    STK_UNSOL_EVENT_NOTIFY,
+    STK_UNSOL_PROACTIVE_CMD,
+} StkUnsolEvent;
+
+typedef enum {
+    STK_RUN_AT        = 0x34,
+    STK_SEND_DTMF     = 0x14,
+    STK_SEND_SMS      = 0x13,
+    STK_SEND_SS       = 0x11,
+    STK_SEND_USSD     = 0x12,
+    STK_PLAY_TONE     = 0x20,
+    STK_OPEN_CHANNEL  = 0x40,
+    STK_CLOSE_CHANNEL = 0x41,
+    STK_RECEIVE_DATA  = 0x42,
+    STK_SEND_DATA     = 0x43,
+    STK_GET_CHANNEL_STATUS = 0x44,
+    STK_REFRESH       = 0x01,
+} StkCmdType;
+
+enum PDPState {
+    PDP_IDLE,
+    PDP_BUSY,
+};
+
+struct PDPInfo {
+    int cid;
+    enum PDPState state;
+};
+
+struct PDPInfo s_PDP[] = {
+     {1, PDP_IDLE},
+     {2, PDP_IDLE},
+     {3, PDP_IDLE},
+};
+
+static void pollSIMState (void *param);
+static void setRadioState(RIL_RadioState newState);
+static void setRadioTechnology(ModemInfo *mdm, int newtech);
+static int query_ctec(ModemInfo *mdm, int *current, int32_t *preferred);
+static int parse_technology_response(const char *response, int *current, int32_t *preferred);
+static int techFromModemType(int mdmtype);
+static void getIccId(char *iccid, int size);
+
+static int clccStateToRILState(int state, RIL_CallState *p_state)
+{
+    switch(state) {
+        case 0: *p_state = RIL_CALL_ACTIVE;   return 0;
+        case 1: *p_state = RIL_CALL_HOLDING;  return 0;
+        case 2: *p_state = RIL_CALL_DIALING;  return 0;
+        case 3: *p_state = RIL_CALL_ALERTING; return 0;
+        case 4: *p_state = RIL_CALL_INCOMING; return 0;
+        case 5: *p_state = RIL_CALL_WAITING;  return 0;
+        default: return -1;
+    }
+}
+
+void convertBytesToHexString(char *bin_ptr, int length, unsigned char *hex_ptr) {
+    int i;
+    unsigned char tmp;
+
+    if (bin_ptr == NULL || hex_ptr == NULL) {
+        return;
+    }
+    for (i = 0; i < length; i++) {
+        tmp = (unsigned char)((bin_ptr[i] & 0xf0) >> 4);
+        if (tmp <= 9) {
+            *hex_ptr = (unsigned char)(tmp + '0');
+        } else {
+            *hex_ptr = (unsigned char)(tmp + 'A' - 10);
+        }
+        hex_ptr++;
+        tmp = (unsigned char)(bin_ptr[i] & 0x0f);
+        if (tmp <= 9) {
+            *hex_ptr = (unsigned char)(tmp + '0');
+        } else {
+            *hex_ptr = (unsigned char)(tmp + 'A' - 10);
+        }
+        hex_ptr++;
+    }
+}
+
+/**
+ * Note: directly modified line and has *p_call point directly into
+ * modified line
+ */
+static int callFromCLCCLine(char *line, RIL_Call *p_call)
+{
+        //+CLCC: 1,0,2,0,0,\"+18005551212\",145
+        //     index,isMT,state,mode,isMpty(,number,TOA)?
+
+    int err;
+    int state;
+    int mode;
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &(p_call->index));
+    if (err < 0) goto error;
+
+    err = at_tok_nextbool(&line, &(p_call->isMT));
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &state);
+    if (err < 0) goto error;
+
+    err = clccStateToRILState(state, &(p_call->state));
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &mode);
+    if (err < 0) goto error;
+
+    p_call->isVoice = (mode == 0);
+
+    err = at_tok_nextbool(&line, &(p_call->isMpty));
+    if (err < 0) goto error;
+
+    if (at_tok_hasmore(&line)) {
+        err = at_tok_nextstr(&line, &(p_call->number));
+
+        /* tolerate null here */
+        if (err < 0) return 0;
+
+        // Some lame implementations return strings
+        // like "NOT AVAILABLE" in the CLCC line
+        if (p_call->number != NULL
+            && 0 == strspn(p_call->number, "+0123456789")
+        ) {
+            p_call->number = NULL;
+        }
+
+        err = at_tok_nextint(&line, &p_call->toa);
+        if (err < 0) goto error;
+    }
+
+    p_call->uusInfo = NULL;
+
+    return 0;
+
+error:
+    RLOGE("invalid CLCC line\n");
+    return -1;
+}
+
+static int parseSimResponseLine(char* line, RIL_SIM_IO_Response* response) {
+    int err;
+
+    err = at_tok_start(&line);
+    if (err < 0) return err;
+    err = at_tok_nextint(&line, &response->sw1);
+    if (err < 0) return err;
+    err = at_tok_nextint(&line, &response->sw2);
+    if (err < 0) return err;
+
+    if (at_tok_hasmore(&line)) {
+        err = at_tok_nextstr(&line, &response->simResponse);
+        if (err < 0) return err;
+    }
+    return 0;
+}
+
+#ifdef CUTTLEFISH_ENABLE
+static void set_Ip_Addr(const char *addr, const char* radioInterfaceName) {
+  RLOGD("%s %d setting ip addr %s on interface %s", __func__, __LINE__, addr,
+        radioInterfaceName);
+  struct ifreq request;
+  int status = 0;
+  int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+  if (sock == -1) {
+    RLOGE("Failed to open interface socket: %s (%d)", strerror(errno), errno);
+    return;
+  }
+
+  memset(&request, 0, sizeof(request));
+  strncpy(request.ifr_name, radioInterfaceName, sizeof(request.ifr_name));
+  request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
+
+  char *myaddr = strdup(addr);
+  char *pch = NULL;
+  pch = strchr(myaddr, '/');
+  if (pch) {
+    *pch = '\0';
+  }
+
+  struct sockaddr_in *sin = (struct sockaddr_in *)&request.ifr_addr;
+  sin->sin_family = AF_INET;
+  sin->sin_addr.s_addr = inet_addr(myaddr);
+  if (ioctl(sock, SIOCSIFADDR, &request) < 0) {
+    RLOGE("%s: failed.", __func__);
+  }
+
+  close(sock);
+  free(myaddr);
+  RLOGD("%s %d done.", __func__, __LINE__);
+}
+#endif
+
+enum InterfaceState {
+    kInterfaceUp,
+    kInterfaceDown,
+};
+
+static RIL_Errno setInterfaceState(const char* interfaceName,
+                                   enum InterfaceState state) {
+    struct ifreq request;
+    int status = 0;
+    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+    if (sock == -1) {
+        RLOGE("Failed to open interface socket: %s (%d)",
+              strerror(errno), errno);
+        return RIL_E_GENERIC_FAILURE;
+    }
+
+    memset(&request, 0, sizeof(request));
+    strncpy(request.ifr_name, interfaceName, sizeof(request.ifr_name));
+    request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
+    status = ioctl(sock, SIOCGIFFLAGS, &request);
+    if (status != 0) {
+        RLOGE("Failed to get interface flags for %s: %s (%d)",
+              interfaceName, strerror(errno), errno);
+        close(sock);
+        return RIL_E_RADIO_NOT_AVAILABLE;
+    }
+
+    bool isUp = (request.ifr_flags & IFF_UP);
+    if ((state == kInterfaceUp && isUp) || (state == kInterfaceDown && !isUp)) {
+        // Interface already in desired state
+        close(sock);
+        return RIL_E_SUCCESS;
+    }
+
+    // Simply toggle the flag since we know it's the opposite of what we want
+    request.ifr_flags ^= IFF_UP;
+
+    status = ioctl(sock, SIOCSIFFLAGS, &request);
+    if (status != 0) {
+        RLOGE("Failed to set interface flags for %s: %s (%d)",
+              interfaceName, strerror(errno), errno);
+        close(sock);
+        return RIL_E_GENERIC_FAILURE;
+    }
+
+    close(sock);
+    return RIL_E_SUCCESS;
+}
+
+/** do post-AT+CFUN=1 initialization */
+static void onRadioPowerOn()
+{
+#ifdef USE_TI_COMMANDS
+    /*  Must be after CFUN=1 */
+    /*  TI specific -- notifications for CPHS things such */
+    /*  as CPHS message waiting indicator */
+
+    at_send_command("AT%CPHS=1", NULL);
+
+    /*  TI specific -- enable NITZ unsol notifs */
+    at_send_command("AT%CTZV=1", NULL);
+#endif
+
+    pollSIMState(NULL);
+}
+
+/** do post- SIM ready initialization */
+static void onSIMReady()
+{
+    at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
+    /*
+     * Always send SMS messages directly to the TE
+     *
+     * mode = 1 // discard when link is reserved (link should never be
+     *             reserved)
+     * mt = 2   // most messages routed to TE
+     * bm = 2   // new cell BM's routed to TE
+     * ds = 1   // Status reports routed to TE
+     * bfr = 1  // flush buffer
+     */
+    at_send_command("AT+CNMI=1,2,2,1,1", NULL);
+}
+
+static void requestRadioPower(void *data, size_t datalen __unused, RIL_Token t)
+{
+    int onOff;
+
+    int err;
+    ATResponse *p_response = NULL;
+
+    assert (datalen >= sizeof(int *));
+    onOff = ((int *)data)[0];
+
+    if (onOff == 0 && sState != RADIO_STATE_OFF) {
+        err = at_send_command("AT+CFUN=0", &p_response);
+        if (err < 0 || p_response->success == 0) goto error;
+        setRadioState(RADIO_STATE_OFF);
+    } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
+        err = at_send_command("AT+CFUN=1", &p_response);
+        if (err < 0|| p_response->success == 0) {
+            // Some stacks return an error when there is no SIM,
+            // but they really turn the RF portion on
+            // So, if we get an error, let's check to see if it
+            // turned on anyway
+
+            if (isRadioOn() != 1) {
+                goto error;
+            }
+        }
+        setRadioState(RADIO_STATE_ON);
+    }
+
+    at_response_free(p_response);
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    return;
+error:
+    at_response_free(p_response);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void requestShutdown(RIL_Token t)
+{
+    int onOff;
+
+    int err;
+    ATResponse *p_response = NULL;
+
+    if (sState != RADIO_STATE_OFF) {
+        err = at_send_command("AT+CFUN=0", &p_response);
+        setRadioState(RADIO_STATE_UNAVAILABLE);
+    }
+
+    at_response_free(p_response);
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    return;
+}
+
+static void requestOrSendDataCallList(int cid, RIL_Token *t);
+
+static void onDataCallListChanged(void *param __unused)
+{
+    requestOrSendDataCallList(-1, NULL);
+}
+
+static void requestDataCallList(void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    requestOrSendDataCallList(-1, &t);
+}
+
+// Hang up, reject, conference, call waiting
+static void requestCallSelection(
+                void *data __unused, size_t datalen __unused, RIL_Token t, int request)
+{
+    // 3GPP 22.030 6.5.5
+    static char hangupWaiting[]    = "AT+CHLD=0";
+    static char hangupForeground[] = "AT+CHLD=1";
+    static char switchWaiting[]    = "AT+CHLD=2";
+    static char conference[]       = "AT+CHLD=3";
+    static char reject[]           = "ATH";
+
+    char* atCommand;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+        return;
+    }
+
+    switch(request) {
+        case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
+            // "Releases all held calls or sets User Determined User Busy
+            //  (UDUB) for a waiting call."
+            atCommand = hangupWaiting;
+            break;
+        case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
+            // "Releases all active calls (if any exist) and accepts
+            //  the other (held or waiting) call."
+            atCommand = hangupForeground;
+            break;
+        case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
+            // "Places all active calls (if any exist) on hold and accepts
+            //  the other (held or waiting) call."
+            atCommand = switchWaiting;
+#ifdef WORKAROUND_ERRONEOUS_ANSWER
+            s_expectAnswer = 1;
+#endif /* WORKAROUND_ERRONEOUS_ANSWER */
+            break;
+        case RIL_REQUEST_CONFERENCE:
+            // "Adds a held call to the conversation"
+            atCommand = conference;
+            break;
+        case RIL_REQUEST_UDUB:
+            // User determined user busy (reject)
+            atCommand = reject;
+            break;
+        default:
+            assert(0);
+    }
+    at_send_command(atCommand, NULL);
+    // Success or failure is ignored by the upper layer here.
+    // It will call GET_CURRENT_CALLS and determine success that way.
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static const char* getRadioInterfaceName()
+{
+    if (isInEmulator()) {
+        return EMULATOR_RADIO_INTERFACE;
+    }
+    return PPP_TTY_PATH_ETH0;
+}
+
+static void requestOrSendDataCallList(int cid, RIL_Token *t)
+{
+    ATResponse *p_response = NULL;
+    ATLine *p_cur = NULL;
+    int err = -1;
+    int n = 0;
+    char *out = NULL;
+    char propValue[PROP_VALUE_MAX] = {0};
+    const char* radioInterfaceName = getRadioInterfaceName();
+
+    err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
+    if (err != 0 || p_response->success == 0) {
+        if (t != NULL)
+            RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        else
+            RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
+                                      NULL, 0);
+        return;
+    }
+
+    for (p_cur = p_response->p_intermediates; p_cur != NULL;
+         p_cur = p_cur->p_next)
+        n++;
+
+    RIL_Data_Call_Response_v11 *responses =
+        alloca(n * sizeof(RIL_Data_Call_Response_v11));
+
+    int i;
+    for (i = 0; i < n; i++) {
+        responses[i].status = -1;
+        responses[i].suggestedRetryTime = -1;
+        responses[i].cid = -1;
+        responses[i].active = -1;
+        responses[i].type = "";
+        responses[i].ifname = "";
+        responses[i].addresses = "";
+        responses[i].dnses = "";
+        responses[i].gateways = "";
+        responses[i].pcscf = "";
+        responses[i].mtu = 0;
+    }
+
+    RIL_Data_Call_Response_v11 *response = responses;
+    for (p_cur = p_response->p_intermediates; p_cur != NULL;
+         p_cur = p_cur->p_next) {
+        char *line = p_cur->line;
+
+        err = at_tok_start(&line);
+        if (err < 0)
+            goto error;
+
+        err = at_tok_nextint(&line, &response->cid);
+        if (err < 0)
+            goto error;
+
+        err = at_tok_nextint(&line, &response->active);
+        if (err < 0)
+            goto error;
+
+        response++;
+    }
+
+    at_response_free(p_response);
+
+    err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
+    if (err != 0 || p_response->success == 0) {
+        if (t != NULL)
+            RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        else
+            RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
+                                      NULL, 0);
+        return;
+    }
+
+    for (p_cur = p_response->p_intermediates; p_cur != NULL;
+         p_cur = p_cur->p_next) {
+        char *line = p_cur->line;
+        int ncid;
+
+        err = at_tok_start(&line);
+        if (err < 0)
+            goto error;
+
+        err = at_tok_nextint(&line, &ncid);
+        if (err < 0)
+            goto error;
+
+        if (cid != ncid)
+            continue;
+
+        i = ncid - 1;
+        // Assume no error
+        responses[i].status = 0;
+
+        // type
+        err = at_tok_nextstr(&line, &out);
+        if (err < 0)
+            goto error;
+
+        int type_size = strlen(out) + 1;
+        responses[i].type = alloca(type_size);
+        strlcpy(responses[i].type, out, type_size);
+
+        // APN ignored for v5
+        err = at_tok_nextstr(&line, &out);
+        if (err < 0)
+            goto error;
+
+        int ifname_size = strlen(radioInterfaceName) + 1;
+        responses[i].ifname = alloca(ifname_size);
+        strlcpy(responses[i].ifname, radioInterfaceName, ifname_size);
+
+        err = at_tok_nextstr(&line, &out);
+        if (err < 0)
+            goto error;
+
+        int addresses_size = strlen(out) + 1;
+        responses[i].addresses = alloca(addresses_size);
+        strlcpy(responses[i].addresses, out, addresses_size);
+#ifdef CUTTLEFISH_ENABLE
+        set_Ip_Addr(responses[i].addresses, radioInterfaceName);
+#endif
+
+        if (isInEmulator()) {
+            /* We are in the emulator - the dns servers are listed
+                * by the following system properties, setup in
+                * /system/etc/init.goldfish.sh:
+                *  - vendor.net.eth0.dns1
+                *  - vendor.net.eth0.dns2
+                *  - vendor.net.eth0.dns3
+                *  - vendor.net.eth0.dns4
+                */
+            const int   dnslist_sz = 128;
+            char*       dnslist = alloca(dnslist_sz);
+            const char* separator = "";
+            int         nn;
+
+            dnslist[0] = 0;
+            for (nn = 1; nn <= 4; nn++) {
+                /* Probe vendor.net.eth0.dns<n> */
+                char  propName[PROP_NAME_MAX];
+                char  propValue[PROP_VALUE_MAX];
+
+                snprintf(propName, sizeof propName, "vendor.net.eth0.dns%d", nn);
+
+                /* Ignore if undefined */
+                if (property_get(propName, propValue, "") <= 0) {
+                    continue;
+                }
+
+                /* Append the DNS IP address */
+                strlcat(dnslist, separator, dnslist_sz);
+                strlcat(dnslist, propValue, dnslist_sz);
+                separator = " ";
+            }
+            responses[i].dnses = dnslist;
+
+            if (property_get("vendor.net.eth0.gw", propValue, "") > 0) {
+                responses[i].gateways = propValue;
+            } else {
+                responses[i].gateways = "";
+            }
+            responses[i].mtu = DEFAULT_MTU;
+        } else {
+            /* I don't know where we are, so use the public Google DNS
+                * servers by default and no gateway.
+                */
+            responses[i].dnses = "8.8.8.8 8.8.4.4";
+            responses[i].gateways = "";
+        }
+    }
+
+    at_response_free(p_response);
+    p_response = NULL;
+
+    char cmd[64] = {0};
+    snprintf(cmd, sizeof(cmd), "AT+CGCONTRDP=%d", cid);
+    err = at_send_command_singleline(cmd, "+CGCONTRDP:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    int skip = 0;
+    char *sskip = NULL;
+    char *input = p_response->p_intermediates->line;
+
+    int ncid = -1;
+    err = at_tok_start(&input);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&input, &ncid);  // cid
+    if (err < 0) goto error;
+
+    if (cid != ncid) goto error;
+
+    i = ncid - 1;
+
+    err = at_tok_nextint(&input, &skip);  // bearer_id
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&input, &sskip);  // apn
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&input, &sskip);  // local_addr_and_subnet_mask
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&input, &responses[i].gateways);  // gw_addr
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&input, &responses[i].dnses);  // dns_prim_addr
+    if (err < 0) goto error;
+
+    if (t != NULL)
+        RIL_onRequestComplete(*t, RIL_E_SUCCESS, &responses[i],
+                               sizeof(RIL_Data_Call_Response_v11));
+    else
+        RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
+                                  responses,
+                                  n * sizeof(RIL_Data_Call_Response_v11));
+
+    at_response_free(p_response);
+    return;
+
+error:
+    if (t != NULL)
+        RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    else
+        RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
+                                  NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestQueryNetworkSelectionMode(
+                void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    ATResponse *p_response = NULL;
+    int response = 0;
+    char *line;
+
+    err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
+
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+
+    err = at_tok_start(&line);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    err = at_tok_nextint(&line, &response);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
+    at_response_free(p_response);
+    return;
+error:
+    at_response_free(p_response);
+    RLOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void sendCallStateChanged(void *param __unused)
+{
+    RIL_onUnsolicitedResponse (
+        RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
+        NULL, 0);
+}
+
+static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    ATResponse *p_response;
+    ATLine *p_cur;
+    int countCalls;
+    int countValidCalls;
+    RIL_Call *p_calls;
+    RIL_Call **pp_calls;
+    int i;
+    int needRepoll = 0;
+
+#ifdef WORKAROUND_ERRONEOUS_ANSWER
+    int prevIncomingOrWaitingLine;
+
+    prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
+    s_incomingOrWaitingLine = -1;
+#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
+
+    err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
+
+    if (err != 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+
+    /* count the calls */
+    for (countCalls = 0, p_cur = p_response->p_intermediates
+            ; p_cur != NULL
+            ; p_cur = p_cur->p_next
+    ) {
+        countCalls++;
+    }
+
+    /* yes, there's an array of pointers and then an array of structures */
+
+    pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
+    p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
+    memset (p_calls, 0, countCalls * sizeof(RIL_Call));
+
+    /* init the pointer array */
+    for(i = 0; i < countCalls ; i++) {
+        pp_calls[i] = &(p_calls[i]);
+    }
+
+    for (countValidCalls = 0, p_cur = p_response->p_intermediates
+            ; p_cur != NULL
+            ; p_cur = p_cur->p_next
+    ) {
+        err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
+
+        if (err != 0) {
+            continue;
+        }
+
+#ifdef WORKAROUND_ERRONEOUS_ANSWER
+        if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
+            || p_calls[countValidCalls].state == RIL_CALL_WAITING
+        ) {
+            s_incomingOrWaitingLine = p_calls[countValidCalls].index;
+        }
+#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
+
+        if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
+            && p_calls[countValidCalls].state != RIL_CALL_HOLDING
+        ) {
+            needRepoll = 1;
+        }
+
+        countValidCalls++;
+    }
+
+#ifdef WORKAROUND_ERRONEOUS_ANSWER
+    // Basically:
+    // A call was incoming or waiting
+    // Now it's marked as active
+    // But we never answered it
+    //
+    // This is probably a bug, and the call will probably
+    // disappear from the call list in the next poll
+    if (prevIncomingOrWaitingLine >= 0
+            && s_incomingOrWaitingLine < 0
+            && s_expectAnswer == 0
+    ) {
+        for (i = 0; i < countValidCalls ; i++) {
+
+            if (p_calls[i].index == prevIncomingOrWaitingLine
+                    && p_calls[i].state == RIL_CALL_ACTIVE
+                    && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
+            ) {
+                RLOGI(
+                    "Hit WORKAROUND_ERRONOUS_ANSWER case."
+                    " Repoll count: %d\n", s_repollCallsCount);
+                s_repollCallsCount++;
+                goto error;
+            }
+        }
+    }
+
+    s_expectAnswer = 0;
+    s_repollCallsCount = 0;
+#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
+            countValidCalls * sizeof (RIL_Call *));
+
+    at_response_free(p_response);
+
+#ifdef POLL_CALL_STATE
+    if (countValidCalls) {  // We don't seem to get a "NO CARRIER" message from
+                            // smd, so we're forced to poll until the call ends.
+#else
+    if (needRepoll) {
+#endif
+        RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
+    }
+
+    return;
+#ifdef WORKAROUND_ERRONEOUS_ANSWER
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+#endif
+}
+
+static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
+{
+    RIL_Dial *p_dial;
+    char *cmd;
+    const char *clir;
+    int ret;
+
+    p_dial = (RIL_Dial *)data;
+
+    switch (p_dial->clir) {
+        case 1: clir = "I"; break;  /*invocation*/
+        case 2: clir = "i"; break;  /*suppression*/
+        default:
+        case 0: clir = ""; break;   /*subscription default*/
+    }
+
+    asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
+
+    ret = at_send_command(cmd, NULL);
+
+    free(cmd);
+
+    /* success or failure is ignored by the upper layer here.
+       it will call GET_CURRENT_CALLS and determine success that way */
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void requestWriteSmsToSim(void *data, size_t datalen __unused, RIL_Token t)
+{
+    RIL_SMS_WriteArgs *p_args;
+    char *cmd;
+    int length;
+    int err;
+    ATResponse *p_response = NULL;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
+        return;
+    }
+
+    p_args = (RIL_SMS_WriteArgs *)data;
+
+    length = strlen(p_args->pdu)/2;
+    asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
+
+    err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
+
+    if (err != 0 || p_response->success == 0) goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    at_response_free(p_response);
+
+    return;
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestHangup(void *data, size_t datalen __unused, RIL_Token t)
+{
+    int *p_line;
+
+    int ret;
+    char *cmd;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
+        return;
+    }
+    p_line = (int *)data;
+
+    // 3GPP 22.030 6.5.5
+    // "Releases a specific active call X"
+    asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
+
+    ret = at_send_command(cmd, NULL);
+
+    free(cmd);
+
+    /* success or failure is ignored by the upper layer here.
+       it will call GET_CURRENT_CALLS and determine success that way */
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void requestSignalStrength(void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    ATResponse *p_response = NULL;
+    int err;
+    char *line;
+    int count = 0;
+    // Accept a response that is at least v6, and up to v12
+    int minNumOfElements=sizeof(RIL_SignalStrength_v6)/sizeof(int);
+    int maxNumOfElements=sizeof(RIL_SignalStrength_v12)/sizeof(int);
+    int response[maxNumOfElements];
+
+    memset(response, 0, sizeof(response));
+
+    err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
+
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    for (count = 0; count < maxNumOfElements; count++) {
+        err = at_tok_nextint(&line, &(response[count]));
+        if (err < 0 && count < minNumOfElements) goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+
+    at_response_free(p_response);
+    return;
+
+error:
+    RLOGE("requestSignalStrength must never return an error when radio is on");
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+/**
+ * networkModePossible. Decides whether the network mode is appropriate for the
+ * specified modem
+ */
+static int networkModePossible(ModemInfo *mdm, int nm)
+{
+    const int asize = sizeof(net2modem) / sizeof(net2modem[0]);
+    if (nm >= asize || nm < 0) {
+        RLOGW("%s %d: invalid net2modem index: %d", __func__, __LINE__, nm);
+        return 0;
+    }
+    if ((net2modem[nm] & mdm->supportedTechs) == net2modem[nm]) {
+       return 1;
+    }
+    return 0;
+}
+
+int getPreferredFromBitmap(int value, int *index) {
+    for (unsigned int i = 0; i < sizeof(s_networkMask) / sizeof(NetworkTypeBitmap); i++) {
+        if (s_networkMask[i].bitmap == value) {
+            if (index) *index = i;
+            return s_networkMask[i].type;
+        }
+    }
+    // set default value here, since there is no match found
+    // ref.
+    //{LTE | GSM | WCDMA,               MDM_LTE | MDM_GSM | MDM_WCDMA},             // 9 - LTE, GSM/WCDMA
+    //
+    const int DEFAULT_PREFERRED_INDEX = 9;
+    const int DEFAULT_PREFERRED_BITMAP = MDM_LTE | MDM_GSM | MDM_WCDMA;
+    assert(s_networkMask[DEFAULT_PREFERRED_INDEX] == DEFAULT_PREFERRED_BITMAP);
+    if (index) {
+        *index = DEFAULT_PREFERRED_INDEX;
+    }
+    RLOGD("getPreferredFromBitmap %d not match", value);
+    return  DEFAULT_PREFERRED_BITMAP;
+}
+
+unsigned getBitmapFromPreferred(int value) {
+    for (unsigned int i = 0; i < sizeof(s_networkMask) / sizeof(NetworkTypeBitmap); i++) {
+        if (s_networkMask[i].type == value) {
+            return s_networkMask[i].bitmap;
+        }
+    }
+    RLOGD("getBitmapFromPreferred %d not match", value);
+    return  LTE | GSM | WCDMA;
+}
+
+static void requestSetPreferredNetworkType(int request, void *data,
+                                           size_t datalen __unused, RIL_Token t )
+{
+    ATResponse *p_response = NULL;
+    char *cmd = NULL;
+    int value = *(int *)data;
+    int index = value;
+    int current, old;
+    int err;
+    int32_t preferred;
+
+    if (request == RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE) {
+        preferred = net2pmask[value];
+    } else {
+        preferred = getPreferredFromBitmap(value, &index);
+    }
+    RLOGD("requestSetPreferredNetworkType: current: %x. New: %x", PREFERRED_NETWORK(sMdmInfo), preferred);
+
+    if (!networkModePossible(sMdmInfo, index)) {
+        RIL_onRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
+        return;
+    }
+
+    if (query_ctec(sMdmInfo, &current, NULL) < 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+    old = PREFERRED_NETWORK(sMdmInfo);
+    RLOGD("old != preferred: %d", old != preferred);
+    if (old != preferred) {
+        asprintf(&cmd, "AT+CTEC=%d,\"%x\"", current, preferred);
+        RLOGD("Sending command: <%s>", cmd);
+        err = at_send_command_singleline(cmd, "+CTEC:", &p_response);
+        free(cmd);
+        if (err || !p_response->success) {
+            RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            return;
+        }
+        PREFERRED_NETWORK(sMdmInfo) = value;
+        if (!strstr( p_response->p_intermediates->line, "DONE") ) {
+            int current;
+            int res = parse_technology_response(p_response->p_intermediates->line, &current, NULL);
+            switch (res) {
+                case -1: // Error or unable to parse
+                    break;
+                case 1: // Only able to parse current
+                case 0: // Both current and preferred were parsed
+                    setRadioTechnology(sMdmInfo, current);
+                    break;
+            }
+        }
+    }
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void requestGetPreferredNetworkType(int request __unused, void *data __unused,
+                                   size_t datalen __unused, RIL_Token t)
+{
+    int preferred;
+    unsigned i;
+
+    switch ( query_ctec(sMdmInfo, NULL, &preferred) ) {
+        case -1: // Error or unable to parse
+        case 1: // Only able to parse current
+            RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            break;
+        case 0: // Both current and preferred were parsed
+            for ( i = 0 ; i < sizeof(net2pmask) / sizeof(int32_t) ; i++ ) {
+                if (preferred == net2pmask[i]) {
+                    goto done;
+                }
+            }
+            RLOGE("Unknown preferred mode received from modem: %d", preferred);
+            RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            return;
+    }
+done:
+    if (request == RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP ||
+            request == RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP) {
+        i = getBitmapFromPreferred(preferred);
+    }
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &i, sizeof(i));
+}
+
+static void requestCdmaPrlVersion(int request __unused, void *data __unused,
+                                   size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    char * responseStr;
+    ATResponse *p_response = NULL;
+    const char *cmd;
+    char *line;
+
+    err = at_send_command_singleline("AT+WPRL?", "+WPRL:", &p_response);
+    if (err < 0 || !p_response->success) goto error;
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+    err = at_tok_nextstr(&line, &responseStr);
+    if (err < 0 || !responseStr) goto error;
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, strlen(responseStr));
+    at_response_free(p_response);
+    return;
+error:
+    at_response_free(p_response);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void requestCdmaBaseBandVersion(int request __unused, void *data __unused,
+                                   size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    char * responseStr;
+    ATResponse *p_response = NULL;
+    const char *cmd;
+    const char *prefix;
+    char *line, *p;
+    int commas;
+    int skip;
+    int count = 4;
+
+    // Fixed values. TODO: query modem
+    responseStr = strdup("1.0.0.0");
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, sizeof(responseStr));
+    free(responseStr);
+}
+
+static void requestDeviceIdentity(int request __unused, void *data __unused,
+                                        size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    int response[4];
+    char * responseStr[4];
+    ATResponse *p_response = NULL;
+    const char *cmd;
+    const char *prefix;
+    char *line, *p;
+    int commas;
+    int skip;
+    int count = 4;
+
+    // Fixed values. TODO: Query modem
+    responseStr[0] = "----";
+    responseStr[1] = "----";
+    responseStr[2] = "77777777";
+    responseStr[3] = ""; // default empty for non-CDMA
+
+    err = at_send_command_numeric("AT+CGSN", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    } else {
+        if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
+            responseStr[3] = p_response->p_intermediates->line;
+        } else {
+            responseStr[0] = p_response->p_intermediates->line;
+        }
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
+    at_response_free(p_response);
+}
+
+static void requestCdmaGetSubscriptionSource(int request __unused, void *data,
+                                        size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    int *ss = (int *)data;
+    ATResponse *p_response = NULL;
+    char *cmd = NULL;
+    char *line = NULL;
+    int response;
+
+    asprintf(&cmd, "AT+CCSS?");
+    if (!cmd) goto error;
+
+    err = at_send_command_singleline(cmd, "+CCSS:", &p_response);
+    if (err < 0 || !p_response->success)
+        goto error;
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &response);
+    free(cmd);
+    cmd = NULL;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+
+    return;
+error:
+    free(cmd);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void requestCdmaSetSubscriptionSource(int request __unused, void *data,
+                                        size_t datalen, RIL_Token t)
+{
+    int err;
+    int *ss = (int *)data;
+    ATResponse *p_response = NULL;
+    char *cmd = NULL;
+
+    if (!ss || !datalen) {
+        RLOGE("RIL_REQUEST_CDMA_SET_SUBSCRIPTION without data!");
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+    asprintf(&cmd, "AT+CCSS=%d", ss[0]);
+    if (!cmd) goto error;
+
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || !p_response->success)
+        goto error;
+    free(cmd);
+    cmd = NULL;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+    RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, ss, sizeof(ss[0]));
+
+    return;
+error:
+    free(cmd);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void requestCdmaSubscription(int request __unused, void *data __unused,
+                                        size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    int response[5];
+    char * responseStr[5];
+    ATResponse *p_response = NULL;
+    const char *cmd;
+    const char *prefix;
+    char *line, *p;
+    int commas;
+    int skip;
+    int count = 5;
+
+    // Fixed values. TODO: Query modem
+    responseStr[0] = "8587777777"; // MDN
+    responseStr[1] = "1"; // SID
+    responseStr[2] = "1"; // NID
+    responseStr[3] = "8587777777"; // MIN
+    responseStr[4] = "1"; // PRL Version
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
+}
+
+static void requestCdmaGetRoamingPreference(int request __unused, void *data __unused,
+                                                 size_t datalen __unused, RIL_Token t)
+{
+    int roaming_pref = -1;
+    ATResponse *p_response = NULL;
+    char *line;
+    int res;
+
+    res = at_send_command_singleline("AT+WRMP?", "+WRMP:", &p_response);
+    if (res < 0 || !p_response->success) {
+        goto error;
+    }
+    line = p_response->p_intermediates->line;
+
+    res = at_tok_start(&line);
+    if (res < 0) goto error;
+
+    res = at_tok_nextint(&line, &roaming_pref);
+    if (res < 0) goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &roaming_pref, sizeof(roaming_pref));
+    return;
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void requestCdmaSetRoamingPreference(int request __unused, void *data,
+                                                 size_t datalen __unused, RIL_Token t)
+{
+    int *pref = (int *)data;
+    ATResponse *p_response = NULL;
+    char *line;
+    int res;
+    char *cmd = NULL;
+
+    asprintf(&cmd, "AT+WRMP=%d", *pref);
+    if (cmd == NULL) goto error;
+
+    res = at_send_command(cmd, &p_response);
+    if (res < 0 || !p_response->success)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    free(cmd);
+    return;
+error:
+    free(cmd);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static int parseRegistrationState(char *str, int *type, int *items, int **response)
+{
+    int err;
+    char *line = str, *p;
+    int *resp = NULL;
+    int skip;
+    int count = 3;
+    int commas;
+
+    RLOGD("parseRegistrationState. Parsing: %s",str);
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    /* Ok you have to be careful here
+     * The solicited version of the CREG response is
+     * +CREG: n, stat, [lac, cid]
+     * and the unsolicited version is
+     * +CREG: stat, [lac, cid]
+     * The <n> parameter is basically "is unsolicited creg on?"
+     * which it should always be
+     *
+     * Now we should normally get the solicited version here,
+     * but the unsolicited version could have snuck in
+     * so we have to handle both
+     *
+     * Also since the LAC and CID are only reported when registered,
+     * we can have 1, 2, 3, or 4 arguments here
+     *
+     * finally, a +CGREG: answer may have a fifth value that corresponds
+     * to the network type, as in;
+     *
+     *   +CGREG: n, stat [,lac, cid [,networkType]]
+     */
+
+    /* count number of commas */
+    commas = 0;
+    for (p = line ; *p != '\0' ;p++) {
+        if (*p == ',') commas++;
+    }
+
+    resp = (int *)calloc(commas + 1, sizeof(int));
+    if (!resp) goto error;
+    switch (commas) {
+        case 0: /* +CREG: <stat> */
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            resp[1] = -1;
+            resp[2] = -1;
+        break;
+
+        case 1: /* +CREG: <n>, <stat> */
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            resp[1] = -1;
+            resp[2] = -1;
+            if (err < 0) goto error;
+        break;
+
+        case 2: /* +CREG: <stat>, <lac>, <cid> */
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[1]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[2]);
+            if (err < 0) goto error;
+        break;
+        case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[1]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[2]);
+            if (err < 0) goto error;
+        break;
+        /* special case for CGREG, there is a fourth parameter
+         * that is the network type (unknown/gprs/edge/umts)
+         */
+        case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[1]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[2]);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[3]);
+            if (err < 0) goto error;
+            count = 4;
+        break;
+        default:
+            goto error;
+    }
+    s_lac = resp[1];
+    s_cid = resp[2];
+    if (response)
+        *response = resp;
+    if (items)
+        *items = commas + 1;
+    if (type)
+        *type = techFromModemType(TECH(sMdmInfo));
+    return 0;
+error:
+    free(resp);
+    return -1;
+}
+
+static int mapNetworkRegistrationResponse(int in_response) {
+    int out_response = 0;
+
+    switch (in_response) {
+        case 0:
+            out_response = RADIO_TECH_GPRS;    /* GPRS */
+            break;
+        case 3:
+            out_response = RADIO_TECH_EDGE;    /* EDGE */
+            break;
+        case 2:
+            out_response = RADIO_TECH_UMTS;    /* TD */
+            break;
+        case 4:
+            out_response = RADIO_TECH_HSDPA;   /* HSDPA */
+            break;
+        case 5:
+            out_response = RADIO_TECH_HSUPA;   /* HSUPA */
+            break;
+        case 6:
+            out_response = RADIO_TECH_HSPA;    /* HSPA */
+            break;
+        case 15:
+            out_response = RADIO_TECH_HSPAP;   /* HSPA+ */
+            break;
+        case 7:
+            out_response = RADIO_TECH_LTE;     /* LTE */
+            break;
+        case 16:
+            out_response = RADIO_TECH_LTE_CA;  /* LTE_CA */
+            break;
+        case 11:  // NR connected to a 5GCN
+        case 12:  // NG-RAN
+        case 13:  // E-UTRA-NR dual connectivity
+            out_response = RADIO_TECH_NR;      /* NR */
+            break;
+        default:
+            out_response = RADIO_TECH_UNKNOWN; /* UNKNOWN */
+            break;
+    }
+    return out_response;
+}
+
+#define REG_STATE_LEN 18
+#define REG_DATA_STATE_LEN 14
+static void requestRegistrationState(int request, void *data __unused,
+                                        size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    int *registration;
+    char **responseStr = NULL;
+    ATResponse *p_response = NULL;
+    const char *cmd;
+    const char *prefix;
+    char *line;
+    int i = 0, j, numElements = 0;
+    int count = 3;
+    int type, startfrom;
+
+    RLOGD("requestRegistrationState");
+    if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
+        cmd = "AT+CREG?";
+        prefix = "+CREG:";
+        numElements = REG_STATE_LEN;
+    } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
+        cmd = "AT+CGREG?";
+        prefix = "+CGREG:";
+        numElements = REG_DATA_STATE_LEN;
+        if (TECH_BIT(sMdmInfo) == MDM_LTE) {
+            cmd = "AT+CEREG?";
+            prefix = "+CEREG:";
+        }
+    } else {
+        assert(0);
+        goto error;
+    }
+
+    err = at_send_command_singleline(cmd, prefix, &p_response);
+
+    if (err < 0 || !p_response->success) goto error;
+
+    line = p_response->p_intermediates->line;
+
+    if (parseRegistrationState(line, &type, &count, &registration)) goto error;
+
+    responseStr = malloc(numElements * sizeof(char *));
+    if (!responseStr) goto error;
+    memset(responseStr, 0, numElements * sizeof(char *));
+    /**
+     * The first '4' bytes for both registration states remain the same.
+     * But if the request is 'DATA_REGISTRATION_STATE',
+     * the 5th and 6th byte(s) are optional.
+     */
+    if (is3gpp2(type) == 1) {
+        RLOGD("registration state type: 3GPP2");
+        // TODO: Query modem
+        startfrom = 3;
+        if(request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
+            asprintf(&responseStr[3], "8");     // EvDo revA
+            asprintf(&responseStr[4], "1");     // BSID
+            asprintf(&responseStr[5], "123");   // Latitude
+            asprintf(&responseStr[6], "222");   // Longitude
+            asprintf(&responseStr[7], "0");     // CSS Indicator
+            asprintf(&responseStr[8], "4");     // SID
+            asprintf(&responseStr[9], "65535"); // NID
+            asprintf(&responseStr[10], "0");    // Roaming indicator
+            asprintf(&responseStr[11], "1");    // System is in PRL
+            asprintf(&responseStr[12], "0");    // Default Roaming indicator
+            asprintf(&responseStr[13], "0");    // Reason for denial
+            asprintf(&responseStr[14], "0");    // Primary Scrambling Code of Current cell
+      } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
+            asprintf(&responseStr[3], "8");   // Available data radio technology
+      }
+    } else { // type == RADIO_TECH_3GPP
+        RLOGD("registration state type: 3GPP");
+        startfrom = 0;
+        asprintf(&responseStr[1], "%x", registration[1]);
+        asprintf(&responseStr[2], "%x", registration[2]);
+        if (count > 3) {
+            asprintf(&responseStr[3], "%d", mapNetworkRegistrationResponse(registration[3]));
+        }
+    }
+    asprintf(&responseStr[0], "%d", registration[0]);
+
+    /**
+     * Optional bytes for DATA_REGISTRATION_STATE request
+     * 4th byte : Registration denial code
+     * 5th byte : The max. number of simultaneous Data Calls
+     */
+    if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
+        // asprintf(&responseStr[4], "3");
+        // asprintf(&responseStr[5], "1");
+        asprintf(&responseStr[11], "%d", s_mcc);
+        asprintf(&responseStr[12], "%d", s_mnc);
+        if (s_mncLength == 2) {
+          asprintf(&responseStr[13], "%03d%02d", s_mcc, s_mnc);
+        } else {
+          asprintf(&responseStr[13], "%03d%03d", s_mcc, s_mnc);
+        }
+    } else {  // Voice
+        asprintf(&responseStr[15], "%d", s_mcc);
+        asprintf(&responseStr[16], "%d", s_mnc);
+        if (s_mncLength == 2) {
+          asprintf(&responseStr[17], "%03d%02d", s_mcc, s_mnc);
+        } else {
+          asprintf(&responseStr[17], "%03d%03d", s_mcc, s_mnc);
+        }
+    }
+
+
+    for (j = startfrom; j < numElements; j++) {
+        if (!responseStr[i]) goto error;
+    }
+    free(registration);
+    registration = NULL;
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, numElements*sizeof(responseStr));
+    for (j = 0; j < numElements; j++ ) {
+        free(responseStr[j]);
+        responseStr[j] = NULL;
+    }
+    free(responseStr);
+    responseStr = NULL;
+    at_response_free(p_response);
+
+    return;
+error:
+    if (responseStr) {
+        for (j = 0; j < numElements; j++) {
+            free(responseStr[j]);
+            responseStr[j] = NULL;
+        }
+        free(responseStr);
+        responseStr = NULL;
+    }
+    RLOGE("requestRegistrationState must never return an error when radio is on");
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestOperator(void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    int i;
+    int skip;
+    ATLine *p_cur;
+    char *response[3];
+
+    memset(response, 0, sizeof(response));
+
+    ATResponse *p_response = NULL;
+
+    err = at_send_command_multiline(
+        "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
+        "+COPS:", &p_response);
+
+    /* we expect 3 lines here:
+     * +COPS: 0,0,"T - Mobile"
+     * +COPS: 0,1,"TMO"
+     * +COPS: 0,2,"310170"
+     */
+
+    if (err != 0) goto error;
+
+    for (i = 0, p_cur = p_response->p_intermediates
+            ; p_cur != NULL
+            ; p_cur = p_cur->p_next, i++
+    ) {
+        char *line = p_cur->line;
+
+        err = at_tok_start(&line);
+        if (err < 0) goto error;
+
+        err = at_tok_nextint(&line, &skip);
+        if (err < 0) goto error;
+
+        // If we're unregistered, we may just get
+        // a "+COPS: 0" response
+        if (!at_tok_hasmore(&line)) {
+            response[i] = NULL;
+            continue;
+        }
+
+        err = at_tok_nextint(&line, &skip);
+        if (err < 0) goto error;
+
+        // a "+COPS: 0, n" response is also possible
+        if (!at_tok_hasmore(&line)) {
+            response[i] = NULL;
+            continue;
+        }
+
+        err = at_tok_nextstr(&line, &(response[i]));
+        if (err < 0) goto error;
+        // Simple assumption that mcc and mnc are 3 digits each
+        int length = strlen(response[i]);
+        if (length == 6) {
+            s_mncLength = 3;
+            if (sscanf(response[i], "%3d%3d", &s_mcc, &s_mnc) != 2) {
+                RLOGE("requestOperator expected mccmnc to be 6 decimal digits");
+            }
+        } else if (length == 5) {
+            s_mncLength = 2;
+            if (sscanf(response[i], "%3d%2d", &s_mcc, &s_mnc) != 2) {
+                RLOGE("requestOperator expected mccmnc to be 5 decimal digits");
+            }
+        }
+    }
+
+    if (i != 3) {
+        /* expect 3 lines exactly */
+        goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+    at_response_free(p_response);
+
+    return;
+error:
+    RLOGE("requestOperator must not return error when radio is on");
+    s_mncLength = 0;
+    s_mcc = 0;
+    s_mnc = 0;
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestCdmaSendSMS(void *data, size_t datalen, RIL_Token t)
+{
+    int err = 1; // Set to go to error:
+    RIL_SMS_Response response;
+    RIL_CDMA_SMS_Message* rcsm;
+
+    memset(&response, 0, sizeof(response));
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
+        return;
+    }
+
+    RLOGD("requestCdmaSendSMS datalen=%zu, sizeof(RIL_CDMA_SMS_Message)=%zu",
+            datalen, sizeof(RIL_CDMA_SMS_Message));
+
+    // verify data content to test marshalling/unmarshalling:
+    rcsm = (RIL_CDMA_SMS_Message*)data;
+    RLOGD("TeleserviceID=%d, bIsServicePresent=%d, \
+            uServicecategory=%d, sAddress.digit_mode=%d, \
+            sAddress.Number_mode=%d, sAddress.number_type=%d, ",
+            rcsm->uTeleserviceID,  rcsm->bIsServicePresent,
+            rcsm->uServicecategory,rcsm->sAddress.digit_mode,
+            rcsm->sAddress.number_mode,rcsm->sAddress.number_type);
+
+    if (err != 0) goto error;
+
+    // Cdma Send SMS implementation will go here:
+    // But it is not implemented yet.
+
+    response.messageRef = 1;
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+    return;
+
+error:
+    // Cdma Send SMS will always cause send retry error.
+    response.messageRef = -1;
+    RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
+}
+
+static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
+{
+    int err;
+    const char *smsc;
+    const char *pdu;
+    int tpLayerLength;
+    char *cmd1, *cmd2;
+    RIL_SMS_Response response;
+    ATResponse *p_response = NULL;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
+        return;
+    }
+
+    memset(&response, 0, sizeof(response));
+    RLOGD("requestSendSMS datalen =%zu", datalen);
+
+    if (s_ims_gsm_fail != 0) goto error;
+    if (s_ims_gsm_retry != 0) goto error2;
+
+    smsc = ((const char **)data)[0];
+    pdu = ((const char **)data)[1];
+
+    tpLayerLength = strlen(pdu)/2;
+
+    // "NULL for default SMSC"
+    if (smsc == NULL) {
+        smsc= "00";
+    }
+
+    asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
+    asprintf(&cmd2, "%s%s", smsc, pdu);
+
+    err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
+
+    free(cmd1);
+    free(cmd2);
+
+    if (err != 0 || p_response->success == 0) goto error;
+
+    int messageRef = 1;
+    char *line = p_response->p_intermediates->line;
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &messageRef);
+    if (err < 0) goto error;
+
+    /* FIXME fill in ackPDU */
+    response.messageRef = messageRef;
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+    at_response_free(p_response);
+
+    return;
+error:
+    response.messageRef = -2;
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
+    at_response_free(p_response);
+    return;
+error2:
+    // send retry error.
+    response.messageRef = -1;
+    RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
+    at_response_free(p_response);
+    return;
+}
+
+static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_IMS_SMS_Message *p_args;
+    RIL_SMS_Response response;
+
+    memset(&response, 0, sizeof(response));
+
+    RLOGD("requestImsSendSMS: datalen=%zu, "
+        "registered=%d, service=%d, format=%d, ims_perm_fail=%d, "
+        "ims_retry=%d, gsm_fail=%d, gsm_retry=%d",
+        datalen, s_ims_registered, s_ims_services, s_ims_format,
+        s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail,
+        s_ims_gsm_retry);
+
+    // figure out if this is gsm/cdma format
+    // then route it to requestSendSMS vs requestCdmaSendSMS respectively
+    p_args = (RIL_IMS_SMS_Message *)data;
+
+    if (0 != s_ims_cause_perm_failure ) goto error;
+
+    // want to fail over ims and this is first request over ims
+    if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2;
+
+    if (RADIO_TECH_3GPP == p_args->tech) {
+        return requestSendSMS(p_args->message.gsmMessage,
+                datalen - sizeof(RIL_RadioTechnologyFamily),
+                t);
+    } else if (RADIO_TECH_3GPP2 == p_args->tech) {
+        return requestCdmaSendSMS(p_args->message.cdmaMessage,
+                datalen - sizeof(RIL_RadioTechnologyFamily),
+                t);
+    } else {
+        RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech);
+    }
+
+error:
+    response.messageRef = -2;
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
+    return;
+
+error2:
+    response.messageRef = -1;
+    RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
+}
+
+/**
+ * Add for CTS test
+ * If open logical channel with AID NULL, this means open logical channel to MF.
+ * If there is P2 value, this P2 value is used for SELECT command.
+ * In addition, if SELECT command returns 61xx, GET RESPONSE command needs to send to get data.
+ */
+static int sendCmdAgainForOpenChannelWithP2( char *data,
+                                        int p2, int *response, int *rspLen) {
+    int len = 0;
+    int err = -1;
+    char *line = NULL;
+    char cmd[64] = {0};
+    RIL_Errno errType = RIL_E_GENERIC_FAILURE;
+    ATResponse *p_response = NULL;
+    RIL_SIM_IO_Response sr;
+
+    memset(&sr, 0, sizeof(sr));
+    sscanf(data, "%2x", &(response[0]));  // response[0] is channel number
+
+    // Send SELECT command to MF
+    snprintf(cmd, sizeof(cmd), "AT+CGLA=%d,14,00A400%02X023F00", response[0],
+             p2);
+
+    err = at_send_command_singleline(cmd, "+CGLA:", &p_response);
+    if (err < 0) goto done;
+    if (p_response->success == 0) {
+        if (!strcmp(p_response->finalResponse, "+CME ERROR: 21") ||
+            !strcmp(p_response->finalResponse, "+CME ERROR: 50")) {
+            errType = RIL_E_GENERIC_FAILURE;
+        }
+        goto done;
+    }
+
+    line = p_response->p_intermediates->line;
+
+    if (at_tok_start(&line) < 0 || at_tok_nextint(&line, &len) < 0 ||
+        at_tok_nextstr(&line, &(sr.simResponse)) < 0) {
+        goto done;
+    }
+
+    sscanf(&(sr.simResponse[len - 4]), "%02x%02x", &(sr.sw1), &(sr.sw2));
+
+    if (sr.sw1 == 0x90 && sr.sw2 == 0x00) {  // 9000 is successful
+        int length = len / 2;
+        for (*rspLen = 1; *rspLen <= length; (*rspLen)++) {
+            sscanf(sr.simResponse, "%02x", &(response[*rspLen]));
+            sr.simResponse += 2;
+        }
+        errType = RIL_E_SUCCESS;
+    } else {  // close channel
+        snprintf(cmd, sizeof(cmd), "AT+CCHC=%d", response[0]);
+        at_send_command( cmd, NULL);
+    }
+
+done:
+    at_response_free(p_response);
+    return errType;
+}
+
+static void requestSimOpenChannel(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(datalen);
+
+    ATResponse *p_response = NULL;
+    int response[260] = {0};
+    int responseLen = 1;
+    int32_t session_id;
+    int err;
+    char cmd[64] = {0};
+    char complex;
+    char *line = NULL;
+    int skip = 0;
+    char *statusWord = NULL;
+    int err_no = RIL_E_GENERIC_FAILURE;
+
+    RIL_OpenChannelParams *params = (RIL_OpenChannelParams *)data;
+
+    // Max length is 16 bytes according to 3GPP spec 27.007 section 8.45
+    if (params->aidPtr == NULL) {
+          err = at_send_command_singleline("AT+CSIM=10,\"0070000001\"", "+CSIM:", &p_response);
+    } else {
+        snprintf(cmd, sizeof(cmd), "AT+CCHO=%s", params->aidPtr);
+        err = at_send_command_numeric(cmd, &p_response);
+    }
+
+    if (err < 0 || p_response == NULL || p_response->success == 0) {
+        ALOGE("Error %d opening logical channel: %d",
+              err, p_response ? p_response->success : 0);
+        goto error;
+    }
+
+    // Ensure integer only by scanning for an extra char but expect one result
+    line = p_response->p_intermediates->line;
+    if (params->aidPtr == NULL) {
+
+        err = at_tok_start(&line);
+        if (err < 0) goto error;
+
+        err = at_tok_nextint(&line, &skip);
+        if (err < 0) goto error;
+
+        err = at_tok_nextstr(&line, &statusWord);
+        if (err < 0) goto error;
+
+        if (params->p2 < 0) {
+            int length = strlen(statusWord) / 2;
+            for (responseLen = 0; responseLen < length; responseLen++) {
+                sscanf(statusWord, "%02x", &(response[responseLen]));
+                statusWord += 2;
+            }
+            err_no = RIL_E_SUCCESS;
+        } else {
+            response[0] = 1;
+            err_no = sendCmdAgainForOpenChannelWithP2(statusWord,
+                                        params->p2, response, &responseLen);
+            if (err_no != RIL_E_SUCCESS) {
+                goto error;
+            }
+        }
+        RIL_onRequestComplete(t, err_no, response, responseLen * sizeof(int));
+        at_response_free(p_response);
+        return;
+    } else {
+        if (sscanf(line, "%" SCNd32 "%c", &session_id, &complex) != 1) {
+           ALOGE("Invalid AT response, expected integer, was '%s'", line);
+           goto error;
+        }
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &session_id, sizeof(session_id));
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, err_no, NULL, 0);
+    at_response_free(p_response);
+    return;
+}
+
+static void requestSimCloseChannel(void *data, size_t datalen, RIL_Token t)
+{
+    ATResponse *p_response = NULL;
+    int32_t session_id;
+    int err;
+    char cmd[32];
+
+    if (data == NULL || datalen != sizeof(session_id)) {
+        ALOGE("Invalid data passed to requestSimCloseChannel");
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+    session_id = ((int32_t *)data)[0];
+    if (session_id == 0) {
+        RIL_onRequestComplete(t, RIL_E_INVALID_ARGUMENTS, NULL, 0);
+        return;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CCHC=%" PRId32, session_id);
+    err = at_send_command_singleline(cmd, "+CCHC", &p_response);
+
+    if (err < 0 || p_response == NULL || p_response->success == 0) {
+        ALOGE("Error %d closing logical channel %d: %d",
+              err, session_id, p_response ? p_response->success : 0);
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        at_response_free(p_response);
+        return;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+    at_response_free(p_response);
+}
+
+static void requestSimTransmitApduChannel(void *data,
+                                          size_t datalen,
+                                          RIL_Token t)
+{
+    ATResponse *p_response = NULL;
+    int err;
+    int len = 0;
+    char *cmd;
+    char *line = NULL;
+    size_t cmd_size;
+    RIL_SIM_IO_Response sr = {0};
+    RIL_SIM_APDU *apdu = (RIL_SIM_APDU *)data;
+
+    if (apdu == NULL || datalen != sizeof(RIL_SIM_APDU)) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+
+    cmd_size = 10 + (apdu->data ? strlen(apdu->data) : 0);
+    asprintf(&cmd, "AT+CGLA=%d,%zu,%02x%02x%02x%02x%02x%s",
+             apdu->sessionid, cmd_size, apdu->cla, apdu->instruction,
+             apdu->p1, apdu->p2, apdu->p3, apdu->data ? apdu->data : "");
+
+    err = at_send_command_singleline(cmd, "+CGLA:", &p_response);
+    free(cmd);
+    if (err < 0 || p_response == NULL || p_response->success == 0) {
+        ALOGE("Error %d transmitting APDU: %d",
+              err, p_response ? p_response->success : 0);
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &len);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &(sr.simResponse));
+    if (err < 0) goto error;
+
+    len = strlen(sr.simResponse);
+    if (len < 4) goto error;
+
+    sscanf(&(sr.simResponse[len - 4]), "%02x%02x", &(sr.sw1), &(sr.sw2));
+    sr.simResponse[len - 4] = '\0';
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestSimAuthentication(int authContext, char* authData, RIL_Token t) {
+    int err = -1, ret = 0;
+    int status = 0;
+    int binSimResponseLen = 0;
+    char *cmd = NULL;
+    char *line = NULL;
+    // Input data
+    int randLen = 0, autnLen = 0;
+    char *rand = NULL, *autn = NULL;
+    // EAP-SIM response data
+    int kcLen = 0, sresLen = 0;
+    char *kc = NULL, *sres = NULL;
+    // EAP-AKA response data
+    int ckLen = 0, ikLen = 0, resAutsLen = 0;
+    char *ck = NULL, *ik = NULL, *resAuts = NULL;
+    unsigned char *binSimResponse = NULL;
+    unsigned char *binAuthData = NULL;
+    unsigned char *hexAuthData = NULL;
+    ATResponse *p_response = NULL;
+    RIL_SIM_IO_Response response;
+
+    memset(&response, 0, sizeof(response));
+    response.sw1 = 0x90;
+    response.sw2 = 0;
+
+    binAuthData  =
+            (unsigned char *)malloc(sizeof(*binAuthData) * strlen(authData));
+    if (binAuthData == NULL) {
+        goto error;
+    }
+    if(base64_decode(authData, binAuthData) <= 0) {
+        RLOGE("base64_decode failed %s %d", __func__, __LINE__);
+        goto error;
+    }
+    hexAuthData =
+            (unsigned char *)malloc(strlen(authData) * 2 + sizeof(char));
+    if (hexAuthData == NULL) {
+        goto error;
+    }
+    memset(hexAuthData, 0, strlen(authData) * 2 + sizeof(char));
+    convertBytesToHexString((char *)binAuthData, strlen(authData), hexAuthData);
+
+    randLen = binAuthData[0];
+    rand = (char *)malloc(sizeof(char) * (randLen * 2 + sizeof(char)));
+    if (rand == NULL) {
+        goto error;
+    }
+    memcpy(rand, hexAuthData + 2, randLen * 2);
+    memcpy(rand + randLen * 2, "\0", 1);
+
+    if (authContext == AUTH_CONTEXT_EAP_AKA) {
+        // There's the autn value to parse as well.
+        autnLen = binAuthData[1 + randLen];
+        autn = (char*)malloc(sizeof(char) * (autnLen * 2 + sizeof(char)));
+        if (autn == NULL) {
+            goto error;
+        }
+        memcpy(autn, hexAuthData + 2 + randLen * 2 + 2, autnLen * 2);
+        memcpy(autn + autnLen * 2, "\0", 1);
+    }
+
+    if (authContext == AUTH_CONTEXT_EAP_SIM) {
+        ret = asprintf(&cmd, "AT^MBAU=\"%s\"", rand);
+    } else {
+        ret = asprintf(&cmd, "AT^MBAU=\"%s,%s\"", rand, autn);
+    }
+    if (ret < 0) {
+        RLOGE("Failed to asprintf");
+        goto error;
+    }
+    err = at_send_command_singleline( cmd, "^MBAU:", &p_response);
+    free(cmd);
+
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &status);
+    if (err < 0) goto error;
+    if (status != SIM_AUTH_RESPONSE_SUCCESS) {
+        goto error;
+    }
+
+    if (authContext == AUTH_CONTEXT_EAP_SIM) {
+        err = at_tok_nextstr(&line, &kc);
+        if (err < 0) goto error;
+        kcLen = strlen(kc);
+
+        err = at_tok_nextstr(&line, &sres);
+        if (err < 0) goto error;
+        sresLen = strlen(sres);
+
+        // sresLen + sres + kcLen + kc + '\0'
+        binSimResponseLen = (kcLen + sresLen) / 2 + 3 * sizeof(char);
+        binSimResponse = (unsigned char*)malloc(binSimResponseLen + sizeof(char));
+        if (binSimResponse == NULL) goto error;
+        memset(binSimResponse, 0, binSimResponseLen);
+        // set sresLen and sres
+        binSimResponse[0] = (sresLen / 2) & 0xFF;
+        uint8_t* tmpBinSimResponse = convertHexStringToBytes(sres, sresLen);
+        snprintf((char*)(binSimResponse + 1), sresLen / 2, "%s", tmpBinSimResponse);
+        free(tmpBinSimResponse);
+        tmpBinSimResponse = NULL;
+        // set kcLen and kc
+        binSimResponse[1 + sresLen / 2] = (kcLen / 2) & 0xFF;
+        tmpBinSimResponse = convertHexStringToBytes(kc, kcLen);
+        snprintf((char*)(binSimResponse + 1 + sresLen / 2 + 1), kcLen / 2, "%s", tmpBinSimResponse);
+        free(tmpBinSimResponse);
+        tmpBinSimResponse = NULL;
+    } else {  // AUTH_CONTEXT_EAP_AKA
+        err = at_tok_nextstr(&line, &ck);
+        if (err < 0) goto error;
+        ckLen = strlen(ck);
+
+        err = at_tok_nextstr(&line, &ik);
+        if (err < 0) goto error;
+        ikLen = strlen(ik);
+
+        err = at_tok_nextstr(&line, &resAuts);
+        if (err < 0) goto error;
+        resAutsLen = strlen(resAuts);
+
+        // 0xDB + ckLen + ck + ikLen + ik + resAutsLen + resAuts + '\0'
+        binSimResponseLen = (ckLen + ikLen + resAutsLen) / 2 + 5 * sizeof(char);
+        binSimResponse = (unsigned char*)malloc(binSimResponseLen + sizeof(char));
+        if (binSimResponse == NULL) goto error;
+        memset(binSimResponse, 0, binSimResponseLen);
+        // The DB prefix indicates successful auth. Not produced by the SIM.
+        binSimResponse[0] = 0xDB;
+        // Set ckLen and ck
+        binSimResponse[1] = (ckLen / 2) & 0xFF;
+        uint8_t* tmpBinSimResponse = convertHexStringToBytes(ck, ckLen);
+        snprintf((char*)(binSimResponse + 2), ckLen / 2 + 1, "%s", tmpBinSimResponse);
+        free(tmpBinSimResponse);
+        tmpBinSimResponse = NULL;
+        // Set ikLen and ik
+        binSimResponse[2 + ckLen / 2] = (ikLen / 2) & 0xFF;
+        tmpBinSimResponse = convertHexStringToBytes(ik, ikLen);
+        snprintf((char*)(binSimResponse + 2 + ckLen / 2 + 1), ikLen / 2 + 1, "%s",
+                 tmpBinSimResponse);
+        free(tmpBinSimResponse);
+        tmpBinSimResponse = NULL;
+        // Set resAutsLen and resAuts
+        binSimResponse[2 + ckLen / 2 + 1 + ikLen / 2] = (resAutsLen / 2) & 0xFF;
+        tmpBinSimResponse = convertHexStringToBytes(resAuts, resAutsLen);
+        snprintf((char*)(binSimResponse + 2 + ckLen / 2 + 1 + ikLen / 2 + 1), resAutsLen / 2 + 1,
+                 "%s", tmpBinSimResponse);
+        free(tmpBinSimResponse);
+        tmpBinSimResponse = NULL;
+    }
+
+    response.simResponse = (char*)malloc(2 * binSimResponseLen + sizeof(char));
+    if (response.simResponse == NULL) goto error;
+    if (NULL == base64_encode(binSimResponse, response.simResponse, binSimResponseLen - 1)) {
+        RLOGE("Failed to call base64_encode %s %d", __func__, __LINE__);
+        goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+    at_response_free(p_response);
+
+    free(binAuthData);
+    free(hexAuthData);
+    free(rand);
+    free(autn);
+    free(response.simResponse);
+    free(binSimResponse);
+    return;
+
+error:
+    free(binAuthData);
+    free(hexAuthData);
+    free(rand);
+    free(autn);
+    free(response.simResponse);
+    free(binSimResponse);
+
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestTransmitApduBasic( void *data, size_t datalen,
+                                      RIL_Token t) {
+    RIL_UNUSED_PARM(datalen);
+
+    int err, len;
+    int instruction = 0;
+    char *cmd = NULL;
+    char *line = NULL;
+    RIL_SIM_APDU *p_args = NULL;
+    ATResponse *p_response = NULL;
+    RIL_SIM_IO_Response sr;
+
+    memset(&sr, 0, sizeof(sr));
+
+    p_args = (RIL_SIM_APDU *)data;
+
+    if ((p_args->data == NULL) || (strlen(p_args->data) == 0)) {
+        if (p_args->p3 < 0) {
+            asprintf(&cmd, "AT+CSIM=%d,\"%02x%02x%02x%02x\"", 8, p_args->cla,
+                    p_args->instruction, p_args->p1, p_args->p2);
+        } else {
+            asprintf(&cmd, "AT+CSIM=%d,\"%02x%02x%02x%02x%02x\"", 10,
+                    p_args->cla, p_args->instruction, p_args->p1, p_args->p2,
+                    p_args->p3);
+        }
+    } else {
+        asprintf(&cmd, "AT+CSIM=%d,\"%02x%02x%02x%02x%02x%s\"",
+                10 + (int)strlen(p_args->data), p_args->cla,
+                p_args->instruction, p_args->p1, p_args->p2, p_args->p3,
+                p_args->data);
+    }
+    err = at_send_command_singleline(cmd, "+CSIM:", &p_response);
+    free(cmd);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &len);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &(sr.simResponse));
+    if (err < 0) goto error;
+
+    sscanf(&(sr.simResponse[len - 4]), "%02x%02x", &(sr.sw1), &(sr.sw2));
+    sr.simResponse[len - 4] = '\0';
+
+    instruction = p_args->instruction;
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static int getPDP() {
+    int ret = -1;
+
+    for (int i = 0; i < MAX_PDP; i++) {
+        if (s_PDP[i].state == PDP_IDLE) {
+            s_PDP[i].state = PDP_BUSY;
+            ret = s_PDP[i].cid;
+            break;
+        }
+    }
+    return ret;
+}
+
+static void putPDP(int cid) {
+    if (cid < 1 || cid > MAX_PDP ) {
+        return;
+    }
+
+    s_PDP[cid - 1].state = PDP_IDLE;
+}
+
+static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
+{
+    const char *apn = NULL;
+    char *cmd = NULL;
+    int err = -1;
+    int cid = -1;
+    ATResponse *p_response = NULL;
+
+    apn = ((const char **)data)[2];
+
+#ifdef USE_TI_COMMANDS
+    // Config for multislot class 10 (probably default anyway eh?)
+    err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
+                        NULL);
+
+    err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
+#endif /* USE_TI_COMMANDS */
+
+    int fd, qmistatus;
+    size_t cur = 0;
+    size_t len;
+    ssize_t written, rlen;
+    char status[32] = {0};
+    int retry = 10;
+    const char *pdp_type;
+
+    RLOGD("requesting data connection to APN '%s'", apn);
+
+    fd = open ("/dev/qmi", O_RDWR);
+    if (fd >= 0) { /* the device doesn't exist on the emulator */
+
+        RLOGD("opened the qmi device\n");
+        asprintf(&cmd, "up:%s", apn);
+        len = strlen(cmd);
+
+        while (cur < len) {
+            do {
+                written = write (fd, cmd + cur, len - cur);
+            } while (written < 0 && errno == EINTR);
+
+            if (written < 0) {
+                RLOGE("### ERROR writing to /dev/qmi");
+                close(fd);
+                goto error;
+            }
+
+            cur += written;
+        }
+
+        // wait for interface to come online
+
+        do {
+            sleep(1);
+            do {
+                rlen = read(fd, status, 31);
+            } while (rlen < 0 && errno == EINTR);
+
+            if (rlen < 0) {
+                RLOGE("### ERROR reading from /dev/qmi");
+                close(fd);
+                goto error;
+            } else {
+                status[rlen] = '\0';
+                RLOGD("### status: %s", status);
+            }
+        } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
+
+        close(fd);
+
+        if (retry == 0) {
+            RLOGE("### Failed to get data connection up\n");
+            goto error;
+        }
+
+        qmistatus = system("netcfg rmnet0 dhcp");
+
+        RLOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
+
+        if (qmistatus < 0) goto error;
+
+    } else {
+        const char* radioInterfaceName = getRadioInterfaceName();
+        if (setInterfaceState(radioInterfaceName, kInterfaceUp) != RIL_E_SUCCESS) {
+            goto error;
+        }
+
+        if (datalen > 6 * sizeof(char *)) {
+            pdp_type = ((const char **)data)[6];
+        } else {
+            pdp_type = "IP";
+        }
+
+        cid = getPDP();
+        if (cid < 1 ) goto error;
+
+        asprintf(&cmd, "AT+CGDCONT=%d,\"%s\",\"%s\",,0,0", cid, pdp_type, apn);
+        //FIXME check for error here
+        err = at_send_command(cmd, NULL);
+        free(cmd);
+
+        // Set required QoS params to default
+        err = at_send_command("AT+CGQREQ=1", NULL);
+
+        // Set minimum QoS params to default
+        err = at_send_command("AT+CGQMIN=1", NULL);
+
+        // packet-domain event reporting
+        err = at_send_command("AT+CGEREP=1,0", NULL);
+
+        // Hangup anything that's happening there now
+        err = at_send_command("AT+CGACT=1,0", NULL);
+
+        // Start data on PDP context 1
+        err = at_send_command("ATD*99***1#", &p_response);
+
+        if (err < 0 || p_response->success == 0) {
+            goto error;
+        }
+    }
+
+    requestOrSendDataCallList(cid, &t);
+
+    at_response_free(p_response);
+
+    return;
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestDeactivateDataCall(void *data, RIL_Token t)
+{
+    const char *p_cid = ((const char **)data)[0];
+    int cid = p_cid ? atoi(p_cid) : -1;
+    RIL_Errno rilErrno = RIL_E_GENERIC_FAILURE;
+    if (cid < 1  || cid > MAX_PDP) {
+        RIL_onRequestComplete(t, rilErrno, NULL, 0);
+        return;
+    }
+
+    const char* radioInterfaceName = getRadioInterfaceName();
+    rilErrno = setInterfaceState(radioInterfaceName, kInterfaceDown);
+    RIL_onRequestComplete(t, rilErrno, NULL, 0);
+    putPDP(cid);
+}
+
+static void requestSMSAcknowledge(void *data, size_t datalen __unused, RIL_Token t)
+{
+    int ackSuccess;
+    int err;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+        return;
+    }
+
+    ackSuccess = ((int *)data)[0];
+
+    if (ackSuccess == 1) {
+        err = at_send_command("AT+CNMA=1", NULL);
+    } else if (ackSuccess == 0)  {
+        err = at_send_command("AT+CNMA=2", NULL);
+    } else {
+        RLOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
+        goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+void convertBytesToHex(uint8_t *bytes, int length, uint8_t *hex_str) {
+    int i;
+    unsigned char tmp;
+
+    if (bytes == NULL || hex_str == NULL) {
+        return;
+    }
+    for (i = 0; i < length; i++) {
+        tmp = (unsigned char)((bytes[i] & 0xf0) >> 4);
+        if (tmp <= 9) {
+            *hex_str = (unsigned char)(tmp + '0');
+        } else {
+            *hex_str = (unsigned char)(tmp + 'A' - 10);
+        }
+        hex_str++;
+        tmp = (unsigned char)(bytes[i] & 0x0f);
+        if (tmp <= 9) {
+            *hex_str = (unsigned char)(tmp + '0');
+        } else {
+            *hex_str = (unsigned char)(tmp + 'A' - 10);
+        }
+        hex_str++;
+    }
+}
+
+#define TYPE_EF                                 4
+#define RESPONSE_EF_SIZE                        15
+#define TYPE_FILE_DES_LEN                       5
+#define RESPONSE_DATA_FILE_DES_FLAG             2
+#define RESPONSE_DATA_FILE_DES_LEN_FLAG         3
+#define RESPONSE_DATA_FILE_TYPE                 6
+#define RESPONSE_DATA_FILE_SIZE_1               2
+#define RESPONSE_DATA_FILE_SIZE_2               3
+#define RESPONSE_DATA_STRUCTURE                 13
+#define RESPONSE_DATA_RECORD_LENGTH             14
+#define RESPONSE_DATA_FILE_RECORD_LEN_1         6
+#define RESPONSE_DATA_FILE_RECORD_LEN_2         7
+#define EF_TYPE_TRANSPARENT                     0x01
+#define EF_TYPE_LINEAR_FIXED                    0x02
+#define EF_TYPE_CYCLIC                          0x06
+#define USIM_DATA_OFFSET_2                      2
+#define USIM_DATA_OFFSET_3                      3
+#define USIM_FILE_DES_TAG                       0x82
+#define USIM_FILE_SIZE_TAG                      0x80
+
+bool convertUsimToSim(uint8_t *byteUSIM, int len, uint8_t *hexSIM) {
+    int desIndex = 0;
+    int sizeIndex = 0;
+    int i = 0;
+    uint8_t byteSIM[RESPONSE_EF_SIZE] = {0};
+    for (i = 0; i < len; i++) {
+        if (byteUSIM[i] == USIM_FILE_DES_TAG) {
+            desIndex = i;
+            break;
+        }
+    }
+    for (i = desIndex; i < len;) {
+        if (byteUSIM[i] == USIM_FILE_SIZE_TAG) {
+            sizeIndex = i;
+            break;
+        } else {
+            i += (byteUSIM[i + 1] + 2);
+        }
+    }
+    byteSIM[RESPONSE_DATA_FILE_SIZE_1] =
+            byteUSIM[sizeIndex + USIM_DATA_OFFSET_2];
+    byteSIM[RESPONSE_DATA_FILE_SIZE_2] =
+            byteUSIM[sizeIndex + USIM_DATA_OFFSET_3];
+    byteSIM[RESPONSE_DATA_FILE_TYPE] = TYPE_EF;
+    if ((byteUSIM[desIndex + RESPONSE_DATA_FILE_DES_FLAG] & 0x07) ==
+        EF_TYPE_TRANSPARENT) {
+        byteSIM[RESPONSE_DATA_STRUCTURE] = 0;
+    } else if ((byteUSIM[desIndex + RESPONSE_DATA_FILE_DES_FLAG] & 0x07) ==
+                EF_TYPE_LINEAR_FIXED) {
+        if (USIM_FILE_DES_TAG != byteUSIM[RESPONSE_DATA_FILE_DES_FLAG]) {
+            RLOGE("USIM_FILE_DES_TAG != ...");
+            goto error;
+        }
+        if (TYPE_FILE_DES_LEN != byteUSIM[RESPONSE_DATA_FILE_DES_LEN_FLAG]) {
+            goto error;
+        }
+        byteSIM[RESPONSE_DATA_STRUCTURE] = 1;
+        byteSIM[RESPONSE_DATA_RECORD_LENGTH] =
+                ((byteUSIM[RESPONSE_DATA_FILE_RECORD_LEN_1] & 0xff) << 8) +
+                (byteUSIM[RESPONSE_DATA_FILE_RECORD_LEN_2] & 0xff);
+    } else if ((byteUSIM[desIndex + RESPONSE_DATA_FILE_DES_FLAG] & 0x07) ==
+                EF_TYPE_CYCLIC) {
+        byteSIM[RESPONSE_DATA_STRUCTURE] = 3;
+        byteSIM[RESPONSE_DATA_RECORD_LENGTH] =
+                ((byteUSIM[RESPONSE_DATA_FILE_RECORD_LEN_1] & 0xff) << 8) +
+                (byteUSIM[RESPONSE_DATA_FILE_RECORD_LEN_2] & 0xff);
+    }
+
+    convertBytesToHex(byteSIM, RESPONSE_EF_SIZE, hexSIM);
+    return true;
+
+error:
+    return false;
+}
+
+static void  requestSIM_IO(void *data, size_t datalen __unused, RIL_Token t)
+{
+    ATResponse *p_response = NULL;
+    RIL_SIM_IO_Response sr;
+    int err;
+    char *cmd = NULL;
+    RIL_SIM_IO_v6 *p_args;
+    char *line;
+
+    /* For Convert USIM to SIM */
+    uint8_t hexSIM[RESPONSE_EF_SIZE * 2 + sizeof(char)] = {0};
+
+    memset(&sr, 0, sizeof(sr));
+
+    p_args = (RIL_SIM_IO_v6 *)data;
+
+    /* FIXME handle pin2 */
+
+    if (p_args->data == NULL) {
+        asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
+                    p_args->command, p_args->fileid,
+                    p_args->p1, p_args->p2, p_args->p3);
+    } else {
+        asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
+                    p_args->command, p_args->fileid,
+                    p_args->p1, p_args->p2, p_args->p3, p_args->data);
+    }
+
+    err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
+
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+
+    err = parseSimResponseLine(line, &sr);
+    if (err < 0) {
+        goto error;
+    }
+    if (sr.simResponse != NULL &&  // Default to be USIM card
+        p_args->command == 192) {  // Get response
+        uint8_t *bytes = convertHexStringToBytes(sr.simResponse, strlen(sr.simResponse));
+        if (bytes == NULL) {
+            RLOGE("Failed to convert sim response to bytes");
+            goto error;
+        }
+        if (bytes[0] != 0x62) {
+            RLOGE("Wrong FCP flag, unable to convert to sim ");
+            free(bytes);
+            goto error;
+        }
+        if (convertUsimToSim(bytes, strlen(sr.simResponse) / 2, hexSIM)) {
+          sr.simResponse = (char *)hexSIM;
+        }
+        free(bytes);
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
+    at_response_free(p_response);
+    free(cmd);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+    free(cmd);
+}
+
+static int getSimlockRemainTimes(const char* type) {
+    int err = -1;
+    int remain_times = -1;
+    char cmd[32] = {0};
+    char *line = NULL;
+    char *lock_type = NULL;
+    ATResponse *p_response = NULL;
+
+    snprintf(cmd, sizeof(cmd), "AT+CPINR=\"%s\"", type);
+    err = at_send_command_multiline(cmd, "+CPINR:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &lock_type);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &remain_times);
+    if (err < 0) goto error;
+
+error:
+    at_response_free(p_response);
+    return remain_times;
+}
+
+static void  requestEnterSimPin(int request, void*  data, size_t  datalen, RIL_Token  t)
+{
+    ATResponse   *p_response = NULL;
+    int           err;
+    int           remaintimes = -1;
+    char*         cmd = NULL;
+    const char**  strings = (const char**)data;;
+
+    if (datalen == sizeof(char*) || datalen == 2 * sizeof(char*)) {
+        asprintf(&cmd, "AT+CPIN=%s", strings[0]);
+    } else
+        goto error;
+
+    err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
+    free(cmd);
+
+    if (err < 0 || p_response->success == 0) {
+error:
+        if (request == RIL_REQUEST_ENTER_SIM_PIN) {
+            remaintimes = getSimlockRemainTimes("SIM PIN");
+        } else if (request == RIL_REQUEST_ENTER_SIM_PIN2) {
+            remaintimes = getSimlockRemainTimes("SIM PIN2");
+        }
+        RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &remaintimes,
+            sizeof(remaintimes));
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void  requestChangeSimPin(int request, void*  data, size_t  datalen, RIL_Token  t)
+{
+    ATResponse   *p_response = NULL;
+    int           err;
+    int           remaintimes = -1;
+    char*         cmd = NULL;
+    const char**  strings = (const char**)data;;
+
+    if (datalen == 2 * sizeof(char*) || datalen == 3 * sizeof(char*)) {
+        asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
+    } else
+        goto error;
+
+    err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
+    free(cmd);
+
+    if (err < 0 || p_response->success == 0) {
+error:
+        if (request == RIL_REQUEST_CHANGE_SIM_PIN) {
+            remaintimes = getSimlockRemainTimes("SIM PIN");
+        } else if (request == RIL_REQUEST_ENTER_SIM_PUK) {
+            remaintimes = getSimlockRemainTimes("SIM PUK");
+        } else if (request == RIL_REQUEST_ENTER_SIM_PUK2) {
+          remaintimes = getSimlockRemainTimes("SIM PUK2");
+        }
+        RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &remaintimes,
+            sizeof(remaintimes));
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestChangeSimPin2(void *data, size_t datalen, RIL_Token t) {
+    int err, ret;
+    int remaintime = -1;
+    char cmd[64] = {0};
+    const char **strings = (const char **)data;
+    ATResponse *p_response = NULL;
+
+    if (datalen != 3 * sizeof(char *)) {
+        goto error;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CPWD=\"P2\",\"%s\",\"%s\"", strings[0],
+             strings[1]);
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || p_response->success == 0) {
+        remaintime = getSimlockRemainTimes("SIM PIN2");
+        goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &remaintime,
+                          sizeof(remaintime));
+    at_response_free(p_response);
+}
+
+static void  requestSendUSSD(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(datalen);
+
+    int err = -1;
+    char cmd[128] = {0};
+    const char *ussdRequest = (char *)(data);
+    ATResponse *p_response = NULL;
+
+    snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\"", ussdRequest);
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestExitEmergencyMode(void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    int err;
+    ATResponse *p_response = NULL;
+
+    err = at_send_command("AT+WSOS=0", &p_response);
+
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static uint64_t s_last_activity_info_query = 0;
+
+static void requestGetActivityInfo(void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    uint64_t curTime = ril_nano_time();
+    RIL_ActivityStatsInfo stats =
+    {
+        0, // sleep_mode_time_ms
+        ((curTime - s_last_activity_info_query) / 1000000) - 1, // idle_mode_time_ms
+        {0, 0, 0, 0, 0}, // tx_mode_time_ms
+        0 // rx_mode_time_ms
+    };
+    s_last_activity_info_query = curTime;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &stats, sizeof(stats));
+}
+
+// TODO: Use all radio types
+static int techFromModemType(int mdmtype)
+{
+    int ret = -1;
+    switch (mdmtype) {
+        case MDM_CDMA:
+            ret = RADIO_TECH_1xRTT;
+            break;
+        case MDM_EVDO:
+            ret = RADIO_TECH_EVDO_A;
+            break;
+        case MDM_GSM:
+            ret = RADIO_TECH_GPRS;
+            break;
+        case MDM_WCDMA:
+            ret = RADIO_TECH_HSPA;
+            break;
+        case MDM_LTE:
+            ret = RADIO_TECH_LTE;
+        case MDM_NR:
+            ret = RADIO_TECH_NR;
+            break;
+    }
+    return ret;
+}
+
+static void requestGetCellInfoList(void *data __unused, size_t datalen __unused, RIL_Token t)
+{
+    uint64_t curTime = ril_nano_time();
+    RIL_CellInfo_v12 ci[1] =
+    {
+        { // ci[0]
+            1, // cellInfoType
+            1, // registered
+            RIL_TIMESTAMP_TYPE_MODEM,
+            curTime - 1000, // Fake some time in the past
+            { // union CellInfo
+                {  // RIL_CellInfoGsm gsm
+                    {  // gsm.cellIdneityGsm
+                        s_mcc, // mcc
+                        s_mnc, // mnc
+                        s_lac, // lac
+                        s_cid, // cid
+                        0, //arfcn unknown
+                        0x1, // Base Station Identity Code set to arbitrarily 1
+                    },
+                    {  // gsm.signalStrengthGsm
+                        10, // signalStrength
+                        0  // bitErrorRate
+                        , INT_MAX // timingAdvance invalid value
+                    }
+                }
+            }
+        }
+    };
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, ci, sizeof(ci));
+}
+
+
+static void requestSetCellInfoListRate(void *data, size_t datalen __unused, RIL_Token t)
+{
+    // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
+    // will be sent.
+    assert (datalen == sizeof(int));
+    s_cell_info_rate_ms = ((int *)data)[0];
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void requestGetHardwareConfig(void *data, size_t datalen, RIL_Token t)
+{
+   // TODO - hook this up with real query/info from radio.
+
+   RIL_HardwareConfig hwCfg;
+
+   RIL_UNUSED_PARM(data);
+   RIL_UNUSED_PARM(datalen);
+
+   hwCfg.type = -1;
+
+   RIL_onRequestComplete(t, RIL_E_SUCCESS, &hwCfg, sizeof(hwCfg));
+}
+
+static void requestGetTtyMode(void *data, size_t datalen, RIL_Token t)
+{
+   int  ttyModeResponse;
+
+   RIL_UNUSED_PARM(data);
+   RIL_UNUSED_PARM(datalen);
+
+   ttyModeResponse = (getSIMStatus() == SIM_READY) ? 1  // TTY Full
+                                                   : 0; // TTY Off
+
+   RIL_onRequestComplete(t, RIL_E_SUCCESS, &ttyModeResponse, sizeof(ttyModeResponse));
+}
+
+static void requestGetRadioCapability(void *data, size_t datalen, RIL_Token t)
+{
+   RIL_RadioCapability radioCapability;
+
+   RIL_UNUSED_PARM(data);
+   RIL_UNUSED_PARM(datalen);
+
+   radioCapability.version = RIL_RADIO_CAPABILITY_VERSION;
+   radioCapability.session = 0;
+   radioCapability.phase   = 0;
+   radioCapability.rat     = NR | LTE | WCDMA | GSM;
+   strncpy(radioCapability.logicalModemUuid, "com.android.modem.simulator", MAX_UUID_LENGTH);
+   radioCapability.status  = RC_STATUS_SUCCESS;
+
+   RIL_onRequestComplete(t, RIL_E_SUCCESS, &radioCapability, sizeof(radioCapability));
+}
+
+static void requestSetRadioCapability(void *data, size_t datalen, RIL_Token t)
+{
+  RIL_RadioCapability* rc = (RIL_RadioCapability*)data;
+  RLOGV(
+      "RadioCapability version %d session %d phase %d rat %d "
+      "logicalModemUuid %s status %d",
+      rc->version, rc->session, rc->phase, rc->rat, rc->logicalModemUuid,
+      rc->status);
+  // TODO(ender): do something about these numbers.
+  RIL_onRequestComplete(t, RIL_E_SUCCESS, rc, datalen);
+}
+
+static void requestGetMute(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(data);
+    RIL_UNUSED_PARM(datalen);
+
+    int err = -1;
+    int muteResponse = 0;  // Mute disabled
+    char *line = NULL;
+    ATResponse *p_response = NULL;
+
+    err = at_send_command_singleline("AT+CMUT?", "+CMUT:", &p_response);
+    if (err < 0 || p_response->success) {
+        goto done;
+    }
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto done;
+
+    at_tok_nextint(&line, &muteResponse);
+
+done:
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &muteResponse, sizeof(muteResponse));
+    at_response_free(p_response);
+}
+
+static void requestSetMute(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(datalen);
+
+    int err = -1;
+    char cmd[64] = {0};
+    ATResponse *p_response = NULL;
+
+    snprintf(cmd, sizeof(cmd), "AT+CMUT=%d", ((int *)data)[0]);
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || p_response->success) {
+      RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+      RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestScreenState(void *data, RIL_Token t)
+{
+    int status = *((int *)data);
+
+    if (!status) {
+        /* Suspend */
+        at_send_command("AT+CEREG=1", NULL);
+        at_send_command("AT+CREG=1", NULL);
+        at_send_command("AT+CGREG=1", NULL);
+    } else {
+       /* Resume */
+        at_send_command("AT+CEREG=2", NULL);
+        at_send_command("AT+CREG=2", NULL);
+        at_send_command("AT+CGREG=2", NULL);
+    }
+
+   RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void requestQueryClip(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(datalen);
+    RIL_UNUSED_PARM(data);
+
+    int err = -1;
+    int skip = 0;
+    int response = 0;
+    char *line = NULL;
+    ATResponse *p_response = NULL;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
+        return;
+    }
+
+    err = at_send_command_singleline("AT+CLIP?", "+CLIP:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &skip);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &response);
+    if (err < 0) goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestQueryClir(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(datalen);
+    RIL_UNUSED_PARM(data);
+
+    int err = -1;
+    int response[2] = {1, 1};
+    char *line = NULL;
+    ATResponse *p_response = NULL;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
+        return;
+    }
+
+    err = at_send_command_singleline("AT+CLIR?", "+CLIR:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &response[0]);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &response[1]);
+    if (err < 0) goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestSetClir(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(datalen);
+
+    int err = -1;
+    int n = ((int *)data)[0];
+    char cmd[64] = {0};
+    ATResponse *p_response = NULL;
+
+    snprintf(cmd, sizeof(cmd), "AT+CLIR=%d", n);
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static int forwardFromCCFCULine(char *line, RIL_CallForwardInfo *p_forward) {
+    int err = -1;
+    int i = 0;
+
+    if (line == NULL || p_forward == NULL) {
+      goto error;
+    }
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &(p_forward->status));
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &(p_forward->serviceClass));
+    if (err < 0) goto error;
+
+    if (at_tok_hasmore(&line)) {
+        int numberType = 0;
+        err = at_tok_nextint(&line, &numberType);
+        if (err < 0) goto error;
+
+        err = at_tok_nextint(&line, &p_forward->toa);
+        if (err < 0) goto error;
+
+        err = at_tok_nextstr(&line, &(p_forward->number));
+
+        /* tolerate null here */
+        if (err < 0) return 0;
+
+        if (at_tok_hasmore(&line)) {
+            for (i = 0; i < 2; i++) {
+                skipNextComma(&line);
+            }
+
+            if (at_tok_hasmore(&line)) {
+                err = at_tok_nextint(&line, &p_forward->timeSeconds);
+                if (err < 0) {
+                    p_forward->timeSeconds = 0;
+                }
+            }
+        }
+    }
+
+    return 0;
+
+error:
+    return -1;
+}
+
+static void requestSetCallForward(RIL_CallForwardInfo *data,
+                                  size_t datalen, RIL_Token t) {
+    int err = -1;
+    char cmd[128] = {0};
+    size_t offset = 0;
+    ATResponse *p_response = NULL;
+
+    if (datalen != sizeof(*data) ||
+            (data->status == 3 && data->number == NULL)) {
+        goto error;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CCFCU=%d,%d,%d,%d,\"%s\",%d",
+                            data->reason,
+                            data->status,
+                            2,
+                            data->toa,
+                            data->number ? data->number : "",
+                            data->serviceClass);
+    offset += strlen(cmd);
+
+    if (data->serviceClass == 0) {
+        if (data->timeSeconds != 0 && data->status == 3) {
+            snprintf(cmd + offset, sizeof(cmd) - offset, ",\"\",\"\",,%d",
+                data->timeSeconds);
+        }
+    } else {
+        if (data->timeSeconds != 0 && data->status == 3) {
+            snprintf(cmd + offset, sizeof(cmd) - offset, ",\"\",\"\",,%d",
+                data->timeSeconds);
+        } else {
+            strlcat(cmd, ",\"\"", sizeof(cmd) - offset);
+        }
+    }
+
+    err = at_send_command_multiline(cmd, "+CCFCU:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestQueryCallForward(RIL_CallForwardInfo *data,
+                                    size_t datalen, RIL_Token t) {
+    int err = -1;
+    char cmd[128] = {0};
+    ATResponse *p_response = NULL;
+    ATLine *p_cur = NULL;
+
+    if (datalen != sizeof(*data)) {
+        goto error;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CCFCU=%d,2,%d,%d,\"%s\",%d", data->reason, 2,
+            data->toa, data->number ? data->number : "", data->serviceClass);
+
+    err = at_send_command_multiline(cmd, "+CCFCU:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    RIL_CallForwardInfo **forwardList = NULL, *forwardPool = NULL;
+    int forwardCount = 0;
+    int validCount = 0;
+    int i = 0;
+
+    for (p_cur = p_response->p_intermediates; p_cur != NULL;
+         p_cur = p_cur->p_next, forwardCount++) {
+    }
+
+    forwardList = (RIL_CallForwardInfo **)
+        alloca(forwardCount * sizeof(RIL_CallForwardInfo *));
+
+    forwardPool = (RIL_CallForwardInfo *)
+        alloca(forwardCount * sizeof(RIL_CallForwardInfo));
+
+    memset(forwardPool, 0, forwardCount * sizeof(RIL_CallForwardInfo));
+
+    /* init the pointer array */
+    for (i = 0; i < forwardCount; i++) {
+        forwardList[i] = &(forwardPool[i]);
+    }
+
+    for (p_cur = p_response->p_intermediates; p_cur != NULL;
+         p_cur = p_cur->p_next) {
+        err = forwardFromCCFCULine(p_cur->line, forwardList[validCount]);
+        forwardList[validCount]->reason = data->reason;
+        if (err == 0) validCount++;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, validCount ? forwardList : NULL,
+                          validCount * sizeof (RIL_CallForwardInfo *));
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestQueryCallWaiting(void *data, size_t datalen, RIL_Token t) {
+    RIL_UNUSED_PARM(datalen);
+
+    int err = -1, mode = 0;
+    int serviceClass = ((int *)data)[0];
+    int response[2] = {0, 0};
+    char cmd[32] = {0};
+    char *line;
+    ATLine *p_cur;
+    ATResponse *p_response = NULL;
+
+    if (serviceClass == 0) {
+        snprintf(cmd, sizeof(cmd), "AT+CCWA=1,2");
+    } else {
+        snprintf(cmd, sizeof(cmd), "AT+CCWA=1,2,%d", serviceClass);
+    }
+    err = at_send_command_multiline(cmd, "+CCWA:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    for (p_cur = p_response->p_intermediates; p_cur != NULL;
+         p_cur = p_cur->p_next) {
+        line = p_cur->line;
+        err = at_tok_start(&line);
+        if (err < 0) goto error;
+
+        err = at_tok_nextint(&line, &mode);
+        if (err < 0) goto error;
+
+        err = at_tok_nextint(&line, &serviceClass);
+        if (err < 0) goto error;
+
+        response[0] = mode;
+        response[1] |= serviceClass;
+    }
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestSetCallWaiting(void *data, size_t datalen, RIL_Token t) {
+    RIL_UNUSED_PARM(datalen);
+
+    ATResponse *p_response = NULL;
+    int err = -1;
+    char cmd[32] = {0};
+    int enable = ((int *)data)[0];
+    int serviceClass = ((int *)data)[1];
+
+    if (serviceClass == 0) {
+        snprintf(cmd, sizeof(cmd), "AT+CCWA=1,%d", enable);
+    } else {
+        snprintf(cmd, sizeof(cmd), "AT+CCWA=1,%d,%d", enable, serviceClass);
+    }
+
+    err = at_send_command(cmd,  &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestSetSuppServiceNotifications(void *data, size_t datalen,
+                                               RIL_Token t) {
+    RIL_UNUSED_PARM(datalen);
+
+    int err = 0;
+    ATResponse *p_response = NULL;
+    int mode = ((int *)data)[0];
+    char cmd[32] = {0};
+
+    snprintf(cmd, sizeof(cmd), "AT+CSSN=%d,%d", mode, mode);
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestChangeBarringPassword(char **data, size_t datalen, RIL_Token t) {
+    int err = -1;
+    int result;
+    char cmd[64] = {0};
+    ATResponse *p_response = NULL;
+
+    if (datalen != 3 * sizeof(char *) || data[0] == NULL || data[1] == NULL ||
+        data[2] == NULL || strlen(data[0]) == 0 ||  strlen(data[1]) == 0 ||
+        strlen(data[2]) == 0) {
+        RIL_onRequestComplete(t, RIL_E_INVALID_ARGUMENTS, NULL, 0);
+        return;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CPWD=\"%s\",\"%s\",\"%s\"", data[0], data[1],
+             data[2]);
+
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void requestFacilityLock(int request, char **data,
+                                size_t datalen, RIL_Token t) {
+    int err = -1;
+    int status = 0;
+    int serviceClass = 0;
+    int remainTimes = 10;
+    char cmd[128] = {0};
+    char *line = NULL;
+    ATLine *p_cur = NULL;
+    ATResponse *p_response = NULL;
+    RIL_Errno errnoType = RIL_E_GENERIC_FAILURE;
+
+    char *type = data[0];
+
+    if (datalen != 5 * sizeof(char *)) {
+        goto error;
+    }
+    if (data[0] == NULL || data[1] == NULL ||
+       (data[2] == NULL && request == RIL_REQUEST_SET_FACILITY_LOCK) ||
+        strlen(data[0]) == 0 || strlen(data[1]) == 0 ||
+       (request == RIL_REQUEST_SET_FACILITY_LOCK && strlen(data[2]) == 0 )) {
+        errnoType = RIL_E_INVALID_ARGUMENTS;
+        RLOGE("FacilityLock invalid arguments");
+        goto error;
+    }
+
+    serviceClass = atoi(data[3]);
+    if (serviceClass == 0) {
+        snprintf(cmd, sizeof(cmd), "AT+CLCK=\"%s\",%c,\"%s\"", data[0], *data[1],
+                 data[2]);
+    } else {
+        snprintf(cmd, sizeof(cmd), "AT+CLCK=\"%s\",%c,\"%s\",%s", data[0],
+                 *data[1], data[2], data[3]);
+    }
+
+    if (*data[1] == '2') {  // query status
+        err = at_send_command_multiline(cmd, "+CLCK: ", &p_response);
+        if (err < 0 || p_response->success == 0) {
+            goto error;
+        }
+        line = p_response->p_intermediates->line;
+
+        err = at_tok_start(&line);
+        if (err < 0) goto error;
+
+        err = at_tok_nextint(&line, &status);
+        if (err < 0) goto error;
+
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, &status, sizeof(int));
+        at_response_free(p_response);
+        return;
+    } else {  // unlock/lock this facility
+        err = at_send_command(cmd, &p_response);
+        if (err < 0 || p_response->success == 0) {
+            errnoType = RIL_E_PASSWORD_INCORRECT;
+            goto error;
+        }
+        errnoType = RIL_E_SUCCESS;
+    }
+
+error:
+    if (!strcmp(data[0], "SC")) {
+        remainTimes = getSimlockRemainTimes("SIM PIN");
+    } else if (!strcmp(data[0], "FD")) {
+        remainTimes = getSimlockRemainTimes("SIM PIN2");
+    } else {
+        remainTimes = 1;
+    }
+
+    RIL_onRequestComplete(t, errnoType, &remainTimes, sizeof(remainTimes));
+    at_response_free(p_response);
+}
+
+static void requestSetSmscAddress(void *data, size_t datalen, RIL_Token t)
+{
+    ATResponse   *p_response = NULL;
+    char          cmd[64] = {0};
+    int           err = -1;
+
+    if (getSIMStatus() != SIM_READY) {
+         RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
+         return;
+    }
+
+    if (data == NULL || strlen(data) == 0) {
+        RLOGE("SET_SMSC_ADDRESS invalid address: %s", (char *)data);
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CSCA=%s,%d", (char *)data, (int)datalen);
+
+    err = at_send_command_singleline(cmd, "+CSCA:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestGetSmscAddress(void *data, size_t datalen, RIL_Token t)
+{
+    RIL_UNUSED_PARM(data);
+    RIL_UNUSED_PARM(datalen);
+
+    ATResponse   *p_response = NULL;
+    int           err = -1;
+    char         *decidata = NULL;
+
+    err = at_send_command_singleline( "AT+CSCA?", "+CSCA:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+       goto error;
+    }
+
+    char *line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &decidata);
+    if (err < 0) goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, decidata, strlen(decidata) + 1);
+    at_response_free(p_response);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(p_response);
+}
+
+static void setGsmBroadcastConfigData(int from, int to, int id, int outStrSize, char *outStr) {
+    if (from < 0 || from > 0xffff || to < 0 || to > 0xffff) {
+        RLOGE("setGsmBroadcastConfig data is invalid, [%d, %d]", from, to);
+        return;
+    }
+
+    if (id != 0) {
+        strlcat(outStr, ",", outStrSize);
+    }
+
+    int len = strlen(outStr);
+    if (from == to) {
+        snprintf(outStr + len, outStrSize - len, "%d", from);
+    } else {
+        snprintf(outStr + len, outStrSize - len, "%d-%d", from, to);
+    }
+}
+
+static void requestSetSmsBroadcastConfig(void *data, size_t datalen,
+                                         RIL_Token t) {
+    int i = 0;
+    int count = datalen / sizeof(RIL_GSM_BroadcastSmsConfigInfo *);
+    int size = count * 16;
+    char cmd[256] = {0};
+    char *channel = (char *)alloca(size);
+    char *languageId = (char *)alloca(size);
+    ATResponse *p_response = NULL;
+    RIL_GSM_BroadcastSmsConfigInfo **pGsmBci =
+            (RIL_GSM_BroadcastSmsConfigInfo **)data;
+    RIL_GSM_BroadcastSmsConfigInfo gsmBci = {0};
+
+    memset(channel, 0, size);
+    memset(languageId, 0, size);
+    RLOGD("requestSetGsmBroadcastConfig %zu, count %d", datalen, count);
+
+    for (i = 0; i < count; i++) {
+        gsmBci = *(pGsmBci[i]);
+        setGsmBroadcastConfigData(gsmBci.fromServiceId, gsmBci.toServiceId, i,
+                                  size, channel);
+        setGsmBroadcastConfigData(gsmBci.fromCodeScheme, gsmBci.toCodeScheme, i,
+                                  size, languageId);
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CSCB=%d,\"%s\",\"%s\"",
+            (*pGsmBci[0]).selected ? 0 : 1, channel, languageId);
+    int err = at_send_command_singleline( cmd, "+CSCB:", &p_response);
+
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestGetSmsBroadcastConfig(void *data, size_t datalen,
+                                         RIL_Token t) {
+    RIL_UNUSED_PARM(data);
+    RIL_UNUSED_PARM(datalen);
+
+    ATResponse *p_response = NULL;
+    int err = -1, mode, commas = 0, i = 0;
+    char *line = NULL;
+    char *serviceIds = NULL, *codeSchemes = NULL, *p = NULL;
+    char *serviceId = NULL, *codeScheme = NULL;
+
+    err = at_send_command_singleline("AT+CSCB?", "+CSCB:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &mode);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &serviceIds);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &codeSchemes);
+    if (err < 0) goto error;
+
+    for (p = serviceIds; *p != '\0'; p++) {
+        if (*p == ',') {
+            commas++;
+        }
+    }
+    RIL_GSM_BroadcastSmsConfigInfo **pGsmBci =
+        (RIL_GSM_BroadcastSmsConfigInfo **)alloca((commas + 1) *
+            sizeof(RIL_GSM_BroadcastSmsConfigInfo *));
+    memset(pGsmBci, 0, (commas + 1) * sizeof(RIL_GSM_BroadcastSmsConfigInfo *));
+
+    for (i = 0; i < commas + 1; i++) {
+        pGsmBci[i] = (RIL_GSM_BroadcastSmsConfigInfo *)alloca(
+                sizeof(RIL_GSM_BroadcastSmsConfigInfo));
+        memset(pGsmBci[i], 0, sizeof(RIL_GSM_BroadcastSmsConfigInfo));
+
+        err = at_tok_nextstr(&serviceIds, &serviceId);
+        if (err < 0) goto error;
+        pGsmBci[i]->toServiceId = pGsmBci[i]->fromServiceId = 0;
+        if (strstr(serviceId, "-")) {
+            sscanf(serviceId,"%d-%d", &pGsmBci[i]->fromServiceId,
+                   &pGsmBci[i]->toServiceId);
+        }
+
+        err = at_tok_nextstr(&codeSchemes, &codeScheme);
+        if (err < 0) goto error;
+        pGsmBci[i]->toCodeScheme = pGsmBci[i]->fromCodeScheme = 0;
+        if (strstr(codeScheme, "-")) {
+            sscanf(codeScheme, "%d-%d", &pGsmBci[i]->fromCodeScheme,
+                   &pGsmBci[i]->toCodeScheme);
+        }
+
+        pGsmBci[i]->selected = (mode == 0 ? false : true);
+    }
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, pGsmBci,
+        (commas + 1) * sizeof(RIL_GSM_BroadcastSmsConfigInfo *));
+    at_response_free(p_response);
+    return;
+
+error:
+    at_response_free(p_response);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+/**
+ * <AcT>: integer type; access technology selected
+ * 0 GSM
+ * 1 GSM Compact
+ * 2 UTRAN
+ * 3 GSM w/EGPRS (see NOTE 1)
+ * 4 UTRAN w/HSDPA (see NOTE 2)
+ * 5 UTRAN w/HSUPA (see NOTE 2)
+ * 6 UTRAN w/HSDPA and HSUPA (see NOTE 2)
+ * 7 E-UTRAN
+ * 8 EC-GSM-IoT (A/Gb mode) (see NOTE 3)
+ * 9 E-UTRAN (NB-S1 mode) (see NOTE 4)
+ * 10  E-UTRA connected to a 5GCN (see NOTE 5)
+ * 11  NR connected to a 5GCN (see NOTE 5)
+ * 12  NG-RAN
+ * 13  E-UTRA-NR dual connectivity (see NOTE 6)
+ */
+int mapRadioAccessNetworkToTech(RIL_RadioAccessNetworks network) {
+    switch (network) {
+        case GERAN:  // GSM EDGE
+            return 3;
+        case UTRAN:
+            return 6;
+        case EUTRAN:
+            return 7;
+        case NGRAN:
+            return 11;
+        default:
+            return 7;  // LTE
+    }
+}
+
+static void requestSetNetworlSelectionManual(void *data, RIL_Token t) {
+    int err = -1;
+    char cmd[64] = {0};
+    ATResponse *p_response = NULL;
+    RIL_NetworkOperator *operator = (RIL_NetworkOperator *)data;
+
+    if (operator->act != UNKNOWN) {
+        snprintf(cmd, sizeof(cmd), "AT+COPS=1,2,\"%s\"", operator->operatorNumeric);
+    } else {
+        snprintf(cmd, sizeof(cmd), "AT+COPS=1,2,\"%s\",%d",
+            operator->operatorNumeric, operator->act);
+    }
+    err = at_send_command(cmd, &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    at_response_free(p_response);
+    return;
+
+error:
+    if (p_response != NULL &&
+        !strcmp(p_response->finalResponse, "+CME ERROR: 30")) {
+          RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestStkServiceIsRunning(RIL_Token t)
+{
+    int err = -1;
+    ATResponse *p_response = NULL;
+
+    s_stkServiceRunning = true;
+    if (NULL != s_stkUnsolResponse) {
+       RIL_onUnsolicitedResponse(RIL_UNSOL_STK_PROACTIVE_COMMAND,
+                            s_stkUnsolResponse, strlen(s_stkUnsolResponse) + 1);
+       free(s_stkUnsolResponse);
+       s_stkUnsolResponse = NULL;
+       RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+       return;
+    }
+
+    err = at_send_command_singleline("AT+CUSATD?", "+CUSATD:", &p_response);
+
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestStkSendEnvelope(void *data, RIL_Token t)
+{
+    int ret = -1, err = -1;
+    char cmd[128] = {0};
+    ATResponse *p_response = NULL;
+
+    if (data == NULL || strlen((char *)data) == 0) {
+        RLOGE("STK sendEnvelope data is invalid");
+        RIL_onRequestComplete(t, RIL_E_INVALID_ARGUMENTS, NULL, 0);
+        return;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CUSATE=\"%s\"", (char *)data);
+    err = at_send_command_singleline(cmd, "+CUSATE:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+        // type of alpha data is 85, such as 850C546F6F6C6B6974204D656E75
+        char *p = strstr(p_response->p_intermediates->line, "85");
+        if (p != NULL) {
+            char alphaStrHexLen[3] = {0};
+            char alphaStr[1024] = {0};
+            uint8_t *alphaBytes = NULL;
+            int len = 0;
+
+            p = p + strlen("85");
+            strncpy(alphaStrHexLen, p, 2);
+            len = strtoul(alphaStrHexLen, NULL, 16);
+            strncpy(alphaStr, p + 2, len * 2);
+            alphaBytes = convertHexStringToBytes(alphaStr, strlen(alphaStr));
+            RIL_onUnsolicitedResponse(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alphaBytes,
+                                      strlen((char *)alphaBytes));
+            free(alphaBytes);
+        }
+    }
+    at_response_free(p_response);
+}
+
+static void requestStksendTerminalResponse(void *data, RIL_Token t)
+{
+    int ret = -1, err = -1;
+    char cmd[128] = {0};
+    ATResponse *p_response = NULL;
+
+    if (data == NULL || strlen((char *)data) == 0) {
+        RLOGE("STK sendTerminalResponse data is invalid");
+        RIL_onRequestComplete(t, RIL_E_INVALID_ARGUMENTS, NULL, 0);
+        return;
+    }
+
+    snprintf(cmd, sizeof(cmd), "AT+CUSATT=\"%s\"", (char *)data);
+    err = at_send_command_singleline( cmd, "+CUSATT:", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+    at_response_free(p_response);
+}
+
+static void requestEccDial(void *data, RIL_Token t) {
+    char cmd[64] = {0};
+    const char *clir = NULL;
+    int err = -1;
+    RIL_EmergencyDial *p_eccDial = (RIL_EmergencyDial *)data;
+
+    switch (p_eccDial->dialInfo.clir) {
+        case 0:  /* subscription default */
+            clir = "";
+            break;
+        case 1:  /* invocation */
+            clir = "I";
+            break;
+        case 2:  /* suppression */
+            clir = "i";
+            break;
+        default:
+            break;
+    }
+
+    if (p_eccDial->routing == ROUTING_MERGENCY ||
+        p_eccDial->routing ==  ROUTING_UNKNOWN) {
+      if (p_eccDial->categories == CATEGORY_UNSPECIFIED) {
+          snprintf(cmd, sizeof(cmd), "ATD%s@,#%s;", p_eccDial->dialInfo.address, clir);
+      } else {
+          snprintf(cmd, sizeof(cmd), "ATD%s@%d,#%s;", p_eccDial->dialInfo.address,
+              p_eccDial->categories, clir);
+      }
+    } else {  // ROUTING_NORMAL
+        snprintf(cmd, sizeof(cmd), "ATD%s%s;", p_eccDial->dialInfo.address, clir);
+    }
+
+    err = at_send_command(cmd, NULL);
+    if (err != 0) goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+void getConfigSlotStatus(RIL_SimSlotStatus_V1_2 *pSimSlotStatus) {
+    if (pSimSlotStatus == NULL) {
+        return;
+    }
+    if (getSIMStatus() == SIM_ABSENT) {
+        pSimSlotStatus->base.cardState = RIL_CARDSTATE_ABSENT;
+    } else {
+        pSimSlotStatus->base.cardState = RIL_CARDSTATE_PRESENT;
+    }
+    // TODO: slot state is always active now
+    pSimSlotStatus->base.slotState = SLOT_STATE_ACTIVE;
+
+    if (pSimSlotStatus->base.cardState != RIL_CARDSTATE_ABSENT) {
+        pSimSlotStatus->base.atr = "";
+        pSimSlotStatus->base.iccid = (char *)calloc(64, sizeof(char));
+        getIccId(pSimSlotStatus->base.iccid, 64);
+    }
+
+    pSimSlotStatus->base.logicalSlotId = 0;
+    pSimSlotStatus->eid = "";
+}
+
+void onIccSlotStatus(RIL_Token t) {
+    RIL_SimSlotStatus_V1_2 *pSimSlotStatusList =
+        (RIL_SimSlotStatus_V1_2 *)calloc(SIM_COUNT, sizeof(RIL_SimSlotStatus_V1_2));
+
+    getConfigSlotStatus(pSimSlotStatusList);
+
+    if (t == NULL) {
+        RIL_onUnsolicitedResponse(RIL_UNSOL_CONFIG_ICC_SLOT_STATUS, pSimSlotStatusList,
+                 SIM_COUNT * sizeof(RIL_SimSlotStatus_V1_2));
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, pSimSlotStatusList,
+                SIM_COUNT * sizeof(RIL_SimSlotStatus_V1_2));
+    }
+
+    if (pSimSlotStatusList != NULL) {
+        free(pSimSlotStatusList->base.iccid);
+        free(pSimSlotStatusList);
+    }
+}
+
+/*** Callback methods from the RIL library to us ***/
+
+/**
+ * Call from RIL to us to make a RIL_REQUEST
+ *
+ * Must be completed with a call to RIL_onRequestComplete()
+ *
+ * RIL_onRequestComplete() may be called from any thread, before or after
+ * this function returns.
+ *
+ * Because onRequest function could be called from multiple different thread,
+ * we must ensure that the underlying at_send_command_* function
+ * is atomic.
+ */
+static void
+onRequest (int request, void *data, size_t datalen, RIL_Token t)
+{
+    ATResponse *p_response;
+    int err;
+
+    RLOGD("onRequest: %s, sState: %d", requestToString(request), sState);
+
+    /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
+     * when RADIO_STATE_UNAVAILABLE.
+     */
+    if (sState == RADIO_STATE_UNAVAILABLE
+        && request != RIL_REQUEST_GET_SIM_STATUS
+    ) {
+        RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+        return;
+    }
+
+    /* Ignore all non-power requests when RADIO_STATE_OFF
+     * (except RIL_REQUEST_GET_SIM_STATUS)
+     */
+    if (sState == RADIO_STATE_OFF) {
+        switch(request) {
+            case RIL_REQUEST_BASEBAND_VERSION:
+            case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
+            case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:
+            case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
+            case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
+            case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
+            case RIL_REQUEST_CDMA_SUBSCRIPTION:
+            case RIL_REQUEST_DEVICE_IDENTITY:
+            case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
+            case RIL_REQUEST_GET_ACTIVITY_INFO:
+            case RIL_REQUEST_GET_CARRIER_RESTRICTIONS:
+            case RIL_REQUEST_GET_CURRENT_CALLS:
+            case RIL_REQUEST_GET_IMEI:
+            case RIL_REQUEST_GET_MUTE:
+            case RIL_REQUEST_SET_MUTE:
+            case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
+            case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
+            case RIL_REQUEST_GET_RADIO_CAPABILITY:
+            case RIL_REQUEST_GET_SIM_STATUS:
+            case RIL_REQUEST_NV_RESET_CONFIG:
+            case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
+            case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
+            case RIL_REQUEST_QUERY_TTY_MODE:
+            case RIL_REQUEST_RADIO_POWER:
+            case RIL_REQUEST_SET_BAND_MODE:
+            case RIL_REQUEST_SET_CARRIER_RESTRICTIONS:
+            case RIL_REQUEST_SET_LOCATION_UPDATES:
+            case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
+            case RIL_REQUEST_SET_TTY_MODE:
+            case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
+            case RIL_REQUEST_STOP_LCE:
+            case RIL_REQUEST_VOICE_RADIO_TECH:
+            case RIL_REQUEST_SCREEN_STATE:
+                // Process all the above, even though the radio is off
+                break;
+
+            default:
+                // For all others, say NOT_AVAILABLE because the radio is off
+                RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+                return;
+        }
+    }
+
+    switch (request) {
+        case RIL_REQUEST_GET_SIM_STATUS: {
+            RIL_CardStatus_v1_5 *p_card_status;
+            char *p_buffer;
+            int buffer_size;
+
+            int result = getCardStatus(&p_card_status);
+            if (result == RIL_E_SUCCESS) {
+                p_buffer = (char *)p_card_status;
+                buffer_size = sizeof(*p_card_status);
+            } else {
+                p_buffer = NULL;
+                buffer_size = 0;
+            }
+            RIL_onRequestComplete(t, result, p_buffer, buffer_size);
+            freeCardStatus(p_card_status);
+            break;
+        }
+        case RIL_REQUEST_GET_CURRENT_CALLS:
+            requestGetCurrentCalls(data, datalen, t);
+            break;
+        case RIL_REQUEST_DIAL:
+            requestDial(data, datalen, t);
+            break;
+        case RIL_REQUEST_HANGUP:
+            requestHangup(data, datalen, t);
+            break;
+        case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
+        case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
+        case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
+        case RIL_REQUEST_CONFERENCE:
+        case RIL_REQUEST_UDUB:
+             requestCallSelection(data, datalen, t, request);
+             break;
+        case RIL_REQUEST_ANSWER:
+            at_send_command("ATA", NULL);
+
+#ifdef WORKAROUND_ERRONEOUS_ANSWER
+            s_expectAnswer = 1;
+#endif /* WORKAROUND_ERRONEOUS_ANSWER */
+
+            if (getSIMStatus() != SIM_READY) {
+                RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
+            } else {
+                // Success or failure is ignored by the upper layer here.
+                // It will call GET_CURRENT_CALLS and determine success that way.
+                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            }
+            break;
+
+        case RIL_REQUEST_SEPARATE_CONNECTION:
+            {
+                char  cmd[12];
+                int   party = ((int*)data)[0];
+
+                if (getSIMStatus() == SIM_ABSENT) {
+                    RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+                    return;
+                }
+                // Make sure that party is in a valid range.
+                // (Note: The Telephony middle layer imposes a range of 1 to 7.
+                // It's sufficient for us to just make sure it's single digit.)
+                if (party > 0 && party < 10) {
+                    sprintf(cmd, "AT+CHLD=2%d", party);
+                    at_send_command(cmd, NULL);
+                    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+                } else {
+                    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+                }
+            }
+            break;
+
+        case RIL_REQUEST_SIGNAL_STRENGTH:
+            requestSignalStrength(data, datalen, t);
+            break;
+        case RIL_REQUEST_VOICE_REGISTRATION_STATE:
+        case RIL_REQUEST_DATA_REGISTRATION_STATE:
+            requestRegistrationState(request, data, datalen, t);
+            break;
+        case RIL_REQUEST_OPERATOR:
+            requestOperator(data, datalen, t);
+            break;
+        case RIL_REQUEST_RADIO_POWER:
+            requestRadioPower(data, datalen, t);
+            break;
+        case RIL_REQUEST_DTMF: {
+            char c = ((char *)data)[0];
+            char *cmd;
+            asprintf(&cmd, "AT+VTS=%c", (int)c);
+            at_send_command(cmd, NULL);
+            free(cmd);
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        }
+        case RIL_REQUEST_SEND_SMS:
+        case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
+            requestSendSMS(data, datalen, t);
+            break;
+        case RIL_REQUEST_CDMA_SEND_SMS:
+            requestCdmaSendSMS(data, datalen, t);
+            break;
+        case RIL_REQUEST_IMS_SEND_SMS:
+            requestImsSendSMS(data, datalen, t);
+            break;
+        case RIL_REQUEST_SIM_OPEN_CHANNEL:
+            requestSimOpenChannel(data, datalen, t);
+            break;
+        case RIL_REQUEST_SIM_CLOSE_CHANNEL:
+            requestSimCloseChannel(data, datalen, t);
+            break;
+        case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
+            requestSimTransmitApduChannel(data, datalen, t);
+            break;
+        case RIL_REQUEST_SIM_AUTHENTICATION: {
+            RIL_SimAuthentication *sim_auth = (RIL_SimAuthentication *)data;
+            if ((sim_auth->authContext == AUTH_CONTEXT_EAP_SIM ||
+                 sim_auth->authContext == AUTH_CONTEXT_EAP_AKA) &&
+                sim_auth->authData != NULL) {
+                requestSimAuthentication(sim_auth->authContext, sim_auth->authData, t);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_INVALID_ARGUMENTS, NULL, 0);
+            }
+            break;
+        }
+        case RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC:
+            requestTransmitApduBasic(data, datalen, t);
+            break;
+        case RIL_REQUEST_SETUP_DATA_CALL:
+            requestSetupDataCall(data, datalen, t);
+            break;
+        case RIL_REQUEST_DEACTIVATE_DATA_CALL:
+            requestDeactivateDataCall(data, t);
+            break;
+        case RIL_REQUEST_SMS_ACKNOWLEDGE:
+            requestSMSAcknowledge(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_IMSI:
+            p_response = NULL;
+            err = at_send_command_numeric("AT+CIMI", &p_response);
+
+            if (err < 0 || p_response->success == 0) {
+                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_SUCCESS,
+                    p_response->p_intermediates->line, sizeof(char *));
+            }
+            at_response_free(p_response);
+            break;
+
+        case RIL_REQUEST_GET_IMEI:
+            p_response = NULL;
+            err = at_send_command_numeric("AT+CGSN", &p_response);
+
+            if (err < 0 || p_response->success == 0) {
+                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_SUCCESS,
+                    p_response->p_intermediates->line, sizeof(char *));
+            }
+            at_response_free(p_response);
+            break;
+
+
+        case RIL_REQUEST_SIM_IO:
+            requestSIM_IO(data,datalen,t);
+            break;
+
+        case RIL_REQUEST_SEND_USSD:
+            requestSendUSSD(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_CANCEL_USSD:
+            if (getSIMStatus() == SIM_ABSENT) {
+                RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+                break;
+            }
+            p_response = NULL;
+            err = at_send_command_numeric("AT+CUSD=2", &p_response);
+
+            if (err < 0 || p_response->success == 0) {
+                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_SUCCESS,
+                    p_response->p_intermediates->line, sizeof(char *));
+            }
+            at_response_free(p_response);
+            break;
+
+        case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
+            if (getSIMStatus() == SIM_ABSENT) {
+                RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+                break;
+            }
+            p_response = NULL;
+            err = at_send_command("AT+COPS=0", &p_response);
+            if (err < 0 || p_response->success == 0) {
+                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            }
+            at_response_free(p_response);
+            break;
+
+        case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
+            requestSetNetworlSelectionManual(data, t);
+            break;
+
+        case RIL_REQUEST_DATA_CALL_LIST:
+            requestDataCallList(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
+            requestQueryNetworkSelectionMode(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_OEM_HOOK_RAW:
+            // echo back data
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
+            break;
+
+
+        case RIL_REQUEST_OEM_HOOK_STRINGS: {
+            int i;
+            const char ** cur;
+
+            RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
+
+
+            for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
+                    i > 0 ; cur++, i --) {
+                RLOGD("> '%s'", *cur);
+            }
+
+            // echo back strings
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
+            break;
+        }
+
+        case RIL_REQUEST_WRITE_SMS_TO_SIM:
+            requestWriteSmsToSim(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_DELETE_SMS_ON_SIM: {
+            char * cmd;
+            p_response = NULL;
+            asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
+            err = at_send_command(cmd, &p_response);
+            free(cmd);
+            if (err < 0 || p_response->success == 0) {
+                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            }
+            at_response_free(p_response);
+            break;
+        }
+
+        case RIL_REQUEST_ENTER_SIM_PIN:
+        case RIL_REQUEST_ENTER_SIM_PIN2:
+            requestEnterSimPin(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_ENTER_SIM_PUK:
+        case RIL_REQUEST_ENTER_SIM_PUK2:
+        case RIL_REQUEST_CHANGE_SIM_PIN:
+            requestChangeSimPin(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_CHANGE_SIM_PIN2:
+            requestChangeSimPin2(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_IMS_REGISTRATION_STATE: {
+            int reply[2];
+            //0==unregistered, 1==registered
+            reply[0] = s_ims_registered;
+
+            //to be used when changed to include service supporated info
+            //reply[1] = s_ims_services;
+
+            // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
+            reply[1] = s_ims_format;
+
+            RLOGD("IMS_REGISTRATION=%d, format=%d ",
+                    reply[0], reply[1]);
+            if (reply[1] != -1) {
+                RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
+            } else {
+                RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            }
+            break;
+        }
+
+        case RIL_REQUEST_VOICE_RADIO_TECH:
+            {
+                int tech = techFromModemType(TECH(sMdmInfo));
+                if (tech < 0 )
+                    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+                else
+                    RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
+            }
+            break;
+        case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
+            requestSetPreferredNetworkType(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
+            requestGetPreferredNetworkType(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_CELL_INFO_LIST:
+            requestGetCellInfoList(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
+            requestSetCellInfoListRate(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_HARDWARE_CONFIG:
+            requestGetHardwareConfig(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SHUTDOWN:
+            requestShutdown(t);
+            break;
+
+        case RIL_REQUEST_QUERY_TTY_MODE:
+            requestGetTtyMode(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_RADIO_CAPABILITY:
+            requestGetRadioCapability(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_RADIO_CAPABILITY:
+            requestSetRadioCapability(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_MUTE:
+            requestGetMute(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_MUTE:
+            requestSetMute(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: {
+          int size = 5;
+          int response[20] = {0};
+          for (int i = 1; i <= size; i++) {
+            response[i] = i - 1;
+          }
+          RIL_onRequestComplete(t, RIL_E_SUCCESS, response, (size + 1) * sizeof(int));
+          break;
+        }
+
+        case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
+        case RIL_REQUEST_ALLOW_DATA:
+        case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
+        case RIL_REQUEST_SET_BAND_MODE:
+        case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
+        case RIL_REQUEST_SET_LOCATION_UPDATES:
+        case RIL_REQUEST_SET_TTY_MODE:
+        case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+
+        case RIL_REQUEST_BASEBAND_VERSION:
+            requestCdmaBaseBandVersion(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_DEVICE_IDENTITY:
+            requestDeviceIdentity(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_CDMA_SUBSCRIPTION:
+            requestCdmaSubscription(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
+            requestCdmaGetSubscriptionSource(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_START_LCE:
+        case RIL_REQUEST_STOP_LCE:
+        case RIL_REQUEST_PULL_LCEDATA:
+            if (getSIMStatus() == SIM_ABSENT) {
+                RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_LCE_NOT_SUPPORTED, NULL, 0);
+            }
+            break;
+
+        case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
+            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
+                requestCdmaGetRoamingPreference(request, data, datalen, t);
+            } else {
+                RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+            }
+            break;
+
+        case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
+            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
+                requestCdmaSetSubscriptionSource(request, data, datalen, t);
+            } else {
+                // VTS tests expect us to silently do nothing
+                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            }
+            break;
+
+        case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
+            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
+                requestCdmaSetRoamingPreference(request, data, datalen, t);
+            } else {
+                // VTS tests expect us to silently do nothing
+                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            }
+            break;
+
+        case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
+            if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
+                requestExitEmergencyMode(data, datalen, t);
+            } else {
+                // VTS tests expect us to silently do nothing
+                RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            }
+            break;
+
+        case RIL_REQUEST_GET_ACTIVITY_INFO:
+            requestGetActivityInfo(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SCREEN_STATE:
+            requestScreenState(data, t);
+            break;
+
+        case RIL_REQUEST_SET_DATA_PROFILE:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+
+        case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS:
+            requestQueryCallForward(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_CALL_FORWARD:
+            requestSetCallForward(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_QUERY_CLIP:
+            requestQueryClip(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_CLIR:
+            requestQueryClir(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_CLIR:
+            requestSetClir(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_QUERY_CALL_WAITING:
+            requestQueryCallWaiting(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_CALL_WAITING:
+            requestSetCallWaiting(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
+            requestSetSuppServiceNotifications(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_CHANGE_BARRING_PASSWORD:
+            requestChangeBarringPassword(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_QUERY_FACILITY_LOCK: {
+            char *lockData[4];
+            lockData[0] = ((char **)data)[0];
+            lockData[1] = "2";
+            lockData[2] = ((char **)data)[1];
+            lockData[3] = ((char **)data)[2];
+            requestFacilityLock(request, lockData, datalen + sizeof(char *), t);
+            break;
+        }
+
+        case RIL_REQUEST_SET_FACILITY_LOCK:
+            requestFacilityLock(request, data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GET_SMSC_ADDRESS:
+            requestGetSmscAddress(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_SMSC_ADDRESS:
+            requestSetSmscAddress(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
+            requestSetSmsBroadcastConfig(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
+            requestGetSmsBroadcastConfig(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING:
+            requestStkServiceIsRunning(t);
+            break;
+
+        case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND:
+            requestStkSendEnvelope(data, t);
+            break;
+
+        case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE:
+            requestStksendTerminalResponse(data, t);
+            break;
+
+        // New requests after P.
+        case RIL_REQUEST_START_NETWORK_SCAN:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_GET_MODEM_STACK_STATUS:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_ENABLE_MODEM:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_EMERGENCY_DIAL:
+            requestEccDial(data, t);
+            break;
+        case RIL_REQUEST_SET_SIM_CARD_POWER:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE_BITMAP:
+            requestSetPreferredNetworkType(request, data, datalen, t);
+            break;
+        case RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP:
+            requestSetPreferredNetworkType(request, data, datalen, t);
+            break;
+        case RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP:
+            requestGetPreferredNetworkType(request, data, datalen, t);
+        case RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY:
+            if (data == NULL || datalen != sizeof(int)) {
+                RIL_onRequestComplete(t, RIL_E_INTERNAL_ERR, NULL, 0);
+                break;
+            }
+            int nrDualConnectivityState = *(int *)(data);
+            isNrDualConnectivityEnabled = (nrDualConnectivityState == 1) ? true : false;
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, &isNrDualConnectivityEnabled,
+                    sizeof(isNrDualConnectivityEnabled));
+            break;
+        case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE_BITMAP:
+            requestGetPreferredNetworkType(request, data, datalen, t);
+            break;
+        case RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_GET_SLICING_CONFIG:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+
+        // Radio config requests
+        case RIL_REQUEST_CONFIG_GET_SLOT_STATUS:
+            RIL_requestTimedCallback(onIccSlotStatus, (void *)t, NULL);
+            break;
+        case RIL_REQUEST_CONFIG_SET_SLOT_MAPPING:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_CONFIG_GET_PHONE_CAPABILITY: {
+            RIL_PhoneCapability *phoneCapability =
+                    (RIL_PhoneCapability *)alloca(sizeof(RIL_PhoneCapability));
+            phoneCapability->maxActiveData = 1;
+            // DSDS is 1, and DSDA is 2, now only support DSDS
+            phoneCapability->maxActiveInternetData = 1;
+            // DSDA can support internet lingering
+            phoneCapability->isInternetLingeringSupported = false;
+            for (int num = 0; num < SIM_COUNT; num++) {
+                phoneCapability->logicalModemList[num].modemId = num;
+            }
+            RIL_onRequestComplete(t, RIL_E_SUCCESS,
+                            phoneCapability, sizeof(RIL_PhoneCapability));
+            break;
+        }
+        case RIL_REQUEST_CONFIG_SET_MODEM_CONFIG:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_CONFIG_GET_MODEM_CONFIG: {
+            RIL_ModemConfig mdConfig;
+            mdConfig.numOfLiveModems = 1;
+
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, &mdConfig, sizeof(RIL_ModemConfig));
+            break;
+        }
+        case RIL_REQUEST_CONFIG_SET_PREFER_DATA_MODEM:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+
+        case RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_ENABLE_UICC_APPLICATIONS: {
+            if (data == NULL || datalen != sizeof(int)) {
+                RIL_onRequestComplete(t, RIL_E_INTERNAL_ERR, NULL, 0);
+                break;
+            }
+            areUiccApplicationsEnabled = *(int *)(data);
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        }
+        case RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, &areUiccApplicationsEnabled,
+                    sizeof(areUiccApplicationsEnabled));
+            break;
+        case RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_GET_BARRING_INFO:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        case RIL_REQUEST_SET_DATA_THROTTLING:
+            RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+            break;
+        default:
+            RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
+            RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+            break;
+    }
+}
+
+/**
+ * Synchronous call from the RIL to us to return current radio state.
+ * RADIO_STATE_UNAVAILABLE should be the initial state.
+ */
+static RIL_RadioState
+currentState()
+{
+    return sState;
+}
+/**
+ * Call from RIL to us to find out whether a specific request code
+ * is supported by this implementation.
+ *
+ * Return 1 for "supported" and 0 for "unsupported"
+ */
+
+static int
+onSupports (int requestCode __unused)
+{
+    //@@@ todo
+
+    return 1;
+}
+
+static void onCancel (RIL_Token t __unused)
+{
+    //@@@todo
+
+}
+
+static const char * getVersion(void)
+{
+    return "android reference-ril 1.0";
+}
+
+static void
+setRadioTechnology(ModemInfo *mdm, int newtech)
+{
+    RLOGD("setRadioTechnology(%d)", newtech);
+
+    int oldtech = TECH(mdm);
+
+    if (newtech != oldtech) {
+        RLOGD("Tech change (%d => %d)", oldtech, newtech);
+        TECH(mdm) = newtech;
+        if (techFromModemType(newtech) != techFromModemType(oldtech)) {
+            int tech = techFromModemType(TECH(sMdmInfo));
+            if (tech > 0 ) {
+                RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
+                                          &tech, sizeof(tech));
+            }
+        }
+    }
+}
+
+static void
+setRadioState(RIL_RadioState newState)
+{
+    RLOGD("setRadioState(%d)", newState);
+    RIL_RadioState oldState;
+
+    pthread_mutex_lock(&s_state_mutex);
+
+    oldState = sState;
+
+    if (s_closed > 0) {
+        // If we're closed, the only reasonable state is
+        // RADIO_STATE_UNAVAILABLE
+        // This is here because things on the main thread
+        // may attempt to change the radio state after the closed
+        // event happened in another thread
+        newState = RADIO_STATE_UNAVAILABLE;
+    }
+
+    if (sState != newState || s_closed > 0) {
+        sState = newState;
+
+        pthread_cond_broadcast (&s_state_cond);
+    }
+
+    pthread_mutex_unlock(&s_state_mutex);
+
+
+    /* do these outside of the mutex */
+    if (sState != oldState) {
+        RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
+                                    NULL, 0);
+        // Sim state can change as result of radio state change
+        RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
+                                    NULL, 0);
+
+        /* FIXME onSimReady() and onRadioPowerOn() cannot be called
+         * from the AT reader thread
+         * Currently, this doesn't happen, but if that changes then these
+         * will need to be dispatched on the request thread
+         */
+        if (sState == RADIO_STATE_ON) {
+            onRadioPowerOn();
+        }
+    }
+}
+
+/** Returns RUIM_NOT_READY on error */
+static SIM_Status
+getRUIMStatus()
+{
+    ATResponse *p_response = NULL;
+    int err;
+    int ret;
+    char *cpinLine;
+    char *cpinResult;
+
+    if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
+        ret = SIM_NOT_READY;
+        goto done;
+    }
+
+    err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
+
+    if (err != 0) {
+        ret = SIM_NOT_READY;
+        goto done;
+    }
+
+    switch (at_get_cme_error(p_response)) {
+        case CME_SUCCESS:
+            break;
+
+        case CME_SIM_NOT_INSERTED:
+            ret = SIM_ABSENT;
+            goto done;
+
+        default:
+            ret = SIM_NOT_READY;
+            goto done;
+    }
+
+    /* CPIN? has succeeded, now look at the result */
+
+    cpinLine = p_response->p_intermediates->line;
+    err = at_tok_start (&cpinLine);
+
+    if (err < 0) {
+        ret = SIM_NOT_READY;
+        goto done;
+    }
+
+    err = at_tok_nextstr(&cpinLine, &cpinResult);
+
+    if (err < 0) {
+        ret = SIM_NOT_READY;
+        goto done;
+    }
+
+    if (0 == strcmp (cpinResult, "SIM PIN")) {
+        ret = SIM_PIN;
+        goto done;
+    } else if (0 == strcmp (cpinResult, "SIM PUK")) {
+        ret = SIM_PUK;
+        goto done;
+    } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
+        return SIM_NETWORK_PERSONALIZATION;
+    } else if (0 != strcmp (cpinResult, "READY"))  {
+        /* we're treating unsupported lock types as "sim absent" */
+        ret = SIM_ABSENT;
+        goto done;
+    }
+
+    at_response_free(p_response);
+    p_response = NULL;
+    cpinResult = NULL;
+
+    ret = SIM_READY;
+
+done:
+    at_response_free(p_response);
+    return ret;
+}
+
+/** Returns SIM_NOT_READY on error */
+static SIM_Status
+getSIMStatus()
+{
+    ATResponse *p_response = NULL;
+    int err;
+    int ret;
+    char *cpinLine;
+    char *cpinResult;
+
+    RLOGD("getSIMStatus(). sState: %d",sState);
+    err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
+
+    if (err != 0) {
+        ret = SIM_NOT_READY;
+        goto done;
+    }
+
+    switch (at_get_cme_error(p_response)) {
+        case CME_SUCCESS:
+            break;
+
+        case CME_SIM_NOT_INSERTED:
+            ret = SIM_ABSENT;
+            goto done;
+
+        default:
+            ret = SIM_NOT_READY;
+            goto done;
+    }
+
+    /* CPIN? has succeeded, now look at the result */
+
+    cpinLine = p_response->p_intermediates->line;
+    err = at_tok_start (&cpinLine);
+
+    if (err < 0) {
+        ret = SIM_NOT_READY;
+        goto done;
+    }
+
+    err = at_tok_nextstr(&cpinLine, &cpinResult);
+
+    if (err < 0) {
+        ret = SIM_NOT_READY;
+        goto done;
+    }
+
+    if (0 == strcmp (cpinResult, "SIM PIN")) {
+        ret = SIM_PIN;
+        goto done;
+    } else if (0 == strcmp (cpinResult, "SIM PUK")) {
+        ret = SIM_PUK;
+        goto done;
+    } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
+        return SIM_NETWORK_PERSONALIZATION;
+    } else if (0 != strcmp (cpinResult, "READY"))  {
+        /* we're treating unsupported lock types as "sim absent" */
+        ret = SIM_ABSENT;
+        goto done;
+    }
+
+    at_response_free(p_response);
+    p_response = NULL;
+    cpinResult = NULL;
+
+    ret = (sState == RADIO_STATE_ON) ? SIM_READY : SIM_NOT_READY;
+
+done:
+    at_response_free(p_response);
+    return ret;
+}
+
+static void getIccId(char *iccid, int size) {
+    int err = 0;
+    ATResponse *p_response = NULL;
+
+    if (iccid == NULL) {
+        RLOGE("iccid buffer is null");
+        return;
+    }
+    err = at_send_command_numeric("AT+CICCID", &p_response);
+    if (err < 0 || p_response->success == 0) {
+        goto error;
+    }
+
+    snprintf(iccid, size, "%s", p_response->p_intermediates->line);
+
+error:
+    at_response_free(p_response);
+}
+
+/**
+ * Get the current card status.
+ *
+ * This must be freed using freeCardStatus.
+ * @return: On success returns RIL_E_SUCCESS
+ */
+static int getCardStatus(RIL_CardStatus_v1_5 **pp_card_status) {
+    static RIL_AppStatus app_status_array[] = {
+        // SIM_ABSENT = 0
+        { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // SIM_NOT_READY = 1
+        { RIL_APPTYPE_USIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // SIM_READY = 2
+        { RIL_APPTYPE_USIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // SIM_PIN = 3
+        { RIL_APPTYPE_USIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+        // SIM_PUK = 4
+        { RIL_APPTYPE_USIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
+        // SIM_NETWORK_PERSONALIZATION = 5
+        { RIL_APPTYPE_USIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+        // RUIM_ABSENT = 6
+        { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // RUIM_NOT_READY = 7
+        { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // RUIM_READY = 8
+        { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // RUIM_PIN = 9
+        { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+        // RUIM_PUK = 10
+        { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
+        // RUIM_NETWORK_PERSONALIZATION = 11
+        { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
+           NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+        // ISIM_ABSENT = 12
+        { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // ISIM_NOT_READY = 13
+        { RIL_APPTYPE_ISIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // ISIM_READY = 14
+        { RIL_APPTYPE_ISIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // ISIM_PIN = 15
+        { RIL_APPTYPE_ISIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+        // ISIM_PUK = 16
+        { RIL_APPTYPE_ISIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
+        // ISIM_NETWORK_PERSONALIZATION = 17
+        { RIL_APPTYPE_ISIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
+          NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+
+    };
+    RIL_CardState card_state;
+    int num_apps;
+
+    int sim_status = getSIMStatus();
+    if (sim_status == SIM_ABSENT) {
+        card_state = RIL_CARDSTATE_ABSENT;
+        num_apps = 0;
+    } else {
+        card_state = RIL_CARDSTATE_PRESENT;
+        num_apps = 3;
+    }
+
+    // Allocate and initialize base card status.
+    RIL_CardStatus_v1_5 *p_card_status = calloc(1, sizeof(RIL_CardStatus_v1_5));
+    p_card_status->base.base.base.card_state = card_state;
+    p_card_status->base.base.base.universal_pin_state = RIL_PINSTATE_UNKNOWN;
+    p_card_status->base.base.base.gsm_umts_subscription_app_index = -1;
+    p_card_status->base.base.base.cdma_subscription_app_index = -1;
+    p_card_status->base.base.base.ims_subscription_app_index = -1;
+    p_card_status->base.base.base.num_applications = num_apps;
+    p_card_status->base.base.physicalSlotId = 0;
+    p_card_status->base.base.atr = NULL;
+    p_card_status->base.base.iccid = NULL;
+    p_card_status->base.eid = "";
+    if (sim_status != SIM_ABSENT) {
+        p_card_status->base.base.iccid = (char *)calloc(64, sizeof(char));
+        getIccId(p_card_status->base.base.iccid, 64);
+    }
+
+    // Initialize application status
+    int i;
+    for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
+        p_card_status->base.base.base.applications[i] = app_status_array[SIM_ABSENT];
+    }
+    RLOGD("enter getCardStatus module, num_apps= %d",num_apps);
+    // Pickup the appropriate application status
+    // that reflects sim_status for gsm.
+    if (num_apps != 0) {
+        p_card_status->base.base.base.num_applications = 3;
+        p_card_status->base.base.base.gsm_umts_subscription_app_index = 0;
+        p_card_status->base.base.base.cdma_subscription_app_index = 1;
+        p_card_status->base.base.base.ims_subscription_app_index = 2;
+
+        // Get the correct app status
+        p_card_status->base.base.base.applications[0] = app_status_array[sim_status];
+        p_card_status->base.base.base.applications[1] = app_status_array[sim_status + RUIM_ABSENT];
+        p_card_status->base.base.base.applications[2] = app_status_array[sim_status + ISIM_ABSENT];
+    }
+
+    *pp_card_status = p_card_status;
+    return RIL_E_SUCCESS;
+}
+
+/**
+ * Free the card status returned by getCardStatus
+ */
+static void freeCardStatus(RIL_CardStatus_v1_5 *p_card_status) {
+    if (p_card_status == NULL) {
+        return;
+    }
+    free(p_card_status->base.base.iccid);
+    free(p_card_status);
+}
+
+/**
+ * SIM ready means any commands that access the SIM will work, including:
+ *  AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
+ *  (all SMS-related commands)
+ */
+
+static void pollSIMState (void *param __unused)
+{
+    ATResponse *p_response;
+    int ret;
+
+    if (sState != RADIO_STATE_UNAVAILABLE) {
+        // no longer valid to poll
+        return;
+    }
+
+    switch(getSIMStatus()) {
+        case SIM_ABSENT:
+        case SIM_PIN:
+        case SIM_PUK:
+        case SIM_NETWORK_PERSONALIZATION:
+        default:
+            RLOGI("SIM ABSENT or LOCKED");
+            RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
+        return;
+
+        case SIM_NOT_READY:
+            RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
+        return;
+
+        case SIM_READY:
+            RLOGI("SIM_READY");
+            onSIMReady();
+            RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
+        return;
+    }
+}
+
+/** returns 1 if on, 0 if off, and -1 on error */
+static int isRadioOn()
+{
+    ATResponse *p_response = NULL;
+    int err;
+    char *line;
+    char ret;
+
+    err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
+
+    if (err < 0 || p_response->success == 0) {
+        // assume radio is off
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextbool(&line, &ret);
+    if (err < 0) goto error;
+
+    at_response_free(p_response);
+
+    return (int)ret;
+
+error:
+
+    at_response_free(p_response);
+    return -1;
+}
+
+/**
+ * Parse the response generated by a +CTEC AT command
+ * The values read from the response are stored in current and preferred.
+ * Both current and preferred may be null. The corresponding value is ignored in that case.
+ *
+ * @return: -1 if some error occurs (or if the modem doesn't understand the +CTEC command)
+ *          1 if the response includes the current technology only
+ *          0 if the response includes both current technology and preferred mode
+ */
+int parse_technology_response( const char *response, int *current, int32_t *preferred )
+{
+    int err;
+    char *line, *p;
+    int ct;
+    int32_t pt = 0;
+    char *str_pt;
+
+    line = p = strdup(response);
+    RLOGD("Response: %s", line);
+    err = at_tok_start(&p);
+    if (err || !at_tok_hasmore(&p)) {
+        RLOGD("err: %d. p: %s", err, p);
+        free(line);
+        return -1;
+    }
+
+    err = at_tok_nextint(&p, &ct);
+    if (err) {
+        free(line);
+        return -1;
+    }
+    if (current) *current = ct;
+
+    RLOGD("line remaining after int: %s", p);
+
+    err = at_tok_nexthexint(&p, &pt);
+    if (err) {
+        free(line);
+        return 1;
+    }
+    if (preferred) {
+        *preferred = pt;
+    }
+    free(line);
+
+    return 0;
+}
+
+int query_supported_techs( ModemInfo *mdm __unused, int *supported )
+{
+    ATResponse *p_response;
+    int err, val, techs = 0;
+    char *tok;
+    char *line;
+
+    RLOGD("query_supported_techs");
+    err = at_send_command_singleline("AT+CTEC=?", "+CTEC:", &p_response);
+    if (err || !p_response->success)
+        goto error;
+    line = p_response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err || !at_tok_hasmore(&line))
+        goto error;
+    while (!at_tok_nextint(&line, &val)) {
+        techs |= ( 1 << val );
+    }
+    if (supported) *supported = techs;
+    return 0;
+error:
+    at_response_free(p_response);
+    return -1;
+}
+
+/**
+ * query_ctec. Send the +CTEC AT command to the modem to query the current
+ * and preferred modes. It leaves values in the addresses pointed to by
+ * current and preferred. If any of those pointers are NULL, the corresponding value
+ * is ignored, but the return value will still reflect if retrieving and parsing of the
+ * values succeeded.
+ *
+ * @mdm Currently unused
+ * @current A pointer to store the current mode returned by the modem. May be null.
+ * @preferred A pointer to store the preferred mode returned by the modem. May be null.
+ * @return -1 on error (or failure to parse)
+ *         1 if only the current mode was returned by modem (or failed to parse preferred)
+ *         0 if both current and preferred were returned correctly
+ */
+int query_ctec(ModemInfo *mdm __unused, int *current, int32_t *preferred)
+{
+    ATResponse *response = NULL;
+    int err;
+    int res;
+
+    RLOGD("query_ctec. current: %p, preferred: %p", current, preferred);
+    err = at_send_command_singleline("AT+CTEC?", "+CTEC:", &response);
+    if (!err && response->success) {
+        res = parse_technology_response(response->p_intermediates->line, current, preferred);
+        at_response_free(response);
+        return res;
+    }
+    RLOGE("Error executing command: %d. response: %p. status: %d", err, response, response? response->success : -1);
+    at_response_free(response);
+    return -1;
+}
+
+int is_multimode_modem(ModemInfo *mdm)
+{
+    ATResponse *response;
+    int err;
+    char *line;
+    int tech;
+    int32_t preferred;
+
+    if (query_ctec(mdm, &tech, &preferred) == 0) {
+        mdm->currentTech = tech;
+        mdm->preferredNetworkMode = preferred;
+        if (query_supported_techs(mdm, &mdm->supportedTechs)) {
+            return 0;
+        }
+        return 1;
+    }
+    return 0;
+}
+
+/**
+ * Find out if our modem is GSM, CDMA or both (Multimode)
+ */
+static void probeForModemMode(ModemInfo *info)
+{
+    ATResponse *response;
+    int err;
+    assert (info);
+    // Currently, our only known multimode modem is qemu's android modem,
+    // which implements the AT+CTEC command to query and set mode.
+    // Try that first
+
+    if (is_multimode_modem(info)) {
+        RLOGI("Found Multimode Modem. Supported techs mask: %8.8x. Current tech: %d",
+            info->supportedTechs, info->currentTech);
+        return;
+    }
+
+    /* Being here means that our modem is not multimode */
+    info->isMultimode = 0;
+
+    /* CDMA Modems implement the AT+WNAM command */
+    err = at_send_command_singleline("AT+WNAM","+WNAM:", &response);
+    if (!err && response->success) {
+        at_response_free(response);
+        // TODO: find out if we really support EvDo
+        info->supportedTechs = MDM_CDMA | MDM_EVDO;
+        info->currentTech = MDM_CDMA;
+        RLOGI("Found CDMA Modem");
+        return;
+    }
+    if (!err) at_response_free(response);
+    // TODO: find out if modem really supports WCDMA/LTE
+    info->supportedTechs = MDM_GSM | MDM_WCDMA | MDM_LTE;
+    info->currentTech = MDM_GSM;
+    RLOGI("Found GSM Modem");
+}
+
+/**
+ * Initialize everything that can be configured while we're still in
+ * AT+CFUN=0
+ */
+static void initializeCallback(void *param __unused)
+{
+    ATResponse *p_response = NULL;
+    int err;
+
+    setRadioState (RADIO_STATE_OFF);
+
+    at_handshake();
+
+    probeForModemMode(sMdmInfo);
+    /* note: we don't check errors here. Everything important will
+       be handled in onATTimeout and onATReaderClosed */
+
+    /*  atchannel is tolerant of echo but it must */
+    /*  have verbose result codes */
+    at_send_command("ATE0Q0V1", NULL);
+
+    /*  No auto-answer */
+    at_send_command("ATS0=0", NULL);
+
+    /*  Extended errors */
+    at_send_command("AT+CMEE=1", NULL);
+
+    /*  Network registration events */
+    err = at_send_command("AT+CREG=2", &p_response);
+
+    /* some handsets -- in tethered mode -- don't support CREG=2 */
+    if (err < 0 || p_response->success == 0) {
+        at_send_command("AT+CREG=1", NULL);
+    }
+
+    at_response_free(p_response);
+
+    /*  GPRS registration events */
+    at_send_command("AT+CGREG=1", NULL);
+
+    /*  Call Waiting notifications */
+    at_send_command("AT+CCWA=1", NULL);
+
+    /*  Alternating voice/data off */
+    at_send_command("AT+CMOD=0", NULL);
+
+    /*  Not muted */
+    at_send_command("AT+CMUT=0", NULL);
+
+    /*  +CSSU unsolicited supp service notifications */
+    at_send_command("AT+CSSN=0,1", NULL);
+
+    /*  no connected line identification */
+    at_send_command("AT+COLP=0", NULL);
+
+    /*  HEX character set */
+    at_send_command("AT+CSCS=\"HEX\"", NULL);
+
+    /*  USSD unsolicited */
+    at_send_command("AT+CUSD=1", NULL);
+
+    /*  Enable +CGEV GPRS event notifications, but don't buffer */
+    at_send_command("AT+CGEREP=1,0", NULL);
+
+    /*  SMS PDU mode */
+    at_send_command("AT+CMGF=0", NULL);
+
+#ifdef USE_TI_COMMANDS
+
+    at_send_command("AT%CPI=3", NULL);
+
+    /*  TI specific -- notifications when SMS is ready (currently ignored) */
+    at_send_command("AT%CSTAT=1", NULL);
+
+#endif /* USE_TI_COMMANDS */
+
+
+    /* assume radio is off on error */
+    if (isRadioOn() > 0) {
+        setRadioState (RADIO_STATE_ON);
+    }
+}
+
+static void waitForClose()
+{
+    pthread_mutex_lock(&s_state_mutex);
+
+    while (s_closed == 0) {
+        pthread_cond_wait(&s_state_cond, &s_state_mutex);
+    }
+
+    pthread_mutex_unlock(&s_state_mutex);
+}
+
+static void sendUnsolImsNetworkStateChanged()
+{
+#if 0 // to be used when unsol is changed to return data.
+    int reply[2];
+    reply[0] = s_ims_registered;
+    reply[1] = s_ims_services;
+    reply[1] = s_ims_format;
+#endif
+    RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED,
+            NULL, 0);
+}
+
+static int parseProactiveCmdInd(char *response) {
+    int typePos = 0;
+    int cmdType = 0;
+    char tempStr[3] = {0};
+    char *end = NULL;
+    StkUnsolEvent ret = STK_UNSOL_EVENT_UNKNOWN;
+
+    if (response == NULL || strlen(response) < 3) {
+      return ret;
+    }
+
+    if (response[2] <= '7') {
+       typePos = 10;
+    } else {
+       typePos = 12;
+    }
+
+    if ((int)strlen(response) < typePos + 1) {
+      return ret;
+    }
+
+    memcpy(tempStr, &(response[typePos]), 2);
+    cmdType = strtoul(tempStr, &end, 16);
+    cmdType = 0xFF & cmdType;
+    RLOGD("cmdType: %d",cmdType);
+
+    switch (cmdType) {
+       case STK_RUN_AT:
+       case STK_SEND_DTMF:
+       case STK_SEND_SMS:
+       case STK_SEND_SS:
+       case STK_SEND_USSD:
+       case STK_PLAY_TONE:
+       case STK_CLOSE_CHANNEL:
+           ret = STK_UNSOL_EVENT_NOTIFY;
+           break;
+       case STK_REFRESH:
+           if (strncasecmp(&(response[typePos + 2]), "04", 2) == 0) {  // SIM_RESET
+               RLOGD("Type of Refresh is SIM_RESET");
+               s_stkServiceRunning = false;
+               ret = STK_UNSOL_PROACTIVE_CMD;
+           } else {
+               ret = STK_UNSOL_EVENT_NOTIFY;
+           }
+           break;
+       default:
+           ret = STK_UNSOL_PROACTIVE_CMD;
+           break;
+    }
+
+    if (getSIMStatus() == SIM_ABSENT && s_stkServiceRunning) {
+        s_stkServiceRunning = false;
+    }
+
+    if (false == s_stkServiceRunning) {
+        ret = STK_UNSOL_EVENT_UNKNOWN;
+        s_stkUnsolResponse = (char *)calloc((strlen(response) + 1), sizeof(char));
+        snprintf(s_stkUnsolResponse, strlen(response) + 1, "%s", response);
+        RLOGD("STK service is not running [%s]", s_stkUnsolResponse);
+    }
+
+    return ret;
+}
+
+/**
+ * Called by atchannel when an unsolicited line appears
+ * This is called on atchannel's reader thread. AT commands may
+ * not be issued here
+ */
+static void onUnsolicited (const char *s, const char *sms_pdu)
+{
+    char *line = NULL, *p;
+    int err;
+
+    /* Ignore unsolicited responses until we're initialized.
+     * This is OK because the RIL library will poll for initial state
+     */
+    if (sState == RADIO_STATE_UNAVAILABLE) {
+        return;
+    }
+
+#define  CGFPCCFG "%CGFPCCFG:"
+    if (strStartsWith(s, CGFPCCFG)) {
+        /* cuttlefish/goldfish specific
+        */
+        char *response;
+        line = p = strdup(s);
+        RLOGD("got CGFPCCFG line %s and %s\n", s, p);
+        err = at_tok_start(&line);
+        if(err) {
+            RLOGE("invalid CGFPCCFG line %s and %s\n", s, p);
+        }
+#define kSize 5
+        int configs[kSize];
+        for (int i=0; i < kSize && !err; ++i) {
+            err = at_tok_nextint(&line, &(configs[i]));
+            RLOGD("got i %d, val = %d", i, configs[i]);
+        }
+        if(err) {
+            RLOGE("invalid CGFPCCFG line %s and %s\n", s, p);
+        } else {
+            int modem_tech = configs[2];
+            configs[2] = techFromModemType(modem_tech);
+            RIL_onUnsolicitedResponse (
+                RIL_UNSOL_PHYSICAL_CHANNEL_CONFIGS,
+                configs, kSize);
+        }
+        free(p);
+    } else if (strStartsWith(s, "%CTZV:")) {
+        /* TI specific -- NITZ time */
+        char *response;
+
+        line = p = strdup(s);
+        at_tok_start(&p);
+
+        err = at_tok_nextstr(&p, &response);
+
+        if (err != 0) {
+            RLOGE("invalid NITZ line %s\n", s);
+        } else {
+            RIL_onUnsolicitedResponse (
+                RIL_UNSOL_NITZ_TIME_RECEIVED,
+                response, strlen(response) + 1);
+        }
+        free(line);
+    } else if (strStartsWith(s,"+CRING:")
+                || strStartsWith(s,"RING")
+                || strStartsWith(s,"NO CARRIER")
+                || strStartsWith(s,"+CCWA")
+    ) {
+        RIL_onUnsolicitedResponse (
+            RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
+            NULL, 0);
+#ifdef WORKAROUND_FAKE_CGEV
+        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
+#endif /* WORKAROUND_FAKE_CGEV */
+    } else if (strStartsWith(s,"+CREG:")
+                || strStartsWith(s,"+CGREG:")
+    ) {
+        RIL_onUnsolicitedResponse (
+            RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
+            NULL, 0);
+#ifdef WORKAROUND_FAKE_CGEV
+        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
+#endif /* WORKAROUND_FAKE_CGEV */
+    } else if (strStartsWith(s, "+CMT:")) {
+        RIL_onUnsolicitedResponse (
+            RIL_UNSOL_RESPONSE_NEW_SMS,
+            sms_pdu, strlen(sms_pdu));
+    } else if (strStartsWith(s, "+CDS:")) {
+        RIL_onUnsolicitedResponse (
+            RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
+            sms_pdu, strlen(sms_pdu));
+    } else if (strStartsWith(s, "+CGEV:")) {
+        /* Really, we can ignore NW CLASS and ME CLASS events here,
+         * but right now we don't since extranous
+         * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
+         */
+        /* can't issue AT commands here -- call on main thread */
+        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
+#ifdef WORKAROUND_FAKE_CGEV
+    } else if (strStartsWith(s, "+CME ERROR: 150")) {
+        RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
+#endif /* WORKAROUND_FAKE_CGEV */
+    } else if (strStartsWith(s, "+CTEC: ")) {
+        int tech, mask;
+        switch (parse_technology_response(s, &tech, NULL))
+        {
+            case -1: // no argument could be parsed.
+                RLOGE("invalid CTEC line %s\n", s);
+                break;
+            case 1: // current mode correctly parsed
+            case 0: // preferred mode correctly parsed
+                mask = 1 << tech;
+                if (mask != MDM_GSM && mask != MDM_CDMA &&
+                     mask != MDM_WCDMA && mask != MDM_LTE) {
+                    RLOGE("Unknown technology %d\n", tech);
+                } else {
+                    setRadioTechnology(sMdmInfo, tech);
+                }
+                break;
+        }
+    } else if (strStartsWith(s, "+CCSS: ")) {
+        int source = 0;
+        line = p = strdup(s);
+        if (!line) {
+            RLOGE("+CCSS: Unable to allocate memory");
+            return;
+        }
+        if (at_tok_start(&p) < 0) {
+            free(line);
+            return;
+        }
+        if (at_tok_nextint(&p, &source) < 0) {
+            RLOGE("invalid +CCSS response: %s", line);
+            free(line);
+            return;
+        }
+        SSOURCE(sMdmInfo) = source;
+        RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
+                                  &source, sizeof(source));
+        free(line);
+    } else if (strStartsWith(s, "+WSOS: ")) {
+        char state = 0;
+        int unsol;
+        line = p = strdup(s);
+        if (!line) {
+            RLOGE("+WSOS: Unable to allocate memory");
+            return;
+        }
+        if (at_tok_start(&p) < 0) {
+            free(line);
+            return;
+        }
+        if (at_tok_nextbool(&p, &state) < 0) {
+            RLOGE("invalid +WSOS response: %s", line);
+            free(line);
+            return;
+        }
+        free(line);
+
+        unsol = state ?
+                RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE : RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
+
+        RIL_onUnsolicitedResponse(unsol, NULL, 0);
+
+    } else if (strStartsWith(s, "+WPRL: ")) {
+        int version = -1;
+        line = p = strdup(s);
+        if (!line) {
+            RLOGE("+WPRL: Unable to allocate memory");
+            return;
+        }
+        if (at_tok_start(&p) < 0) {
+            RLOGE("invalid +WPRL response: %s", s);
+            free(line);
+            return;
+        }
+        if (at_tok_nextint(&p, &version) < 0) {
+            RLOGE("invalid +WPRL response: %s", s);
+            free(line);
+            return;
+        }
+        free(line);
+        RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_PRL_CHANGED, &version, sizeof(version));
+    } else if (strStartsWith(s, "+CFUN: 0")) {
+        setRadioState(RADIO_STATE_OFF);
+    } else if (strStartsWith(s, "+CSQ: ")) {
+        // Accept a response that is at least v6, and up to v12
+        int minNumOfElements=sizeof(RIL_SignalStrength_v6)/sizeof(int);
+        int maxNumOfElements=sizeof(RIL_SignalStrength_v12)/sizeof(int);
+        int response[maxNumOfElements];
+        memset(response, 0, sizeof(response));
+
+        line = p = strdup(s);
+        at_tok_start(&p);
+
+        for (int count = 0; count < maxNumOfElements; count++) {
+            err = at_tok_nextint(&p, &(response[count]));
+            if (err < 0 && count < minNumOfElements) {
+              free(line);
+              return;
+            }
+        }
+
+        RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH,
+            response, sizeof(response));
+        free(line);
+    } else if (strStartsWith(s, "+CUSATEND")) {  // session end
+      RIL_onUnsolicitedResponse(RIL_UNSOL_STK_SESSION_END, NULL, 0);
+    } else if (strStartsWith(s, "+CUSATP:")) {
+        line = p = strdup(s);
+        if (!line) {
+            RLOGE("+CUSATP: Unable to allocate memory");
+            return;
+        }
+        if (at_tok_start(&p) < 0) {
+            RLOGE("invalid +CUSATP response: %s", s);
+            free(line);
+            return;
+        }
+
+        char *response = NULL;
+        if (at_tok_nextstr(&p, &response) < 0) {
+            RLOGE("%s fail", s);
+            free(line);
+            return;
+        }
+
+        StkUnsolEvent ret = parseProactiveCmdInd(response);
+        if (ret == STK_UNSOL_EVENT_NOTIFY) {
+            RIL_onUnsolicitedResponse(RIL_UNSOL_STK_EVENT_NOTIFY, response,
+                                      strlen(response) + 1);
+        } else if (ret == STK_UNSOL_PROACTIVE_CMD) {
+            RIL_onUnsolicitedResponse(RIL_UNSOL_STK_PROACTIVE_COMMAND, response,
+                                      strlen(response) + 1);
+        }
+
+        free(line);
+    }
+}
+
+/* Called on command or reader thread */
+static void onATReaderClosed()
+{
+    RLOGI("AT channel closed\n");
+    at_close();
+    s_closed = 1;
+
+    setRadioState (RADIO_STATE_UNAVAILABLE);
+}
+
+/* Called on command thread */
+static void onATTimeout()
+{
+    RLOGI("AT channel timeout; closing\n");
+    at_close();
+
+    s_closed = 1;
+
+    /* FIXME cause a radio reset here */
+
+    setRadioState (RADIO_STATE_UNAVAILABLE);
+}
+
+/* Called to pass hardware configuration information to telephony
+ * framework.
+ */
+static void setHardwareConfiguration(int num, RIL_HardwareConfig *cfg)
+{
+   RIL_onUnsolicitedResponse(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, cfg, num*sizeof(*cfg));
+}
+
+static void usage(char *s __unused)
+{
+#ifdef RIL_SHLIB
+    fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
+#else
+    fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
+    exit(-1);
+#endif
+}
+
+static void *
+mainLoop(void *param __unused)
+{
+    int fd;
+    int ret;
+
+    AT_DUMP("== ", "entering mainLoop()", -1 );
+    at_set_on_reader_closed(onATReaderClosed);
+    at_set_on_timeout(onATTimeout);
+
+    for (;;) {
+        fd = -1;
+        while  (fd < 0) {
+            if (isInEmulator()) {
+                fd = qemu_open_modem_port();
+                RLOGD("opening qemu_modem_port %d!", fd);
+            } else if (s_port > 0) {
+                fd = socket_network_client("localhost", s_port, SOCK_STREAM);
+            } else if (s_modem_simulator_port >= 0) {
+              fd = socket(AF_VSOCK, SOCK_STREAM, 0);
+              if (fd < 0) {
+                 RLOGD("Can't create AF_VSOCK socket!");
+                 continue;
+              }
+              struct sockaddr_vm sa;
+              memset(&sa, 0, sizeof(struct sockaddr_vm));
+              sa.svm_family = AF_VSOCK;
+              sa.svm_cid = VMADDR_CID_HOST;
+              sa.svm_port = s_modem_simulator_port;
+
+              if (connect(fd, (struct sockaddr *)(&sa), sizeof(sa)) < 0) {
+                  RLOGD("Can't connect to port:%ud, errno: %s",
+                      s_modem_simulator_port, strerror(errno));
+                  close(fd);
+                  fd = -1;
+                  continue;
+              }
+            } else if (s_device_socket) {
+                fd = socket_local_client(s_device_path,
+                                         ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
+                                         SOCK_STREAM);
+            } else if (s_device_path != NULL) {
+                fd = open (s_device_path, O_RDWR);
+                if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
+                    /* disable echo on serial ports */
+                    struct termios  ios;
+                    tcgetattr( fd, &ios );
+                    ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
+                    tcsetattr( fd, TCSANOW, &ios );
+                }
+            }
+
+            if (fd < 0) {
+                perror ("opening AT interface. retrying...");
+                sleep(10);
+                /* never returns */
+            }
+        }
+
+        s_closed = 0;
+        ret = at_open(fd, onUnsolicited);
+
+        if (ret < 0) {
+            RLOGE ("AT error %d on at_open\n", ret);
+            return 0;
+        }
+
+        RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
+
+        // Give initializeCallback a chance to dispatched, since
+        // we don't presently have a cancellation mechanism
+        sleep(1);
+
+        waitForClose();
+        RLOGI("Re-opening after close");
+    }
+}
+
+#ifdef RIL_SHLIB
+
+pthread_t s_tid_mainloop;
+
+const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
+{
+    int ret;
+    int fd = -1;
+    int opt;
+    pthread_attr_t attr;
+
+    s_rilenv = env;
+
+    RLOGD("RIL_Init");
+    while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:m:"))) {
+        switch (opt) {
+            case 'p':
+                s_port = atoi(optarg);
+                if (s_port == 0) {
+                    usage(argv[0]);
+                    return NULL;
+                }
+                RLOGI("Opening loopback port %d\n", s_port);
+            break;
+
+            case 'd':
+                s_device_path = optarg;
+                RLOGI("Opening tty device %s\n", s_device_path);
+            break;
+
+            case 's':
+                s_device_path   = optarg;
+                s_device_socket = 1;
+                RLOGI("Opening socket %s\n", s_device_path);
+            break;
+
+            case 'c':
+                RLOGI("Client id received %s\n", optarg);
+            break;
+
+            case 'm':
+              s_modem_simulator_port = strtoul(optarg, NULL, 10);
+              RLOGI("Opening modem simulator port %ud\n", s_modem_simulator_port);
+            break;
+
+            default:
+                usage(argv[0]);
+                return NULL;
+        }
+    }
+
+    if (s_port < 0 && s_device_path == NULL && !isInEmulator() &&
+        s_modem_simulator_port < 0) {
+        usage(argv[0]);
+        return NULL;
+    }
+
+    sMdmInfo = calloc(1, sizeof(ModemInfo));
+    if (!sMdmInfo) {
+        RLOGE("Unable to alloc memory for ModemInfo");
+        return NULL;
+    }
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
+
+    return &s_callbacks;
+}
+#else /* RIL_SHLIB */
+int main (int argc, char **argv)
+{
+    int ret;
+    int fd = -1;
+    int opt;
+
+    while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
+        switch (opt) {
+            case 'p':
+                s_port = atoi(optarg);
+                if (s_port == 0) {
+                    usage(argv[0]);
+                }
+                RLOGI("Opening loopback port %d\n", s_port);
+            break;
+
+            case 'd':
+                s_device_path = optarg;
+                RLOGI("Opening tty device %s\n", s_device_path);
+            break;
+
+            case 's':
+                s_device_path   = optarg;
+                s_device_socket = 1;
+                RLOGI("Opening socket %s\n", s_device_path);
+            break;
+
+            default:
+                usage(argv[0]);
+        }
+    }
+
+    if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
+        usage(argv[0]);
+    }
+
+    RIL_register(&s_callbacks);
+
+    mainLoop(NULL);
+
+    return 0;
+}
+
+#endif /* RIL_SHLIB */
diff --git a/guest/hals/rild/Android.bp b/guest/hals/rild/Android.bp
new file mode 100644
index 0000000..9a7ad01
--- /dev/null
+++ b/guest/hals/rild/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "libcuttlefish-rild",
+    vendor: true,
+    cflags: [
+        "-DRIL_SHLIB",
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    srcs: [
+        "rild_cuttlefish.c",
+    ],
+    include_dirs: [
+        "device/google/cuttlefish",
+        "hardware/ril/include",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libdl",
+        "liblog",
+        "libril-modem-lib",
+    ],
+    init_rc: ["rild_cuttlefish.rc"],
+    relative_install_path: "hw",
+    overrides: ["rild"],
+}
diff --git a/guest/hals/rild/Android.mk b/guest/hals/rild/Android.mk
deleted file mode 100644
index 40e6b10..0000000
--- a/guest/hals/rild/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) 2006 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.
-
-# only for PLATFORM_VERSION greater or equal to Q
-ifeq (true,$(ENABLE_CUTTLEFISH_RILD))
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    rild_cuttlefish.c
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libdl \
-    liblog \
-    libril-cuttlefish-fork
-
-LOCAL_C_INCLUDES += \
-    device/google/cuttlefish
-
-# Temporary hack for broken vendor RILs.
-LOCAL_WHOLE_STATIC_LIBRARIES := \
-    librilutils
-
-LOCAL_CFLAGS := -DRIL_SHLIB
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE:= libcuttlefish-rild
-LOCAL_OVERRIDES_PACKAGES := rild
-PACKAGES.$(LOCAL_MODULE).OVERRIDES := rild
-LOCAL_INIT_RC := rild_cuttlefish.rc
-
-include $(BUILD_EXECUTABLE)
-endif
diff --git a/guest/hals/rild/rild_cuttlefish.c b/guest/hals/rild/rild_cuttlefish.c
index cfd74fa..49f34ec 100644
--- a/guest/hals/rild/rild_cuttlefish.c
+++ b/guest/hals/rild/rild_cuttlefish.c
@@ -24,7 +24,7 @@
 #include <fcntl.h>
 #include <errno.h>
 
-#include <guest/hals/ril/libril/ril.h>
+#include <guest/hals/ril/reference-libril/ril.h>
 
 #define LOG_TAG "RILD"
 #include <log/log.h>
@@ -34,9 +34,8 @@
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <guest/hals/ril/libril/ril_ex.h>
+#include <guest/hals/ril/reference-libril/ril_ex.h>
 
-#define LIB_PATH_PROPERTY   "vendor.rild.libpath"
 #define LIB_ARGS_PROPERTY   "vendor.rild.libargs"
 #define MAX_LIB_ARGS        16
 
@@ -109,10 +108,9 @@
 
     // functions returned by ril init function in vendor ril
     const RIL_RadioFunctions *funcs;
-    // lib path from rild.libpath property (if it's read)
-    char libPath[PROPERTY_VALUE_MAX];
     // flat to indicate if -- parameters are present
     unsigned char hasLibArgs = 0;
+    char port[PROPERTY_VALUE_MAX] = {0};
 
     int i;
     // ril/socket id received as -c parameter, otherwise set to 0
@@ -149,14 +147,12 @@
                  clientId);
     }
 
-    if (rilLibPath == NULL) {
-        if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
-            // No lib sepcified on the command line, and nothing set in props.
-            // Assume "no-ril" case.
-            goto done;
-        } else {
-            rilLibPath = libPath;
-        }
+    property_get("ro.boot.modem_simulator_ports", port, "");
+    if (strcmp(port, "") == 0) {
+      // Assume "no-ril" case.
+      goto done;
+    } else {
+      rilLibPath = "libcuttlefish-ril-2.so";
     }
 
     dlHandle = dlopen(rilLibPath, RTLD_NOW);
@@ -203,6 +199,11 @@
     rilArgv[argc++] = (char*)clientId;
     RLOGD("RIL_Init argc = %d clientId = %s", argc, rilArgv[argc-1]);
 
+    if (strcmp(port, "")) {
+      rilArgv[argc++] = "-m";
+      rilArgv[argc++] = port;
+    }
+
     // Make sure there's a reasonable argv[0]
     rilArgv[0] = argv[0];
 
diff --git a/guest/hals/rild/rild_cuttlefish.legacy.rc b/guest/hals/rild/rild_cuttlefish.legacy.rc
deleted file mode 100644
index e9c2d07..0000000
--- a/guest/hals/rild/rild_cuttlefish.legacy.rc
+++ /dev/null
@@ -1,5 +0,0 @@
-service ril-daemon /vendor/bin/hw/libcuttlefish-rild
-    class main
-    user radio
-    group radio cache inet misc audio log readproc wakelock
-    capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW
diff --git a/guest/hals/rild/rild_cuttlefish.rc b/guest/hals/rild/rild_cuttlefish.rc
index 9990a7a..5757e9a 100644
--- a/guest/hals/rild/rild_cuttlefish.rc
+++ b/guest/hals/rild/rild_cuttlefish.rc
@@ -1,5 +1,5 @@
 service vendor.ril-daemon /vendor/bin/hw/libcuttlefish-rild
     class main
     user radio
-    group radio cache inet misc audio log readproc wakelock
+    group radio inet misc audio log readproc wakelock
     capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW
diff --git a/guest/libs/Android.mk b/guest/libs/Android.mk
new file mode 100644
index 0000000..428f4b5
--- /dev/null
+++ b/guest/libs/Android.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2021 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/guest/libs/wpa_supplicant_8_lib/Android.mk b/guest/libs/wpa_supplicant_8_lib/Android.mk
new file mode 100644
index 0000000..31179f5
--- /dev/null
+++ b/guest/libs/wpa_supplicant_8_lib/Android.mk
@@ -0,0 +1,82 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(WPA_SUPPLICANT_VERSION),VER_0_8_X)
+
+ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
+  CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
+endif
+
+# Use a custom libnl on releases before N
+ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?))
+EXTERNAL_VSOC_LIBNL_INCLUDE := external/gce/libnl/include
+else
+EXTERNAL_VSOC_LIBNL_INCLUDE :=
+endif
+
+
+WPA_SUPPL_DIR = external/wpa_supplicant_8
+WPA_SRC_FILE :=
+
+include $(WPA_SUPPL_DIR)/wpa_supplicant/android.config
+
+WPA_SUPPL_DIR_INCLUDE = $(WPA_SUPPL_DIR)/src \
+	$(WPA_SUPPL_DIR)/src/common \
+	$(WPA_SUPPL_DIR)/src/drivers \
+	$(WPA_SUPPL_DIR)/src/l2_packet \
+	$(WPA_SUPPL_DIR)/src/utils \
+	$(WPA_SUPPL_DIR)/src/wps \
+	$(WPA_SUPPL_DIR)/wpa_supplicant \
+	$(EXTERNAL_VSOC_LIBNL_INCLUDE)
+
+WPA_SUPPL_DIR_INCLUDE += external/libnl/include
+
+ifdef CONFIG_DRIVER_NL80211
+WPA_SRC_FILE += driver_cmd_nl80211.c
+endif
+
+ifeq ($(TARGET_ARCH),arm)
+# To force sizeof(enum) = 4
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := lib_driver_cmd_simulated_cf
+LOCAL_VENDOR_MODULE := true
+LOCAL_SHARED_LIBRARIES := libc libcutils
+
+LOCAL_CFLAGS := $(L_CFLAGS) \
+    $(VSOC_VERSION_CFLAGS)
+
+LOCAL_SRC_FILES := $(WPA_SRC_FILE)
+
+LOCAL_C_INCLUDES := \
+  device/google/cuttlefish_common \
+  $(WPA_SUPPL_DIR_INCLUDE)\
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+include $(BUILD_STATIC_LIBRARY)
+
+########################
+
+endif
diff --git a/guest/libs/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/guest/libs/wpa_supplicant_8_lib/driver_cmd_nl80211.c
new file mode 100644
index 0000000..7181498
--- /dev/null
+++ b/guest/libs/wpa_supplicant_8_lib/driver_cmd_nl80211.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+/*
+ * Driver interaction with extended Linux CFG8021
+ */
+
+#include "driver_cmd_nl80211.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <netinet/in.h>
+#include "driver_nl80211.h"
+
+#include "android_drv.h"
+#include "common.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+
+int wpa_driver_nl80211_driver_cmd(void* priv, char* cmd, char* buf,
+                                  size_t buf_len) {
+  struct i802_bss* bss = priv;
+  struct wpa_driver_nl80211_data* drv = bss->drv;
+  struct ifreq ifr;
+  android_wifi_priv_cmd priv_cmd;
+  int ret = 0;
+
+  D("%s: called", __FUNCTION__);
+  if (os_strcasecmp(cmd, "STOP") == 0) {
+    linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+    wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
+  } else if (os_strcasecmp(cmd, "START") == 0) {
+    linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
+    wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
+  } else if (os_strcasecmp(cmd, "MACADDR") == 0) {
+    u8 macaddr[ETH_ALEN] = {};
+
+    ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr);
+    if (!ret)
+      ret =
+          os_snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr));
+  } else if (os_strcasecmp(cmd, "RELOAD") == 0) {
+    wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+  } else {  // Use private command
+    return 0;
+  }
+  return ret;
+}
+
+int wpa_driver_set_p2p_noa(void* priv, u8 count, int start, int duration) {
+  D("%s: called", __FUNCTION__);
+  return 0;
+}
+
+int wpa_driver_get_p2p_noa(void* priv, u8* buf, size_t len) {
+  D("%s: called", __FUNCTION__);
+  return 0;
+}
+
+int wpa_driver_set_p2p_ps(void* priv, int legacy_ps, int opp_ps, int ctwindow) {
+  D("%s: called", __FUNCTION__);
+  return -1;
+}
+
+int wpa_driver_set_ap_wps_p2p_ie(void* priv, const struct wpabuf* beacon,
+                                 const struct wpabuf* proberesp,
+                                 const struct wpabuf* assocresp) {
+  D("%s: called", __FUNCTION__);
+  return 0;
+}
diff --git a/guest/libs/wpa_supplicant_8_lib/driver_cmd_nl80211.h b/guest/libs/wpa_supplicant_8_lib/driver_cmd_nl80211.h
new file mode 100644
index 0000000..0970a63
--- /dev/null
+++ b/guest/libs/wpa_supplicant_8_lib/driver_cmd_nl80211.h
@@ -0,0 +1,40 @@
+#pragma once
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <linux/if_ether.h>
+#include <memory.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "linux_ioctl.h"
+#include "wpa_supplicant_i.h"
+
+#define VSOC_WPA_SUPPLICANT_DEBUG 0
+
+#if VSOC_WPA_SUPPLICANT_DEBUG
+#define D(...) ALOGD(__VA_ARGS__)
+#else
+#define D(...) ((void)0)
+#endif
+
+typedef struct android_wifi_priv_cmd {
+  char* buf;
+  int used_len;
+  int total_len;
+} android_wifi_priv_cmd;
diff --git a/guest/monitoring/Android.bp b/guest/monitoring/Android.bp
deleted file mode 100644
index a7f69c0..0000000
--- a/guest/monitoring/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "dumpstate_ext",
-    "tombstone_transmit",
-]
diff --git a/guest/monitoring/cuttlefish_service/Android.bp b/guest/monitoring/cuttlefish_service/Android.bp
new file mode 100644
index 0000000..133d233
--- /dev/null
+++ b/guest/monitoring/cuttlefish_service/Android.bp
@@ -0,0 +1,30 @@
+// Copyright 2020 Google Inc. All Rights Reserved.
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "CuttlefishService",
+    vendor: true,
+    srcs: ["java/**/*.java"],
+    static_libs: ["guava"],
+    sdk_version: "28",
+    privileged: true,
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+        enabled: true,
+    }
+}
diff --git a/guest/monitoring/cuttlefish_service/Android.mk b/guest/monitoring/cuttlefish_service/Android.mk
deleted file mode 100644
index b08adaf..0000000
--- a/guest/monitoring/cuttlefish_service/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-LOCAL_STATIC_JAVA_LIBRARIES := guava
-LOCAL_PACKAGE_NAME := CuttlefishService
-LOCAL_SDK_VERSION := 28
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_PROGUARD_FLAGS := -include build/core/proguard.flags
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_PROGUARD_ENABLED := obfuscation
-LOCAL_VENDOR_MODULE := true
-
-include $(BUILD_PACKAGE)
diff --git a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/BootReporter.java b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/BootReporter.java
deleted file mode 100644
index b866b35..0000000
--- a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/BootReporter.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-package com.android.google.gce.gceservice;
-
-import android.os.Handler;
-import android.util.Log;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-
-/**
- * Report boot status to console.
- *
- * This class sends messages to kernel log (and serial console) directly by
- * writing to /dev/kmsg.
- */
-public class BootReporter extends JobBase {
-    private static final String LOG_TAG = "GceBootReporter";
-    private static final int KLOG_NOTICE = 5;
-    private static final String KLOG_OUTPUT = "/dev/kmsg";
-    private static final String KLOG_FORMAT = "<%d>%s: %s\n";
-    private static final String VIRTUAL_DEVICE_BOOT_STARTED = "VIRTUAL_DEVICE_BOOT_STARTED";
-    private static final String VIRTUAL_DEVICE_BOOT_PENDING = "VIRTUAL_DEVICE_BOOT_PENDING";
-    private static final String VIRTUAL_DEVICE_BOOT_COMPLETED = "VIRTUAL_DEVICE_BOOT_COMPLETED";
-    private static final String VIRTUAL_DEVICE_BOOT_FAILED = "VIRTUAL_DEVICE_BOOT_FAILED";
-    private FileOutputStream mKmsgStream = null;
-    private PrintWriter mKmsgWriter = null;
-    private List<String> mMessageList = new ArrayList<String>();
-
-
-    /** Constructor. */
-    public BootReporter() {
-        super(LOG_TAG);
-
-        try {
-            mKmsgStream = new FileOutputStream(KLOG_OUTPUT);
-            mKmsgWriter = new PrintWriter(mKmsgStream);
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Could not open output stream.", e);
-        }
-    }
-
-
-    /** Report boot failure.
-     *
-     * Send message to kernel log and serial console explaining boot failure.
-     */
-    @Override
-    public void onDependencyFailed(Exception e) {
-        reportMessage(String.format("%s: %s", VIRTUAL_DEVICE_BOOT_FAILED, e.getMessage()));
-    }
-
-
-    /** Report straggling jobs.
-     *
-     * Reports boot pending, if any of the parent jobs is still awaiting completion
-     * and reschedules itself for re-execution.
-     *
-     * If all jobs have completed, reports boot completed and stops.
-     */
-    @Override
-    public void onDependencyStraggling(ArrayList<GceFuture<?>> deps) {
-        reportMessage(String.format("%s: %s", VIRTUAL_DEVICE_BOOT_PENDING,
-                    GceFuture.toString(deps)));
-    }
-
-
-    /** Report successful boot completion.
-     *
-     * Issue message to serial port confirming successful boot completion and
-     * custom boot completion message, if specified by the user prior to reboot.
-     */
-    @Override
-    public int execute() {
-        // We suspect that something is throttling our messages and preventing
-        // the following message from being logged to bugreport.
-        // The log is present in logcat log (that we collect independently), yet
-        // occasionally most of the GCEService logs never make it to show up on
-        // bug report.
-        // This may or may not prove to be effective. We need to monitor bugreports
-        // for VIRTUAL_DEVICE_BOOT_COMPLETED messages are being dropped.
-        //
-        // Number chosen at random - yet guaranteed to be prime.
-        try {
-            Thread.sleep(937);
-        } catch (InterruptedException e) {}
-
-        reportMessage(VIRTUAL_DEVICE_BOOT_COMPLETED);
-        return 0;
-    }
-
-
-    public void reportMessage(String message) {
-        Log.i(LOG_TAG, message);
-        mKmsgWriter.printf(KLOG_FORMAT, KLOG_NOTICE, LOG_TAG, message);
-        mKmsgWriter.flush();
-        DateFormat df = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
-        String date = df.format(Calendar.getInstance().getTime());
-        mMessageList.add("[" + date + "] "  + message);
-    }
-
-
-    public void reportBootStarted() {
-        reportMessage(VIRTUAL_DEVICE_BOOT_STARTED);
-    }
-
-    /** Get the list of reported messages so far.
-     */
-    public List<String> getMessageList() {
-      return mMessageList;
-    }
-}
diff --git a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java
index 1354021..43f4e3b 100644
--- a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java
+++ b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java
@@ -28,17 +28,20 @@
     private static final String LOG_TAG = "GceConnChecker";
     private static final String MOBILE_NETWORK_CONNECTED_MESSAGE =
         "VIRTUAL_DEVICE_NETWORK_MOBILE_CONNECTED";
+    private static final String ETHERNET_NETWORK_CONNECTED_MESSAGE =
+        "VIRTUAL_DEVICE_NETWORK_ETHERNET_CONNECTED";
 
     private final Context mContext;
-    private final BootReporter mBootReporter;
+    private final EventReporter mEventReporter;
     private final GceFuture<Boolean> mConnected = new GceFuture<Boolean>("Connectivity");
     // TODO(schuffelen): Figure out why this has to be static in order to not report 3 times.
     private static boolean reportedMobileConnectivity = false;
+    private static boolean reportedEthernetConnectivity = false;
 
-    public ConnectivityChecker(Context context, BootReporter bootReporter) {
+    public ConnectivityChecker(Context context, EventReporter eventReporter) {
         super(LOG_TAG);
         mContext = context;
-        mBootReporter = bootReporter;
+        mEventReporter = eventReporter;
     }
 
 
@@ -54,11 +57,16 @@
             NetworkInfo info = connManager.getNetworkInfo(network);
             if (info.isConnected()) {
                 NetworkCapabilities capabilities = connManager.getNetworkCapabilities(network);
-                if (capabilities != null
-                        && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
-                        && !reportedMobileConnectivity) {
-                    mBootReporter.reportMessage(MOBILE_NETWORK_CONNECTED_MESSAGE);
-                    reportedMobileConnectivity = true;
+                if (capabilities != null) {
+                    if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+                            && !reportedMobileConnectivity) {
+                        mEventReporter.reportMessage(MOBILE_NETWORK_CONNECTED_MESSAGE);
+                        reportedMobileConnectivity = true;
+                    } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
+                                   && !reportedEthernetConnectivity) {
+                        mEventReporter.reportMessage(ETHERNET_NETWORK_CONNECTED_MESSAGE);
+                        reportedEthernetConnectivity = true;
+                    }
                 }
             }
         }
diff --git a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/EventReporter.java b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/EventReporter.java
new file mode 100644
index 0000000..5d9b02f
--- /dev/null
+++ b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/EventReporter.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.google.gce.gceservice;
+
+import android.os.Handler;
+import android.util.Log;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+/**
+ * Report virtual device boot status and other messages to console.
+ *
+ * This class sends messages to kernel log (and serial console) directly by
+ * writing to /dev/kmsg.
+ */
+public class EventReporter extends JobBase {
+    private static final String LOG_TAG = "GceEventReporter";
+    private static final int KLOG_NOTICE = 5;
+    private static final String KLOG_OUTPUT = "/dev/kmsg";
+    private static final String KLOG_FORMAT = "<%d>%s: %s\n";
+    private static final String VIRTUAL_DEVICE_BOOT_STARTED = "VIRTUAL_DEVICE_BOOT_STARTED";
+    private static final String VIRTUAL_DEVICE_BOOT_PENDING = "VIRTUAL_DEVICE_BOOT_PENDING";
+    private static final String VIRTUAL_DEVICE_BOOT_COMPLETED = "VIRTUAL_DEVICE_BOOT_COMPLETED";
+    private static final String VIRTUAL_DEVICE_BOOT_FAILED = "VIRTUAL_DEVICE_BOOT_FAILED";
+    private static final String VIRTUAL_DEVICE_SCREEN_CHANGED = "VIRTUAL_DEVICE_SCREEN_CHANGED";
+    private FileOutputStream mKmsgStream = null;
+    private PrintWriter mKmsgWriter = null;
+    private List<String> mMessageList = new ArrayList<String>();
+
+
+    /** Constructor. */
+    public EventReporter() {
+        super(LOG_TAG);
+
+        try {
+            mKmsgStream = new FileOutputStream(KLOG_OUTPUT);
+            mKmsgWriter = new PrintWriter(mKmsgStream);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Could not open output stream.", e);
+        }
+    }
+
+
+    /** Report boot failure.
+     *
+     * Send message to kernel log and serial console explaining boot failure.
+     */
+    @Override
+    public void onDependencyFailed(Exception e) {
+        reportMessage(String.format("%s: %s", VIRTUAL_DEVICE_BOOT_FAILED, e.getMessage()));
+    }
+
+
+    /** Report straggling jobs.
+     *
+     * Reports boot pending, if any of the parent jobs is still awaiting completion
+     * and reschedules itself for re-execution.
+     *
+     * If all jobs have completed, reports boot completed and stops.
+     */
+    @Override
+    public void onDependencyStraggling(ArrayList<GceFuture<?>> deps) {
+        reportMessage(String.format("%s: %s", VIRTUAL_DEVICE_BOOT_PENDING,
+                    GceFuture.toString(deps)));
+    }
+
+
+    /** Report successful boot completion.
+     *
+     * Issue message to serial port confirming successful boot completion and
+     * custom boot completion message, if specified by the user prior to reboot.
+     */
+    @Override
+    public int execute() {
+        // We suspect that something is throttling our messages and preventing
+        // the following message from being logged to bugreport.
+        // The log is present in logcat log (that we collect independently), yet
+        // occasionally most of the GCEService logs never make it to show up on
+        // bug report.
+        // This may or may not prove to be effective. We need to monitor bugreports
+        // for VIRTUAL_DEVICE_BOOT_COMPLETED messages are being dropped.
+        //
+        // Number chosen at random - yet guaranteed to be prime.
+        try {
+            Thread.sleep(937);
+        } catch (InterruptedException e) {}
+
+        reportMessage(VIRTUAL_DEVICE_BOOT_COMPLETED);
+        return 0;
+    }
+
+
+    public void reportMessage(String message) {
+        Log.i(LOG_TAG, message);
+        mKmsgWriter.printf(KLOG_FORMAT, KLOG_NOTICE, LOG_TAG, message);
+        mKmsgWriter.flush();
+        DateFormat df = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+        String date = df.format(Calendar.getInstance().getTime());
+        mMessageList.add("[" + date + "] "  + message);
+    }
+
+
+    public void reportBootStarted() {
+        reportMessage(VIRTUAL_DEVICE_BOOT_STARTED);
+    }
+
+    public void reportScreenChanged(int width, int height, int dpi, int rotation) {
+        reportMessage(String.format("%s width=%d height=%d dpi=%d rotation=%d",
+              VIRTUAL_DEVICE_SCREEN_CHANGED,
+              width, height, dpi, rotation));
+    }
+
+    /** Get the list of reported messages so far.
+     */
+    public List<String> getMessageList() {
+      return mMessageList;
+    }
+}
diff --git a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceService.java b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceService.java
index 8e7bcc5..80d497a 100644
--- a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceService.java
+++ b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceService.java
@@ -23,16 +23,20 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.graphics.Point;
 import android.net.ConnectivityManager;
 import android.util.Log;
 import android.os.IBinder;
+import android.view.Display;
+import android.view.WindowManager;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
 
 /**
  * Service is started by the BootCompletedReceiver at the end of Android Boot process.
- * Responsible for final configuration changes and emitting final BOOT_COMPLETED message.
+ * Responsible for emitting final BOOT_COMPLETED message and continued configuration changes.
  */
 public class GceService extends Service {
     private static final String LOG_TAG = "GceService";
@@ -45,13 +49,19 @@
     private static final int NOTIFICATION_ID = 1;
 
     private final JobExecutor mExecutor = new JobExecutor();
-    private final BootReporter mBootReporter = new BootReporter();
+    private final EventReporter mEventReporter = new EventReporter();
     private final GceBroadcastReceiver mBroadcastReceiver = new GceBroadcastReceiver();
     private final BluetoothChecker mBluetoothChecker = new BluetoothChecker();
 
     private ConnectivityChecker mConnChecker;
     private GceWifiManager mWifiManager = null;
     private String mMostRecentAction = null;
+    private WindowManager mWindowManager;
+
+    private int mPreviousRotation;
+    private Point mPreviousScreenBounds;
+    private int mPreviousDpi;
+
 
     public GceService() {}
 
@@ -60,17 +70,22 @@
     public void onCreate() {
         try {
             super.onCreate();
-            mBootReporter.reportBootStarted();
+            mEventReporter.reportBootStarted();
             registerBroadcastReceivers();
 
-            mConnChecker = new ConnectivityChecker(this, mBootReporter);
-            mWifiManager = new GceWifiManager(this, mBootReporter, mExecutor);
+            mWindowManager = getSystemService(WindowManager.class);
+            mConnChecker = new ConnectivityChecker(this, mEventReporter);
+            mWifiManager = new GceWifiManager(this, mEventReporter, mExecutor);
+
+            mPreviousRotation = getRotation();
+            mPreviousScreenBounds = getScreenBounds();
+            mPreviousDpi = getResources().getConfiguration().densityDpi;
 
             mExecutor.schedule(mWifiManager);
             mExecutor.schedule(mBluetoothChecker);
             mExecutor.schedule(mConnChecker);
 
-            mExecutor.schedule(mBootReporter, mBluetoothChecker.getEnabled());
+            mExecutor.schedule(mEventReporter, mBluetoothChecker.getEnabled());
 
             NotificationManager notificationManager =
                     (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
@@ -105,6 +120,42 @@
         this.registerReceiver(mBroadcastReceiver, filter);
     }
 
+    private Point getScreenBounds() {
+        Display display = mWindowManager.getDefaultDisplay();
+        Point screenBounds = new Point();
+        display.getRealSize(screenBounds);
+        return screenBounds;
+    }
+
+    private int getRotation() {
+      return mWindowManager.getDefaultDisplay().getRotation();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration config) {
+        super.onConfigurationChanged(config);
+
+        int rotation = getRotation();
+        Point screenBounds = getScreenBounds();
+        int dpi = config.densityDpi;
+        // NOTE: We cannot rely on config.diff(previous config) here because
+        // diff shows CONFIG_SCREEN_SIZE changes when changing between 3-button
+        // and gesture navigation. We only care about the display bounds.
+        if (rotation == mPreviousRotation &&
+            screenBounds.equals(mPreviousScreenBounds) &&
+            dpi == mPreviousDpi) {
+            return;
+        }
+
+        int width = screenBounds.x;
+        int height = screenBounds.y;
+        mEventReporter.reportScreenChanged(width, height, dpi, rotation);
+
+        mPreviousRotation = rotation;
+        mPreviousScreenBounds = screenBounds;
+        mPreviousDpi = dpi;
+    }
+
 
     /** StartService entry point.
      */
@@ -127,6 +178,8 @@
                         .setSmallIcon(android.R.drawable.ic_dialog_info)
                         .setTimeoutAfter(10000)
                         .build();
+        // Start in the Foreground (and do not stop) so that this service
+        // continues running and reporting events without being killed.
         startForeground(NOTIFICATION_ID, notification);
 
         if (INTENT_ACTION_CONFIGURE.equals(mMostRecentAction)) {
@@ -137,8 +190,6 @@
             mExecutor.schedule(mBluetoothChecker);
         }
 
-        stopForeground(Service.STOP_FOREGROUND_DETACH);
-
         /* If anything goes wrong, make sure we receive intent again. */
         return Service.START_STICKY;
     }
@@ -152,8 +203,8 @@
      */
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("Boot reporter:");
-        List<String> messageList = mBootReporter.getMessageList();
+        pw.println("Virtual Device reporter:");
+        List<String> messageList = mEventReporter.getMessageList();
         for (int i = 0; i < messageList.size(); i++) {
             pw.println("  " + messageList.get(i));
         }
diff --git a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceWifiManager.java b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceWifiManager.java
index 1b07c04..a0dbd40 100644
--- a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceWifiManager.java
+++ b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/GceWifiManager.java
@@ -41,18 +41,18 @@
     private final Context mContext;
     private final WifiManager mWifiManager;
     private final ConnectivityManager mConnManager;
-    private final BootReporter mBootReporter;
+    private final EventReporter mEventReporter;
 
     private final MonitorWifiJob mMonitorWifiJob;
 
 
-    public GceWifiManager(Context context, BootReporter bootReporter, JobExecutor executor) {
+    public GceWifiManager(Context context, EventReporter eventReporter, JobExecutor executor) {
         super(LOG_TAG);
 
         mContext = context;
         mWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
         mConnManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mBootReporter = bootReporter;
+        mEventReporter = eventReporter;
         mJobExecutor = executor;
         mMonitorWifiJob = new MonitorWifiJob();
     }
@@ -108,7 +108,7 @@
                 }
                 return WIFI_RECONNECTION_TIMEOUT_S;
             } else {
-                mBootReporter.reportMessage(WIFI_CONNECTED_MESSAGE);
+                mEventReporter.reportMessage(WIFI_CONNECTED_MESSAGE);
                 Log.i(LOG_TAG, "Wifi connected.");
                 mWifiReady.set(true);
                 return 0;
diff --git a/guest/monitoring/tombstone_transmit/Android.bp b/guest/monitoring/tombstone_transmit/Android.bp
index 2e0af82..d24985a 100644
--- a/guest/monitoring/tombstone_transmit/Android.bp
+++ b/guest/monitoring/tombstone_transmit/Android.bp
@@ -13,6 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary {
     name: "tombstone_transmit",
     srcs: [
@@ -28,9 +32,6 @@
         "liblog",
     ],
     stl: "libc++_static",
-    header_libs: [
-        "cuttlefish_glog_product",
-    ],
     defaults: ["cuttlefish_guest_product_only"],
 }
 
diff --git a/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp b/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp
index c2e07ee..3d08780 100644
--- a/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp
+++ b/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp
@@ -108,7 +108,7 @@
 
     if(ts_path.empty()) {continue;}
 
-    auto log_fd = cvd::SharedFD::VsockClient(FLAGS_cid, FLAGS_port,
+    auto log_fd = cuttlefish::SharedFD::VsockClient(FLAGS_cid, FLAGS_port,
       SOCK_STREAM);
 
     std::ifstream ifs(ts_path);
diff --git a/guest/services/suspend_blocker/Android.bp b/guest/services/suspend_blocker/Android.bp
index c87c4da..6412632 100644
--- a/guest/services/suspend_blocker/Android.bp
+++ b/guest/services/suspend_blocker/Android.bp
@@ -12,9 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary {
     name: "suspend_blocker",
     srcs: ["suspend_blocker.cpp"],
     shared_libs: ["libpower"],
-    defaults: ["cuttlefish_guest_product_only"],
+    defaults: ["cuttlefish_guest_only"],
 }
diff --git a/guest/services/suspend_blocker/suspend_blocker.cpp b/guest/services/suspend_blocker/suspend_blocker.cpp
index 120a01b..2228b8a 100644
--- a/guest/services/suspend_blocker/suspend_blocker.cpp
+++ b/guest/services/suspend_blocker/suspend_blocker.cpp
@@ -18,7 +18,10 @@
 #include <wakelock/wakelock.h>
 
 int main() {
-    android::wakelock::WakeLock wl{"suspend_blocker"};  // RAII object
+    auto wl = android::wakelock::WakeLock::tryGet("suspend_blocker");  // RAII object
+    if (!wl.has_value()) {
+        return EXIT_FAILURE;
+    }
 
     sigset_t mask;
     sigemptyset(&mask);
diff --git a/host/Android.bp b/host/Android.bp
deleted file mode 100644
index 2280c23..0000000
--- a/host/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "commands",
-    "frontend",
-    "libs",
-]
diff --git a/host/commands/Android.bp b/host/commands/Android.bp
deleted file mode 100644
index c200611..0000000
--- a/host/commands/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "adbshell",
-    "fetch_cvd",
-    "launch",
-    "stop_cvd",
-    "ivserver",
-    "virtual_usb_manager",
-    "kernel_log_monitor",
-    "config_server",
-    "console_forwarder",
-    "run_cvd",
-    "assemble_cvd",
-]
diff --git a/host/commands/adbshell/Android.bp b/host/commands/adbshell/Android.bp
index ea84dd4..883503e 100644
--- a/host/commands/adbshell/Android.bp
+++ b/host/commands/adbshell/Android.bp
@@ -13,6 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_binary_host {
     name: "adbshell",
     srcs: [
@@ -29,5 +33,5 @@
         "libcuttlefish_host_config",
         "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_buildhost_only"],
 }
diff --git a/host/commands/adbshell/main.cpp b/host/commands/adbshell/main.cpp
index 95f5fef..7263f4c 100644
--- a/host/commands/adbshell/main.cpp
+++ b/host/commands/adbshell/main.cpp
@@ -16,8 +16,6 @@
 
 /* Utility that uses an adb connection as the login shell. */
 
-#include "host/libs/config/cuttlefish_config.h"
-
 #include <array>
 #include <cassert>
 #include <cstdio>
@@ -29,6 +27,9 @@
 #include <errno.h>
 #include <unistd.h>
 
+#include "common/libs/utils/environment.h"
+#include "host/libs/config/cuttlefish_config.h"
+
 // Many of our users interact with CVDs via ssh. They expect to be able to
 // get an Android shell (as opposed to the host shell) with a single command.
 //
@@ -51,13 +52,12 @@
 
 namespace {
 std::string VsocUser() {
-  const char* user_cstring = std::getenv("USER");
-  assert(user_cstring != nullptr);
-  std::string user(user_cstring);
+  std::string user = cuttlefish::StringFromEnv("USER", "");
+  assert(!user_cstring.empty());
 
   std::string cvd_prefix = "cvd-";
   if (user.find(cvd_prefix) == 0) {
-    user.replace(0, cvd_prefix.size(), vsoc::kVsocUserPrefix);
+    user.replace(0, cvd_prefix.size(), cuttlefish::kVsocUserPrefix);
   }
   return user;
 }
@@ -76,14 +76,14 @@
 }
 
 void SetCuttlefishConfigEnv() {
-  setenv(vsoc::kCuttlefishConfigEnvVarName, CuttlefishConfigLocation().c_str(),
+  setenv(cuttlefish::kCuttlefishConfigEnvVarName, CuttlefishConfigLocation().c_str(),
          true);
 }
 }  // namespace
 
 int main(int argc, char* argv[]) {
   SetCuttlefishConfigEnv();
-  auto instance = vsoc::CuttlefishConfig::Get()
+  auto instance = cuttlefish::CuttlefishConfig::Get()
       ->ForDefaultInstance().adb_device_name();
   std::string adb_path = CuttlefishFindAdb();
 
diff --git a/host/commands/assemble_cvd/Android.bp b/host/commands/assemble_cvd/Android.bp
index ef77942..4ed4452 100644
--- a/host/commands/assemble_cvd/Android.bp
+++ b/host/commands/assemble_cvd/Android.bp
@@ -13,59 +13,49 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_host_shared {
-    name: "cdisk_spec",
-    srcs: [
-        "cdisk_spec.proto",
-    ],
-    proto: {
-        type: "full",
-        export_proto_headers: true,
-        include_dirs: [
-            "external/protobuf/src",
-        ],
-    },
-    defaults: ["cuttlefish_host_only"],
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_binary_host {
+cc_binary {
     name: "assemble_cvd",
     srcs: [
+        "alloc.cc",
         "assemble_cvd.cc",
-        "boot_image_unpacker.cc",
-        "data_image.cc",
+        "boot_config.cc",
+        "boot_image_utils.cc",
+        "clean.cc",
+        "disk_flags.cc",
         "flags.cc",
-        "image_aggregator.cc",
         "misc_info.cc",
         "super_image_mixer.cc",
     ],
     header_libs: [
         "bootimg_headers",
-        "cuttlefish_glog",
     ],
     shared_libs: [
-        "cdisk_spec",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "libbase",
+        "libjsoncpp",
         "libnl",
         "libprotobuf-cpp-full",
         "libziparchive",
         "libz",
+        "libcuttlefish_allocd_utils",
     ],
     static_libs: [
+        "libcdisk_spec",
+        "libext2_uuid",
+        "libimage_aggregator",
         "libsparse",
+        "libcuttlefish_graphics_detector",
         "libcuttlefish_host_config",
         "libcuttlefish_vm_manager",
         "libgflags",
-        "libxml2",
-        "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only", "cuttlefish_libicuuc"],
-}
-
-python_binary_host {
-    name: "cf_bpttool",
-    srcs: [ "cf_bpttool.py" ],
-    defaults: ["py2_only"],
+    required: [
+        "lz4",
+    ],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
 }
diff --git a/host/commands/assemble_cvd/alloc.cc b/host/commands/assemble_cvd/alloc.cc
new file mode 100644
index 0000000..62b1b78
--- /dev/null
+++ b/host/commands/assemble_cvd/alloc.cc
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#include "host/commands/assemble_cvd/alloc.h"
+
+#include <iomanip>
+#include <sstream>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/allocd/utils.h"
+
+namespace cuttlefish {
+
+static std::string StrForInstance(const std::string& prefix, int num) {
+  std::ostringstream stream;
+  stream << prefix << std::setfill('0') << std::setw(2) << num;
+  return stream.str();
+}
+
+IfaceConfig DefaultNetworkInterfaces(int num) {
+  IfaceConfig config{};
+  config.mobile_tap.name = StrForInstance("cvd-mtap-", num);
+  config.mobile_tap.resource_id = 0;
+  config.mobile_tap.session_id = 0;
+
+  config.wireless_tap.name = StrForInstance("cvd-wtap-", num);
+  config.wireless_tap.resource_id = 0;
+  config.wireless_tap.session_id = 0;
+
+  config.ethernet_tap.name = StrForInstance("cvd-etap-", num);
+  config.ethernet_tap.resource_id = 0;
+  config.ethernet_tap.session_id = 0;
+
+  return config;
+}
+
+std::optional<IfaceConfig> AllocateNetworkInterfaces() {
+  IfaceConfig config{};
+
+  SharedFD allocd_sock = SharedFD::SocketLocalClient(
+      kDefaultLocation, false, SOCK_STREAM);
+  CHECK(allocd_sock->IsOpen())
+      << "Unable to connect to allocd on " << kDefaultLocation
+      << ": " << allocd_sock->StrError();
+
+  Json::Value resource_config;
+  Json::Value request_list;
+  Json::Value req;
+  req["request_type"] = "create_interface";
+  req["uid"] = geteuid();
+  req["iface_type"] = "mtap";
+  request_list.append(req);
+  req["iface_type"] = "wtap";
+  request_list.append(req);
+  req["iface_type"] = "etap";
+  request_list.append(req);
+
+  resource_config["config_request"]["request_list"] = request_list;
+
+  CHECK(SendJsonMsg(allocd_sock, resource_config))
+      << "Failed to send JSON to allocd";
+
+  auto resp_opt = RecvJsonMsg(allocd_sock);
+  CHECK(resp_opt.has_value()) << "Bad response from allocd";
+  auto resp = resp_opt.value();
+
+  CHECK(resp.isMember("config_status") && !resp["config_status"].isString())
+      << "Bad response from allocd: " << resp;
+
+  CHECK_EQ(
+      resp["config_status"].asString(),
+      StatusToStr(RequestStatus::Success))
+          <<"Failed to allocate interfaces " << resp;
+
+  CHECK(resp.isMember("session_id") && resp["session_id"].isUInt())
+      << "Bad response from allocd: " << resp;
+  auto session_id = resp["session_id"].asUInt();
+
+  CHECK(resp.isMember("response_list") && resp["response_list"].isArray())
+      << "Bad response from allocd: " << resp;
+
+  Json::Value resp_list = resp["response_list"];
+  Json::Value mtap_resp;
+  Json::Value wtap_resp;
+  Json::Value etap_resp;
+  for (Json::Value::ArrayIndex i = 0; i != resp_list.size(); ++i) {
+    auto ty = StrToIfaceTy(resp_list[i]["iface_type"].asString());
+
+    switch (ty) {
+      case IfaceType::mtap: {
+        mtap_resp = resp_list[i];
+        break;
+      }
+      case IfaceType::wtap: {
+        wtap_resp = resp_list[i];
+        break;
+      }
+      case IfaceType::etap: {
+        etap_resp = resp_list[i];
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+  }
+
+  if (!mtap_resp.isMember("iface_type")) {
+    LOG(ERROR) << "Missing mtap response from allocd";
+    return std::nullopt;
+  }
+  if (!wtap_resp.isMember("iface_type")) {
+    LOG(ERROR) << "Missing wtap response from allocd";
+    return std::nullopt;
+  }
+  if (!etap_resp.isMember("iface_type")) {
+    LOG(ERROR) << "Missing etap response from allocd";
+    return std::nullopt;
+  }
+
+  config.mobile_tap.name = mtap_resp["iface_name"].asString();
+  config.mobile_tap.resource_id = mtap_resp["resource_id"].asUInt();
+  config.mobile_tap.session_id = session_id;
+
+  config.wireless_tap.name = wtap_resp["iface_name"].asString();
+  config.wireless_tap.resource_id = wtap_resp["resource_id"].asUInt();
+  config.wireless_tap.session_id = session_id;
+
+  config.ethernet_tap.name = etap_resp["iface_name"].asString();
+  config.ethernet_tap.resource_id = etap_resp["resource_id"].asUInt();
+  config.ethernet_tap.session_id = session_id;
+
+  return config;
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/alloc.h b/host/commands/assemble_cvd/alloc.h
new file mode 100644
index 0000000..d74c2b2
--- /dev/null
+++ b/host/commands/assemble_cvd/alloc.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <stdint.h>
+#include <optional>
+#include <string>
+
+namespace cuttlefish {
+
+struct IfaceData {
+  std::string name;
+  uint32_t session_id;
+  uint32_t resource_id;
+};
+
+struct IfaceConfig {
+  IfaceData mobile_tap;
+  IfaceData wireless_tap;
+  IfaceData ethernet_tap;
+};
+
+IfaceConfig DefaultNetworkInterfaces(int num);
+
+// Acquires interfaces from the resource allocator daemon.
+std::optional<IfaceConfig> AllocateNetworkInterfaces();
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/assemble_cvd.cc b/host/commands/assemble_cvd/assemble_cvd.cc
index b45f069..c249473 100644
--- a/host/commands/assemble_cvd/assemble_cvd.cc
+++ b/host/commands/assemble_cvd/assemble_cvd.cc
@@ -16,21 +16,40 @@
 #include <iostream>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
 
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
-#include "common/libs/fs/tee.h"
-#include "host/commands/assemble_cvd/assembler_defs.h"
+#include "common/libs/utils/environment.h"
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/tee_logging.h"
+#include "host/commands/assemble_cvd/clean.h"
+#include "host/commands/assemble_cvd/disk_flags.h"
 #include "host/commands/assemble_cvd/flags.h"
 #include "host/libs/config/fetcher_config.h"
 
+using cuttlefish::StringFromEnv;
+
+DEFINE_string(assembly_dir, StringFromEnv("HOME", ".") + "/cuttlefish_assembly",
+              "A directory to put generated files common between instances");
+DEFINE_string(instance_dir, StringFromEnv("HOME", ".") + "/cuttlefish_runtime",
+              "A directory to put all instance specific files");
+DEFINE_bool(resume, true, "Resume using the disk from the last session, if "
+                          "possible. i.e., if --noresume is passed, the disk "
+                          "will be reset to the state it was initially launched "
+                          "in. This flag is ignored if the underlying partition "
+                          "images have been updated since the first launch.");
+DEFINE_int32(modem_simulator_count, 1,
+             "Modem simulator count corresponding to maximum sim number");
+
+namespace cuttlefish {
 namespace {
 
 std::string kFetcherConfigFile = "fetcher_config.json";
 
-cvd::FetcherConfig FindFetcherConfig(const std::vector<std::string>& files) {
-  cvd::FetcherConfig fetcher_config;
+FetcherConfig FindFetcherConfig(const std::vector<std::string>& files) {
+  FetcherConfig fetcher_config;
   for (const auto& file : files) {
     auto expected_pos = file.size() - kFetcherConfigFile.size();
     if (file.rfind(kFetcherConfigFile) == expected_pos) {
@@ -43,44 +62,205 @@
   return fetcher_config;
 }
 
-} // namespace
+std::string GetLegacyConfigFilePath(const CuttlefishConfig& config) {
+  return config.ForDefaultInstance().PerInstancePath("cuttlefish_config.json");
+}
 
-int main(int argc, char** argv) {
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
-
-  if (isatty(0)) {
-    LOG(FATAL) << "stdin was a tty, expected to be passed the output of a previous stage. "
-               << "Did you mean to run launch_cvd?";
-    return cvd::AssemblerExitCodes::kInvalidHostConfiguration;
-  } else {
-    int error_num = errno;
-    if (error_num == EBADF) {
-      LOG(FATAL) << "stdin was not a valid file descriptor, expected to be passed the output "
-                 << "of launch_cvd. Did you mean to run launch_cvd?";
-      return cvd::AssemblerExitCodes::kInvalidHostConfiguration;
-    }
+bool SaveConfig(const CuttlefishConfig& tmp_config_obj) {
+  auto config_file = GetConfigFilePath(tmp_config_obj);
+  auto config_link = GetGlobalConfigFileLink();
+  // Save the config object before starting any host process
+  if (!tmp_config_obj.SaveToFile(config_file)) {
+    LOG(ERROR) << "Unable to save config object";
+    return false;
+  }
+  auto legacy_config_file = GetLegacyConfigFilePath(tmp_config_obj);
+  if (!tmp_config_obj.SaveToFile(legacy_config_file)) {
+    LOG(ERROR) << "Unable to save legacy config object";
+    return false;
+  }
+  setenv(kCuttlefishConfigEnvVarName, config_file.c_str(), true);
+  if (symlink(config_file.c_str(), config_link.c_str()) != 0) {
+    LOG(ERROR) << "Failed to create symlink to config file at " << config_link
+               << ": " << strerror(errno);
+    return false;
   }
 
-  cvd::TeeStderrToFile stderr_tee;
+  return true;
+}
+
+void ValidateAdbModeFlag(const CuttlefishConfig& config) {
+  auto adb_modes = config.adb_mode();
+  adb_modes.erase(AdbMode::Unknown);
+  if (adb_modes.size() < 1) {
+    LOG(INFO) << "ADB not enabled";
+  }
+}
+
+#ifndef O_TMPFILE
+# define O_TMPFILE (020000000 | O_DIRECTORY)
+#endif
+
+const CuttlefishConfig* InitFilesystemAndCreateConfig(
+    FetcherConfig fetcher_config, KernelConfig kernel_config) {
+  std::string assembly_dir_parent = AbsolutePath(FLAGS_assembly_dir);
+  while (assembly_dir_parent[assembly_dir_parent.size() - 1] == '/') {
+    assembly_dir_parent =
+        assembly_dir_parent.substr(0, FLAGS_assembly_dir.rfind('/'));
+  }
+  assembly_dir_parent =
+      assembly_dir_parent.substr(0, FLAGS_assembly_dir.rfind('/'));
+  auto log =
+      SharedFD::Open(
+          assembly_dir_parent,
+          O_WRONLY | O_TMPFILE,
+          S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+  if (!log->IsOpen()) {
+    LOG(ERROR) << "Could not open O_TMPFILE precursor to assemble_cvd.log: "
+               << log->StrError();
+  } else {
+    android::base::SetLogger(TeeLogger({
+        {ConsoleSeverity(), SharedFD::Dup(2), MetadataLevel::ONLY_MESSAGE},
+        {LogFileSeverity(), log, MetadataLevel::FULL},
+    }));
+  }
+
+  {
+    // The config object is created here, but only exists in memory until the
+    // SaveConfig line below. Don't launch cuttlefish subprocesses between these
+    // two operations, as those will assume they can read the config object from
+    // disk.
+    auto config = InitializeCuttlefishConfiguration(
+        FLAGS_instance_dir, FLAGS_modem_simulator_count, kernel_config);
+    std::set<std::string> preserving;
+    if (FLAGS_resume && ShouldCreateAllCompositeDisks(config)) {
+      LOG(INFO) << "Requested resuming a previous session (the default behavior) "
+                << "but the base images have changed under the overlay, making the "
+                << "overlay incompatible. Wiping the overlay files.";
+    } else if (FLAGS_resume && !ShouldCreateAllCompositeDisks(config)) {
+      preserving.insert("overlay.img");
+      preserving.insert("os_composite_disk_config.txt");
+      preserving.insert("os_composite_gpt_header.img");
+      preserving.insert("os_composite_gpt_footer.img");
+      preserving.insert("os_composite.img");
+      preserving.insert("sdcard.img");
+      preserving.insert("boot_repacked.img");
+      preserving.insert("vendor_boot_repacked.img");
+      preserving.insert("access-kregistry");
+      preserving.insert("NVChip");
+      preserving.insert("gatekeeper_secure");
+      preserving.insert("gatekeeper_insecure");
+      preserving.insert("modem_nvram.json");
+      preserving.insert("recording");
+      preserving.insert("persistent_composite_disk_config.txt");
+      preserving.insert("persistent_composite_gpt_header.img");
+      preserving.insert("persistent_composite_gpt_footer.img");
+      preserving.insert("persistent_composite.img");
+      preserving.insert("uboot_env.img");
+      preserving.insert("factory_reset_protected.img");
+      std::stringstream ss;
+      for (int i = 0; i < FLAGS_modem_simulator_count; i++) {
+        ss.clear();
+        ss << "iccprofile_for_sim" << i << ".xml";
+        preserving.insert(ss.str());
+        ss.str("");
+      }
+    }
+    CHECK(CleanPriorFiles(preserving, FLAGS_assembly_dir, FLAGS_instance_dir))
+        << "Failed to clean prior files";
+
+    // Create assembly directory if it doesn't exist.
+    CHECK(EnsureDirectoryExists(FLAGS_assembly_dir));
+    if (log->LinkAtCwd(config.AssemblyPath("assemble_cvd.log"))) {
+      LOG(ERROR) << "Unable to persist assemble_cvd log at "
+                  << config.AssemblyPath("assemble_cvd.log")
+                  << ": " << log->StrError();
+    }
+    for (const auto& instance : config.Instances()) {
+      // Create instance directory if it doesn't exist.
+      CHECK(EnsureDirectoryExists(instance.instance_dir()));
+      auto internal_dir = instance.instance_dir() + "/" + kInternalDirName;
+      CHECK(EnsureDirectoryExists(internal_dir));
+      auto shared_dir = instance.instance_dir() + "/" + kSharedDirName;
+      CHECK(EnsureDirectoryExists(shared_dir));
+      auto recording_dir = instance.instance_dir() + "/recording";
+      CHECK(EnsureDirectoryExists(recording_dir));
+    }
+    CHECK(SaveConfig(config)) << "Failed to initialize configuration";
+  }
+
+  std::string first_instance = FLAGS_instance_dir + "." + std::to_string(GetInstance());
+  CHECK_EQ(symlink(first_instance.c_str(), FLAGS_instance_dir.c_str()), 0)
+      << "Could not symlink \"" << first_instance << "\" to \"" << FLAGS_instance_dir << "\"";
+
+  // Do this early so that the config object is ready for anything that needs it
+  auto config = CuttlefishConfig::Get();
+  CHECK(config) << "Failed to obtain config singleton";
+
+  ValidateAdbModeFlag(*config);
+
+  CreateDynamicDiskFiles(fetcher_config, config);
+
+  return config;
+}
+
+const std::string kKernelDefaultPath = "kernel";
+const std::string kInitramfsImg = "initramfs.img";
+static void ExtractKernelParamsFromFetcherConfig(
+    const FetcherConfig& fetcher_config) {
+  std::string discovered_kernel =
+      fetcher_config.FindCvdFileWithSuffix(kKernelDefaultPath);
+  std::string discovered_ramdisk =
+      fetcher_config.FindCvdFileWithSuffix(kInitramfsImg);
+
+  SetCommandLineOptionWithMode("kernel_path", discovered_kernel.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+
+  SetCommandLineOptionWithMode("initramfs_path", discovered_ramdisk.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+}
+} // namespace
+
+int AssembleCvdMain(int argc, char** argv) {
+  setenv("ANDROID_LOG_TAGS", "*:v", /* overwrite */ 0);
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+
+  int tty = isatty(0);
+  int error_num = errno;
+  CHECK_EQ(tty, 0)
+      << "stdin was a tty, expected to be passed the output of a previous stage. "
+      << "Did you mean to run launch_cvd?";
+  CHECK(error_num != EBADF)
+      << "stdin was not a valid file descriptor, expected to be passed the output "
+      << "of launch_cvd. Did you mean to run launch_cvd?";
 
   std::string input_files_str;
   {
-    auto input_fd = cvd::SharedFD::Dup(0);
-    auto bytes_read = cvd::ReadAll(input_fd, &input_files_str);
-    if (bytes_read < 0) {
-      LOG(FATAL) << "Failed to read input files. Error was \"" << input_fd->StrError() << "\"";
-    }
+    auto input_fd = SharedFD::Dup(0);
+    auto bytes_read = ReadAll(input_fd, &input_files_str);
+    CHECK(bytes_read >= 0)
+        << "Failed to read input files. Error was \"" << input_fd->StrError() << "\"";
   }
   std::vector<std::string> input_files = android::base::Split(input_files_str, "\n");
 
-  auto config = InitFilesystemAndCreateConfig(&argc, &argv, FindFetcherConfig(input_files));
-  auto instance = config->ForDefaultInstance();
+  FetcherConfig fetcher_config = FindFetcherConfig(input_files);
+  // set gflags defaults to point to kernel/RD from fetcher config
+  ExtractKernelParamsFromFetcherConfig(fetcher_config);
 
-  auto assembler_log_path = instance.PerInstancePath("assemble_cvd.log");
-  stderr_tee.SetFile(cvd::SharedFD::Creat(assembler_log_path.c_str(), 0755));
+  KernelConfig kernel_config;
+  CHECK(ParseCommandLineFlags(&argc, &argv, &kernel_config)) << "Failed to parse arguments";
+
+  auto config =
+      InitFilesystemAndCreateConfig(std::move(fetcher_config), kernel_config);
 
   std::cout << GetConfigFilePath(*config) << "\n";
   std::cout << std::flush;
 
-  return cvd::AssemblerExitCodes::kSuccess;
+  return 0;
+}
+
+} // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::AssembleCvdMain(argc, argv);
 }
diff --git a/host/commands/assemble_cvd/assembler_defs.h b/host/commands/assemble_cvd/assembler_defs.h
deleted file mode 100644
index b890ca0..0000000
--- a/host/commands/assemble_cvd/assembler_defs.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2018 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
-
-namespace cvd {
-
-constexpr char kLogcatSerialMode[] = "serial";
-constexpr char kLogcatVsockMode[] = "vsock";
-
-enum AssemblerExitCodes : int {
-  kSuccess = 0,
-  kArgumentParsingError = 1,
-  kInvalidHostConfiguration = 2,
-  kCuttlefishConfigurationInitError = 3,
-  kInstanceDirCreationError = 4,
-  kPrioFilesCleanupError = 5,
-  kBootImageUnpackError = 6,
-  kCuttlefishConfigurationSaveError = 7,
-  kDaemonizationError = 8,
-  kVMCreationError = 9,
-  kPipeIOError = 10,
-  kVirtualDeviceBootFailed = 11,
-  kProcessGroupError = 12,
-  kMonitorCreationFailed = 13,
-  kServerError = 14,
-  kUsbV1SocketError = 15,
-  kE2eTestFailed = 16,
-  kKernelDecompressError = 17,
-  kLogcatServerError = 18,
-  kConfigServerError = 19,
-  kTombstoneServerError = 20,
-  kTombstoneDirCreationError = 21,
-  kInitRamFsConcatError = 22,
-  kAssemblyDirCreationError = 23,
-  kDiskSpaceError = 24,
-};
-
-}  // namespace cvd
diff --git a/host/commands/assemble_cvd/boot_config.cc b/host/commands/assemble_cvd/boot_config.cc
new file mode 100644
index 0000000..b433940
--- /dev/null
+++ b/host/commands/assemble_cvd/boot_config.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "host/commands/assemble_cvd/boot_config.h"
+
+#include <fstream>
+#include <sstream>
+#include <string>
+
+#include <sys/stat.h>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+
+#include "common/libs/utils/environment.h"
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/kernel_args.h"
+#include "host/libs/vm_manager/crosvm_manager.h"
+#include "host/libs/vm_manager/vm_manager.h"
+
+using cuttlefish::vm_manager::CrosvmManager;
+
+DECLARE_bool(pause_in_bootloader);
+DECLARE_string(vm_manager);
+
+namespace cuttlefish {
+namespace {
+
+size_t WriteEnvironment(const CuttlefishConfig& config,
+                        const std::vector<std::string>& kernel_args,
+                        const std::string& env_path) {
+  std::ostringstream env;
+  env << "bootargs=" << android::base::Join(kernel_args, " ") << '\0';
+  if (!config.boot_slot().empty()) {
+      env << "android_slot_suffix=_" << config.boot_slot() << '\0';
+  }
+
+  if(FLAGS_pause_in_bootloader) {
+    env << "bootdelay=-1" << '\0';
+  } else {
+    env << "bootdelay=0" << '\0';
+  }
+
+  // Note that the 0 index points to the GPT table.
+  env << "bootcmd=boot_android virtio 0#misc" << '\0';
+  if (FLAGS_vm_manager == CrosvmManager::name() &&
+      config.target_arch() == Arch::Arm64) {
+    env << "fdtaddr=0x80000000" << '\0';
+  } else {
+    env << "fdtaddr=0x40000000" << '\0';
+  }
+  env << '\0';
+  std::string env_str = env.str();
+  std::ofstream file_out(env_path.c_str(), std::ios::binary);
+  file_out << env_str;
+
+  if(!file_out.good()) {
+    return 0;
+  }
+
+  return env_str.length();
+}
+
+}  // namespace
+
+
+bool InitBootloaderEnvPartition(const CuttlefishConfig& config,
+                                const CuttlefishConfig::InstanceSpecific& instance) {
+  auto boot_env_image_path = instance.uboot_env_image_path();
+  auto tmp_boot_env_image_path = boot_env_image_path + ".tmp";
+  auto uboot_env_path = instance.PerInstancePath("mkenvimg_input");
+  auto kernel_args = KernelCommandLineFromConfig(config);
+  if(!WriteEnvironment(config, kernel_args, uboot_env_path)) {
+    LOG(ERROR) << "Unable to write out plaintext env '" << uboot_env_path << ".'";
+    return false;
+  }
+
+  auto mkimage_path = HostBinaryPath("mkenvimage");
+  Command cmd(mkimage_path);
+  cmd.AddParameter("-s");
+  cmd.AddParameter("4096");
+  cmd.AddParameter("-o");
+  cmd.AddParameter(tmp_boot_env_image_path);
+  cmd.AddParameter(uboot_env_path);
+  int success = cmd.Start().Wait();
+  if (success != 0) {
+    LOG(ERROR) << "Unable to run mkenvimage. Exited with status " << success;
+    return false;
+  }
+
+  if(!FileExists(boot_env_image_path) || ReadFile(boot_env_image_path) != ReadFile(tmp_boot_env_image_path)) {
+    if(!RenameFile(tmp_boot_env_image_path, boot_env_image_path)) {
+      LOG(ERROR) << "Unable to delete the old env image.";
+      return false;
+    }
+    LOG(DEBUG) << "Updated bootloader environment image.";
+  } else {
+    RemoveFile(tmp_boot_env_image_path);
+  }
+
+  return true;
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/boot_config.h b/host/commands/assemble_cvd/boot_config.h
new file mode 100644
index 0000000..1a81b79
--- /dev/null
+++ b/host/commands/assemble_cvd/boot_config.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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>
+#include <host/libs/config/cuttlefish_config.h>
+
+namespace cuttlefish {
+
+bool InitBootloaderEnvPartition(const CuttlefishConfig& config,
+                                const CuttlefishConfig::InstanceSpecific& instance);
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/boot_image_unpacker.cc b/host/commands/assemble_cvd/boot_image_unpacker.cc
deleted file mode 100644
index f1ead30..0000000
--- a/host/commands/assemble_cvd/boot_image_unpacker.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include "host/commands/assemble_cvd/boot_image_unpacker.h"
-
-#include <string.h>
-#include <unistd.h>
-
-#include <sstream>
-
-#include <bootimg.h>
-#include <glog/logging.h>
-
-#include "common/libs/utils/subprocess.h"
-
-namespace cvd {
-
-namespace {
-
-// Extracts size bytes from file, starting at offset bytes from the beginning to
-// path.
-bool ExtractFile(SharedFD source, off_t offset, size_t size,
-                 const std::string& path) {
-  auto dest = SharedFD::Open(path.c_str(), O_CREAT | O_RDWR, 0755);
-  if (!dest->IsOpen()) {
-    LOG(ERROR) << "Unable to open " << path;
-    return false;
-  }
-  auto off = source->LSeek(offset, SEEK_SET);
-  if (off != offset) {
-    LOG(ERROR) << "Failed to lseek: " << source->StrError();
-    return false;
-  }
-  return dest->CopyFrom(*source, size);
-}
-}  // namespace
-
-std::unique_ptr<BootImageUnpacker> BootImageUnpacker::FromImages(
-    const std::string& boot_image_path,
-    const std::string& vendor_boot_image_path) {
-  auto boot_img = SharedFD::Open(boot_image_path.c_str(), O_RDONLY);
-  if (!boot_img->IsOpen()) {
-    LOG(ERROR) << "Unable to open boot image (" << boot_image_path
-               << "): " << boot_img->StrError();
-    return nullptr;
-  }
-  boot_img_hdr_v3 header;
-  auto bytes_read = boot_img->Read(&header, sizeof(header));
-  if (bytes_read != sizeof(header)) {
-    LOG(ERROR) << "Error reading boot image header";
-    return nullptr;
-  }
-
-  auto vendor_boot_img = SharedFD::Open(vendor_boot_image_path.c_str(),
-                                        O_RDONLY);
-  if (!vendor_boot_img->IsOpen()) {
-    LOG(ERROR) << "Unable to open vendor boot image (" << vendor_boot_image_path
-               << "): " << vendor_boot_img->StrError();
-    return nullptr;
-  }
-  vendor_boot_img_hdr_v3 vboot_header;
-  bytes_read = vendor_boot_img->Read(&vboot_header, sizeof(vboot_header));
-  if (bytes_read != sizeof(vboot_header)) {
-    LOG(ERROR) << "Error reading vendor boot image header";
-    return nullptr;
-  }
-
-  std::ostringstream cmdline;
-  cmdline << reinterpret_cast<char*>(&header.cmdline[0]);
-  if (vboot_header.cmdline[0] != '\0') {
-    cmdline << " ";
-    cmdline << reinterpret_cast<char*>(&vboot_header.cmdline[0]);
-  }
-
-  uint32_t page_size = 4096;
-  // See system/tools/mkbootimg/include/bootimg/bootimg.h for the origin of
-  // these offset calculations
-  uint32_t kernel_offset = page_size;
-  uint32_t ramdisk_offset =
-      kernel_offset +
-      ((header.kernel_size + page_size - 1) / page_size) * page_size;
-  uint32_t vendor_ramdisk_offset =
-      ((vboot_header.header_size + vboot_header.page_size - 1) / vboot_header.page_size) *
-      vboot_header.page_size;
-
-  std::unique_ptr<BootImageUnpacker> ret(new BootImageUnpacker(
-      boot_img, cmdline.str(), header.kernel_size, kernel_offset,
-      header.ramdisk_size, ramdisk_offset, vendor_boot_img,
-      vboot_header.vendor_ramdisk_size, vendor_ramdisk_offset));
-
-  return ret;
-}
-
-std::string BootImageUnpacker::kernel_cmdline() const {
-  return kernel_cmdline_;
-}
-
-bool BootImageUnpacker::ExtractKernelImage(const std::string& path) const {
-  if (kernel_image_size_ == 0) return false;
-  return ExtractFile(boot_image_, kernel_image_offset_, kernel_image_size_,
-                     path);
-}
-bool BootImageUnpacker::ExtractRamdiskImage(const std::string& path) const {
-  if (ramdisk_image_size_ == 0) return false;
-  return ExtractFile(boot_image_, ramdisk_image_offset_, ramdisk_image_size_,
-                     path);
-}
-bool BootImageUnpacker::ExtractVendorRamdiskImage(const std::string& path) const {
-  if (vendor_ramdisk_image_size_ == 0) return false;
-  return ExtractFile(vendor_boot_image_, vendor_ramdisk_image_offset_,
-                     vendor_ramdisk_image_size_, path);
-}
-
-bool BootImageUnpacker::Unpack(const std::string& ramdisk_image_path,
-                               const std::string& vendor_ramdisk_image_path,
-                               const std::string& kernel_image_path) {
-  if (HasRamdiskImage()) {
-    if (!ExtractRamdiskImage(ramdisk_image_path)) {
-      LOG(ERROR) << "Error extracting ramdisk from boot image";
-      return false;
-    }
-  }
-  if (HasVendorRamdiskImage()) {
-    if (!ExtractVendorRamdiskImage(vendor_ramdisk_image_path)) {
-      LOG(ERROR) << "Error extracting vendor ramdisk from venodr boot image";
-      return false;
-    }
-  }
-  if (!kernel_image_path.empty()) {
-    if (HasKernelImage()) {
-      if (!ExtractKernelImage(kernel_image_path)) {
-        LOG(ERROR) << "Error extracting kernel from boot image";
-        return false;
-      }
-    } else {
-      LOG(ERROR) << "No kernel found on boot image";
-      return false;
-    }
-  }
-  return true;
-}
-
-}  // namespace cvd
diff --git a/host/commands/assemble_cvd/boot_image_unpacker.h b/host/commands/assemble_cvd/boot_image_unpacker.h
deleted file mode 100644
index a331f0c..0000000
--- a/host/commands/assemble_cvd/boot_image_unpacker.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 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 <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "common/libs/fs/shared_fd.h"
-
-namespace cvd {
-
-// Unpacks the boot image and extracts kernel, ramdisk and kernel arguments
-class BootImageUnpacker {
- public:
-  // Reads header section of boot image at path and returns a BootImageUnpacker
-  // preloaded with all the metadata.
-  static std::unique_ptr<BootImageUnpacker> FromImages(
-    const std::string& boot_image_path,
-    const std::string& vendor_boot_image_path);
-
-  ~BootImageUnpacker() = default;
-
-  std::string kernel_cmdline() const;
-
-  bool HasKernelImage() const { return kernel_image_size_ > 0; }
-  bool HasRamdiskImage() const { return ramdisk_image_size_ > 0; }
-  bool HasVendorRamdiskImage() const { return vendor_ramdisk_image_size_ > 0; }
-
-  bool Unpack(const std::string& ramdisk_image_path,
-              const std::string& vendor_ramdisk_image_path,
-              const std::string& kernel_image_path);
-
- private:
-  BootImageUnpacker(SharedFD boot_image, const std::string& cmdline,
-                    uint32_t kernel_image_size, uint32_t kernel_image_offset,
-                    uint32_t ramdisk_image_size, uint32_t ramdisk_image_offset,
-                    SharedFD vendor_boot_image,
-                    uint32_t vendor_ramdisk_image_size,
-                    uint32_t vendor_ramdisk_image_offset)
-      : boot_image_(boot_image),
-        vendor_boot_image_(vendor_boot_image),
-        kernel_cmdline_(cmdline),
-        kernel_image_size_(kernel_image_size),
-        kernel_image_offset_(kernel_image_offset),
-        ramdisk_image_size_(ramdisk_image_size),
-        ramdisk_image_offset_(ramdisk_image_offset),
-        vendor_ramdisk_image_size_(vendor_ramdisk_image_size),
-        vendor_ramdisk_image_offset_(vendor_ramdisk_image_offset) {}
-
-  // Mutable because we only read from the fd, but do not modify its contents
-  mutable SharedFD boot_image_;
-  mutable SharedFD vendor_boot_image_;
-  std::string kernel_cmdline_;
-  // When buidling the boot image a particular page size is assumed, which may
-  // not match the actual page size of the system.
-  uint32_t kernel_image_size_;
-  uint32_t kernel_image_offset_;
-  uint32_t ramdisk_image_size_;
-  uint32_t ramdisk_image_offset_;
-  uint32_t vendor_ramdisk_image_size_;
-  uint32_t vendor_ramdisk_image_offset_;
-
-  // Extracts the kernel image to the given path
-  bool ExtractKernelImage(const std::string& path) const;
-  // Extracts the ramdisk image to the given path. It may return false if the
-  // boot image does not contain a ramdisk, which is the case when having system
-  // as root.
-  bool ExtractRamdiskImage(const std::string& path) const;
-  // Extracts the vendor ramdisk image to the given path
-  bool ExtractVendorRamdiskImage(const std::string& path) const;
-};
-
-}  // namespace cvd
diff --git a/host/commands/assemble_cvd/boot_image_utils.cc b/host/commands/assemble_cvd/boot_image_utils.cc
new file mode 100644
index 0000000..cfad23f
--- /dev/null
+++ b/host/commands/assemble_cvd/boot_image_utils.cc
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+#include "host/commands/assemble_cvd/boot_image_utils.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+#include <string.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <sstream>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/subprocess.h"
+
+const char TMP_EXTENSION[] = ".tmp";
+const char CPIO_EXT[] = ".cpio";
+const char TMP_RD_DIR[] = "stripped_ramdisk_dir";
+const char STRIPPED_RD[] = "stripped_ramdisk";
+const char CONCATENATED_VENDOR_RAMDISK[] = "concatenated_vendor_ramdisk";
+namespace cuttlefish {
+namespace {
+std::string ExtractValue(const std::string& dictionary, const std::string& key) {
+  std::size_t index = dictionary.find(key);
+  if (index != std::string::npos) {
+    std::size_t end_index = dictionary.find('\n', index + key.length());
+    if (end_index != std::string::npos) {
+      return dictionary.substr(index + key.length(),
+          end_index - index - key.length());
+    }
+  }
+  return "";
+}
+
+// Though it is just as fast to overwrite the existing boot images with the newly generated ones,
+// the cuttlefish composite disk generator checks the age of each of the components and
+// regenerates the disk outright IF any one of the components is younger/newer than the current
+// composite disk. If this file overwrite occurs, that condition is fulfilled. This action then
+// causes data in the userdata partition from previous boots to be lost (which is not expected by
+// the user if they've been booting the same kernel/ramdisk combination repeatedly).
+// Consequently, the file is checked for differences and ONLY overwritten if there is a diff.
+bool DeleteTmpFileIfNotChanged(const std::string& tmp_file, const std::string& current_file) {
+  if (!FileExists(current_file) ||
+      ReadFile(current_file) != ReadFile(tmp_file)) {
+    if (!RenameFile(tmp_file, current_file)) {
+      LOG(ERROR) << "Unable to delete " << current_file;
+      return false;
+    }
+    LOG(DEBUG) << "Updated " << current_file;
+  } else {
+    LOG(DEBUG) << "Didn't update " << current_file;
+    RemoveFile(tmp_file);
+  }
+
+  return true;
+}
+
+bool UnpackBootImage(const std::string& boot_image_path,
+                     const std::string& unpack_dir) {
+  auto unpack_path = HostBinaryPath("unpack_bootimg");
+  Command unpack_cmd(unpack_path);
+  unpack_cmd.AddParameter("--boot_img");
+  unpack_cmd.AddParameter(boot_image_path);
+  unpack_cmd.AddParameter("--out");
+  unpack_cmd.AddParameter(unpack_dir);
+
+  auto output_file = SharedFD::Creat(unpack_dir + "/boot_params", 0666);
+  if (!output_file->IsOpen()) {
+    LOG(ERROR) << "Unable to create intermediate boot params file: "
+               << output_file->StrError();
+    return false;
+  }
+  unpack_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, output_file);
+
+  int success = unpack_cmd.Start().Wait();
+  if (success != 0) {
+    LOG(ERROR) << "Unable to run unpack_bootimg. Exited with status "
+               << success;
+    return false;
+  }
+  return true;
+}
+
+void RepackVendorRamdisk(const std::string& kernel_modules_ramdisk_path,
+                         const std::string& original_ramdisk_path,
+                         const std::string& new_ramdisk_path,
+                         const std::string& build_dir) {
+  int success = execute({"/bin/bash", "-c", HostBinaryPath("lz4") + " -c -d -l " +
+                        original_ramdisk_path + " > " + original_ramdisk_path + CPIO_EXT});
+  CHECK(success == 0) << "Unable to run lz4. Exited with status " << success;
+
+  const std::string ramdisk_stage_dir = build_dir + "/" + TMP_RD_DIR;
+  success =
+      mkdir(ramdisk_stage_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+  CHECK(success == 0) << "Could not mkdir \"" << ramdisk_stage_dir
+                      << "\", error was " << strerror(errno);
+
+  success = execute(
+      {"/bin/bash", "-c",
+       "(cd " + ramdisk_stage_dir + " && while " + HostBinaryPath("toybox") +
+           " cpio -idu; do :; done) < " + original_ramdisk_path + CPIO_EXT});
+  CHECK(success == 0) << "Unable to run cd or cpio. Exited with status "
+                      << success;
+
+  success = execute({"rm", "-rf", ramdisk_stage_dir + "/lib/modules"});
+  CHECK(success == 0) << "Could not rmdir \"lib/modules\" in TMP_RD_DIR. "
+                      << "Exited with status " << success;
+
+  const std::string stripped_ramdisk_path = build_dir + "/" + STRIPPED_RD;
+  success = execute({"/bin/bash", "-c",
+                     HostBinaryPath("mkbootfs") + " " + ramdisk_stage_dir +
+                         " > " + stripped_ramdisk_path + CPIO_EXT});
+  CHECK(success == 0) << "Unable to run cd or cpio. Exited with status "
+                      << success;
+
+  success = execute({"/bin/bash", "-c", HostBinaryPath("lz4") +
+                     " -c -l -12 --favor-decSpeed " + stripped_ramdisk_path + CPIO_EXT + " > " +
+                     stripped_ramdisk_path});
+  CHECK(success == 0) << "Unable to run lz4. Exited with status " << success;
+
+  // Concatenates the stripped ramdisk and input ramdisk and places the result at new_ramdisk_path
+  std::ofstream final_rd(new_ramdisk_path, std::ios_base::binary | std::ios_base::trunc);
+  std::ifstream ramdisk_a(stripped_ramdisk_path, std::ios_base::binary);
+  std::ifstream ramdisk_b(kernel_modules_ramdisk_path, std::ios_base::binary);
+  final_rd << ramdisk_a.rdbuf() << ramdisk_b.rdbuf();
+}
+
+bool UnpackVendorBootImageIfNotUnpacked(
+    const std::string& vendor_boot_image_path, const std::string& unpack_dir) {
+  // the vendor boot params file is created during the first unpack. If it's
+  // already there, a unpack has occurred and there's no need to repeat the
+  // process.
+  if (FileExists(unpack_dir + "/vendor_boot_params")) {
+    return true;
+  }
+
+  auto unpack_path = HostBinaryPath("unpack_bootimg");
+  Command unpack_cmd(unpack_path);
+  unpack_cmd.AddParameter("--boot_img");
+  unpack_cmd.AddParameter(vendor_boot_image_path);
+  unpack_cmd.AddParameter("--out");
+  unpack_cmd.AddParameter(unpack_dir);
+  auto output_file = SharedFD::Creat(unpack_dir + "/vendor_boot_params", 0666);
+  if (!output_file->IsOpen()) {
+    LOG(ERROR) << "Unable to create intermediate vendor boot params file: "
+               << output_file->StrError();
+    return false;
+  }
+  unpack_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, output_file);
+  int success = unpack_cmd.Start().Wait();
+  if (success != 0) {
+    LOG(ERROR) << "Unable to run unpack_bootimg. Exited with status " << success;
+    return false;
+  }
+
+  // Concatenates all vendor ramdisk into one single ramdisk.
+  Command concat_cmd("/bin/bash");
+  concat_cmd.AddParameter("-c");
+  concat_cmd.AddParameter("cat " + unpack_dir + "/vendor_ramdisk*");
+  auto concat_file =
+      SharedFD::Creat(unpack_dir + "/" + CONCATENATED_VENDOR_RAMDISK, 0666);
+  if (!concat_file->IsOpen()) {
+    LOG(ERROR) << "Unable to create concatenated vendor ramdisk file: "
+               << concat_file->StrError();
+    return false;
+  }
+  concat_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, concat_file);
+  success = concat_cmd.Start().Wait();
+  if (success != 0) {
+    LOG(ERROR) << "Unable to run cat. Exited with status " << success;
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+bool RepackBootImage(const std::string& new_kernel_path,
+                     const std::string& boot_image_path,
+                     const std::string& new_boot_image_path,
+                     const std::string& build_dir) {
+  if (UnpackBootImage(boot_image_path, build_dir) == false) {
+    return false;
+  }
+
+  std::string boot_params = ReadFile(build_dir + "/boot_params");
+  auto kernel_cmdline = ExtractValue(boot_params, "command line args: ");
+  LOG(DEBUG) << "Cmdline from boot image is " << kernel_cmdline;
+
+  auto tmp_boot_image_path = new_boot_image_path + TMP_EXTENSION;
+  auto repack_path = HostBinaryPath("mkbootimg");
+  Command repack_cmd(repack_path);
+  repack_cmd.AddParameter("--kernel");
+  repack_cmd.AddParameter(new_kernel_path);
+  repack_cmd.AddParameter("--ramdisk");
+  repack_cmd.AddParameter(build_dir + "/ramdisk");
+  repack_cmd.AddParameter("--header_version");
+  repack_cmd.AddParameter("4");
+  repack_cmd.AddParameter("--cmdline");
+  repack_cmd.AddParameter(kernel_cmdline);
+  repack_cmd.AddParameter("-o");
+  repack_cmd.AddParameter(tmp_boot_image_path);
+  int success = repack_cmd.Start().Wait();
+  if (success != 0) {
+    LOG(ERROR) << "Unable to run mkbootimg. Exited with status " << success;
+    return false;
+  }
+
+  auto fd = SharedFD::Open(tmp_boot_image_path, O_RDWR);
+  auto original_size = FileSize(boot_image_path);
+  CHECK(fd->Truncate(original_size) == 0)
+    << "`truncate --size=" << original_size << " " << tmp_boot_image_path << "` "
+    << "failed: " << fd->StrError();
+
+  return DeleteTmpFileIfNotChanged(tmp_boot_image_path, new_boot_image_path);
+}
+
+bool RepackVendorBootImage(const std::string& new_ramdisk,
+                           const std::string& vendor_boot_image_path,
+                           const std::string& new_vendor_boot_image_path,
+                           const std::string& unpack_dir,
+                           const std::string& repack_dir,
+                           const std::vector<std::string>& bootconfig_args,
+                           bool bootconfig_supported) {
+  if (UnpackVendorBootImageIfNotUnpacked(vendor_boot_image_path, unpack_dir) ==
+      false) {
+    return false;
+  }
+
+  std::string ramdisk_path;
+  if (new_ramdisk.size()) {
+    ramdisk_path = unpack_dir + "/vendor_ramdisk_repacked";
+    if (!FileExists(ramdisk_path)) {
+      RepackVendorRamdisk(new_ramdisk,
+                          unpack_dir + "/" + CONCATENATED_VENDOR_RAMDISK,
+                          ramdisk_path, unpack_dir);
+    }
+  } else {
+    ramdisk_path = unpack_dir + "/" + CONCATENATED_VENDOR_RAMDISK;
+  }
+
+  auto bootconfig_fd = SharedFD::Creat(repack_dir + "/bootconfig", 0666);
+  if (!bootconfig_fd->IsOpen()) {
+    LOG(ERROR) << "Unable to create intermediate bootconfig file: "
+               << bootconfig_fd->StrError();
+    return false;
+  }
+  std::string bootconfig = ReadFile(unpack_dir + "/bootconfig");
+  bootconfig_fd->Write(bootconfig.c_str(), bootconfig.size());
+  LOG(DEBUG) << "Bootconfig parameters from vendor boot image are "
+             << ReadFile(repack_dir + "/bootconfig");
+  std::string vendor_boot_params = ReadFile(unpack_dir + "/vendor_boot_params");
+  auto kernel_cmdline =
+      ExtractValue(vendor_boot_params, "vendor command line args: ") +
+      (bootconfig_supported
+           ? ""
+           : " " + android::base::StringReplace(bootconfig, "\n", " ", true) +
+                 " " + android::base::Join(bootconfig_args, " "));
+  if (!bootconfig_supported) {
+    // TODO(b/182417593): Until we pass the module parameters through
+    // modules.options, we pass them through bootconfig using
+    // 'kernel.<key>=<value>' But if we don't support bootconfig, we need to
+    // rename them back to the old cmdline version
+    kernel_cmdline = android::base::StringReplace(
+        kernel_cmdline, " kernel.", " ", true);
+  }
+  LOG(DEBUG) << "Cmdline from vendor boot image and config is "
+             << kernel_cmdline;
+
+  auto tmp_vendor_boot_image_path = new_vendor_boot_image_path + TMP_EXTENSION;
+  auto repack_path = HostBinaryPath("mkbootimg");
+  Command repack_cmd(repack_path);
+  repack_cmd.AddParameter("--vendor_ramdisk");
+  repack_cmd.AddParameter(ramdisk_path);
+  repack_cmd.AddParameter("--header_version");
+  repack_cmd.AddParameter("4");
+  repack_cmd.AddParameter("--vendor_cmdline");
+  repack_cmd.AddParameter(kernel_cmdline);
+  repack_cmd.AddParameter("--vendor_boot");
+  repack_cmd.AddParameter(tmp_vendor_boot_image_path);
+  repack_cmd.AddParameter("--dtb");
+  repack_cmd.AddParameter(unpack_dir + "/dtb");
+  if (bootconfig_supported) {
+    repack_cmd.AddParameter("--vendor_bootconfig");
+    repack_cmd.AddParameter(repack_dir + "/bootconfig");
+  }
+
+  int success = repack_cmd.Start().Wait();
+  if (success != 0) {
+    LOG(ERROR) << "Unable to run mkbootimg. Exited with status " << success;
+    return false;
+  }
+
+  auto fd = SharedFD::Open(tmp_vendor_boot_image_path, O_RDWR);
+  auto original_size = FileSize(vendor_boot_image_path);
+  CHECK(fd->Truncate(original_size) == 0)
+    << "`truncate --size=" << original_size << " " << tmp_vendor_boot_image_path << "` "
+    << "failed: " << fd->StrError();
+
+  return DeleteTmpFileIfNotChanged(tmp_vendor_boot_image_path, new_vendor_boot_image_path);
+}
+
+bool RepackVendorBootImageWithEmptyRamdisk(
+    const std::string& vendor_boot_image_path,
+    const std::string& new_vendor_boot_image_path,
+    const std::string& unpack_dir, const std::string& repack_dir,
+    const std::vector<std::string>& bootconfig_args,
+    bool bootconfig_supported) {
+  auto empty_ramdisk_file =
+      SharedFD::Creat(unpack_dir + "/empty_ramdisk", 0666);
+  return RepackVendorBootImage(
+      unpack_dir + "/empty_ramdisk", vendor_boot_image_path,
+      new_vendor_boot_image_path, unpack_dir, repack_dir, bootconfig_args,
+      bootconfig_supported);
+}
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/boot_image_utils.h b/host/commands/assemble_cvd/boot_image_utils.h
new file mode 100644
index 0000000..fafb514
--- /dev/null
+++ b/host/commands/assemble_cvd/boot_image_utils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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>
+#include <vector>
+
+namespace cuttlefish {
+bool RepackBootImage(const std::string& new_kernel_path,
+                     const std::string& boot_image_path,
+                     const std::string& new_boot_image_path,
+                     const std::string& tmp_artifact_dir);
+bool RepackVendorBootImage(const std::string& new_ramdisk_path,
+                           const std::string& vendor_boot_image_path,
+                           const std::string& new_vendor_boot_image_path,
+                           const std::string& unpack_dir,
+                           const std::string& repack_dir,
+                           const std::vector<std::string>& bootconfig_args,
+                           bool bootconfig_supported);
+bool RepackVendorBootImageWithEmptyRamdisk(
+    const std::string& vendor_boot_image_path,
+    const std::string& new_vendor_boot_image_path,
+    const std::string& unpack_dir, const std::string& repack_dir,
+    const std::vector<std::string>& bootconfig_args, bool bootconfig_supported);
+}
diff --git a/host/commands/assemble_cvd/cf_bpttool.py b/host/commands/assemble_cvd/cf_bpttool.py
deleted file mode 100755
index a29d737..0000000
--- a/host/commands/assemble_cvd/cf_bpttool.py
+++ /dev/null
@@ -1,1649 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2016, 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.
-
-
-"""Command-line tool for partitioning Brillo images."""
-
-
-import argparse
-import bisect
-import copy
-import json
-import math
-import numbers
-import os
-import struct
-import sys
-import uuid
-import zlib
-
-# Python 2.6 required for modern exception syntax
-if sys.hexversion < 0x02060000:
-  print >> sys.stderr, "Python 2.6 or newer is required."
-  sys.exit(1)
-
-# Keywords used in JSON files.
-JSON_KEYWORD_SETTINGS = 'settings'
-JSON_KEYWORD_SETTINGS_AB_SUFFIXES = 'ab_suffixes'
-JSON_KEYWORD_SETTINGS_DISK_SIZE = 'disk_size'
-JSON_KEYWORD_SETTINGS_DISK_ALIGNMENT = 'disk_alignment'
-JSON_KEYWORD_SETTINGS_DISK_GUID = 'disk_guid'
-JSON_KEYWORD_SETTINGS_PARTITIONS_OFFSET_BEGIN = 'partitions_offset_begin'
-JSON_KEYWORD_PARTITIONS = 'partitions'
-JSON_KEYWORD_PARTITIONS_LABEL = 'label'
-JSON_KEYWORD_PARTITIONS_OFFSET = 'offset'
-JSON_KEYWORD_PARTITIONS_SIZE = 'size'
-JSON_KEYWORD_PARTITIONS_GROW = 'grow'
-JSON_KEYWORD_PARTITIONS_GUID = 'guid'
-JSON_KEYWORD_PARTITIONS_TYPE_GUID = 'type_guid'
-JSON_KEYWORD_PARTITIONS_FLAGS = 'flags'
-JSON_KEYWORD_PARTITIONS_PERSIST = 'persist'
-JSON_KEYWORD_PARTITIONS_IGNORE = 'ignore'
-JSON_KEYWORD_PARTITIONS_AB = 'ab'
-JSON_KEYWORD_PARTITIONS_AB_EXPANDED = 'ab_expanded'
-JSON_KEYWORD_PARTITIONS_POSITION = 'position'
-JSON_KEYWORD_AUTO = 'auto'
-
-# Possible values for the --type option of the query_partition
-# sub-command.
-QUERY_PARTITION_TYPES = ['size',
-                         'offset',
-                         'guid',
-                         'type_guid',
-                         'flags',
-                         'persist']
-
-BPT_VERSION_MAJOR = 1
-BPT_VERSION_MINOR = 0
-
-DISK_SECTOR_SIZE = 512
-
-GPT_NUM_LBAS = 33
-
-GPT_MIN_PART_NUM = 1
-GPT_MAX_PART_NUM = 128
-
-KNOWN_TYPE_GUIDS = {
-    'brillo_boot': 'bb499290-b57e-49f6-bf41-190386693794',
-    'brillo_bootloader': '4892aeb3-a45f-4c5f-875f-da3303c0795c',
-    'brillo_system': '0f2778c4-5cc1-4300-8670-6c88b7e57ed6',
-    'brillo_odm': 'e99d84d7-2c1b-44cf-8c58-effae2dc2558',
-    'brillo_oem': 'aa3434b2-ddc3-4065-8b1a-18e99ea15cb7',
-    'brillo_userdata': '0bb7e6ed-4424-49c0-9372-7fbab465ab4c',
-    'brillo_misc': '6b2378b0-0fbc-4aa9-a4f6-4d6e17281c47',
-    'brillo_vbmeta': 'b598858a-5fe3-418e-b8c4-824b41f4adfc',
-    'brillo_vendor_specific': '314f99d5-b2bf-4883-8d03-e2f2ce507d6a',
-    'linux_fs': '0fc63daf-8483-4772-8e79-3d69d8477de4',
-    'ms_basic_data': 'ebd0a0a2-b9e5-4433-87c0-68b6b72699c7',
-    'efi_system': 'c12a7328-f81f-11d2-ba4b-00a0c93ec93b'
-}
-
-
-def RoundToMultiple(number, size, round_down=False):
-  """Rounds a number up (or down) to nearest multiple of another number.
-
-  Args:
-    number: The number to round up.
-    size: The multiple to round up to.
-    round_down: If True, the number will be rounded down.
-
-  Returns:
-    If |number| is a multiple of |size|, returns |number|, otherwise
-    returns |number| + |size| - |remainder| (if |round_down| is False) or
-    |number| - |remainder| (if |round_down| is True). Always returns
-    an integer.
-  """
-  remainder = number % size
-  if remainder == 0:
-    return int(number)
-  if round_down:
-    return int(number - remainder)
-  return int(number + size - remainder)
-
-
-def ParseNumber(arg):
-  """Number parser.
-
-  If |arg| is an integer, that value is returned. Otherwise int(arg, 0)
-  is returned.
-
-  This function is suitable for use in the |type| parameter of
-  |ArgumentParser|'s add_argument() function. An improvement to just
-  using type=int is that this function supports numbers in other
-  bases, e.g. "0x1234".
-
-  Arguments:
-    arg: Argument (int or string) to parse.
-
-  Returns:
-    The parsed value, as an integer.
-
-  Raises:
-    ValueError: If the argument could not be parsed.
-  """
-  if isinstance(arg, numbers.Integral):
-    return arg
-  return int(arg, 0)
-
-
-def ParseGuid(arg):
-  """Parser for RFC 4122 GUIDs.
-
-  Arguments:
-    arg: The argument, as a string.
-
-  Returns:
-    UUID in hyphenated format.
-
-  Raises:
-    ValueError: If the given string cannot be parsed.
-  """
-  return str(uuid.UUID(arg))
-
-
-def ParseSize(arg):
-  """Parser for size strings with decimal and binary unit support.
-
-  This supports both integers and strings.
-
-  Arguments:
-    arg: The string to parse.
-
-  Returns:
-    The parsed size in bytes as an integer.
-
-  Raises:
-    ValueError: If the given string cannot be parsed.
-  """
-  if isinstance(arg, numbers.Integral):
-    return arg
-
-  ws_index = arg.find(' ')
-  if ws_index != -1:
-    num = float(arg[0:ws_index])
-    factor = 1
-    if arg.endswith('KiB'):
-      factor = 1024
-    elif arg.endswith('MiB'):
-      factor = 1024*1024
-    elif arg.endswith('GiB'):
-      factor = 1024*1024*1024
-    elif arg.endswith('TiB'):
-      factor = 1024*1024*1024*1024
-    elif arg.endswith('PiB'):
-      factor = 1024*1024*1024*1024*1024
-    elif arg.endswith('kB'):
-      factor = 1000
-    elif arg.endswith('MB'):
-      factor = 1000*1000
-    elif arg.endswith('GB'):
-      factor = 1000*1000*1000
-    elif arg.endswith('TB'):
-      factor = 1000*1000*1000*1000
-    elif arg.endswith('PB'):
-      factor = 1000*1000*1000*1000*1000
-    else:
-      raise ValueError('Cannot parse string "{}"'.format(arg))
-    value = num*factor
-    # If the resulting value isn't an integer, round up.
-    if not value.is_integer():
-      value = int(math.ceil(value))
-  else:
-    value = int(arg, 0)
-  return value
-
-
-class ImageChunk(object):
-  """Data structure used for representing chunks in Android sparse files.
-
-  Attributes:
-    chunk_type: One of TYPE_RAW, TYPE_FILL, or TYPE_DONT_CARE.
-    chunk_offset: Offset in the sparse file where this chunk begins.
-    output_offset: Offset in de-sparsified file where output begins.
-    output_size: Number of bytes in output.
-    input_offset: Offset in sparse file for data if TYPE_RAW otherwise None.
-    fill_data: Blob with data to fill if TYPE_FILL otherwise None.
-  """
-
-  FORMAT = '<2H2I'
-  TYPE_RAW = 0xcac1
-  TYPE_FILL = 0xcac2
-  TYPE_DONT_CARE = 0xcac3
-  TYPE_CRC32 = 0xcac4
-
-  def __init__(self, chunk_type, chunk_offset, output_offset, output_size,
-               input_offset, fill_data):
-    """Initializes an ImageChunk object.
-
-    Arguments:
-      chunk_type: One of TYPE_RAW, TYPE_FILL, or TYPE_DONT_CARE.
-      chunk_offset: Offset in the sparse file where this chunk begins.
-      output_offset: Offset in de-sparsified file.
-      output_size: Number of bytes in output.
-      input_offset: Offset in sparse file if TYPE_RAW otherwise None.
-      fill_data: Blob with data to fill if TYPE_FILL otherwise None.
-
-    Raises:
-      ValueError: If data is not well-formed.
-    """
-    self.chunk_type = chunk_type
-    self.chunk_offset = chunk_offset
-    self.output_offset = output_offset
-    self.output_size = output_size
-    self.input_offset = input_offset
-    self.fill_data = fill_data
-    # Check invariants.
-    if self.chunk_type == self.TYPE_RAW:
-      if self.fill_data is not None:
-        raise ValueError('RAW chunk cannot have fill_data set.')
-      if not self.input_offset:
-        raise ValueError('RAW chunk must have input_offset set.')
-    elif self.chunk_type == self.TYPE_FILL:
-      if self.fill_data is None:
-        raise ValueError('FILL chunk must have fill_data set.')
-      if self.input_offset:
-        raise ValueError('FILL chunk cannot have input_offset set.')
-    elif self.chunk_type == self.TYPE_DONT_CARE:
-      if self.fill_data is not None:
-        raise ValueError('DONT_CARE chunk cannot have fill_data set.')
-      if self.input_offset:
-        raise ValueError('DONT_CARE chunk cannot have input_offset set.')
-    else:
-      raise ValueError('Invalid chunk type')
-
-
-class ImageHandler(object):
-  """Abstraction for image I/O with support for Android sparse images.
-
-  This class provides an interface for working with image files that
-  may be using the Android Sparse Image format. When an instance is
-  constructed, we test whether it's an Android sparse file. If so,
-  operations will be on the sparse file by interpreting the sparse
-  format, otherwise they will be directly on the file. Either way the
-  operations do the same.
-
-  For reading, this interface mimics a file object - it has seek(),
-  tell(), and read() methods. For writing, only truncation
-  (truncate()) and appending is supported (append_raw(),
-  append_fill(), and append_dont_care()). Additionally, data can only
-  be written in units of the block size.
-
-  Attributes:
-    is_sparse: Whether the file being operated on is sparse.
-    block_size: The block size, typically 4096.
-    image_size: The size of the unsparsified file.
-
-  """
-  # See system/core/libsparse/sparse_format.h for details.
-  MAGIC = 0xed26ff3a
-  HEADER_FORMAT = '<I4H4I'
-
-  # These are formats and offset of just the |total_chunks| and
-  # |total_blocks| fields.
-  NUM_CHUNKS_AND_BLOCKS_FORMAT = '<II'
-  NUM_CHUNKS_AND_BLOCKS_OFFSET = 16
-
-  def __init__(self, image_filename):
-    """Initializes an image handler.
-
-    Arguments:
-      image_filename: The name of the file to operate on.
-
-    Raises:
-      ValueError: If data in the file is invalid.
-    """
-    self._image_filename = image_filename
-    self._read_header()
-
-  def _read_header(self):
-    """Initializes internal data structures used for reading file.
-
-    This may be called multiple times and is typically called after
-    modifying the file (e.g. appending, truncation).
-
-    Raises:
-      ValueError: If data in the file is invalid.
-    """
-    self.is_sparse = False
-    self.block_size = 4096
-    self._file_pos = 0
-    self._image = open(self._image_filename, 'r+b')
-    self._image.seek(0, os.SEEK_END)
-    self.image_size = self._image.tell()
-
-    self._image.seek(0, os.SEEK_SET)
-    header_bin = self._image.read(struct.calcsize(self.HEADER_FORMAT))
-    if len(header_bin) < struct.calcsize(self.HEADER_FORMAT):
-      # Not a sparse image, our job here is done.
-      return
-    (magic, major_version, minor_version, file_hdr_sz, chunk_hdr_sz,
-     block_size, self._num_total_blocks, self._num_total_chunks,
-     _) = struct.unpack(self.HEADER_FORMAT, header_bin)
-    if magic != self.MAGIC:
-      # Not a sparse image, our job here is done.
-      return
-    if not (major_version == 1 and minor_version == 0):
-      raise ValueError('Encountered sparse image format version {}.{} but '
-                       'only 1.0 is supported'.format(major_version,
-                                                      minor_version))
-    if file_hdr_sz != struct.calcsize(self.HEADER_FORMAT):
-      raise ValueError('Unexpected file_hdr_sz value {}.'.
-                       format(file_hdr_sz))
-    if chunk_hdr_sz != struct.calcsize(ImageChunk.FORMAT):
-      raise ValueError('Unexpected chunk_hdr_sz value {}.'.
-                       format(chunk_hdr_sz))
-
-    self.block_size = block_size
-
-    # Build an list of chunks by parsing the file.
-    self._chunks = []
-
-    # Find the smallest offset where only "Don't care" chunks
-    # follow. This will be the size of the content in the sparse
-    # image.
-    offset = 0
-    output_offset = 0
-    for _ in xrange(1, self._num_total_chunks + 1):
-      chunk_offset = self._image.tell()
-
-      header_bin = self._image.read(struct.calcsize(ImageChunk.FORMAT))
-      (chunk_type, _, chunk_sz, total_sz) = struct.unpack(ImageChunk.FORMAT,
-                                                          header_bin)
-      data_sz = total_sz - struct.calcsize(ImageChunk.FORMAT)
-
-      if chunk_type == ImageChunk.TYPE_RAW:
-        if data_sz != (chunk_sz * self.block_size):
-          raise ValueError('Raw chunk input size ({}) does not match output '
-                           'size ({})'.
-                           format(data_sz, chunk_sz*self.block_size))
-        self._chunks.append(ImageChunk(ImageChunk.TYPE_RAW,
-                                       chunk_offset,
-                                       output_offset,
-                                       chunk_sz*self.block_size,
-                                       self._image.tell(),
-                                       None))
-        self._image.read(data_sz)
-
-      elif chunk_type == ImageChunk.TYPE_FILL:
-        if data_sz != 4:
-          raise ValueError('Fill chunk should have 4 bytes of fill, but this '
-                           'has {}'.format(data_sz))
-        fill_data = self._image.read(4)
-        self._chunks.append(ImageChunk(ImageChunk.TYPE_FILL,
-                                       chunk_offset,
-                                       output_offset,
-                                       chunk_sz*self.block_size,
-                                       None,
-                                       fill_data))
-      elif chunk_type == ImageChunk.TYPE_DONT_CARE:
-        if data_sz != 0:
-          raise ValueError('Don\'t care chunk input size is non-zero ({})'.
-                           format(data_sz))
-        self._chunks.append(ImageChunk(ImageChunk.TYPE_DONT_CARE,
-                                       chunk_offset,
-                                       output_offset,
-                                       chunk_sz*self.block_size,
-                                       None,
-                                       None))
-      elif chunk_type == ImageChunk.TYPE_CRC32:
-        if data_sz != 4:
-          raise ValueError('CRC32 chunk should have 4 bytes of CRC, but '
-                           'this has {}'.format(data_sz))
-        self._image.read(4)
-      else:
-        raise ValueError('Unknown chunk type {}'.format(chunk_type))
-
-      offset += chunk_sz
-      output_offset += chunk_sz * self.block_size
-
-    # Record where sparse data end.
-    self._sparse_end = self._image.tell()
-
-    # Now that we've traversed all chunks, sanity check.
-    if self._num_total_blocks != offset:
-      raise ValueError('The header said we should have {} output blocks, '
-                       'but we saw {}'.format(self._num_total_blocks, offset))
-    junk_len = len(self._image.read())
-    if junk_len > 0:
-      raise ValueError('There were {} bytes of extra data at the end of the '
-                       'file.'.format(junk_len))
-
-    # Assign |image_size|.
-    self.image_size = output_offset
-
-    # This is used when bisecting in read() to find the initial slice.
-    self._chunk_output_offsets = [i.output_offset for i in self._chunks]
-
-    self.is_sparse = True
-
-  def _update_chunks_and_blocks(self):
-    """Helper function to update the image header.
-
-    The the |total_chunks| and |total_blocks| fields in the header
-    will be set to value of the |_num_total_blocks| and
-    |_num_total_chunks| attributes.
-
-    """
-    self._image.seek(self.NUM_CHUNKS_AND_BLOCKS_OFFSET, os.SEEK_SET)
-    self._image.write(struct.pack(self.NUM_CHUNKS_AND_BLOCKS_FORMAT,
-                                  self._num_total_blocks,
-                                  self._num_total_chunks))
-
-  def append_dont_care(self, num_bytes):
-    """Appends a DONT_CARE chunk to the sparse file.
-
-    The given number of bytes must be a multiple of the block size.
-
-    Arguments:
-      num_bytes: Size in number of bytes of the DONT_CARE chunk.
-    """
-    assert num_bytes % self.block_size == 0
-
-    if not self.is_sparse:
-      self._image.seek(0, os.SEEK_END)
-      # This is more efficient that writing NUL bytes since it'll add
-      # a hole on file systems that support sparse files (native
-      # sparse, not Android sparse).
-      self._image.truncate(self._image.tell() + num_bytes)
-      self._read_header()
-      return
-
-    self._num_total_chunks += 1
-    self._num_total_blocks += num_bytes / self.block_size
-    self._update_chunks_and_blocks()
-
-    self._image.seek(self._sparse_end, os.SEEK_SET)
-    self._image.write(struct.pack(ImageChunk.FORMAT,
-                                  ImageChunk.TYPE_DONT_CARE,
-                                  0,  # Reserved
-                                  num_bytes / self.block_size,
-                                  struct.calcsize(ImageChunk.FORMAT)))
-    self._read_header()
-
-  def append_raw(self, data):
-    """Appends a RAW chunk to the sparse file.
-
-    The length of the given data must be a multiple of the block size.
-
-    Arguments:
-      data: Data to append.
-    """
-    assert len(data) % self.block_size == 0
-
-    if not self.is_sparse:
-      self._image.seek(0, os.SEEK_END)
-      self._image.write(data)
-      self._read_header()
-      return
-
-    self._num_total_chunks += 1
-    self._num_total_blocks += len(data) / self.block_size
-    self._update_chunks_and_blocks()
-
-    self._image.seek(self._sparse_end, os.SEEK_SET)
-    self._image.write(struct.pack(ImageChunk.FORMAT,
-                                  ImageChunk.TYPE_RAW,
-                                  0,  # Reserved
-                                  len(data) / self.block_size,
-                                  len(data) +
-                                  struct.calcsize(ImageChunk.FORMAT)))
-    self._image.write(data)
-    self._read_header()
-
-  def append_fill(self, fill_data, size):
-    """Appends a fill chunk to the sparse file.
-
-    The total length of the fill data must be a multiple of the block size.
-
-    Arguments:
-      fill_data: Fill data to append - must be four bytes.
-      size: Number of chunk - must be a multiple of four and the block size.
-    """
-    assert len(fill_data) == 4
-    assert size % 4 == 0
-    assert size % self.block_size == 0
-
-    if not self.is_sparse:
-      self._image.seek(0, os.SEEK_END)
-      self._image.write(fill_data * (size/4))
-      self._read_header()
-      return
-
-    self._num_total_chunks += 1
-    self._num_total_blocks += size / self.block_size
-    self._update_chunks_and_blocks()
-
-    self._image.seek(self._sparse_end, os.SEEK_SET)
-    self._image.write(struct.pack(ImageChunk.FORMAT,
-                                  ImageChunk.TYPE_FILL,
-                                  0,  # Reserved
-                                  size / self.block_size,
-                                  4 + struct.calcsize(ImageChunk.FORMAT)))
-    self._image.write(fill_data)
-    self._read_header()
-
-  def seek(self, offset):
-    """Sets the cursor position for reading from unsparsified file.
-
-    Arguments:
-      offset: Offset to seek to from the beginning of the file.
-    """
-    self._file_pos = offset
-
-  def read(self, size):
-    """Reads data from the unsparsified file.
-
-    This method may return fewer than |size| bytes of data if the end
-    of the file was encountered.
-
-    The file cursor for reading is advanced by the number of bytes
-    read.
-
-    Arguments:
-      size: Number of bytes to read.
-
-    Returns:
-      The data.
-
-    """
-    if not self.is_sparse:
-      self._image.seek(self._file_pos)
-      data = self._image.read(size)
-      self._file_pos += len(data)
-      return data
-
-    # Iterate over all chunks.
-    chunk_idx = bisect.bisect_right(self._chunk_output_offsets,
-                                    self._file_pos) - 1
-    data = bytearray()
-    to_go = size
-    while to_go > 0:
-      chunk = self._chunks[chunk_idx]
-      chunk_pos_offset = self._file_pos - chunk.output_offset
-      chunk_pos_to_go = min(chunk.output_size - chunk_pos_offset, to_go)
-
-      if chunk.chunk_type == ImageChunk.TYPE_RAW:
-        self._image.seek(chunk.input_offset + chunk_pos_offset)
-        data.extend(self._image.read(chunk_pos_to_go))
-      elif chunk.chunk_type == ImageChunk.TYPE_FILL:
-        all_data = chunk.fill_data*(chunk_pos_to_go/len(chunk.fill_data) + 2)
-        offset_mod = chunk_pos_offset % len(chunk.fill_data)
-        data.extend(all_data[offset_mod:(offset_mod + chunk_pos_to_go)])
-      else:
-        assert chunk.chunk_type == ImageChunk.TYPE_DONT_CARE
-        data.extend('\0' * chunk_pos_to_go)
-
-      to_go -= chunk_pos_to_go
-      self._file_pos += chunk_pos_to_go
-      chunk_idx += 1
-      # Generate partial read in case of EOF.
-      if chunk_idx >= len(self._chunks):
-        break
-
-    return data
-
-  def tell(self):
-    """Returns the file cursor position for reading from unsparsified file.
-
-    Returns:
-      The file cursor position for reading.
-    """
-    return self._file_pos
-
-  def truncate(self, size):
-    """Truncates the unsparsified file.
-
-    Arguments:
-      size: Desired size of unsparsified file.
-
-    Raises:
-      ValueError: If desired size isn't a multiple of the block size.
-    """
-    if not self.is_sparse:
-      self._image.truncate(size)
-      self._read_header()
-      return
-
-    if size % self.block_size != 0:
-      raise ValueError('Cannot truncate to a size which is not a multiple '
-                       'of the block size')
-
-    if size == self.image_size:
-      # Trivial where there's nothing to do.
-      return
-    elif size < self.image_size:
-      chunk_idx = bisect.bisect_right(self._chunk_output_offsets, size) - 1
-      chunk = self._chunks[chunk_idx]
-      if chunk.output_offset != size:
-        # Truncation in the middle of a trunk - need to keep the chunk
-        # and modify it.
-        chunk_idx_for_update = chunk_idx + 1
-        num_to_keep = size - chunk.output_offset
-        assert num_to_keep % self.block_size == 0
-        if chunk.chunk_type == ImageChunk.TYPE_RAW:
-          truncate_at = (chunk.chunk_offset +
-                         struct.calcsize(ImageChunk.FORMAT) + num_to_keep)
-          data_sz = num_to_keep
-        elif chunk.chunk_type == ImageChunk.TYPE_FILL:
-          truncate_at = (chunk.chunk_offset +
-                         struct.calcsize(ImageChunk.FORMAT) + 4)
-          data_sz = 4
-        else:
-          assert chunk.chunk_type == ImageChunk.TYPE_DONT_CARE
-          truncate_at = chunk.chunk_offset + struct.calcsize(ImageChunk.FORMAT)
-          data_sz = 0
-        chunk_sz = num_to_keep/self.block_size
-        total_sz = data_sz + struct.calcsize(ImageChunk.FORMAT)
-        self._image.seek(chunk.chunk_offset)
-        self._image.write(struct.pack(ImageChunk.FORMAT,
-                                      chunk.chunk_type,
-                                      0,  # Reserved
-                                      chunk_sz,
-                                      total_sz))
-        chunk.output_size = num_to_keep
-      else:
-        # Truncation at trunk boundary.
-        truncate_at = chunk.chunk_offset
-        chunk_idx_for_update = chunk_idx
-
-      self._num_total_chunks = chunk_idx_for_update
-      self._num_total_blocks = 0
-      for i in range(0, chunk_idx_for_update):
-        self._num_total_blocks += self._chunks[i].output_size / self.block_size
-      self._update_chunks_and_blocks()
-      self._image.truncate(truncate_at)
-
-      # We've modified the file so re-read all data.
-      self._read_header()
-    else:
-      # Truncating to grow - just add a DONT_CARE section.
-      self.append_dont_care(size - self.image_size)
-
-
-class GuidGenerator(object):
-  """An interface for obtaining strings that are GUIDs.
-
-  To facilitate unit testing, this abstraction is used instead of the
-  directly using the uuid module.
-  """
-
-  def dispense_guid(self, partition_number):
-    """Dispenses a GUID.
-
-    Arguments:
-      partition_number: The partition number or 0 if requesting a GUID
-                        for the whole disk.
-
-    Returns:
-      A RFC 4122 compliant GUID, as a string.
-    """
-    return str(uuid.uuid4())
-
-
-class Partition(object):
-  """Object representing a partition.
-
-  Attributes:
-    label: The partition label.
-    offset: Offset of the partition on the disk, or None.
-    size: Size of the partition or None if not specified.
-    grow: True if partition has been requested to use all remaining space.
-    guid: Instance GUID (RFC 4122 compliant) as a string or None or 'auto'
-          if it should be automatically generated.
-    type_guid: Type GUID (RFC 4122 compliant) as a string or a known type
-               from the |KNOWN_TYPE_GUIDS| map.
-    flags: GUID flags.
-    persist: If true, sets bit 0 of flags indicating that this partition should
-             not be deleted by the bootloader.
-    ab: If True, the partition is an A/B partition.
-    ab_expanded: If True, the A/B partitions have been generated.
-    ignore: If True, the partition should not be included in the final output.
-    position: The requested position of the partition or 0 if it doesn't matter.
-  """
-
-  def __init__(self):
-    """Initializer method."""
-    self.label = ''
-    self.offset = None
-    self.size = None
-    self.grow = False
-    self.guid = None
-    self.type_guid = None
-    self.flags = 0
-    self.persist = False
-    self.ab = False
-    self.ab_expanded = False
-    self.ignore = False
-    self.position = 0
-
-  def add_info(self, pobj):
-    """Add information to partition.
-
-    Arguments:
-      pobj: A JSON object with information about the partition.
-    """
-    self.label = pobj[JSON_KEYWORD_PARTITIONS_LABEL]
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_OFFSET)
-    if value is not None:
-      self.offset = ParseSize(value)
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_SIZE)
-    if value is not None:
-      self.size = ParseSize(value)
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_GROW)
-    if value is not None:
-      self.grow = value
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_AB)
-    if value is not None:
-      self.ab = value
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_AB_EXPANDED)
-    if value is not None:
-      self.ab_expanded = value
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_GUID)
-    if value is not None:
-      self.guid = value
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_IGNORE)
-    if value is not None:
-      self.ignore = value
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_TYPE_GUID)
-    if value is not None:
-      self.type_guid = str.lower(str(value))
-      if self.type_guid in KNOWN_TYPE_GUIDS:
-        self.type_guid = KNOWN_TYPE_GUIDS[self.type_guid]
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_FLAGS)
-    if value is not None:
-      self.flags = ParseNumber(value)
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_PERSIST)
-    if value is not None:
-      self.persist = value
-      if value:
-        self.flags = self.flags | 0x1
-    value = pobj.get(JSON_KEYWORD_PARTITIONS_POSITION)
-    if value is not None:
-      self.position = ParseNumber(value)
-
-  def expand_guid(self, guid_generator, partition_number):
-    """Assign instance GUID and type GUID if required.
-
-    Arguments:
-      guid_generator: A GuidGenerator object.
-      partition_number: The partition number, starting from 1.
-    """
-    if not self.guid or self.guid == JSON_KEYWORD_AUTO:
-      self.guid = guid_generator.dispense_guid(partition_number)
-    if not self.type_guid:
-      self.type_guid = KNOWN_TYPE_GUIDS['brillo_vendor_specific']
-
-  def validate(self):
-    """Sanity checks data in object."""
-
-    try:
-      _ = uuid.UUID(str(self.guid))
-    except ValueError:
-      raise ValueError('The string "{}" is not a valid GPT instance GUID on '
-                       'partition with label "{}".'.format(
-                           str(self.guid), self.label))
-
-    try:
-      _ = uuid.UUID(str(self.type_guid))
-    except ValueError:
-      raise ValueError('The string "{}" is not a valid GPT type GUID on '
-                       'partition with label "{}".'.format(
-                           str(self.type_guid), self.label))
-
-    if not self.size:
-      if not self.grow:
-        raise ValueError('Size can only be unset if "grow" is True.')
-
-  def cmp(self, other):
-    """Comparison method."""
-    self_position = self.position
-    if self_position == 0:
-      self_position = GPT_MAX_PART_NUM
-    other_position = other.position
-    if other_position == 0:
-      other_position = GPT_MAX_PART_NUM
-    return cmp(self_position, other_position)
-
-
-class Settings(object):
-  """An object for holding settings.
-
-  Attributes:
-    ab_suffixes: A list of A/B suffixes to use.
-    disk_size: An integer with the disk size in bytes.
-    partitions_offset_begin: An integer with the disk partitions
-                             offset begin size in bytes.
-    disk_alignment: The alignment to use for partitions.
-    disk_guid: The GUID to use for the disk or None or 'auto' if
-               automatically generated.
-  """
-
-  def __init__(self):
-    """Initializer with defaults."""
-    self.ab_suffixes = ['_a', '_b']
-    self.disk_size = None
-    self.partitions_offset_begin = 0
-    self.disk_alignment = 4096
-    self.disk_guid = JSON_KEYWORD_AUTO
-
-
-class BptError(Exception):
-  """Application-specific errors.
-
-  These errors represent issues for which a stack-trace should not be
-  presented.
-
-  Attributes:
-    message: Error message.
-  """
-
-  def __init__(self, message):
-    Exception.__init__(self, message)
-
-
-class BptParsingError(BptError):
-  """Represents an error with an input file.
-
-  Attributes:
-    message: Error message.
-    filename: Name of the file that caused an error.
-  """
-
-  def __init__(self, filename, message):
-    self.filename = filename
-    BptError.__init__(self, message)
-
-
-class Bpt(object):
-  """Business logic for bpttool command-line tool."""
-
-  def _read_json(self, input_files, ab_collapse=True):
-    """Parses a stack of JSON files into suitable data structures.
-
-    The order of files matters as later files can modify partitions
-    declared in earlier files.
-
-    Arguments:
-      input_files: An ordered list of open files.
-      ab_collapse: If True, collapse A/B partitions.
-
-    Returns:
-      A tuple where the first element is a list of Partition objects
-      and the second element is a Settings object.
-
-    Raises:
-      BptParsingError: If an input file has an error.
-    """
-    partitions = []
-    settings = Settings()
-
-    # Read all input file and merge partitions and settings.
-    for f in input_files:
-      try:
-        obj = json.loads(f.read())
-      except ValueError as e:
-        # Unfortunately we can't easily get the line number where the
-        # error occurred.
-        raise BptParsingError(f.name, e.message)
-
-      sobj = obj.get(JSON_KEYWORD_SETTINGS)
-      if sobj:
-        ab_suffixes = sobj.get(JSON_KEYWORD_SETTINGS_AB_SUFFIXES)
-        if ab_suffixes:
-          settings.ab_suffixes = ab_suffixes
-        disk_size = sobj.get(JSON_KEYWORD_SETTINGS_DISK_SIZE)
-        if disk_size:
-          settings.disk_size = ParseSize(disk_size)
-        partitions_offset_begin = sobj.get(
-                JSON_KEYWORD_SETTINGS_PARTITIONS_OFFSET_BEGIN)
-        if partitions_offset_begin:
-          settings.partitions_offset_begin = ParseSize(partitions_offset_begin)
-        disk_alignment = sobj.get(JSON_KEYWORD_SETTINGS_DISK_ALIGNMENT)
-        if disk_alignment:
-          settings.disk_alignment = ParseSize(disk_alignment)
-        disk_guid = sobj.get(JSON_KEYWORD_SETTINGS_DISK_GUID)
-        if disk_guid:
-          settings.disk_guid = disk_guid
-
-      pobjs = obj.get(JSON_KEYWORD_PARTITIONS)
-      if pobjs:
-        for pobj in pobjs:
-          if ab_collapse and pobj.get(JSON_KEYWORD_PARTITIONS_AB_EXPANDED):
-            # If we encounter an expanded partition, unexpand it. This
-            # is to make it possible to use output-JSON (from this tool)
-            # and stack it with an input-JSON file that e.g. specifies
-            # size='256 GiB' for the 'system' partition.
-            label = pobj[JSON_KEYWORD_PARTITIONS_LABEL]
-            if label.endswith(settings.ab_suffixes[0]):
-              # Modify first A/B copy so it doesn't have the trailing suffix.
-              new_len = len(label) - len(settings.ab_suffixes[0])
-              pobj[JSON_KEYWORD_PARTITIONS_LABEL] = label[0:new_len]
-              pobj[JSON_KEYWORD_PARTITIONS_AB_EXPANDED] = False
-              pobj[JSON_KEYWORD_PARTITIONS_GUID] = JSON_KEYWORD_AUTO
-            else:
-              # Skip other A/B copies.
-              continue
-          # Find or create a partition.
-          p = None
-          for candidate in partitions:
-            if candidate.label == pobj[JSON_KEYWORD_PARTITIONS_LABEL]:
-              p = candidate
-              break
-          if not p:
-            p = Partition()
-            partitions.append(p)
-          p.add_info(pobj)
-
-    return partitions, settings
-
-  def _generate_json(self, partitions, settings):
-    """Generate a string with JSON representing partitions and settings.
-
-    Arguments:
-      partitions: A list of Partition objects.
-      settings: A Settings object.
-
-    Returns:
-      A JSON string.
-    """
-    suffixes_str = '['
-    for n in range(0, len(settings.ab_suffixes)):
-      if n != 0:
-        suffixes_str += ', '
-      suffixes_str += '"{}"'.format(settings.ab_suffixes[n])
-    suffixes_str += ']'
-
-    ret = ('{{\n'
-           '  "' + JSON_KEYWORD_SETTINGS + '": {{\n'
-           '    "' + JSON_KEYWORD_SETTINGS_AB_SUFFIXES + '": {},\n'
-           '    "' + JSON_KEYWORD_SETTINGS_PARTITIONS_OFFSET_BEGIN + '": {},\n'
-           '    "' + JSON_KEYWORD_SETTINGS_DISK_SIZE + '": {},\n'
-           '    "' + JSON_KEYWORD_SETTINGS_DISK_ALIGNMENT + '": {},\n'
-           '    "' + JSON_KEYWORD_SETTINGS_DISK_GUID + '": "{}"\n'
-           '  }},\n'
-           '  "' + JSON_KEYWORD_PARTITIONS + '": [\n').format(
-               suffixes_str,
-               settings.partitions_offset_begin,
-               settings.disk_size,
-               settings.disk_alignment,
-               settings.disk_guid)
-
-    for n in range(0, len(partitions)):
-      p = partitions[n]
-      ret += ('    {{\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_LABEL + '": "{}",\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_OFFSET + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_SIZE + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_GROW + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_GUID + '": "{}",\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_TYPE_GUID + '": "{}",\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_FLAGS + '": "{:#018x}",\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_PERSIST + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_IGNORE + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_AB + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_AB_EXPANDED + '": {},\n'
-              '      "' + JSON_KEYWORD_PARTITIONS_POSITION + '": {}\n'
-              '    }}{}\n').format(p.label,
-                                   p.offset,
-                                   p.size,
-                                   'true' if p.grow else 'false',
-                                   p.guid,
-                                   p.type_guid,
-                                   p.flags,
-                                   'true' if p.persist else 'false',
-                                   'true' if p.ignore else 'false',
-                                   'true' if p.ab else 'false',
-                                   'true' if p.ab_expanded else 'false',
-                                   p.position,
-                                   '' if n == len(partitions) - 1 else ',')
-    ret += ('  ]\n'
-            '}\n')
-    return ret
-
-  def _lba_to_chs(self, lba):
-    """Converts LBA to CHS.
-
-    Arguments:
-      lba: The sector number to convert.
-
-    Returns:
-      An array containing the CHS encoded the way it's expected in a
-      MBR partition table.
-    """
-    # See https://en.wikipedia.org/wiki/Cylinder-head-sector
-    num_heads = 255
-    num_sectors = 63
-    # If LBA isn't going to fit in CHS, return maximum CHS values.
-    max_lba = 255*num_heads*num_sectors
-    if lba > max_lba:
-      return [255, 255, 255]
-    c = lba / (num_heads*num_sectors)
-    h = (lba / num_sectors) % num_heads
-    s = lba % num_sectors
-    return [h, (((c>>8) & 0x03)<<6) | (s & 0x3f), c & 0xff]
-
-  def _generate_protective_mbr(self, settings):
-    """Generate Protective MBR.
-
-    Arguments:
-      settings: A Settings object.
-
-    Returns:
-      A string with the binary protective MBR (512 bytes).
-    """
-    # See https://en.wikipedia.org/wiki/Master_boot_record for MBR layout.
-    #
-    # The first partition starts at offset 446 (0x1be).
-    lba_start = 1
-    lba_end = settings.disk_size/DISK_SECTOR_SIZE - 1
-    start_chs = self._lba_to_chs(lba_start)
-    end_chs = self._lba_to_chs(lba_end)
-    pmbr = struct.pack('<446s'     # Bootloader code
-                       'B'         # Status.
-                       'BBB'       # CHS start.
-                       'B'         # Partition type.
-                       'BBB'       # CHS end.
-                       'I'         # LBA of partition start.
-                       'I'         # Number of sectors in partition.
-                       '48x'       # Padding to get to offset 510 (0x1fe).
-                       'BB',       # Boot signature.
-                       '\xfa\xeb\xfe', # cli ; jmp $ (x86)
-                       0x00,
-                       start_chs[0], start_chs[1], start_chs[2],
-                       0xee,       # MBR Partition Type: GPT protective MBR.
-                       end_chs[0], end_chs[1], end_chs[2],
-                       1,          # LBA start
-                       lba_end,
-                       0x55, 0xaa)
-    return pmbr
-
-  def _generate_gpt(self, partitions, settings, primary=True):
-    """Generate GUID Partition Table.
-
-    Arguments:
-      partitions: A list of Partition objects.
-      settings: A Settings object.
-      primary: True to generate primary GPT, False to generate secondary.
-
-    Returns:
-      A string with the binary GUID Partition Table (33*512 bytes).
-    """
-    # See https://en.wikipedia.org/wiki/Master_boot_record for MBR layout.
-    #
-    # The first partition starts at offset 446 (0x1be).
-
-    disk_num_lbas = settings.disk_size/DISK_SECTOR_SIZE
-    if primary:
-      current_lba = 1
-      other_lba = disk_num_lbas - 1
-      partitions_lba = 2
-    else:
-      current_lba = disk_num_lbas - 1
-      other_lba = 1
-      partitions_lba = disk_num_lbas - GPT_NUM_LBAS
-    first_usable_lba = GPT_NUM_LBAS + 1
-    last_usable_lba = disk_num_lbas - GPT_NUM_LBAS - 1
-
-    part_array = []
-    for p in partitions:
-      part_array.append(struct.pack(
-          '<16s'    # Partition type GUID.
-          '16s'     # Partition instance GUID.
-          'QQ'      # First and last LBA.
-          'Q'       # Flags.
-          '72s',    # Name (36 UTF-16LE code units).
-          uuid.UUID(p.type_guid).get_bytes_le(),
-          uuid.UUID(p.guid).get_bytes_le(),
-          p.offset/DISK_SECTOR_SIZE,
-          (p.offset + p.size)/DISK_SECTOR_SIZE - 1,
-          p.flags,
-          p.label.encode(encoding='utf-16le')))
-
-    part_array.append(((128 - len(partitions))*128) * '\0')
-    part_array_str = ''.join(part_array)
-
-    partitions_crc32 = zlib.crc32(part_array_str) % (1<<32)
-
-    header_crc32 = 0
-    while True:
-      header = struct.pack(
-          '<8s'    # Signature.
-          '4B'     # Version.
-          'I'      # Header size.
-          'I'      # CRC32 (must be zero during calculation).
-          'I'      # Reserved (must be zero).
-          'QQ'     # Current and Other LBA.
-          'QQ'     # First and last usable LBA.
-          '16s'    # Disk GUID.
-          'Q'      # Starting LBA of array of partitions.
-          'I'      # Number of partitions.
-          'I'      # Partition entry size, in bytes.
-          'I'      # CRC32 of partition array
-          '420x',  # Padding to get to 512 bytes.
-          'EFI PART',
-          0x00, 0x00, 0x01, 0x00,
-          92,
-          header_crc32,
-          0x00000000,
-          current_lba, other_lba,
-          first_usable_lba, last_usable_lba,
-          uuid.UUID(settings.disk_guid).get_bytes_le(),
-          partitions_lba,
-          128,
-          128,
-          partitions_crc32)
-      if header_crc32 != 0:
-        break
-      header_crc32 = zlib.crc32(header[0:92]) % (1<<32)
-
-    if primary:
-      return header + part_array_str
-    else:
-      return part_array_str + header
-
-  def _generate_gpt_bin(self, partitions, settings):
-    """Generate a bytearray representing partitions and settings.
-
-    The blob will have three partition tables, laid out one after
-    another: 1) Protective MBR (512 bytes); 2) Primary GPT (33*512
-    bytes); and 3) Secondary GPT (33*512 bytes).
-
-    The total size will be 34,304 bytes.
-
-    Arguments:
-      partitions: A list of Partition objects.
-      settings: A Settings object.
-
-    Returns:
-      A bytearray() object.
-    """
-    protective_mbr = self._generate_protective_mbr(settings)
-    primary_gpt = self._generate_gpt(partitions, settings)
-    secondary_gpt = self._generate_gpt(partitions, settings, primary=False)
-    ret = protective_mbr + primary_gpt + secondary_gpt
-    return ret
-
-  def _validate_disk_partitions(self, partitions, disk_size):
-    """Check that a list of partitions have assigned offsets and fits on a
-       disk of a given size.
-
-    This function checks partition offsets and sizes to see if they may fit on
-    a disk image.
-
-    Arguments:
-      partitions: A list of Partition objects.
-      settings: Integer size of disk image.
-
-    Raises:
-      BptError: If checked condition is not satisfied.
-    """
-    for p in partitions:
-      if not p.offset or p.offset < (GPT_NUM_LBAS + 1)*DISK_SECTOR_SIZE:
-        raise BptError('Partition with label "{}" has no offset.'
-                       .format(p.label))
-      if not p.size or p.size < 0:
-        raise BptError('Partition with label "{}" has no size.'
-                        .format(p.label))
-      if (p.offset + p.size) > (disk_size - GPT_NUM_LBAS*DISK_SECTOR_SIZE):
-        raise BptError('Partition with label "{}" exceeds the disk '
-                       'image size.'.format(p.label))
-
-  def make_table(self,
-                 inputs,
-                 ab_suffixes=None,
-                 partitions_offset_begin=None,
-                 disk_size=None,
-                 disk_alignment=None,
-                 disk_guid=None,
-                 guid_generator=None):
-    """Implementation of the 'make_table' command.
-
-    This function takes a list of input partition definition files,
-    flattens them, expands A/B partitions, grows partitions, and lays
-    out partitions according to alignment constraints.
-
-    Arguments:
-      inputs: List of JSON files to parse.
-      ab_suffixes: List of the A/B suffixes (as a comma-separated string)
-                   to use or None to not override.
-      partitions_offset_begin: Size of disk partitions offset
-                               begin or None to not override.
-      disk_size: Size of disk or None to not override.
-      disk_alignment: Disk alignment or None to not override.
-      disk_guid: Disk GUID as a string or None to not override.
-      guid_generator: A GuidGenerator or None to use the default.
-
-    Returns:
-      A tuple where the first argument is a JSON string for the resulting
-      partitions and the second argument is the binary partition tables.
-
-    Raises:
-      BptParsingError: If an input file has an error.
-      BptError: If another application-specific error occurs
-    """
-    partitions, settings = self._read_json(inputs)
-
-    # Command-line arguments override anything specified in input
-    # files.
-    if disk_size:
-      settings.disk_size = int(math.ceil(disk_size))
-    if disk_alignment:
-      settings.disk_alignment = int(disk_alignment)
-    if partitions_offset_begin:
-      settings.partitions_offset_begin = int(partitions_offset_begin)
-    if ab_suffixes:
-      settings.ab_suffixes = ab_suffixes.split(',')
-    if disk_guid:
-      settings.disk_guid = disk_guid
-
-    if not guid_generator:
-      guid_generator = GuidGenerator()
-
-    # We need to know the disk size. Also round it down to ensure it's
-    # a multiple of the sector size.
-    if not settings.disk_size:
-      raise BptError('Disk size not specified. Use --disk_size option '
-                     'or specify it in an input file.\n')
-    settings.disk_size = RoundToMultiple(settings.disk_size,
-                                         DISK_SECTOR_SIZE,
-                                         round_down=True)
-
-    # Alignment must be divisible by disk sector size.
-    if settings.disk_alignment % DISK_SECTOR_SIZE != 0:
-      raise BptError(
-          'Disk alignment size of {} is not divisible by {}.\n'.format(
-              settings.disk_alignment, DISK_SECTOR_SIZE))
-
-    if settings.partitions_offset_begin != 0:
-      # Disk partitions offset begin size must be
-      # divisible by disk sector size.
-      if settings.partitions_offset_begin % settings.disk_alignment != 0:
-        raise BptError(
-            'Disk Partitions offset begin size of {} '
-            'is not divisible by {}.\n'.format(
-                settings.partitions_offset_begin, settings.disk_alignment))
-      settings.partitions_offset_begin = max(settings.partitions_offset_begin,
-                                           DISK_SECTOR_SIZE*(1 + GPT_NUM_LBAS))
-      settings.partitions_offset_begin = RoundToMultiple(
-          settings.partitions_offset_begin, settings.disk_alignment)
-
-    # Expand A/B partitions and skip ignored partitions.
-    expanded_partitions = []
-    for p in partitions:
-      if p.ignore:
-        continue
-      if p.ab and not p.ab_expanded:
-        p.ab_expanded = True
-        for suffix in settings.ab_suffixes:
-          new_p = copy.deepcopy(p)
-          new_p.label += suffix
-          expanded_partitions.append(new_p)
-      else:
-        expanded_partitions.append(p)
-    partitions = expanded_partitions
-
-    # Expand Disk GUID if needed.
-    if not settings.disk_guid or settings.disk_guid == JSON_KEYWORD_AUTO:
-      settings.disk_guid = guid_generator.dispense_guid(0)
-
-    # Sort according to 'position' attribute.
-    partitions = sorted(partitions, cmp=lambda x, y: x.cmp(y))
-
-    # Automatically generate GUIDs if the GUID is unset or set to
-    # 'auto'. Also validate the rest of the fields.
-    part_no = 1
-    for p in partitions:
-      p.expand_guid(guid_generator, part_no)
-      p.validate()
-      part_no += 1
-
-    # Idenfify partition to grow and lay out partitions, ignoring the
-    # one to grow. This way we can figure out how much space is left.
-    #
-    # Right now we only support a single 'grow' partition but we could
-    # support more in the future by splitting up the available bytes
-    # between them.
-    grow_part = None
-    # offset minimal size: DISK_SECTOR_SIZE*(1 + GPT_NUM_LBAS)
-    offset = max(settings.partitions_offset_begin,
-                 DISK_SECTOR_SIZE*(1 + GPT_NUM_LBAS))
-    for p in partitions:
-      if p.grow:
-        if grow_part:
-          raise BptError('Only a single partition can be automatically '
-                         'grown.\n')
-        grow_part = p
-      else:
-        # Ensure size is a multiple of DISK_SECTOR_SIZE by rounding up
-        # (user may specify it as e.g. "1.5 GB" which is not divisible
-        # by 512).
-        p.size = RoundToMultiple(p.size, DISK_SECTOR_SIZE)
-        # Align offset to disk alignment.
-        offset = RoundToMultiple(offset, settings.disk_alignment)
-        offset += p.size
-
-    # After laying out (respecting alignment) all non-grow
-    # partitions, check that the given disk size is big enough.
-    if offset > settings.disk_size - DISK_SECTOR_SIZE*GPT_NUM_LBAS:
-      raise BptError('Disk size of {} bytes is too small for partitions '
-                     'totaling {} bytes.\n'.format(
-                         settings.disk_size, offset))
-
-    # If we have a grow partition, it'll starts at the next
-    # available alignment offset and we can calculate its size as
-    # follows.
-    if grow_part:
-      offset = RoundToMultiple(offset, settings.disk_alignment)
-      grow_part.size = RoundToMultiple(
-          settings.disk_size - DISK_SECTOR_SIZE*GPT_NUM_LBAS - offset,
-          settings.disk_alignment,
-          round_down=True)
-      if grow_part.size < DISK_SECTOR_SIZE:
-        raise BptError('Not enough space for partition "{}" to be '
-                       'automatically grown.\n'.format(grow_part.label))
-
-    # Now we can assign partition start offsets for all partitions,
-    # including the grow partition.
-    # offset minimal size: DISK_SECTOR_SIZE*(1 + GPT_NUM_LBAS)
-    offset = max(settings.partitions_offset_begin,
-                 DISK_SECTOR_SIZE*(1 + GPT_NUM_LBAS))
-    for p in partitions:
-      # Align offset.
-      offset = RoundToMultiple(offset, settings.disk_alignment)
-      p.offset = offset
-      offset += p.size
-    assert offset <= settings.disk_size - DISK_SECTOR_SIZE*GPT_NUM_LBAS
-
-    json_str = self._generate_json(partitions, settings)
-
-    gpt_bin = self._generate_gpt_bin(partitions, settings)
-
-    return json_str, gpt_bin
-
-  def make_disk_image(self, output, bpt, images, allow_empty_partitions=False):
-    """Implementation of the 'make_disk_image' command.
-
-    This function takes in a list of partitions images and a bpt file
-    for the purpose of creating a raw disk image with a protective MBR,
-    primary and secondary GPT, and content for each partition as specified.
-
-    Arguments:
-      output: Output file where disk image is to be written to.
-      bpt: BPT JSON file to parse.
-      images: List of partition image paths to be combined (as specified by
-              bpt).  Each element is of the form.
-              'PARTITION_NAME:/PATH/TO/PARTITION_IMAGE'
-      allow_empty_partitions: If True, partitions defined in |bpt| need not to
-                              be present in |images|. Otherwise an exception is
-                              thrown if a partition is referenced in |bpt| but
-                              not in |images|.
-
-    Raises:
-      BptParsingError: If an image file has an error.
-      BptError: If another application-specific error occurs.
-    """
-    # Generate partition list and settings.
-    partitions, settings = self._read_json([bpt], ab_collapse=False)
-
-    # Validated partition sizes and offsets.
-    self._validate_disk_partitions(partitions, settings.disk_size)
-
-    # Sort according to 'offset' attribute.
-    partitions = sorted(partitions, cmp=lambda x, y: cmp(x.offset, y.offset))
-
-    # Create necessary tables.
-    protective_mbr = self._generate_protective_mbr(settings)
-    primary_gpt = self._generate_gpt(partitions, settings)
-    secondary_gpt = self._generate_gpt(partitions, settings, primary=False)
-
-    # Start at 0 offset for mbr and primary gpt.
-    output.seek(0)
-    output.write(protective_mbr)
-    output.write(primary_gpt)
-
-    # Create mapping of partition name to partition image file.
-    image_file_names = {}
-    try:
-      for name_path in images:
-        name, path = name_path.split(":")
-        image_file_names[name] = path
-    except ValueError as e:
-      raise BptParsingError(name_path, 'Bad image argument {}.'.format(
-                            images[i]))
-
-    # Read image and insert in correct offset.
-    for p in partitions:
-      if p.label not in image_file_names:
-        if allow_empty_partitions:
-          continue
-        else:
-          raise BptParsingError(bpt.name, 'No content specified for partition'
-                                ' with label {}'.format(p.label))
-
-      input_image = ImageHandler(image_file_names[p.label])
-      output.seek(p.offset)
-      partition_blob = input_image.read(p.size)
-      output.write(partition_blob)
-
-    # Put secondary GPT and end of disk.
-    output.seek(settings.disk_size - len(secondary_gpt))
-    output.write(secondary_gpt)
-
-  def query_partition(self, input_file, part_label, query_type, ab_collapse):
-    """Implementation of the 'query_partition' command.
-
-    This reads the partition definition file given by |input_file| and
-    returns information of type |query_type| for the partition with
-    label |part_label|.
-
-    Arguments:
-      input_file: A JSON file to parse.
-      part_label: Label of partition to query information about.
-      query_type: The information to query, see |QUERY_PARTITION_TYPES|.
-      ab_collapse: If True, collapse A/B partitions.
-
-    Returns:
-      The requested information as a string or None if there is no
-      partition with the given label.
-
-    Raises:
-      BptParsingError: If an input file has an error.
-      BptError: If another application-specific error occurs
-    """
-
-    partitions, _ = self._read_json([input_file], ab_collapse)
-
-    part = None
-    for p in partitions:
-      if p.label == part_label:
-        part = p
-        break
-
-    if not part:
-      return None
-
-    value = part.__dict__.get(query_type)
-    # Print out flags as a hex-value.
-    if query_type == 'flags':
-      return '{:#018x}'.format(value)
-    return str(value)
-
-
-class BptTool(object):
-  """Object for bpttool command-line tool."""
-
-  def __init__(self):
-    """Initializer method."""
-    self.bpt = Bpt()
-
-  def run(self, argv):
-    """Command-line processor.
-
-    Arguments:
-      argv: Pass sys.argv from main.
-    """
-    parser = argparse.ArgumentParser()
-    subparsers = parser.add_subparsers(title='subcommands')
-
-    sub_parser = subparsers.add_parser(
-        'version',
-        help='Prints version of bpttool.')
-    sub_parser.set_defaults(func=self.version)
-
-    sub_parser = subparsers.add_parser(
-        'make_table',
-        help='Lays out partitions and creates partition table.')
-    sub_parser.add_argument('--input',
-                            help='Path to partition definition file.',
-                            type=argparse.FileType('r'),
-                            action='append')
-    sub_parser.add_argument('--ab_suffixes',
-                            help='Set or override A/B suffixes.')
-    sub_parser.add_argument('--partitions_offset_begin',
-                            help='Set or override disk partitions '
-                                 'offset begin size.',
-                            type=ParseSize)
-    sub_parser.add_argument('--disk_size',
-                            help='Set or override disk size.',
-                            type=ParseSize)
-    sub_parser.add_argument('--disk_alignment',
-                            help='Set or override disk alignment.',
-                            type=ParseSize)
-    sub_parser.add_argument('--disk_guid',
-                            help='Set or override disk GUID.',
-                            type=ParseGuid)
-    sub_parser.add_argument('--output_json',
-                            help='JSON output file name.',
-                            type=argparse.FileType('w'))
-    sub_parser.add_argument('--output_gpt',
-                            help='Output file name for MBR/GPT/GPT file.',
-                            type=argparse.FileType('w'))
-    sub_parser.set_defaults(func=self.make_table)
-
-    sub_parser = subparsers.add_parser(
-        'make_disk_image',
-        help='Creates disk image for loaded with partitions.')
-    sub_parser.add_argument('--output',
-                            help='Path to image output.',
-                            type=argparse.FileType('w'),
-                            required=True)
-    sub_parser.add_argument('--input',
-                            help='Path to bpt file input.',
-                            type=argparse.FileType('r'),
-                            required=True)
-    sub_parser.add_argument('--image',
-                            help='Partition name and path to image file.',
-                            metavar='PARTITION_NAME:PATH',
-                            action='append')
-    sub_parser.add_argument('--allow_empty_partitions',
-                            help='Allow skipping partitions in bpt file.',
-                            action='store_true')
-    sub_parser.set_defaults(func=self.make_disk_image)
-
-    sub_parser = subparsers.add_parser(
-        'query_partition',
-        help='Looks up informtion about a partition.')
-    sub_parser.add_argument('--input',
-                            help='Path to partition definition file.',
-                            type=argparse.FileType('r'),
-                            required=True)
-    sub_parser.add_argument('--label',
-                            help='Label of partition to look up.',
-                            required=True)
-    sub_parser.add_argument('--ab_collapse',
-                            help='Collapse A/B partitions.',
-                            action='store_true')
-    sub_parser.add_argument('--type',
-                            help='Type of information to look up.',
-                            choices=QUERY_PARTITION_TYPES,
-                            required=True)
-    sub_parser.set_defaults(func=self.query_partition)
-
-    args = parser.parse_args(argv[1:])
-    args.func(args)
-
-  def version(self, _):
-    """Implements the 'version' sub-command."""
-    print '{}.{}'.format(BPT_VERSION_MAJOR, BPT_VERSION_MINOR)
-
-  def query_partition(self, args):
-    """Implements the 'query_partition' sub-command."""
-    try:
-      result = self.bpt.query_partition(args.input,
-                                        args.label,
-                                        args.type,
-                                        args.ab_collapse)
-    except BptParsingError as e:
-      sys.stderr.write('{}: Error parsing: {}\n'.format(e.filename, e.message))
-      sys.exit(1)
-    except BptError as e:
-      sys.stderr.write('{}\n'.format(e.message))
-      sys.exit(1)
-
-    if not result:
-      sys.stderr.write('No partition with label "{}".\n'.format(args.label))
-      sys.exit(1)
-
-    print result
-
-  def make_table(self, args):
-    """Implements the 'make_table' sub-command."""
-    if not args.input:
-      sys.stderr.write('Option --input is required one or more times.\n')
-      sys.exit(1)
-
-    try:
-      (json_str, gpt_bin) = self.bpt.make_table(args.input, args.ab_suffixes,
-                                                args.partitions_offset_begin,
-                                                args.disk_size,
-                                                args.disk_alignment,
-                                                args.disk_guid)
-    except BptParsingError as e:
-      sys.stderr.write('{}: Error parsing: {}\n'.format(e.filename, e.message))
-      sys.exit(1)
-    except BptError as e:
-      sys.stderr.write('{}\n'.format(e.message))
-      sys.exit(1)
-
-    if args.output_json:
-      args.output_json.write(json_str)
-    if args.output_gpt:
-      args.output_gpt.write(gpt_bin)
-
-  def make_disk_image(self, args):
-    """Implements the 'make_disk_image' sub-command."""
-    if not args.input:
-      sys.stderr.write('Option --input is required.\n')
-      sys.exit(1)
-    if not args.output:
-      sys.stderr.write('Option --ouptut is required.\n')
-      sys.exit(1)
-
-    try:
-      self.bpt.make_disk_image(args.output,
-                               args.input,
-                               args.image,
-                               args.allow_empty_partitions)
-    except BptParsingError as e:
-      sys.stderr.write('{}: Error parsing: {}\n'.format(e.filename, e.message))
-      sys.exit(1)
-    except 'BptError' as e:
-      sys.stderr.write('{}\n'.format(e.message))
-      sys.exit(1)
-
-if __name__ == '__main__':
-  tool = BptTool()
-  tool.run(sys.argv)
diff --git a/host/commands/assemble_cvd/clean.cc b/host/commands/assemble_cvd/clean.cc
new file mode 100644
index 0000000..6197a8f
--- /dev/null
+++ b/host/commands/assemble_cvd/clean.cc
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+#include "host/commands/assemble_cvd/clean.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <regex>
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include "host/commands/assemble_cvd/flags.h"
+#include "common/libs/utils/files.h"
+
+namespace cuttlefish {
+namespace {
+
+bool CleanPriorFiles(const std::string& path, const std::set<std::string>& preserving) {
+  if (preserving.count(cpp_basename(path))) {
+    LOG(DEBUG) << "Preserving: " << path;
+    return true;
+  }
+  struct stat statbuf;
+  if (lstat(path.c_str(), &statbuf) < 0) {
+    int error_num = errno;
+    if (error_num == ENOENT) {
+      return true;
+    } else {
+      LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
+      return false;
+    }
+  }
+  if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
+    LOG(DEBUG) << "Deleting: " << path;
+    if (unlink(path.c_str()) < 0) {
+      int error_num = errno;
+      LOG(ERROR) << "Could not unlink \"" << path << "\", error was " << strerror(error_num);
+      return false;
+    }
+    return true;
+  }
+  std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(path.c_str()), closedir);
+  if (!dir) {
+    int error_num = errno;
+    LOG(ERROR) << "Could not clean \"" << path << "\": error was " << strerror(error_num);
+    return false;
+  }
+  for (auto entity = readdir(dir.get()); entity != nullptr; entity = readdir(dir.get())) {
+    std::string entity_name(entity->d_name);
+    if (entity_name == "." || entity_name == "..") {
+      continue;
+    }
+    std::string entity_path = path + "/" + entity_name;
+    if (!CleanPriorFiles(entity_path.c_str(), preserving)) {
+      return false;
+    }
+  }
+  if (rmdir(path.c_str()) < 0) {
+    if (!(errno == EEXIST || errno == ENOTEMPTY)) {
+      // If EEXIST or ENOTEMPTY, probably because a file was preserved
+      int error_num = errno;
+      LOG(ERROR) << "Could not rmdir \"" << path << "\", error was " << strerror(error_num);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool CleanPriorFiles(const std::vector<std::string>& paths, const std::set<std::string>& preserving) {
+  std::string prior_files;
+  for (auto path : paths) {
+    struct stat statbuf;
+    if (stat(path.c_str(), &statbuf) < 0 && errno != ENOENT) {
+      // If ENOENT, it doesn't exist yet, so there is no work to do'
+      int error_num = errno;
+      LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
+      return false;
+    }
+    bool is_directory = (statbuf.st_mode & S_IFMT) == S_IFDIR;
+    prior_files += (is_directory ? (path + "/*") : path) + " ";
+  }
+  LOG(DEBUG) << "Assuming prior files of " << prior_files;
+  std::string lsof_cmd = "lsof -t " + prior_files + " >/dev/null 2>&1";
+  int rval = std::system(lsof_cmd.c_str());
+  // lsof returns 0 if any of the files are open
+  if (WEXITSTATUS(rval) == 0) {
+    LOG(ERROR) << "Clean aborted: files are in use";
+    return false;
+  }
+  for (const auto& path : paths) {
+    if (!CleanPriorFiles(path, preserving)) {
+      LOG(ERROR) << "Remove of file under \"" << path << "\" failed";
+      return false;
+    }
+  }
+  return true;
+}
+
+} // namespace
+
+bool CleanPriorFiles(
+    const std::set<std::string>& preserving,
+    const std::string& assembly_dir,
+    const std::string& instance_dir) {
+  std::vector<std::string> paths = {
+    // Everything in the assembly directory
+    assembly_dir,
+    // The environment file
+    GetCuttlefishEnvPath(),
+    // The global link to the config file
+    GetGlobalConfigFileLink(),
+  };
+
+  std::string runtime_dir_parent = cpp_dirname(AbsolutePath(instance_dir));
+  std::string runtime_dirs_basename = cpp_basename(AbsolutePath(instance_dir));
+
+  std::regex instance_dir_regex("^.+\\.[1-9]\\d*$");
+  for (const auto& path : DirectoryContents(runtime_dir_parent)) {
+    std::string absl_path = runtime_dir_parent + "/" + path;
+    if((path.rfind(runtime_dirs_basename, 0) == 0) && std::regex_match(path, instance_dir_regex) &&
+        DirectoryExists(absl_path)) {
+      paths.push_back(absl_path);
+    }
+  }
+  paths.push_back(instance_dir);
+  return CleanPriorFiles(paths, preserving);
+}
+
+bool EnsureDirectoryExists(const std::string& directory_path) {
+  if (!DirectoryExists(directory_path)) {
+    LOG(DEBUG) << "Setting up " << directory_path;
+    if (mkdir(directory_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
+        && errno != EEXIST) {
+      PLOG(ERROR) << "Failed to create dir: \"" << directory_path << "\" ";
+      return false;
+    }
+  }
+  return true;
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/clean.h b/host/commands/assemble_cvd/clean.h
new file mode 100644
index 0000000..1f33685
--- /dev/null
+++ b/host/commands/assemble_cvd/clean.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <set>
+#include <string>
+
+namespace cuttlefish {
+
+bool CleanPriorFiles(
+    const std::set<std::string>& preserving,
+    const std::string& assembly_dir,
+    const std::string& instance_dir);
+
+bool EnsureDirectoryExists(const std::string& directory_path);
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/data_image.cc b/host/commands/assemble_cvd/data_image.cc
deleted file mode 100644
index 4e89ba6..0000000
--- a/host/commands/assemble_cvd/data_image.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-#include "host/commands/assemble_cvd/data_image.h"
-
-#include <glog/logging.h>
-
-#include "common/libs/fs/shared_buf.h"
-
-#include "common/libs/utils/files.h"
-#include "common/libs/utils/subprocess.h"
-
-#include "host/commands/assemble_cvd/mbr.h"
-
-namespace {
-const std::string kDataPolicyUseExisting = "use_existing";
-const std::string kDataPolicyCreateIfMissing = "create_if_missing";
-const std::string kDataPolicyAlwaysCreate = "always_create";
-const std::string kDataPolicyResizeUpTo= "resize_up_to";
-
-const int FSCK_ERROR_CORRECTED = 1;
-const int FSCK_ERROR_CORRECTED_REQUIRES_REBOOT = 2;
-
-bool ForceFsckImage(const char* data_image) {
-  auto fsck_path = vsoc::DefaultHostArtifactsPath("bin/fsck.f2fs");
-  int fsck_status = cvd::execute({fsck_path, "-y", "-f", data_image});
-  if (fsck_status & ~(FSCK_ERROR_CORRECTED|FSCK_ERROR_CORRECTED_REQUIRES_REBOOT)) {
-    LOG(ERROR) << "`fsck.f2fs -y -f " << data_image << "` failed with code "
-               << fsck_status;
-    return false;
-  }
-  return true;
-}
-
-bool ResizeImage(const char* data_image, int data_image_mb) {
-  auto file_mb = cvd::FileSize(data_image) >> 20;
-  if (file_mb > data_image_mb) {
-    LOG(ERROR) << data_image << " is already " << file_mb << " MB, will not "
-               << "resize down.";
-    return false;
-  } else if (file_mb == data_image_mb) {
-    LOG(INFO) << data_image << " is already the right size";
-    return true;
-  } else {
-    off_t raw_target = static_cast<off_t>(data_image_mb) << 20;
-    auto fd = cvd::SharedFD::Open(data_image, O_RDWR);
-    if (fd->Truncate(raw_target) != 0) {
-      LOG(ERROR) << "`truncate --size=" << data_image_mb << "M "
-                  << data_image << "` failed:" << fd->StrError();
-      return false;
-    }
-    bool fsck_success = ForceFsckImage(data_image);
-    if (!fsck_success) {
-      return false;
-    }
-    auto resize_path = vsoc::DefaultHostArtifactsPath("bin/resize.f2fs");
-    int resize_status = cvd::execute({resize_path, data_image});
-    if (resize_status != 0) {
-      LOG(ERROR) << "`resize.f2fs " << data_image << "` failed with code "
-                 << resize_status;
-      return false;
-    }
-    fsck_success = ForceFsckImage(data_image);
-    if (!fsck_success) {
-      return false;
-    }
-  }
-  return true;
-}
-} // namespace
-
-void CreateBlankImage(
-    const std::string& image, int num_mb, const std::string& image_fmt) {
-  LOG(INFO) << "Creating " << image;
-
-  off_t image_size_bytes = static_cast<off_t>(num_mb) << 20;
-  // The newfs_msdos tool with the mandatory -C option will do the same
-  // as below to zero the image file, so we don't need to do it here
-  if (image_fmt != "sdcard") {
-    auto fd = cvd::SharedFD::Open(image, O_CREAT | O_TRUNC | O_RDWR, 0666);
-    if (fd->Truncate(image_size_bytes) != 0) {
-      LOG(ERROR) << "`truncate --size=" << num_mb << "M " << image
-                 << "` failed:" << fd->StrError();
-      return;
-    }
-  }
-
-  if (image_fmt == "ext4") {
-    cvd::execute({"/sbin/mkfs.ext4", image});
-  } else if (image_fmt == "f2fs") {
-    auto make_f2fs_path = vsoc::DefaultHostArtifactsPath("bin/make_f2fs");
-    cvd::execute({make_f2fs_path, "-t", image_fmt, image, "-g", "android"});
-  } else if (image_fmt == "sdcard") {
-    // Reserve 1MB in the image for the MBR and padding, to simulate what
-    // other OSes do by default when partitioning a drive
-    off_t offset_size_bytes = 1 << 20;
-    image_size_bytes -= offset_size_bytes;
-    off_t image_size_sectors = image_size_bytes / 512;
-    auto newfs_msdos_path = vsoc::DefaultHostArtifactsPath("bin/newfs_msdos");
-    cvd::execute({newfs_msdos_path, "-F", "32", "-m", "0xf8", "-a", "4088",
-                                    "-o", "0",  "-c", "8",    "-h", "255",
-                                    "-u", "63", "-S", "512",
-                                    "-s", std::to_string(image_size_sectors),
-                                    "-C", std::to_string(num_mb) + "M",
-                                    "-@", std::to_string(offset_size_bytes),
-                                    image});
-    // Write the MBR after the filesystem is formatted, as the formatting tools
-    // don't consistently preserve the image contents
-    MasterBootRecord mbr = {
-      .partitions = {{
-        .partition_type = 0xC,
-        .first_lba = (std::uint32_t) offset_size_bytes / SECTOR_SIZE,
-        .num_sectors = (std::uint32_t) image_size_bytes / SECTOR_SIZE,
-      }},
-      .boot_signature = { 0x55, 0xAA },
-    };
-    auto fd = cvd::SharedFD::Open(image, O_RDWR);
-    if (cvd::WriteAllBinary(fd, &mbr) != sizeof(MasterBootRecord)) {
-      LOG(ERROR) << "Writing MBR to " << image << " failed:" << fd->StrError();
-      return;
-    }
-  } else if (image_fmt != "none") {
-    LOG(WARNING) << "Unknown image format '" << image_fmt
-                 << "' for " << image << ", treating as 'none'.";
-  }
-}
-
-bool ApplyDataImagePolicy(const vsoc::CuttlefishConfig& config,
-                          const std::string& data_image) {
-  bool data_exists = cvd::FileHasContent(data_image.c_str());
-  bool remove{};
-  bool create{};
-  bool resize{};
-
-  if (config.data_policy() == kDataPolicyUseExisting) {
-    if (!data_exists) {
-      LOG(ERROR) << "Specified data image file does not exists: " << data_image;
-      return false;
-    }
-    if (config.blank_data_image_mb() > 0) {
-      LOG(ERROR) << "You should NOT use -blank_data_image_mb with -data_policy="
-                 << kDataPolicyUseExisting;
-      return false;
-    }
-    create = false;
-    remove = false;
-    resize = false;
-  } else if (config.data_policy() == kDataPolicyAlwaysCreate) {
-    remove = data_exists;
-    create = true;
-    resize = false;
-  } else if (config.data_policy() == kDataPolicyCreateIfMissing) {
-    create = !data_exists;
-    remove = false;
-    resize = false;
-  } else if (config.data_policy() == kDataPolicyResizeUpTo) {
-    create = false;
-    remove = false;
-    resize = true;
-  } else {
-    LOG(ERROR) << "Invalid data_policy: " << config.data_policy();
-    return false;
-  }
-
-  if (remove) {
-    cvd::RemoveFile(data_image.c_str());
-  }
-
-  if (create) {
-    if (config.blank_data_image_mb() <= 0) {
-      LOG(ERROR) << "-blank_data_image_mb is required to create data image";
-      return false;
-    }
-    CreateBlankImage(data_image.c_str(), config.blank_data_image_mb(),
-                     config.blank_data_image_fmt());
-  } else if (resize) {
-    if (!data_exists) {
-      LOG(ERROR) << data_image << " does not exist, but resizing was requested";
-      return false;
-    }
-    return ResizeImage(data_image.c_str(), config.blank_data_image_mb());
-  } else {
-    LOG(INFO) << data_image << " exists. Not creating it.";
-  }
-
-  return true;
-}
-
-bool InitializeMiscImage(const std::string& misc_image) {
-  bool misc_exists = cvd::FileHasContent(misc_image.c_str());
-
-  if (misc_exists) {
-    LOG(INFO) << "misc partition image: use existing";
-    return true;
-  }
-
-  LOG(INFO) << "misc partition image: creating empty";
-  CreateBlankImage(misc_image, 1 /* mb */, "none");
-  return true;
-}
diff --git a/host/commands/assemble_cvd/data_image.h b/host/commands/assemble_cvd/data_image.h
deleted file mode 100644
index 4c4022f..0000000
--- a/host/commands/assemble_cvd/data_image.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-#include <string>
-
-#include "host/libs/config/cuttlefish_config.h"
-
-bool ApplyDataImagePolicy(const vsoc::CuttlefishConfig& config,
-                          const std::string& path);
-bool InitializeMiscImage(const std::string& misc_image);
-void CreateBlankImage(
-    const std::string& image, int num_mb, const std::string& image_fmt);
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
new file mode 100644
index 0000000..e5ccac9
--- /dev/null
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "host/commands/assemble_cvd/disk_flags.h"
+
+#include <sys/statvfs.h>
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/utils/environment.h"
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/size_utils.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/commands/assemble_cvd/boot_config.h"
+#include "host/commands/assemble_cvd/boot_image_utils.h"
+#include "host/commands/assemble_cvd/super_image_mixer.h"
+#include "host/libs/config/bootconfig_args.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/data_image.h"
+#include "host/libs/image_aggregator/image_aggregator.h"
+#include "host/libs/vm_manager/crosvm_manager.h"
+
+// Taken from external/avb/libavb/avb_slot_verify.c; this define is not in the headers
+#define VBMETA_MAX_SIZE 65536ul
+
+DEFINE_string(system_image_dir, cuttlefish::DefaultGuestImagePath(""),
+              "Location of the system partition images.");
+
+DEFINE_string(boot_image, "",
+              "Location of cuttlefish boot image. If empty it is assumed to be "
+              "boot.img in the directory specified by -system_image_dir.");
+DEFINE_string(data_image, "", "Location of the data partition image.");
+DEFINE_string(super_image, "", "Location of the super partition image.");
+DEFINE_string(misc_image, "",
+              "Location of the misc partition image. If the image does not "
+              "exist, a blank new misc partition image is created.");
+DEFINE_string(metadata_image, "", "Location of the metadata partition image "
+              "to be generated.");
+DEFINE_string(vendor_boot_image, "",
+              "Location of cuttlefish vendor boot image. If empty it is assumed to "
+              "be vendor_boot.img in the directory specified by -system_image_dir.");
+DEFINE_string(vbmeta_image, "",
+              "Location of cuttlefish vbmeta image. If empty it is assumed to "
+              "be vbmeta.img in the directory specified by -system_image_dir.");
+DEFINE_string(vbmeta_system_image, "",
+              "Location of cuttlefish vbmeta_system image. If empty it is assumed to "
+              "be vbmeta_system.img in the directory specified by -system_image_dir.");
+DEFINE_string(esp, "", "Path to ESP partition image (FAT formatted)");
+
+DEFINE_int32(blank_metadata_image_mb, 16,
+             "The size of the blank metadata image to generate, MB.");
+DEFINE_int32(blank_sdcard_image_mb, 2048,
+             "If enabled, the size of the blank sdcard image to generate, MB.");
+
+DECLARE_string(bootloader);
+DECLARE_bool(use_sdcard);
+DECLARE_string(initramfs_path);
+DECLARE_string(kernel_path);
+DECLARE_bool(resume);
+DECLARE_bool(protected_vm);
+
+namespace cuttlefish {
+
+using vm_manager::CrosvmManager;
+
+bool ResolveInstanceFiles() {
+  if (FLAGS_system_image_dir.empty()) {
+    LOG(ERROR) << "--system_image_dir must be specified.";
+    return false;
+  }
+
+  // If user did not specify location of either of these files, expect them to
+  // be placed in --system_image_dir location.
+  std::string default_boot_image = FLAGS_system_image_dir + "/boot.img";
+  SetCommandLineOptionWithMode("boot_image", default_boot_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_data_image = FLAGS_system_image_dir + "/userdata.img";
+  SetCommandLineOptionWithMode("data_image", default_data_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_metadata_image = FLAGS_system_image_dir + "/metadata.img";
+  SetCommandLineOptionWithMode("metadata_image", default_metadata_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_super_image = FLAGS_system_image_dir + "/super.img";
+  SetCommandLineOptionWithMode("super_image", default_super_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_misc_image = FLAGS_system_image_dir + "/misc.img";
+  SetCommandLineOptionWithMode("misc_image", default_misc_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_vendor_boot_image = FLAGS_system_image_dir
+                                        + "/vendor_boot.img";
+  SetCommandLineOptionWithMode("vendor_boot_image",
+                               default_vendor_boot_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_vbmeta_image = FLAGS_system_image_dir + "/vbmeta.img";
+  SetCommandLineOptionWithMode("vbmeta_image", default_vbmeta_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_vbmeta_system_image = FLAGS_system_image_dir
+                                          + "/vbmeta_system.img";
+  SetCommandLineOptionWithMode("vbmeta_system_image",
+                               default_vbmeta_system_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+
+  return true;
+}
+
+std::vector<ImagePartition> os_composite_disk_config(
+    const CuttlefishConfig::InstanceSpecific& instance) {
+  std::vector<ImagePartition> partitions;
+  partitions.push_back(ImagePartition {
+    .label = "misc",
+    .image_file_path = FLAGS_misc_image,
+  });
+  if (!FLAGS_esp.empty()) {
+    partitions.push_back(ImagePartition {
+      .label = "esp",
+      .image_file_path = FLAGS_esp,
+      .type = kEfiSystemPartition,
+    });
+  }
+  partitions.push_back(ImagePartition {
+    .label = "boot_a",
+    .image_file_path = FLAGS_boot_image,
+  });
+  partitions.push_back(ImagePartition {
+    .label = "boot_b",
+    .image_file_path = FLAGS_boot_image,
+  });
+  // Boot image repacking is not supported on protected VMs. Repacking requires
+  // resigning the image and keys on android hosts aren't trusted.
+  if (!FLAGS_protected_vm) {
+    partitions.push_back(ImagePartition{
+        .label = "vendor_boot_a",
+        .image_file_path = instance.vendor_boot_image_path(),
+    });
+    partitions.push_back(ImagePartition{
+        .label = "vendor_boot_b",
+        .image_file_path = instance.vendor_boot_image_path(),
+    });
+  } else {
+    partitions.push_back(ImagePartition{
+        .label = "vendor_boot_a",
+        .image_file_path = FLAGS_vendor_boot_image,
+    });
+    partitions.push_back(ImagePartition{
+        .label = "vendor_boot_b",
+        .image_file_path = FLAGS_vendor_boot_image,
+    });
+  }
+  partitions.push_back(ImagePartition {
+    .label = "vbmeta_a",
+    .image_file_path = FLAGS_vbmeta_image,
+  });
+  partitions.push_back(ImagePartition {
+    .label = "vbmeta_b",
+    .image_file_path = FLAGS_vbmeta_image,
+  });
+  partitions.push_back(ImagePartition {
+    .label = "vbmeta_system_a",
+    .image_file_path = FLAGS_vbmeta_system_image,
+  });
+  partitions.push_back(ImagePartition {
+    .label = "vbmeta_system_b",
+    .image_file_path = FLAGS_vbmeta_system_image,
+  });
+  partitions.push_back(ImagePartition {
+    .label = "super",
+    .image_file_path = FLAGS_super_image,
+  });
+  partitions.push_back(ImagePartition {
+    .label = "userdata",
+    .image_file_path = FLAGS_data_image,
+  });
+  partitions.push_back(ImagePartition {
+    .label = "metadata",
+    .image_file_path = FLAGS_metadata_image,
+  });
+  return partitions;
+}
+
+std::vector<ImagePartition> persistent_composite_disk_config(
+    const CuttlefishConfig::InstanceSpecific& instance) {
+  std::vector<ImagePartition> partitions;
+
+  // Note that if the position of uboot_env changes, the environment for
+  // u-boot must be updated as well (see boot_config.cc and
+  // cuttlefish.fragment in external/u-boot).
+  partitions.push_back(ImagePartition{
+      .label = "uboot_env",
+      .image_file_path = instance.uboot_env_image_path(),
+  });
+  if (!FLAGS_protected_vm) {
+    partitions.push_back(ImagePartition{
+        .label = "frp",
+        .image_file_path = instance.factory_reset_protected_path(),
+    });
+  }
+  partitions.push_back(ImagePartition{
+      .label = "bootconfig",
+      .image_file_path = instance.persistent_bootconfig_path(),
+  });
+  return partitions;
+}
+
+static std::chrono::system_clock::time_point LastUpdatedInputDisk(
+    const std::vector<ImagePartition>& partitions) {
+  std::chrono::system_clock::time_point ret;
+  for (auto& partition : partitions) {
+    if (partition.label == "frp") {
+      continue;
+    }
+
+    auto partition_mod_time = FileModificationTime(partition.image_file_path);
+    if (partition_mod_time > ret) {
+      ret = partition_mod_time;
+    }
+  }
+  return ret;
+}
+
+bool ShouldCreateAllCompositeDisks(const CuttlefishConfig& config) {
+  std::chrono::system_clock::time_point youngest_disk_img;
+  for (auto& partition :
+       os_composite_disk_config(config.ForDefaultInstance())) {
+    auto partition_mod_time = FileModificationTime(partition.image_file_path);
+    if (partition_mod_time > youngest_disk_img) {
+      youngest_disk_img = partition_mod_time;
+    }
+  }
+
+  // If the youngest partition img is younger than any composite disk, this fact implies that
+  // the composite disks are all out of date and need to be reinitialized.
+  for (auto& instance : config.Instances()) {
+    if (!FileExists(instance.os_composite_disk_path())) {
+      continue;
+    }
+    if (youngest_disk_img >
+        FileModificationTime(instance.os_composite_disk_path())) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool DoesCompositeMatchCurrentDiskConfig(
+    const std::string& prior_disk_config_path,
+    const std::vector<ImagePartition>& partitions) {
+  std::string current_disk_config_path = prior_disk_config_path + ".tmp";
+  std::ostringstream disk_conf;
+  for (auto& partition : partitions) {
+    disk_conf << partition.image_file_path << "\n";
+  }
+
+  {
+    // This file acts as a descriptor of the cuttlefish disk contents in a VMM agnostic way (VMMs
+    // used are QEMU and CrosVM at the time of writing). This file is used to determine if the
+    // disk config for the pending boot matches the disk from the past boot.
+    std::ofstream file_out(current_disk_config_path.c_str(), std::ios::binary);
+    file_out << disk_conf.str();
+    CHECK(file_out.good()) << "Disk config verification failed.";
+  }
+
+  if (!FileExists(prior_disk_config_path) ||
+      ReadFile(prior_disk_config_path) != ReadFile(current_disk_config_path)) {
+    CHECK(cuttlefish::RenameFile(current_disk_config_path, prior_disk_config_path))
+        << "Unable to delete the old disk config descriptor";
+    LOG(DEBUG) << "Disk Config has changed since last boot. Regenerating composite disk.";
+    return false;
+  } else {
+    RemoveFile(current_disk_config_path);
+    return true;
+  }
+}
+
+bool ShouldCreateCompositeDisk(const std::string& composite_disk_path,
+                               const std::vector<ImagePartition>& partitions) {
+  if (!FileExists(composite_disk_path)) {
+    return true;
+  }
+
+  auto composite_age = FileModificationTime(composite_disk_path);
+  return composite_age < LastUpdatedInputDisk(partitions);
+}
+
+static uint64_t AvailableSpaceAtPath(const std::string& path) {
+  struct statvfs vfs;
+  if (statvfs(path.c_str(), &vfs) != 0) {
+    int error_num = errno;
+    LOG(ERROR) << "Could not find space available at " << path << ", error was "
+               << strerror(error_num);
+    return 0;
+  }
+  // f_frsize (block size) * f_bavail (free blocks) for unprivileged users.
+  return static_cast<uint64_t>(vfs.f_frsize) * vfs.f_bavail;
+}
+
+bool CreateCompositeDisk(const CuttlefishConfig& config,
+                         const CuttlefishConfig::InstanceSpecific& instance) {
+  if (!SharedFD::Open(instance.os_composite_disk_path().c_str(),
+                      O_WRONLY | O_CREAT, 0644)
+           ->IsOpen()) {
+    LOG(ERROR) << "Could not ensure " << instance.os_composite_disk_path()
+               << " exists";
+    return false;
+  }
+  if (config.vm_manager() == CrosvmManager::name()) {
+    // Check if filling in the sparse image would run out of disk space.
+    auto existing_sizes = SparseFileSizes(FLAGS_data_image);
+    if (existing_sizes.sparse_size == 0 && existing_sizes.disk_size == 0) {
+      LOG(ERROR) << "Unable to determine size of \"" << FLAGS_data_image
+                 << "\". Does this file exist?";
+    }
+    auto available_space = AvailableSpaceAtPath(FLAGS_data_image);
+    if (available_space < existing_sizes.sparse_size - existing_sizes.disk_size) {
+      // TODO(schuffelen): Duplicate this check in run_cvd when it can run on a separate machine
+      LOG(ERROR) << "Not enough space remaining in fs containing " << FLAGS_data_image;
+      LOG(ERROR) << "Wanted " << (existing_sizes.sparse_size - existing_sizes.disk_size);
+      LOG(ERROR) << "Got " << available_space;
+      return false;
+    } else {
+      LOG(DEBUG) << "Available space: " << available_space;
+      LOG(DEBUG) << "Sparse size of \"" << FLAGS_data_image << "\": "
+                 << existing_sizes.sparse_size;
+      LOG(DEBUG) << "Disk size of \"" << FLAGS_data_image << "\": "
+                 << existing_sizes.disk_size;
+    }
+    std::string header_path =
+        instance.PerInstancePath("os_composite_gpt_header.img");
+    std::string footer_path =
+        instance.PerInstancePath("os_composite_gpt_footer.img");
+    CreateCompositeDisk(os_composite_disk_config(instance), header_path,
+                        footer_path, instance.os_composite_disk_path());
+  } else {
+    // If this doesn't fit into the disk, it will fail while aggregating. The
+    // aggregator doesn't maintain any sparse attributes.
+    AggregateImage(os_composite_disk_config(instance),
+                   instance.os_composite_disk_path());
+  }
+  return true;
+}
+
+bool CreatePersistentCompositeDisk(
+    const CuttlefishConfig& config,
+    const CuttlefishConfig::InstanceSpecific& instance) {
+  if (!SharedFD::Open(instance.persistent_composite_disk_path().c_str(),
+                      O_WRONLY | O_CREAT, 0644)
+           ->IsOpen()) {
+    LOG(ERROR) << "Could not ensure "
+               << instance.persistent_composite_disk_path() << " exists";
+    return false;
+  }
+  if (config.vm_manager() == CrosvmManager::name()) {
+    std::string header_path =
+        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());
+  } else {
+    AggregateImage(persistent_composite_disk_config(instance),
+                   instance.persistent_composite_disk_path());
+  }
+  return true;
+}
+
+static void RepackAllBootImages(const CuttlefishConfig* config) {
+  CHECK(FileHasContent(FLAGS_boot_image))
+      << "File not found: " << FLAGS_boot_image;
+
+  CHECK(FileHasContent(FLAGS_vendor_boot_image))
+      << "File not found: " << FLAGS_vendor_boot_image;
+
+  if (FLAGS_kernel_path.size()) {
+    const std::string new_boot_image_path =
+        config->AssemblyPath("boot_repacked.img");
+    bool success = RepackBootImage(FLAGS_kernel_path, FLAGS_boot_image,
+                                   new_boot_image_path, config->assembly_dir());
+    CHECK(success) << "Failed to regenerate the boot image with the new kernel";
+    SetCommandLineOptionWithMode("boot_image", new_boot_image_path.c_str(),
+                                 google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  }
+
+  for (auto instance : config->Instances()) {
+    const std::string new_vendor_boot_image_path =
+        instance.vendor_boot_image_path();
+    const std::vector<std::string> boot_config_vector =
+        BootconfigArgsFromConfig(*config, instance);
+    if (FLAGS_kernel_path.size() || FLAGS_initramfs_path.size()) {
+      // Repack the vendor boot images if kernels and/or ramdisks are passed in.
+      if (FLAGS_initramfs_path.size()) {
+        bool success = RepackVendorBootImage(
+            FLAGS_initramfs_path, FLAGS_vendor_boot_image,
+            new_vendor_boot_image_path, config->assembly_dir(),
+            instance.instance_dir(), boot_config_vector,
+            config->bootconfig_supported());
+        CHECK(success) << "Failed to regenerate the vendor boot image with the "
+                          "new ramdisk";
+      } else {
+        // This control flow implies a kernel with all configs built in.
+        // If it's just the kernel, repack the vendor boot image without a
+        // ramdisk.
+        bool success = RepackVendorBootImageWithEmptyRamdisk(
+            FLAGS_vendor_boot_image, new_vendor_boot_image_path,
+            config->assembly_dir(), instance.instance_dir(), boot_config_vector,
+            config->bootconfig_supported());
+        CHECK(success)
+            << "Failed to regenerate the vendor boot image without a ramdisk";
+      }
+    } else {
+      // Repack the vendor boot image to add the instance specific bootconfig
+      // parameters
+      bool success = RepackVendorBootImage(
+          std::string(), FLAGS_vendor_boot_image, new_vendor_boot_image_path,
+          config->assembly_dir(), instance.instance_dir(), boot_config_vector,
+          config->bootconfig_supported());
+      CHECK(success) << "Failed to regenerate the vendor boot image";
+    }
+  }
+}
+
+void CreateDynamicDiskFiles(const FetcherConfig& fetcher_config,
+                            const CuttlefishConfig* config) {
+  // Create misc if necessary
+  CHECK(InitializeMiscImage(FLAGS_misc_image)) << "Failed to create misc image";
+
+  // Create data if necessary
+  DataImageResult dataImageResult = ApplyDataImagePolicy(*config, FLAGS_data_image);
+  CHECK(dataImageResult != DataImageResult::Error) << "Failed to set up userdata";
+
+  if (!FileExists(FLAGS_metadata_image)) {
+    CreateBlankImage(FLAGS_metadata_image, FLAGS_blank_metadata_image_mb, "none");
+  }
+
+  // If we are booting a protected VM, for now, assume we want a super minimal
+  // environment with no userdata encryption, limited debug, no FRP emulation, a
+  // static env for the bootloader, no SD-Card and no resume-on-reboot HAL
+  // support. We can also assume that image repacking isn't trusted. Repacking
+  // requires resigning the image and keys from an android host aren't trusted.
+  if (!FLAGS_protected_vm) {
+    RepackAllBootImages(config);
+
+    for (const auto& instance : config->Instances()) {
+      if (!FileExists(instance.access_kregistry_path())) {
+        CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
+      }
+
+      if (!FileExists(instance.pstore_path())) {
+        CreateBlankImage(instance.pstore_path(), 2 /* mb */, "none");
+      }
+
+      if (FLAGS_use_sdcard && !FileExists(instance.sdcard_path())) {
+        CreateBlankImage(instance.sdcard_path(),
+                         FLAGS_blank_sdcard_image_mb, "sdcard");
+      }
+
+      CHECK(InitBootloaderEnvPartition(*config, instance))
+          << "Failed to create bootloader environment partition";
+
+      const auto frp = instance.factory_reset_protected_path();
+      if (!FileExists(frp)) {
+        CreateBlankImage(frp, 1 /* mb */, "none");
+      }
+
+      const auto bootconfig_path = instance.persistent_bootconfig_path();
+      if (!FileExists(bootconfig_path)) {
+        CreateBlankImage(bootconfig_path, 1 /* mb */, "none");
+      }
+
+      auto bootconfig_fd = SharedFD::Open(bootconfig_path, O_RDWR);
+      CHECK(bootconfig_fd->IsOpen())
+          << "Unable to open bootconfig file: " << bootconfig_fd->StrError();
+
+      const std::string bootconfig =
+          android::base::Join(BootconfigArgsFromConfig(*config, instance),
+                              "\n") +
+          "\n";
+      ssize_t bytesWritten = WriteAll(bootconfig_fd, bootconfig);
+      CHECK(bytesWritten == bootconfig.size());
+      LOG(DEBUG)
+          << "Bootconfig parameters from vendor boot image and config are "
+          << ReadFile(bootconfig_path);
+
+      const off_t bootconfig_size_bytes =
+          AlignToPowerOf2(bootconfig.size(), PARTITION_SIZE_SHIFT);
+      CHECK(bootconfig_fd->Truncate(bootconfig_size_bytes) == 0)
+          << "`truncate --size=" << bootconfig_size_bytes << " bytes "
+          << bootconfig_path << "` failed:" << bootconfig_fd->StrError();
+    }
+  }
+
+  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 (!FLAGS_esp.empty()) {
+    CHECK(FileHasContent(FLAGS_esp))
+        << "File not found: " << FLAGS_esp;
+  }
+
+  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.";
+  }
+
+  bool newDataImage = dataImageResult == DataImageResult::FileUpdated;
+
+  for (auto instance : config->Instances()) {
+    bool compositeMatchesDiskConfig = DoesCompositeMatchCurrentDiskConfig(
+        instance.PerInstancePath("os_composite_disk_config.txt"),
+        os_composite_disk_config(instance));
+    bool oldCompositeDisk = ShouldCreateCompositeDisk(
+        instance.os_composite_disk_path(), os_composite_disk_config(instance));
+    if (!compositeMatchesDiskConfig || oldCompositeDisk || !FLAGS_resume || newDataImage) {
+      if (FLAGS_resume) {
+        LOG(INFO) << "Requested to continue an existing session, (the default) "
+                  << "but the disk files have become out of date. Wiping the "
+                  << "old session files and starting a new session for device "
+                  << instance.serial_number();
+      }
+      CHECK(CreateCompositeDisk(*config, instance))
+          << "Failed to create composite disk";
+      if (FileExists(instance.access_kregistry_path())) {
+        CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
+      }
+      if (FileExists(instance.pstore_path())) {
+        CreateBlankImage(instance.pstore_path(), 2 /* mb */, "none");
+      }
+    }
+  }
+
+  if (!FLAGS_protected_vm) {
+    for (auto instance : config->Instances()) {
+      auto overlay_path = instance.PerInstancePath("overlay.img");
+      bool missingOverlay = !FileExists(overlay_path);
+      bool newOverlay = FileModificationTime(overlay_path) <
+                        FileModificationTime(instance.os_composite_disk_path());
+      if (missingOverlay || !FLAGS_resume || newOverlay) {
+        CreateQcowOverlay(config->crosvm_binary(),
+                          instance.os_composite_disk_path(), overlay_path);
+      }
+    }
+  }
+
+  for (auto instance : config->Instances()) {
+    // Check that the files exist
+    for (const auto& file : instance.virtual_disk_paths()) {
+      if (!file.empty()) {
+        CHECK(FileHasContent(file)) << "File not found: " << file;
+      }
+    }
+  }
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/disk_flags.h b/host/commands/assemble_cvd/disk_flags.h
new file mode 100644
index 0000000..3491c3a
--- /dev/null
+++ b/host/commands/assemble_cvd/disk_flags.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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 <chrono>
+#include <memory>
+#include <vector>
+
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/fetcher_config.h"
+
+namespace cuttlefish {
+
+bool ResolveInstanceFiles();
+bool ShouldCreateAllCompositeDisks(const CuttlefishConfig& config);
+void CreateDynamicDiskFiles(const FetcherConfig& fetcher_config,
+                            const CuttlefishConfig* config);
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index 8562271..43f7bc2 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -1,48 +1,47 @@
 #include "host/commands/assemble_cvd/flags.h"
 
-#include <dirent.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+#include <json/json.h>
+#include <json/writer.h>
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
 #include <unistd.h>
 
 #include <algorithm>
 #include <array>
-#include <iostream>
 #include <fstream>
-
-#include <android-base/strings.h>
-#include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <iostream>
+#include <optional>
+#include <regex>
+#include <set>
+#include <sstream>
 
 #include "common/libs/utils/environment.h"
 #include "common/libs/utils/files.h"
-#include "host/commands/assemble_cvd/boot_image_unpacker.h"
-#include "host/commands/assemble_cvd/data_image.h"
-#include "host/commands/assemble_cvd/image_aggregator.h"
-#include "host/commands/assemble_cvd/assembler_defs.h"
-#include "host/commands/assemble_cvd/super_image_mixer.h"
-#include "host/libs/config/fetcher_config.h"
+#include "host/commands/assemble_cvd/alloc.h"
+#include "host/commands/assemble_cvd/boot_config.h"
+#include "host/commands/assemble_cvd/clean.h"
+#include "host/commands/assemble_cvd/disk_flags.h"
+#include "host/libs/config/host_tools_version.h"
+#include "host/libs/graphics_detector/graphics_detector.h"
 #include "host/libs/vm_manager/crosvm_manager.h"
 #include "host/libs/vm_manager/qemu_manager.h"
 #include "host/libs/vm_manager/vm_manager.h"
 
-// Taken from external/avb/libavb/avb_slot_verify.c; this define is not in the headers
-#define VBMETA_MAX_SIZE 65536ul
+using cuttlefish::DefaultHostArtifactsPath;
+using cuttlefish::HostBinaryPath;
+using cuttlefish::StringFromEnv;
+using cuttlefish::vm_manager::CrosvmManager;
+using google::FlagSettingMode::SET_FLAGS_DEFAULT;
 
-using vsoc::ForCurrentInstance;
-using vsoc::RandomSerialNumber;
-using cvd::AssemblerExitCodes;
+DEFINE_string(config, "phone",
+              "Config preset name. Will automatically set flag fields "
+              "using the values from this file of presets. See "
+              "device/google/cuttlefish/shared/config/config_*.json "
+              "for possible values.");
 
-DEFINE_string(cache_image, "", "Location of the cache partition image.");
-DEFINE_string(metadata_image, "", "Location of the metadata partition image "
-              "to be generated.");
-DEFINE_int32(blank_metadata_image_mb, 16,
-             "The size of the blank metadata image to generate, MB.");
-DEFINE_int32(blank_sdcard_image_mb, 2048,
-             "The size of the blank sdcard image to generate, MB.");
 DEFINE_int32(cpus, 2, "Virtual CPU count.");
-DEFINE_string(data_image, "", "Location of the data partition image.");
 DEFINE_string(data_policy, "use_existing", "How to handle userdata partition."
             " Either 'use_existing', 'create_if_missing', 'resize_up_to', or "
             "'always_create'.");
@@ -50,64 +49,34 @@
              "The size of the blank data image to generate, MB.");
 DEFINE_string(blank_data_image_fmt, "f2fs",
               "The fs format for the blank data image. Used with mkfs.");
-DEFINE_string(qemu_gdb, "",
-              "Debug flag to pass to qemu. e.g. -qemu_gdb=tcp::1234");
+DEFINE_int32(gdb_port, 0,
+             "Port number to spawn kernel gdb on e.g. -gdb_port=1234. The"
+             "kernel must have been built with CONFIG_RANDOMIZE_BASE "
+             "disabled.");
 
-DEFINE_int32(x_res, 720, "Width of the screen in pixels");
-DEFINE_int32(y_res, 1280, "Height of the screen in pixels");
-DEFINE_int32(dpi, 160, "Pixels per inch for the screen");
+DEFINE_int32(x_res, 0, "Width of the screen in pixels");
+DEFINE_int32(y_res, 0, "Height of the screen in pixels");
+DEFINE_int32(dpi, 0, "Pixels per inch for the screen");
 DEFINE_int32(refresh_rate_hz, 60, "Screen refresh rate in Hertz");
 DEFINE_string(kernel_path, "",
               "Path to the kernel. Overrides the one from the boot image");
 DEFINE_string(initramfs_path, "", "Path to the initramfs");
-DEFINE_bool(decompress_kernel, false,
-            "Whether to decompress the kernel image.");
 DEFINE_string(extra_kernel_cmdline, "",
               "Additional flags to put on the kernel command line");
-DEFINE_int32(loop_max_part, 7, "Maximum number of loop partitions");
 DEFINE_bool(guest_enforce_security, true,
             "Whether to run in enforcing mode (non permissive).");
 DEFINE_bool(guest_audit_security, true,
             "Whether to log security audits.");
-DEFINE_bool(guest_force_normal_boot, true,
-            "Whether to force the boot sequence to skip recovery.");
-DEFINE_string(boot_image, "",
-              "Location of cuttlefish boot image. If empty it is assumed to be "
-              "boot.img in the directory specified by -system_image_dir.");
-DEFINE_string(vendor_boot_image, "",
-              "Location of cuttlefish vendor boot image. If empty it is assumed to "
-              "be vendor_boot.img in the directory specified by -system_image_dir.");
-DEFINE_string(vbmeta_image, "",
-              "Location of cuttlefish vbmeta image. If empty it is assumed to "
-              "be vbmeta.img in the directory specified by -system_image_dir.");
-DEFINE_string(vbmeta_system_image, "",
-              "Location of cuttlefish vbmeta_system image. If empty it is assumed to "
-              "be vbmeta_system.img in the directory specified by -system_image_dir.");
-DEFINE_int32(memory_mb, 2048,
-             "Total amount of memory available for guest, MB.");
-DEFINE_string(serial_number, ForCurrentInstance("CUTTLEFISHCVD"),
+DEFINE_int32(memory_mb, 0, "Total amount of memory available for guest, MB.");
+DEFINE_string(serial_number, cuttlefish::ForCurrentInstance("CUTTLEFISHCVD"),
               "Serial number to use for the device");
 DEFINE_bool(use_random_serial, false,
             "Whether to use random serial for the device.");
-DEFINE_string(assembly_dir,
-              cvd::StringFromEnv("HOME", ".") + "/cuttlefish_assembly",
-              "A directory to put generated files common between instances");
-DEFINE_string(instance_dir,
-              cvd::StringFromEnv("HOME", ".") + "/cuttlefish_runtime",
-              "A directory to put all instance specific files");
-DEFINE_string(
-    vm_manager, vm_manager::CrosvmManager::name(),
-    "What virtual machine manager to use, one of {qemu_cli, crosvm}");
-DEFINE_string(
-    gpu_mode, vsoc::kGpuModeGuestSwiftshader,
-    "What gpu configuration to use, one of {guest_swiftshader, drm_virgl}");
-
-DEFINE_string(system_image_dir, vsoc::DefaultGuestImagePath(""),
-              "Location of the system partition images.");
-DEFINE_string(super_image, "", "Location of the super partition image.");
-DEFINE_string(misc_image, "",
-              "Location of the misc partition image. If the image does not "
-              "exist, a blank new misc partition image is created.");
+DEFINE_string(vm_manager, "",
+              "What virtual machine manager to use, one of {qemu_cli, crosvm}");
+DEFINE_string(gpu_mode, cuttlefish::kGpuModeAuto,
+              "What gpu configuration to use, one of {auto, drm_virgl, "
+              "gfxstream, guest_swiftshader}");
 
 DEFINE_bool(deprecated_boot_completed, false, "Log boot completed message to"
             " host kernel. This is only used during transition of our clients."
@@ -116,29 +85,116 @@
                                      "The VNC server runs at port 6443 + i for "
                                      "the vsoc-i user or CUTTLEFISH_INSTANCE=i, "
                                      "starting from 1.");
+DEFINE_bool(use_allocd, false,
+            "Acquire static resources from the resource allocator daemon.");
+DEFINE_bool(enable_minimal_mode, false,
+            "Only enable the minimum features to boot a cuttlefish device and "
+            "support minimal UI interactions.\nNote: Currently only supports "
+            "handheld/phone targets");
+DEFINE_bool(pause_in_bootloader, false,
+            "Stop the bootflow in u-boot. You can continue the boot by connecting "
+            "to the device console and typing in \"boot\".");
+DEFINE_bool(enable_host_bluetooth, true,
+            "Enable the root-canal which is Bluetooth emulator in the host.");
 
-DEFINE_bool(start_webrtc, false, "[Experimental] Whether to start the webrtc process.");
+DEFINE_string(bluetooth_controller_properties_file,
+              "etc/rootcanal/data/controller_properties.json",
+              "The configuartion file path for root-canal which is a Bluetooth "
+              "emulator.");
+DEFINE_string(
+    bluetooth_default_commands_file, "etc/rootcanal/data/default_commands",
+    "The default commands which root-canal executes when it launches.");
+
+/**
+ *
+ * crosvm sandbox feature requires /var/empty and seccomp directory
+ *
+ * --enable-sandbox: will enforce the sandbox feature
+ *                   failing to meet the requirements result in assembly_cvd termination
+ *
+ * --enable-sandbox=no, etc: will disable sandbox
+ *
+ * no option given: it is enabled if /var/empty exists and an empty directory
+ *                             or if it does not exist and can be created
+ *
+ * if seccomp dir doesn't exist, assembly_cvd will terminate
+ *
+ * See SetDefaultFlagsForCrosvm()
+ *
+ */
+DEFINE_bool(enable_sandbox,
+            false,
+            "Enable crosvm sandbox. Use this when you are sure about what you are doing.");
+
+static const std::string kSeccompDir =
+    std::string("usr/share/crosvm/") + cuttlefish::HostArchStr() + "-linux-gnu/seccomp";
+DEFINE_string(seccomp_policy_dir, DefaultHostArtifactsPath(kSeccompDir),
+              "With sandbox'ed crosvm, overrieds the security comp policy directory");
+
+DEFINE_bool(start_webrtc, false, "Whether to start the webrtc process.");
 
 DEFINE_string(
-        webrtc_assets_dir,
-        vsoc::DefaultHostArtifactsPath("usr/share/webrtc/assets"),
+        webrtc_assets_dir, DefaultHostArtifactsPath("usr/share/webrtc/assets"),
         "[Experimental] Path to WebRTC webpage assets.");
 
 DEFINE_string(
-        webrtc_certs_dir,
-        vsoc::DefaultHostArtifactsPath("usr/share/webrtc/certs"),
+        webrtc_certs_dir, DefaultHostArtifactsPath("usr/share/webrtc/certs"),
         "[Experimental] Path to WebRTC certificates directory.");
 
 DEFINE_string(
         webrtc_public_ip,
-        "127.0.0.1",
-        "[Experimental] Public IPv4 address of your server, a.b.c.d format");
+        "0.0.0.0",
+        "[Deprecated] Ignored, webrtc can figure out its IP address");
 
 DEFINE_bool(
         webrtc_enable_adb_websocket,
         false,
         "[Experimental] If enabled, exposes local adb service through a websocket.");
 
+DEFINE_bool(
+    start_webrtc_sig_server, false,
+    "Whether to start the webrtc signaling server. This option only applies to "
+    "the first instance, if multiple instances are launched they'll share the "
+    "same signaling server, which is owned by the first one.");
+
+DEFINE_string(webrtc_sig_server_addr, "0.0.0.0",
+              "The address of the webrtc signaling server.");
+
+DEFINE_int32(
+    webrtc_sig_server_port, 443,
+    "The port of the signaling server if started outside of this launch. If "
+    "-start_webrtc_sig_server is given it will choose 8443+instance_num1-1 and "
+    "this parameter is ignored.");
+
+// TODO (jemoreira): We need a much bigger range to reliably support several
+// simultaneous connections.
+DEFINE_string(tcp_port_range, "15550:15558",
+              "The minimum and maximum TCP port numbers to allocate for ICE "
+              "candidates as 'min:max'. To use any port just specify '0:0'");
+
+DEFINE_string(udp_port_range, "15550:15558",
+              "The minimum and maximum UDP port numbers to allocate for ICE "
+              "candidates as 'min:max'. To use any port just specify '0:0'");
+
+DEFINE_string(webrtc_sig_server_path, "/register_device",
+              "The path section of the URL where the device should be "
+              "registered with the signaling server.");
+
+DEFINE_bool(verify_sig_server_certificate, false,
+            "Whether to verify the signaling server's certificate with a "
+            "trusted signing authority (Disallow self signed certificates).");
+
+DEFINE_string(sig_server_headers_file, "",
+              "Path to a file containing HTTP headers to be included in the "
+              "connection to the signaling server. Each header should be on a "
+              "line by itself in the form <name>: <value>");
+
+DEFINE_string(
+    webrtc_device_id, "cvd-{num}",
+    "The for the device to register with the signaling server. Every "
+    "appearance of the substring '{num}' in the device id will be substituted "
+    "with the instance number to support multiple instances");
+
 DEFINE_string(adb_mode, "vsock_half_tunnel",
               "Mode for ADB connection."
               "'vsock_tunnel' for a TCP connection tunneled through vsock, "
@@ -146,11 +202,11 @@
               "vsock, 'vsock_half_tunnel' for a TCP connection forwarded to "
               "the guest ADB server, or a comma separated list of types as in "
               "'native_vsock,vsock_half_tunnel'");
-DEFINE_bool(run_adb_connector, true,
+DEFINE_bool(run_adb_connector, !cuttlefish::IsRunningInContainer(),
             "Maintain adb connection by sending 'adb connect' commands to the "
             "server. Only relevant with -adb_mode=tunnel or vsock_tunnel");
 
-DEFINE_string(uuid, vsoc::ForCurrentInstance(vsoc::kDefaultUuidPrefix),
+DEFINE_string(uuid, cuttlefish::ForCurrentInstance(cuttlefish::kDefaultUuidPrefix),
               "UUID to use for the device. Random if not specified");
 DEFINE_bool(daemon, false,
             "Run cuttlefish in background, the launcher exits on boot "
@@ -161,87 +217,113 @@
 DEFINE_string(setupwizard_mode, "DISABLED",
             "One of DISABLED,OPTIONAL,REQUIRED");
 
-DEFINE_string(qemu_binary,
-              "/usr/bin/qemu-system-x86_64",
-              "The qemu binary to use");
-DEFINE_string(crosvm_binary,
-              vsoc::DefaultHostArtifactsPath("bin/crosvm"),
+DEFINE_string(qemu_binary_dir, "/usr/bin",
+              "Path to the directory containing the qemu binary to use");
+DEFINE_string(crosvm_binary, HostBinaryPath("crosvm"),
               "The Crosvm binary to use");
+DEFINE_string(tpm_device, "", "A host TPM device to pass through commands to.");
 DEFINE_bool(restart_subprocesses, true, "Restart any crashed host process");
-DEFINE_string(logcat_mode, "", "How to send android's log messages from "
-                               "guest to host. One of [serial, vsock]");
-DEFINE_bool(enable_tombstone_receiver, true, "Enables the tombstone logger on "
-            "both the guest and the host");
 DEFINE_bool(enable_vehicle_hal_grpc_server, true, "Enables the vehicle HAL "
             "emulation gRPC server on the host");
-DEFINE_bool(use_bootloader, false, "Boots the device using a bootloader");
+DEFINE_string(custom_action_config, "",
+              "Path to a custom action config JSON. Defaults to the file provided by "
+              "build variable CVD_CUSTOM_ACTION_CONFIG. If this build variable "
+              "is empty then the custom action config will be empty as well.");
+DEFINE_string(custom_actions, "",
+              "Serialized JSON of an array of custom action objects (in the "
+              "same format as custom action config JSON files). For use "
+              "within --config preset config files; prefer "
+              "--custom_action_config to specify a custom config file on the "
+              "command line. Actions in this flag are combined with actions "
+              "in --custom_action_config.");
 DEFINE_string(bootloader, "", "Bootloader binary path");
 DEFINE_string(boot_slot, "", "Force booting into the given slot. If empty, "
              "the slot will be chosen based on the misc partition if using a "
              "bootloader. It will default to 'a' if empty and not using a "
              "bootloader.");
 DEFINE_int32(num_instances, 1, "Number of Android guests to launch");
-DEFINE_bool(resume, true, "Resume using the disk from the last session, if "
-                          "possible. i.e., if --noresume is passed, the disk "
-                          "will be reset to the state it was initially launched "
-                          "in. This flag is ignored if the underlying partition "
-                          "images have been updated since the first launch.");
+DEFINE_string(report_anonymous_usage_stats, "", "Report anonymous usage "
+            "statistics for metrics collection and analysis.");
+DEFINE_string(ril_dns, "8.8.8.8", "DNS address of mobile network (RIL)");
+DEFINE_bool(kgdb, false, "Configure the virtual device for debugging the kernel "
+                         "with kgdb/kdb. The kernel must have been built with "
+                         "kgdb support, and serial console must be enabled.");
+
+DEFINE_bool(start_gnss_proxy, false, "Whether to start the gnss proxy.");
+
+DEFINE_string(gnss_file_path, "",
+              "Local gnss file path for the gnss proxy");
+
+// by default, this modem-simulator is disabled
+DEFINE_bool(enable_modem_simulator, true,
+            "Enable the modem simulator to process RILD AT commands");
+// modem_simulator_sim_type=2 for test CtsCarrierApiTestCases
+DEFINE_int32(modem_simulator_sim_type, 1,
+             "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
+
+DEFINE_bool(console, false, "Enable the serial console");
+
+DEFINE_bool(vhost_net, false, "Enable vhost acceleration of networking");
+
+DEFINE_bool(record_screen, false, "Enable screen recording. "
+                                  "Requires --start_webrtc");
+
+DEFINE_bool(ethernet, false, "Enable Ethernet network interface");
+
+DEFINE_bool(smt, false, "Enable simultaneous multithreading (SMT/HT)");
+
+DEFINE_int32(vsock_guest_cid,
+             cuttlefish::GetDefaultVsockCid(),
+             "vsock_guest_cid is used to determine the guest vsock cid as well as all the ports"
+             "of all vsock servers such as tombstone or modem simulator(s)."
+             "The vsock ports and guest vsock cid are a function of vsock_guest_cid and instance number."
+             "An instance number of i th instance is determined by --num_instances=N and --base_instance_num=B"
+             "The instance number of i th instance is B + i where i in [0, N-1] and B >= 1."
+             "See --num_instances, and --base_instance_num for more information"
+             "If --vsock_guest_cid=C is given and C >= 3, the guest vsock cid is C + i. Otherwise,"
+             "the guest vsock cid is 2 + instance number, which is 2 + (B + i)."
+             "If --vsock_guest_cid is not given, each vsock server port number for i th instance is"
+             "base + instance number - 1. vsock_guest_cid is by default B + i + 2."
+             "Thus, by default, each port is base + vsock_guest_cid - 3."
+             "The same formula holds when --vsock_guest_cid=C is given, for algorithm's sake."
+             "Each vsock server port number is base + C - 3.");
+
+DEFINE_string(secure_hals, "keymint,gatekeeper",
+              "Which HALs to use enable host security features for. Supports "
+              "keymint and gatekeeper at the moment.");
+
+DEFINE_bool(use_sdcard, true, "Create blank SD-Card image and expose to guest");
+
+DEFINE_bool(protected_vm, false, "Boot in Protected VM mode");
+
+DEFINE_bool(enable_audio, cuttlefish::HostArch() != cuttlefish::Arch::Arm64,
+            "Whether to play or capture audio");
+
+DECLARE_string(assembly_dir);
+DECLARE_string(boot_image);
+DECLARE_string(system_image_dir);
+
+namespace cuttlefish {
+using vm_manager::QemuManager;
+using vm_manager::GetVmManager;
 
 namespace {
 
-const std::string kKernelDefaultPath = "kernel";
-const std::string kInitramfsImg = "initramfs.img";
-const std::string kRamdiskConcatExt = ".concat";
-
-bool ResolveInstanceFiles() {
-  if (FLAGS_system_image_dir.empty()) {
-    LOG(ERROR) << "--system_image_dir must be specified.";
-    return false;
-  }
-
-  // If user did not specify location of either of these files, expect them to
-  // be placed in --system_image_dir location.
-  std::string default_boot_image = FLAGS_system_image_dir + "/boot.img";
-  SetCommandLineOptionWithMode("boot_image", default_boot_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_cache_image = FLAGS_system_image_dir + "/cache.img";
-  SetCommandLineOptionWithMode("cache_image", default_cache_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_data_image = FLAGS_system_image_dir + "/userdata.img";
-  SetCommandLineOptionWithMode("data_image", default_data_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_metadata_image = FLAGS_system_image_dir + "/metadata.img";
-  SetCommandLineOptionWithMode("metadata_image", default_metadata_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_super_image = FLAGS_system_image_dir + "/super.img";
-  SetCommandLineOptionWithMode("super_image", default_super_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_misc_image = FLAGS_system_image_dir + "/misc.img";
-  SetCommandLineOptionWithMode("misc_image", default_misc_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_vendor_boot_image = FLAGS_system_image_dir
-                                        + "/vendor_boot.img";
-  SetCommandLineOptionWithMode("vendor_boot_image",
-                               default_vendor_boot_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_vbmeta_image = FLAGS_system_image_dir + "/vbmeta.img";
-  SetCommandLineOptionWithMode("vbmeta_image", default_vbmeta_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  std::string default_vbmeta_system_image = FLAGS_system_image_dir
-                                          + "/vbmeta_system.img";
-  SetCommandLineOptionWithMode("vbmeta_system_image",
-                               default_vbmeta_system_image.c_str(),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-
-  return true;
+bool IsFlagSet(const std::string& flag) {
+  return !gflags::GetCommandLineFlagInfoOrDie(flag.c_str()).is_default;
 }
 
-std::string GetCuttlefishEnvPath() {
-  return cvd::StringFromEnv("HOME", ".") + "/.cuttlefish.sh";
-}
-
-std::string GetLegacyConfigFilePath(const vsoc::CuttlefishConfig& config) {
-  return config.ForDefaultInstance().PerInstancePath("cuttlefish_config.json");
+std::pair<uint16_t, uint16_t> ParsePortRange(const std::string& flag) {
+  static const std::regex rgx("[0-9]+:[0-9]+");
+  CHECK(std::regex_match(flag, rgx))
+      << "Port range flag has invalid value: " << flag;
+  std::pair<uint16_t, uint16_t> port_range;
+  std::stringstream ss(flag);
+  char c;
+  ss >> port_range.first;
+  ss.read(&c, 1);
+  ss >> port_range.second;
+  return port_range;
 }
 
 int NumStreamers() {
@@ -255,186 +337,385 @@
   return stream.str();
 }
 
-// Initializes the config object and saves it to file. It doesn't return it, all
-// further uses of the config should happen through the singleton
-vsoc::CuttlefishConfig InitializeCuttlefishConfiguration(
-    const cvd::BootImageUnpacker& boot_image_unpacker,
-    const cvd::FetcherConfig& fetcher_config) {
+#ifdef __ANDROID__
+void ReadKernelConfig(KernelConfig* kernel_config) {
+  // QEMU isn't on Android, so always follow host arch
+  kernel_config->target_arch = HostArch();
+  kernel_config->bootconfig_supported = true;
+}
+#else
+void ReadKernelConfig(KernelConfig* kernel_config) {
+  // extract-ikconfig can be called directly on the boot image since it looks
+  // for the ikconfig header in the image before extracting the config list.
+  // This code is liable to break if the boot image ever includes the
+  // ikconfig header outside the kernel.
+  const std::string kernel_image_path =
+      FLAGS_kernel_path.size() ? FLAGS_kernel_path : FLAGS_boot_image;
+
+  Command ikconfig_cmd(HostBinaryPath("extract-ikconfig"));
+  ikconfig_cmd.AddParameter(kernel_image_path);
+
+  std::string current_path = StringFromEnv("PATH", "");
+  std::string bin_folder = DefaultHostArtifactsPath("bin");
+  ikconfig_cmd.SetEnvironment({"PATH=" + current_path + ":" + bin_folder});
+
+  std::string ikconfig_path =
+      StringFromEnv("TEMP", "/tmp") + "/ikconfig.XXXXXX";
+  auto ikconfig_fd = SharedFD::Mkstemp(&ikconfig_path);
+  CHECK(ikconfig_fd->IsOpen())
+      << "Unable to create ikconfig file: " << ikconfig_fd->StrError();
+  ikconfig_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, ikconfig_fd);
+
+  auto ikconfig_proc = ikconfig_cmd.Start();
+  CHECK(ikconfig_proc.Started() && ikconfig_proc.Wait() == 0)
+      << "Failed to extract ikconfig from " << kernel_image_path;
+
+  std::string config = ReadFile(ikconfig_path);
+
+  if (config.find("\nCONFIG_ARM=y") != std::string::npos) {
+    kernel_config->target_arch = Arch::Arm;
+  } else if (config.find("\nCONFIG_ARM64=y") != std::string::npos) {
+    kernel_config->target_arch = Arch::Arm64;
+  } else if (config.find("\nCONFIG_X86_64=y") != std::string::npos) {
+    kernel_config->target_arch = Arch::X86_64;
+  } else if (config.find("\nCONFIG_X86=y") != std::string::npos) {
+    kernel_config->target_arch = Arch::X86;
+  } else {
+    LOG(FATAL) << "Unknown target architecture";
+  }
+  kernel_config->bootconfig_supported =
+      config.find("\nCONFIG_BOOT_CONFIG=y") != std::string::npos;
+
+  unlink(ikconfig_path.c_str());
+}
+#endif  // #ifdef __ANDROID__
+
+} // namespace
+
+CuttlefishConfig InitializeCuttlefishConfiguration(
+    const std::string& instance_dir, int modem_simulator_count,
+    KernelConfig kernel_config) {
   // At most one streamer can be started.
   CHECK(NumStreamers() <= 1);
 
-  vsoc::CuttlefishConfig tmp_config_obj;
+  CuttlefishConfig tmp_config_obj;
   tmp_config_obj.set_assembly_dir(FLAGS_assembly_dir);
-  if (!vm_manager::VmManager::IsValidName(FLAGS_vm_manager)) {
-    LOG(FATAL) << "Invalid vm_manager: " << FLAGS_vm_manager;
-  }
-  if (!vm_manager::VmManager::IsValidName(FLAGS_vm_manager)) {
+  tmp_config_obj.set_target_arch(kernel_config.target_arch);
+  tmp_config_obj.set_bootconfig_supported(kernel_config.bootconfig_supported);
+  auto vmm = GetVmManager(FLAGS_vm_manager, kernel_config.target_arch);
+  if (!vmm) {
     LOG(FATAL) << "Invalid vm_manager: " << FLAGS_vm_manager;
   }
   tmp_config_obj.set_vm_manager(FLAGS_vm_manager);
+
+  const GraphicsAvailability graphics_availability =
+    GetGraphicsAvailabilityWithSubprocessCheck();
+
+  LOG(VERBOSE) << graphics_availability;
+
   tmp_config_obj.set_gpu_mode(FLAGS_gpu_mode);
-  if (vm_manager::VmManager::ConfigureGpuMode(tmp_config_obj.vm_manager(),
-                                              tmp_config_obj.gpu_mode()).empty()) {
+
+  if (tmp_config_obj.gpu_mode() != kGpuModeAuto &&
+      tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl &&
+      tmp_config_obj.gpu_mode() != kGpuModeGfxStream &&
+      tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) {
+    LOG(FATAL) << "Invalid gpu_mode: " << FLAGS_gpu_mode;
+  }
+  if (tmp_config_obj.gpu_mode() == kGpuModeAuto) {
+    if (ShouldEnableAcceleratedRendering(graphics_availability)) {
+        LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated "
+                     "rendering support.";
+      if (FLAGS_vm_manager == QemuManager::name()) {
+        LOG(INFO) << "Enabling --gpu_mode=drm_virgl.";
+        tmp_config_obj.set_gpu_mode(kGpuModeDrmVirgl);
+      } else {
+        LOG(INFO) << "Enabling --gpu_mode=gfxstream.";
+        tmp_config_obj.set_gpu_mode(kGpuModeGfxStream);
+      }
+    } else {
+      LOG(INFO) << "GPU auto mode: did not detect prerequisites for "
+                   "accelerated rendering support, enabling "
+                   "--gpu_mode=guest_swiftshader.";
+      tmp_config_obj.set_gpu_mode(kGpuModeGuestSwiftshader);
+    }
+  } else if (tmp_config_obj.gpu_mode() == kGpuModeGfxStream ||
+             tmp_config_obj.gpu_mode() == kGpuModeDrmVirgl) {
+    if (!ShouldEnableAcceleratedRendering(graphics_availability)) {
+      LOG(ERROR) << "--gpu_mode="
+                 << tmp_config_obj.gpu_mode()
+                 << " was requested but the prerequisites for accelerated "
+                    "rendering were not detected so the device may not "
+                    "function correctly. Please consider switching to "
+                    "--gpu_mode=auto or --gpu_mode=guest_swiftshader.";
+    }
+  }
+  // Sepolicy rules need to be updated to support gpu mode. Temporarily disable
+  // auto-enabling sandbox when gpu is enabled (b/152323505).
+  if (tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) {
+    SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT);
+  }
+
+  if (vmm->ConfigureGpuMode(tmp_config_obj.gpu_mode()).empty()) {
     LOG(FATAL) << "Invalid gpu_mode=" << FLAGS_gpu_mode <<
                " does not work with vm_manager=" << FLAGS_vm_manager;
   }
 
+  CHECK(!FLAGS_smt || FLAGS_cpus % 2 == 0)
+      << "CPUs must be a multiple of 2 in SMT mode";
   tmp_config_obj.set_cpus(FLAGS_cpus);
+  tmp_config_obj.set_smt(FLAGS_smt);
+
   tmp_config_obj.set_memory_mb(FLAGS_memory_mb);
 
-  tmp_config_obj.set_dpi(FLAGS_dpi);
   tmp_config_obj.set_setupwizard_mode(FLAGS_setupwizard_mode);
-  tmp_config_obj.set_x_res(FLAGS_x_res);
-  tmp_config_obj.set_y_res(FLAGS_y_res);
+
+  std::vector<cuttlefish::CuttlefishConfig::DisplayConfig> display_configs = {{
+    .width = FLAGS_x_res,
+    .height = FLAGS_y_res,
+  }};
+  tmp_config_obj.set_display_configs(display_configs);
+  tmp_config_obj.set_dpi(FLAGS_dpi);
   tmp_config_obj.set_refresh_rate_hz(FLAGS_refresh_rate_hz);
-  tmp_config_obj.set_gdb_flag(FLAGS_qemu_gdb);
+
+  auto secure_hals = android::base::Split(FLAGS_secure_hals, ",");
+  tmp_config_obj.set_secure_hals(
+      std::set<std::string>(secure_hals.begin(), secure_hals.end()));
+
+  tmp_config_obj.set_gdb_port(FLAGS_gdb_port);
+
   std::vector<std::string> adb = android::base::Split(FLAGS_adb_mode, ",");
   tmp_config_obj.set_adb_mode(std::set<std::string>(adb.begin(), adb.end()));
-  std::string discovered_kernel = fetcher_config.FindCvdFileWithSuffix(kKernelDefaultPath);
-  std::string foreign_kernel = FLAGS_kernel_path.size() ? FLAGS_kernel_path : discovered_kernel;
-  if (foreign_kernel.size()) {
-    tmp_config_obj.set_kernel_image_path(foreign_kernel);
-    tmp_config_obj.set_use_unpacked_kernel(false);
-  } else {
-    tmp_config_obj.set_kernel_image_path(
-        tmp_config_obj.AssemblyPath(kKernelDefaultPath.c_str()));
-    tmp_config_obj.set_use_unpacked_kernel(true);
-  }
 
-  tmp_config_obj.set_decompress_kernel(FLAGS_decompress_kernel);
-  if (tmp_config_obj.decompress_kernel()) {
-    tmp_config_obj.set_decompressed_kernel_image_path(
-        tmp_config_obj.AssemblyPath("vmlinux"));
-  }
-
-  auto ramdisk_path = tmp_config_obj.AssemblyPath("ramdisk.img");
-  auto vendor_ramdisk_path = tmp_config_obj.AssemblyPath("vendor_ramdisk.img");
-  if (!boot_image_unpacker.HasRamdiskImage()) {
-    LOG(FATAL) << "A ramdisk is required, but the boot image did not have one.";
-  }
-
-  tmp_config_obj.set_boot_image_kernel_cmdline(boot_image_unpacker.kernel_cmdline());
-  tmp_config_obj.set_loop_max_part(FLAGS_loop_max_part);
   tmp_config_obj.set_guest_enforce_security(FLAGS_guest_enforce_security);
   tmp_config_obj.set_guest_audit_security(FLAGS_guest_audit_security);
-  tmp_config_obj.set_guest_force_normal_boot(FLAGS_guest_force_normal_boot);
   tmp_config_obj.set_extra_kernel_cmdline(FLAGS_extra_kernel_cmdline);
 
-  tmp_config_obj.set_ramdisk_image_path(ramdisk_path);
-  tmp_config_obj.set_vendor_ramdisk_image_path(vendor_ramdisk_path);
-
-  std::string discovered_ramdisk = fetcher_config.FindCvdFileWithSuffix(kInitramfsImg);
-  std::string foreign_ramdisk = FLAGS_initramfs_path.size () ? FLAGS_initramfs_path : discovered_ramdisk;
-  if (foreign_kernel.size() && !foreign_ramdisk.size()) {
-    // If there's a kernel that's passed in without an initramfs, that implies
-    // user error or a kernel built with no modules. In either case, let's
-    // choose to avoid loading the modules from the vendor ramdisk which are
-    // built for the default cf kernel. Once boot occurs, user error will
-    // become obvious.
-    tmp_config_obj.set_final_ramdisk_path(ramdisk_path);
-  } else {
-    tmp_config_obj.set_final_ramdisk_path(ramdisk_path + kRamdiskConcatExt);
-    if(foreign_ramdisk.size()) {
-      tmp_config_obj.set_initramfs_path(foreign_ramdisk);
-    }
+  if (FLAGS_console) {
+    SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT);
   }
 
-  tmp_config_obj.set_deprecated_boot_completed(FLAGS_deprecated_boot_completed);
-  tmp_config_obj.set_logcat_receiver_binary(
-      vsoc::DefaultHostArtifactsPath("bin/logcat_receiver"));
-  tmp_config_obj.set_config_server_binary(
-      vsoc::DefaultHostArtifactsPath("bin/config_server"));
+  tmp_config_obj.set_console(FLAGS_console);
+  tmp_config_obj.set_kgdb(FLAGS_console && FLAGS_kgdb);
 
-  tmp_config_obj.set_qemu_binary(FLAGS_qemu_binary);
+  tmp_config_obj.set_host_tools_version(HostToolsCrc());
+
+  tmp_config_obj.set_deprecated_boot_completed(FLAGS_deprecated_boot_completed);
+
+  tmp_config_obj.set_qemu_binary_dir(FLAGS_qemu_binary_dir);
   tmp_config_obj.set_crosvm_binary(FLAGS_crosvm_binary);
-  tmp_config_obj.set_console_forwarder_binary(
-      vsoc::DefaultHostArtifactsPath("bin/console_forwarder"));
-  tmp_config_obj.set_kernel_log_monitor_binary(
-      vsoc::DefaultHostArtifactsPath("bin/kernel_log_monitor"));
+  tmp_config_obj.set_tpm_device(FLAGS_tpm_device);
 
   tmp_config_obj.set_enable_vnc_server(FLAGS_start_vnc_server);
-  tmp_config_obj.set_vnc_server_binary(
-      vsoc::DefaultHostArtifactsPath("bin/vnc_server"));
+
+  tmp_config_obj.set_seccomp_policy_dir(FLAGS_seccomp_policy_dir);
 
   tmp_config_obj.set_enable_webrtc(FLAGS_start_webrtc);
-  tmp_config_obj.set_webrtc_binary(
-      vsoc::DefaultHostArtifactsPath("bin/webRTC"));
   tmp_config_obj.set_webrtc_assets_dir(FLAGS_webrtc_assets_dir);
-  tmp_config_obj.set_webrtc_public_ip(FLAGS_webrtc_public_ip);
   tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir);
+  // Note: This will be overridden if the sig server is started by us
+  tmp_config_obj.set_sig_server_port(FLAGS_webrtc_sig_server_port);
+  tmp_config_obj.set_sig_server_address(FLAGS_webrtc_sig_server_addr);
+  tmp_config_obj.set_sig_server_path(FLAGS_webrtc_sig_server_path);
+  tmp_config_obj.set_sig_server_strict(FLAGS_verify_sig_server_certificate);
+  tmp_config_obj.set_sig_server_headers_path(FLAGS_sig_server_headers_file);
+
+  auto tcp_range  = ParsePortRange(FLAGS_tcp_port_range);
+  tmp_config_obj.set_webrtc_tcp_port_range(tcp_range);
+  auto udp_range  = ParsePortRange(FLAGS_udp_port_range);
+  tmp_config_obj.set_webrtc_udp_port_range(udp_range);
+
+  tmp_config_obj.set_enable_modem_simulator(FLAGS_enable_modem_simulator &&
+                                            !FLAGS_enable_minimal_mode);
+  tmp_config_obj.set_modem_simulator_instance_number(modem_simulator_count);
+  tmp_config_obj.set_modem_simulator_sim_type(FLAGS_modem_simulator_sim_type);
 
   tmp_config_obj.set_webrtc_enable_adb_websocket(
           FLAGS_webrtc_enable_adb_websocket);
 
   tmp_config_obj.set_restart_subprocesses(FLAGS_restart_subprocesses);
   tmp_config_obj.set_run_adb_connector(FLAGS_run_adb_connector);
-  tmp_config_obj.set_adb_connector_binary(
-      vsoc::DefaultHostArtifactsPath("bin/adb_connector"));
-  tmp_config_obj.set_socket_vsock_proxy_binary(
-      vsoc::DefaultHostArtifactsPath("bin/socket_vsock_proxy"));
   tmp_config_obj.set_run_as_daemon(FLAGS_daemon);
 
   tmp_config_obj.set_data_policy(FLAGS_data_policy);
   tmp_config_obj.set_blank_data_image_mb(FLAGS_blank_data_image_mb);
   tmp_config_obj.set_blank_data_image_fmt(FLAGS_blank_data_image_fmt);
 
-  tmp_config_obj.set_logcat_mode(FLAGS_logcat_mode);
-
-  tmp_config_obj.set_enable_tombstone_receiver(FLAGS_enable_tombstone_receiver);
-  tmp_config_obj.set_tombstone_receiver_binary(
-      vsoc::DefaultHostArtifactsPath("bin/tombstone_receiver"));
+  tmp_config_obj.set_enable_gnss_grpc_proxy(FLAGS_start_gnss_proxy);
 
   tmp_config_obj.set_enable_vehicle_hal_grpc_server(FLAGS_enable_vehicle_hal_grpc_server);
   tmp_config_obj.set_vehicle_hal_grpc_server_binary(
-      vsoc::DefaultHostArtifactsPath("bin/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server"));
+      HostBinaryPath("android.hardware.automotive.vehicle@2.0-virtualization-grpc-server"));
 
-  tmp_config_obj.set_use_bootloader(FLAGS_use_bootloader);
+  std::string custom_action_config;
+  if (!FLAGS_custom_action_config.empty()) {
+    custom_action_config = FLAGS_custom_action_config;
+  } else {
+    std::string custom_action_config_dir =
+        DefaultHostArtifactsPath("etc/cvd_custom_action_config");
+    if (DirectoryExists(custom_action_config_dir)) {
+      auto custom_action_configs = DirectoryContents(custom_action_config_dir);
+      // Two entries are always . and ..
+      if (custom_action_configs.size() > 3) {
+        LOG(ERROR) << "Expected at most one custom action config in "
+                   << custom_action_config_dir << ". Please delete extras.";
+      } else if (custom_action_configs.size() == 3) {
+        for (const auto& config : custom_action_configs) {
+          if (android::base::EndsWithIgnoreCase(config, ".json")) {
+            custom_action_config = custom_action_config_dir + "/" + config;
+          }
+        }
+      }
+    }
+  }
+  std::vector<CustomActionConfig> custom_actions;
+  Json::CharReaderBuilder builder;
+  Json::Value custom_action_array(Json::arrayValue);
+  if (custom_action_config != "") {
+    // Load the custom action config JSON.
+    std::ifstream ifs(custom_action_config);
+    std::string errorMessage;
+    if (!Json::parseFromStream(builder, ifs, &custom_action_array, &errorMessage)) {
+      LOG(FATAL) << "Could not read custom actions config file "
+                 << custom_action_config << ": "
+                 << errorMessage;
+    }
+    for (const auto& custom_action : custom_action_array) {
+      custom_actions.push_back(CustomActionConfig(custom_action));
+    }
+  }
+  if (FLAGS_custom_actions != "") {
+    // Load the custom action from the --config preset file.
+    std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
+    std::string errorMessage;
+    if (!reader->parse(&*FLAGS_custom_actions.begin(), &*FLAGS_custom_actions.end(),
+                       &custom_action_array, &errorMessage)) {
+      LOG(FATAL) << "Could not read custom actions config flag: "
+                 << errorMessage;
+    }
+    for (const auto& custom_action : custom_action_array) {
+      custom_actions.push_back(CustomActionConfig(custom_action));
+    }
+  }
+  tmp_config_obj.set_custom_actions(custom_actions);
+
   tmp_config_obj.set_bootloader(FLAGS_bootloader);
 
+  tmp_config_obj.set_enable_metrics(FLAGS_report_anonymous_usage_stats);
+
   if (!FLAGS_boot_slot.empty()) {
       tmp_config_obj.set_boot_slot(FLAGS_boot_slot);
   }
 
   tmp_config_obj.set_cuttlefish_env_path(GetCuttlefishEnvPath());
 
-  std::vector<int> instance_nums;
-  for (int i = 0; i < FLAGS_num_instances; i++) {
-    instance_nums.push_back(vsoc::GetInstance() + i);
-  }
+  tmp_config_obj.set_ril_dns(FLAGS_ril_dns);
 
-  for (const auto& num : instance_nums) {
+  tmp_config_obj.set_enable_minimal_mode(FLAGS_enable_minimal_mode);
+
+  tmp_config_obj.set_vhost_net(FLAGS_vhost_net);
+
+  tmp_config_obj.set_record_screen(FLAGS_record_screen);
+
+  tmp_config_obj.set_ethernet(FLAGS_ethernet);
+
+  tmp_config_obj.set_enable_host_bluetooth(FLAGS_enable_host_bluetooth);
+
+  tmp_config_obj.set_protected_vm(FLAGS_protected_vm);
+
+  std::vector<int> num_instances;
+  for (int i = 0; i < FLAGS_num_instances; i++) {
+    num_instances.push_back(GetInstance() + i);
+  }
+  std::vector<std::string> gnss_file_paths = android::base::Split(FLAGS_gnss_file_path, ",");
+
+  bool is_first_instance = true;
+  for (const auto& num : num_instances) {
+    IfaceConfig iface_config;
+    if (FLAGS_use_allocd) {
+      auto iface_opt = AllocateNetworkInterfaces();
+      if (!iface_opt.has_value()) {
+        LOG(FATAL) << "Failed to acquire network interfaces";
+      }
+      iface_config = iface_opt.value();
+    } else {
+      iface_config = DefaultNetworkInterfaces(num);
+    }
+
     auto instance = tmp_config_obj.ForInstance(num);
-    auto const_instance = const_cast<const vsoc::CuttlefishConfig&>(tmp_config_obj)
-        .ForInstance(num);
+    auto const_instance =
+        const_cast<const CuttlefishConfig&>(tmp_config_obj)
+            .ForInstance(num);
     // Set this first so that calls to PerInstancePath below are correct
-    instance.set_instance_dir(FLAGS_instance_dir + "." + std::to_string(num));
-    if(FLAGS_use_random_serial){
-      instance.set_serial_number(RandomSerialNumber("CFCVD" + std::to_string(num)));
+    instance.set_instance_dir(instance_dir + "." + std::to_string(num));
+    instance.set_use_allocd(FLAGS_use_allocd);
+    if (FLAGS_use_random_serial) {
+      instance.set_serial_number(
+          RandomSerialNumber("CFCVD" + std::to_string(num)));
     } else {
       instance.set_serial_number(FLAGS_serial_number + std::to_string(num));
     }
+    // call this before all stuff that has vsock server: e.g. touchpad, keyboard, etc
+    const auto vsock_guest_cid = FLAGS_vsock_guest_cid + num - GetInstance();
+    instance.set_vsock_guest_cid(vsock_guest_cid);
+    auto calc_vsock_port = [vsock_guest_cid](const int base_port) {
+      // a base (vsock) port is like 9200 for modem_simulator, etc
+      return cuttlefish::GetVsockServerPort(base_port, vsock_guest_cid);
+    };
+    instance.set_session_id(iface_config.mobile_tap.session_id);
 
     instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num));
-    instance.set_mobile_tap_name(StrForInstance("cvd-mtap-", num));
-
-    instance.set_wifi_tap_name(StrForInstance("cvd-wtap-", num));
-
-    instance.set_vsock_guest_cid(3 + num - 1);
+    instance.set_mobile_tap_name(iface_config.mobile_tap.name);
+    instance.set_wifi_tap_name(iface_config.wireless_tap.name);
+    instance.set_ethernet_tap_name(iface_config.ethernet_tap.name);
 
     instance.set_uuid(FLAGS_uuid);
 
     instance.set_vnc_server_port(6444 + num - 1);
     instance.set_host_port(6520 + num - 1);
-    instance.set_adb_ip_and_port("127.0.0.1:" + std::to_string(6520 + num - 1));
-
+    instance.set_adb_ip_and_port("0.0.0.0:" + std::to_string(6520 + num - 1));
+    instance.set_tombstone_receiver_port(calc_vsock_port(6600));
     instance.set_vehicle_hal_server_port(9210 + num - 1);
+    instance.set_audiocontrol_server_port(9410);  /* OK to use the same port number across instances */
+    instance.set_config_server_port(calc_vsock_port(6800));
+
+    if (tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl &&
+        tmp_config_obj.gpu_mode() != kGpuModeGfxStream) {
+        instance.set_frames_server_port(calc_vsock_port(6900));
+      if (FLAGS_vm_manager == QemuManager::name()) {
+        instance.set_keyboard_server_port(calc_vsock_port(7000));
+        instance.set_touch_server_port(calc_vsock_port(7100));
+      }
+    }
+
+    instance.set_gnss_grpc_proxy_server_port(7200 + num -1);
+
+    if (num <= gnss_file_paths.size()) {
+      instance.set_gnss_file_path(gnss_file_paths[num-1]);
+    }
+
+    instance.set_rootcanal_hci_port(7300 + num - 1);
+    instance.set_rootcanal_link_port(7400 + num - 1);
+    instance.set_rootcanal_test_port(7500 + num - 1);
+    instance.set_rootcanal_config_file(
+        FLAGS_bluetooth_controller_properties_file);
+    instance.set_rootcanal_default_commands_file(
+        FLAGS_bluetooth_default_commands_file);
 
     instance.set_device_title(FLAGS_device_title);
 
-    instance.set_virtual_disk_paths({
-      const_instance.PerInstancePath("overlay.img"),
-      const_instance.sdcard_path(),
-    });
+    if (FLAGS_protected_vm) {
+      instance.set_virtual_disk_paths(
+          {const_instance.PerInstancePath("os_composite.img")});
+    } else {
+      std::vector<std::string> virtual_disk_paths = {
+          const_instance.PerInstancePath("overlay.img"),
+          const_instance.PerInstancePath("persistent_composite.img"),
+      };
+      if (FLAGS_use_sdcard) {
+        virtual_disk_paths.push_back(const_instance.sdcard_path());
+      }
+      instance.set_virtual_disk_paths(virtual_disk_paths);
+    }
 
     std::array<unsigned char, 6> mac_address;
     mac_address[0] = 1 << 6; // locally administered
@@ -444,570 +725,206 @@
     }
     mac_address[5] = num;
     instance.set_wifi_mac_address(mac_address);
-  }
+
+    instance.set_start_webrtc_signaling_server(false);
+
+    if (FLAGS_webrtc_device_id.empty()) {
+      // Use the instance's name as a default
+      instance.set_webrtc_device_id(const_instance.instance_name());
+    } else {
+      std::string device_id = FLAGS_webrtc_device_id;
+      size_t pos;
+      while ((pos = device_id.find("{num}")) != std::string::npos) {
+        device_id.replace(pos, strlen("{num}"), std::to_string(num));
+      }
+      instance.set_webrtc_device_id(device_id);
+    }
+    if (FLAGS_start_webrtc_sig_server && is_first_instance) {
+      auto port = 8443 + num - 1;
+      // Change the signaling server port for all instances
+      tmp_config_obj.set_sig_server_port(port);
+      instance.set_start_webrtc_signaling_server(true);
+    } else {
+      instance.set_start_webrtc_signaling_server(false);
+    }
+    is_first_instance = false;
+
+    // instance.modem_simulator_ports := "" or "[port,]*port"
+    if (modem_simulator_count > 0) {
+      std::stringstream modem_ports;
+      for (auto index {0}; index < modem_simulator_count - 1; index++) {
+        modem_ports << calc_vsock_port(9200) << ",";
+      }
+      modem_ports << calc_vsock_port(9200);
+      instance.set_modem_simulator_ports(modem_ports.str());
+    } else {
+      instance.set_modem_simulator_ports("");
+    }
+  } // end of num_instances loop
+
+  tmp_config_obj.set_enable_sandbox(FLAGS_enable_sandbox);
+
+  // Audio is not available for VNC server
+  SetCommandLineOptionWithMode(
+      "enable_audio",
+      (FLAGS_start_vnc_server || (cuttlefish::HostArch() == cuttlefish::Arch::Arm64))
+          ? "false"
+          : "true",
+      SET_FLAGS_DEFAULT);
+  tmp_config_obj.set_enable_audio(FLAGS_enable_audio);
 
   return tmp_config_obj;
 }
 
-bool SaveConfig(const vsoc::CuttlefishConfig& tmp_config_obj) {
-  auto config_file = GetConfigFilePath(tmp_config_obj);
-  auto config_link = vsoc::GetGlobalConfigFileLink();
-  // Save the config object before starting any host process
-  if (!tmp_config_obj.SaveToFile(config_file)) {
-    LOG(ERROR) << "Unable to save config object";
-    return false;
-  }
-  auto legacy_config_file = GetLegacyConfigFilePath(tmp_config_obj);
-  if (!tmp_config_obj.SaveToFile(legacy_config_file)) {
-    LOG(ERROR) << "Unable to save legacy config object";
-    return false;
-  }
-  setenv(vsoc::kCuttlefishConfigEnvVarName, config_file.c_str(), true);
-  if (symlink(config_file.c_str(), config_link.c_str()) != 0) {
-    LOG(ERROR) << "Failed to create symlink to config file at " << config_link
-               << ": " << strerror(errno);
-    return false;
+void SetDefaultFlagsFromConfigPreset() {
+  std::string config_preset = FLAGS_config;  // The name of the preset config.
+  std::string config_file_path;  // The path to the preset config JSON.
+  std::set<std::string> allowed_config_presets;
+  for (const std::string& file :
+       DirectoryContents(DefaultHostArtifactsPath("etc/cvd_config"))) {
+    std::string_view local_file(file);
+    if (android::base::ConsumePrefix(&local_file, "cvd_config_") &&
+        android::base::ConsumeSuffix(&local_file, ".json")) {
+      allowed_config_presets.emplace(local_file);
+    }
   }
 
-  return true;
+  // If the user specifies a --config name, then use that config
+  // preset option.
+  std::string android_info_path = FLAGS_system_image_dir + "/android-info.txt";
+  if (IsFlagSet("config")) {
+    if (!allowed_config_presets.count(config_preset)) {
+      LOG(FATAL) << "Invalid --config option '" << config_preset
+                 << "'. Valid options: "
+                 << android::base::Join(allowed_config_presets, ",");
+    }
+  } else if (FileExists(android_info_path)) {
+    // Otherwise try to load the correct preset using android-info.txt.
+    std::ifstream ifs(android_info_path);
+    if (ifs.is_open()) {
+      std::string android_info;
+      ifs >> android_info;
+      std::string_view local_android_info(android_info);
+      if (android::base::ConsumePrefix(&local_android_info, "config=")) {
+        config_preset = local_android_info;
+      }
+      if (!allowed_config_presets.count(config_preset)) {
+        LOG(WARNING) << android_info_path
+                     << " contains invalid config preset: '"
+                     << local_android_info << "'. Defaulting to 'phone'.";
+        config_preset = "phone";
+      }
+    }
+  }
+  LOG(INFO) << "Launching CVD using --config='" << config_preset << "'.";
+
+  config_file_path = DefaultHostArtifactsPath("etc/cvd_config/cvd_config_" +
+                                              config_preset + ".json");
+  Json::Value config;
+  Json::CharReaderBuilder builder;
+  std::ifstream ifs(config_file_path);
+  std::string errorMessage;
+  if (!Json::parseFromStream(builder, ifs, &config, &errorMessage)) {
+    LOG(FATAL) << "Could not read config file " << config_file_path << ": "
+               << errorMessage;
+  }
+  for (const std::string& flag : config.getMemberNames()) {
+    std::string value;
+    if (flag == "custom_actions") {
+      Json::StreamWriterBuilder factory;
+      value = Json::writeString(factory, config[flag]);
+    } else {
+      value = config[flag].asString();
+    }
+    if (gflags::SetCommandLineOptionWithMode(flag.c_str(), value.c_str(),
+                                             SET_FLAGS_DEFAULT)
+            .empty()) {
+      LOG(FATAL) << "Error setting flag '" << flag << "'.";
+    }
+  }
 }
 
 void SetDefaultFlagsForQemu() {
-  // TODO(b/144119457) Use the serial port.
-  SetCommandLineOptionWithMode("logcat_mode", cvd::kLogcatVsockMode,
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  // for now, we don't set non-default options for QEMU
+  if (FLAGS_gpu_mode == kGpuModeGuestSwiftshader && NumStreamers() == 0) {
+    // This makes WebRTC the default streamer unless the user requests
+    // another via a --star_<streamer> flag, while at the same time it's
+    // possible to run without any streamer by setting --start_webrtc=false.
+    SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT);
+  }
+  std::string default_bootloader = FLAGS_system_image_dir + "/bootloader.qemu";
+  SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
+                               SET_FLAGS_DEFAULT);
 }
 
 void SetDefaultFlagsForCrosvm() {
-  SetCommandLineOptionWithMode("logcat_mode", cvd::kLogcatVsockMode,
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
-
-  // Crosvm requires a specific setting for kernel decompression; it must be
-  // on for aarch64 and off for x86, no other mode is supported.
-  bool decompress_kernel = false;
-  if (cvd::HostArch() == "aarch64") {
-    decompress_kernel = true;
+  if (NumStreamers() == 0) {
+    // This makes WebRTC the default streamer unless the user requests
+    // another via a --star_<streamer> flag, while at the same time it's
+    // possible to run without any streamer by setting --start_webrtc=false.
+    SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT);
   }
-  SetCommandLineOptionWithMode("decompress_kernel",
-                               (decompress_kernel ? "true" : "false"),
-                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
+
+  // TODO(b/182484563): Re-enable autodetection when we fix the crosvm crashes
+  bool default_enable_sandbox = false;
+
+  SetCommandLineOptionWithMode("enable_sandbox",
+                               (default_enable_sandbox ? "true" : "false"),
+                               SET_FLAGS_DEFAULT);
+
+  std::string default_bootloader = FLAGS_system_image_dir + "/bootloader";
+  SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
+                               SET_FLAGS_DEFAULT);
 }
 
-bool ParseCommandLineFlags(int* argc, char*** argv) {
+bool ParseCommandLineFlags(int* argc, char*** argv, KernelConfig* kernel_config) {
   google::ParseCommandLineNonHelpFlags(argc, argv, true);
+  SetDefaultFlagsFromConfigPreset();
+  google::HandleCommandLineHelpFlags();
   bool invalid_manager = false;
-  if (FLAGS_vm_manager == vm_manager::QemuManager::name()) {
+
+  if (!ResolveInstanceFiles()) {
+    return false;
+  }
+
+  ReadKernelConfig(kernel_config);
+  if (FLAGS_vm_manager == "") {
+    if (IsHostCompatible(kernel_config->target_arch)) {
+      FLAGS_vm_manager = CrosvmManager::name();
+    } else {
+      FLAGS_vm_manager = QemuManager::name();
+    }
+  }
+
+  if (FLAGS_vm_manager == QemuManager::name()) {
     SetDefaultFlagsForQemu();
-  } else if (FLAGS_vm_manager == vm_manager::CrosvmManager::name()) {
+  } else if (FLAGS_vm_manager == CrosvmManager::name()) {
     SetDefaultFlagsForCrosvm();
   } else {
     std::cerr << "Unknown Virtual Machine Manager: " << FLAGS_vm_manager
               << std::endl;
     invalid_manager = true;
   }
-  if (NumStreamers() == 0) {
-    // This makes the vnc server the default streamer unless the user requests
-    // another via a --star_<streamer> flag, while at the same time it's
-    // possible to run without any streamer by setting --start_vnc_server=false.
-    SetCommandLineOptionWithMode("start_vnc_server", "true",
-                                 google::FlagSettingMode::SET_FLAGS_DEFAULT);
-  }
-  google::HandleCommandLineHelpFlags();
+  // The default for starting signaling server is whether or not webrt is to be
+  // started.
+  SetCommandLineOptionWithMode("start_webrtc_sig_server",
+                               FLAGS_start_webrtc ? "true" : "false",
+                               SET_FLAGS_DEFAULT);
   if (invalid_manager) {
     return false;
   }
   // Set the env variable to empty (in case the caller passed a value for it).
-  unsetenv(vsoc::kCuttlefishConfigEnvVarName);
+  unsetenv(kCuttlefishConfigEnvVarName);
 
-  return ResolveInstanceFiles();
-}
-
-std::string cpp_basename(const std::string& str) {
-  char* copy = strdup(str.c_str()); // basename may modify its argument
-  std::string ret(basename(copy));
-  free(copy);
-  return ret;
-}
-
-bool CleanPriorFiles(const std::string& path, const std::set<std::string>& preserving) {
-  if (preserving.count(cpp_basename(path))) {
-    LOG(INFO) << "Preserving: " << path;
-    return true;
-  }
-  struct stat statbuf;
-  if (lstat(path.c_str(), &statbuf) < 0) {
-    int error_num = errno;
-    if (error_num == ENOENT) {
-      return true;
-    } else {
-      LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
-      return false;
-    }
-  }
-  if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
-    LOG(INFO) << "Deleting: " << path;
-    if (unlink(path.c_str()) < 0) {
-      int error_num = errno;
-      LOG(ERROR) << "Could not unlink \"" << path << "\", error was " << strerror(error_num);
-      return false;
-    }
-    return true;
-  }
-  std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(path.c_str()), closedir);
-  if (!dir) {
-    int error_num = errno;
-    LOG(ERROR) << "Could not clean \"" << path << "\": error was " << strerror(error_num);
-    return false;
-  }
-  for (auto entity = readdir(dir.get()); entity != nullptr; entity = readdir(dir.get())) {
-    std::string entity_name(entity->d_name);
-    if (entity_name == "." || entity_name == "..") {
-      continue;
-    }
-    std::string entity_path = path + "/" + entity_name;
-    if (!CleanPriorFiles(entity_path.c_str(), preserving)) {
-      return false;
-    }
-  }
-  if (rmdir(path.c_str()) < 0) {
-    if (!(errno == EEXIST || errno == ENOTEMPTY)) {
-      // If EEXIST or ENOTEMPTY, probably because a file was preserved
-      int error_num = errno;
-      LOG(ERROR) << "Could not rmdir \"" << path << "\", error was " << strerror(error_num);
-      return false;
-    }
-  }
   return true;
 }
 
-bool CleanPriorFiles(const std::vector<std::string>& paths, const std::set<std::string>& preserving) {
-  std::string prior_files;
-  for (auto path : paths) {
-    struct stat statbuf;
-    if (stat(path.c_str(), &statbuf) < 0 && errno != ENOENT) {
-      // If ENOENT, it doesn't exist yet, so there is no work to do'
-      int error_num = errno;
-      LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
-      return false;
-    }
-    bool is_directory = (statbuf.st_mode & S_IFMT) == S_IFDIR;
-    prior_files += (is_directory ? (path + "/*") : path) + " ";
-  }
-  LOG(INFO) << "Assuming prior files of " << prior_files;
-  std::string lsof_cmd = "lsof -t " + prior_files + " >/dev/null 2>&1";
-  int rval = std::system(lsof_cmd.c_str());
-  // lsof returns 0 if any of the files are open
-  if (WEXITSTATUS(rval) == 0) {
-    LOG(ERROR) << "Clean aborted: files are in use";
-    return false;
-  }
-  for (const auto& path : paths) {
-    if (!CleanPriorFiles(path, preserving)) {
-      LOG(ERROR) << "Remove of file under \"" << path << "\" failed";
-      return false;
-    }
-  }
-  return true;
-}
-
-bool CleanPriorFiles(const vsoc::CuttlefishConfig& config, const std::set<std::string>& preserving) {
-  std::vector<std::string> paths = {
-    // Everything in the assembly directory
-    FLAGS_assembly_dir,
-    // The environment file
-    GetCuttlefishEnvPath(),
-    // The global link to the config file
-    vsoc::GetGlobalConfigFileLink(),
-  };
-  for (const auto& instance : config.Instances()) {
-    paths.push_back(instance.instance_dir());
-  }
-  paths.push_back(FLAGS_instance_dir);
-  return CleanPriorFiles(paths, preserving);
-}
-
-bool DecompressKernel(const std::string& src, const std::string& dst) {
-  cvd::Command decomp_cmd(vsoc::DefaultHostArtifactsPath("bin/extract-vmlinux"));
-  decomp_cmd.AddParameter(src);
-  auto output_file = cvd::SharedFD::Creat(dst.c_str(), 0666);
-  if (!output_file->IsOpen()) {
-    LOG(ERROR) << "Unable to create decompressed image file: "
-               << output_file->StrError();
-    return false;
-  }
-  decomp_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, output_file);
-  auto decomp_proc = decomp_cmd.Start();
-  return decomp_proc.Started() && decomp_proc.Wait() == 0;
-}
-
-void ValidateAdbModeFlag(const vsoc::CuttlefishConfig& config) {
-  auto adb_modes = config.adb_mode();
-  adb_modes.erase(vsoc::AdbMode::Unknown);
-  if (adb_modes.size() < 1) {
-    LOG(INFO) << "ADB not enabled";
-  }
-}
-
-} // namespace
-
-namespace {
-
-std::vector<ImagePartition> disk_config() {
-  std::vector<ImagePartition> partitions;
-  partitions.push_back(ImagePartition {
-    .label = "misc",
-    .image_file_path = FLAGS_misc_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "boot_a",
-    .image_file_path = FLAGS_boot_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "boot_b",
-    .image_file_path = FLAGS_boot_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "vendor_boot_a",
-    .image_file_path = FLAGS_vendor_boot_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "vendor_boot_b",
-    .image_file_path = FLAGS_vendor_boot_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "vbmeta_a",
-    .image_file_path = FLAGS_vbmeta_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "vbmeta_b",
-    .image_file_path = FLAGS_vbmeta_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "vbmeta_system_a",
-    .image_file_path = FLAGS_vbmeta_system_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "vbmeta_system_b",
-    .image_file_path = FLAGS_vbmeta_system_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "super",
-    .image_file_path = FLAGS_super_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "userdata",
-    .image_file_path = FLAGS_data_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "cache",
-    .image_file_path = FLAGS_cache_image,
-  });
-  partitions.push_back(ImagePartition {
-    .label = "metadata",
-    .image_file_path = FLAGS_metadata_image,
-  });
-  return partitions;
-}
-
-std::chrono::system_clock::time_point LastUpdatedInputDisk() {
-  std::chrono::system_clock::time_point ret;
-  for (auto& partition : disk_config()) {
-    auto partition_mod_time = cvd::FileModificationTime(partition.image_file_path);
-    if (partition_mod_time > ret) {
-      ret = partition_mod_time;
-    }
-  }
-  return ret;
-}
-
-bool ShouldCreateCompositeDisk(const vsoc::CuttlefishConfig& config) {
-  if (!cvd::FileExists(config.composite_disk_path())) {
-    return true;
-  }
-  auto composite_age = cvd::FileModificationTime(config.composite_disk_path());
-  return composite_age < LastUpdatedInputDisk();
-}
-
-bool ConcatRamdisks(const std::string& new_ramdisk_path, const std::string& ramdisk_a_path,
-  const std::string& ramdisk_b_path) {
-  // clear out file of any pre-existing content
-  std::ofstream new_ramdisk(new_ramdisk_path, std::ios_base::binary | std::ios_base::trunc);
-  std::ifstream ramdisk_a(ramdisk_a_path, std::ios_base::binary);
-  std::ifstream ramdisk_b(ramdisk_b_path, std::ios_base::binary);
-
-  if(!new_ramdisk.is_open() || !ramdisk_a.is_open() || !ramdisk_b.is_open()) {
-    return false;
-  }
-
-  new_ramdisk << ramdisk_a.rdbuf() << ramdisk_b.rdbuf();
-  return true;
-}
-
-off_t AvailableSpaceAtPath(const std::string& path) {
-  struct statvfs vfs;
-  if (statvfs(path.c_str(), &vfs) != 0) {
-    int error_num = errno;
-    LOG(ERROR) << "Could not find space available at " << path << ", error was "
-               << strerror(error_num);
-    return 0;
-  }
-  return vfs.f_bsize * vfs.f_bavail; // block size * free blocks for unprivileged users
-}
-
-off_t USERDATA_IMAGE_RESERVED = 4l * (1l << 30l); // 4 GiB
-off_t AGGREGATE_IMAGE_RESERVED = 12l * (1l << 30l); // 12 GiB
-
-bool CreateCompositeDisk(const vsoc::CuttlefishConfig& config) {
-  if (!cvd::SharedFD::Open(config.composite_disk_path().c_str(), O_WRONLY | O_CREAT, 0644)->IsOpen()) {
-    LOG(ERROR) << "Could not ensure " << config.composite_disk_path() << " exists";
-    return false;
-  }
-  if (FLAGS_vm_manager == vm_manager::CrosvmManager::name()) {
-    auto existing_size = cvd::FileSize(FLAGS_data_image);
-    auto available_space = AvailableSpaceAtPath(FLAGS_data_image);
-    if (available_space < USERDATA_IMAGE_RESERVED - existing_size) {
-      // TODO(schuffelen): Duplicate this check in run_cvd when it can run on a separate machine
-      LOG(ERROR) << "Not enough space in fs containing " << FLAGS_data_image;
-      LOG(ERROR) << "Wanted " << (USERDATA_IMAGE_RESERVED - existing_size);
-      LOG(ERROR) << "Got " << available_space;
-      return false;
-    }
-    std::string header_path = config.AssemblyPath("gpt_header.img");
-    std::string footer_path = config.AssemblyPath("gpt_footer.img");
-    CreateCompositeDisk(disk_config(), header_path, footer_path, config.composite_disk_path());
-  } else {
-    auto existing_size = cvd::FileSize(config.composite_disk_path());
-    auto available_space = AvailableSpaceAtPath(config.composite_disk_path());
-    if (available_space < AGGREGATE_IMAGE_RESERVED - existing_size) {
-      LOG(ERROR) << "Not enough space to create " << config.composite_disk_path();
-      LOG(ERROR) << "Wanted " << (AGGREGATE_IMAGE_RESERVED - existing_size);
-      LOG(ERROR) << "Got " << available_space;
-      return false;
-    }
-    AggregateImage(disk_config(), config.composite_disk_path());
-  }
-  return true;
-}
-
-} // namespace
-
-const vsoc::CuttlefishConfig* InitFilesystemAndCreateConfig(
-    int* argc, char*** argv, cvd::FetcherConfig fetcher_config) {
-  if (!ParseCommandLineFlags(argc, argv)) {
-    LOG(ERROR) << "Failed to parse command arguments";
-    exit(AssemblerExitCodes::kArgumentParsingError);
-  }
-
-  auto boot_img_unpacker =
-    cvd::BootImageUnpacker::FromImages(FLAGS_boot_image,
-                                      FLAGS_vendor_boot_image);
-  {
-    // The config object is created here, but only exists in memory until the
-    // SaveConfig line below. Don't launch cuttlefish subprocesses between these
-    // two operations, as those will assume they can read the config object from
-    // disk.
-    auto config = InitializeCuttlefishConfiguration(*boot_img_unpacker, fetcher_config);
-    std::set<std::string> preserving;
-    if (FLAGS_resume && ShouldCreateCompositeDisk(config)) {
-      LOG(WARNING) << "Requested resuming a previous session (the default behavior) "
-                   << "but the base images have changed under the overlay, making the "
-                   << "overlay incompatible. Wiping the overlay files.";
-    } else if (FLAGS_resume && !ShouldCreateCompositeDisk(config)) {
-      preserving.insert("overlay.img");
-      preserving.insert("gpt_header.img");
-      preserving.insert("gpt_footer.img");
-      preserving.insert("composite.img");
-      preserving.insert("sdcard.img");
-      preserving.insert("access-kregistry");
-    }
-    if (!CleanPriorFiles(config, preserving)) {
-      LOG(ERROR) << "Failed to clean prior files";
-      exit(AssemblerExitCodes::kPrioFilesCleanupError);
-    }
-    // Create assembly directory if it doesn't exist.
-    if (!cvd::DirectoryExists(FLAGS_assembly_dir.c_str())) {
-      LOG(INFO) << "Setting up " << FLAGS_assembly_dir;
-      if (mkdir(FLAGS_assembly_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
-          && errno != EEXIST) {
-        LOG(ERROR) << "Failed to create assembly directory: "
-                  << FLAGS_assembly_dir << ". Error: " << errno;
-        exit(AssemblerExitCodes::kAssemblyDirCreationError);
-      }
-    }
-    for (const auto& instance : config.Instances()) {
-      // Create instance directory if it doesn't exist.
-      if (!cvd::DirectoryExists(instance.instance_dir().c_str())) {
-        LOG(INFO) << "Setting up " << FLAGS_instance_dir << ".N";
-        if (mkdir(instance.instance_dir().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
-            && errno != EEXIST) {
-          LOG(ERROR) << "Failed to create instance directory: "
-                    << FLAGS_instance_dir << ". Error: " << errno;
-          exit(AssemblerExitCodes::kInstanceDirCreationError);
-        }
-      }
-      auto internal_dir = instance.instance_dir() + "/" + vsoc::kInternalDirName;
-      if (!cvd::DirectoryExists(internal_dir)) {
-        if (mkdir(internal_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
-           && errno != EEXIST) {
-          LOG(ERROR) << "Failed to create internal instance directory: "
-                    << internal_dir << ". Error: " << errno;
-          exit(AssemblerExitCodes::kInstanceDirCreationError);
-        }
-      }
-    }
-    if (!SaveConfig(config)) {
-      LOG(ERROR) << "Failed to initialize configuration";
-      exit(AssemblerExitCodes::kCuttlefishConfigurationInitError);
-    }
-  }
-
-  std::string first_instance = FLAGS_instance_dir + "." + std::to_string(vsoc::GetInstance());
-  if (symlink(first_instance.c_str(), FLAGS_instance_dir.c_str()) < 0) {
-    LOG(ERROR) << "Could not symlink \"" << first_instance << "\" to \"" << FLAGS_instance_dir << "\"";
-    exit(cvd::kCuttlefishConfigurationInitError);
-  }
-
-  if (!cvd::FileHasContent(FLAGS_boot_image)) {
-    LOG(ERROR) << "File not found: " << FLAGS_boot_image;
-    exit(cvd::kCuttlefishConfigurationInitError);
-  }
-
-  if (!cvd::FileHasContent(FLAGS_vendor_boot_image)) {
-    LOG(ERROR) << "File not found: " << FLAGS_vendor_boot_image;
-    exit(cvd::kCuttlefishConfigurationInitError);
-  }
-
-  // Do this early so that the config object is ready for anything that needs it
-  auto config = vsoc::CuttlefishConfig::Get();
-  if (!config) {
-    LOG(ERROR) << "Failed to obtain config singleton";
-    exit(AssemblerExitCodes::kCuttlefishConfigurationInitError);
-  }
-
-  if (!boot_img_unpacker->Unpack(config->ramdisk_image_path(),
-                                 config->vendor_ramdisk_image_path(),
-                                 config->use_unpacked_kernel()
-                                     ? config->kernel_image_path()
-                                     : "")) {
-    LOG(ERROR) << "Failed to unpack boot image";
-    exit(AssemblerExitCodes::kBootImageUnpackError);
-  }
-
-  // TODO(134522463) as part of the bootloader refactor, repack the vendor boot
-  // image and use the bootloader to load both the boot and vendor ramdisk.
-  // Until then, this hack to get gki modules into cuttlefish will suffice.
-
-  // If a vendor ramdisk comes in via this mechanism, let it supercede the one
-  // in the vendor boot image. This flag is what kernel presubmit testing uses
-  // to pass in the kernel ramdisk.
-
-  // If no kernel is passed in or an initramfs is made available, the default
-  // vendor boot ramdisk or the initramfs provided should be appended to the
-  // boot ramdisk. If a kernel IS provided with no initramfs, it is safe to
-  // safe to assume that the kernel was built with no modules and expects no
-  // modules for cf to run properly.
-  std::string discovered_kernel = fetcher_config.FindCvdFileWithSuffix(kKernelDefaultPath);
-  std::string foreign_kernel = FLAGS_kernel_path.size() ? FLAGS_kernel_path : discovered_kernel;
-  std::string discovered_ramdisk = fetcher_config.FindCvdFileWithSuffix(kInitramfsImg);
-  std::string foreign_ramdisk = FLAGS_initramfs_path.size () ? FLAGS_initramfs_path : discovered_ramdisk;
-  if(!foreign_kernel.size() || foreign_ramdisk.size()) {
-    const std::string& vendor_ramdisk_path =
-      config->initramfs_path().size() ? config->initramfs_path()
-                                      : config->vendor_ramdisk_image_path();
-    if(!ConcatRamdisks(config->final_ramdisk_path(),
-                       config->ramdisk_image_path(), vendor_ramdisk_path)) {
-      LOG(ERROR) << "Failed to concatenate ramdisk and vendor ramdisk";
-      exit(AssemblerExitCodes::kInitRamFsConcatError);
-    }
-  }
-
-  if (config->decompress_kernel()) {
-    if (!DecompressKernel(config->kernel_image_path(),
-        config->decompressed_kernel_image_path())) {
-      LOG(ERROR) << "Failed to decompress kernel";
-      exit(AssemblerExitCodes::kKernelDecompressError);
-    }
-  }
-
-  ValidateAdbModeFlag(*config);
-
-  // Create misc if necessary
-  if (!InitializeMiscImage(FLAGS_misc_image)) {
-    exit(cvd::kCuttlefishConfigurationInitError);
-  }
-
-  // Create data if necessary
-  if (!ApplyDataImagePolicy(*config, FLAGS_data_image)) {
-    exit(cvd::kCuttlefishConfigurationInitError);
-  }
-
-  if (!cvd::FileExists(FLAGS_metadata_image)) {
-    CreateBlankImage(FLAGS_metadata_image, FLAGS_blank_metadata_image_mb, "none");
-  }
-
-  for (const auto& instance : config->Instances()) {
-    if (!cvd::FileExists(instance.access_kregistry_path())) {
-      CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
-    }
-
-    if (!cvd::FileExists(instance.sdcard_path())) {
-      CreateBlankImage(instance.sdcard_path(),
-                       FLAGS_blank_sdcard_image_mb, "sdcard");
-    }
-  }
-
-  // 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 (cvd::FileSize(vbmeta_image) != VBMETA_MAX_SIZE) {
-      auto fd = cvd::SharedFD::Open(vbmeta_image, O_RDWR);
-      if (fd->Truncate(VBMETA_MAX_SIZE) != 0) {
-        LOG(ERROR) << "`truncate --size=" << VBMETA_MAX_SIZE << " "
-                   << vbmeta_image << "` failed: " << fd->StrError();
-        exit(cvd::kCuttlefishConfigurationInitError);
-      }
-    }
-  }
-
-  if (SuperImageNeedsRebuilding(fetcher_config, *config)) {
-    if (!RebuildSuperImage(fetcher_config, *config, FLAGS_super_image)) {
-      LOG(ERROR) << "Super image rebuilding requested but could not be completed.";
-      exit(cvd::kCuttlefishConfigurationInitError);
-    }
-  }
-
-  if (ShouldCreateCompositeDisk(*config)) {
-    if (!CreateCompositeDisk(*config)) {
-      exit(cvd::kDiskSpaceError);
-    }
-  }
-
-  for (auto instance : config->Instances()) {
-    auto overlay_path = instance.PerInstancePath("overlay.img");
-    if (!cvd::FileExists(overlay_path) || ShouldCreateCompositeDisk(*config) || !FLAGS_resume
-        || cvd::FileModificationTime(overlay_path) < cvd::FileModificationTime(config->composite_disk_path())) {
-      if (FLAGS_resume) {
-        LOG(WARNING) << "Requested to continue an existing session, but the overlay was "
-                     << "newer than its underlying composite disk. Wiping the overlay.";
-      }
-      CreateQcowOverlay(config->crosvm_binary(), config->composite_disk_path(), overlay_path);
-      CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
-    }
-  }
-
-  for (auto instance : config->Instances()) {
-    // Check that the files exist
-    for (const auto& file : instance.virtual_disk_paths()) {
-      if (!file.empty() && !cvd::FileHasContent(file.c_str())) {
-        LOG(ERROR) << "File not found: " << file;
-        exit(cvd::kCuttlefishConfigurationInitError);
-      }
-    }
-  }
-
-  return config;
-}
-
-std::string GetConfigFilePath(const vsoc::CuttlefishConfig& config) {
+std::string GetConfigFilePath(const CuttlefishConfig& config) {
   return config.AssemblyPath("cuttlefish_config.json");
 }
+
+std::string GetCuttlefishEnvPath() {
+  return StringFromEnv("HOME", ".") + "/.cuttlefish.sh";
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/flags.h b/host/commands/assemble_cvd/flags.h
index 0373388..3c02d92 100644
--- a/host/commands/assemble_cvd/flags.h
+++ b/host/commands/assemble_cvd/flags.h
@@ -1,8 +1,27 @@
 #pragma once
 
+#include <cstdint>
+#include <optional>
+
+#include "common/libs/utils/environment.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/config/fetcher_config.h"
 
-const vsoc::CuttlefishConfig* InitFilesystemAndCreateConfig(
-    int* argc, char*** argv, cvd::FetcherConfig config);
-std::string GetConfigFilePath(const vsoc::CuttlefishConfig& config);
+namespace cuttlefish {
+
+struct KernelConfig {
+  Arch target_arch;
+  bool bootconfig_supported;
+};
+
+bool ParseCommandLineFlags(int* argc, char*** argv,
+                           KernelConfig* kernel_config);
+// Must be called after ParseCommandLineFlags.
+CuttlefishConfig InitializeCuttlefishConfiguration(
+    const std::string& instance_dir, int modem_simulator_count,
+    KernelConfig kernel_config);
+
+std::string GetConfigFilePath(const CuttlefishConfig& config);
+std::string GetCuttlefishEnvPath();
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/image_aggregator.cc b/host/commands/assemble_cvd/image_aggregator.cc
deleted file mode 100644
index f700ccd..0000000
--- a/host/commands/assemble_cvd/image_aggregator.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include "host/commands/assemble_cvd/image_aggregator.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-
-#include <fstream>
-#include <string>
-#include <vector>
-
-#include <glog/logging.h>
-#include <json/json.h>
-#include <google/protobuf/text_format.h>
-#include <sparse/sparse.h>
-
-#include "common/libs/fs/shared_buf.h"
-#include "common/libs/fs/shared_fd.h"
-#include "common/libs/utils/files.h"
-#include "common/libs/utils/subprocess.h"
-#include "host/commands/assemble_cvd/mbr.h"
-#include "host/libs/config/cuttlefish_config.h"
-#include "device/google/cuttlefish/host/commands/assemble_cvd/cdisk_spec.pb.h"
-
-namespace {
-
-const int GPT_HEADER_SIZE = 512 * 34;
-const int GPT_FOOTER_SIZE = 512 * 33;
-
-const std::string BPTTOOL_FILE_PATH = "bin/cf_bpttool";
-
-Json::Value BpttoolInput(const std::vector<ImagePartition>& partitions) {
-  std::vector<off_t> file_sizes;
-  off_t total_size = 20 << 20; // 20 MB for padding
-  for (auto& partition : partitions) {
-    LOG(INFO) << "Examining " << partition.label;
-    auto file = cvd::SharedFD::Open(partition.image_file_path.c_str(), O_RDONLY);
-    if (!file->IsOpen()) {
-      LOG(FATAL) << "Could not open \"" << partition.image_file_path
-                 << "\": " << file->StrError();
-      break;
-    }
-    int fd = file->UNMANAGED_Dup();
-    auto sparse = sparse_file_import(fd, /* verbose */ false, /* crc */ false);
-    off_t partition_file_size = 0;
-    if (sparse) {
-      partition_file_size = sparse_file_len(sparse, /* sparse */ false,
-                                            /* crc */ true);
-      sparse_file_destroy(sparse);
-      close(fd);
-      LOG(INFO) << "was sparse";
-    } else {
-      partition_file_size = cvd::FileSize(partition.image_file_path);
-      if (partition_file_size == 0) {
-        LOG(FATAL) << "Could not get file size of \"" << partition.image_file_path
-                  << "\"";
-        break;
-      }
-      LOG(INFO) << "was not sparse";
-    }
-    LOG(INFO) << "size was " << partition_file_size;
-    total_size += partition_file_size;
-    file_sizes.push_back(partition_file_size);
-  }
-  Json::Value bpttool_input_json;
-  bpttool_input_json["settings"] = Json::Value();
-  bpttool_input_json["settings"]["disk_size"] = (Json::Int64) total_size;
-  bpttool_input_json["partitions"] = Json::Value(Json::arrayValue);
-  for (size_t i = 0; i < partitions.size(); i++) {
-    Json::Value partition_json;
-    partition_json["label"] = partitions[i].label;
-    partition_json["size"] = (Json::Int64) file_sizes[i];
-    partition_json["guid"] = "auto";
-    partition_json["type_guid"] = "linux_fs";
-    bpttool_input_json["partitions"].append(partition_json);
-  }
-  return bpttool_input_json;
-}
-
-std::string CreateFile(size_t len) {
-  char file_template[] = "/tmp/diskXXXXXX";
-  int fd = mkstemp(file_template);
-  if (fd < 0) {
-    LOG(FATAL) << "not able to create disk hole temp file";
-  }
-  char data[4096];
-  for (size_t i = 0; i < sizeof(data); i++) {
-    data[i] = '\0';
-  }
-  for (size_t i = 0; i < len + 2 * sizeof(data); i+= sizeof(data)) {
-    if (write(fd, data, sizeof(data)) < (ssize_t) sizeof(data)) {
-      LOG(FATAL) << "not able to write to disk hole temp file";
-    }
-  }
-  close(fd);
-  return std::string(file_template);
-}
-
-CompositeDisk MakeCompositeDiskSpec(const Json::Value& bpt_file,
-                                    const std::vector<ImagePartition>& partitions,
-                                    const std::string& header_file,
-                                    const std::string& footer_file) {
-  CompositeDisk disk;
-  disk.set_version(1);
-  ComponentDisk* header = disk.add_component_disks();
-  header->set_file_path(header_file);
-  header->set_offset(0);
-  size_t previous_end = GPT_HEADER_SIZE;
-  for (auto& bpt_partition: bpt_file["partitions"]) {
-    if (bpt_partition["offset"].asUInt64() != previous_end) {
-      ComponentDisk* component = disk.add_component_disks();
-      component->set_file_path(CreateFile(bpt_partition["offset"].asUInt64() - previous_end));
-      component->set_offset(previous_end);
-    }
-    ComponentDisk* component = disk.add_component_disks();
-    for (auto& partition : partitions) {
-      if (bpt_partition["label"] == partition.label) {
-        component->set_file_path(partition.image_file_path);
-      }
-    }
-    component->set_offset(bpt_partition["offset"].asUInt64());
-    component->set_read_write_capability(ReadWriteCapability::READ_WRITE);
-    previous_end = bpt_partition["offset"].asUInt64() + bpt_partition["size"].asUInt64();
-  }
-  size_t footer_start = bpt_file["settings"]["disk_size"].asUInt64() - GPT_FOOTER_SIZE;
-  if (footer_start != previous_end) {
-    ComponentDisk* component = disk.add_component_disks();
-    component->set_file_path(CreateFile(footer_start - previous_end));
-    component->set_offset(previous_end);
-  }
-  ComponentDisk* footer = disk.add_component_disks();
-  footer->set_file_path(footer_file);
-  footer->set_offset(bpt_file["settings"]["disk_size"].asUInt64() - GPT_FOOTER_SIZE);
-  disk.set_length(bpt_file["settings"]["disk_size"].asUInt64());
-  return disk;
-}
-
-cvd::SharedFD JsonToFd(const Json::Value& json) {
-  Json::FastWriter json_writer;
-  std::string json_string = json_writer.write(json);
-  cvd::SharedFD pipe[2];
-  cvd::SharedFD::Pipe(&pipe[0], &pipe[1]);
-  int written = pipe[1]->Write(json_string.c_str(), json_string.size());
-  if (written < 0) {
-    LOG(FATAL) << "Failed to write to pipe, errno is " << pipe[0]->GetErrno();
-  } else if (written < (int) json_string.size()) {
-    LOG(FATAL) << "Failed to write full json to pipe, only did " << written;
-  }
-  return pipe[0];
-}
-
-Json::Value FdToJson(cvd::SharedFD fd) {
-  std::string contents;
-  cvd::ReadAll(fd, &contents);
-  Json::Reader reader;
-  Json::Value json;
-  if (!reader.parse(contents, json)) {
-    LOG(FATAL) << "Could not parse json: " << reader.getFormattedErrorMessages();
-  }
-  return json;
-}
-
-cvd::SharedFD BpttoolMakeTable(const cvd::SharedFD& input) {
-  auto bpttool_path = vsoc::DefaultHostArtifactsPath(BPTTOOL_FILE_PATH);
-  cvd::Command bpttool_cmd(bpttool_path);
-  bpttool_cmd.AddParameter("make_table");
-  bpttool_cmd.AddParameter("--input=/dev/stdin");
-  bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, input);
-  bpttool_cmd.AddParameter("--output_json=/dev/stdout");
-  cvd::SharedFD output_pipe[2];
-  cvd::SharedFD::Pipe(&output_pipe[0], &output_pipe[1]);
-  bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, output_pipe[1]);
-  int success = bpttool_cmd.Start().Wait();
-  if (success != 0) {
-    LOG(FATAL) << "Unable to run bpttool. Exited with status " << success;
-  }
-  return output_pipe[0];
-}
-
-cvd::SharedFD BpttoolMakePartitionTable(cvd::SharedFD input) {
-  auto bpttool_path = vsoc::DefaultHostArtifactsPath(BPTTOOL_FILE_PATH);
-  cvd::Command bpttool_cmd(bpttool_path);
-  bpttool_cmd.AddParameter("make_table");
-  bpttool_cmd.AddParameter("--input=/dev/stdin");
-  bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, input);
-  bpttool_cmd.AddParameter("--output_gpt=/dev/stdout");
-  cvd::SharedFD output_pipe[2];
-  cvd::SharedFD::Pipe(&output_pipe[0], &output_pipe[1]);
-  bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, output_pipe[1]);
-  int success = bpttool_cmd.Start().Wait();
-  if (success != 0) {
-    LOG(FATAL) << "Unable to run bpttool. Exited with status " << success;
-  }
-  return output_pipe[0];
-}
-
-void CreateGptFiles(cvd::SharedFD gpt, const std::string& header_file,
-                    const std::string& footer_file) {
-  std::string content;
-  content.resize(GPT_HEADER_SIZE);
-  if (cvd::ReadExact(gpt, &content) < GPT_HEADER_SIZE) {
-    LOG(FATAL) << "Unable to run read full gpt. Errno is " << gpt->GetErrno();
-  }
-  auto header_fd = cvd::SharedFD::Open(header_file.c_str(), O_CREAT | O_RDWR, 0755);
-  if (cvd::WriteAll(header_fd, content) < GPT_HEADER_SIZE) {
-    LOG(FATAL) << "Unable to run write full gpt. Errno is " << gpt->GetErrno();
-  }
-  content.resize(GPT_FOOTER_SIZE);
-  if (cvd::ReadExact(gpt, &content) < GPT_FOOTER_SIZE) {
-    LOG(FATAL) << "Unable to run read full gpt. Errno is " << gpt->GetErrno();
-  }
-  auto footer_fd = cvd::SharedFD::Open(footer_file.c_str(), O_CREAT | O_RDWR, 0755);
-  if (cvd::WriteAll(footer_fd, content) < GPT_FOOTER_SIZE) {
-    LOG(FATAL) << "Unable to run write full gpt. Errno is " << gpt->GetErrno();
-  }
-}
-
-void BptToolMakeDiskImage(const std::vector<ImagePartition>& partitions,
-                          cvd::SharedFD table, const std::string& output) {
-  auto bpttool_path = vsoc::DefaultHostArtifactsPath(BPTTOOL_FILE_PATH);
-  cvd::Command bpttool_cmd(bpttool_path);
-  bpttool_cmd.AddParameter("make_disk_image");
-  bpttool_cmd.AddParameter("--input=/dev/stdin");
-  bpttool_cmd.AddParameter("--output=", cvd::AbsolutePath(output));
-  bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, table);
-  for (auto& partition : partitions) {
-    auto abs_path = cvd::AbsolutePath(partition.image_file_path);
-    bpttool_cmd.AddParameter("--image=" + partition.label + ":" + abs_path);
-  }
-  int success = bpttool_cmd.Start().Wait();
-  if (success != 0) {
-    LOG(FATAL) << "Unable to run bpttool. Exited with status " << success;
-  }
-}
-
-void DeAndroidSparse(const std::vector<ImagePartition>& partitions) {
-  for (const auto& partition : partitions) {
-    auto file = cvd::SharedFD::Open(partition.image_file_path.c_str(), O_RDONLY);
-    if (!file->IsOpen()) {
-      LOG(FATAL) << "Could not open \"" << partition.image_file_path
-                  << "\": " << file->StrError();
-      break;
-    }
-    int fd = file->UNMANAGED_Dup();
-    auto sparse = sparse_file_import(fd, /* verbose */ false, /* crc */ false);
-    if (!sparse) {
-      close(fd);
-      continue;
-    }
-    LOG(INFO) << "Desparsing " << partition.image_file_path;
-    std::string out_file_name = partition.image_file_path + ".desparse";
-    auto out_file = cvd::SharedFD::Open(out_file_name.c_str(), O_RDWR | O_CREAT | O_TRUNC,
-                                        S_IRUSR | S_IWUSR | S_IRGRP);
-    int write_fd = out_file->UNMANAGED_Dup();
-    int write_status = sparse_file_write(sparse, write_fd, /* gz */ false,
-                                         /* sparse */ false, /* crc */ false);
-    if (write_status < 0) {
-      LOG(FATAL) << "Failed to desparse \"" << partition.image_file_path << "\": " << write_status;
-    }
-    close(write_fd);
-    if (rename(out_file_name.c_str(), partition.image_file_path.c_str()) < 0) {
-      int error_num = errno;
-      LOG(FATAL) << "Could not move \"" << out_file_name << "\" to \""
-                 << partition.image_file_path << "\": " << strerror(error_num);
-    }
-    sparse_file_destroy(sparse);
-    close(fd);
-  }
-}
-
-} // namespace
-
-void AggregateImage(const std::vector<ImagePartition>& partitions,
-                    const std::string& output_path) {
-  DeAndroidSparse(partitions);
-  auto bpttool_input_json = BpttoolInput(partitions);
-  auto input_json_fd = JsonToFd(bpttool_input_json);
-  auto table_fd = BpttoolMakeTable(input_json_fd);
-  BptToolMakeDiskImage(partitions, table_fd, output_path);
-};
-
-void CreateCompositeDisk(std::vector<ImagePartition> partitions,
-                         const std::string& header_file,
-                         const std::string& footer_file,
-                         const std::string& output_composite_path) {
-  auto bpttool_input_json = BpttoolInput(partitions);
-  auto table_fd = BpttoolMakeTable(JsonToFd(bpttool_input_json));
-  auto table = FdToJson(table_fd);
-  auto partition_table_fd = BpttoolMakePartitionTable(JsonToFd(bpttool_input_json));
-  CreateGptFiles(partition_table_fd, header_file, footer_file);
-  auto composite_proto = MakeCompositeDiskSpec(table, partitions, header_file, footer_file);
-  std::ofstream composite(output_composite_path.c_str(), std::ios::binary | std::ios::trunc);
-  composite << "composite_disk\x1d";
-  composite_proto.SerializeToOstream(&composite);
-  composite.flush();
-}
-
-void CreateQcowOverlay(const std::string& crosvm_path,
-                       const std::string& backing_file,
-                       const std::string& output_overlay_path) {
-  cvd::Command crosvm_qcow2_cmd(crosvm_path);
-  crosvm_qcow2_cmd.AddParameter("create_qcow2");
-  crosvm_qcow2_cmd.AddParameter("--backing_file=", backing_file);
-  crosvm_qcow2_cmd.AddParameter(output_overlay_path);
-  int success = crosvm_qcow2_cmd.Start().Wait();
-  if (success != 0) {
-    LOG(FATAL) << "Unable to run crosvm create_qcow2. Exited with status " << success;
-  }
-}
diff --git a/host/commands/assemble_cvd/image_aggregator.h b/host/commands/assemble_cvd/image_aggregator.h
deleted file mode 100644
index d27931b..0000000
--- a/host/commands/assemble_cvd/image_aggregator.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 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>
-#include <vector>
-
-struct ImagePartition {
-  std::string label;
-  std::string image_file_path;
-};
-
-void AggregateImage(const std::vector<ImagePartition>& partitions,
-                    const std::string& output_path);
-void CreateCompositeDisk(std::vector<ImagePartition> partitions,
-                         const std::string& header_file,
-                         const std::string& footer_file,
-                         const std::string& output_composite_path);
-void CreateQcowOverlay(const std::string& crosvm_path,
-                       const std::string& backing_file,
-                       const std::string& output_overlay_path);
diff --git a/host/commands/assemble_cvd/mbr.h b/host/commands/assemble_cvd/mbr.h
deleted file mode 100644
index b06a5e3..0000000
--- a/host/commands/assemble_cvd/mbr.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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
-
-constexpr int SECTOR_SIZE = 512;
-
-struct __attribute__((packed)) MbrPartitionEntry {
-  std::uint8_t status;
-  std::uint8_t begin_chs[3];
-  std::uint8_t partition_type;
-  std::uint8_t end_chs[3];
-  std::uint32_t first_lba;
-  std::uint32_t num_sectors;
-};
-
-struct __attribute__((packed)) MasterBootRecord {
-  std::uint8_t bootstrap_code[446];
-  MbrPartitionEntry partitions[4];
-  std::uint8_t boot_signature[2];
-};
-
-static_assert(sizeof(MasterBootRecord) == SECTOR_SIZE);
diff --git a/host/commands/assemble_cvd/misc_info.cc b/host/commands/assemble_cvd/misc_info.cc
index 4d5ecd5..e96099c 100644
--- a/host/commands/assemble_cvd/misc_info.cc
+++ b/host/commands/assemble_cvd/misc_info.cc
@@ -18,8 +18,11 @@
 #include <algorithm>
 
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
+namespace cuttlefish {
+
 MiscInfo ParseMiscInfo(const std::string& misc_info_contents) {
   auto lines = android::base::Split(misc_info_contents, "\n");
   MiscInfo misc_info;
@@ -70,11 +73,55 @@
   return components;
 }
 
-static const std::string kGoogleDynamicPartitions =
-    "super_google_dynamic_partitions_partition_list";
+static constexpr const char* kGoogleDynamicPartitions =
+    "google_dynamic_partitions";
+static constexpr const char* kSuperPartitionGroups = "super_partition_groups";
 
-void SetSuperPartitionComponents(const std::vector<std::string>& components,
+bool SetSuperPartitionComponents(const std::vector<std::string>& components,
                                  MiscInfo* misc_info) {
+  auto super_partition_groups = misc_info->find(kSuperPartitionGroups);
+  if (super_partition_groups == misc_info->end()) {
+    LOG(ERROR) << "Failed to find super partition groups in misc_info";
+    return false;
+  }
+
+  // Remove all existing update groups in misc_info
+  auto update_groups =
+      android::base::Split(super_partition_groups->second, " ");
+  for (const auto& group_name : update_groups) {
+    auto partition_list = android::base::StringPrintf("super_%s_partition_list",
+                                                      group_name.c_str());
+    auto partition_size =
+        android::base::StringPrintf("super_%s_group_size", group_name.c_str());
+    for (const auto& key : {partition_list, partition_size}) {
+      auto it = misc_info->find(key);
+      if (it == misc_info->end()) {
+        LOG(ERROR) << "Failed to find " << key << " in misc_info";
+        return false;
+      }
+      misc_info->erase(it);
+    }
+  }
+
+  // For merged target-file, put all dynamic partitions under the
+  // google_dynamic_partitions update group.
+  // TODO(xunchang) use different update groups for system and vendor images.
   (*misc_info)[kDynamicPartitions] = android::base::Join(components, " ");
-  (*misc_info)[kGoogleDynamicPartitions] = android::base::Join(components, " ");
+  (*misc_info)[kSuperPartitionGroups] = kGoogleDynamicPartitions;
+  std::string partitions_list_key = android::base::StringPrintf(
+      "super_%s_partition_list", kGoogleDynamicPartitions);
+  (*misc_info)[partitions_list_key] = android::base::Join(components, " ");
+
+  // Use the entire super partition as the group size
+  std::string group_size_key = android::base::StringPrintf(
+      "super_%s_group_size", kGoogleDynamicPartitions);
+  auto super_size_it = misc_info->find("super_partition_size");
+  if (super_size_it == misc_info->end()) {
+    LOG(ERROR) << "Failed to find super partition size";
+    return false;
+  }
+  (*misc_info)[group_size_key] = super_size_it->second;
+  return true;
 }
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/misc_info.h b/host/commands/assemble_cvd/misc_info.h
index 7c32e3b..aa130bc 100644
--- a/host/commands/assemble_cvd/misc_info.h
+++ b/host/commands/assemble_cvd/misc_info.h
@@ -17,6 +17,9 @@
 
 #include <map>
 #include <string>
+#include <vector>
+
+namespace cuttlefish {
 
 using MiscInfo = std::map<std::string, std::string>;
 
@@ -24,5 +27,7 @@
 std::string WriteMiscInfo(const MiscInfo& info);
 
 std::vector<std::string> SuperPartitionComponents(const MiscInfo&);
-void SetSuperPartitionComponents(const std::vector<std::string>& components,
+bool SetSuperPartitionComponents(const std::vector<std::string>& components,
                                  MiscInfo* misc_info);
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/super_image_mixer.cc b/host/commands/assemble_cvd/super_image_mixer.cc
index 1171126..c1e7eac 100644
--- a/host/commands/assemble_cvd/super_image_mixer.cc
+++ b/host/commands/assemble_cvd/super_image_mixer.cc
@@ -24,7 +24,7 @@
 #include <memory>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/utils/archive.h"
@@ -34,13 +34,11 @@
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/config/fetcher_config.h"
 
+namespace cuttlefish {
 namespace {
 
-using cvd::FileExists;
-using vsoc::DefaultHostArtifactsPath;
-
-std::string TargetFilesZip(const cvd::FetcherConfig& fetcher_config,
-                           cvd::FileSource source) {
+std::string TargetFilesZip(const FetcherConfig& fetcher_config,
+                           FileSource source) {
   for (const auto& file_iter : fetcher_config.get_cvd_files()) {
     const auto& file_path = file_iter.first;
     const auto& file_info = file_iter.second;
@@ -58,12 +56,13 @@
 const std::string kMiscInfoPath = "META/misc_info.txt";
 const std::set<std::string> kDefaultTargetImages = {
   "IMAGES/boot.img",
-  "IMAGES/cache.img",
   "IMAGES/odm.img",
+  "IMAGES/odm_dlkm.img",
   "IMAGES/recovery.img",
   "IMAGES/userdata.img",
   "IMAGES/vbmeta.img",
   "IMAGES/vendor.img",
+  "IMAGES/vendor_dlkm.img",
 };
 const std::set<std::string> kDefaultTargetBuildProp = {
   "ODM/build.prop",
@@ -72,7 +71,7 @@
   "VENDOR/etc/build.prop",
 };
 
-void FindImports(cvd::Archive* archive, const std::string& build_prop_file) {
+void FindImports(Archive* archive, const std::string& build_prop_file) {
   auto contents = archive->ExtractToMemory(build_prop_file);
   auto lines = android::base::Split(contents, "\n");
   for (const auto& line : lines) {
@@ -86,8 +85,8 @@
 bool CombineTargetZipFiles(const std::string& default_target_zip,
                            const std::string& system_target_zip,
                            const std::string& output_path) {
-  cvd::Archive default_target_archive(default_target_zip);
-  cvd::Archive system_target_archive(system_target_zip);
+  Archive default_target_archive(default_target_zip);
+  Archive system_target_archive(system_target_zip);
 
   auto default_target_contents = default_target_archive.Contents();
   if (default_target_contents.size() == 0) {
@@ -133,21 +132,27 @@
   }
   auto output_misc = default_misc;
   auto system_super_partitions = SuperPartitionComponents(system_misc);
-  if (std::find(system_super_partitions.begin(), system_super_partitions.end(),
-                "odm") == system_super_partitions.end()) {
-    // odm is not one of the partitions skipped by the system check
-    system_super_partitions.push_back("odm");
+  // Ensure specific skipped partitions end up in the misc_info.txt
+  for (auto partition : {"odm", "odm_dlkm", "vendor", "vendor_dlkm"}) {
+    if (std::find(system_super_partitions.begin(), system_super_partitions.end(),
+                  partition) == system_super_partitions.end()) {
+      system_super_partitions.push_back(partition);
+    }
   }
-  SetSuperPartitionComponents(system_super_partitions, &output_misc);
+  if (!SetSuperPartitionComponents(system_super_partitions, &output_misc)) {
+    LOG(ERROR) << "Failed to update super partitions components for misc_info";
+    return false;
+  }
+
   auto misc_output_path = output_path + "/" + kMiscInfoPath;
-  cvd::SharedFD misc_output_file =
-      cvd::SharedFD::Creat(misc_output_path.c_str(), 0644);
+  SharedFD misc_output_file =
+      SharedFD::Creat(misc_output_path.c_str(), 0644);
   if (!misc_output_file->IsOpen()) {
     LOG(ERROR) << "Failed to open output misc file: "
                << misc_output_file->StrError();
     return false;
   }
-  if (cvd::WriteAll(misc_output_file, WriteMiscInfo(output_misc)) < 0) {
+  if (WriteAll(misc_output_file, WriteMiscInfo(output_misc)) < 0) {
     LOG(ERROR) << "Failed to write output misc file contents: "
                << misc_output_file->StrError();
     return false;
@@ -220,15 +225,15 @@
     build_super_image_binary =
         DefaultHostArtifactsPath("otatools/bin/build_super_image");
     otatools_path = DefaultHostArtifactsPath("otatools");
-  } else if (FileExists(DefaultHostArtifactsPath("bin/build_super_image"))) {
+  } else if (FileExists(HostBinaryPath("build_super_image"))) {
     build_super_image_binary =
-        DefaultHostArtifactsPath("bin/build_super_image");
+        HostBinaryPath("build_super_image");
     otatools_path = DefaultHostArtifactsPath("");
   } else {
     LOG(ERROR) << "Could not find otatools";
     return false;
   }
-  return cvd::execute({
+  return execute({
     build_super_image_binary,
     "--path=" + otatools_path,
     combined_target_zip,
@@ -238,31 +243,31 @@
 
 } // namespace
 
-bool SuperImageNeedsRebuilding(const cvd::FetcherConfig& fetcher_config,
-                               const vsoc::CuttlefishConfig&) {
+bool SuperImageNeedsRebuilding(const FetcherConfig& fetcher_config,
+                               const CuttlefishConfig&) {
   bool has_default_build = false;
   bool has_system_build = false;
   for (const auto& file_iter : fetcher_config.get_cvd_files()) {
-    if (file_iter.second.source == cvd::FileSource::DEFAULT_BUILD) {
+    if (file_iter.second.source == FileSource::DEFAULT_BUILD) {
       has_default_build = true;
-    } else if (file_iter.second.source == cvd::FileSource::SYSTEM_BUILD) {
+    } else if (file_iter.second.source == FileSource::SYSTEM_BUILD) {
       has_system_build = true;
     }
   }
   return has_default_build && has_system_build;
 }
 
-bool RebuildSuperImage(const cvd::FetcherConfig& fetcher_config,
-                       const vsoc::CuttlefishConfig& config,
+bool RebuildSuperImage(const FetcherConfig& fetcher_config,
+                       const CuttlefishConfig& config,
                        const std::string& output_path) {
   std::string default_target_zip =
-      TargetFilesZip(fetcher_config, cvd::FileSource::DEFAULT_BUILD);
+      TargetFilesZip(fetcher_config, FileSource::DEFAULT_BUILD);
   if (default_target_zip == "") {
     LOG(ERROR) << "Unable to find default target zip file.";
     return false;
   }
   std::string system_target_zip =
-      TargetFilesZip(fetcher_config, cvd::FileSource::SYSTEM_BUILD);
+      TargetFilesZip(fetcher_config, FileSource::SYSTEM_BUILD);
   if (system_target_zip == "") {
     LOG(ERROR) << "Unable to find system target zip file.";
     return false;
@@ -282,3 +287,5 @@
   }
   return success;
 }
+
+} // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/super_image_mixer.h b/host/commands/assemble_cvd/super_image_mixer.h
index 1b8c420..91f2c13 100644
--- a/host/commands/assemble_cvd/super_image_mixer.h
+++ b/host/commands/assemble_cvd/super_image_mixer.h
@@ -16,8 +16,12 @@
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/config/fetcher_config.h"
 
-bool SuperImageNeedsRebuilding(const cvd::FetcherConfig& fetcher_config,
-                               const vsoc::CuttlefishConfig& config);
-bool RebuildSuperImage(const cvd::FetcherConfig& fetcher_config,
-                       const vsoc::CuttlefishConfig& config,
+namespace cuttlefish {
+
+bool SuperImageNeedsRebuilding(const FetcherConfig& fetcher_config,
+                               const CuttlefishConfig& config);
+bool RebuildSuperImage(const FetcherConfig& fetcher_config,
+                       const CuttlefishConfig& config,
                        const std::string& output_path);
+
+} // namespace cuttlefish
diff --git a/host/commands/bt_connector/Android.bp b/host/commands/bt_connector/Android.bp
new file mode 100644
index 0000000..d617eaa
--- /dev/null
+++ b/host/commands/bt_connector/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2021 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.
+
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "bt_connector",
+    srcs: [
+        "main.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libjsoncpp",
+        "liblog",
+        "libcuttlefish_utils",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_buildhost_only"]
+}
diff --git a/host/commands/bt_connector/OWNERS b/host/commands/bt_connector/OWNERS
new file mode 100644
index 0000000..e8a4a00
--- /dev/null
+++ b/host/commands/bt_connector/OWNERS
@@ -0,0 +1,2 @@
+include platform/system/bt:/OWNERS
+jeongik@google.com
\ No newline at end of file
diff --git a/host/commands/bt_connector/main.cpp b/host/commands/bt_connector/main.cpp
new file mode 100644
index 0000000..fc17b31
--- /dev/null
+++ b/host/commands/bt_connector/main.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <ios>
+#include <mutex>
+
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
+#include <thread>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/logging.h"
+
+// Copied from net/bluetooth/hci.h
+#define HCI_MAX_ACL_SIZE 1024
+#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
+
+// Include H4 header byte, and reserve more buffer size in the case of excess
+// packet.
+constexpr const size_t kBufferSize = (HCI_MAX_FRAME_SIZE + 1) * 2;
+
+DEFINE_int32(bt_in, -1, "A pipe for bt communication");
+DEFINE_int32(bt_out, -1, "A pipe for bt communication");
+DEFINE_int32(hci_port, -1, "A port for bt hci command");
+DEFINE_int32(link_port, -1, "A pipe for bt link layer command");
+DEFINE_int32(test_port, -1, "A pipe for rootcanal test channel");
+
+void openSocket(cuttlefish::SharedFD* fd, int port) {
+  static std::mutex mutex;
+  std::unique_lock<std::mutex> lock(mutex);
+  *fd = cuttlefish::SharedFD::SocketLocalClient(port, SOCK_STREAM);
+}
+
+int main(int argc, char** argv) {
+  cuttlefish::DefaultSubprocessLogging(argv);
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
+  auto bt_in = cuttlefish::SharedFD::Dup(FLAGS_bt_in);
+  if (!bt_in->IsOpen()) {
+    LOG(ERROR) << "Error dupping fd " << FLAGS_bt_in << ": "
+               << bt_in->StrError();
+    return 1;
+  }
+  close(FLAGS_bt_in);
+
+  auto bt_out = cuttlefish::SharedFD::Dup(FLAGS_bt_out);
+  if (!bt_out->IsOpen()) {
+    LOG(ERROR) << "Error dupping fd " << FLAGS_bt_out << ": "
+               << bt_out->StrError();
+    return 1;
+  }
+  close(FLAGS_bt_out);
+  cuttlefish::SharedFD sock;
+  openSocket(&sock, FLAGS_hci_port);
+
+  auto guest_to_host = std::thread([&]() {
+    while (true) {
+      char buf[kBufferSize];
+      auto read = bt_in->Read(buf, sizeof(buf));
+      while (cuttlefish::WriteAll(sock, buf, read) == -1) {
+        LOG(ERROR) << "failed to write to socket, retry.";
+        // Wait for the host process to be ready
+        sleep(1);
+        openSocket(&sock, FLAGS_hci_port);
+      }
+    }
+  });
+
+  auto host_to_guest = std::thread([&]() {
+    while (true) {
+      char buf[kBufferSize];
+      auto read = sock->Read(buf, sizeof(buf));
+      if (read == -1) {
+        LOG(ERROR) << "failed to read from socket, retry.";
+        // Wait for the host process to be ready
+        sleep(1);
+        openSocket(&sock, FLAGS_hci_port);
+        continue;
+      }
+      cuttlefish::WriteAll(bt_out, buf, read);
+    }
+  });
+  guest_to_host.join();
+  host_to_guest.join();
+}
diff --git a/host/commands/config_server/Android.bp b/host/commands/config_server/Android.bp
index fcf6d39..b567bd9 100644
--- a/host/commands/config_server/Android.bp
+++ b/host/commands/config_server/Android.bp
@@ -13,25 +13,28 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "config_server",
     srcs: [
         "main.cpp",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
+        "libjsoncpp",
         "liblog",
         "libcuttlefish_utils",
         "libcuttlefish_device_config",
+        "libcuttlefish_device_config_proto",
+        "libprotobuf-cpp-full"
     ],
     static_libs: [
         "libcuttlefish_host_config",
         "libgflags",
-        "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/config_server/main.cpp b/host/commands/config_server/main.cpp
index 6d1e7f8..9210842 100644
--- a/host/commands/config_server/main.cpp
+++ b/host/commands/config_server/main.cpp
@@ -16,40 +16,37 @@
 
 #include <common/libs/device_config/device_config.h>
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/fs/shared_fd.h"
-#include "host/libs/config/cuttlefish_config.h"
+#include "common/libs/utils/tee_logging.h"
+#include "host/libs/config/logging.h"
 
 DEFINE_int32(
     server_fd, -1,
     "File descriptor to an already created vsock server. Must be specified.");
 
 int main(int argc, char** argv) {
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  cuttlefish::DefaultSubprocessLogging(argv);
   google::ParseCommandLineFlags(&argc, &argv, true);
 
-  CHECK(vsoc::CuttlefishConfig::Get()) << "Could not open config";
+  auto device_config_helper = cuttlefish::DeviceConfigHelper::Get();
 
-  cvd::SharedFD server_fd = cvd::SharedFD::Dup(FLAGS_server_fd);
+  CHECK(device_config_helper) << "Could not open device config";
+
+  cuttlefish::SharedFD server_fd = cuttlefish::SharedFD::Dup(FLAGS_server_fd);
 
   CHECK(server_fd->IsOpen()) << "Inheriting logcat server: "
                              << server_fd->StrError();
 
-  auto device_config = cvd::DeviceConfig::Get();
-  if (!device_config) {
-    LOG(ERROR) << "Failed to obtain device configuration";
-    return -1;
-  }
-
   // Server loop
   while (true) {
-    auto conn = cvd::SharedFD::Accept(*server_fd);
-    LOG(INFO) << "Connection received on configuration server";
+    auto conn = cuttlefish::SharedFD::Accept(*server_fd);
+    LOG(DEBUG) << "Connection received on configuration server";
 
-    bool succeeded = device_config->SendRawData(conn);
+    bool succeeded = device_config_helper->SendDeviceConfig(conn);
     if (succeeded) {
-      LOG(INFO) << "Successfully sent device configuration";
+      LOG(DEBUG) << "Successfully sent device configuration";
     } else {
       LOG(ERROR) << "Failed to send the device configuration: "
                  << conn->StrError();
diff --git a/host/commands/console_forwarder/Android.bp b/host/commands/console_forwarder/Android.bp
index a090e98..230a0f7 100644
--- a/host/commands/console_forwarder/Android.bp
+++ b/host/commands/console_forwarder/Android.bp
@@ -13,23 +13,24 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "console_forwarder",
     srcs: [
         "main.cpp",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libbase",
+        "libjsoncpp",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
     ],
     static_libs: [
         "libcuttlefish_host_config",
-        "libjsoncpp",
         "libgflags",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/console_forwarder/main.cpp b/host/commands/console_forwarder/main.cpp
index 1d12b22..df5c9f7 100644
--- a/host/commands/console_forwarder/main.cpp
+++ b/host/commands/console_forwarder/main.cpp
@@ -14,18 +14,22 @@
  * limitations under the License.
  */
 
+#include <termios.h>
+#include <stdlib.h>
 #include <signal.h>
+#include <unistd.h>
 
 #include <deque>
 #include <thread>
 #include <vector>
 
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include <common/libs/fs/shared_fd.h>
 #include <common/libs/fs/shared_select.h>
 #include <host/libs/config/cuttlefish_config.h>
+#include <host/libs/config/logging.h>
 
 DEFINE_int32(console_in_fd,
              -1,
@@ -34,9 +38,11 @@
              -1,
              "File descriptor for the console's output channel");
 
-// Handles forwarding the serial console to a socket.
-// It receives the socket fd along with a couple of fds for the console (could
-// be the same fd twice if, for example a socket_pair were used).
+namespace cuttlefish {
+
+// Handles forwarding the serial console to a pseudo-terminal (PTY)
+// It receives a couple of fds for the console (could be the same fd twice if,
+// for example a socket_pair were used).
 // Data available in the console's output needs to be read immediately to avoid
 // the having the VMM blocked on writes to the pipe. To achieve this one thread
 // takes care of (and only of) all read calls (from console output and from the
@@ -45,35 +51,73 @@
 // protected by a mutex.
 class ConsoleForwarder {
  public:
-  ConsoleForwarder(cvd::SharedFD socket,
-                   cvd::SharedFD console_in,
-                   cvd::SharedFD console_out) : socket_(socket),
-                                                console_in_(console_in),
-                                                console_out_(console_out) {}
+  ConsoleForwarder(std::string console_path, SharedFD console_in,
+                   SharedFD console_out, SharedFD console_log)
+      : console_path_(console_path),
+        console_in_(console_in),
+        console_out_(console_out),
+        console_log_(console_log) {}
   [[noreturn]] void StartServer() {
-    // Create a new thread to handle writes to the console and to the any client
-    // connected to the socket.
+    // Create a new thread to handle writes to the console
     writer_thread_ = std::thread([this]() { WriteLoop(); });
     // Use the calling thread (likely the process' main thread) to handle
     // reading the console's output and input from the client.
     ReadLoop();
   }
  private:
-  void EnqueueWrite(std::vector<char> buffer, cvd::SharedFD fd) {
+  SharedFD OpenPTY() {
+    // Remove any stale symlink to a pts device
+    auto ret = unlink(console_path_.c_str());
+    CHECK(!(ret < 0 && errno != ENOENT))
+        << "Failed to unlink " << console_path_ << ": " << strerror(errno);
+
+    auto pty = posix_openpt(O_RDWR | O_NOCTTY | O_NONBLOCK);
+    CHECK(pty >= 0) << "Failed to open a PTY: " << strerror(errno);
+
+    grantpt(pty);
+    unlockpt(pty);
+
+    // Disable all echo modes on the PTY
+    struct termios termios;
+    CHECK(tcgetattr(pty, &termios) >= 0)
+        << "Failed to get terminal control: " << strerror(errno);
+
+    termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+    termios.c_oflag &= ~(ONLCR);
+    CHECK(tcsetattr(pty, TCSANOW, &termios) >= 0)
+        << "Failed to set terminal control: " << strerror(errno);
+
+    auto pty_dev_name = ptsname(pty);
+    CHECK(pty_dev_name != nullptr)
+        << "Failed to obtain PTY device name: " << strerror(errno);
+
+    CHECK(symlink(pty_dev_name, console_path_.c_str()) >= 0)
+        << "Failed to create symlink to " << pty_dev_name << " at "
+        << console_path_ << ": " << strerror(errno);
+
+    auto pty_shared_fd = SharedFD::Dup(pty);
+    close(pty);
+    CHECK(pty_shared_fd->IsOpen())
+        << "Error dupping fd " << pty << ": " << pty_shared_fd->StrError();
+
+    return pty_shared_fd;
+  }
+
+  void EnqueueWrite(std::shared_ptr<std::vector<char>> buf_ptr, SharedFD fd) {
     std::lock_guard<std::mutex> lock(write_queue_mutex_);
-    write_queue_.emplace_back(fd, std::move(buffer));
+    write_queue_.emplace_back(fd, buf_ptr);
     condvar_.notify_one();
   }
 
   [[noreturn]] void WriteLoop() {
     while (true) {
       while (!write_queue_.empty()) {
-        std::vector<char> buffer;
-        cvd::SharedFD fd;
+        std::shared_ptr<std::vector<char>> buf_ptr;
+        SharedFD fd;
         {
           std::lock_guard<std::mutex> lock(write_queue_mutex_);
           auto& front = write_queue_.front();
-          buffer = std::move(front.second);
+          buf_ptr = front.second;
           fd = front.first;
           write_queue_.pop_front();
         }
@@ -81,12 +125,16 @@
         // mutex lock should NOT be held while writing to avoid blocking the
         // other thread.
         ssize_t bytes_written = 0;
-        ssize_t bytes_to_write = buffer.size();
+        ssize_t bytes_to_write = buf_ptr->size();
         while (bytes_to_write > 0) {
           bytes_written =
-              fd->Write(buffer.data() + bytes_written, bytes_to_write);
+              fd->Write(buf_ptr->data() + bytes_written, bytes_to_write);
           if (bytes_written < 0) {
-            LOG(ERROR) << "Error writing to fd: " << fd->StrError();
+            // It is expected for writes to the PTY to fail if nothing is connected
+            if(fd->GetErrno() != EAGAIN) {
+              LOG(ERROR) << "Error writing to fd: " << fd->StrError();
+            }
+
             // Don't try to write from this buffer anymore, error handling will
             // be done on the reading thread (failed client will be
             // disconnected, on serial console failure this process will abort).
@@ -106,116 +154,95 @@
   }
 
   [[noreturn]] void ReadLoop() {
-    cvd::SharedFD client_fd;
+    SharedFD client_fd;
     while (true) {
-      cvd::SharedFDSet read_set;
-      if (client_fd->IsOpen()) {
-        read_set.Set(client_fd);
-      } else {
-        read_set.Set(socket_);
+      if (!client_fd->IsOpen()) {
+        client_fd = OpenPTY();
       }
+
+      SharedFDSet read_set;
       read_set.Set(console_out_);
-      cvd::Select(&read_set, nullptr, nullptr, nullptr);
+      read_set.Set(client_fd);
+
+      Select(&read_set, nullptr, nullptr, nullptr);
       if (read_set.IsSet(console_out_)) {
-        std::vector<char> buffer(4096);
-        auto bytes_read = console_out_->Read(buffer.data(), buffer.size());
-        if (bytes_read <= 0) {
-          LOG(ERROR) << "Error reading from console output: "
-                     << console_out_->StrError();
-          // This is likely unrecoverable, so exit here
-          std::exit(-4);
-        }
-        buffer.resize(bytes_read);
+        std::shared_ptr<std::vector<char>> buf_ptr = std::make_shared<std::vector<char>>(4096);
+        auto bytes_read = console_out_->Read(buf_ptr->data(), buf_ptr->size());
+        // This is likely unrecoverable, so exit here
+        CHECK(bytes_read > 0) << "Error reading from console output: "
+                              << console_out_->StrError();
+        buf_ptr->resize(bytes_read);
+        EnqueueWrite(buf_ptr, console_log_);
         if (client_fd->IsOpen()) {
-          EnqueueWrite(std::move(buffer), client_fd);
-        }
-      }
-      if (read_set.IsSet(socket_)) {
-        // socket_ will only be included in the select call (and therefore only
-        // present in the read set) if there is no client connected, so this
-        // assignment is safe.
-        client_fd = cvd::SharedFD::Accept(*socket_);
-        if (!client_fd->IsOpen()) {
-          LOG(ERROR) << "Error accepting connection on socket: "
-                     << client_fd->StrError();
+          EnqueueWrite(buf_ptr, client_fd);
         }
       }
       if (read_set.IsSet(client_fd)) {
-        std::vector<char> buffer(4096);
-        auto bytes_read = client_fd->Read(buffer.data(), buffer.size());
+        std::shared_ptr<std::vector<char>> buf_ptr = std::make_shared<std::vector<char>>(4096);
+        auto bytes_read = client_fd->Read(buf_ptr->data(), buf_ptr->size());
         if (bytes_read <= 0) {
+          // If this happens, it's usually because the PTY controller went away
+          // e.g. the user closed minicom, or killed screen, or closed kgdb. In
+          // such a case, we will just re-create the PTY
           LOG(ERROR) << "Error reading from client fd: "
                      << client_fd->StrError();
-          client_fd->Close(); // ignore errors here
+          client_fd->Close();
         } else {
-          buffer.resize(bytes_read);
-          EnqueueWrite(std::move(buffer), console_in_);
+          buf_ptr->resize(bytes_read);
+          EnqueueWrite(buf_ptr, console_in_);
         }
       }
     }
   }
 
-  cvd::SharedFD socket_;
-  cvd::SharedFD console_in_;
-  cvd::SharedFD console_out_;
+  std::string console_path_;
+  SharedFD console_in_;
+  SharedFD console_out_;
+  SharedFD console_log_;
   std::thread writer_thread_;
   std::mutex write_queue_mutex_;
   std::condition_variable condvar_;
-  std::deque<std::pair<cvd::SharedFD, std::vector<char>>> write_queue_;
+  std::deque<std::pair<SharedFD, std::shared_ptr<std::vector<char>>>>
+      write_queue_;
 };
 
-int main(int argc, char** argv) {
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
+int ConsoleForwarderMain(int argc, char** argv) {
+  DefaultSubprocessLogging(argv);
   ::gflags::ParseCommandLineFlags(&argc, &argv, true);
 
-  if (FLAGS_console_in_fd < 0 || FLAGS_console_out_fd < 0) {
-    LOG(ERROR) << "Invalid file descriptors: " << FLAGS_console_in_fd << ", "
-               << FLAGS_console_out_fd;
-    return -1;
-  }
+  CHECK(!(FLAGS_console_in_fd < 0 || FLAGS_console_out_fd < 0))
+      << "Invalid file descriptors: " << FLAGS_console_in_fd << ", "
+      << FLAGS_console_out_fd;
 
-  auto console_in = cvd::SharedFD::Dup(FLAGS_console_in_fd);
-  close(FLAGS_console_in_fd);
-  if (!console_in->IsOpen()) {
-    LOG(ERROR) << "Error dupping fd " << FLAGS_console_in_fd << ": "
-               << console_in->StrError();
-    return -2;
-  }
+  auto console_in = SharedFD::Dup(FLAGS_console_in_fd);
+  CHECK(console_in->IsOpen()) << "Error dupping fd " << FLAGS_console_in_fd
+                              << ": " << console_in->StrError();
   close(FLAGS_console_in_fd);
 
-  auto console_out = cvd::SharedFD::Dup(FLAGS_console_out_fd);
+  auto console_out = SharedFD::Dup(FLAGS_console_out_fd);
+  CHECK(console_out->IsOpen()) << "Error dupping fd " << FLAGS_console_out_fd
+                               << ": " << console_out->StrError();
   close(FLAGS_console_out_fd);
-  if (!console_out->IsOpen()) {
-    LOG(ERROR) << "Error dupping fd " << FLAGS_console_out_fd << ": "
-               << console_out->StrError();
-    return -2;
-  }
 
-  auto config = vsoc::CuttlefishConfig::Get();
-  if (!config) {
-    LOG(ERROR) << "Unable to get config object";
-    return -3;
-  }
+  auto config = CuttlefishConfig::Get();
+  CHECK(config) << "Unable to get config object";
 
   auto instance = config->ForDefaultInstance();
-  auto console_socket_name = instance.console_path();
-  auto socket = cvd::SharedFD::SocketLocalServer(console_socket_name.c_str(),
-                                                 false,
-                                                 SOCK_STREAM,
-                                                 0600);
-  if (!socket->IsOpen()) {
-    LOG(ERROR) << "Failed to create console socket at " << console_socket_name
-               << ": " << socket->StrError();
-    return -5;
-  }
-
-  ConsoleForwarder console_forwarder(socket, console_in, console_out);
+  auto console_path = instance.console_path();
+  auto console_log = instance.PerInstancePath("console_log");
+  auto console_log_fd =
+      SharedFD::Open(console_log.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0666);
+  ConsoleForwarder console_forwarder(console_path, console_in, console_out, console_log_fd);
 
   // Don't get a SIGPIPE from the clients
-  if (sigaction(SIGPIPE, nullptr, nullptr) != 0) {
-    LOG(FATAL) << "Failed to set SIGPIPE to be ignored: " << strerror(errno);
-    return -6;
-  }
+  CHECK(sigaction(SIGPIPE, nullptr, nullptr) == 0)
+      << "Failed to set SIGPIPE to be ignored: " << strerror(errno);
 
   console_forwarder.StartServer();
 }
+
+}  // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::ConsoleForwarderMain(argc, argv);
+}
diff --git a/host/commands/cvd_host_bugreport/Android.bp b/host/commands/cvd_host_bugreport/Android.bp
new file mode 100644
index 0000000..4f6aeda
--- /dev/null
+++ b/host/commands/cvd_host_bugreport/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2018 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "cvd_host_bugreport",
+    srcs: [
+        "main.cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libjsoncpp",
+        "libziparchive",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libcuttlefish_vm_manager",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+}
diff --git a/host/commands/cvd_host_bugreport/main.cc b/host/commands/cvd_host_bugreport/main.cc
new file mode 100644
index 0000000..c920e7c
--- /dev/null
+++ b/host/commands/cvd_host_bugreport/main.cc
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <stdio.h>
+#include <fstream>
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/fs/shared_select.h"
+#include "common/libs/utils/files.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "ziparchive/zip_writer.h"
+
+DEFINE_string(output, "host_bugreport.zip", "Where to write the output");
+
+namespace cuttlefish {
+namespace {
+
+void SaveFile(ZipWriter& writer, const std::string& zip_path,
+              const std::string& file_path) {
+  writer.StartEntry(zip_path, ZipWriter::kCompress | ZipWriter::kAlign32);
+  std::fstream file(file_path, std::fstream::in | std::fstream::binary);
+  do {
+    char data[1024 * 10];
+    file.read(data, sizeof(data));
+    writer.WriteBytes(data, file.gcount());
+  } while (file);
+  writer.FinishEntry();
+  if (file.bad()) {
+    LOG(ERROR) << "Error in logging " << file_path << " to " << zip_path;
+  }
+}
+
+int CvdHostBugreportMain(int argc, char** argv) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  auto config = CuttlefishConfig::Get();
+  CHECK(config) << "Unable to find the config";
+
+  auto out_path = FLAGS_output.c_str();
+  std::unique_ptr<FILE, decltype(&fclose)> out(fopen(out_path, "wb"), &fclose);
+  ZipWriter writer(out.get());
+
+  auto save = [&writer, config](const std::string& path) {
+    SaveFile(writer, "cuttlefish_assembly/" + path, config->AssemblyPath(path));
+  };
+  save("assemble_cvd.log");
+  save("cuttlefish_config.json");
+
+  for (const auto& instance : config->Instances()) {
+    auto save = [&writer, instance](const std::string& path) {
+      const auto& zip_name = instance.instance_name() + "/" + path;
+      const auto& file_name = instance.PerInstancePath(path.c_str());
+      SaveFile(writer, zip_name, file_name);
+    };
+    save("cuttlefish_config.json");
+    save("disk_config.txt");
+    save("kernel.log");
+    save("launcher.log");
+    save("logcat");
+    save("metrics.log");
+    auto tombstones = DirectoryContents(instance.PerInstancePath("tombstones"));
+    for (const auto& tombstone : tombstones) {
+      if (tombstone == "." || tombstone == "..") {
+        continue;
+      }
+      save("tombstones/" + tombstone);
+    }
+    auto recordings = DirectoryContents(instance.PerInstancePath("recording"));
+    for (const auto& recording : recordings) {
+      if (recording == "." || recording == "..") {
+        continue;
+      }
+      save("recording/" + recording);
+    }
+  }
+
+  writer.Finish();
+
+  LOG(INFO) << "Saved to \"" << FLAGS_output << "\"";
+
+  return 0;
+}
+
+}  // namespace
+}  // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::CvdHostBugreportMain(argc, argv);
+}
diff --git a/host/commands/cvd_status/Android.bp b/host/commands/cvd_status/Android.bp
index 3b1cbbc..ae48d19 100644
--- a/host/commands/cvd_status/Android.bp
+++ b/host/commands/cvd_status/Android.bp
@@ -13,25 +13,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "cvd_status",
     srcs: [
         "cvd_status.cc",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
+        "libjsoncpp",
     ],
     static_libs: [
         "libcuttlefish_host_config",
         "libcuttlefish_vm_manager",
-        "libjsoncpp",
         "libgflags",
-        "libxml2",
     ],
-    defaults: ["cuttlefish_host_only", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
 }
diff --git a/host/commands/cvd_status/cvd_status.cc b/host/commands/cvd_status/cvd_status.cc
index 5b0513c..81436d4 100644
--- a/host/commands/cvd_status/cvd_status.cc
+++ b/host/commands/cvd_status/cvd_status.cc
@@ -36,7 +36,7 @@
 #include <vector>
 
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/fs/shared_select.h"
@@ -53,7 +53,7 @@
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   google::ParseCommandLineFlags(&argc, &argv, true);
 
-  auto config = vsoc::CuttlefishConfig::Get();
+  auto config = cuttlefish::CuttlefishConfig::Get();
   if (!config) {
     LOG(ERROR) << "Failed to obtain config object";
     return 1;
@@ -65,14 +65,14 @@
     LOG(ERROR) << "No path to launcher monitor found";
     return 2;
   }
-  auto monitor_socket = cvd::SharedFD::SocketLocalClient(monitor_path.c_str(),
-                                                         false, SOCK_STREAM);
+  auto monitor_socket = cuttlefish::SharedFD::SocketLocalClient(
+      monitor_path.c_str(), false, SOCK_STREAM, FLAGS_wait_for_launcher);
   if (!monitor_socket->IsOpen()) {
     LOG(ERROR) << "Unable to connect to launcher monitor at " << monitor_path
                << ": " << monitor_socket->StrError();
     return 3;
   }
-  auto request = cvd::LauncherAction::kStatus;
+  auto request = cuttlefish::LauncherAction::kStatus;
   auto bytes_sent = monitor_socket->Send(&request, sizeof(request), 0);
   if (bytes_sent < 0) {
     LOG(ERROR) << "Error sending launcher monitor the status command: "
@@ -80,10 +80,10 @@
     return 4;
   }
   // Perform a select with a timeout to guard against launcher hanging
-  cvd::SharedFDSet read_set;
+  cuttlefish::SharedFDSet read_set;
   read_set.Set(monitor_socket);
   struct timeval timeout = {FLAGS_wait_for_launcher, 0};
-  int selected = cvd::Select(&read_set, nullptr, nullptr,
+  int selected = cuttlefish::Select(&read_set, nullptr, nullptr,
                              FLAGS_wait_for_launcher <= 0 ? nullptr : &timeout);
   if (selected < 0){
     LOG(ERROR) << "Failed communication with the launcher monitor: "
@@ -94,14 +94,14 @@
     LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
     return 6;
   }
-  cvd::LauncherResponse response;
+  cuttlefish::LauncherResponse response;
   auto bytes_recv = monitor_socket->Recv(&response, sizeof(response), 0);
   if (bytes_recv < 0) {
     LOG(ERROR) << "Error receiving response from launcher monitor: "
                << monitor_socket->StrError();
     return 7;
   }
-  if (response != cvd::LauncherResponse::kSuccess) {
+  if (response != cuttlefish::LauncherResponse::kSuccess) {
     LOG(ERROR) << "Received '" << static_cast<char>(response)
                << "' response from launcher monitor";
     return 8;
diff --git a/host/commands/fetcher/Android.bp b/host/commands/fetcher/Android.bp
index 1aaf04f..fdb97ec 100644
--- a/host/commands/fetcher/Android.bp
+++ b/host/commands/fetcher/Android.bp
@@ -13,7 +13,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "fetch_cvd",
     srcs: [
         "build_api.cc",
@@ -22,22 +26,38 @@
         "fetch_cvd.cc",
         "install_zip.cc",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
-    stl: "libc++_static",
     static_libs: [
-        "libbase",
         "libcuttlefish_host_config",
-        "libcuttlefish_fs",
-        "libcuttlefish_utils",
-        "libcurl",
-        "libcrypto",
         "libgflags",
-        "liblog",
-        "libssl",
-        "libz",
-        "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only"],
+    target: {
+        host: {
+            stl: "libc++_static",
+            static_libs: [
+                "libbase",
+                "libcuttlefish_fs",
+                "libcuttlefish_utils",
+                "libcurl",
+                "libcrypto",
+                "liblog",
+                "libssl",
+                "libz",
+                "libjsoncpp",
+            ],
+        },
+        android: {
+            shared_libs: [
+                "libbase",
+                "libcuttlefish_fs",
+                "libcuttlefish_utils",
+                "libcurl",
+                "libcrypto",
+                "liblog",
+                "libssl",
+                "libz",
+                "libjsoncpp",
+            ],
+        },
+    },
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/fetcher/build_api.cc b/host/commands/fetcher/build_api.cc
index 1f3d81b..69229f0 100644
--- a/host/commands/fetcher/build_api.cc
+++ b/host/commands/fetcher/build_api.cc
@@ -24,10 +24,12 @@
 #include <thread>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
+#include "common/libs/utils/environment.h"
 #include "common/libs/utils/files.h"
 
+namespace cuttlefish {
 namespace {
 
 const std::string BUILD_API =
@@ -72,6 +74,12 @@
   return out;
 }
 
+DirectoryBuild::DirectoryBuild(const std::vector<std::string>& paths,
+                               const std::string& target)
+    : paths(paths), target(target), id("eng") {
+  product = StringFromEnv("TARGET_PRODUCT", "");
+}
+
 BuildApi::BuildApi(std::unique_ptr<CredentialSource> credential_source)
     : credential_source(std::move(credential_source)) {}
 
@@ -110,6 +118,15 @@
   return response_json["buildAttemptStatus"].asString();
 }
 
+std::string BuildApi::ProductName(const DeviceBuild& build) {
+  std::string url = BUILD_API + "/builds/" + build.id + "/" + build.target;
+  auto response_json = curl.DownloadToJson(url, Headers());
+  CHECK(!response_json.isMember("error")) << "Error fetching the status of "
+      << "build " << build << ". Response was " << response_json;
+  CHECK(response_json.isMember("target")) << "Build was missing target field.";
+  return response_json["target"]["product"].asString();
+}
+
 std::vector<Artifact> BuildApi::Artifacts(const DeviceBuild& build) {
   std::string url = BUILD_API + "/builds/" + build.id + "/" + build.target
       + "/attempts/latest/artifacts?maxResults=1000";
@@ -147,8 +164,21 @@
 bool BuildApi::ArtifactToFile(const DeviceBuild& build,
                               const std::string& artifact,
                               const std::string& path) {
-  std::string url = BUILD_API + "/builds/" + build.id + "/" + build.target
-      + "/attempts/latest/artifacts/" + artifact + "?alt=media";
+  std::string url;
+  if (credential_source) {
+    url = BUILD_API + "/builds/" + build.id + "/" + build.target +
+          "/attempts/latest/artifacts/" + artifact + "?alt=media";
+  } else {
+    std::string download_url_endpoint =
+        BUILD_API + "/builds/" + build.id + "/" + build.target +
+        "/attempts/latest/artifacts/" + artifact + "/url";
+    auto download_url_json = curl.DownloadToJson(download_url_endpoint);
+    if (!download_url_json.isMember("signedUrl")) {
+      LOG(ERROR) << "URL endpoint did not have json path";
+      return false;
+    }
+    url = download_url_json["signedUrl"].asString();
+  }
   return curl.DownloadToFile(url, path, Headers());
 }
 
@@ -157,7 +187,7 @@
                               const std::string& destination) {
   for (const auto& path : build.paths) {
     auto source = path + "/" + artifact;
-    if (!cvd::FileExists(source)) {
+    if (!FileExists(source)) {
       continue;
     }
     unlink(destination.c_str());
@@ -213,5 +243,8 @@
     status = build_api->BuildStatus(proposed_build);
   }
   LOG(INFO) << "Status for build " << proposed_build << " is " << status;
+  proposed_build.product = build_api->ProductName(proposed_build);
   return proposed_build;
 }
+
+} // namespace cuttlefish
diff --git a/host/commands/fetcher/build_api.h b/host/commands/fetcher/build_api.h
index 54bbd72..505ad4b 100644
--- a/host/commands/fetcher/build_api.h
+++ b/host/commands/fetcher/build_api.h
@@ -25,6 +25,8 @@
 #include "credential_source.h"
 #include "curl_wrapper.h"
 
+namespace cuttlefish {
+
 class Artifact {
   std::string name;
   size_t size;
@@ -56,6 +58,7 @@
 
   std::string id;
   std::string target;
+  std::string product;
 };
 
 std::ostream& operator<<(std::ostream&, const DeviceBuild&);
@@ -63,12 +66,12 @@
 struct DirectoryBuild {
   // TODO(schuffelen): Support local builds other than "eng"
   DirectoryBuild(const std::vector<std::string>& paths,
-                 const std::string& target)
-      : paths(paths), target(target), id("eng") {}
+                 const std::string& target);
 
   std::vector<std::string> paths;
   std::string target;
   std::string id;
+  std::string product;
 };
 
 std::ostream& operator<<(std::ostream&, const DirectoryBuild&);
@@ -91,6 +94,8 @@
 
   std::string BuildStatus(const DeviceBuild&);
 
+  std::string ProductName(const DeviceBuild&);
+
   std::vector<Artifact> Artifacts(const DeviceBuild&);
 
   bool ArtifactToFile(const DeviceBuild& build, const std::string& artifact,
@@ -116,3 +121,5 @@
 Build ArgumentToBuild(BuildApi* api, const std::string& arg,
                       const std::string& default_build_target,
                       const std::chrono::seconds& retry_period);
+
+} // namespace cuttlefish
diff --git a/host/commands/fetcher/credential_source.cc b/host/commands/fetcher/credential_source.cc
index 89d6b14..0144e2d 100644
--- a/host/commands/fetcher/credential_source.cc
+++ b/host/commands/fetcher/credential_source.cc
@@ -15,8 +15,9 @@
 
 #include "credential_source.h"
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
+namespace cuttlefish {
 namespace {
 
 std::chrono::steady_clock::duration REFRESH_WINDOW =
@@ -24,7 +25,7 @@
 std::string REFRESH_URL = "http://metadata.google.internal/computeMetadata/"
     "v1/instance/service-accounts/default/token";
 
-}
+} // namespace
 
 GceMetadataCredentialSource::GceMetadataCredentialSource() {
   latest_credential = "";
@@ -72,3 +73,5 @@
     const std::string& credential) {
   return std::unique_ptr<CredentialSource>(new FixedCredentialSource(credential));
 }
+
+} // namespace cuttlefish
diff --git a/host/commands/fetcher/credential_source.h b/host/commands/fetcher/credential_source.h
index fa82eab..78ec51a 100644
--- a/host/commands/fetcher/credential_source.h
+++ b/host/commands/fetcher/credential_source.h
@@ -20,6 +20,8 @@
 
 #include "curl_wrapper.h"
 
+namespace cuttlefish {
+
 class CredentialSource {
 public:
   virtual ~CredentialSource() = default;
@@ -50,3 +52,5 @@
 
   static std::unique_ptr<CredentialSource> make(const std::string& credential);
 };
+
+}
diff --git a/host/commands/fetcher/curl_wrapper.cc b/host/commands/fetcher/curl_wrapper.cc
index 472963a..c32f4ce 100644
--- a/host/commands/fetcher/curl_wrapper.cc
+++ b/host/commands/fetcher/curl_wrapper.cc
@@ -19,11 +19,12 @@
 #include <string>
 #include <stdio.h>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include <curl/curl.h>
 #include <json/json.h>
 
+namespace cuttlefish {
 namespace {
 
 size_t file_write_callback(char *ptr, size_t, size_t nmemb, void *userdata) {
@@ -145,12 +146,16 @@
 Json::Value CurlWrapper::DownloadToJson(const std::string& url,
                                         const std::vector<std::string>& headers) {
   std::string contents = DownloadToString(url, headers);
-  Json::Reader reader;
+  Json::CharReaderBuilder builder;
+  std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
   Json::Value json;
-  if (!reader.parse(contents, json)) {
-    LOG(ERROR) << "Could not parse json: " << reader.getFormattedErrorMessages();
+  std::string errorMessage;
+  if (!reader->parse(&*contents.begin(), &*contents.end(), &json, &errorMessage)) {
+    LOG(ERROR) << "Could not parse json: " << errorMessage;
     json["error"] = "Failed to parse json.";
     json["response"] = contents;
   }
   return json;
 }
+
+}
diff --git a/host/commands/fetcher/curl_wrapper.h b/host/commands/fetcher/curl_wrapper.h
index 5a5ba9c..6d3a2cb 100644
--- a/host/commands/fetcher/curl_wrapper.h
+++ b/host/commands/fetcher/curl_wrapper.h
@@ -20,6 +20,8 @@
 #include <curl/curl.h>
 #include <json/json.h>
 
+namespace cuttlefish {
+
 class CurlWrapper {
   CURL* curl;
 public:
@@ -39,3 +41,5 @@
   Json::Value DownloadToJson(const std::string& url,
                              const std::vector<std::string>& headers);
 };
+
+}
diff --git a/host/commands/fetcher/fetch_cvd.cc b/host/commands/fetcher/fetch_cvd.cc
index 8a15686..b84fbba 100644
--- a/host/commands/fetcher/fetch_cvd.cc
+++ b/host/commands/fetcher/fetch_cvd.cc
@@ -20,8 +20,9 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "android-base/logging.h"
+#include "android-base/strings.h"
 #include "gflags/gflags.h"
-#include <glog/logging.h>
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/archive.h"
@@ -37,14 +38,16 @@
 namespace {
 
 const std::string DEFAULT_BRANCH = "aosp-master";
-const std::string DEFAULT_BUILD_TARGET = "aosp_cf_x86_phone-userdebug";
-
+const std::string DEFAULT_BUILD_TARGET = "aosp_cf_x86_64_phone-userdebug";
 }
 
+using cuttlefish::CurrentDirectory;
+
 DEFINE_string(default_build, DEFAULT_BRANCH + "/" + DEFAULT_BUILD_TARGET,
               "source for the cuttlefish build to use (vendor.img + host)");
 DEFINE_string(system_build, "", "source for system.img and product.img");
 DEFINE_string(kernel_build, "", "source for the kernel or gki target");
+DEFINE_string(bootloader_build, "", "source for the bootloader target");
 DEFINE_string(otatools_build, "", "source for the host ota tools");
 
 DEFINE_bool(download_img_zip, true, "Whether to fetch the -img-*.zip file.");
@@ -52,12 +55,13 @@
                                               "-target_files-*.zip file.");
 
 DEFINE_string(credential_source, "", "Build API credential source");
-DEFINE_string(directory, cvd::CurrentDirectory(), "Target directory to fetch "
-                                                  "files into");
+DEFINE_string(directory, CurrentDirectory(), "Target directory to fetch "
+                                             "files into");
 DEFINE_bool(run_next_stage, false, "Continue running the device through the next stage.");
 DEFINE_string(wait_retry_period, "20", "Retry period for pending builds given "
                                        "in seconds. Set to 0 to not wait.");
 
+namespace cuttlefish {
 namespace {
 
 const std::string HOST_TOOLS = "cvd-host_package.tar.gz";
@@ -72,13 +76,9 @@
 std::string TargetBuildZipFromArtifacts(
     const Build& build, const std::string& name,
     const std::vector<Artifact>& artifacts) {
-  std::string target = std::visit([](auto&& arg) { return arg.target; }, build);
-  size_t dash_pos = target.find('-');
-  if (dash_pos != std::string::npos) {
-    target.replace(dash_pos, target.size() - dash_pos, "");
-  }
+  std::string product = std::visit([](auto&& arg) { return arg.product; }, build);
   auto id = std::visit([](auto&& arg) { return arg.id; }, build);
-  auto match = target + "-" + name + "-" + id;
+  auto match = product + "-" + name + "-" + id;
   for (const auto& artifact : artifacts) {
     if (artifact.Name().find(match) != std::string::npos) {
       return artifact.Name();
@@ -159,7 +159,7 @@
     return {};
   }
 
-  cvd::Archive archive(local_path);
+  Archive archive(local_path);
   if (!archive.ExtractAll(target_directory)) {
     LOG(ERROR) << "Could not extract " << local_path;
     return {};
@@ -196,11 +196,11 @@
   }
 
   std::string otatools_dir = target_directory + OTA_TOOLS_DIR;
-  if (!cvd::DirectoryExists(otatools_dir) && mkdir(otatools_dir.c_str(), 0777) != 0) {
+  if (!DirectoryExists(otatools_dir) && mkdir(otatools_dir.c_str(), 0777) != 0) {
     LOG(ERROR) << "Could not create " << otatools_dir;
     return {};
   }
-  cvd::Archive archive(local_path);
+  Archive archive(local_path);
   if (!archive.ExtractAll(otatools_dir)) {
     LOG(ERROR) << "Could not extract " << local_path;
     return {};
@@ -213,14 +213,24 @@
   return files;
 }
 
-void AddFilesToConfig(cvd::FileSource purpose, const Build& build,
-                      const std::vector<std::string>& paths, cvd::FetcherConfig* config,
+void AddFilesToConfig(FileSource purpose, const Build& build,
+                      const std::vector<std::string>& paths,
+                      FetcherConfig* config,
+                      const std::string& directory_prefix,
                       bool override_entry = false) {
   for (const std::string& path : paths) {
+    std::string_view local_path(path);
+    if (!android::base::ConsumePrefix(&local_path, directory_prefix)) {
+      LOG(ERROR) << "Failed to remove prefix " << directory_prefix << " from "
+                 << local_path;
+    }
+    while (android::base::StartsWith(local_path, "/")) {
+      android::base::ConsumePrefix(&local_path, "/");
+    }
     // TODO(schuffelen): Do better for local builds here.
     auto id = std::visit([](auto&& arg) { return arg.id; }, build);
     auto target = std::visit([](auto&& arg) { return arg.target; }, build);
-    cvd::CvdFile file(purpose, id, target, path);
+    CvdFile file(purpose, id, target, std::string(local_path));
     bool added = config->add_cvd_file(file, override_entry);
     if (!added) {
       LOG(ERROR) << "Duplicate file " << file;
@@ -241,18 +251,19 @@
 
 } // namespace
 
-int main(int argc, char** argv) {
+int FetchCvdMain(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   gflags::SetUsageMessage(USAGE_MESSAGE);
   gflags::ParseCommandLineFlags(&argc, &argv, true);
 
-  cvd::FetcherConfig config;
+  FetcherConfig config;
   config.RecordFlags();
 
-  std::string target_dir = cvd::AbsolutePath(FLAGS_directory);
-  if (!cvd::DirectoryExists(target_dir) && mkdir(target_dir.c_str(), 0777) != 0) {
+  std::string target_dir = AbsolutePath(FLAGS_directory);
+  if (!DirectoryExists(target_dir) && mkdir(target_dir.c_str(), 0777) != 0) {
     LOG(FATAL) << "Could not create " << target_dir;
   }
+  std::string target_dir_slash = target_dir;
   std::chrono::seconds retry_period(std::stoi(FLAGS_wait_retry_period));
 
   curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -274,7 +285,8 @@
     if (host_package_files.empty()) {
       LOG(FATAL) << "Could not download host package for " << default_build;
     }
-    AddFilesToConfig(cvd::FileSource::DEFAULT_BUILD, default_build, host_package_files, &config);
+    AddFilesToConfig(FileSource::DEFAULT_BUILD, default_build,
+                     host_package_files, &config, target_dir);
 
     if (FLAGS_system_build != "" || FLAGS_kernel_build != "" || FLAGS_otatools_build != "") {
       auto ota_build = default_build;
@@ -287,7 +299,8 @@
       if (ota_tools_files.empty()) {
         LOG(FATAL) << "Could not download ota tools for " << ota_build;
       }
-      AddFilesToConfig(cvd::FileSource::DEFAULT_BUILD, default_build, ota_tools_files, &config);
+      AddFilesToConfig(FileSource::DEFAULT_BUILD, default_build,
+                       ota_tools_files, &config, target_dir);
     }
     if (FLAGS_download_img_zip) {
       std::vector<std::string> image_files =
@@ -299,7 +312,8 @@
       for (auto& file : image_files) {
         LOG(INFO) << file;
       }
-      AddFilesToConfig(cvd::FileSource::DEFAULT_BUILD, default_build, image_files, &config);
+      AddFilesToConfig(FileSource::DEFAULT_BUILD, default_build, image_files,
+                       &config, target_dir);
     }
     if (FLAGS_system_build != "" || FLAGS_download_target_files_zip) {
       std::string default_target_dir = target_dir + "/default";
@@ -312,7 +326,8 @@
         LOG(FATAL) << "Could not download target files for " << default_build;
       }
       LOG(INFO) << "Adding target files for default build";
-      AddFilesToConfig(cvd::FileSource::DEFAULT_BUILD, default_build, target_files, &config);
+      AddFilesToConfig(FileSource::DEFAULT_BUILD, default_build, target_files,
+                       &config, target_dir);
     }
 
     if (FLAGS_system_build != "") {
@@ -322,16 +337,17 @@
       bool system_in_img_zip = true;
       if (FLAGS_download_img_zip) {
         std::vector<std::string> image_files =
-            download_images(&build_api, system_build, target_dir, {"system.img"});
+            download_images(&build_api, system_build, target_dir,
+                            {"system.img", "product.img"});
         if (image_files.empty()) {
           LOG(INFO) << "Could not find system image for " << system_build
                     << "in the img zip. Assuming a super image build, which will "
-                    << "get the super image from the target zip.";
+                    << "get the system image from the target zip.";
           system_in_img_zip = false;
         } else {
           LOG(INFO) << "Adding img-zip files for system build";
-          AddFilesToConfig(cvd::FileSource::SYSTEM_BUILD, system_build, image_files,
-                           &config, true);
+          AddFilesToConfig(FileSource::SYSTEM_BUILD, system_build, image_files,
+                           &config, target_dir, true);
         }
       }
       std::string system_target_dir = target_dir + "/system";
@@ -344,29 +360,55 @@
         LOG(FATAL) << "Could not download target files for " << system_build;
         return -1;
       }
-      AddFilesToConfig(cvd::FileSource::SYSTEM_BUILD, system_build, target_files, &config);
+      AddFilesToConfig(FileSource::SYSTEM_BUILD, system_build, target_files,
+                       &config, target_dir);
       if (!system_in_img_zip) {
-        std::vector<std::string> wanted_images = {"IMAGES/system.img", "IMAGES/product.img"};
-        auto images = ExtractImages(target_files[0], target_dir, wanted_images);
-        if (images.size() != 2) {
-          LOG(FATAL) << "Could not get system.img, product.img from target zip";
+        if (ExtractImages(target_files[0], target_dir, {"IMAGES/system.img"})
+            != std::vector<std::string>{}) {
+          std::string extracted_system = target_dir + "/IMAGES/system.img";
+          std::string target_system = target_dir + "/system.img";
+          if (rename(extracted_system.c_str(), target_system.c_str())) {
+            int error_num = errno;
+            LOG(FATAL) << "Could not replace system.img in target directory: "
+                       << strerror(error_num);
+            return -1;
+          }
+	} else {
+          LOG(FATAL) << "Could not get system.img from the target zip";
           return -1;
         }
-        std::string extracted_system = target_dir + "/IMAGES/system.img";
-        std::string target_system = target_dir + "/system.img";
-        if (rename(extracted_system.c_str(), target_system.c_str())) {
-          int error_num = errno;
-          LOG(FATAL) << "Could not replace system.img in target directory: "
-              << strerror(error_num);
-          return -1;
+	if (ExtractImages(target_files[0], target_dir, {"IMAGES/product.img"})
+	  != std::vector<std::string>{}) {
+          std::string extracted_product = target_dir + "/IMAGES/product.img";
+          std::string target_product = target_dir + "/product.img";
+          if (rename(extracted_product.c_str(), target_product.c_str())) {
+            int error_num = errno;
+            LOG(FATAL) << "Could not replace product.img in target directory"
+                       << strerror(error_num);
+            return -1;
+          }
+	}
+        if (ExtractImages(target_files[0], target_dir, {"IMAGES/system_ext.img"})
+            != std::vector<std::string>{}) {
+          std::string extracted_system_ext = target_dir + "/IMAGES/system_ext.img";
+          std::string target_system_ext = target_dir + "/system_ext.img";
+          if (rename(extracted_system_ext.c_str(), target_system_ext.c_str())) {
+            int error_num = errno;
+            LOG(FATAL) << "Could not move system_ext.img in target directory: "
+                       << strerror(error_num);
+            return -1;
+          }
         }
-        std::string extracted_product = target_dir + "/IMAGES/product.img";
-        std::string target_product = target_dir + "/product.img";
-        if (rename(extracted_product.c_str(), target_product.c_str())) {
-          int error_num = errno;
-          LOG(FATAL) << "Could not replace product.img in target directory"
-              << strerror(error_num);
-          return -1;
+        if (ExtractImages(target_files[0], target_dir, {"IMAGES/vbmeta_system.img"})
+            != std::vector<std::string>{}) {
+          std::string extracted_vbmeta_system = target_dir + "/IMAGES/vbmeta_system.img";
+          std::string target_vbmeta_system = target_dir + "/vbmeta_system.img";
+          if (rename(extracted_vbmeta_system.c_str(), target_vbmeta_system.c_str())) {
+            int error_num = errno;
+            LOG(FATAL) << "Could not move vbmeta_system.img in target directory: "
+                       << strerror(error_num);
+            return -1;
+          }
         }
         // This should technically call AddFilesToConfig with the produced files,
         // but it will conflict with the ones produced from the default system image
@@ -380,7 +422,14 @@
 
       std::string local_path = target_dir + "/kernel";
       if (build_api.ArtifactToFile(kernel_build, "bzImage", local_path)) {
-        AddFilesToConfig(cvd::FileSource::KERNEL_BUILD, kernel_build, {local_path}, &config);
+        AddFilesToConfig(FileSource::KERNEL_BUILD, kernel_build, {local_path},
+                         &config, target_dir);
+      }
+      // If the kernel is from an arm/aarch64 build, the artifact will be called
+      // Image.
+      else if (build_api.ArtifactToFile(kernel_build, "Image", local_path)) {
+        AddFilesToConfig(FileSource::KERNEL_BUILD, kernel_build, {local_path},
+                         &config, target_dir);
       } else {
         LOG(FATAL) << "Could not download " << kernel_build << ":bzImage to "
             << local_path;
@@ -396,8 +445,31 @@
           LOG(FATAL) << "Could not download " << kernel_build << ":initramfs.img to "
                      << target_dir + "/initramfs.img";
         }
-        AddFilesToConfig(cvd::FileSource::KERNEL_BUILD, kernel_build,
-                         {target_dir + "/initramfs.img"}, &config);
+        AddFilesToConfig(FileSource::KERNEL_BUILD, kernel_build,
+                         {target_dir + "/initramfs.img"}, &config, target_dir);
+      }
+    }
+
+    if (FLAGS_bootloader_build != "") {
+      auto bootloader_build = ArgumentToBuild(&build_api,
+                                              FLAGS_bootloader_build,
+                                              "u-boot_crosvm_x86_64",
+					      retry_period);
+
+      std::string local_path = target_dir + "/bootloader";
+      if (build_api.ArtifactToFile(bootloader_build, "u-boot.rom", local_path)) {
+        AddFilesToConfig(FileSource::BOOTLOADER_BUILD, bootloader_build,
+                         {local_path}, &config, target_dir, true);
+      }
+      // If the bootloader is from an arm/aarch64 build, the artifact will be of
+      // filetype bin.
+      else if (build_api.ArtifactToFile(bootloader_build, "u-boot.bin",
+                                        local_path)) {
+        AddFilesToConfig(FileSource::BOOTLOADER_BUILD, bootloader_build,
+                         {local_path}, &config, target_dir, true);
+      } else {
+        LOG(FATAL) << "Could not download " << bootloader_build << ":u-boot.rom to "
+            << local_path;
       }
     }
   }
@@ -407,11 +479,12 @@
   // their own build id. So it's unclear which build number fetch_cvd itself was built at.
   // https://android.googlesource.com/platform/build/+/979c9f3/Changes.md#build_number
   std::string fetcher_path = target_dir + "/fetcher_config.json";
-  AddFilesToConfig(cvd::GENERATED, DeviceBuild("", ""), {fetcher_path}, &config);
+  AddFilesToConfig(GENERATED, DeviceBuild("", ""), {fetcher_path}, &config,
+                   target_dir);
   config.SaveToFile(fetcher_path);
 
   for (const auto& file : config.get_cvd_files()) {
-    std::cout << file.second.file_path << "\n";
+    std::cout << target_dir << "/" << file.second.file_path << "\n";
   }
   std::cout << std::flush;
 
@@ -421,15 +494,15 @@
 
   // Ignore return code. We want to make sure there is no running instance,
   // and stop_cvd will exit with an error code if there is already no running instance.
-  cvd::Command stop_cmd(target_dir + "/bin/stop_cvd");
-  stop_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut,
-                         cvd::Subprocess::StdIOChannel::kStdErr);
+  Command stop_cmd(target_dir + "/bin/stop_cvd");
+  stop_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut,
+                         Subprocess::StdIOChannel::kStdErr);
   stop_cmd.Start().Wait();
 
   // gflags::ParseCommandLineFlags will remove fetch_cvd's flags from this.
   // This depends the remove_flags argument (3rd) is "true".
 
-  auto filelist_fd = cvd::SharedFD::MemfdCreate("files_list");
+  auto filelist_fd = SharedFD::MemfdCreate("files_list");
   if (!filelist_fd->IsOpen()) {
     LOG(FATAL) << "Unable to create temp file to write file list. "
                << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
@@ -468,4 +541,12 @@
   execv(next_stage.c_str(), const_cast<char* const*>(next_stage_argv.data()));
   int error = errno;
   LOG(FATAL) << "execv returned with errno " << error << ":" << strerror(error);
+
+  return -1;
+}
+
+} // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::FetchCvdMain(argc, argv);
 }
diff --git a/host/commands/fetcher/install_zip.cc b/host/commands/fetcher/install_zip.cc
index b3d0e8e..624c419 100644
--- a/host/commands/fetcher/install_zip.cc
+++ b/host/commands/fetcher/install_zip.cc
@@ -21,7 +21,7 @@
 #include <vector>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/utils/archive.h"
 #include "common/libs/utils/subprocess.h"
@@ -29,7 +29,7 @@
 std::vector<std::string> ExtractImages(const std::string& archive_file,
                                        const std::string& target_directory,
                                        const std::vector<std::string>& images) {
-  cvd::Archive archive(archive_file);
+  cuttlefish::Archive archive(archive_file);
   bool extracted =
       images.size() > 0
           ? archive.ExtractFiles(images, target_directory)
diff --git a/host/commands/gnss_grpc_proxy/Android.bp b/host/commands/gnss_grpc_proxy/Android.bp
new file mode 100644
index 0000000..e85a919
--- /dev/null
+++ b/host/commands/gnss_grpc_proxy/Android.bp
@@ -0,0 +1,91 @@
+// Copyright (C) 2018 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.
+
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "gnss_grpc_proxy",
+    srcs: [
+        "gnss_grpc_proxy.cpp",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-D_XOPEN_SOURCE",
+    ],
+    generated_headers: [
+        "GnssGrpcProxyStub_h",
+    ],
+    generated_sources: [
+        "GnssGrpcProxyStub_cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libjsoncpp",
+        "libprotobuf-cpp-full",
+        "libgrpc++_unsecure",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host"],
+    include_dirs: [
+        "external/grpc-grpc/include",
+        "external/protobuf/src",
+    ],
+}
+
+filegroup {
+    name: "GnssGrpcProxyProto",
+    srcs: [
+        "gnss_grpc_proxy.proto",
+    ],
+}
+
+genrule {
+    name: "GnssGrpcProxyStub_h",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -Idevice/google/cuttlefish/host/commands/gnss_grpc_proxy -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        ":GnssGrpcProxyProto",
+    ],
+    out: [
+        "gnss_grpc_proxy.grpc.pb.h",
+        "gnss_grpc_proxy.pb.h",
+    ],
+}
+
+genrule {
+    name: "GnssGrpcProxyStub_cc",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -Idevice/google/cuttlefish/host/commands/gnss_grpc_proxy -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        ":GnssGrpcProxyProto",
+    ],
+    out: [
+        "gnss_grpc_proxy.grpc.pb.cc",
+        "gnss_grpc_proxy.pb.cc",
+    ],
+}
diff --git a/host/commands/gnss_grpc_proxy/gnss_grpc_proxy.cpp b/host/commands/gnss_grpc_proxy/gnss_grpc_proxy.cpp
new file mode 100644
index 0000000..ff8e54e
--- /dev/null
+++ b/host/commands/gnss_grpc_proxy/gnss_grpc_proxy.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <memory>
+#include <string>
+
+#include <grpcpp.h>
+
+#include "gnss_grpc_proxy.grpc.pb.h"
+
+#include <signal.h>
+
+#include <chrono>
+#include <deque>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include <gflags/gflags.h>
+#include <android-base/logging.h>
+
+#include <common/libs/fs/shared_fd.h>
+#include <common/libs/fs/shared_buf.h>
+#include <common/libs/fs/shared_select.h>
+#include <host/libs/config/cuttlefish_config.h>
+
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+using gnss_grpc_proxy::SendNmeaRequest;
+using gnss_grpc_proxy::SendNmeaReply;
+using gnss_grpc_proxy::GnssGrpcProxy;
+
+DEFINE_int32(gnss_in_fd,
+             -1,
+             "File descriptor for the gnss's input channel");
+DEFINE_int32(gnss_out_fd,
+             -1,
+             "File descriptor for the gnss's output channel");
+
+DEFINE_int32(gnss_grpc_port,
+             -1,
+             "Service port for gnss grpc");
+
+DEFINE_string(gnss_file_path,
+              "",
+              "NMEA file path for gnss grpc");
+
+constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION";
+constexpr uint32_t GNSS_SERIAL_BUFFER_SIZE = 4096;
+// Logic and data behind the server's behavior.
+class GnssGrpcProxyServiceImpl final : public GnssGrpcProxy::Service {
+  public:
+    GnssGrpcProxyServiceImpl(cuttlefish::SharedFD gnss_in,
+                     cuttlefish::SharedFD gnss_out) : gnss_in_(gnss_in),
+                                                  gnss_out_(gnss_out) {}
+    Status SendNmea(ServerContext* context, const SendNmeaRequest* request,
+                    SendNmeaReply* reply) override {
+      reply->set_reply("Received nmea record.");
+
+      auto buffer = request->nmea();
+      std::lock_guard<std::mutex> lock(cached_nmea_mutex);
+      cached_nmea = request->nmea();
+      return Status::OK;
+    }
+
+    void sendToSerial() {
+      LOG(DEBUG) << "Send NMEA to serial:" << cached_nmea;
+      std::lock_guard<std::mutex> lock(cached_nmea_mutex);
+      ssize_t bytes_written = cuttlefish::WriteAll(gnss_in_, cached_nmea);
+      if (bytes_written < 0) {
+          LOG(ERROR) << "Error writing to fd: " << gnss_in_->StrError();
+      }
+    }
+
+    void StartServer() {
+      // Create a new thread to handle writes to the gnss and to the any client
+      // connected to the socket.
+      read_thread_ = std::thread([this]() { ReadLoop(); });
+    }
+
+    void StartReadFileThread() {
+      // Create a new thread to handle writes to the gnss and to the any client
+      // connected to the socket.
+      file_read_thread_ = std::thread([this]() { ReadNmeaFromLocalFile(); });
+    }
+
+    void ReadNmeaFromLocalFile() {
+      std::ifstream file(FLAGS_gnss_file_path);
+      if (file.is_open()) {
+          std::string line;
+          std::string lastLine;
+          int count = 0;
+          while (std::getline(file, line)) {
+              count++;
+              /* Only support a lite version of NEMA format to make it simple.
+               * Records will only contains $GPGGA, $GPRMC,
+               * $GPGGA,213204.00,3725.371240,N,12205.589239,W,7,,0.38,-26.75,M,0.0,M,0.0,0000*78
+               * $GPRMC,213204.00,A,3725.371240,N,12205.589239,W,000.0,000.0,290819,,,A*49
+               * $GPGGA,....
+               * $GPRMC,....
+               * Sending at 1Hz, currently user should
+               * provide a NMEA file that has one location per second. need some extra work
+               * to make it more generic, i.e. align with the timestamp in the file.
+               */
+              if (count % 2 == 0) {
+                {
+                  std::lock_guard<std::mutex> lock(cached_nmea_mutex);
+                  cached_nmea = lastLine + '\n' + line;
+                }
+                std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+              }
+              lastLine = line;
+          }
+          file.close();
+      } else {
+        LOG(ERROR) << "Can not open NMEA file: " << FLAGS_gnss_file_path ;
+        return;
+      }
+    }
+  private:
+    [[noreturn]] void ReadLoop() {
+      cuttlefish::SharedFDSet read_set;
+      read_set.Set(gnss_out_);
+      std::vector<char> buffer(GNSS_SERIAL_BUFFER_SIZE);
+      int total_read = 0;
+      std::string gnss_cmd_str;
+      int flags = gnss_out_->Fcntl(F_GETFL, 0);
+      gnss_out_->Fcntl(F_SETFL, flags | O_NONBLOCK);
+      while (true) {
+        auto bytes_read = gnss_out_->Read(buffer.data(), buffer.size());
+        if (bytes_read > 0) {
+          std::string s(buffer.data(), bytes_read);
+          gnss_cmd_str += s;
+          // In case random string sent though /dev/gnss0, gnss_cmd_str will auto resize,
+          // to get rid of first page.
+          if (gnss_cmd_str.size() > GNSS_SERIAL_BUFFER_SIZE * 2) {
+            gnss_cmd_str = gnss_cmd_str.substr(gnss_cmd_str.size() - GNSS_SERIAL_BUFFER_SIZE);
+          }
+          total_read += bytes_read;
+          if (gnss_cmd_str.find(CMD_GET_LOCATION) != std::string::npos) {
+            sendToSerial();
+            gnss_cmd_str = "";
+            total_read = 0;
+          }
+        } else {
+          if (gnss_out_->GetErrno() == EAGAIN|| gnss_out_->GetErrno() == EWOULDBLOCK) {
+            std::this_thread::sleep_for(std::chrono::milliseconds(100));
+          } else {
+            LOG(ERROR) << "Error reading fd " << FLAGS_gnss_out_fd << ": "
+              << " Error code: " << gnss_out_->GetErrno()
+              << " Error sg:" << gnss_out_->StrError();
+          }
+        }
+      }
+    }
+
+    cuttlefish::SharedFD gnss_in_;
+    cuttlefish::SharedFD gnss_out_;
+    std::thread read_thread_;
+    std::thread file_read_thread_;
+    std::string cached_nmea;
+    std::mutex cached_nmea_mutex;
+};
+
+void RunServer() {
+  auto gnss_in = cuttlefish::SharedFD::Dup(FLAGS_gnss_in_fd);
+  close(FLAGS_gnss_in_fd);
+  if (!gnss_in->IsOpen()) {
+    LOG(ERROR) << "Error dupping fd " << FLAGS_gnss_in_fd << ": "
+               << gnss_in->StrError();
+    return;
+  }
+  close(FLAGS_gnss_in_fd);
+
+  auto gnss_out = cuttlefish::SharedFD::Dup(FLAGS_gnss_out_fd);
+  close(FLAGS_gnss_out_fd);
+  if (!gnss_out->IsOpen()) {
+    LOG(ERROR) << "Error dupping fd " << FLAGS_gnss_out_fd << ": "
+               << gnss_out->StrError();
+    return;
+  }
+  auto server_address("0.0.0.0:" + std::to_string(FLAGS_gnss_grpc_port));
+  GnssGrpcProxyServiceImpl service(gnss_in, gnss_out);
+  service.StartServer();
+  if (!FLAGS_gnss_file_path.empty()) {
+    service.StartReadFileThread();
+    // In the local mode, we are not start a grpc server, use a infinite loop instead
+    while(true) {
+      std::this_thread::sleep_for(std::chrono::milliseconds(2000));
+    }
+  } else {
+    ServerBuilder builder;
+    // Listen on the given address without any authentication mechanism.
+    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+    // Register "service" as the instance through which we'll communicate with
+    // clients. In this case it corresponds to an *synchronous* service.
+    builder.RegisterService(&service);
+    // Finally assemble the server.
+    std::unique_ptr<Server> server(builder.BuildAndStart());
+    std::cout << "Server listening on " << server_address << std::endl;
+
+    // Wait for the server to shutdown. Note that some other thread must be
+    // responsible for shutting down the server for this call to ever return.
+    server->Wait();
+  }
+
+}
+
+
+int main(int argc, char** argv) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  ::gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+  LOG(DEBUG) << "Starting gnss grpc proxy server...";
+  RunServer();
+
+  return 0;
+}
diff --git a/host/commands/gnss_grpc_proxy/gnss_grpc_proxy.proto b/host/commands/gnss_grpc_proxy/gnss_grpc_proxy.proto
new file mode 100644
index 0000000..2a12d2d
--- /dev/null
+++ b/host/commands/gnss_grpc_proxy/gnss_grpc_proxy.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+package gnss_grpc_proxy;
+
+// The greeting service definition.
+service GnssGrpcProxy {
+  // Sends NmeaRequest
+  rpc SendNmea (SendNmeaRequest) returns (SendNmeaReply) {}
+}
+
+// The request message containing nmea
+message SendNmeaRequest {
+  string nmea = 1;
+}
+
+// The response message containing the return information
+message SendNmeaReply {
+  string reply = 1;
+}
diff --git a/host/commands/gnss_grpc_proxy/grpcpp.h b/host/commands/gnss_grpc_proxy/grpcpp.h
new file mode 100644
index 0000000..e952806
--- /dev/null
+++ b/host/commands/gnss_grpc_proxy/grpcpp.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * 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.
+ *
+ */
+
+/// \mainpage gRPC C++ API
+///
+/// The gRPC C++ API mainly consists of the following classes:
+/// <br>
+/// - grpc::Channel, which represents the connection to an endpoint. See [the
+/// gRPC Concepts page](https://grpc.io/docs/guides/concepts.html) for more
+/// details. Channels are created by the factory function grpc::CreateChannel.
+///
+/// - grpc::CompletionQueue, the producer-consumer queue used for all
+/// asynchronous communication with the gRPC runtime.
+///
+/// - grpc::ClientContext and grpc::ServerContext, where optional configuration
+/// for an RPC can be set, such as setting custom metadata to be conveyed to the
+/// peer, compression settings, authentication, etc.
+///
+/// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
+///
+/// Streaming calls are handled with the streaming classes in
+/// \ref sync_stream.h and
+/// \ref async_stream.h.
+///
+/// Refer to the
+/// [examples](https://github.com/grpc/)
+/// for code putting these pieces into play.
+
+#ifndef GRPCPP_GRPCPP_H
+#define GRPCPP_GRPCPP_H
+
+// Pragma for http://include-what-you-use.org/ tool, tells that following
+// headers are not private for grpcpp.h and are part of its interface.
+// IWYU pragma: begin_exports
+#include <grpc/grpc.h>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/create_channel_posix.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/server_posix.h>
+// IWYU pragma: end_exports
+
+namespace grpc {
+/// Return gRPC library version.
+grpc::string Version();
+}  // namespace grpc
+
+#endif  // GRPCPP_GRPCPP_H
\ No newline at end of file
diff --git a/host/commands/kernel_log_monitor/Android.bp b/host/commands/kernel_log_monitor/Android.bp
index 54dda47..02e2be8 100644
--- a/host/commands/kernel_log_monitor/Android.bp
+++ b/host/commands/kernel_log_monitor/Android.bp
@@ -13,24 +13,40 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "kernel_log_monitor",
     srcs: [
         "main.cc",
         "kernel_log_server.cc",
     ],
-    header_libs: [
-        "cuttlefish_glog",
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libcuttlefish_kernel_log_monitor_utils",
+        "libbase",
+        "libjsoncpp",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host"],
+}
+
+cc_library {
+    name: "libcuttlefish_kernel_log_monitor_utils",
+    srcs: [
+        "utils.cc",
     ],
     shared_libs: [
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "libbase",
-    ],
-    static_libs: [
-        "libcuttlefish_host_config",
-        "libgflags",
         "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.cc b/host/commands/kernel_log_monitor/kernel_log_server.cc
index 4231751..66fafab 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.cc
+++ b/host/commands/kernel_log_monitor/kernel_log_server.cc
@@ -19,38 +19,42 @@
 #include <map>
 #include <utility>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <netinet/in.h>
 #include "common/libs/fs/shared_select.h"
 #include "host/libs/config/cuttlefish_config.h"
 
-using cvd::SharedFD;
+using cuttlefish::SharedFD;
 
 namespace {
 static const std::map<std::string, std::string> kInformationalPatterns = {
+    {"U-Boot ", "GUEST_UBOOT_VERSION: "},
     {"] Linux version ", "GUEST_KERNEL_VERSION: "},
     {"GUEST_BUILD_FINGERPRINT: ", "GUEST_BUILD_FINGERPRINT: "},
 };
 
-static const std::map<std::string, monitor::BootEvent> kStageToEventMap = {
-    {vsoc::kBootStartedMessage, monitor::BootEvent::BootStarted},
-    {vsoc::kBootCompletedMessage, monitor::BootEvent::BootCompleted},
-    {vsoc::kBootFailedMessage, monitor::BootEvent::BootFailed},
-    {vsoc::kMobileNetworkConnectedMessage,
-     monitor::BootEvent::MobileNetworkConnected},
-    {vsoc::kWifiConnectedMessage, monitor::BootEvent::WifiNetworkConnected},
+static const std::map<std::string, monitor::Event> kStageToEventMap = {
+    {cuttlefish::kBootStartedMessage, monitor::Event::BootStarted},
+    {cuttlefish::kBootCompletedMessage, monitor::Event::BootCompleted},
+    {cuttlefish::kBootFailedMessage, monitor::Event::BootFailed},
+    {cuttlefish::kMobileNetworkConnectedMessage,
+     monitor::Event::MobileNetworkConnected},
+    {cuttlefish::kWifiConnectedMessage, monitor::Event::WifiNetworkConnected},
+    {cuttlefish::kEthernetConnectedMessage, monitor::Event::EthernetNetworkConnected},
     // TODO(b/131864854): Replace this with a string less likely to change
-    {"init: starting service 'adbd'", monitor::BootEvent::AdbdStarted},
+    {"init: starting service 'adbd'...", monitor::Event::AdbdStarted},
+    {cuttlefish::kScreenChangedMessage, monitor::Event::ScreenChanged},
 };
 
 void ProcessSubscriptions(
-    monitor::BootEvent evt,
-    std::vector<monitor::BootEventCallback>* subscribers) {
+    Json::Value message,
+    std::vector<monitor::EventCallback>* subscribers) {
   auto active_subscription_count = subscribers->size();
   std::size_t idx = 0;
   while (idx < active_subscription_count) {
     // Call the callback
-    auto action = (*subscribers)[idx](evt);
+    auto action = (*subscribers)[idx](message);
     if (action == monitor::SubscriptionAction::ContinueSubscription) {
       ++idx;
     } else {
@@ -66,25 +70,24 @@
 }  // namespace
 
 namespace monitor {
-KernelLogServer::KernelLogServer(cvd::SharedFD pipe_fd,
+KernelLogServer::KernelLogServer(cuttlefish::SharedFD pipe_fd,
                                  const std::string& log_name,
                                  bool deprecated_boot_completed)
     : pipe_fd_(pipe_fd),
-      log_fd_(cvd::SharedFD::Open(log_name.c_str(), O_CREAT | O_RDWR, 0666)),
+      log_fd_(cuttlefish::SharedFD::Open(log_name.c_str(), O_CREAT | O_RDWR | O_APPEND, 0666)),
       deprecated_boot_completed_(deprecated_boot_completed) {}
 
-void KernelLogServer::BeforeSelect(cvd::SharedFDSet* fd_read) const {
+void KernelLogServer::BeforeSelect(cuttlefish::SharedFDSet* fd_read) const {
   fd_read->Set(pipe_fd_);
 }
 
-void KernelLogServer::AfterSelect(const cvd::SharedFDSet& fd_read) {
+void KernelLogServer::AfterSelect(const cuttlefish::SharedFDSet& fd_read) {
   if (fd_read.IsSet(pipe_fd_)) {
     HandleIncomingMessage();
   }
 }
 
-void KernelLogServer::SubscribeToBootEvents(
-    monitor::BootEventCallback callback) {
+void KernelLogServer::SubscribeToEvents(monitor::EventCallback callback) {
   subscribers_.push_back(callback);
 }
 
@@ -117,10 +120,35 @@
       for (auto& stage_kv : kStageToEventMap) {
         auto& stage = stage_kv.first;
         auto event = stage_kv.second;
-        if (std::string::npos != line_.find(stage)) {
+        auto pos = line_.find(stage);
+        if (std::string::npos != pos) {
           // Log the stage
           LOG(INFO) << stage;
-          ProcessSubscriptions(event, &subscribers_);
+
+          Json::Value message;
+          message["event"] = event;
+          Json::Value metadata;
+          // Expect space-separated key=value pairs in the log message.
+          const auto& fields = android::base::Split(
+              line_.substr(pos + stage.size()), " ");
+          for (std::string field : fields) {
+            field = android::base::Trim(field);
+            if (field.empty()) {
+              // Expected; android::base::Split() always returns at least
+              // one (possibly empty) string.
+              LOG(DEBUG) << "Empty field for line: " << line_;
+              continue;
+            }
+            const auto& keyvalue = android::base::Split(field, "=");
+            if (keyvalue.size() != 2) {
+              LOG(WARNING) << "Field is not in key=value format: " << field;
+              continue;
+            }
+            metadata[keyvalue[0]] = keyvalue[1];
+          }
+          message["metadata"] = metadata;
+          ProcessSubscriptions(message, &subscribers_);
+
           //TODO(b/69417553) Remove this when our clients have transitioned to the
           // new boot completed
           if (deprecated_boot_completed_) {
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.h b/host/commands/kernel_log_monitor/kernel_log_server.h
index f5709ee..659a372 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.h
+++ b/host/commands/kernel_log_monitor/kernel_log_server.h
@@ -21,18 +21,22 @@
 #include <string>
 #include <vector>
 
+#include <json/json.h>
+
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/fs/shared_select.h"
 
 namespace monitor {
 
-enum BootEvent : int32_t {
+enum Event : int32_t {
   BootStarted = 0,
   BootCompleted = 1,
   BootFailed = 2,
   WifiNetworkConnected = 3,
   MobileNetworkConnected = 4,
   AdbdStarted = 5,
+  ScreenChanged = 6,
+  EthernetNetworkConnected = 7,
 };
 
 enum class SubscriptionAction {
@@ -40,13 +44,13 @@
   CancelSubscription,
 };
 
-using BootEventCallback = std::function<SubscriptionAction(BootEvent)>;
+using EventCallback = std::function<SubscriptionAction(Json::Value)>;
 
-// KernelLogServer manages incoming kernel log connection from QEmu. Only accept
-// one connection.
+// KernelLogServer manages an incoming kernel log connection from the VMM.
+// Only accept one connection.
 class KernelLogServer {
  public:
-  KernelLogServer(cvd::SharedFD pipe_fd,
+  KernelLogServer(cuttlefish::SharedFD pipe_fd,
                   const std::string& log_name,
                   bool deprecated_boot_completed);
 
@@ -54,23 +58,24 @@
 
   // BeforeSelect is Called right before Select() to populate interesting
   // SharedFDs.
-  void BeforeSelect(cvd::SharedFDSet* fd_read) const;
+  void BeforeSelect(cuttlefish::SharedFDSet* fd_read) const;
 
   // AfterSelect is Called right after Select() to detect and respond to changes
   // on affected SharedFDs.
-  void AfterSelect(const cvd::SharedFDSet& fd_read);
+  void AfterSelect(const cuttlefish::SharedFDSet& fd_read);
 
-  void SubscribeToBootEvents(BootEventCallback callback);
+  void SubscribeToEvents(EventCallback callback);
+
  private:
   // Respond to message from remote client.
   // Returns false, if client disconnected.
   bool HandleIncomingMessage();
 
-  cvd::SharedFD pipe_fd_;
-  cvd::SharedFD log_fd_;
+  cuttlefish::SharedFD pipe_fd_;
+  cuttlefish::SharedFD log_fd_;
   std::string line_;
   bool deprecated_boot_completed_;
-  std::vector<BootEventCallback> subscribers_;
+  std::vector<EventCallback> subscribers_;
 
   KernelLogServer(const KernelLogServer&) = delete;
   KernelLogServer& operator=(const KernelLogServer&) = delete;
diff --git a/host/commands/kernel_log_monitor/main.cc b/host/commands/kernel_log_monitor/main.cc
index d7e8fdf..3f708b7 100644
--- a/host/commands/kernel_log_monitor/main.cc
+++ b/host/commands/kernel_log_monitor/main.cc
@@ -20,14 +20,17 @@
 #include <string>
 #include <vector>
 
+#include <android-base/logging.h>
 #include <android-base/strings.h>
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <json/json.h>
 
 #include <common/libs/fs/shared_fd.h>
 #include <common/libs/fs/shared_select.h>
 #include <host/libs/config/cuttlefish_config.h>
+#include <host/libs/config/logging.h>
 #include "host/commands/kernel_log_monitor/kernel_log_server.h"
+#include "host/commands/kernel_log_monitor/utils.h"
 
 DEFINE_int32(log_pipe_fd, -1,
              "A file descriptor representing a (UNIX) socket from which to "
@@ -35,9 +38,9 @@
              "the instance configuration");
 DEFINE_string(subscriber_fds, "",
              "A comma separated list of file descriptors (most likely pipes) to"
-             " send boot events to.");
+             " send kernel log events to.");
 
-std::vector<cvd::SharedFD> SubscribersFromCmdline() {
+std::vector<cuttlefish::SharedFD> SubscribersFromCmdline() {
   // Validate the parameter
   std::string fd_list = FLAGS_subscriber_fds;
   for (auto c: fd_list) {
@@ -48,10 +51,10 @@
   }
 
   auto fds = android::base::Split(FLAGS_subscriber_fds, ",");
-  std::vector<cvd::SharedFD> shared_fds;
+  std::vector<cuttlefish::SharedFD> shared_fds;
   for (auto& fd_str: fds) {
     auto fd = std::stoi(fd_str);
-    auto shared_fd = cvd::SharedFD::Dup(fd);
+    auto shared_fd = cuttlefish::SharedFD::Dup(fd);
     close(fd);
     shared_fds.push_back(shared_fd);
   }
@@ -60,9 +63,15 @@
 }
 
 int main(int argc, char** argv) {
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  cuttlefish::DefaultSubprocessLogging(argv);
   google::ParseCommandLineFlags(&argc, &argv, true);
 
+  auto config = cuttlefish::CuttlefishConfig::Get();
+
+  CHECK(config) << "Could not open cuttlefish config";
+
+  auto instance = config->ForDefaultInstance();
+
   auto subscriber_fds = SubscribersFromCmdline();
 
   // Disable default handling of SIGPIPE
@@ -71,19 +80,12 @@
   new_action.sa_handler = SIG_IGN;
   sigaction(SIGPIPE, &new_action, &old_action);
 
-  auto config = vsoc::CuttlefishConfig::Get();
-  if (!config) {
-    LOG(ERROR) << "Unable to get config object";
-    return 1;
-  }
-  auto instance = config->ForDefaultInstance();
-
-  cvd::SharedFD pipe;
+  cuttlefish::SharedFD pipe;
   if (FLAGS_log_pipe_fd < 0) {
     auto log_name = instance.kernel_log_pipe_name();
-    pipe = cvd::SharedFD::Open(log_name.c_str(), O_RDONLY);
+    pipe = cuttlefish::SharedFD::Open(log_name.c_str(), O_RDONLY);
   } else {
-    pipe = cvd::SharedFD::Dup(FLAGS_log_pipe_fd);
+    pipe = cuttlefish::SharedFD::Dup(FLAGS_log_pipe_fd);
     close(FLAGS_log_pipe_fd);
   }
 
@@ -97,9 +99,8 @@
 
   for (auto subscriber_fd: subscriber_fds) {
     if (subscriber_fd->IsOpen()) {
-      klog.SubscribeToBootEvents([subscriber_fd](monitor::BootEvent evt) {
-        int retval = subscriber_fd->Write(&evt, sizeof(evt));
-        if (retval < 0) {
+      klog.SubscribeToEvents([subscriber_fd](Json::Value message) {
+        if (!monitor::WriteEvent(subscriber_fd, message)) {
           if (subscriber_fd->GetErrno() != EPIPE) {
             LOG(ERROR) << "Error while writing to pipe: "
                        << subscriber_fd->StrError();
@@ -116,12 +117,12 @@
   }
 
   for (;;) {
-    cvd::SharedFDSet fd_read;
+    cuttlefish::SharedFDSet fd_read;
     fd_read.Zero();
 
     klog.BeforeSelect(&fd_read);
 
-    int ret = cvd::Select(&fd_read, nullptr, nullptr, nullptr);
+    int ret = cuttlefish::Select(&fd_read, nullptr, nullptr, nullptr);
     if (ret <= 0) continue;
 
     klog.AfterSelect(fd_read);
diff --git a/host/commands/kernel_log_monitor/utils.cc b/host/commands/kernel_log_monitor/utils.cc
new file mode 100644
index 0000000..9649668
--- /dev/null
+++ b/host/commands/kernel_log_monitor/utils.cc
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "host/commands/kernel_log_monitor/utils.h"
+
+#include <android-base/logging.h>
+
+#include "common/libs/fs/shared_buf.h"
+
+namespace monitor {
+
+std::optional<ReadEventResult> ReadEvent(cuttlefish::SharedFD fd) {
+  size_t length;
+  ssize_t bytes_read = cuttlefish::ReadExactBinary(fd, &length);
+  if (bytes_read <= 0) {
+    LOG(ERROR) << "Failed to read event buffer size: " << fd->StrError();
+    return std::nullopt;
+  }
+  std::string buf(length, ' ');
+  bytes_read = cuttlefish::ReadExact(fd, &buf);
+  if (bytes_read <= 0) {
+    LOG(ERROR) << "Failed to read event buffer: " << fd->StrError();
+    return std::nullopt;
+  }
+
+  Json::CharReaderBuilder builder;
+  std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
+  std::string errorMessage;
+  Json::Value message;
+  if (!reader->parse(&*buf.begin(), &*buf.end(), &message, &errorMessage)) {
+    LOG(ERROR) << "Unable to parse event JSON: " << errorMessage;
+    return std::nullopt;
+  }
+
+  ReadEventResult result = {
+    static_cast<monitor::Event>(message["event"].asInt()),
+    message["metadata"]
+  };
+  return result;
+}
+
+bool WriteEvent(cuttlefish::SharedFD fd, const Json::Value& event_message) {
+  Json::StreamWriterBuilder factory;
+  std::string message_string = Json::writeString(factory, event_message);
+  size_t length = message_string.length();
+  ssize_t retval = cuttlefish::WriteAllBinary(fd, &length);
+  if (retval <= 0) {
+    LOG(ERROR) << "Failed to write event buffer size: " << fd->StrError();
+    return false;
+  }
+  retval = cuttlefish::WriteAll(fd, message_string);
+  if (retval <= 0) {
+    LOG(ERROR) << "Failed to write event buffer: " << fd->StrError();
+    return false;
+  }
+  return true;
+}
+
+}  // namespace monitor
diff --git a/host/commands/kernel_log_monitor/utils.h b/host/commands/kernel_log_monitor/utils.h
new file mode 100644
index 0000000..1293a12
--- /dev/null
+++ b/host/commands/kernel_log_monitor/utils.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <json/json.h>
+#include <optional>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/commands/kernel_log_monitor/kernel_log_server.h"
+
+namespace monitor {
+
+struct ReadEventResult {
+  Event event;
+  Json::Value metadata;
+};
+
+// Read a kernel log event from fd.
+std::optional<ReadEventResult> ReadEvent(cuttlefish::SharedFD fd);
+
+// Writes a kernel log event to the fd, in a format expected by ReadEvent.
+bool WriteEvent(cuttlefish::SharedFD fd, const Json::Value& event_message);
+
+}  // namespace monitor
diff --git a/host/commands/launch/Android.bp b/host/commands/launch/Android.bp
index dafe990..6adf7a2 100644
--- a/host/commands/launch/Android.bp
+++ b/host/commands/launch/Android.bp
@@ -13,28 +13,33 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "launch_cvd",
     srcs: [
         "filesystem_explorer.cc",
         "flag_forwarder.cc",
         "launch_cvd.cc",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "libbase",
+        "libjsoncpp",
         "libnl",
+        "libxml2",
+        "libz",
     ],
     static_libs: [
         "libcuttlefish_host_config",
         "libcuttlefish_vm_manager",
         "libgflags",
-        "libxml2",
-        "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only", "cuttlefish_libicuuc"],
+    required: [
+        "mkenvimage",
+    ],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
 }
diff --git a/host/commands/launch/filesystem_explorer.cc b/host/commands/launch/filesystem_explorer.cc
index 4d43dcf..aac8ae6 100644
--- a/host/commands/launch/filesystem_explorer.cc
+++ b/host/commands/launch/filesystem_explorer.cc
@@ -22,16 +22,16 @@
 #include <errno.h>
 #include <sys/types.h>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/environment.h"
 #include "host/libs/config/fetcher_config.h"
 
-cvd::FetcherConfig AvailableFilesReport() {
-  std::string current_directory = cvd::AbsolutePath(cvd::CurrentDirectory());
-  if (cvd::FileExists(current_directory + "/fetcher_config.json")) {
-    cvd::FetcherConfig config;
+cuttlefish::FetcherConfig AvailableFilesReport() {
+  std::string current_directory = cuttlefish::AbsolutePath(cuttlefish::CurrentDirectory());
+  if (cuttlefish::FileExists(current_directory + "/fetcher_config.json")) {
+    cuttlefish::FetcherConfig config;
     config.LoadFromFile(current_directory + "/fetcher_config.json");
     return config;
   }
@@ -39,16 +39,16 @@
   std::set<std::string> files;
 
   std::string psuedo_fetcher_dir =
-      cvd::StringFromEnv("ANDROID_HOST_OUT",
-                         cvd::StringFromEnv("HOME", current_directory));
+      cuttlefish::StringFromEnv("ANDROID_HOST_OUT",
+                         cuttlefish::StringFromEnv("HOME", current_directory));
   std::string psuedo_fetcher_config =
       psuedo_fetcher_dir + "/launcher_pseudo_fetcher_config.json";
   files.insert(psuedo_fetcher_config);
 
-  cvd::FetcherConfig config;
+  cuttlefish::FetcherConfig config;
   config.RecordFlags();
   for (const auto& file : files) {
-    config.add_cvd_file(cvd::CvdFile(cvd::FileSource::LOCAL_FILE, "", "", file));
+    config.add_cvd_file(cuttlefish::CvdFile(cuttlefish::FileSource::LOCAL_FILE, "", "", file));
   }
   config.SaveToFile(psuedo_fetcher_config);
   return config;
diff --git a/host/commands/launch/filesystem_explorer.h b/host/commands/launch/filesystem_explorer.h
index 3290ebd..ceae504 100644
--- a/host/commands/launch/filesystem_explorer.h
+++ b/host/commands/launch/filesystem_explorer.h
@@ -17,4 +17,4 @@
 
 #include "host/libs/config/fetcher_config.h"
 
-cvd::FetcherConfig AvailableFilesReport();
+cuttlefish::FetcherConfig AvailableFilesReport();
diff --git a/host/commands/launch/flag_forwarder.cc b/host/commands/launch/flag_forwarder.cc
index 9e639e4..692e453 100644
--- a/host/commands/launch/flag_forwarder.cc
+++ b/host/commands/launch/flag_forwarder.cc
@@ -23,7 +23,7 @@
 #include <vector>
 
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include <libxml/tree.h>
 
 #include "common/libs/fs/shared_buf.h"
@@ -234,12 +234,12 @@
   std::map<std::string, std::string> flag_to_type = CurrentFlagsToTypes();
 
   for (const auto& subprocess : subprocesses_) {
-    cvd::Command cmd(subprocess);
+    cuttlefish::Command cmd(subprocess);
     cmd.AddParameter("--helpxml");
     std::string helpxml_input, helpxml_output, helpxml_error;
-    cvd::SubprocessOptions options;
+    cuttlefish::SubprocessOptions options;
     options.Verbose(false);
-    int helpxml_ret = cvd::RunWithManagedStdio(std::move(cmd), &helpxml_input,
+    int helpxml_ret = cuttlefish::RunWithManagedStdio(std::move(cmd), &helpxml_input,
                                                &helpxml_output, &helpxml_error,
                                                options);
     if (helpxml_ret != 1) {
@@ -273,7 +273,7 @@
 void FlagForwarder::UpdateFlagDefaults() const {
 
   for (const auto& subprocess : subprocesses_) {
-    cvd::Command cmd(subprocess);
+    cuttlefish::Command cmd(subprocess);
     std::vector<std::string> invocation = {subprocess};
     for (const auto& flag : ArgvForSubprocess(subprocess)) {
       cmd.AddParameter(flag);
@@ -290,9 +290,9 @@
     // Ensure this is set on by putting it at the end.
     cmd.AddParameter("--helpxml");
     std::string helpxml_input, helpxml_output, helpxml_error;
-    cvd::SubprocessOptions options;
+    cuttlefish::SubprocessOptions options;
     options.Verbose(false);
-    int helpxml_ret = cvd::RunWithManagedStdio(std::move(cmd), &helpxml_input,
+    int helpxml_ret = cuttlefish::RunWithManagedStdio(std::move(cmd), &helpxml_input,
                                                &helpxml_output, &helpxml_error,
                                                options);
     if (helpxml_ret != 1) {
diff --git a/host/commands/launch/launch_cvd.cc b/host/commands/launch/launch_cvd.cc
index 6cc7c93..f67ce48 100644
--- a/host/commands/launch/launch_cvd.cc
+++ b/host/commands/launch/launch_cvd.cc
@@ -13,16 +13,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <iostream>
 #include <sstream>
+#include <fstream>
 
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/subprocess.h"
 #include "host/commands/launch/filesystem_explorer.h"
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/host_tools_version.h"
 #include "host/libs/config/fetcher_config.h"
 
 #include "flag_forwarder.h"
@@ -40,49 +43,124 @@
 DEFINE_bool(run_file_discovery, true,
             "Whether to run file discovery or get input files from stdin.");
 DEFINE_int32(num_instances, 1, "Number of Android guests to launch");
+DEFINE_string(report_anonymous_usage_stats, "", "Report anonymous usage "
+            "statistics for metrics collection and analysis.");
+DEFINE_int32(base_instance_num,
+             cuttlefish::GetInstance(),
+             "The instance number of the device created. When `-num_instances N`"
+             " is used, N instance numbers are claimed starting at this number.");
+DEFINE_string(verbosity, "INFO", "Console logging verbosity. Options are VERBOSE,"
+                                 "DEBUG,INFO,WARNING,ERROR");
+DEFINE_string(file_verbosity, "DEBUG",
+              "Log file logging verbosity. Options are VERBOSE,DEBUG,INFO,"
+              "WARNING,ERROR");
 
 namespace {
 
-std::string kAssemblerBin = vsoc::DefaultHostArtifactsPath("bin/assemble_cvd");
-std::string kRunnerBin = vsoc::DefaultHostArtifactsPath("bin/run_cvd");
+std::string kAssemblerBin = cuttlefish::HostBinaryPath("assemble_cvd");
+std::string kRunnerBin = cuttlefish::HostBinaryPath("run_cvd");
 
-cvd::Subprocess StartAssembler(cvd::SharedFD assembler_stdin,
-                               cvd::SharedFD assembler_stdout,
+cuttlefish::Subprocess StartAssembler(cuttlefish::SharedFD assembler_stdin,
+                               cuttlefish::SharedFD assembler_stdout,
                                const std::vector<std::string>& argv) {
-  cvd::Command assemble_cmd(kAssemblerBin);
+  cuttlefish::Command assemble_cmd(kAssemblerBin);
   for (const auto& arg : argv) {
     assemble_cmd.AddParameter(arg);
   }
   if (assembler_stdin->IsOpen()) {
-    assemble_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, assembler_stdin);
+    assemble_cmd.RedirectStdIO(cuttlefish::Subprocess::StdIOChannel::kStdIn, assembler_stdin);
   }
-  assemble_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, assembler_stdout);
+  assemble_cmd.RedirectStdIO(cuttlefish::Subprocess::StdIOChannel::kStdOut, assembler_stdout);
   return assemble_cmd.Start();
 }
 
-cvd::Subprocess StartRunner(cvd::SharedFD runner_stdin,
+cuttlefish::Subprocess StartRunner(cuttlefish::SharedFD runner_stdin,
                             const std::vector<std::string>& argv) {
-  cvd::Command run_cmd(kRunnerBin);
+  cuttlefish::Command run_cmd(kRunnerBin);
   for (const auto& arg : argv) {
     run_cmd.AddParameter(arg);
   }
-  run_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, runner_stdin);
+  run_cmd.RedirectStdIO(cuttlefish::Subprocess::StdIOChannel::kStdIn, runner_stdin);
   return run_cmd.Start();
 }
 
-void WriteFiles(cvd::FetcherConfig fetcher_config, cvd::SharedFD out) {
+void WriteFiles(cuttlefish::FetcherConfig fetcher_config, cuttlefish::SharedFD out) {
   std::stringstream output_streambuf;
   for (const auto& file : fetcher_config.get_cvd_files()) {
     output_streambuf << file.first << "\n";
   }
   std::string output_string = output_streambuf.str();
-  int written = cvd::WriteAll(out, output_string);
+  int written = cuttlefish::WriteAll(out, output_string);
   if (written < 0) {
     LOG(FATAL) << "Could not write file report (" << strerror(out->GetErrno())
                << ")";
   }
 }
 
+std::string ValidateMetricsConfirmation(std::string use_metrics) {
+  if (use_metrics == "") {
+    if (cuttlefish::CuttlefishConfig::ConfigExists()) {
+      auto config = cuttlefish::CuttlefishConfig::Get();
+      if (config) {
+        if (config->enable_metrics() == cuttlefish::CuttlefishConfig::kYes) {
+          use_metrics = "y";
+        } else if (config->enable_metrics() == cuttlefish::CuttlefishConfig::kNo) {
+          use_metrics = "n";
+        }
+      }
+    }
+  }
+  char ch = !use_metrics.empty() ? tolower(use_metrics.at(0)) : -1;
+  if (ch != 'n') {
+    std::cout << "===================================================================\n";
+    std::cout << "NOTICE:\n\n";
+    std::cout << "We collect usage statistics in accordance with our\n"
+                 "Content Licenses (https://source.android.com/setup/start/licenses),\n"
+                 "Contributor License Agreement (https://cla.developers.google.com/),\n"
+                 "Privacy Policy (https://policies.google.com/privacy) and\n"
+                 "Terms of Service (https://policies.google.com/terms).\n";
+    std::cout << "===================================================================\n\n";
+    if (use_metrics.empty()) {
+      std::cout << "Do you accept anonymous usage statistics reporting (Y/n)?: ";
+    }
+  }
+  for (;;) {
+    switch (ch) {
+      case 0:
+      case '\r':
+      case '\n':
+      case 'y':
+        return "y";
+      case 'n':
+        return "n";
+      default:
+        std::cout << "Must accept/reject anonymous usage statistics reporting (Y/n): ";
+        FALLTHROUGH_INTENDED;
+      case -1:
+        std::cin.get(ch);
+        // if there's no tty the EOF flag is set, in which case default to 'n'
+        if (std::cin.eof()) {
+          ch = 'n';
+          std::cout << "n\n";  // for consistency with user input
+        }
+        ch = tolower(ch);
+    }
+  }
+  return "";
+}
+
+bool HostToolsUpdated() {
+  if (cuttlefish::CuttlefishConfig::ConfigExists()) {
+    auto config = cuttlefish::CuttlefishConfig::Get();
+    if (config) {
+      auto current_tools = cuttlefish::HostToolsCrc();
+      auto last_tools = config->host_tools_version();
+      return current_tools != last_tools;
+    }
+  }
+  return true;
+}
+
 } // namespace
 
 int main(int argc, char** argv) {
@@ -96,15 +174,35 @@
 
   gflags::HandleCommandLineHelpFlags();
 
-  cvd::SharedFD assembler_stdout, assembler_stdout_capture;
-  cvd::SharedFD::Pipe(&assembler_stdout_capture, &assembler_stdout);
+  setenv("CF_CONSOLE_SEVERITY", FLAGS_verbosity.c_str(), /* replace */ false);
+  setenv("CF_FILE_SEVERITY", FLAGS_file_verbosity.c_str(), /* replace */ false);
 
-  cvd::SharedFD launcher_report, assembler_stdin;
+  auto use_metrics = FLAGS_report_anonymous_usage_stats;
+  FLAGS_report_anonymous_usage_stats = ValidateMetricsConfirmation(use_metrics);
+
+  // TODO(b/159068082) Make decisions based on this value in assemble_cvd
+  LOG(INFO) << "Host changed from last run: " << HostToolsUpdated();
+
+  cuttlefish::SharedFD assembler_stdout, assembler_stdout_capture;
+  cuttlefish::SharedFD::Pipe(&assembler_stdout_capture, &assembler_stdout);
+
+  cuttlefish::SharedFD launcher_report, assembler_stdin;
   bool should_generate_report = FLAGS_run_file_discovery;
   if (should_generate_report) {
-    cvd::SharedFD::Pipe(&assembler_stdin, &launcher_report);
+    cuttlefish::SharedFD::Pipe(&assembler_stdin, &launcher_report);
   }
 
+  auto instance_num_str = std::to_string(FLAGS_base_instance_num);
+  setenv("CUTTLEFISH_INSTANCE", instance_num_str.c_str(), /* overwrite */ 1);
+
+#if defined(__BIONIC__)
+  // These environment variables are needed in case when Bionic is used.
+  // b/171754977
+  setenv("ANDROID_DATA", cuttlefish::DefaultHostArtifactsPath("").c_str(), /* overwrite */ 0);
+  setenv("ANDROID_TZDATA_ROOT", cuttlefish::DefaultHostArtifactsPath("").c_str(), /* overwrite */ 0);
+  setenv("ANDROID_ROOT", cuttlefish::DefaultHostArtifactsPath("").c_str(), /* overwrite */ 0);
+#endif
+
   // SharedFDs are std::move-d in to avoid dangling references.
   // Removing the std::move will probably make run_cvd hang as its stdin never closes.
   auto assemble_proc = StartAssembler(std::move(assembler_stdin),
@@ -116,7 +214,7 @@
   }
 
   std::string assembler_output;
-  if (cvd::ReadAll(assembler_stdout_capture, &assembler_output) < 0) {
+  if (cuttlefish::ReadAll(assembler_stdout_capture, &assembler_output) < 0) {
     int error_num = errno;
     LOG(ERROR) << "Read error getting output from assemble_cvd: " << strerror(error_num);
     return -1;
@@ -127,20 +225,20 @@
     LOG(ERROR) << "assemble_cvd returned " << assemble_ret;
     return assemble_ret;
   } else {
-    LOG(INFO) << "assemble_cvd exited successfully.";
+    LOG(DEBUG) << "assemble_cvd exited successfully.";
   }
 
-  std::vector<cvd::Subprocess> runners;
+  std::vector<cuttlefish::Subprocess> runners;
   for (int i = 0; i < FLAGS_num_instances; i++) {
-    cvd::SharedFD runner_stdin_in, runner_stdin_out;
-    cvd::SharedFD::Pipe(&runner_stdin_out, &runner_stdin_in);
-    std::string instance_name = std::to_string(i + vsoc::GetInstance());
+    cuttlefish::SharedFD runner_stdin_in, runner_stdin_out;
+    cuttlefish::SharedFD::Pipe(&runner_stdin_out, &runner_stdin_in);
+    std::string instance_name = std::to_string(i + FLAGS_base_instance_num);
     setenv("CUTTLEFISH_INSTANCE", instance_name.c_str(), /* overwrite */ 1);
 
     auto run_proc = StartRunner(std::move(runner_stdin_out),
                                 forwarder.ArgvForSubprocess(kRunnerBin));
     runners.push_back(std::move(run_proc));
-    if (cvd::WriteAll(runner_stdin_in, assembler_output) < 0) {
+    if (cuttlefish::WriteAll(runner_stdin_in, assembler_output) < 0) {
       int error_num = errno;
       LOG(ERROR) << "Could not write to run_cvd: " << strerror(error_num);
       return -1;
@@ -154,7 +252,7 @@
       run_cvd_failure = true;
       LOG(ERROR) << "run_cvd returned " << run_ret;
     } else {
-      LOG(INFO) << "run_cvd exited successfully.";
+      LOG(DEBUG) << "run_cvd exited successfully.";
     }
   }
   return run_cvd_failure ? -1 : 0;
diff --git a/host/commands/log_tee/Android.bp b/host/commands/log_tee/Android.bp
new file mode 100644
index 0000000..49b3e69
--- /dev/null
+++ b/host/commands/log_tee/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "log_tee",
+    srcs: [
+        "log_tee.cpp",
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libbase",
+        "libjsoncpp",
+        "libnl",
+    ],
+    static_libs: [
+        "libgflags",
+        "libcuttlefish_host_config",
+        "libcuttlefish_vm_manager",
+    ],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+}
diff --git a/host/commands/log_tee/log_tee.cpp b/host/commands/log_tee/log_tee.cpp
new file mode 100644
index 0000000..7021a99
--- /dev/null
+++ b/host/commands/log_tee/log_tee.cpp
@@ -0,0 +1,85 @@
+//
+// 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.
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/tee_logging.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+DEFINE_string(process_name, "", "The process to credit log messages to");
+DEFINE_int32(log_fd_in, -1, "The file descriptor to read logs from.");
+
+int main(int argc, char** argv) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  google::ParseCommandLineFlags(&argc, &argv, /* remove_flags */ true);
+
+  CHECK(FLAGS_log_fd_in >= 0) << "-log_fd_in is required";
+
+  auto config = cuttlefish::CuttlefishConfig::Get();
+
+  CHECK(config) << "Could not open cuttlefish config";
+
+  auto instance = config->ForDefaultInstance();
+
+  if (config->run_as_daemon()) {
+    android::base::SetLogger(
+        cuttlefish::LogToFiles({instance.launcher_log_path()}));
+  } else {
+    android::base::SetLogger(
+        cuttlefish::LogToStderrAndFiles({instance.launcher_log_path()}));
+  }
+
+  auto log_fd = cuttlefish::SharedFD::Dup(FLAGS_log_fd_in);
+  CHECK(log_fd->IsOpen()) << "Failed to dup log_fd_in: " <<  log_fd->StrError();
+  close(FLAGS_log_fd_in);
+
+  if (FLAGS_process_name.size() > 0) {
+    android::base::SetDefaultTag(FLAGS_process_name);
+  }
+
+  char buf[1 << 16];
+  ssize_t chars_read = 0;
+
+  LOG(DEBUG) << "Starting to read from process " << FLAGS_process_name;
+
+  while ((chars_read = log_fd->Read(buf, sizeof(buf))) > 0) {
+    auto trimmed = android::base::Trim(std::string(buf, chars_read));
+    // Newlines inside `trimmed` are handled by the android logging code.
+    // These checks attempt to determine the log severity coming from crosvm.
+    // There is no guarantee of success all the time since log line boundaries
+    // could be out sync with the reads, but that's ok.
+    if (android::base::StartsWith(trimmed, "[INFO")) {
+      LOG(INFO) << trimmed;
+    } else if (android::base::StartsWith(trimmed, "[ERROR")) {
+      LOG(ERROR) << trimmed;
+    } else if (android::base::StartsWith(trimmed, "[WARNING")) {
+      LOG(WARNING) << trimmed;
+    } else if (android::base::StartsWith(trimmed, "[VERBOSE")) {
+      LOG(VERBOSE) << trimmed;
+    } else {
+      LOG(DEBUG) << trimmed;
+    }
+  }
+
+  if (chars_read < 0) {
+    LOG(DEBUG) << "Failed to read from process " << FLAGS_process_name << ": "
+               << log_fd->StrError();
+  }
+
+  LOG(DEBUG) << "Finished reading from process " << FLAGS_process_name;
+}
diff --git a/host/commands/logcat_receiver/Android.bp b/host/commands/logcat_receiver/Android.bp
index 72438c7..305ab7f 100644
--- a/host/commands/logcat_receiver/Android.bp
+++ b/host/commands/logcat_receiver/Android.bp
@@ -13,24 +13,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "logcat_receiver",
     srcs: [
         "main.cpp",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
+        "libjsoncpp",
         "liblog",
         "libcuttlefish_utils",
     ],
     static_libs: [
         "libcuttlefish_host_config",
         "libgflags",
-        "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/logcat_receiver/main.cpp b/host/commands/logcat_receiver/main.cpp
index e07e3ec..b1c4d93 100644
--- a/host/commands/logcat_receiver/main.cpp
+++ b/host/commands/logcat_receiver/main.cpp
@@ -14,54 +14,70 @@
  * limitations under the License.
  */
 
-#include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <signal.h>
 
+#include <gflags/gflags.h>
+#include <android-base/logging.h>
+
+#include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/logging.h"
 
-DEFINE_int32(
-    server_fd, -1,
-    "File descriptor to an already created vsock server. Must be specified.");
+DEFINE_int32(log_pipe_fd, -1,
+             "A file descriptor representing a (UNIX) socket from which to "
+             "read the logs. If -1 is given the socket is created according to "
+             "the instance configuration");
 
 int main(int argc, char** argv) {
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  cuttlefish::DefaultSubprocessLogging(argv);
   google::ParseCommandLineFlags(&argc, &argv, true);
 
-  auto config = vsoc::CuttlefishConfig::Get();
+  auto config = cuttlefish::CuttlefishConfig::Get();
+
+  CHECK(config) << "Could not open cuttlefish config";
 
   auto instance = config->ForDefaultInstance();
+
+  // Disable default handling of SIGPIPE
+  struct sigaction new_action {
+  }, old_action{};
+  new_action.sa_handler = SIG_IGN;
+  sigaction(SIGPIPE, &new_action, &old_action);
+
+  cuttlefish::SharedFD pipe;
+  if (FLAGS_log_pipe_fd < 0) {
+    auto log_name = instance.logcat_pipe_name();
+    pipe = cuttlefish::SharedFD::Open(log_name.c_str(), O_RDONLY);
+  } else {
+    pipe = cuttlefish::SharedFD::Dup(FLAGS_log_pipe_fd);
+    close(FLAGS_log_pipe_fd);
+  }
+
+  if (!pipe->IsOpen()) {
+    LOG(ERROR) << "Error opening log pipe: " << pipe->StrError();
+    return 2;
+  }
+
   auto path = instance.logcat_path();
   auto logcat_file =
-      cvd::SharedFD::Open(path.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0666);
-  CHECK(logcat_file->IsOpen())
-      << "Unable to open logcat file: " << logcat_file->StrError();
-
-  cvd::SharedFD server_fd = cvd::SharedFD::Dup(FLAGS_server_fd);
-  close(FLAGS_server_fd);
-
-  CHECK(server_fd->IsOpen()) << "Error creating or inheriting logcat server: "
-                             << server_fd->StrError();
+      cuttlefish::SharedFD::Open(path.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0666);
 
   // Server loop
   while (true) {
-    auto conn = cvd::SharedFD::Accept(*server_fd);
-
-    while (true) {
-      char buff[1024];
-      auto read = conn->Read(buff, sizeof(buff));
-      if (read <= 0) {
-        // Close here to ensure the other side gets reset if it's still
-        // connected
-        conn->Close();
-        LOG(WARNING) << "Detected close from the other side";
-        break;
-      }
-      auto written = logcat_file->Write(buff, read);
-      CHECK(written == read)
-          << "Error writing to log file: " << logcat_file->StrError()
-          << ". This is unrecoverable.";
+    char buff[1024];
+    auto read = pipe->Read(buff, sizeof(buff));
+    if (read < 0) {
+      LOG(ERROR) << "Could not read logcat: " << pipe->StrError();
+      break;
     }
+    auto written = cuttlefish::WriteAll(logcat_file, buff, read);
+    CHECK(written == read)
+        << "Error writing to log file: " << logcat_file->StrError()
+        << ". This is unrecoverable.";
   }
+
+  logcat_file->Close();
+  pipe->Close();
   return 0;
 }
diff --git a/host/commands/metrics/Android.bp b/host/commands/metrics/Android.bp
new file mode 100644
index 0000000..67eb3b0
--- /dev/null
+++ b/host/commands/metrics/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "metrics",
+    srcs: [
+        "metrics.cc",
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libbase",
+        "libjsoncpp",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/commands/metrics/metrics.cc b/host/commands/metrics/metrics.cc
new file mode 100644
index 0000000..378155c
--- /dev/null
+++ b/host/commands/metrics/metrics.cc
@@ -0,0 +1,56 @@
+//
+// 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.
+
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+#include <android-base/logging.h>
+
+#include "common/libs/utils/tee_logging.h"
+#include "host/commands/metrics/metrics_defs.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+using cuttlefish::MetricsExitCodes;
+
+int main(int argc, char** argv) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  auto config = cuttlefish::CuttlefishConfig::Get();
+
+  CHECK(config) << "Could not open cuttlefish config";
+
+  auto instance = config->ForDefaultInstance();
+  auto metrics_log_path = instance.PerInstancePath("metrics.log");
+
+  if (config->run_as_daemon()) {
+    android::base::SetLogger(
+        cuttlefish::LogToFiles({metrics_log_path, instance.launcher_log_path()}));
+  } else {
+    android::base::SetLogger(
+        cuttlefish::LogToStderrAndFiles(
+            {metrics_log_path, instance.launcher_log_path()}));
+  }
+
+  if (config->enable_metrics() != cuttlefish::CuttlefishConfig::kYes) {
+    LOG(ERROR) << "metrics not enabled, but metrics were launched.";
+    return cuttlefish::MetricsExitCodes::kInvalidHostConfiguration;
+  }
+
+  while (true) {
+    // do nothing
+    sleep(std::numeric_limits<unsigned int>::max());
+  }
+  return cuttlefish::MetricsExitCodes::kMetricsError;
+}
diff --git a/host/commands/metrics/metrics_defs.h b/host/commands/metrics/metrics_defs.h
new file mode 100644
index 0000000..f36b3a0
--- /dev/null
+++ b/host/commands/metrics/metrics_defs.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+
+namespace cuttlefish {
+
+enum MetricsExitCodes : int {
+  kSuccess=0,
+  kMetricsError=1,
+  kInvalidHostConfiguration=2,
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/metrics/proto/Android.bp b/host/commands/metrics/proto/Android.bp
new file mode 100644
index 0000000..250abcf
--- /dev/null
+++ b/host/commands/metrics/proto/Android.bp
@@ -0,0 +1,63 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_shared {
+    name: "cf_proto",
+    vendor_available: true,
+
+    srcs: [
+        "*.proto",
+    ],
+
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libbase",
+        "libprotobuf-cpp-lite",
+        "libprotobuf-cpp-full",
+    ],
+
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+        "libjsoncpp",
+    ],
+
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+        canonical_path_from_root: false,
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    cppflags: [
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-format",
+        "-Wno-c++98-compat-pedantic",
+        "-Wno-float-conversion",
+        "-Wno-disabled-macro-expansion",
+        "-Wno-float-equal",
+        "-Wno-sign-conversion",
+        "-Wno-padded",
+        "-Wno-old-style-cast",
+        "-Wno-undef",
+    ],
+
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/commands/metrics/proto/cf_log.proto b/host/commands/metrics/proto/cf_log.proto
new file mode 100644
index 0000000..46659fb
--- /dev/null
+++ b/host/commands/metrics/proto/cf_log.proto
@@ -0,0 +1,42 @@
+syntax = "proto2";
+
+package cuttlefish;
+
+import "common.proto";
+import "cf_metrics_event.proto";
+
+// Wrapper for Cuttlefish log events
+// Next index: 7
+message CuttlefishLogEvent {
+  // Defines the device class that this log was sourced from.
+  // This may not be the same device which uploaded the log event.
+  // Next index: 3
+  enum DeviceType {
+    // The log event was sourced from an unspecified device type.
+    CUTTLEFISH_DEVICE_TYPE_UNSPECIFIED = 0;
+
+    // A log event that was sourced from a Cuttlefish host device.
+    CUTTLEFISH_DEVICE_TYPE_HOST = 1;
+
+    // A log event that was sent by an Cuttlefish guest device.
+    CUTTLEFISH_DEVICE_TYPE_GUEST = 2;
+  }
+
+  // Local time on the event source device of when this event occurred.
+  optional Timestamp timestamp_ms = 1;
+
+  // The type of device this log event originated from.
+  optional DeviceType device_type = 2;
+
+  // The identifier for this device.
+  optional string device_id = 3;
+
+  // The identifier for this session.
+  optional string session_id = 6;
+
+  // The version of Cuttlefish that's sending the log event.
+  optional string cuttlefish_version = 4;
+
+  // An event encompassing metrics data
+  optional MetricsEvent metrics_event = 5;
+}
diff --git a/host/commands/metrics/proto/cf_metrics_event.proto b/host/commands/metrics/proto/cf_metrics_event.proto
new file mode 100644
index 0000000..7129c23
--- /dev/null
+++ b/host/commands/metrics/proto/cf_metrics_event.proto
@@ -0,0 +1,143 @@
+syntax = "proto2";
+
+package cuttlefish;
+
+import "common.proto";
+
+// Wrapper for Cuttlefish Metrics log events.
+// Next index: 22
+message MetricsEvent {
+  // High level event types for this message. This is the broadest
+  // category identifier for MetricsEvent and should be used to indicate
+  // which other fields will be populated. Only used in field event_type.
+  // Next index: 6
+  enum EventType {
+    // An unspecified, unhandled event.
+    CUTTLEFISH_EVENT_TYPE_UNSPECIFIED = 0;
+
+    // The device experienced an error.
+    CUTTLEFISH_EVENT_TYPE_ERROR = 1;
+
+    // The event type is the time the VM instance is instantiated.
+    CUTTLEFISH_EVENT_TYPE_VM_INSTANTIATION = 2;
+
+    // The event type is the time the device boot process is started.
+    CUTTLEFISH_EVENT_TYPE_DEVICE_BOOT = 3;
+
+    // The event type is the time the device lock screen is available.
+    CUTTLEFISH_EVENT_TYPE_LOCK_SCREEN_AVAILABLE = 4;
+
+    // The event type is the time the virtual device was stopped.
+    CUTTLEFISH_EVENT_TYPE_VM_STOP = 5;
+  }
+
+  // Defines the OS that this log was sourced from.
+  // This may not be the same OS which uploaded the log event.
+  // Next index: 5
+  enum OsType {
+    // The log event was sourced from an unspecified os type.
+    CUTTLEFISH_OS_TYPE_UNSPECIFIED = 0;
+
+    // The log event was sourced from Linux x86 os type.
+    CUTTLEFISH_OS_TYPE_LINUX_X86 = 1;
+
+    // The log event was sourced from Linux x86_64 os type.
+    CUTTLEFISH_OS_TYPE_LINUX_X86_64 = 2;
+
+    // The log event was sourced from Linux aarch32 os type.
+    CUTTLEFISH_OS_TYPE_LINUX_AARCH32 = 3;
+
+    // The log event was sourced from Linux aarch64 os type.
+    CUTTLEFISH_OS_TYPE_LINUX_AARCH64 = 4;
+  }
+
+  // Defines the VMM that this log was sourced from.
+  // This may not be the same VMM which uploaded the log event.
+  // Next index: 3
+  enum VmmType {
+    // The log event was sourced from an unspecified vmm type.
+    CUTTLEFISH_VMM_TYPE_UNSPECIFIED = 0;
+
+    // The log event was sourced from a CrOS VM vmm type.
+    CUTTLEFISH_VMM_TYPE_CROSVM = 1;
+
+    // The log event was sourced from a QEMU vmm type.
+    CUTTLEFISH_VMM_TYPE_QEMU = 2;
+  }
+
+  // High level error types for this message. Defines the error
+  // the device received when it experienced an error. This field
+  // should only be present when event_type is ERROR.
+  // Next index: 1
+  enum ErrorType {
+    // An unspecified, unhandled error.
+    CUTTLEFISH_ERROR_TYPE_UNSPECIFIED = 0;
+  }
+
+  // Defines the type of device event contained in this message.
+  // This is the highest level identifier for MetricsEvent messages.
+  optional EventType event_type = 1;
+
+  // Defines the error the device received when it experienced an error.
+  // The field should only be present when event_type is ERROR.
+  optional ErrorType error_type = 2;
+
+  // Time the event occurred in milliseconds since Unix epoch.
+  optional Timestamp event_time_ms = 3;
+
+  // Elapsed time for the event in milliseconds.
+  optional Duration elapsed_time_ms = 4;
+
+  // The type of OS this log event originated from.
+  optional OsType os_type = 5;
+
+  // OS version for the host/guest operating system.
+  // Ex. Android version (9.x, 10.x, etc.) or `uname -r` output
+  optional string os_version = 6;
+
+  // Android guest API level
+  optional int32 api_level = 7;
+
+  // The type of VMM this log event originated from.
+  optional VmmType vmm_type = 8;
+
+  // The version of the VMM that's sending the log event.
+  optional string vmm_version = 9;
+
+  // The company that's sending the log event.
+  optional string company = 10;
+
+  // The allowlist of launch_cvd flags attached to the launch_cvd command
+  // associated with this instance
+  repeated string launch_cvd_flags = 11;
+
+  // Exists a -system_image_dir specified in launch_cvd
+  optional bool exists_system_image_spec = 12;
+
+  // Exists a -boot_image specified in launch_cvd
+  optional bool exists_boot_image_spec = 13;
+
+  // Exists a -bootloader specified in launch_cvd
+  optional bool exists_bootloader_spec = 14;
+
+  // Exists a -composite_disk specified in launch_cvd
+  optional bool exists_composite_disk_spec = 15;
+
+  // Exists a -data_image specified in launch_cvd
+  optional bool exists_data_image_spec = 16;
+
+  // Exists a -metadata_image specified in launch_cvd
+  optional bool exists_metadata_image_spec = 17;
+
+  // Exists a -misc_image specified in launch_cvd
+  optional bool exists_misc_image_spec = 18;
+
+  // Exists a -qemu_binary specified in launch_cvd
+  optional bool exists_qemu_binary_spec = 19;
+
+  // Exists a -super_image specified in launch_cvd
+  optional bool exists_super_image_spec = 20;
+
+  // Exists a -vendor_boot_image specified in launch_cvd
+  optional bool exists_vendor_boot_image_spec = 21;
+}
diff --git a/host/commands/metrics/proto/clientanalytics.proto b/host/commands/metrics/proto/clientanalytics.proto
new file mode 100644
index 0000000..955a15c
--- /dev/null
+++ b/host/commands/metrics/proto/clientanalytics.proto
@@ -0,0 +1,21 @@
+syntax = "proto2";
+
+message LogRequest {
+  optional ClientInfo client_info = 1;
+  optional int32 log_source = 2;
+  optional int64 request_time_ms = 4;
+  repeated LogEvent log_event = 3;
+}
+
+message ClientInfo {
+  optional int32 client_type = 1;
+}
+
+message LogResponse {
+  optional int64 next_request_wait_millis = 1;
+}
+
+message LogEvent {
+  optional int64 event_time_ms = 1;
+  optional bytes source_extension = 6;
+}
diff --git a/host/commands/metrics/proto/common.proto b/host/commands/metrics/proto/common.proto
new file mode 100644
index 0000000..6ad0380
--- /dev/null
+++ b/host/commands/metrics/proto/common.proto
@@ -0,0 +1,16 @@
+syntax = "proto2";
+
+message Duration {
+  required int64 seconds = 1;
+  required int32 nanos = 2;
+}
+
+message Timestamp {
+  required int64 seconds = 1;
+  required int32 nanos = 2;
+}
+
+enum UserType {
+  GOOGLE = 0;
+  EXTERNAL = 1;
+}
diff --git a/host/commands/mk_cdisk/Android.bp b/host/commands/mk_cdisk/Android.bp
new file mode 100644
index 0000000..a0cf8ba
--- /dev/null
+++ b/host/commands/mk_cdisk/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2021 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "mk_cdisk",
+    srcs: [
+        "mk_cdisk.cc",
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libbase",
+        "libjsoncpp",
+        "liblog",
+        "libz",
+    ],
+    static_libs: [
+        "libcdisk_spec",
+        "libext2_uuid",
+        "libimage_aggregator",
+        "libprotobuf-cpp-lite",
+        "libsparse",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/commands/mk_cdisk/mk_cdisk.cc b/host/commands/mk_cdisk/mk_cdisk.cc
new file mode 100644
index 0000000..028547c
--- /dev/null
+++ b/host/commands/mk_cdisk/mk_cdisk.cc
@@ -0,0 +1,146 @@
+//
+// Copyright (C) 2021 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.
+
+#include <fstream>
+#include <iostream>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/result.h>
+#include <json/json.h>
+
+#include "common/libs/utils/files.h"
+#include "host/libs/image_aggregator/image_aggregator.h"
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+using cuttlefish::CreateCompositeDisk;
+using cuttlefish::FileExists;
+using cuttlefish::ImagePartition;
+using cuttlefish::kLinuxFilesystem;
+
+// Returns `append` is appended to the end of filename preserving the extension.
+std::string AppendFileName(const std::string& filename,
+                           const std::string& append) {
+  size_t pos = filename.find_last_of('.');
+  if (pos == std::string::npos) {
+    return filename + append;
+  } else {
+    return filename.substr(0, pos) + append + filename.substr(pos);
+  }
+}
+
+// config JSON schema:
+// {
+//   "partitions": [
+//     {
+//       "label": string,
+//       "path": string,
+//       "writable": bool, // optional. defaults to false.
+//     }
+//   ]
+// }
+
+Result<std::vector<ImagePartition>> LoadConfig(std::istream& in) {
+  std::vector<ImagePartition> partitions;
+
+  Json::CharReaderBuilder builder;
+  Json::Value root;
+  Json::String errs;
+  if (!parseFromStream(builder, in, &root, &errs)) {
+    return Error() << "bad config: " << errs;
+  }
+  for (const Json::Value& part : root["partitions"]) {
+    const std::string label = part["label"].asString();
+    const std::string path = part["path"].asString();
+    const bool writable =
+        part["writable"].asBool();  // default: false (if null)
+
+    if (!FileExists(path)) {
+      return Error() << "bad config: Can't find \'" << path << '\'';
+    }
+    partitions.push_back(
+        ImagePartition{label, path, kLinuxFilesystem, .read_only = !writable});
+  }
+
+  if (partitions.empty()) {
+    return Error() << "bad config: no partitions";
+  }
+  return partitions;
+}
+
+Result<std::vector<ImagePartition>> LoadConfig(const std::string& config_file) {
+  if (config_file == "-") {
+    return LoadConfig(std::cin);
+  } else {
+    std::ifstream in(config_file);
+    if (!in) {
+      return ErrnoError() << "Can't open file \'" << config_file << '\'';
+    }
+    return LoadConfig(in);
+  }
+}
+
+struct CompositeDiskArgs {
+  std::string config_file;
+  std::string output_file;
+};
+
+Result<CompositeDiskArgs> ParseCompositeDiskArgs(int argc, char** argv) {
+  if (argc != 3) {
+    std::cerr << fmt::format(
+        "Usage: {0} <config_file> <output_file>\n"
+        "   or  {0} - <output_file>  (read config from STDIN)\n",
+        argv[0]);
+    return Error() << "missing arguments.";
+  }
+  CompositeDiskArgs args{
+      .config_file = argv[1],
+      .output_file = argv[2],
+  };
+  return args;
+}
+
+Result<void> MakeCompositeDiskMain(int argc, char** argv) {
+  setenv("ANDROID_LOG_TAGS", "*:v", /* overwrite */ 0);
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+
+  auto args = ParseCompositeDiskArgs(argc, argv);
+  if (!args.ok()) {
+    return args.error();
+  }
+  auto partitions = LoadConfig(args->config_file);
+  if (!partitions.ok()) {
+    return partitions.error();
+  }
+
+  // We need two implicit output paths: GPT header/footer
+  // e.g. out.img will have out-header.img and out-footer.img
+  std::string gpt_header = AppendFileName(args->output_file, "-header");
+  std::string gpt_footer = AppendFileName(args->output_file, "-footer");
+  CreateCompositeDisk(*partitions, gpt_header, gpt_footer, args->output_file);
+  return {};
+}
+
+int main(int argc, char** argv) {
+  auto result = MakeCompositeDiskMain(argc, argv);
+  if (!result.ok()) {
+    LOG(ERROR) << result.error();
+    return EXIT_FAILURE;
+  }
+  return 0;
+}
diff --git a/host/commands/modem_simulator/Android.bp b/host/commands/modem_simulator/Android.bp
new file mode 100644
index 0000000..c0d0371
--- /dev/null
+++ b/host/commands/modem_simulator/Android.bp
@@ -0,0 +1,126 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+    name: "modem_simulator_base",
+    srcs: [
+        "channel_monitor.cpp",
+        "thread_looper.cpp",
+        "command_parser.cpp",
+        "modem_simulator.cpp",
+        "modem_service.cpp",
+        "sim_service.cpp",
+        "network_service.cpp",
+        "misc_service.cpp",
+        "call_service.cpp",
+        "data_service.cpp",
+        "sms_service.cpp",
+        "sup_service.cpp",
+        "stk_service.cpp",
+        "pdu_parser.cpp",
+        "cf_device_config.cpp",
+        "nvram_config.cpp"
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libbase",
+        "libjsoncpp",
+        "libnl",
+        "libcuttlefish_device_config",
+        "libcuttlefish_device_config_proto",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+        "libtinyxml2",
+    ],
+    cflags: ["-Werror", "-Wall", "-fexceptions"],
+    defaults: ["cuttlefish_host"],
+}
+
+cc_binary {
+    name: "modem_simulator",
+    srcs: [
+        "main.cpp"
+    ],
+    defaults: ["cuttlefish_host", "modem_simulator_base"],
+}
+
+prebuilt_etc {
+    name: "iccprofile_for_sim0.xml",
+    vendor: true,
+    src: "files/iccprofile_for_sim0.xml",
+    filename: "iccprofile_for_sim0.xml",
+    sub_dir: "modem_simulator/files",
+}
+
+prebuilt_etc {
+    name: "iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml",
+    vendor: true,
+    src: "files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml",
+    filename: "iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml",
+    sub_dir: "modem_simulator/files",
+}
+
+prebuilt_etc {
+    name: "numeric_operator.xml",
+    vendor: true,
+    src: "files/numeric_operator.xml",
+    filename: "numeric_operator.xml",
+    sub_dir: "modem_simulator/files",
+}
+
+prebuilt_etc_host {
+    name: "iccprofile_for_sim0.xml_host",
+    src: "files/iccprofile_for_sim0.xml",
+    filename: "iccprofile_for_sim0.xml",
+    sub_dir: "modem_simulator/files",
+}
+
+prebuilt_etc_host {
+    name: "iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml_host",
+    src: "files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml",
+    filename: "iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml",
+    sub_dir: "modem_simulator/files",
+}
+
+prebuilt_etc_host {
+    name: "numeric_operator.xml_host",
+    src: "files/numeric_operator.xml",
+    filename: "numeric_operator.xml",
+    sub_dir: "modem_simulator/files",
+}
+
+cc_test_host {
+    name: "modem_simulator_test",
+    srcs: [
+        "unittest/main_test.cpp",
+        "unittest/service_test.cpp",
+        "unittest/command_parser_test.cpp",
+        "unittest/pdu_parser_test.cpp",
+    ],
+    include_dirs: [
+        "device/google/cuttlefish/host/commands",
+    ],
+    defaults: ["cuttlefish_host", "modem_simulator_base"],
+    whole_static_libs: [
+        "libc++fs"
+    ],
+}
diff --git a/host/commands/modem_simulator/call_service.cpp b/host/commands/modem_simulator/call_service.cpp
new file mode 100644
index 0000000..678da4f
--- /dev/null
+++ b/host/commands/modem_simulator/call_service.cpp
@@ -0,0 +1,719 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/call_service.h"
+
+#include <android-base/logging.h>
+
+#include <chrono>
+#include <iostream>
+#include <thread>
+
+#include "host/commands/modem_simulator/nvram_config.h"
+
+namespace cuttlefish {
+
+CallService::CallService(int32_t service_id, ChannelMonitor* channel_monitor,
+                         ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {
+  InitializeServiceState();
+}
+
+void CallService::InitializeServiceState() {
+  auto nvram_config = NvramConfig::Get();
+  auto instance = nvram_config->ForInstance(service_id_);
+  in_emergency_mode_ = instance.emergency_mode();
+
+  last_active_call_index_ = 1;
+  mute_on_ = false;
+}
+
+void CallService::SetupDependency(SimService* sim, NetworkService* net) {
+  sim_service_ = sim;
+  network_service_ = net;
+}
+
+std::vector<CommandHandler> CallService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      CommandHandler("D",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleDial(client, cmd);
+                     }),
+      CommandHandler(
+          "A",
+          [this](const Client& client) { this->HandleAcceptCall(client); }),
+      CommandHandler(
+          "H",
+          [this](const Client& client) { this->HandleRejectCall(client); }),
+      CommandHandler(
+          "+CLCC",
+          [this](const Client& client) { this->HandleCurrentCalls(client); }),
+      CommandHandler("+CHLD=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleHangup(client, cmd);
+                     }),
+      CommandHandler("+CMUT",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleMute(client, cmd);
+                     }),
+      CommandHandler("+VTS=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSendDtmf(client, cmd);
+                     }),
+      CommandHandler("+CUSD=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleCancelUssd(client, cmd);
+                     }),
+      CommandHandler("+WSOS=0",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleEmergencyMode(client, cmd);
+                     }),
+      CommandHandler("+REMOTECALL",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleRemoteCall(client, cmd);
+                     }),
+  };
+  return (command_handlers);
+}
+
+// This also resumes held calls
+void CallService::SimulatePendingCallsAnswered() {
+  for (auto& iter : active_calls_) {
+    if (iter.second.isCallDialing()) {
+      iter.second.SetCallActive();
+    }
+  }
+}
+
+void CallService::TimerWaitingRemoteCallResponse(CallToken call_token) {
+  LOG(DEBUG) << "Dialing id: " << call_token.first
+             << ", number: " << call_token.second << "timeout, cancel";
+  auto iter = active_calls_.find(call_token.first);
+  if (iter != active_calls_.end() && iter->second.number == call_token.second) {
+    if (iter->second.remote_client != std::nullopt) {
+      CloseRemoteConnection(*(iter->second.remote_client));
+    }
+    active_calls_.erase(iter);  // match
+    CallStateUpdate();
+  }  // else not match, ignore
+}
+
+/* ATD */
+void CallService::HandleDial(const Client& client, const std::string& command) {
+  // Check the network registration state
+  auto registration_state = NetworkService::NET_REGISTRATION_UNKNOWN;
+  if (network_service_) {
+    registration_state = network_service_->GetVoiceRegistrationState();
+  }
+
+  bool emergency_only = false;
+  if (registration_state == NetworkService::NET_REGISTRATION_HOME ||
+      registration_state == NetworkService::NET_REGISTRATION_ROAMING) {
+    emergency_only = false;
+  } else if (registration_state == NetworkService::NET_REGISTRATION_EMERGENCY) {
+    emergency_only = true;
+  } else {
+    client.SendCommandResponse(kCmeErrorNoNetworkService);
+    return;
+  }
+
+  CommandParser cmd(command);
+  cmd.SkipPrefixAT();
+
+  std::string number;
+  bool emergency_number = false;
+  /**
+   * Normal dial:     ATDnumber[clir];
+   * Emergency dial:  ATDnumber@[category],#[clir];
+   */
+  auto pos = cmd->find_last_of('@');
+  if (pos != std::string_view::npos) {
+    emergency_number = true;
+    number = cmd->substr(1, pos -1); // Skip 'D' and ignore category, clir
+  } else {  // Remove 'i' or 'I' or ';'
+    pos = cmd->find_last_of('i');
+    if (pos == std::string_view::npos) {
+      pos = cmd->find_last_of('I');
+      if (pos == std::string_view::npos) {
+        pos = cmd->find_last_of(';');
+      }
+    }
+    if (pos == std::string_view::npos) {
+      number = cmd->substr(1);
+    } else {
+      number = cmd->substr(1, pos -1);
+    }
+  }
+
+  // Check the number is valid digits or not
+  if (strspn(number.c_str(), "1234567890") != number.size()) {
+    client.SendCommandResponse(kCmeErrorInCorrectParameters);
+    return;
+  }
+
+  if (emergency_only && !emergency_number) {
+    client.SendCommandResponse(kCmeErrorNetworkNotAllowedEmergencyCallsOnly);
+    return;
+  }
+
+  // If the number is not emergency number, FDN enabled and the number is not in
+  // the fdn list, return kCmeErrorFixedDialNumberOnlyAllowed.
+  if (!emergency_number && sim_service_->IsFDNEnabled() &&
+      !sim_service_->IsFixedDialNumber(number)) {
+    client.SendCommandResponse(kCmeErrorFixedDialNumberOnlyAllowed);
+    return;
+  }
+
+  int port = 0;
+  if (number.length() == 11) {
+    port = std::stoi(number.substr(7));
+  } else if (number.length() == 4) {
+    port = std::stoi(number);
+  }
+
+  if (port >= kRemotePortRange.first &&
+      port <= kRemotePortRange.second) {  // May be a remote call
+    std::stringstream ss;
+    ss << port;
+    auto remote_port = ss.str();
+    auto remote_client = ConnectToRemoteCvd(remote_port);
+    if (!remote_client->IsOpen()) {
+      client.SendCommandResponse(kCmeErrorNoNetworkService);
+      return;
+    }
+    auto local_host_port = GetHostPort();
+    if (local_host_port == remote_port) {
+      client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+      return;
+    }
+
+    if (channel_monitor_) {
+      channel_monitor_->SetRemoteClient(remote_client, false);
+    }
+
+    ss.clear();
+    ss.str("");
+    ss << "AT+REMOTECALL=4,0,0,\"" << local_host_port << "\",129";
+
+    SendCommandToRemote(remote_client, "REM0");
+    SendCommandToRemote(remote_client, ss.str());
+
+    CallStatus call_status(remote_port);
+    call_status.is_remote_call = true;
+    call_status.is_mobile_terminated = false;
+    call_status.call_state = CallStatus::CALL_STATE_DIALING;
+    call_status.remote_client = remote_client;
+    int index = last_active_call_index_++;
+
+    auto call_token = std::make_pair(index, call_status.number);
+    call_status.timeout_serial = thread_looper_->PostWithDelay(
+        std::chrono::minutes(1),
+        makeSafeCallback<CallService>(this, [call_token](CallService* me) {
+          me->TimerWaitingRemoteCallResponse(call_token);
+        }));
+
+    active_calls_[index] = call_status;
+  } else {
+    CallStatus call_status(number);
+    call_status.is_mobile_terminated = false;
+    call_status.call_state = CallStatus::CALL_STATE_DIALING;
+    auto index = last_active_call_index_++;
+    active_calls_[index] = call_status;
+
+    if (emergency_number) {
+      in_emergency_mode_ = true;
+      SendUnsolicitedCommand("+WSOS: 1");
+    }
+    thread_looper_->PostWithDelay(std::chrono::seconds(1),
+        makeSafeCallback(this, &CallService::SimulatePendingCallsAnswered));
+  }
+
+  client.SendCommandResponse("OK");
+  std::this_thread::sleep_for(std::chrono::seconds(2));
+}
+
+void CallService::SendCallStatusToRemote(CallStatus& call,
+                                         CallStatus::CallState state) {
+  if (call.is_remote_call && call.remote_client != std::nullopt) {
+    std::stringstream ss;
+    ss << "AT+REMOTECALL=" << state << ","
+                           << call.is_voice_mode << ","
+                           << call.is_multi_party << ",\""
+                           << GetHostPort() << "\","
+                           << call.is_international;
+
+    SendCommandToRemote(*(call.remote_client), ss.str());
+    if (state == CallStatus::CALL_STATE_HANGUP) {
+      CloseRemoteConnection(*(call.remote_client));
+    }
+  }
+}
+
+/* ATA */
+void CallService::HandleAcceptCall(const Client& client) {
+  for (auto& iter : active_calls_) {
+    if (iter.second.isCallIncoming()) {
+      iter.second.SetCallActive();
+      SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_ACTIVE);
+    } else if (iter.second.isCallActive()) {
+      iter.second.SetCallBackground();
+      SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_HELD);
+    }
+  }
+
+  client.SendCommandResponse("OK");
+}
+
+/* ATH */
+void CallService::HandleRejectCall(const Client& client) {
+  for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
+    /* ATH: hangup, since user is busy */
+    if (iter->second.isCallIncoming()) {
+      SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
+      iter = active_calls_.erase(iter);
+    } else {
+      ++iter;
+    }
+  }
+
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * AT+CLCC
+ *   Returns list of current calls of MT. If command succeeds but no
+ *   calls are available, no information response is sent to TE.
+ *
+ *   command             Possible response(s)
+ *   AT+CLCC               [+CLCC: <ccid1>,<dir>,<stat>,<mode>,<mpty>
+ *                         [,<number>,<type>[,<alpha>[,<priority>
+ *                         [,<CLI validity>]]]][<CR><LF>
+ *                         +CLCC: <ccid2>,<dir>,<stat>,<mode>,<mpty>
+ *                         [,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
+ *                         +CME ERROR: <err>
+ *
+ * <ccidx>: integer type. This number can be used in +CHLD command
+ * operations. Value range is from 1 to N. N, the maximum number of
+ * simultaneous call control processes is implementation specific.
+ * <dir>: integer type
+ *       0 mobile originated (MO) call
+         1 mobile terminated (MT) call
+ * <stat>: integer type (state of the call)
+ *       0 active
+ *       1 held
+ *       2 dialing (MO call)
+ *       3 alerting (MO call)
+ *       4 incoming (MT call)
+ *       5 waiting (MT call)
+ * <mode>: integer type (bearer/teleservice)
+ *       0 voice
+ *       1 data
+ *       2 fax
+ *       3 voice followed by data, voice mode
+ *       4 alternating voice/data, voice mode
+ *       5 alternating voice/fax, voice mode
+ *       6 voice followed by data, data mode
+ *       7 alternating voice/data, data mode
+ *       8 alternating voice/fax, fax mode
+ *       9 unknown
+ * <mpty>: integer type
+ *       0 call is not one of multiparty (conference) call parties
+ *       1 call is one of multiparty (conference) call parties
+ * <number>: string type phone number in format specified by <type>.
+ * <type>: type of address octet in integer format
+ *
+ *see RIL_REQUEST_GET_CURRENT_CALLS in RIL
+ */
+void CallService::HandleCurrentCalls(const Client& client) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  // AT+CLCC
+  // [+CLCC: <ccid1>,<dir>,<stat>,<mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
+  // [+CLCC: <ccid2>,<dir>,<stat>,<mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
+  // [...]]]
+  for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
+    int index = iter->first;
+    int dir = iter->second.is_mobile_terminated;
+    CallStatus::CallState call_state = iter->second.call_state;
+    int mode = iter->second.is_voice_mode;
+    int mpty = iter->second.is_multi_party;
+    int type = iter->second.is_international ? 145 : 129;
+    std::string number = iter->second.number;
+
+    ss.clear();
+    ss << "+CLCC: " << index << "," << dir << "," << call_state << ","
+        << mode << "," << mpty << "," << number<<  "," << type;
+    responses.push_back(ss.str());
+    ss.str("");
+  }
+
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CHLD
+ *   This command allows the control of the following call related services:
+ *   1) a call can be temporarily disconnected from the MT but the connection
+ *      is retained by the network;
+ *   2) multiparty conversation (conference calls);
+ *   3) the served subscriber who has two calls (one held and the other
+ *     either active or alerting) can connect the other parties and release
+ *     the served subscriber's own connection.
+ *
+ *   Calls can be put on hold, recovered, released, added to conversation,
+ *   and transferred similarly.
+ *
+ *   command             Possible response(s)
+ *   +CHLD=<n>           +CME ERROR: <err>
+ *
+ *   +CHLD=?             +CHLD: (list of supported <n>s)
+ *   e.g. +CHLD: (0,1,1x,2,2x,3,4)
+ *
+ *
+ * see RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND
+ *     RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
+ *     RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE
+ *     RIL_REQUEST_CONFERENCE
+ *     RIL_REQUEST_SEPARATE_CONNECTION
+ *     RIL_REQUEST_HANGUP
+ *     RIL_REQUEST_UDUB in RIL
+ */
+void CallService::HandleHangup(const Client& client,
+                               const std::string& command) {
+  std::vector<std::string> responses;
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  std::string action(*cmd);
+  int n = std::stoi(action.substr(0, 1));
+  int index = -1;
+  if (cmd->length() > 1) {
+    index = std::stoi(action.substr(1));
+  }
+
+  switch (n) {
+    case 0:  // Release all held calls or set User Determined User Busy(UDUB) for a waiting call
+      for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
+        if (iter->second.isCallIncoming() ||
+            iter->second.isCallBackground() ||
+            iter->second.isCallWaiting()) {
+          SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
+          iter = active_calls_.erase(iter);
+        } else {
+          ++iter;
+        }
+      }
+      break;
+    case 1:
+      if (index == -1) {  // Release all active calls and accepts the other(hold or waiting) call
+        for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
+          if (iter->second.isCallActive()) {
+            SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
+            iter = active_calls_.erase(iter);
+            continue;
+          } else if (iter->second.isCallBackground() ||
+              iter->second.isCallWaiting()) {
+            iter->second.SetCallActive();
+            SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
+          }
+          ++iter;
+        }
+      } else {  // Release a specific active call
+        auto iter = active_calls_.find(index);
+        if (iter != active_calls_.end()) {
+          SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
+          active_calls_.erase(iter);
+        }
+      }
+      break;
+    case 2:
+      if (index == -1) {  // Place all active calls and the waiting calls, activates all held calls
+        for (auto& iter : active_calls_) {
+          if (iter.second.isCallActive() || iter.second.isCallWaiting()) {
+            iter.second.SetCallBackground();
+            SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_HELD);
+          } else if (iter.second.isCallBackground()) {
+            iter.second.SetCallActive();
+            SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_ACTIVE);
+          }
+        }
+      } else {  // Disconnect a call from the conversation
+        auto iter = active_calls_.find(index);
+        if (iter != active_calls_.end()) {
+          SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
+          active_calls_.erase(iter);
+        }
+      }
+      break;
+    case 3:  // Adds an held call to the conversation
+      for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
+        if (iter->second.isCallBackground()) {
+          iter->second.SetCallActive();
+          SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
+        }
+      }
+      break;
+    case 4:  // Connect the two calls
+      for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
+        if (iter->second.isCallBackground()) {
+          iter->second.SetCallActive();
+          SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
+        }
+      }
+      break;
+    default:
+      client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+      return;
+  }
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * AT+CMUT
+ *   This command is used to enable and disable the uplink voice muting
+ * during a voice call.
+ *   Read command returns the current value of <n>.
+ *
+ * Command          Possible response(s)
+ * +CMUT=[<n>]        +CME ERROR: <err>
+ * +CMUT?             +CMUT: <n>
+ *                    +CME ERROR: <err>
+ *
+ * <n>: integer type
+ *   0 mute off
+ *   1 mute on
+ *
+ * see RIL_REQUEST_SET_MUTE or RIL_REQUEST_GET_MUTE in RIL
+ */
+void CallService::HandleMute(const Client& client, const std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // If AT+CMUT?, it remains AT+CMUT?
+
+  if (cmd == "AT+CMUT?") {
+    ss << "+CMUT: " << mute_on_;
+    responses.push_back(ss.str());
+  } else {  // AT+CMUT = <n>
+    int n = cmd.GetNextInt();
+    switch (n) {
+      case 0:  // Mute off
+        mute_on_ = false;
+        break;
+      case 1:  // Mute on
+        mute_on_ = true;
+        break;
+      default:
+        client.SendCommandResponse(kCmeErrorInCorrectParameters);
+        return;
+    }
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+VTS
+ *   This command transmits DTMF, after a successful call connection.
+ * Setting Command is used to send one or more ASCII characters which make
+ * MSC (Mobile Switching Center) send DTMF tone to remote User.
+ *
+ * Command                         Possible response(s)
+ * AT+VTS=<dtmf>[,<duration>]        +CME ERROR: <err>
+ *
+ * <dtmf>
+ *   A single ASCII character in the set { 0 -9, #, *, A – D}.
+ * <duration>
+ *   Refer to duration value range of +VTD command
+ *
+ * see RIL_REQUEST_DTMF in RIL
+ */
+void CallService::HandleSendDtmf(const Client& client,
+                                 const std::string& /*command*/) {
+  client.SendCommandResponse("OK");
+}
+
+void CallService::HandleCancelUssd(const Client& client,
+                                   const std::string& /*command*/) {
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * AT+WSOS
+ *
+ * Command          Possible response(s)
+ * +WSOS=[<n>]        +CME ERROR: <err>
+ * +WSOS?             +WSOS: <n>
+ *                    +CME ERROR: <err>
+ *
+ * <n>: integer type
+ *   0 enter emergency mode
+ *   1 exit emergency mode
+ *
+ * see RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE
+ *     RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE
+ *     RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE in RIL
+ */
+void CallService::HandleEmergencyMode(const Client& client,
+                                      const std::string& command) {
+  std::vector<std::string> responses;
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  if (cmd == "AT+WSOS?") {
+    std::stringstream ss;
+    ss << "+WSOS: " << in_emergency_mode_;
+    responses.push_back(ss.str());
+  } else {
+    int n = cmd.GetNextInt();
+    switch (n) {
+      case 0:  // Exit
+        in_emergency_mode_ = false;
+        break;
+      case 1:  // Enter
+        in_emergency_mode_ = true;
+        break;
+      default:
+        client.SendCommandResponse(kCmeErrorInCorrectParameters);
+        return;
+    }
+    auto nvram_config = NvramConfig::Get();
+    auto instance = nvram_config->ForInstance(service_id_);
+    instance.set_emergency_mode(in_emergency_mode_);
+    NvramConfig::SaveToFile();
+  }
+  client.SendCommandResponse("OK");
+}
+
+void CallService::CallStateUpdate() {
+  SendUnsolicitedCommand("RING");
+}
+
+/**
+ * AT+REMOTECALL=<dir>,<stat>,<mode>,<mpty>,<number>,<num_type>
+ *   This command allows to dial a remote voice call with another cuttlefish
+ * emulator. If request is successful, the remote emulator can simulate hold on,
+ * hang up, reject and so on.
+ *
+ * e.g. AT+REMOTECALL=4,0,0,6521,129
+ *
+ * <stat>: integer type (state of the call)
+ *       0 active
+ *       1 held
+ *       2 dialing (MO call)
+ *       3 alerting (MO call)
+ *       4 incoming (MT call)
+ *       5 waiting (MT call)
+ * <mode>: integer type
+ *       0 voice
+ *       1 data
+ *       2 fax
+ *       3 voice followed by data, voice mode
+ *       4 alternating voice/data, voice mode
+ *       5 alternating voice/fax, voice mode
+ *       6 voice followed by data, data mode
+ *       7 alternating voice/data, data mode
+ *       8 alternating voice/fax, fax mode
+ *       9 unknown
+ * <mpty>: integer type
+ *       0 call is not one of multiparty (conference) call parties
+ *       1 call is one of multiparty (conference) call parties
+ * <number>: string here maybe remote port
+ * <num_type>: type of address octet in integer format
+ *
+ * Note: reason should be added to indicate why hang up. Since not realizing
+ *       RIL_LAST_CALL_FAIL_CAUSE, delay to be implemented.
+ */
+void CallService::HandleRemoteCall(const Client& client,
+                                   const std::string& command) {
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  int state = cmd.GetNextInt();
+  int mode = cmd.GetNextInt();
+  int mpty = cmd.GetNextInt();
+  auto number = cmd.GetNextStr();
+  int num_type = cmd.GetNextInt();
+
+  // According to the number to determine whether it is a existing call
+  auto iter = active_calls_.begin();
+  for (; iter != active_calls_.end(); ++iter) {
+    if (iter->second.number == number) {
+      break;
+    }
+  }
+
+  switch (state) {
+    case CallStatus::CALL_STATE_ACTIVE: {
+      if (iter != active_calls_.end()) {
+        iter->second.SetCallActive();
+        if (iter->second.timeout_serial != std::nullopt) {
+          thread_looper_->CancelSerial(*(iter->second.timeout_serial));
+        }
+      }
+      break;
+    }
+    case CallStatus::CALL_STATE_HELD:
+      if (iter != active_calls_.end()) {
+        iter->second.SetCallBackground();
+        if (iter->second.timeout_serial != std::nullopt) {
+          thread_looper_->CancelSerial(*(iter->second.timeout_serial));
+        }
+      }
+      break;
+    case CallStatus::CALL_STATE_HANGUP:
+      if (iter != active_calls_.end()) {
+        auto client = iter->second.remote_client;
+        if (client != std::nullopt) {
+          CloseRemoteConnection(*client);
+        }
+        if (iter->second.timeout_serial != std::nullopt) {
+          thread_looper_->CancelSerial(*(iter->second.timeout_serial));
+        }
+        active_calls_.erase(iter);
+      }
+      break;
+    case CallStatus::CALL_STATE_INCOMING: {
+      if (network_service_) {
+        if (network_service_->isRadioOff()) {
+          LOG(DEBUG) << " radio is off, reject incoming call from: " << number;
+          client.client_fd->Close();
+          return;
+        }
+      }
+      CallStatus call_status(number);
+      call_status.is_remote_call = true;
+      call_status.is_voice_mode = mode;
+      call_status.is_multi_party = mpty;
+      call_status.is_mobile_terminated = true;
+      call_status.is_international = num_type;
+      call_status.remote_client = client.client_fd;
+      call_status.call_state = CallStatus::CALL_STATE_INCOMING;
+
+      auto index = last_active_call_index_++;
+      active_calls_[index] = call_status;
+      break;
+    }
+    default:  // Unsupported call state
+      return;
+  }
+  thread_looper_->Post(makeSafeCallback(this, &CallService::CallStateUpdate));
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/call_service.h b/host/commands/modem_simulator/call_service.h
new file mode 100644
index 0000000..1870372
--- /dev/null
+++ b/host/commands/modem_simulator/call_service.h
@@ -0,0 +1,150 @@
+//
+// 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 "host/commands/modem_simulator/modem_service.h"
+#include "host/commands/modem_simulator/network_service.h"
+#include "host/commands/modem_simulator/sim_service.h"
+
+namespace cuttlefish {
+
+class CallService : public ModemService, public std::enable_shared_from_this<CallService>  {
+ public:
+  CallService(int32_t service_id, ChannelMonitor* channel_monitor,
+              ThreadLooper* thread_looper);
+  ~CallService() = default;
+
+  CallService(const CallService &) = delete;
+  CallService &operator=(const CallService &) = delete;
+
+  void SetupDependency(SimService* sim, NetworkService* net);
+
+  void HandleDial(const Client& client, const std::string& command);
+  void HandleAcceptCall(const Client& client);
+  void HandleRejectCall(const Client& client);
+  void HandleCurrentCalls(const Client& client);
+  void HandleHangup(const Client& client, const std::string& command);
+  void HandleMute(const Client& client, const std::string& command);
+  void HandleSendDtmf(const Client& client, const std::string& command);
+  void HandleCancelUssd(const Client& client, const std::string& command);
+  void HandleEmergencyMode(const Client& client, const std::string& command);
+  void HandleRemoteCall(const Client& client, const std::string& command);
+
+ private:
+  void InitializeServiceState();
+  std::vector<CommandHandler> InitializeCommandHandlers();
+  void SimulatePendingCallsAnswered();
+  void CallStateUpdate();
+
+  struct CallStatus {
+    enum CallState {
+      CALL_STATE_ACTIVE = 0,
+      CALL_STATE_HELD,
+      CALL_STATE_DIALING,
+      CALL_STATE_ALERTING,
+      CALL_STATE_INCOMING,
+      CALL_STATE_WAITING,
+      CALL_STATE_HANGUP
+    };
+
+    // ctors
+    CallStatus()
+      : call_state(CALL_STATE_ACTIVE),
+        is_mobile_terminated(true),
+        is_international(false),
+        is_voice_mode(true),
+        is_multi_party(false),
+        can_present_number(true) {}
+
+    CallStatus(const std::string_view number)
+        : call_state(CALL_STATE_INCOMING),
+          is_mobile_terminated(true),
+          is_international(false),
+          is_voice_mode(true),
+          is_multi_party(false),
+          number(number),
+          can_present_number(true) {}
+
+    bool isCallBackground() {
+      return call_state == CALL_STATE_HELD;
+    }
+
+    bool isCallActive() {
+      return call_state == CALL_STATE_ACTIVE;
+    }
+
+    bool isCallDialing() {
+      return call_state == CALL_STATE_DIALING;
+    }
+
+    bool isCallIncoming() {
+      return call_state == CALL_STATE_INCOMING;
+    }
+
+    bool isCallWaiting() {
+      return call_state == CALL_STATE_WAITING;
+    }
+
+    bool isCallAlerting() {
+      return call_state == CALL_STATE_ALERTING;
+    }
+
+    bool SetCallBackground() {
+      if (call_state == CALL_STATE_ACTIVE) {
+        call_state = CALL_STATE_HELD;
+        return true;
+      }
+
+      return false;
+    }
+
+    bool SetCallActive() {
+      if (call_state == CALL_STATE_INCOMING || call_state == CALL_STATE_WAITING ||
+          call_state == CALL_STATE_DIALING || call_state == CALL_STATE_HELD) {
+        call_state = CALL_STATE_ACTIVE;
+        return true;
+      }
+
+      return false;
+    }
+
+    // date member public
+    CallState call_state;
+    bool is_mobile_terminated;
+    bool is_international;
+    bool is_voice_mode;
+    bool is_multi_party;
+    bool is_remote_call;
+    std::optional<cuttlefish::SharedFD> remote_client;
+    std::optional<int32_t> timeout_serial;
+    std::string number;
+    bool can_present_number;
+  };
+  using CallToken = std::pair<int, std::string>;
+
+  void SendCallStatusToRemote(CallStatus& call, CallStatus::CallState state);
+  void TimerWaitingRemoteCallResponse(CallToken token);
+
+  // private data members
+  SimService* sim_service_;
+  NetworkService* network_service_;
+  int32_t last_active_call_index_;
+  std::map<int, CallStatus> active_calls_;
+  bool in_emergency_mode_;
+  bool mute_on_;
+};
+
+}  // namespace
diff --git a/host/commands/modem_simulator/cf_device_config.cpp b/host/commands/modem_simulator/cf_device_config.cpp
new file mode 100644
index 0000000..559e1f8
--- /dev/null
+++ b/host/commands/modem_simulator/cf_device_config.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include "common/libs/device_config/device_config.h"
+#include "host/commands/modem_simulator/device_config.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+// this file provide cuttlefish hooks
+namespace cuttlefish {
+namespace modem {
+
+int DeviceConfig::host_port() {
+  if (!cuttlefish::CuttlefishConfig::Get()) {
+      return 6500;
+  }
+  auto config = cuttlefish::CuttlefishConfig::Get();
+  auto instance = config->ForDefaultInstance();
+  auto host_port = instance.host_port();
+  return host_port;
+}
+
+std::string DeviceConfig::PerInstancePath(const char* file_name) {
+  if (!cuttlefish::CuttlefishConfig::Get()) {
+      return "";
+  }
+  auto config = cuttlefish::CuttlefishConfig::Get();
+  auto instance = config->ForDefaultInstance();
+  return instance.PerInstancePath(file_name);
+}
+
+std::string DeviceConfig::DefaultHostArtifactsPath(const std::string& file) {
+  return cuttlefish::DefaultHostArtifactsPath(file);
+}
+
+std::string DeviceConfig::ril_address_and_prefix() {
+  auto device_config_helper = cuttlefish::DeviceConfigHelper::Get();
+  if (!device_config_helper) {
+      return "10.0.2.15/24";
+  }
+  const auto& ril_config = device_config_helper->GetDeviceConfig().ril_config();
+  return ril_config.ipaddr() + "/" + std::to_string(ril_config.prefixlen());
+};
+
+std::string DeviceConfig::ril_gateway() {
+  auto device_config_helper = cuttlefish::DeviceConfigHelper::Get();
+  if (!device_config_helper) {
+      return "10.0.2.2";
+  }
+  const auto& ril_config = device_config_helper->GetDeviceConfig().ril_config();
+  return ril_config.gateway();
+}
+
+std::string DeviceConfig::ril_dns() {
+  auto device_config_helper = cuttlefish::DeviceConfigHelper::Get();
+  if (!device_config_helper) {
+      return "8.8.8.8";
+  }
+  const auto& ril_config = device_config_helper->GetDeviceConfig().ril_config();
+  return ril_config.dns();
+}
+
+}  // namespace modem
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/channel_monitor.cpp b/host/commands/modem_simulator/channel_monitor.cpp
new file mode 100644
index 0000000..e598f2d
--- /dev/null
+++ b/host/commands/modem_simulator/channel_monitor.cpp
@@ -0,0 +1,279 @@
+
+//
+// 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.
+
+#include "host/commands/modem_simulator/channel_monitor.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include <algorithm>
+
+#include "host/commands/modem_simulator/modem_simulator.h"
+
+namespace cuttlefish {
+
+constexpr int32_t kMaxCommandLength = 4096;
+
+Client::Client(cuttlefish::SharedFD fd) : client_fd(fd) {}
+
+Client::Client(cuttlefish::SharedFD fd, ClientType client_type)
+    : type(client_type), client_fd(fd) {}
+
+bool Client::operator==(const Client& other) const {
+  return client_fd == other.client_fd;
+}
+
+void Client::SendCommandResponse(std::string response) const {
+  if (response.empty()) {
+    LOG(DEBUG) << "Invalid response, ignore!";
+    return;
+  }
+
+  if (response.back() != '\r') {
+    response += '\r';
+  }
+  LOG(VERBOSE) << " AT< " << response;
+
+  std::lock_guard<std::mutex> autolock(const_cast<Client*>(this)->write_mutex);
+  client_fd->Write(response.data(), response.size());
+}
+
+void Client::SendCommandResponse(
+    const std::vector<std::string>& responses) const {
+  for (auto& response : responses) {
+    SendCommandResponse(response);
+  }
+}
+
+ChannelMonitor::ChannelMonitor(ModemSimulator* modem,
+                               cuttlefish::SharedFD server)
+    : modem_(modem), server_(server) {
+  if (!cuttlefish::SharedFD::Pipe(&read_pipe_, &write_pipe_)) {
+    LOG(ERROR) << "Unable to create pipe, ignore";
+  }
+
+  if (server_->IsOpen())
+    monitor_thread_ = std::thread([this]() { MonitorLoop(); });
+}
+
+void ChannelMonitor::SetRemoteClient(cuttlefish::SharedFD client, bool is_accepted) {
+  auto remote_client = std::make_unique<Client>(client, Client::REMOTE);
+
+  if (is_accepted) {
+    // There may be new data from remote client before select.
+    remote_client->first_read_command_ = true;
+    ReadCommand(*remote_client);
+  }
+
+  if (remote_client->client_fd->IsOpen()) {
+    remote_client->first_read_command_ = false;
+    remote_clients_.push_back(std::move(remote_client));
+    LOG(DEBUG) << "added one remote client";
+  }
+
+  // Trigger monitor loop
+  if (write_pipe_->IsOpen()) {
+    write_pipe_->Write("OK", sizeof("OK"));
+  } else {
+    LOG(ERROR) << "Pipe created fail, can't trigger monitor loop";
+  }
+}
+
+void ChannelMonitor::AcceptIncomingConnection() {
+  auto client_fd  = cuttlefish::SharedFD::Accept(*server_);
+  if (!client_fd->IsOpen()) {
+    LOG(ERROR) << "Error accepting connection on socket: " << client_fd->StrError();
+  } else {
+    auto client = std::make_unique<Client>(client_fd);
+    LOG(DEBUG) << "added one RIL client";
+    clients_.push_back(std::move(client));
+    if (clients_.size() == 1) {
+      // The first connected client default to be the unsolicited commands channel
+      modem_->OnFirstClientConnected();
+    }
+  }
+}
+
+void ChannelMonitor::ReadCommand(Client& client) {
+  std::vector<char> buffer(kMaxCommandLength);
+  auto bytes_read = client.client_fd->Read(buffer.data(), buffer.size());
+  if (bytes_read <= 0) {
+    if (errno == EAGAIN && client.type == Client::REMOTE &&
+        client.first_read_command_) {
+      LOG(ERROR) << "After read 'REM' from remote client, and before select "
+          "no new data come.";
+      return;
+    }
+    LOG(DEBUG) << "Error reading from client fd: "
+               << client.client_fd->StrError();
+    client.client_fd->Close();  // Ignore errors here
+    // Erase client from the vector clients
+    auto& clients = client.type == Client::REMOTE ? remote_clients_ : clients_;
+    auto iter = std::find_if(
+        clients.begin(), clients.end(),
+        [&](std::unique_ptr<Client>& other) { return *other == client; });
+    if (iter != clients.end()) {
+      clients.erase(iter);
+    }
+    return;
+  }
+
+  std::string& incomplete_command = client.incomplete_command;
+
+  // Add the incomplete command from the last read
+  auto commands = std::string{incomplete_command.data()};
+  commands.append(buffer.data());
+
+  incomplete_command.clear();
+
+  // Replacing '\n' with '\r'
+  commands = android::base::StringReplace(commands, "\n", "\r", true);
+
+  // Split into commands and dispatch
+  size_t pos = 0, r_pos = 0;  // '\r' or '\n'
+  while (r_pos != std::string::npos) {
+    if (modem_->IsWaitingSmsPdu()) {
+      r_pos = commands.find('\032', pos);  // In sms, find ctrl-z
+    } else {
+      r_pos = commands.find('\r', pos);
+    }
+    if (r_pos != std::string::npos) {
+      auto command = commands.substr(pos, r_pos - pos);
+      if (command.size() > 0) {  // "\r\r" ?
+        LOG(VERBOSE) << "AT> " << command;
+        modem_->DispatchCommand(client, command);
+      }
+      pos = r_pos + 1;  // Skip '\r'
+    } else if (pos < commands.length()) {  // Incomplete command
+      incomplete_command = commands.substr(pos);
+      LOG(DEBUG) << "incomplete command: " << incomplete_command;
+    }
+  }
+}
+
+void ChannelMonitor::SendUnsolicitedCommand(std::string& response) {
+  // The first accepted client default to be unsolicited command channel?
+  auto iter = clients_.begin();
+  if (iter != clients_.end()) {
+    iter->get()->SendCommandResponse(response);
+  } else {
+    LOG(DEBUG) << "No client connected yet.";
+  }
+}
+
+void ChannelMonitor::SendRemoteCommand(cuttlefish::SharedFD client, std::string& response) {
+  auto iter = remote_clients_.begin();
+  for (; iter != remote_clients_.end(); ++iter) {
+    if (iter->get()->client_fd == client) {
+      iter->get()->SendCommandResponse(response);
+      return;
+    }
+  }
+  LOG(DEBUG) << "Remote client has closed.";
+}
+
+void ChannelMonitor::CloseRemoteConnection(cuttlefish::SharedFD client) {
+  auto iter = remote_clients_.begin();
+  for (; iter != remote_clients_.end(); ++iter) {
+    if (iter->get()->client_fd == client) {
+      iter->get()->client_fd->Close();
+      iter->get()->is_valid = false;
+
+      // Trigger monitor loop
+      if (write_pipe_->IsOpen()) {
+        write_pipe_->Write("OK", sizeof("OK"));
+        LOG(DEBUG) << "asking to remove clients";
+      } else {
+        LOG(ERROR) << "Pipe created fail, can't trigger monitor loop";
+      }
+      return;
+    }
+  }
+  LOG(DEBUG) << "Remote client has been erased.";
+}
+
+ChannelMonitor::~ChannelMonitor() {
+  if (write_pipe_->IsOpen()) {
+    write_pipe_->Write("KO", sizeof("KO"));
+  }
+
+  if (monitor_thread_.joinable()) {
+    LOG(DEBUG) << "waiting for monitor thread to join";
+    monitor_thread_.join();
+  }
+}
+
+static void removeInvalidClients(std::vector<std::unique_ptr<Client>>& clients) {
+  auto iter = clients.begin();
+  for (; iter != clients.end();) {
+    if (iter->get()->is_valid) {
+      ++iter;
+    } else {
+      LOG(DEBUG) << "removed 1 client";
+      iter = clients.erase(iter);
+    }
+  }
+}
+
+void ChannelMonitor::MonitorLoop() {
+  do {
+    cuttlefish::SharedFDSet read_set;
+    read_set.Set(server_);
+    read_set.Set(read_pipe_);
+    for (auto& client: clients_) {
+      if (client->is_valid) read_set.Set(client->client_fd);
+    }
+    for (auto& client: remote_clients_) {
+      if (client->is_valid) read_set.Set(client->client_fd);
+    }
+    int num_fds = cuttlefish::Select(&read_set, nullptr, nullptr, nullptr);
+    if (num_fds < 0) {
+      LOG(ERROR) << "Select call returned error : " << strerror(errno);
+      // std::exit(kSelectError);
+      break;
+    } else if (num_fds > 0) {
+      if (read_set.IsSet(server_)) {
+        AcceptIncomingConnection();
+      }
+      if (read_set.IsSet(read_pipe_)) {
+        std::string buf(2, ' ');
+        read_pipe_->Read(buf.data(), buf.size());  // Empty pipe
+        if (buf == std::string("KO")) {
+          LOG(DEBUG) << "requested to exit now";
+          break;
+        }
+        // clean the lists
+        removeInvalidClients(clients_);
+        removeInvalidClients(remote_clients_);
+      }
+      for (auto& client : clients_) {
+        if (read_set.IsSet(client->client_fd)) {
+          ReadCommand(*client);
+        }
+      }
+      for (auto& client : remote_clients_) {
+        if (read_set.IsSet(client->client_fd)) {
+          ReadCommand(*client);
+        }
+      }
+    } else {
+      // Ignore errors here
+      LOG(ERROR) << "Select call returned error : " << strerror(errno);
+    }
+  } while (true);
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/channel_monitor.h b/host/commands/modem_simulator/channel_monitor.h
new file mode 100644
index 0000000..6dc7c4a
--- /dev/null
+++ b/host/commands/modem_simulator/channel_monitor.h
@@ -0,0 +1,97 @@
+//
+// 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 <mutex>
+#include <thread>
+#include <vector>
+
+#include "common/libs/fs/shared_select.h"
+
+namespace cuttlefish {
+
+class ModemSimulator;
+
+enum ModemSimulatorExitCodes : int {
+  kSuccess = 0,
+  kSelectError = 1,
+  kServerError = 2,
+};
+
+/**
+ * Client object managed by ChannelMonitor, contains two types, the RIL client
+ * and the remote client of other cuttlefish instance.
+ * Due to std::mutex does not implement its copy and operate= constructors, it
+ * cann't be stored in standard contains (vector, map), so use the point instead.
+ */
+class Client {
+ public:
+  enum ClientType { RIL, REMOTE };
+
+  ClientType type = RIL;
+  cuttlefish::SharedFD client_fd;
+  std::string incomplete_command;
+  std::mutex write_mutex;
+  bool first_read_command_;  // Only used when ClientType::REMOTE
+  bool is_valid = true;
+
+  Client() = default;
+  ~Client() = default;
+  Client(cuttlefish::SharedFD fd);
+  Client(cuttlefish::SharedFD fd, ClientType client_type);
+  Client(const Client& client) = delete;
+  Client(Client&& client) = delete;
+
+  Client& operator=(Client&& other) = delete;
+
+  bool operator==(const Client& other) const;
+
+  void SendCommandResponse(std::string response) const;
+  void SendCommandResponse(const std::vector<std::string>& responses) const;
+};
+
+class ChannelMonitor {
+ public:
+  ChannelMonitor(ModemSimulator* modem, cuttlefish::SharedFD server);
+  ~ChannelMonitor();
+
+  ChannelMonitor(const ChannelMonitor&) = delete;
+  ChannelMonitor& operator=(const ChannelMonitor&) = delete;
+
+  void SetRemoteClient(cuttlefish::SharedFD client,  bool is_accepted);
+  void SendRemoteCommand(cuttlefish::SharedFD client, std::string& response);
+  void CloseRemoteConnection(cuttlefish::SharedFD client);
+
+  // For modem services to send unsolicited commands
+  void SendUnsolicitedCommand(std::string& response);
+
+ private:
+  ModemSimulator* modem_;
+  std::thread monitor_thread_;
+  cuttlefish::SharedFD server_;
+  cuttlefish::SharedFD read_pipe_;
+  cuttlefish::SharedFD write_pipe_;
+  std::vector<std::unique_ptr<Client>> clients_;
+  std::vector<std::unique_ptr<Client>> remote_clients_;
+
+  void AcceptIncomingConnection();
+  void OnClientSocketClosed(int sock);
+  void ReadCommand(Client& client);
+
+  void MonitorLoop();
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/command_parser.cpp b/host/commands/modem_simulator/command_parser.cpp
new file mode 100644
index 0000000..9b95706
--- /dev/null
+++ b/host/commands/modem_simulator/command_parser.cpp
@@ -0,0 +1,125 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/command_parser.h"
+
+#include <sstream>
+#include <string>
+
+namespace cuttlefish {
+
+/**
+ * Parses the next string between double quotes
+ * returns the string on success and "" on fail
+ * updates command_
+ */
+std::string_view CommandParser::GetNextStr() {
+  auto fpos = command_.find('\"');
+  if (fpos == std::string_view::npos) {
+    return {};
+  }
+
+  auto spos = command_.find('\"', fpos + 1);
+  if (spos == std::string_view::npos) {
+    command_ = command_.substr(fpos + 1);
+    return {};
+  }
+
+  auto str = command_.substr(fpos + 1, (spos - fpos - 1));
+  command_ = command_.substr(spos + 1);
+  SkipComma();
+  return str;
+}
+
+/**
+ * Parses the next string before the flag
+ * If flag not exists, returns the whole command_
+ * updates command_
+ */
+std::string_view CommandParser::GetNextStr(char flag) {
+  auto pos = command_.find(flag);
+  auto str = command_.substr(0, pos);
+  if (pos != std::string_view::npos) pos += 1;  // npos + 1 = 0
+  command_.remove_prefix(std::min(pos, command_.size()));
+  return str;
+}
+
+/**
+ * Parses the next base 10 integer in the AT command and convert to upper case
+ * hex string
+ * returns the hex string on success and "" on fail
+ * updates command_
+ *
+ * Specially, for AT+CRSM
+ */
+std::string CommandParser::GetNextStrDeciToHex() {
+  std::string str;
+  int value = GetNextInt();
+  if (value == -1) {
+    return {};
+  } else {
+    std::stringstream ss;
+    ss << std::hex << std::uppercase << value;
+    return ss.str();
+  }
+}
+
+static int parse_int(const std::string& snumber, int base) {
+  if (snumber.empty()) return -1;
+  const char* p = snumber.c_str();
+  char* p_end = nullptr;
+  errno = 0;
+  const long lval = std::strtol(p, &p_end, base);
+  if (p == p_end) {
+    return -1;
+  }
+  const bool range_error = errno == ERANGE;
+
+  if (range_error) return -1;
+  return lval;
+}
+
+/**
+ * Parses the next base 10 integer in the AT command
+ * returns the value on success and -1 on fail
+ * updates command_
+ */
+int CommandParser::GetNextInt() {
+  if (command_.empty()) {
+    return -1;
+  }
+  std::string sub(GetNextStr(','));
+
+  int value = parse_int(sub, 10);
+
+  return value;
+}
+
+/**
+ * Parses the next base 16 integer in the AT command
+ * returns the value on success and -1 on fail
+ * updates command_
+ */
+int CommandParser::GetNextHexInt() {
+  if (command_.empty()) {
+    return -1;
+  }
+
+  std::string sub(GetNextStr(','));
+  int value = parse_int(sub, 16);
+  return value;
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/command_parser.h b/host/commands/modem_simulator/command_parser.h
new file mode 100644
index 0000000..7cde60b
--- /dev/null
+++ b/host/commands/modem_simulator/command_parser.h
@@ -0,0 +1,98 @@
+//
+// 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.
+
+#include <android-base/strings.h>
+
+#include <algorithm>
+#include <string>
+
+namespace cuttlefish {
+
+class CommandParser {
+ public:
+  explicit CommandParser(const std::string& command) : copy_command_(command) {
+    command_ = copy_command_;
+  };
+
+  ~CommandParser() = default;
+
+  CommandParser(CommandParser&&) = default;
+  CommandParser& operator=(CommandParser&&) = default;
+
+  inline void SkipPrefix();
+  inline void SkipPrefixAT();
+  inline void SkipComma();
+  inline void SkipWhiteSpace();
+
+  std::string_view GetNextStr();
+  std::string_view GetNextStr(char flag);
+  std::string GetNextStrDeciToHex();  /* for AT+CRSM */
+
+  int GetNextInt();
+  int GetNextHexInt();
+
+  const std::string_view* operator->() const { return &command_; }
+  const std::string_view& operator*() const { return command_; }
+  bool operator==(const std::string &rhs) const { return command_ == rhs; }
+  std::string_view::const_reference& operator[](int index) const { return command_[index]; }
+
+ private:
+  std::string copy_command_;
+  std::string_view command_;
+};
+
+/**
+ * Skip the substring before the first '=', including '='
+ * updates command_
+ * If '=' not exists, command_ remains unchanged
+ */
+inline void CommandParser::SkipPrefix() {
+  auto pos = command_.find('=');
+  if (pos != std::string_view::npos) {
+    command_.remove_prefix(std::min(pos + 1, command_.size()));
+  }
+}
+
+/**
+ * Skip the next "AT" substring
+ * updates command_
+ */
+inline void CommandParser::SkipPrefixAT() {
+  android::base::ConsumePrefix(&command_, std::string_view("AT"));
+}
+
+/**
+ * Skip the next comma
+ * updates command_
+ */
+inline void CommandParser::SkipComma() {
+  auto pos = command_.find(',');
+  if (pos != std::string_view::npos) {
+    command_.remove_prefix(std::min(pos + 1, command_.size()));
+  }
+}
+
+/**
+ * Skip the next whitespace
+ * updates command_
+ */
+inline void CommandParser::SkipWhiteSpace() {
+  auto pos = command_.find(' ');
+  if (pos != std::string_view::npos) {
+    command_.remove_prefix(std::min(pos + 1, command_.size()));
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/data_service.cpp b/host/commands/modem_simulator/data_service.cpp
new file mode 100644
index 0000000..b48a777
--- /dev/null
+++ b/host/commands/modem_simulator/data_service.cpp
@@ -0,0 +1,344 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/data_service.h"
+
+#include <android-base/strings.h>
+
+#include "host/commands/modem_simulator/device_config.h"
+
+namespace cuttlefish {
+
+DataService::DataService(int32_t service_id, ChannelMonitor* channel_monitor,
+                         ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {
+  InitializeServiceState();
+}
+
+std::vector<CommandHandler> DataService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      CommandHandler("+CGACT=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleActivateDataCall(client, cmd);
+                     }),
+      CommandHandler("+CGACT?",
+                     [this](const Client& client) {
+                       this->HandleQueryDataCallList(client);
+                     }),
+      CommandHandler("+CGDCONT=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandlePDPContext(client, cmd);
+                     }),
+      CommandHandler("+CGDCONT?",
+                     [this](const Client& client) {
+                       this->HandleQueryPDPContextList(client);
+                     }),
+      CommandHandler("+CGQREQ=1",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CGQMIN=1",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CGEREP=1,0",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CGDATA",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleEnterDataState(client, cmd);
+                     }),
+      CommandHandler("D*99***1#",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CGCONTRDP",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleReadDynamicParam(client, cmd);
+                     }),
+  };
+  return (command_handlers);
+}
+
+void DataService::InitializeServiceState() {
+  // Initialize data connection config
+}
+
+/**
+ * AT+CGACT
+ *   The execution command is used to activate or deactivate the specified PDP
+ * context(s).
+ *
+ * Command                            Possible response(s)
+ * +CGACT=[<state>[,<cid>              OK
+ *        [,<cid>[,...]]]]             +CME ERROR: <err>
+ * +CGACT?                             [+CGACT: <cid>,<state>]
+ *                                     [<CR><LF>+CGACT: <cid>,<state>[...]]
+ * <state>: integer type; indicates the state of PDP context activation.
+ *       0: deactivated
+ *       1: activated
+ * <cid>: (PDP Context Identifier) integer(1~15), specifies the PDP context ID.
+ *
+ * see RIL_REQUEST_SETUP_DATA_CALL in RIL
+ */
+void DataService::HandleActivateDataCall(const Client& client,
+                                         const std::string& /*command*/) {
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * see AT+CGACT
+ */
+void DataService::HandleQueryDataCallList(const Client& client) {
+  std::vector<std::string> responses;
+
+  std::stringstream ss;
+  for (auto iter = pdp_context_.begin(); iter != pdp_context_.end(); ++iter) {
+    if (iter->state == PDPContext::ACTIVE) {
+      ss.clear();
+      ss << "+CGACT: " << iter->cid << "," << iter->state;
+      responses.push_back(ss.str());
+      ss.str("");
+    }
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CGDCONT
+ *   The set command specifies PDP context parameter values for a PDP context
+ * identified by the (local) context identification parameter, <cid>.
+ *
+ * Command                            Possible response(s)
+ * +CGDCONT=[<cid>[,<PDP_type>[,<APN>  OK
+ * [,<PDP_addr>[,<d_comp> [,<h_comp>]  +CME ERROR: <err>
+ * ]]]]]
+ * +CGDCONT?                           +CGDCONT: <cid>,<pdp_type>,<APN>,
+ *                                     <pdp_addr>,<d_comp>,<h_comp><CR><LF>
+ *                                     [+CGDCONT: <cid>,<pdp_type>,<APN>,
+ *                                     <pdp_addr>,<d_comp>,<h_comp><CR><LF>[...]]
+ *                                     OK
+ * <cid>: see AT+CGACT
+ * <PDP_type>: string type; specifies the type of packet data protocol.
+ *             Value: X.25, IP, IPV6, IPV4V6, OSPIH, PPP, Non-IP,Ethernet
+ * <APN>: string type; a logical name that is used to select the GGSN or the
+ *        external packet data network.If the value is null or omitted, then
+ *        the subscription value will be requested
+ * <PDP_addr>: string type; identifies the MT in the address space applicable
+ *             to the PDP
+ * <d_comp>: integer type; controls PDP data compression
+ * <h_comp>: integer type; controls PDP header compression
+ *
+ * see RIL_REQUEST_SETUP_DATA_CALL in RIL
+ */
+void DataService::HandlePDPContext(const Client& client,
+                                   const std::string& command) {
+  CommandParser cmd(command);
+  cmd.SkipPrefix(); /* skip +CGDCONT= */
+  int cid = cmd.GetNextInt();
+
+  std::string ip_type(cmd.GetNextStr(','));
+  std::string apn(cmd.GetNextStr(','));
+
+  auto address = cuttlefish::modem::DeviceConfig::ril_address_and_prefix();
+  auto dnses = cuttlefish::modem::DeviceConfig::ril_dns();
+  auto gateways = cuttlefish::modem::DeviceConfig::ril_gateway();
+
+  PDPContext pdp_context = {cid,
+                            PDPContext::ACTIVE,
+                            ip_type,  // IPV4 or IPV6 or IPV4V6
+                            apn,
+                            address,
+                            dnses,
+                            gateways};
+
+  // check cid
+  auto iter = pdp_context_.begin();
+  for (; iter != pdp_context_.end(); ++iter) {
+    if (pdp_context.cid == iter->cid) {
+      *iter = pdp_context;
+      break;
+    }
+  }
+
+  if (iter == pdp_context_.end()) {
+    pdp_context_.push_back(pdp_context);
+  }
+
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * see AT+CGDCONT above
+ */
+void DataService::HandleQueryPDPContextList(const Client& client) {
+  std::vector<std::string> responses;
+
+  std::stringstream ss;
+  for (auto it = pdp_context_.begin(); it != pdp_context_.end(); ++it) {
+    std::stringstream ss;
+    ss << "+CGDCONT: " << it->cid << "," << it->conn_types << ","
+       << it->apn << "," << it->addresses << ",0,0";
+    responses.push_back(ss.str());
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CGDATA
+ *   The execution command causes the MT to perform whatever actions are
+ * necessary to establish communication between the TE and the network using
+ * one or more Packet Domain PDP types.
+ *
+ * Command                            Possible response(s)
+ * +CGDATA[=<L2P>[,[,<cid>             CONNECT
+ *          [,...]]]]                  ERROR
+ *                                     +CME ERROR: <err>
+ *
+ * <L2P>: string type; indicates the layer 2 protocol to be used between the
+ *        TE and MT NULL  none, for PDP type OSP:IHOSS (Obsolete)
+ *        value: PPP, PAD, X25, M-xxxx
+ * <cid>: see AT+CGACT
+ *
+ * see RIL_REQUEST_SETUP_DATA_CALL in RIL
+ */
+void DataService::HandleEnterDataState(const Client& client,
+                                       const std::string& command) {
+  std::string response;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  cmd.SkipComma();
+  int cid = cmd.GetNextInt();
+
+  // Check cid
+  auto iter = pdp_context_.begin();
+  for (; iter != pdp_context_.end(); ++iter) {
+    if (cid == iter->cid && iter->state == PDPContext::ACTIVE) {
+      response = "CONNECT";
+      break;
+    }
+  }
+
+  if (iter == pdp_context_.end()) {
+    response = "ERROR";
+  }
+
+  client.SendCommandResponse(response);
+}
+
+/**
+ * AT+CGCONTRDP
+ *   The execution command returns the relevant information for an active non
+ * secondary PDP context with the context identifier <cid>.
+ *
+ * Command                            Possible response(s)
+ * +CGCONTRDP[=<cid>]                 [+CGCONTRDP: <cid>,<bearer_id>,<apn>
+ *                                    [,<local_addr and subnet_mask>[,<gw_addr>
+ *                                    [,<DNS_prim_addr>[<DNS_sec_addr>[...]]]]]]
+ *                                    [<CR><LF>+CGCONTRDP: <cid>,<bearer_id>,<apn>
+ *                                    [,<local_addr and subnet_mask>[,<gw_addr>
+ *                                    [,<DNS_prim_addr>[<DNS_sec_addr>[...]]]]]]
+ *
+ * <cid>: see AT+CGACT
+ * <bearer_id>: integer type; identifies the bearer, i.e. the EPS bearer and
+ *              the NSAPI.
+ * <local_addr and subnet_mask>: string type; shows the IP address and subnet
+ *                               mask of the MT.
+ * <gw_addr>: string type; shows the Gateway Address of the MT. The string is
+ *            given as dot-separated numeric (0-255) parameters.
+ * <DNS_prim_addr>: string type; shows the IP address of the primary DNS server.
+ * <DNS_sec_addr>: string type; shows the IP address of the secondary DNS server.
+ *
+ *
+ * see RIL_REQUEST_SETUP_DATA_CALL in RIL
+ */
+void DataService::HandleReadDynamicParam(const Client& client,
+                                         const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix(); /* skip prefix AT+CGCONTRDP= */
+
+  int cid = cmd.GetNextInt();
+  auto iter = pdp_context_.begin();  // Check cid
+  for (; iter != pdp_context_.end(); ++iter) {
+    if (cid == iter->cid && iter->state == PDPContext::ACTIVE) {
+      break;
+    }
+  }
+
+  if (iter == pdp_context_.end()) {
+    responses.push_back(kCmeErrorInvalidIndex);  // number
+  } else {
+    std::stringstream ss;
+    ss << "+CGCONTRDP: "
+       << iter->cid << ",5,"
+       << iter->apn << ","
+       << iter->addresses << ","
+       << iter->gateways << ","
+       << iter->dnses;
+    responses.push_back(ss.str());
+    responses.push_back("OK");
+  }
+
+  client.SendCommandResponse(responses);
+}
+
+void DataService::sendOnePhysChanCfgUpdate(int status, int bandwidth, int rat,
+                                           int freq, int id) {
+  std::stringstream ss;
+  ss << "%CGFPCCFG: " << status << "," << bandwidth << "," << rat << "," << freq
+     << "," << id;
+  SendUnsolicitedCommand(ss.str());
+}
+
+void DataService::onUpdatePhysicalChannelconfigs(int modem_tech, int freq,
+                                                 int cellBandwidthDownlink) {
+  updatePhysicalChannelconfigs(modem_tech, freq, cellBandwidthDownlink, 3);
+}
+
+void DataService::updatePhysicalChannelconfigs(int modem_tech, int freq,
+                                               int cellBandwidthDownlink,
+                                               int count) {
+  if (count <= 0) {
+    return;
+  }
+
+  const int PRIMARY_SERVING = 1;
+  const int SECONDARY_SERVING = 2;
+
+  for (const auto& iter : pdp_context_) {
+    if (iter.state == PDPContext::ACTIVE) {
+      sendOnePhysChanCfgUpdate(PRIMARY_SERVING, cellBandwidthDownlink,
+                               modem_tech, freq, iter.cid);
+      sendOnePhysChanCfgUpdate(SECONDARY_SERVING, cellBandwidthDownlink,
+                               modem_tech, freq, iter.cid);
+    }
+  }
+
+  // call again after 1 sec delay
+  count--;
+  thread_looper_->PostWithDelay(
+      std::chrono::seconds(1),
+      makeSafeCallback(this, &DataService::updatePhysicalChannelconfigs,
+                       modem_tech, freq, cellBandwidthDownlink, count));
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/data_service.h b/host/commands/modem_simulator/data_service.h
new file mode 100644
index 0000000..2da2d1c
--- /dev/null
+++ b/host/commands/modem_simulator/data_service.h
@@ -0,0 +1,63 @@
+//
+// 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 "host/commands/modem_simulator/modem_service.h"
+
+namespace cuttlefish {
+
+class DataService : public ModemService, public std::enable_shared_from_this<DataService> {
+ public:
+  DataService(int32_t service_id, ChannelMonitor* channel_monitor,
+              ThreadLooper* thread_looper);
+  ~DataService() = default;
+
+  DataService(const DataService &) = delete;
+  DataService &operator=(const DataService &) = delete;
+
+  void HandleActivateDataCall(const Client& client, const std::string& command);
+  void HandleQueryDataCallList(const Client& client);
+  void HandlePDPContext(const Client& client, const std::string& command);
+  void HandleQueryPDPContextList(const Client& client);
+  void HandleEnterDataState(const Client& client, const std::string& command);
+  void HandleReadDynamicParam(const Client& client, const std::string& command);
+
+  void onUpdatePhysicalChannelconfigs(int modem_tech, int freq,
+                                      int cellBandwidthDownlink);
+
+ private:
+  std::vector<CommandHandler> InitializeCommandHandlers();
+  void InitializeServiceState();
+  void sendOnePhysChanCfgUpdate(int status, int bandwidth, int rat, int freq,
+                                int id);
+  void updatePhysicalChannelconfigs(int modem_tech, int freq,
+                                    int cellBandwidthDownlink, int count);
+
+  struct PDPContext {
+    enum CidState {ACTIVE, NO_ACTIVE};
+
+    int cid;
+    CidState state;
+    std::string conn_types;
+    std::string apn;
+    std::string addresses;
+    std::string dnses;
+    std::string gateways;
+  };
+  std::vector<PDPContext> pdp_context_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/device_config.h b/host/commands/modem_simulator/device_config.h
new file mode 100644
index 0000000..05bca77
--- /dev/null
+++ b/host/commands/modem_simulator/device_config.h
@@ -0,0 +1,38 @@
+/*
+ * 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>
+
+// this file provide a few device (cvd or emulator) specific hooks for
+// modem-simulator
+
+namespace cuttlefish {
+namespace modem {
+
+class DeviceConfig {
+ public:
+  static int host_port();
+  static std::string PerInstancePath(const char* file_name);
+  static std::string DefaultHostArtifactsPath(const std::string& file);
+  static std::string ril_address_and_prefix();
+  static std::string ril_gateway();
+  static std::string ril_dns();
+};
+
+}  // namespace modem
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/files/iccprofile_for_sim0.xml b/host/commands/modem_simulator/files/iccprofile_for_sim0.xml
new file mode 100755
index 0000000..655c37a
--- /dev/null
+++ b/host/commands/modem_simulator/files/iccprofile_for_sim0.xml
@@ -0,0 +1,181 @@
+<IccProfile>
+<MF path="3F00">
+    <EF name="EF_DIR" id="2F00" structure="linear fixed">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A8205422100300483022F008A01058B032F0601800200C08801F0</SIMIO>
+        <SIMIO cmd="B2" p1="1" p2="4" p3="30" data="">144,0,61184F10A0000003431002FF86FF0389FFFFFFFF50044353494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="2" p2="4" p3="30" data="">144,0,61184F10A0000000871002FF86FF0389FFFFFFFF50045553494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="3" p2="4" p3="30" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="4" p2="4" p3="30" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+    </EF>
+    <EF name="EF_ICCID" id="2FE2" structure="transparent">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183022FE28A01058B032F06038002000A880110</SIMIO>
+        <SIMIO cmd="B0" p1="0" p2="0" p3="A" data="">144,0,98683081462002318379</SIMIO>
+        <!-- Special ATC to read ICCID from modem cache -->
+        <CCID>89860318640220133897</CCID>
+    </EF>
+    <EF name="EF_PL" id="2F05" structure="transparent">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183022F058A01058B032F060280020004880128</SIMIO>
+        <SIMIO cmd="B0" p1="0" p2="0" p3="4" data="">144,0,FFFFFFFF</SIMIO>
+    </EF>
+
+    <DF name="TELECOM" path="7F10">
+        <DF name="PHONEBOOK" path="5F3A">
+            <EF name="EF_PBR" id="4F30" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62198205422100400283024F308A01058B036F0606800200808800</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="40" data="">144,0,A81EC0034F3A01C1034F3306C5034F0902C4034F1104C6034F2503C9034F3107A905CA034F5008AA0FC2034F4A09C7034F4B0AC8034F4C0BFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="40" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_GAS" id="4F4C" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A8205422100140A83024F4C8A01058B036F060E800200C8880158</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="3" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="4" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="5" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="6" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="7" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="8" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="9" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="A" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_ADN" id="4F3A" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A82054221001C1483024F3A8A01058B036F060E80020230880108</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="3" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="4" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="5" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="6" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="7" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="8" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="9" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="A" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="B" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="C" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="D" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="E" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="F" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="10" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="11" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="12" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="13" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="14" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_IAP" id="4F33" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A820542210001FA83024F338A01058B036F060E800200FA880130</SIMIO>
+            </EF>
+            <EF name="EF_PBC" id="4F09" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A820542210002FA83024F098A01058B036F060E800201F4880110</SIMIO>
+            </EF>
+            <EF name="EF_ANR" id="4F11" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A82054221000FFA83024F118A01058B036F060E80020EA6880120</SIMIO>
+            </EF>
+            <!-- EF_SNE, EF_AAS, EF_EXT1, EF_GRP, EF_UID, EF_EMAIL, EF_CCP1, EF_PUR1 ... -->
+        </DF>
+    </DF>
+
+    <ADF name="USIM" path="7FFF" aid="A0000000871002FF86FF0389FFFFFFFF">
+        <EF name="EF_IMSI" id="6F07" structure="transparent">
+            <CIMI>311740123456789</CIMI>
+        </EF>
+        <EF name="EF_MSISDN" id="6F40" structure="linear fixed">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621982054221001C0283026F408A01058B036F0605800200388800</SIMIO>
+            <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,000000000000000000000000000007915155214365F7FFFFFFFFFFFF</SIMIO>
+        </EF>
+        <EF name="EF_MBI" id="6FC9" structure="linear fixed">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62198205422100050183026FC98A01058B036F0602800200058800</SIMIO>
+            <SIMIO cmd="B2" p1="1" p2="4" p3="5" data="">144,0,0100000000</SIMIO>
+       </EF>
+        <EF name="EF_MBDN" id="6FC7" structure="linear fixed">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621982054221001C0283026F408A01058B036F06058002003E8800</SIMIO>
+            <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07915155674523F1FFFFFFFFFFFF</SIMIO>
+       </EF>
+       <EF name="EF_AD" id="6FAD" structure="transparent">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183026FAD8A01058B036F060180020004880118</SIMIO>
+            <SIMIO cmd="B0" p1="0" p2="0" p3="4" data="">144,0,00000003</SIMIO>
+       </EF>
+       <EF name="EF_MWIS" id="6FCA" structure="linear fixed">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62198205422100050183026FCA8A01058B036F060E800200058800</SIMIO>
+           <SIMIO cmd="B2" p1="1" p2="4" p3="5" data="">144,0,0000000000</SIMIO>
+       </EF>
+       <EF name="EF_VOICE_MAIL_INDICATOR_CPHS" id="6F11" structure="transparent">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">106,130</SIMIO>
+       </EF>
+       <EF name="EF_FPLMN" id="6F7B" structure="transparent">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621C8202412183026F7BA5038001718A01058B036F06038002001E880168</SIMIO>
+           <SIMIO cmd="B0" p1="0" p2="0" p3="1E" data="">144,0,64F00064F02064F04064F07064F080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+       </EF>
+       <EF name="EF_FDN" id="6F3B" structure="linear fixed">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621982054221001C0A83026F3B8A01058B036F0605800201188800</SIMIO>
+           <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="2" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="3" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="4" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="5" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="6" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="7" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="8" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="9" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="A" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+       </EF>
+       <!-- Other USIM files... -->
+     </ADF>
+</MF>
+
+<ADF name="PKCS15" aid="A000000063504B43532D3135">
+    <CGLA cmd="A40004025031">4,6124</CGLA>
+    <CGLA cmd="C0000024">76,62228202412183025031A503C001408A01058B066F0601010001800200108102002288009000 </CGLA>
+    <CGLA cmd="B0000010">36,A706300404024401A5063004040244029000</CGLA>
+</ADF>
+
+<ADF name="" aid="">
+    <CSIM cmd='10,"0070000001"'>6,019000</CSIM>
+    <CGLA cmd='1,14,"81F2FF0000"'>4,6b00</CGLA>
+    <!-- more CGLA Command -->
+</ADF>
+
+<PinProfile>
+    <!-- PIN: PINSTATE_ENABLED_NOT_VERIFIED -->
+    <!-- PUK: PINSTATE_ENABLED_BLOCKED -->
+    <!-- Ready: PINSTATE_UNKNOWN -->
+    <PINSTATE>PINSTATE_UNKNOWN</PINSTATE>
+    <PINCODE>1234</PINCODE>
+    <PUKCODE>12345678</PUKCODE>
+    <PINREMAINTIMES>3</PINREMAINTIMES>
+    <PUKREMAINTIMES>10</PUKREMAINTIMES>
+    <PIN2CODE>1234</PIN2CODE>
+    <PUK2CODE>12345678</PUK2CODE>
+    <PIN2REMAINTIMES>3</PIN2REMAINTIMES>
+    <PUK2REMAINTIMES>10</PUK2REMAINTIMES>
+</PinProfile>
+
+<FacilityLock>
+    <SC>DISABLE</SC>
+    <FD>DISABLE</FD>
+    <AO>DISABLE</AO>
+    <OI>DISABLE</OI>
+    <AI>DISABLE</AI>
+    <IR>DISABLE</IR>
+    <AB>DISABLE</AB>
+    <AG>DISABLE</AG>
+    <AC>DISABLE</AC>
+</FacilityLock>
+
+<SETUPMENU cmd="25" text="D0388103012500820281820509804E2D56FD79FB52A88F10508000530049004D5FEB6377786E8BA48F104E80005500530049004D53614FE1606F">
+    <SELECTITEM id="1" cmd="24" menuId="50" text="D02D8103012400820281828F0A018053E34EE48BBE7F6E8F0A02804E1A52A14ECB7ECD8F0A0380724867434FE1606F">
+        <SELECTITEM id="1" cmd="24" menuId="01" text="D0218103012400820281828F0A01806DFB52A083DC53558F0A02805220966483DC5355">
+            <DISPLAYTEXT id="1" cmd="21" menuId="01" text="D0228103012181820281028D1708662F542666F465B04E0B8F7D83DC535552178868FF1F"></DISPLAYTEXT>
+            <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D01A8103012101820281028D0F0883DC5355522096646210529FFF01"></DISPLAYTEXT>
+        </SELECTITEM>
+        <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D081BB8103012181820281028D81AF08201C00530049004D5FEB6377786E8BA4201D662F4E2D56FD79FB52A863D04F9B7684FF0C57FA4E8E624B673A00530049004D53617684727982725B8951688EAB4EFD8BA48BC1670D52A1300276F86BD44F207EDF75286237540D5BC678018BA48BC165B95F0FFF0C5B83517767094E0D53EF62E6622A30014E0D4F208F935BC6780130014F7F75285FEB63777B49727970B9FF0C662F60A87545884C4E9280547F5176848EAB4EFD536B58EB3002"></DISPLAYTEXT>
+        <DISPLAYTEXT id="3" cmd="21" menuId="03" text="D02E8103012181820281028D23084E2D56FD79FB52A8901A4FE167099650516C53F8FF0C0031002E00307248672C3002">
+        </DISPLAYTEXT>
+    </SELECTITEM>
+    <SELECTITEM id="2" cmd="24" menuId="4E" text="D04E810301240082028182850F80005500530049004D53614FE1606F8F0A0180536172477C7B578B8F14028075358BDD53F7780153CA77ED4FE15BB991CF8F100380004F00540041529F80FD4ECB7ECD">
+        <DISPLAYTEXT id="1" cmd="21" menuId="01" text="D03A8103012181820281028D2F08666E901A005500530049004D5361002000560032002E003000410027FF0C652F6301004F005400410033529F80FD"></DISPLAYTEXT>
+        <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D05C8103012181820281028D510875358BDD53F77801672C5B5850A85BB991CF0035003000306761FF0C5DF2752875358BDD672C003100336761FF0C77ED4FE15B5850A85BB991CF003500306761FF0C5DF2752877ED4FE1003400396761"></DISPLAYTEXT>
+        <DISPLAYTEXT id="3" cmd="21" menuId="03" text="D05E8103012181820281028D5308004F00540041529F80FD53EF5229752877ED4FE1606F901A9053FF0C5E2E52A95BA262375B9E73B0005500530049004D536151854E1A52A183DC5355768452A860014E0B8F7D3001522096644E0E66F465B0"></DISPLAYTEXT>
+    </SELECTITEM>
+</SETUPMENU>
+
+</IccProfile>
diff --git a/host/commands/modem_simulator/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml b/host/commands/modem_simulator/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml
new file mode 100755
index 0000000..1eeb885
--- /dev/null
+++ b/host/commands/modem_simulator/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml
@@ -0,0 +1,207 @@
+<IccProfile>
+<MF path="3F00">
+    <EF name="EF_DIR" id="2F00" structure="linear fixed">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A8205422100300483022F008A01058B032F0601800200C08801F0</SIMIO>
+        <SIMIO cmd="B2" p1="1" p2="4" p3="30" data="">144,0,61184F10A0000003431002FF86FF0389FFFFFFFF50044353494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="2" p2="4" p3="30" data="">144,0,61184F10A0000000871002FF86FF0389FFFFFFFF50045553494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="3" p2="4" p3="30" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="4" p2="4" p3="30" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+    </EF>
+    <EF name="EF_ICCID" id="2FE2" structure="transparent">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183022FE28A01058B032F06038002000A880110</SIMIO>
+        <SIMIO cmd="B0" p1="0" p2="0" p3="A" data="">144,0,98683081462002318379</SIMIO>
+        <!-- Special ATC to read ICCID from modem cache -->
+        <CCID>89860318640220133897</CCID>
+    </EF>
+    <EF name="EF_PL" id="2F05" structure="transparent">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183022F058A01058B032F060280020004880128</SIMIO>
+        <SIMIO cmd="B0" p1="0" p2="0" p3="4" data="">144,0,FFFFFFFF</SIMIO>
+    </EF>
+
+    <DF name="TELECOM" path="7F10">
+        <DF name="PHONEBOOK" path="5F3A">
+            <EF name="EF_PBR" id="4F30" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62198205422100400283024F308A01058B036F0606800200808800</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="40" data="">144,0,A81EC0034F3A01C1034F3306C5034F0902C4034F1104C6034F2503C9034F3107A905CA034F5008AA0FC2034F4A09C7034F4B0AC8034F4C0BFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="40" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_GAS" id="4F4C" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A8205422100140A83024F4C8A01058B036F060E800200C8880158</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="3" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="4" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="5" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="6" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="7" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="8" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="9" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="A" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_ADN" id="4F3A" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A82054221001C1483024F3A8A01058B036F060E80020230880108</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="3" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="4" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="5" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="6" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="7" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="8" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="9" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="A" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="B" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="C" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="D" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="E" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="F" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="10" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="11" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="12" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="13" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="14" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_IAP" id="4F33" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A820542210001FA83024F338A01058B036F060E800200FA880130</SIMIO>
+            </EF>
+            <EF name="EF_PBC" id="4F09" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A820542210002FA83024F098A01058B036F060E800201F4880110</SIMIO>
+            </EF>
+            <EF name="EF_ANR" id="4F11" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A82054221000FFA83024F118A01058B036F060E80020EA6880120</SIMIO>
+            </EF>
+            <!-- EF_SNE, EF_AAS, EF_EXT1, EF_GRP, EF_UID, EF_EMAIL, EF_CCP1, EF_PUR1 ... -->
+        </DF>
+    </DF>
+
+    <ADF name="USIM" path="7FFF" aid="A0000000871002FF86FF0389FFFFFFFF">
+        <EF name="EF_IMSI" id="6F07" structure="transparent">
+            <CIMI>310260000000000</CIMI>
+        </EF>
+        <EF name="EF_MSISDN" id="6F40" structure="linear fixed">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621982054221001C0283026F408A01058B036F0605800200388800</SIMIO>
+            <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,00000000000000000000000000000891688118109844F0FFFFFFFFFF</SIMIO>
+        </EF>
+        <EF name="EF_MBI" id="6FC9" structure="linear fixed">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62258205422100040183026FC9A503C001408A01058B066F060103000080020004810200188800</SIMIO>
+            <SIMIO cmd="B2" p1="1" p2="4" p3="4" data="">144,0,01000000</SIMIO>
+       </EF>
+       <EF name="EF_AD" id="6FAD" structure="transparent">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183026FAD8A01058B036F060180020004880118</SIMIO>
+            <SIMIO cmd="B0" p1="0" p2="0" p3="4" data="">144,0,00000002</SIMIO>
+       </EF>
+       <EF name="EF_MBDN" id="6FC7" structure="linear fixed">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62258205422100260483026FC7A503C001408A01058B066F060103000080020098810200AC8800</SIMIO>
+           <SIMIO cmd="DC" p1="1" p2="4" p3="26" data="74616741FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06812143658709FFFFFFFFFFFFFF">144,0</SIMIO>
+           <SIMIO cmd="DC" p1="1" p2="4" p3="26" data="74616742FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06819078563412FFFFFFFFFFFFFF">144,0</SIMIO>
+           <SIMIO cmd="DC" p1="1" p2="4" p3="26" data="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF">144,0</SIMIO>
+       </EF>
+       <EF name="EF_MWIS" id="6FCA" structure="linear fixed">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62198205422100050183026FCA8A01058B036F060E800200058800</SIMIO>
+           <SIMIO cmd="B2" p1="1" p2="4" p3="5" data="">144,0,0000000000</SIMIO>
+       </EF>
+       <EF name="EF_VOICE_MAIL_INDICATOR_CPHS" id="6F11" structure="transparent">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">106,130</SIMIO>
+       </EF>
+       <EF name="EF_FPLMN" id="6F7B" structure="transparent">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621C8202412183026F7BA5038001718A01058B036F06038002001E880168</SIMIO>
+           <SIMIO cmd="B0" p1="0" p2="0" p3="1E" data="">144,0,64F00064F02064F04064F07064F080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+       </EF>
+       <EF name="EF_FDN" id="6F3B" structure="linear fixed">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621982054221001C0A83026F3B8A01058B036F0605800201188800</SIMIO>
+           <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="2" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="3" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="4" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="5" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="6" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="7" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="8" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="9" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="A" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+       </EF>
+       <!-- Other USIM files... -->
+     </ADF>
+</MF>
+
+<ADF name="PKCS15" aid="A000000063504B43532D3135">
+    <File id="4300">
+        <CGLA cmd="00a40004024300">76,62228202412183024300A503C001408A01058B066F0601010001800201DC810201EE88009000</CGLA>
+        <CGLA cmd="00b00000004300">516,30088200300404024310301AA0120410A000000476416E64726F696443545340300404024311301AA0120410A000000476416E64726F696443545341300404024312301AA0120410A000000476416E64726F696443545342300404024313301AA0120410A000000476416E64726F696443545343300404024314301AA0120410A000000476416E64726F696443545344300404024315301AA0120410A000000476416E64726F696443545345300404024316301AA0120410A000000476416E64726F6964435453463004040243173010A0080406FFFFFFFFFFFF300404024318301AA0120410A000000476416E64726F696443545347300404024313301AA0129000</CGLA>
+    </File>
+    <File id="4318">
+        <CGLA cmd="00a40004024318">76,62228202412183024318A503C001408A01058B066F0601010001800200188102002A88009000</CGLA>
+        <CGLA cmd="00b00000004318">124,3016041461ED377E85D386A8DFEE6B864BD85B0BFAA5AF8130220420CE7B2B47AE2B7552C8F92CC29124279883041FB623A5F194A82C9BF15D492AA09000</CGLA>
+    </File>
+</ADF>
+
+<ADF name="" aid="CSIM">
+    <CSIM cmd="0070000001">6,019000</CSIM>
+    <CSIM cmd="80f2000000">110,62338202782183023F00A50C80016187010183040007DBF08A01058B062F0601020002C60C90016083010183010A83010D8102FFFF9000</CSIM>
+    <CSIM cmd="0070000000">6,019000</CSIM>
+    <CSIM cmd="0070800100">4,9000</CSIM>
+    <CSIM cmd="80F20000">4,6C35</CSIM>
+    <CGLA cmd="00A40000023F00">4,6B00</CGLA>
+    <CGLA cmd="00A4000C023F00">4,9000</CGLA>
+    <CGLA cmd="00ff000000">4,6D00</CGLA>
+    <CGLA cmd="81f2ff0000">4,6B00</CGLA>
+    <CGLA cmd="00a4000c02FFFF">4,6A82</CGLA>
+    <CGLA cmd="0170830100">4,6A81</CGLA>
+    <CGLA cmd="fff2000000">4,6E00</CGLA>
+    <CGLA cmd="00a4000c022FE2">4,9000</CGLA>
+    <CGLA cmd="00b0000000">24,983311111111111111029000</CGLA>
+    <CGLA cmd="00a40004022F06">78,622382054221004A1283022F06A503C001408A01058B062F060101000080020534810205489000</CGLA>
+    <!-- more CSIM Command -->
+</ADF>
+
+<ADF name="" aid="">
+    <CSIM cmd='10,"0070000001"'>6,019000</CSIM>
+    <CGLA cmd='1,14,"81F2FF0000"'>4,6b00</CGLA>
+    <!-- more CGLA Command -->
+</ADF>
+
+<PinProfile>
+    <!-- PIN: PINSTATE_ENABLED_NOT_VERIFIED -->
+    <!-- PUK: PINSTATE_ENABLED_BLOCKED -->
+    <!-- Ready: PINSTATE_UNKNOWN -->
+    <PINSTATE>PINSTATE_UNKNOWN</PINSTATE>
+    <PINCODE>1234</PINCODE>
+    <PUKCODE>12345678</PUKCODE>
+    <PINREMAINTIMES>3</PINREMAINTIMES>
+    <PUKREMAINTIMES>10</PUKREMAINTIMES>
+    <PIN2CODE>1234</PIN2CODE>
+    <PUK2CODE>12345678</PUK2CODE>
+    <PIN2REMAINTIMES>3</PIN2REMAINTIMES>
+    <PUK2REMAINTIMES>10</PUK2REMAINTIMES>
+</PinProfile>
+
+<FacilityLock>
+    <SC>DISABLE</SC>
+    <FD>DISABLE</FD>
+    <AO>DISABLE</AO>
+    <OI>DISABLE</OI>
+    <AI>DISABLE</AI>
+    <IR>DISABLE</IR>
+    <AB>DISABLE</AB>
+    <AG>DISABLE</AG>
+    <AC>DISABLE</AC>
+</FacilityLock>
+
+<SETUPMENU cmd="25" text="D0388103012500820281820509804E2D56FD79FB52A88F10508000530049004D5FEB6377786E8BA48F104E80005500530049004D53614FE1606F">
+    <SELECTITEM id="1" cmd="24" menuId="50" text="D02D8103012400820281828F0A018053E34EE48BBE7F6E8F0A02804E1A52A14ECB7ECD8F0A0380724867434FE1606F">
+        <SELECTITEM id="1" cmd="24" menuId="01" text="D0218103012400820281828F0A01806DFB52A083DC53558F0A02805220966483DC5355">
+            <DISPLAYTEXT id="1" cmd="21" menuId="01" text="D0228103012181820281028D1708662F542666F465B04E0B8F7D83DC535552178868FF1F"></DISPLAYTEXT>
+            <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D01A8103012101820281028D0F0883DC5355522096646210529FFF01"></DISPLAYTEXT>
+        </SELECTITEM>
+        <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D081BB8103012181820281028D81AF08201C00530049004D5FEB6377786E8BA4201D662F4E2D56FD79FB52A863D04F9B7684FF0C57FA4E8E624B673A00530049004D53617684727982725B8951688EAB4EFD8BA48BC1670D52A1300276F86BD44F207EDF75286237540D5BC678018BA48BC165B95F0FFF0C5B83517767094E0D53EF62E6622A30014E0D4F208F935BC6780130014F7F75285FEB63777B49727970B9FF0C662F60A87545884C4E9280547F5176848EAB4EFD536B58EB3002"></DISPLAYTEXT>
+        <DISPLAYTEXT id="3" cmd="21" menuId="03" text="D02E8103012181820281028D23084E2D56FD79FB52A8901A4FE167099650516C53F8FF0C0031002E00307248672C3002">
+        </DISPLAYTEXT>
+    </SELECTITEM>
+    <SELECTITEM id="2" cmd="24" menuId="4E" text="D04E810301240082028182850F80005500530049004D53614FE1606F8F0A0180536172477C7B578B8F14028075358BDD53F7780153CA77ED4FE15BB991CF8F100380004F00540041529F80FD4ECB7ECD">
+        <DISPLAYTEXT id="1" cmd="21" menuId="01" text="D03A8103012181820281028D2F08666E901A005500530049004D5361002000560032002E003000410027FF0C652F6301004F005400410033529F80FD"></DISPLAYTEXT>
+        <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D05C8103012181820281028D510875358BDD53F77801672C5B5850A85BB991CF0035003000306761FF0C5DF2752875358BDD672C003100336761FF0C77ED4FE15B5850A85BB991CF003500306761FF0C5DF2752877ED4FE1003400396761"></DISPLAYTEXT>
+        <DISPLAYTEXT id="3" cmd="21" menuId="03" text="D05E8103012181820281028D5308004F00540041529F80FD53EF5229752877ED4FE1606F901A9053FF0C5E2E52A95BA262375B9E73B0005500530049004D536151854E1A52A183DC5355768452A860014E0B8F7D3001522096644E0E66F465B0"></DISPLAYTEXT>
+    </SELECTITEM>
+</SETUPMENU>
+
+</IccProfile>
diff --git a/host/commands/modem_simulator/files/numeric_operator.xml b/host/commands/modem_simulator/files/numeric_operator.xml
new file mode 100644
index 0000000..202c84b
--- /dev/null
+++ b/host/commands/modem_simulator/files/numeric_operator.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <add-resource name="numeric_to_operator" type="array"/>
+    <string-array name="numeric_to_operator">
+        <item numeric="311740">TelAlaska=TelAlaska</item>
+        <item numeric="310260">T-Mobile=TMOBILE</item>
+        <item numeric="46000">China Mobile=CMCC</item>
+        <item numeric="46001">China UNICOM=UNICOM</item>
+        <item numeric="46002">China Mobile=CMCC</item>
+        <item numeric="46003">China Telecom=CT</item>
+        <item numeric="46004">China Mobile=CMCC</item>
+        <item numeric="46005">China Telecom=CT</item>
+        <item numeric="46006">China UNICOM=UNICOM</item>
+        <item numeric="46007">China Mobile=CMCC</item>
+        <item numeric="46008">China Mobile=CMCC</item>
+        <item numeric="46009">China UNICOM=UNICOM</item>
+        <item numeric="46011">China Telecom=CT</item>
+    </string-array>
+</resources>
diff --git a/host/commands/modem_simulator/main.cpp b/host/commands/modem_simulator/main.cpp
new file mode 100644
index 0000000..794ad77
--- /dev/null
+++ b/host/commands/modem_simulator/main.cpp
@@ -0,0 +1,163 @@
+//
+// 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.
+
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <limits>
+
+#include "common/libs/device_config/device_config.h"
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/tee_logging.h"
+#include "host/commands/modem_simulator/modem_simulator.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+// we can start multiple modems simultaneously; each modem
+// will listent to one server fd for incoming sms/phone call
+// there should be at least 1 valid fd
+DEFINE_string(server_fds, "", "A comma separated list of file descriptors");
+DEFINE_int32(sim_type, 1, "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
+
+std::vector<cuttlefish::SharedFD> ServerFdsFromCmdline() {
+  // Validate the parameter
+  std::string fd_list = FLAGS_server_fds;
+  for (auto c: fd_list) {
+    if (c != ',' && (c < '0' || c > '9')) {
+      LOG(ERROR) << "Invalid file descriptor list: " << fd_list;
+      std::exit(1);
+    }
+  }
+
+  auto fds = android::base::Split(fd_list, ",");
+  std::vector<cuttlefish::SharedFD> shared_fds;
+  for (auto& fd_str: fds) {
+    auto fd = std::stoi(fd_str);
+    auto shared_fd = cuttlefish::SharedFD::Dup(fd);
+    close(fd);
+    shared_fds.push_back(shared_fd);
+  }
+
+  return shared_fds;
+}
+
+int main(int argc, char** argv) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  google::ParseCommandLineFlags(&argc, &argv, false);
+
+  // Modem simulator log saved in cuttlefish_runtime
+  auto config = cuttlefish::CuttlefishConfig::Get();
+  auto instance = config->ForDefaultInstance();
+
+  auto modem_log_path = instance.PerInstancePath("modem_simulator.log");
+
+  {
+    auto log_path = instance.launcher_log_path();
+    std::vector<std::string> log_files{log_path, modem_log_path};
+    android::base::SetLogger(cuttlefish::LogToStderrAndFiles(log_files));
+  }
+
+  LOG(INFO) << "Start modem simulator, server_fds: " << FLAGS_server_fds
+            << ", Sim type: " << ((FLAGS_sim_type == 2) ?
+                "special for CtsCarrierApiTestCases" : "normal" );
+
+  auto server_fds = ServerFdsFromCmdline();
+  if (server_fds.empty()) {
+    LOG(ERROR) << "Need to provide server fd";
+    return -1;
+  }
+
+  cuttlefish::NvramConfig::InitNvramConfigService(server_fds.size(), FLAGS_sim_type);
+
+  // Don't get a SIGPIPE from the clients
+  if (sigaction(SIGPIPE, nullptr, nullptr) != 0) {
+    LOG(ERROR) << "Failed to set SIGPIPE to be ignored: " << strerror(errno);
+  }
+
+  auto nvram_config = cuttlefish::NvramConfig::Get();
+  auto nvram_config_file = nvram_config->ConfigFileLocation();
+
+  // Start channel monitor, wait for RIL to connect
+  int32_t modem_id = 0;
+  std::vector<std::shared_ptr<cuttlefish::ModemSimulator>> modem_simulators;
+
+  for (auto& fd : server_fds) {
+    CHECK(fd->IsOpen()) << "Error creating or inheriting modem simulator server: "
+        << fd->StrError();
+
+    auto modem_simulator = std::make_shared<cuttlefish::ModemSimulator>(modem_id);
+    auto channel_monitor =
+        std::make_unique<cuttlefish::ChannelMonitor>(modem_simulator.get(), fd);
+
+    modem_simulator->Initialize(std::move(channel_monitor));
+
+    modem_simulators.push_back(modem_simulator);
+
+    modem_id++;
+  }
+
+  // Monitor exit request and
+  // remote call, remote sms from other cuttlefish instance
+  std::string monitor_socket_name = "modem_simulator";
+  std::stringstream ss;
+  ss << instance.host_port();
+  monitor_socket_name.append(ss.str());
+
+  auto monitor_socket = cuttlefish::SharedFD::SocketLocalServer(
+      monitor_socket_name.c_str(), true, SOCK_STREAM, 0666);
+  if (!monitor_socket->IsOpen()) {
+    LOG(ERROR) << "Unable to create monitor socket for modem simulator";
+    std::exit(cuttlefish::kServerError);
+  }
+
+  // Server loop
+  while (true) {
+    cuttlefish::SharedFDSet read_set;
+    read_set.Set(monitor_socket);
+    int num_fds = cuttlefish::Select(&read_set, nullptr, nullptr, nullptr);
+    if (num_fds <= 0) {  // Ignore select error
+      LOG(ERROR) << "Select call returned error : " << strerror(errno);
+    } else if (read_set.IsSet(monitor_socket)) {
+      auto conn = cuttlefish::SharedFD::Accept(*monitor_socket);
+      std::string buf(4, ' ');
+      auto read = cuttlefish::ReadExact(conn, &buf);
+      if (read <= 0) {
+        conn->Close();
+        LOG(WARNING) << "Detected close from the other side";
+        continue;
+      }
+      if (buf == "STOP") {  // Exit request from parent process
+        LOG(INFO) << "Exit request from parent process";
+        nvram_config->SaveToFile(nvram_config_file);
+        for (auto modem : modem_simulators) {
+          modem->SaveModemState();
+        }
+        cuttlefish::WriteAll(conn, "OK"); // Ignore the return value. Exit anyway.
+        std::exit(cuttlefish::kSuccess);
+      } else if (buf.compare(0, 3, "REM") == 0) {  // REMO for modem id 0 ...
+        // Remote request from other cuttlefish instance
+        int id = std::stoi(buf.substr(3, 1));
+        if (id >= modem_simulators.size()) {
+          LOG(ERROR) << "Not supported modem simulator count: " << id;
+        } else {
+          modem_simulators[id]->SetRemoteClient(conn, true);
+        }
+      }
+    }
+  }
+  // Until kill or exit
+}
diff --git a/host/commands/modem_simulator/misc_service.cpp b/host/commands/modem_simulator/misc_service.cpp
new file mode 100644
index 0000000..1a2b767
--- /dev/null
+++ b/host/commands/modem_simulator/misc_service.cpp
@@ -0,0 +1,167 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/misc_service.h"
+
+#include <ctime>
+#include <fstream>
+#include <iomanip>
+
+namespace cuttlefish {
+
+MiscService::MiscService(int32_t service_id, ChannelMonitor* channel_monitor,
+                         ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {
+  ParseTimeZone();
+}
+
+void MiscService::ParseTimeZone() {
+#if defined(__linux__)
+  constexpr char TIMEZONE_FILENAME[] = "/etc/timezone";
+  std::ifstream ifs(TIMEZONE_FILENAME);
+  if (ifs.is_open()) {
+    std::string line;
+    if (std::getline(ifs, line)) {
+      FixTimeZone(line);
+      timezone_ = line;
+    }
+  }
+#endif
+}
+
+void MiscService::FixTimeZone(std::string& line) {
+  auto slashpos = line.find("/");
+  // "/" will be treated as separator, change it !
+  if (slashpos != std::string::npos) {
+    line.replace(slashpos, 1, "!");
+  }
+}
+
+void MiscService::SetTimeZone(std::string timezone) {
+  FixTimeZone(timezone);
+  timezone_ = timezone;
+}
+
+std::vector<CommandHandler> MiscService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      /* initializeCallback */
+      CommandHandler("E0Q0V1",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("S0=0",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CMEE=1",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CMOD=0",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CSSN=0,1",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+COLP=0",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CSCS=\"HEX\"",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+      CommandHandler("+CMGF=0",
+                     [this](const Client& client) {
+                       this->HandleCommandDefaultSupported(client);
+                     }),
+
+      CommandHandler("+CGSN",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleGetIMEI(client, cmd);
+                     }),
+  };
+  return (command_handlers);
+}
+
+void MiscService::HandleGetIMEI(const Client& client, std::string& command) {
+  const std::string identityGsmImei = "867400022047199";
+  const std::string identityGsmSvn = "01";
+  const std::string information = "modem simulator";
+
+  std::vector<std::string> responses;
+
+  if (command == "AT+CGSN") {
+    responses.push_back(identityGsmImei);
+  } else {
+    CommandParser cmd(command);
+    cmd.SkipPrefix();
+    int snt = cmd.GetNextInt();
+    switch (snt) {
+      case 0:  // SN: IMEI and more information provided by manufacturers
+        responses.push_back(identityGsmImei + information);
+        break;
+      case 1:  // IMEI
+        responses.push_back(identityGsmImei);
+        break;
+      case 2:  // IMEI and software version number
+        responses.push_back(identityGsmImei + identityGsmSvn);
+        break;
+      case 3:  // Software version number
+        responses.push_back(identityGsmSvn);
+        break;
+      default:  // Default IMEI
+        responses.push_back(identityGsmImei);
+        break;
+    }
+  }
+
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+void MiscService::TimeUpdate() {
+  auto now = std::time(0);
+
+  auto local_time = *std::localtime(&now);
+  auto gm_time = *std::gmtime(&now);
+
+  auto t_local_time = std::mktime(&local_time);
+  auto t_gm_time = std::mktime(&gm_time);
+
+  // Timezone offset is in number of quarter-hours
+  auto tzdiff = (int)std::difftime(t_local_time, t_gm_time) / (15 * 60);
+
+  std::stringstream ss;
+  ss << "%CTZV: \"" << std::setfill('0') << std::setw(2)
+     << local_time.tm_year % 100 << "/" << std::setfill('0') << std::setw(2)
+     << local_time.tm_mon + 1 << "/" << std::setfill('0') << std::setw(2)
+     << local_time.tm_mday << "," << std::setfill('0') << std::setw(2)
+     << local_time.tm_hour << ":" << std::setfill('0') << std::setw(2)
+     << local_time.tm_min << ":" << std::setfill('0') << std::setw(2)
+     << local_time.tm_sec << (tzdiff >= 0 ? '+' : '-')
+     << (tzdiff >= 0 ? tzdiff : -tzdiff) << ":" << local_time.tm_isdst;
+  if (!timezone_.empty()) {
+    ss << ":" << timezone_;
+  }
+  ss << "\"";
+
+  SendUnsolicitedCommand(ss.str());
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/misc_service.h b/host/commands/modem_simulator/misc_service.h
new file mode 100644
index 0000000..e795a06
--- /dev/null
+++ b/host/commands/modem_simulator/misc_service.h
@@ -0,0 +1,44 @@
+//
+// 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 "host/commands/modem_simulator/modem_service.h"
+
+namespace cuttlefish {
+
+class MiscService : public ModemService, public std::enable_shared_from_this<MiscService>  {
+ public:
+  MiscService(int32_t service_id, ChannelMonitor* channel_monitor,
+              ThreadLooper* thread_looper);
+  ~MiscService() = default;
+
+  MiscService(const MiscService &) = delete;
+  MiscService &operator=(const MiscService &) = delete;
+
+  void HandleGetIMEI(const Client& client, std::string& command);
+
+  void TimeUpdate();
+
+  void SetTimeZone(std::string timezone);
+
+ private:
+  void ParseTimeZone();
+  void FixTimeZone(std::string& line);
+  std::string timezone_;
+  std::vector<CommandHandler> InitializeCommandHandlers();
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/modem_service.cpp b/host/commands/modem_simulator/modem_service.cpp
new file mode 100644
index 0000000..062da6f
--- /dev/null
+++ b/host/commands/modem_simulator/modem_service.cpp
@@ -0,0 +1,147 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/modem_service.h"
+
+#include <android-base/logging.h>
+
+#include <cstring>
+
+#include "host/commands/modem_simulator/device_config.h"
+
+namespace cuttlefish {
+
+const std::string ModemService::kCmeErrorOperationNotAllowed      = "+CME ERROR: 3";
+const std::string ModemService::kCmeErrorOperationNotSupported    = "+CME ERROR: 4";
+const std::string ModemService::kCmeErrorSimNotInserted           = "+CME ERROR: 10";
+const std::string ModemService::kCmeErrorSimPinRequired           = "+CME ERROR: 11";
+const std::string ModemService::kCmeErrorSimPukRequired           = "+CME ERROR: 12";
+const std::string ModemService::kCmeErrorSimBusy                  = "+CME ERROR: 14";
+const std::string ModemService::kCmeErrorIncorrectPassword        = "+CME ERROR: 16";
+const std::string ModemService::kCmeErrorMemoryFull               = "+CME ERROR: 20";
+const std::string ModemService::kCmeErrorInvalidIndex             = "+CME ERROR: 21";
+const std::string ModemService::kCmeErrorNotFound                 = "+CME ERROR: 22";
+const std::string ModemService::kCmeErrorInvalidCharactersInTextString = "+CME ERROR: 27";
+const std::string ModemService::kCmeErrorNoNetworkService         = "+CME ERROR: 30";
+const std::string ModemService::kCmeErrorNetworkNotAllowedEmergencyCallsOnly = "+CME ERROR: 32";
+const std::string ModemService::kCmeErrorInCorrectParameters      = "+CME ERROR: 50";
+const std::string ModemService::kCmeErrorNetworkNotAttachedDueToMTFunctionalRestrictions = "+CME ERROR: 53";
+const std::string ModemService::kCmeErrorFixedDialNumberOnlyAllowed = "+CME ERROR: 56";
+
+const std::string ModemService::kCmsErrorOperationNotAllowed      = "+CMS ERROR: 302";
+const std::string ModemService::kCmsErrorOperationNotSupported    = "+CMS ERROR: 303";
+const std::string ModemService::kCmsErrorInvalidPDUModeParam      = "+CMS ERROR: 304";
+const std::string ModemService::kCmsErrorSCAddressUnknown         = "+CMS ERROR: 304";
+
+const std::pair<int, int> ModemService::kRemotePortRange =
+    std::make_pair(6520, 6527);
+
+CommandHandler::CommandHandler(const std::string& command, f_func handler)
+    : command_prefix(command),
+      match_mode(FULL_MATCH),
+      f_command_handler(handler) {}
+
+CommandHandler::CommandHandler(const std::string& command, p_func handler)
+    : command_prefix(command),
+      match_mode(PARTIAL_MATCH),
+      p_command_handler(handler) {}
+
+int CommandHandler::Compare(const std::string& command) const {
+  int result = -1;
+  if (match_mode == PARTIAL_MATCH) {
+    result = command.compare(2, command_prefix.size(), command_prefix);  // skip "AT"
+  } else {
+    result = command.compare(2, command.size(), command_prefix);
+  }
+  return result;
+}
+
+void CommandHandler::HandleCommand(const Client& client,
+                                   std::string& command) const {
+  if (match_mode == PARTIAL_MATCH && p_command_handler != nullptr) {
+    (*p_command_handler)(client, command);
+  } else if (match_mode == FULL_MATCH && f_command_handler != nullptr) {
+    (*f_command_handler)(client);
+  } else {
+    LOG(ERROR) << "Mismatched mode and handler, CHECK!";
+  }
+}
+
+ModemService::ModemService(int32_t service_id,
+                           std::vector<CommandHandler> command_handlers,
+                           ChannelMonitor* channel_monitor,
+                           ThreadLooper* thread_looper)
+    : service_id_(service_id),
+      command_handlers_(command_handlers),
+      thread_looper_(thread_looper),
+      channel_monitor_(channel_monitor) {}
+
+bool ModemService::HandleModemCommand(const Client& client,
+                                      std::string command) {
+  for (auto& handler : command_handlers_) {
+    if (handler.Compare(command) == 0) {
+      handler.HandleCommand(client, command);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void ModemService::HandleCommandDefaultSupported(const Client& client) {
+  std::string response{"OK\r"};
+  client.SendCommandResponse(response);
+}
+
+void ModemService::SendUnsolicitedCommand(std::string unsol_command) {
+  if (channel_monitor_) {
+    channel_monitor_->SendUnsolicitedCommand(unsol_command);
+    ;
+  }
+}
+
+cuttlefish::SharedFD ModemService::ConnectToRemoteCvd(std::string port) {
+  std::string remote_sock_name = "modem_simulator" + port;
+  auto remote_sock = cuttlefish::SharedFD::SocketLocalClient(
+      remote_sock_name.c_str(), true, SOCK_STREAM);
+  if (!remote_sock->IsOpen()) {
+    LOG(ERROR) << "Failed to connect to remote cuttlefish: " << port
+               << ", error: " << strerror(errno);
+  }
+  return remote_sock;
+}
+
+void ModemService::SendCommandToRemote(cuttlefish::SharedFD remote_client, std::string response) {
+  if (channel_monitor_) {
+    channel_monitor_->SendRemoteCommand(remote_client, response);
+    ;
+  }
+}
+
+void ModemService::CloseRemoteConnection(cuttlefish::SharedFD remote_client) {
+  if (channel_monitor_) {
+    channel_monitor_->CloseRemoteConnection(remote_client);
+    ;
+  }
+}
+
+std::string ModemService::GetHostPort() {
+  auto host_port = cuttlefish::modem::DeviceConfig::host_port();
+  std::stringstream ss;
+  ss << host_port;
+  return ss.str();
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/modem_service.h b/host/commands/modem_simulator/modem_service.h
new file mode 100644
index 0000000..0b75d7d
--- /dev/null
+++ b/host/commands/modem_simulator/modem_service.h
@@ -0,0 +1,115 @@
+//
+// 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 <functional>
+#include <map>
+#include <optional>
+
+#include "host/commands/modem_simulator/channel_monitor.h"
+#include "host/commands/modem_simulator/command_parser.h"
+#include "host/commands/modem_simulator/thread_looper.h"
+
+namespace cuttlefish {
+
+enum ModemServiceType : int {
+  kSimService     = 0,
+  kNetworkService = 1,
+  kDataService    = 2,
+  kCallService    = 3,
+  kSmsService     = 4,
+  kSupService     = 5,
+  kStkService     = 6,
+  kMiscService    = 7,
+};
+
+using f_func = std::function<void(const Client&)>;                // Full match
+using p_func = std::function<void(const Client&, std::string&)>;  // Partial match
+
+class CommandHandler {
+ public:
+  CommandHandler(const std::string& command, f_func handler);
+  CommandHandler(const std::string& command, p_func handler);
+
+  ~CommandHandler() = default;
+
+  int Compare(const std::string& command) const;
+  void HandleCommand(const Client& client, std::string& command) const;
+
+ private:
+  enum MatchMode {FULL_MATCH = 0, PARTIAL_MATCH = 1};
+
+  std::string command_prefix;
+  MatchMode match_mode;
+
+  std::optional<f_func> f_command_handler;
+  std::optional<p_func> p_command_handler;
+};
+
+class ModemService {
+ public:
+
+  virtual ~ModemService() = default;
+
+  ModemService(const ModemService &) = delete;
+  ModemService &operator=(const ModemService &) = delete;
+
+  bool HandleModemCommand(const Client& client, std::string command);
+
+  static const std::string kCmeErrorOperationNotAllowed;
+  static const std::string kCmeErrorOperationNotSupported;
+  static const std::string kCmeErrorSimNotInserted;
+  static const std::string kCmeErrorSimPinRequired;
+  static const std::string kCmeErrorSimPukRequired;
+  static const std::string kCmeErrorSimBusy;
+  static const std::string kCmeErrorIncorrectPassword;
+  static const std::string kCmeErrorMemoryFull;
+  static const std::string kCmeErrorInvalidIndex;
+  static const std::string kCmeErrorNotFound;
+  static const std::string kCmeErrorInvalidCharactersInTextString;
+  static const std::string kCmeErrorNoNetworkService;
+  static const std::string kCmeErrorNetworkNotAllowedEmergencyCallsOnly;
+  static const std::string kCmeErrorInCorrectParameters;
+  static const std::string kCmeErrorNetworkNotAttachedDueToMTFunctionalRestrictions;
+  static const std::string kCmeErrorFixedDialNumberOnlyAllowed;
+
+  static const std::string kCmsErrorOperationNotAllowed;
+  static const std::string kCmsErrorOperationNotSupported;
+  static const std::string kCmsErrorInvalidPDUModeParam;
+  static const std::string kCmsErrorSCAddressUnknown;
+
+  static const std::pair<int, int> kRemotePortRange;
+
+ protected:
+  ModemService(int32_t service_id, std::vector<CommandHandler> command_handlers,
+               ChannelMonitor* channel_monitor, ThreadLooper* thread_looper);
+  void HandleCommandDefaultSupported(const Client& client);
+  void SendUnsolicitedCommand(std::string unsol_command);
+
+  cuttlefish::SharedFD ConnectToRemoteCvd(std::string port);
+  void SendCommandToRemote(cuttlefish::SharedFD remote_client,
+                           std::string response);
+  void CloseRemoteConnection(cuttlefish::SharedFD remote_client);
+  static std::string GetHostPort();
+
+  int32_t service_id_;
+  const std::vector<CommandHandler> command_handlers_;
+  ThreadLooper* thread_looper_;
+  ChannelMonitor* channel_monitor_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/modem_simulator.cpp b/host/commands/modem_simulator/modem_simulator.cpp
new file mode 100644
index 0000000..61a23bd
--- /dev/null
+++ b/host/commands/modem_simulator/modem_simulator.cpp
@@ -0,0 +1,161 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/modem_simulator.h"
+
+#include <android-base/logging.h>
+
+#include <memory>
+
+#include "host/commands/modem_simulator/call_service.h"
+#include "host/commands/modem_simulator/data_service.h"
+#include "host/commands/modem_simulator/misc_service.h"
+#include "host/commands/modem_simulator/network_service.h"
+#include "host/commands/modem_simulator/sim_service.h"
+#include "host/commands/modem_simulator/sms_service.h"
+#include "host/commands/modem_simulator/stk_service.h"
+#include "host/commands/modem_simulator/sup_service.h"
+
+namespace cuttlefish {
+
+ModemSimulator::ModemSimulator(int32_t modem_id)
+    : modem_id_(modem_id), thread_looper_(new ThreadLooper()) {}
+
+ModemSimulator::~ModemSimulator() {
+  // this will stop the looper so all the callbacks
+  // will be gone;
+  thread_looper_->Stop();
+  modem_services_.clear();
+}
+
+void ModemSimulator::LoadNvramConfig() {
+  auto nvram_config = NvramConfig::Get();
+  if (!nvram_config) {
+    LOG(FATAL) << "Failed to obtain nvram config singleton";
+    return;
+  }
+}
+
+void ModemSimulator::Initialize(
+    std::unique_ptr<ChannelMonitor>&& channel_monitor) {
+  channel_monitor_ = std::move(channel_monitor);
+  LoadNvramConfig();
+  RegisterModemService();
+}
+
+void ModemSimulator::RegisterModemService() {
+  auto networkservice = std::make_unique<NetworkService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+  auto simservice = std::make_unique<SimService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+  auto miscservice = std::make_unique<MiscService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+  auto callservice = std::make_unique<CallService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+  auto stkservice = std::make_unique<StkService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+  auto smsservice = std::make_unique<SmsService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+  auto dataservice = std::make_unique<DataService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+  auto supservice = std::make_unique<SupService>(
+      modem_id_, channel_monitor_.get(), thread_looper_.get());
+
+  networkservice->SetupDependency(miscservice.get(), simservice.get(),
+                                  dataservice.get());
+  simservice->SetupDependency(networkservice.get());
+  callservice->SetupDependency(simservice.get(), networkservice.get());
+  stkservice->SetupDependency(simservice.get());
+  smsservice->SetupDependency(simservice.get());
+
+  sms_service_ = smsservice.get();
+  sim_service_ = simservice.get();
+  misc_service_ = miscservice.get();
+  network_service_ = networkservice.get();
+  modem_services_[kSimService] = std::move(simservice);
+  modem_services_[kNetworkService] = std::move(networkservice);
+  modem_services_[kCallService] = std::move(callservice);
+  modem_services_[kDataService] = std::move(dataservice);
+  modem_services_[kSmsService] = std::move(smsservice);
+  modem_services_[kSupService] = std::move(supservice);
+  modem_services_[kStkService] = std::move(stkservice);
+  modem_services_[kMiscService] = std::move(miscservice);
+}
+
+void ModemSimulator::DispatchCommand(const Client& client, std::string& command) {
+  if (sms_service_) {
+    if (sms_service_->IsWaitingSmsPdu()) {
+      sms_service_->HandleSendSMSPDU(client, command);
+      return;
+    } else if (sms_service_->IsWaitingSmsToSim()) {
+      sms_service_->HandleWriteSMSPduToSim(client, command);
+      return;
+    }
+  }
+
+  bool success = false;
+  for (auto& service : modem_services_) {
+    success = service.second->HandleModemCommand(client, command);
+    if (success) {
+      break;
+    }
+  }
+
+  if (!success && client.type != Client::REMOTE) {
+    LOG(DEBUG) << "Not supported AT command: " << command;
+    client.SendCommandResponse(ModemService::kCmeErrorOperationNotSupported);
+  }
+}
+
+void ModemSimulator::OnFirstClientConnected() {
+  if (misc_service_) {
+    misc_service_->TimeUpdate();
+  }
+
+  if (network_service_) {
+    network_service_->OnVoiceRegisterStateChanged();
+    network_service_->OnDataRegisterStateChanged();
+  }
+}
+
+void ModemSimulator::SaveModemState() {
+  if (sim_service_) {
+    sim_service_->SavePinStateToIccProfile();
+    sim_service_->SaveFacilityLockToIccProfile();
+  }
+}
+
+bool ModemSimulator::IsRadioOn() const {
+  if (network_service_) {
+    return !network_service_->isRadioOff();
+  }
+  return false;
+}
+
+bool ModemSimulator::IsWaitingSmsPdu() {
+  if (sms_service_) {
+    return (sms_service_->IsWaitingSmsPdu() |
+            sms_service_->IsWaitingSmsToSim());
+  }
+  return false;
+}
+
+void ModemSimulator::SetTimeZone(std::string timezone) {
+  if (misc_service_) {
+    misc_service_->SetTimeZone(timezone);
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/modem_simulator.h b/host/commands/modem_simulator/modem_simulator.h
new file mode 100644
index 0000000..9340e49
--- /dev/null
+++ b/host/commands/modem_simulator/modem_simulator.h
@@ -0,0 +1,68 @@
+//
+// 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 "host/commands/modem_simulator/channel_monitor.h"
+#include "host/commands/modem_simulator/modem_service.h"
+#include "host/commands/modem_simulator/nvram_config.h"
+#include "host/commands/modem_simulator/thread_looper.h"
+
+namespace cuttlefish {
+
+class SimService;
+class MiscService;
+class NetworkService;
+class SmsService;
+class ModemSimulator {
+ public:
+  ModemSimulator(int32_t modem_id);
+  ~ModemSimulator();
+
+  ModemSimulator(const ModemSimulator&) = delete;
+  ModemSimulator& operator=(const ModemSimulator&) = delete;
+
+  void Initialize(std::unique_ptr<ChannelMonitor>&& channel_monitor);
+
+  void DispatchCommand(const Client& client, std::string& command);
+
+  void OnFirstClientConnected();
+  void SaveModemState();
+  bool IsWaitingSmsPdu();
+  bool IsRadioOn() const;
+  void SetRemoteClient(cuttlefish::SharedFD client, bool is_accepted) {
+    channel_monitor_->SetRemoteClient(client, is_accepted);
+  }
+
+  void SetTimeZone(std::string timezone);
+
+ private:
+  int32_t modem_id_;
+  std::unique_ptr<ChannelMonitor> channel_monitor_;
+  std::unique_ptr<ThreadLooper> thread_looper_;
+
+  SmsService* sms_service_{nullptr};
+  SimService* sim_service_{nullptr};
+  MiscService* misc_service_{nullptr};
+  NetworkService* network_service_{nullptr};
+
+  std::map<ModemServiceType, std::unique_ptr<ModemService>> modem_services_;
+
+  static void LoadNvramConfig();
+
+  void RegisterModemService();
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/network_service.cpp b/host/commands/modem_simulator/network_service.cpp
new file mode 100644
index 0000000..56f14e5
--- /dev/null
+++ b/host/commands/modem_simulator/network_service.cpp
@@ -0,0 +1,1266 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/network_service.h"
+
+#include <android-base/logging.h>
+
+#include <map>
+#include <sstream>
+
+#include "common/libs/utils/files.h"
+#include "host/commands/modem_simulator/device_config.h"
+#include "host/commands/modem_simulator/nvram_config.h"
+#include "host/commands/modem_simulator/thread_looper.h"
+namespace cuttlefish {
+
+// string type; two byte location area code in hexadecimal format
+static const std::string kAreaCode = "2142";
+// string type; four byte GERAN/UTRAN cell ID in hexadecimal format
+static const std::string kCellId = "0000B804";
+
+// Check SignalStrength.java file for more details on how these map to
+// signal strength bars
+const std::pair<int, int> kGSMSignalStrength = std::make_pair(4, 30);
+const std::pair<int, int> kCDMASignalStrength = std::make_pair(4, 120);
+const std::pair<int, int> kEVDOSignalStrength = std::make_pair(4, 120);
+const std::pair<int, int> kLTESignalStrength = std::make_pair(4, 30);
+const std::pair<int, int> kWCDMASignalStrength = std::make_pair(4, 30);
+const std::pair<int, int> kNRSignalStrength = std::make_pair(45, 135);
+
+NetworkService::NetworkService(int32_t service_id,
+                               ChannelMonitor* channel_monitor,
+                               ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {
+  InitializeServiceState();
+}
+
+std::vector<CommandHandler> NetworkService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      CommandHandler(
+          "+CFUN?",
+          [this](const Client& client) { this->HandleRadioPowerReq(client); }),
+      CommandHandler("+CFUN=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleRadioPower(client, cmd);
+                     }),
+      CommandHandler("+REMOTECFUN=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleRadioPower(client, cmd);
+                     }),
+      CommandHandler(
+          "+CSQ",
+          [this](const Client& client) { this->HandleSignalStrength(client); }),
+      CommandHandler("+COPS?",
+                     [this](const Client& client) {
+                       this->HandleQueryNetworkSelectionMode(client);
+                     }),
+      CommandHandler("+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
+                     [this](const Client& client) {
+                       this->HandleRequestOperator(client);
+                     }),
+      CommandHandler("+COPS=?",
+                     [this](const Client& client) {
+                       this->HandleQueryAvailableNetwork(client);
+                     }),
+      CommandHandler("+COPS=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSetNetworkSelectionMode(client, cmd);
+                     }),
+      CommandHandler("+CREG",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleVoiceNetworkRegistration(client, cmd);
+                     }),
+      CommandHandler("+CGREG",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleDataNetworkRegistration(client, cmd);
+                     }),
+      CommandHandler("+CEREG",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleDataNetworkRegistration(client, cmd);
+                     }),
+      CommandHandler("+CTEC?",
+                     [this](const Client& client) {
+                       this->HandleGetPreferredNetworkType(client);
+                     }),
+      CommandHandler("+CTEC=?",
+                     [this](const Client& client) {
+                       this->HandleQuerySupportedTechs(client);
+                     }),
+      CommandHandler("+CTEC=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSetPreferredNetworkType(client, cmd);
+                     }),
+      CommandHandler("+REMOTECTEC",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleReceiveRemoteCTEC(client, cmd);
+                     }),
+      CommandHandler("+REMOTESIGNAL",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleReceiveRemoteSignal(client, cmd);
+                     }),
+      CommandHandler("+REMOTEREG",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleReceiveRemoteVoiceDataReg(client, cmd);
+                     }),
+  };
+  return (command_handlers);
+}
+
+void NetworkService::InitializeServiceState() {
+  radio_state_ = RadioState::RADIO_STATE_OFF;
+
+  modem_radio_capability_ =
+      M_MODEM_TECH_GSM | M_MODEM_TECH_WCDMA | M_MODEM_TECH_LTE | M_MODEM_TECH_NR;
+
+  auto nvram_config = NvramConfig::Get();
+  auto instance = nvram_config->ForInstance(service_id_);
+
+  // Default to be ""
+  current_operator_numeric_ = instance.operator_numeric();
+  // Default to be OPER_SELECTION_AUTOMATIC
+  oper_selection_mode_ = (OperatorSelectionMode)instance.network_selection_mode();
+  // Default to be M_MODEM_TECH_LTE | M_MODEM_TECH_WCDMA | M_MODEM_TECH_GSM;
+  preferred_network_mode_ = instance.preferred_network_mode();
+  // Default to be M_MODEM_TECH_LTE
+  current_network_mode_ = (ModemTechnology)instance.modem_technoloy();
+
+  InitializeNetworkOperator();
+
+  first_signal_strength_request_ = true;
+  android_last_signal_time_ = 0;
+}
+
+void NetworkService::InitializeNetworkOperator() {
+  operator_list_.push_back(
+      {"311740", "Android Virtual Operator", "Android", NetworkOperator::OPER_STATE_AVAILABLE});
+  operator_list_.push_back(
+      {"310300", "Alternative Operator", "Alternative", NetworkOperator::OPER_STATE_AVAILABLE});
+  operator_list_.push_back(
+      {"310400", "Hermetic Network Operator", "Hermetic", NetworkOperator::OPER_STATE_FORBIDDEN});
+
+  if (oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_AUTOMATIC) {
+    current_operator_numeric_ = operator_list_.begin()->numeric;
+    operator_list_.begin()->operator_state = NetworkOperator::OPER_STATE_CURRENT;
+  } else if (oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC) {
+    auto iter = operator_list_.begin();
+    for (; iter != operator_list_.end(); ++iter) {
+      if (iter->numeric == current_operator_numeric_) {
+        break;
+      }
+    }
+    if (iter == operator_list_.end()) {
+      current_operator_numeric_ = operator_list_.begin()->numeric;
+      operator_list_.begin()->operator_state = NetworkOperator::OPER_STATE_CURRENT;
+    } else {
+      iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
+    }
+  }
+}
+
+void NetworkService::InitializeSimOperator() {
+  if (sim_service_ == nullptr) {
+    return;
+  }
+  auto sim_operator_numeric = sim_service_->GetSimOperator();
+  if (sim_operator_numeric == "") {
+    return;
+  }
+
+  // ensure the first element is sim_operator_numeric
+  for (auto iter = operator_list_.begin(); iter != operator_list_.end();
+       ++iter) {
+    if (iter->numeric == sim_operator_numeric) {
+      std::swap(*iter, *(operator_list_.begin()));
+      return;
+    }
+  }
+
+  {
+    const char *operator_numeric_xml = "etc/modem_simulator/files/numeric_operator.xml";
+    auto file = cuttlefish::modem::DeviceConfig::DefaultHostArtifactsPath(
+        operator_numeric_xml);
+    if (!cuttlefish::FileExists(file) || !cuttlefish::FileHasContent(file)) {
+      return;
+    }
+
+    XMLDocument doc;
+    auto err = doc.LoadFile(file.c_str());
+    if (err != tinyxml2::XML_SUCCESS) {
+      LOG(ERROR) << "unable to load XML file '" << file << " ', error " << err;
+      return;
+    }
+    XMLElement *resources = doc.RootElement();
+    if (resources == NULL)  return;
+
+    XMLElement *stringArray = resources->FirstChildElement("string-array");
+    if (stringArray == NULL) return;
+
+    XMLElement *item = stringArray->FirstChildElement("item");
+    while (item) {
+      const XMLAttribute *attr_numeric = item->FindAttribute("numeric");
+      std::string numeric = attr_numeric ? attr_numeric->Value() : "";
+      if (numeric == sim_operator_numeric) {
+        break;
+      }
+      item = item->NextSiblingElement("item");
+    }
+    if (item) {
+      std::string names = item->GetText();
+      auto pos = names.find('=');
+      if (pos != std::string::npos) {
+        auto long_name = names.substr(0, pos);
+        auto short_name = names.substr(pos + 1);
+        NetworkOperator sim_operator(sim_operator_numeric, long_name,
+            short_name, NetworkOperator::OPER_STATE_AVAILABLE);
+        operator_list_.insert(operator_list_.begin(), sim_operator);
+      }
+    }
+  }
+  InitializeNetworkOperator();
+}
+
+void NetworkService::SetupDependency(MiscService* misc, SimService* sim,
+                                     DataService* data) {
+  misc_service_ = misc;
+  sim_service_ = sim;
+  data_service_ = data;
+  InitializeSimOperator();
+}
+
+void NetworkService::OnSimStatusChanged(SimService::SimStatus sim_status) {
+  if (radio_state_ == RadioState::RADIO_STATE_OFF) {
+    return;  // RegistrationState::NET_REGISTRATION_UNREGISTERED unchanged
+  }
+  if (sim_status == SimService::SIM_STATUS_READY) {
+    voice_registration_status_.registration_state = NET_REGISTRATION_HOME;
+  } else {
+    voice_registration_status_.registration_state = NET_REGISTRATION_EMERGENCY;
+    // 3GPP TS 24.008 [8] and 3GPP TS 24.301 [83] specify the condition
+    // when the MT is considered as attached for emergency bearer services.
+    // applicable only when <AcT> indicates 2,4,5,6
+    // Note: not saved to nvram config due to sim status may change after reboot
+    current_network_mode_ = M_MODEM_TECH_WCDMA;
+  }
+  thread_looper_->PostWithDelay(std::chrono::seconds(1),
+      makeSafeCallback(this, &NetworkService::UpdateRegisterState,
+          voice_registration_status_.registration_state));
+}
+
+/**
+ * AT+CFUN
+ *   Set command selects the level of functionality <fun> in the MT. Level
+ * "full functionality" is where the highest level of power is drawn.
+ * "Minimum functionality" is where minimum power is drawn. Level of functionality
+ * between these may also be specified by manufacturers. When supported by
+ * manufacturers, MT resetting with <rst> parameter may be utilized
+ *
+ * Command                Possible response(s)
+ * +CFUN=[<fun>[,<rst>]]    +CME ERROR: <err>
+ * +CFUN?                   +CFUN: <fun>
+ *                          +CME ERROR: <err>
+ *
+ * <fun>: integer type
+ *   0 minimum functionality
+ *   1 full functionality. Enable (turn on) the transmit and receive RF circuits
+ *     for all supported radio access technologies.
+ *   2 disable (turn off) MT transmit RF circuits only
+ *   3 disable (turn off) MT receive RF circuits only
+ *   4 disable (turn off) both MT transmit and receive RF circuits
+ *   5...127 reserved for manufacturers as intermediate states between full
+ *           and minimum functionality
+ *   128 Full functionality with radio access support according to the setting of +CSRA.
+ *   129 Prepare for shutdown.
+ *
+ * see RIL_REQUEST_RADIO_POWER in RIL
+ */
+void NetworkService::HandleRadioPowerReq(const Client& client) {
+  std::stringstream ss;
+  ss << "+CFUN: " << radio_state_;
+
+  std::vector<std::string> responses;
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+
+  client.SendCommandResponse(responses);
+}
+
+void NetworkService::HandleRadioPower(const Client& client, std::string& command) {
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  int on = cmd.GetNextInt();
+  switch (on) {
+    case 0:
+      radio_state_ = RadioState::RADIO_STATE_OFF;
+      UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
+      break;
+    case 1:
+      radio_state_ = RadioState::RADIO_STATE_ON;
+      if (sim_service_ != nullptr) {
+        auto sim_status = sim_service_->GetSimStatus();
+        OnSimStatusChanged(sim_status);
+      }
+      break;
+    default:
+      client.SendCommandResponse(kCmeErrorOperationNotSupported);
+      return;
+  }
+  signal_strength_.Reset();
+
+  client.SendCommandResponse("OK");
+}
+
+bool NetworkService::WakeupFromSleep() {
+  // It has not called once yet
+  if (android_last_signal_time_ == 0) {
+      return false;
+  }
+  // Heuristics: if guest has not asked for signal strength
+  // for 2 minutes, we assume it is caused by host sleep
+  time_t now = time(0);
+  const bool wakeup_from_sleep = (now > android_last_signal_time_ + 120);
+  return wakeup_from_sleep;
+}
+
+void NetworkService::SetSignalStrengthValue(int& value,
+                                            const std::pair<int, int>& range,
+                                            double percentd) {
+  value = range.first + percentd * (range.second - range.first);
+  AdjustSignalStrengthValue(value, range);
+}
+
+void NetworkService::AdjustSignalStrengthValue(int& value,
+                                               const std::pair<int, int>& range) {
+  if (value < range.first) {
+    value = range.first;
+  } else if (value > range.second) {
+    value = range.second;
+  }
+}
+/**
+ * AT+CSQ
+ *   Execution command returns received signal strength indication <rssi>
+ *   and channel bit error rate <ber> from the MT.
+ *
+ * command            Possible response(s)
+ * AT+CSQ               +CSQ: <rssi>,<ber>
+ *                      +CME ERROR: <err>
+ *
+ * <rssi>: integer type
+ *       0 ‑113 dBm or less
+ *       1 ‑111 dBm
+ *       2...30  ‑109... ‑53 dBm
+ *       31  ‑51 dBm or greater
+ *       99  not known or not detectable
+ * <ber>: integer type; channel bit error rate (in percent)
+ *      0...7 as RXQUAL values in the table in 3GPP TS 45.008 [20] subclause 8.2.4
+ *      99  not known or not detectable
+ *
+ * see RIL_REQUEST_SIGNAL_STRENGTH in RIL
+ */
+void NetworkService::HandleSignalStrength(const Client& client) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  if (WakeupFromSleep()) {
+    misc_service_->TimeUpdate();
+  } else if (first_signal_strength_request_) {
+    first_signal_strength_request_ = false;
+    misc_service_->TimeUpdate();
+  }
+
+  android_last_signal_time_ = time(0);
+
+  auto response = GetSignalStrength();
+
+  responses.push_back(response);
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+bool NetworkService::IsHasNetwork() {
+  if (radio_state_ == RADIO_STATE_OFF ||
+      oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION) {
+    return false;
+  }
+  return true;
+}
+
+/**
+ * AT+COPS
+ *    Set command forces an attempt to select and register to the
+ *    GSM/UMTS/EPS/5GS network operator using the SIM/USIM card installed
+ *    in the currently selected card slot.
+ *
+ * command                         Possible response(s)
+ * +COPS=[<mode>[,<format>          +CME ERROR: <err>
+ *       [,<oper>[,<AcT>]]]]
+ *
+ * +COPS?                           +COPS: <mode>[,<format>,<oper>[,<AcT>]]
+ *                                  +CME ERROR: <err>
+ *
+ * +COPS=?                          +COPS: [list of supported (<stat>,
+ *                                         long alphanumeric <oper>,
+ *                                         short alphanumeric <oper>,
+ *                                         numeric <oper>[,<AcT>])s]
+ *                                      [,,(list of supported <mode>s),
+ *                                      (list of supported <format>s)]
+ *                                  +CME ERROR: <err>
+ *
+ * <mode>: integer type
+ *       0 automatic (<oper> field is ignored)
+ *       1 manual (<oper> field shall be present, and <AcT> optionally)
+ *       2 deregister from network
+ *       3 set only <format> (for read command +COPS?), do not attempt
+ *       registration/deregistration (<oper> and <AcT> fields are ignored);
+ *        this value is not applicable in read command response
+ *       4 manual/automatic (<oper> field shall be present); if manual selection fails, automatic mode (<mode>=0) is entered
+ * <format>: integer type
+ *         0 long format alphanumeric <oper>
+ *         1 short format alphanumeric <oper>
+ *         2 numeric <oper>
+ * <oper>: string type;
+ * <format> indicates if the format is alphanumeric or numeric;
+ * <stat>: integer type
+ *       0 unknown
+ *       1 available
+ *       2 current
+ *       3 forbidden
+ * <AcT>: integer type; access technology selected
+ *      0 GSM
+ *      1 GSM Compact
+ *      2 UTRAN
+ *      3 GSM w/EGPRS (see NOTE 1)
+ *      4 UTRAN w/HSDPA (see NOTE 2)
+ *      5 UTRAN w/HSUPA (see NOTE 2)
+ *      6 UTRAN w/HSDPA and HSUPA (see NOTE 2)
+ *      7 E-UTRAN
+ *      8 EC-GSM-IoT (A/Gb mode) (see NOTE 3)
+ *      9 E-UTRAN (NB-S1 mode) (see NOTE 4)
+ *      10 E-UTRA connected to a 5GCN (see NOTE 5)
+ *      11 NR connected to a 5GCN (see NOTE 5)
+ *      12 NG-RAN
+ *      13 E-UTRA-NR dual connectivity (see NOTE 6)
+ *
+ *  see RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC or
+ *      RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE or
+ *      RIL_REQUEST_OPERATOR in RIL
+ */
+void NetworkService::HandleQueryNetworkSelectionMode(const Client& client) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  if (!IsHasNetwork()) {
+    ss << "+COPS: 0,0,0";
+  } else {
+    auto iter = operator_list_.begin();
+    for (; iter != operator_list_.end(); ++iter) {
+      if (iter->numeric == current_operator_numeric_) {
+        break;
+      }
+    }
+    if (iter != operator_list_.end()) {
+      ss << "+COPS: " << oper_selection_mode_ << ",2," << iter->numeric;
+    } else {
+      ss << "+COPS: " << oper_selection_mode_ << ",0,0";
+    }
+  }
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/* AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? */
+void NetworkService::HandleRequestOperator(const Client& client) {
+  if (!IsHasNetwork()) {
+    client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+    return;
+  }
+
+  auto iter = operator_list_.begin();
+  for (; iter != operator_list_.end(); ++iter) {
+    if (iter->numeric == current_operator_numeric_) {
+      break;
+    }
+  }
+  if (iter == operator_list_.end()) {
+    client.SendCommandResponse(kCmeErrorNoNetworkService);
+    return;
+  }
+
+  std::vector<std::string> responses;
+  std::vector<std::stringstream> ss;
+  ss.resize(3);
+
+  ss[0] << "+COPS: 0,0," << iter->long_name;
+  ss[1] << "+COPS: 0,1," << iter->short_name;
+  ss[2] << "+COPS: 0,2," << iter->numeric;
+
+  responses.push_back(ss[0].str());
+  responses.push_back(ss[1].str());
+  responses.push_back(ss[2].str());
+  responses.push_back("OK");
+
+  client.SendCommandResponse(responses);
+}
+
+/* AT+COPS=? */
+void NetworkService::HandleQueryAvailableNetwork(const Client& client) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  for (auto iter = operator_list_.begin(); iter != operator_list_.end(); ++iter) {
+    ss.clear();
+    ss << "+COPS: (" << iter->operator_state << ","
+                     << iter->long_name << ","
+                     << iter->short_name << ","
+                     << iter->numeric << "),";
+    responses.push_back(ss.str());
+    ss.str("");
+  }
+
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/* AT+COPS=mode,format,operatorNumeric,act */
+void NetworkService::HandleSetNetworkSelectionMode(const Client& client, std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  int mode = (OperatorSelectionMode)cmd.GetNextInt();
+  cmd.SkipPrefix();  // Default to be numeric
+
+  auto& registration_state = voice_registration_status_.registration_state;
+
+  switch (mode) {
+    // <oper> field is ignored
+    case OperatorSelectionMode::OPER_SELECTION_AUTOMATIC: {
+      oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_AUTOMATIC;
+
+      // The first operator stored in operator_list_ map default to be
+      // the automatic selected operator
+      auto iter = operator_list_.begin();
+      current_operator_numeric_ = iter->numeric;
+      iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
+
+      // Change operator state stored in the operator_list_ map
+      ++iter;
+      for (; iter != operator_list_.end(); ++iter) {
+        if (iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
+          iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
+          break;
+        }
+      }
+
+      registration_state = NET_REGISTRATION_HOME;
+      client.SendCommandResponse("OK");
+      break;
+    }
+
+    // <oper> field shall be present, and <AcT> optionally
+    case OperatorSelectionMode::OPER_SELECTION_MANUAL: {
+      oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_MANUAL;
+      current_operator_numeric_ = cmd.GetNextStr();
+      auto iter = operator_list_.begin();
+      for (; iter != operator_list_.end(); ++iter) {
+        if (iter->numeric == current_operator_numeric_) {
+          break;
+        }
+      }
+      // If the selected operator is not available, no other operator shall be
+      // selected (except <mode>=4).
+      if (iter == operator_list_.end()) {
+        registration_state = NET_REGISTRATION_UNKNOWN;
+        client.SendCommandResponse(kCmeErrorNoNetworkService);
+        break;
+      }
+
+      // Change operator state stored in the operator_list_ vector
+      iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
+      iter = operator_list_.begin();
+      for (; iter != operator_list_.end(); ++iter) {
+        if (iter->numeric != current_operator_numeric_ &&
+            iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
+          iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
+        }
+      }
+
+      // If the selected access technology is not available, then the same operator
+      // shall be selected in other access technology
+      int act = cmd.GetNextInt();
+      if (act != -1) {
+        auto tech = getTechFromNetworkType((NetworkRegistrationStatus::AccessTechnoloy)act);
+        if (tech & modem_radio_capability_) {
+          current_network_mode_ = tech;
+        }  // else: remain current network mode unchanged
+      }  // else: remain act unchanged
+
+      if (iter->operator_state == NetworkOperator::OPER_STATE_FORBIDDEN) {
+        registration_state = NET_REGISTRATION_DENIED;
+      } else if (iter->operator_state == NetworkOperator::OPER_STATE_UNKNOWN) {
+        registration_state = NET_REGISTRATION_UNKNOWN;
+      } else {
+        registration_state = NET_REGISTRATION_HOME;
+      }
+      client.SendCommandResponse("OK");
+      break;
+    }
+
+    case OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION: {
+      oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION;
+      registration_state = NET_REGISTRATION_UNREGISTERED;
+      client.SendCommandResponse("OK");
+      break;
+    }
+
+    // <oper> field shall be present
+    case OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC: {
+      oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC;
+      auto operator_numeric = cmd.GetNextStr();
+      // If manual selection fails, automatic mode (<mode>=0) is entered
+      auto iter = operator_list_.begin();
+      for (; iter != operator_list_.end(); ++iter) {
+        if (iter->numeric == operator_numeric) {
+          break;
+        }
+      }
+      // If the selected operator is not available, no other operator shall be
+      // selected (except <mode>=4)
+      if (iter != operator_list_.end() ||
+          iter->operator_state == NetworkOperator::OPER_STATE_AVAILABLE) {
+        current_operator_numeric_ = iter->numeric;
+      }
+
+      // Change operator state stored in the operator_list_ vector
+      iter = operator_list_.begin();
+      for (; iter != operator_list_.end(); ++iter) {
+        if (iter->numeric == current_operator_numeric_) {
+          iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
+        } else if (iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
+          iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
+        }
+      }
+
+      registration_state = NET_REGISTRATION_HOME;
+      client.SendCommandResponse("OK");
+      break;
+    }
+
+    default:
+      client.SendCommandResponse(kCmeErrorInCorrectParameters);
+      return;
+  }
+
+  // Save the value anyway, no matter the value changes or not
+  auto nvram_config = NvramConfig::Get();
+  auto instance = nvram_config->ForInstance(service_id_);
+  instance.set_network_selection_mode(oper_selection_mode_);
+  instance.set_operator_numeric(current_operator_numeric_);
+
+  NvramConfig::SaveToFile();
+
+  thread_looper_->PostWithDelay(std::chrono::seconds(1),
+      makeSafeCallback(this, &NetworkService::UpdateRegisterState, registration_state));
+}
+
+NetworkService::NetworkRegistrationStatus::AccessTechnoloy
+NetworkService::getNetworkTypeFromTech(ModemTechnology modemTech) {
+  switch (modemTech) {
+   case ModemTechnology::M_MODEM_TECH_GSM:
+     return NetworkRegistrationStatus::ACESS_TECH_EGPRS;
+   case ModemTechnology::M_MODEM_TECH_WCDMA:
+     return NetworkRegistrationStatus::ACESS_TECH_HSPA;
+   case ModemTechnology::M_MODEM_TECH_LTE:
+     return NetworkRegistrationStatus::ACESS_TECH_EUTRAN;
+   case ModemTechnology::M_MODEM_TECH_NR:
+     return NetworkRegistrationStatus::ACESS_TECH_NR;
+   default:
+     return NetworkRegistrationStatus::ACESS_TECH_EGPRS;
+  }
+}
+
+NetworkService::ModemTechnology NetworkService::getTechFromNetworkType(
+    NetworkRegistrationStatus::AccessTechnoloy act) {
+  switch (act) {
+    case NetworkRegistrationStatus::ACESS_TECH_GSM:
+    case NetworkRegistrationStatus::ACESS_TECH_GSM_COMPACT:
+    case NetworkRegistrationStatus::ACESS_TECH_EGPRS:
+    case NetworkRegistrationStatus::ACESS_TECH_EC_GSM_IoT:
+      return ModemTechnology::M_MODEM_TECH_GSM;
+
+    case NetworkRegistrationStatus::ACESS_TECH_UTRAN:
+    case NetworkRegistrationStatus::ACESS_TECH_HSDPA:
+    case NetworkRegistrationStatus::ACESS_TECH_HSUPA:
+    case NetworkRegistrationStatus::ACESS_TECH_HSPA:
+      return ModemTechnology::M_MODEM_TECH_WCDMA;
+
+    case NetworkRegistrationStatus::ACESS_TECH_EUTRAN:
+    case NetworkRegistrationStatus::ACESS_TECH_E_UTRAN:
+    case NetworkRegistrationStatus::ACESS_TECH_E_UTRA:
+      return ModemTechnology::M_MODEM_TECH_LTE;
+
+    case NetworkRegistrationStatus::ACESS_TECH_NR:
+    case NetworkRegistrationStatus::ACESS_TECH_NG_RAN:
+    case NetworkRegistrationStatus::ACESS_TECH_E_UTRA_NR:
+      return ModemTechnology::M_MODEM_TECH_NR;
+
+    default:
+      return ModemTechnology::M_MODEM_TECH_GSM;
+  }
+}
+
+/**
+ * AT+CREG
+ *   Set command controls the presentation of an unsolicited result code
+ * +CREG: <stat> when <n>=1 and there is a change in the MT’s circuit
+ * mode network registration status in GERAN/UTRAN/E-UTRAN, or unsolicited
+ * result code +CREG: <stat>[,[<lac>],[<ci>],[<AcT>]]
+ * when <n>=2 and there is a change of the network cell in GERAN/UTRAN/E-UTRAN. The
+ * parameters <AcT>, <lac> and <ci> are sent only if available.
+ * The value <n>=3 further extends the unsolicited result code with [,<cause_type>,
+ * <reject_cause>], when available, when the value of <stat> changes.
+ *
+ * command             Possible response(s)
+ * +CREG=[<n>]         +CME ERROR: <err>
+ *
+ * +CREG?             +CREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>]
+ *                            [,<cause_type>,<reject_cause>]]
+ *
+ * <n>: integer type
+ *    0 disable network registration unsolicited result code
+ *    1 enable network registration unsolicited result code +CREG: <stat>
+ *    2 enable network registration and location information unsolicited
+ *      result code +CREG: <stat>[,[<lac>],[<ci>],[<AcT>]]
+ *    3 enable network registration, location information and cause value
+ *      information unsolicited result code +CREG: <stat>[,[<lac>],[<ci>],
+ *      [<AcT>][,<cause_type>,<reject_cause>]]
+ *
+ * <stat>: integer type;
+ *      0 not registered, MT is not currently searching a new operator to register to
+ *      1 registered, home network
+ *      2 not registered, but MT is currently searching a new operator to register to
+ *      3 registration denied
+ *      4 unknown (e.g. out of GERAN/UTRAN/E-UTRAN coverage)
+ *      5 registered, roaming
+ *
+ * <lac>: string type; two byte location area code (when <AcT> indicates
+ *        value 0 to 6), or tracking area code (when <AcT> indicates
+ *        value 7). In hexadecimal format
+ * <ci>: string type; four byte GERAN/UTRAN/E-UTRAN cell ID in
+ *       hexadecimal format
+ * <AcT>: refer line 190
+ *
+ * see RIL_REQUEST_VOICE_REGISTRATION_STATE or in RIL
+*/
+void NetworkService::HandleVoiceNetworkRegistration(const Client& client,
+                                                    std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  if (*cmd == "AT+CREG?") {
+    ss << "+CREG: " << voice_registration_status_.unsol_mode << ","
+                    << voice_registration_status_.registration_state;
+    if (voice_registration_status_.unsol_mode ==
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL &&
+       (voice_registration_status_.registration_state ==
+            NET_REGISTRATION_HOME ||
+        voice_registration_status_.registration_state ==
+            NET_REGISTRATION_ROAMING ||
+        voice_registration_status_.registration_state ==
+            NET_REGISTRATION_EMERGENCY)) {
+      ss << ",\"" << kAreaCode << "\"" << ",\"" << kCellId << "\","
+                  << voice_registration_status_.network_type;
+    }
+
+    responses.push_back(ss.str());
+  } else {
+    int n = cmd.GetNextInt();
+    switch (n) {
+      case 0:
+        voice_registration_status_.unsol_mode =
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_DISABLED;
+        break;
+      case 1:
+        voice_registration_status_.unsol_mode =
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED;
+        break;
+      case 2:
+        voice_registration_status_.unsol_mode =
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL;
+        break;
+      default:
+        client.SendCommandResponse(kCmeErrorInCorrectParameters);
+        return;
+    }
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CGREG
+ * The set command controls the presentation of an unsolicited result
+ *  code +CGREG: <stat> when <n>=1 and there is a change in the MT's
+ *  GPRS network registration status, or code +CGREG: <stat>[,<lac>,
+ *  <ci>[,<AcT>]] when <n>=2 and there is a change of the network cell.
+ *
+ * command             Possible response(s)
+ * +CGREG=[<n>]         +CME ERROR: <err>
+ *
+ * +CGREG?             when <n>=0, 1, 2 or 3 and command successful:
+ *                     +CGREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>],
+ *                             [<rac>][,<cause_type>,<reject_cause>]]
+ *                     when <n>=4 or 5 and command successful:
+ *                     +CGREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>],
+ *                             [<rac>][,[<cause_type>],[<reject_cause>][,
+ *                             [<Active-Time>],[<Periodic-RAU>],
+ *                             [<GPRS-READY-timer>]]]]
+ *                             [,<cause_type>,<reject_cause>]]
+ *
+ * note: see AT+CREG
+ *
+ * see  RIL_REQUEST_DATA_REGISTRATION_STATE in RIL
+ */
+void NetworkService::HandleDataNetworkRegistration(const Client& client,
+                                                   std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+  std::string prefix;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  if (command.find("CGREG") != std::string::npos) {
+    prefix = "+CGREG: ";
+  } else if (command.find("CEREG") != std::string::npos){
+    prefix = "+CEREG: ";
+  }
+
+  if (*cmd == "AT+CGREG?" || *cmd == "AT+CEREG?") {
+    ss << prefix << data_registration_status_.unsol_mode << ","
+                 << data_registration_status_.registration_state;
+    if (voice_registration_status_.unsol_mode ==
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL &&
+       (voice_registration_status_.registration_state ==
+            NET_REGISTRATION_HOME ||
+        voice_registration_status_.registration_state ==
+            NET_REGISTRATION_ROAMING ||
+        voice_registration_status_.registration_state ==
+            NET_REGISTRATION_EMERGENCY)) {
+      data_registration_status_.network_type =
+          getNetworkTypeFromTech(current_network_mode_);
+      ss << ",\"" << kAreaCode << "\"" << ",\"" << kCellId << "\"" << ","
+                  << data_registration_status_.network_type;
+    }
+    responses.push_back(ss.str());
+  } else {
+    int n = cmd.GetNextInt();
+    switch (n) {
+      case 0:
+        data_registration_status_.unsol_mode =
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_DISABLED;
+        break;
+      case 1:
+        data_registration_status_.unsol_mode =
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED;
+        break;
+      case 2:
+        data_registration_status_.unsol_mode =
+            NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL;
+        break;
+      default:
+        client.SendCommandResponse(kCmeErrorInCorrectParameters);
+        return;
+    }
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/* AT+CTEC? */
+void NetworkService::HandleGetPreferredNetworkType(const Client& client) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  ss << "+CTEC: " << current_network_mode_ << "," << std::hex << preferred_network_mode_;
+
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/* AT+CTEC=? */
+void NetworkService::HandleQuerySupportedTechs(const Client& client) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+  ss << "+CTEC: 0,1,5,6";  // NR | LTE | WCDMA | GSM
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * Preferred mode bitmask. This is actually 4 byte-sized bitmasks with different priority values,
+ * in which the byte number from LSB to MSB give the priority.
+ *
+ *          |MSB|   |   |LSB
+ * value:   |00 |00 |00 |00
+ * byte #:  |3  |2  |1  |0
+ *
+ * Higher byte order give higher priority. Thus, a value of 0x0000000f represents
+ * a preferred mode of GSM, WCDMA, CDMA, and EvDo in which all are equally preferrable, whereas
+ * 0x00000201 represents a mode with GSM and WCDMA, in which WCDMA is preferred over GSM
+ */
+int NetworkService::getModemTechFromPrefer(int preferred_mask) {
+  int i, j;
+
+  // Current implementation will only return the highest priority,
+  // lowest numbered technology that is set in the mask.
+  for (i = 3 ; i >= 0; i--) {
+    for (j = 7 ; j >= 0 ; j--) {
+      if (preferred_mask & (1 << (j + 8 * i)))
+          return 1 << j;
+    }
+  }
+  // This should never happen. Just to please the compiler.
+  return ModemTechnology::M_MODEM_TECH_GSM;
+}
+
+void NetworkService::UpdateRegisterState(RegistrationState state ) {
+  voice_registration_status_.registration_state = state;
+  data_registration_status_.registration_state = state;
+  voice_registration_status_.network_type =
+      (NetworkRegistrationStatus::AccessTechnoloy)getNetworkTypeFromTech(current_network_mode_);
+  data_registration_status_.network_type =
+      (NetworkRegistrationStatus::AccessTechnoloy)getNetworkTypeFromTech(current_network_mode_);
+
+  OnVoiceRegisterStateChanged();
+  OnDataRegisterStateChanged();
+  OnSignalStrengthChanged();
+
+  int cellBandwidthDownlink = 5000;
+  const int UNKNOWN = 0;
+  const int MMWAVE = 4;
+  int freq = UNKNOWN;
+  if (current_network_mode_ == M_MODEM_TECH_NR) {
+    freq = MMWAVE;
+    cellBandwidthDownlink = 50000;
+  }
+
+  data_service_->onUpdatePhysicalChannelconfigs(current_network_mode_, freq,
+                                                cellBandwidthDownlink);
+}
+
+/* AT+CTEC=current,preferred */
+void NetworkService::HandleSetPreferredNetworkType(const Client& client, std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+  int preferred_mask_new;
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  int current = cmd.GetNextInt();
+  std::string preferred(cmd.GetNextStr());
+  preferred_mask_new = std::stoi(preferred, nullptr, 16);
+  if (preferred_mask_new != preferred_network_mode_) {
+    current_network_mode_ = (ModemTechnology)getModemTechFromPrefer(preferred_mask_new);
+    preferred_network_mode_ = preferred_mask_new;
+  }
+
+  if (current != current_network_mode_) {
+    UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
+    signal_strength_.Reset();
+
+    ss << "+CTEC: "<< current_network_mode_;
+
+    thread_looper_->PostWithDelay(std::chrono::milliseconds(200),
+        makeSafeCallback(this, &NetworkService::UpdateRegisterState,
+            NET_REGISTRATION_HOME));
+  } else {
+    ss << "+CTEC: DONE";
+  }
+
+  auto nvram_config = NvramConfig::Get();
+  auto instance = nvram_config->ForInstance(service_id_);
+  instance.set_modem_technoloy(current_network_mode_);
+  instance.set_preferred_network_mode(preferred_network_mode_);
+
+  NvramConfig::SaveToFile();
+
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+void NetworkService::OnVoiceRegisterStateChanged() {
+  std::stringstream ss;
+
+  switch (voice_registration_status_.unsol_mode) {
+    case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED:
+      ss << "+CREG: " << voice_registration_status_.registration_state;
+      break;
+    case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL:
+      ss << "+CREG: " << voice_registration_status_.registration_state;
+      if (voice_registration_status_.registration_state ==
+              NET_REGISTRATION_HOME ||
+          voice_registration_status_.registration_state ==
+              NET_REGISTRATION_ROAMING) {
+        ss << ",\""<< kAreaCode << "\",\"" << kCellId << "\","
+                 << voice_registration_status_.network_type;
+      }
+      break;
+    default :
+      return;
+  }
+  SendUnsolicitedCommand(ss.str());
+}
+
+void NetworkService::OnDataRegisterStateChanged() {
+  std::stringstream ss;
+
+  switch (data_registration_status_.unsol_mode) {
+    case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED:
+      ss << "+CGREG: " << data_registration_status_.registration_state;
+      if (data_registration_status_.network_type ==
+              NetworkRegistrationStatus::ACESS_TECH_EUTRAN) {
+        ss << "\r+CEREG: " << data_registration_status_.registration_state;
+      }
+      break;
+    case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL:
+      ss << "+CGREG: " << data_registration_status_.registration_state;
+      if (data_registration_status_.registration_state ==
+                NET_REGISTRATION_HOME ||
+          data_registration_status_.registration_state ==
+                NET_REGISTRATION_ROAMING) {
+        ss << ",\"" << kAreaCode << "\",\"" << kCellId << "\","
+           << data_registration_status_.network_type;
+      }
+      if (data_registration_status_.network_type ==
+                NetworkRegistrationStatus::ACESS_TECH_EUTRAN) {
+          ss << "\r+CEREG: " << data_registration_status_.registration_state;
+          if (data_registration_status_.registration_state ==
+                  NET_REGISTRATION_HOME ||
+              data_registration_status_.registration_state ==
+                  NET_REGISTRATION_ROAMING) {
+            ss << ",\"" << kAreaCode << "\",\"" << kCellId << "\","
+                      << data_registration_status_.network_type;
+          }
+      }
+      break;
+    default:
+      return;
+  }
+  SendUnsolicitedCommand(ss.str());
+}
+
+std::string NetworkService::GetSignalStrength() {
+  switch (current_network_mode_) {
+    case M_MODEM_TECH_GSM:
+      signal_strength_.gsm_rssi += (rand() % 3 - 1);
+      AdjustSignalStrengthValue(signal_strength_.gsm_rssi, kGSMSignalStrength);
+      break;
+    case M_MODEM_TECH_CDMA:
+      signal_strength_.cdma_dbm += (rand() % 3 - 1);
+      AdjustSignalStrengthValue(signal_strength_.cdma_dbm, kCDMASignalStrength);
+      break;
+    case M_MODEM_TECH_EVDO:
+      signal_strength_.evdo_dbm += (rand() % 3 - 1);
+      AdjustSignalStrengthValue(signal_strength_.evdo_dbm, kEVDOSignalStrength);
+      break;
+    case M_MODEM_TECH_LTE:
+      signal_strength_.lte_rssi += (rand() % 3 - 1);
+      AdjustSignalStrengthValue(signal_strength_.lte_rssi, kLTESignalStrength);
+      break;
+    case M_MODEM_TECH_WCDMA:
+      signal_strength_.wcdma_rssi += (rand() % 3 - 1);
+      AdjustSignalStrengthValue(signal_strength_.wcdma_rssi, kWCDMASignalStrength);
+      break;
+    case M_MODEM_TECH_NR:
+      signal_strength_.nr_ss_rsrp += (rand() % 3 - 1);
+      AdjustSignalStrengthValue(signal_strength_.nr_ss_rsrp, kNRSignalStrength);
+      break;
+    default:
+      break;
+  }
+
+  std::stringstream ss;
+  ss << "+CSQ: " << signal_strength_.gsm_rssi << ","
+                 << signal_strength_.gsm_ber << ","
+                 << signal_strength_.cdma_dbm << ","
+                 << signal_strength_.cdma_ecio << ","
+                 << signal_strength_.evdo_dbm << ","
+                 << signal_strength_.evdo_ecio << ","
+                 << signal_strength_.evdo_snr << ","
+                 << signal_strength_.lte_rssi << ","
+                 << signal_strength_.lte_rsrp << ","
+                 << signal_strength_.lte_rsrq << ","
+                 << signal_strength_.lte_rssnr << ","
+                 << signal_strength_.lte_cqi << ","
+                 << signal_strength_.lte_ta << ","
+                 << signal_strength_.tdscdma_rscp << ","
+                 << signal_strength_.wcdma_rssi << ","
+                 << signal_strength_.wcdma_ber << ","
+                 << signal_strength_.nr_ss_rsrp << ","
+                 << signal_strength_.nr_ss_rsrq << ","
+                 << signal_strength_.nr_ss_sinr << ","
+                 << signal_strength_.nr_csi_rsrp << ","
+                 << signal_strength_.nr_csi_rsrq << ","
+                 << signal_strength_.nr_csi_sinr;;
+  return ss.str();
+}
+
+/* AT+REMOTEREG: state*/
+void NetworkService::HandleReceiveRemoteVoiceDataReg(const Client& client,
+                                                     std::string& command) {
+  (void)client;
+  std::stringstream ss;
+  std::string states = command.substr(std::string("AT+REMOTEREG:").size());
+  int stated = std::stoi(states, nullptr, 10);
+
+  UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
+  signal_strength_.Reset();
+
+  thread_looper_->PostWithDelay(
+      std::chrono::seconds(1),
+      makeSafeCallback(this, &NetworkService::UpdateRegisterState,
+                       (cuttlefish::NetworkService::RegistrationState)stated));
+}
+
+/* AT+REMOTECTEC: ctec */
+void NetworkService::HandleReceiveRemoteCTEC(const Client& client,
+                                             std::string& command) {
+  (void)client;
+  LOG(DEBUG) << "calling ctec from remote";
+  std::stringstream ss;
+  std::string types = command.substr(std::string("AT+REMOTECTEC: ").size());
+  int preferred_mask_new = std::stoi(types, nullptr, 10);
+
+  if (preferred_mask_new != preferred_network_mode_) {
+    preferred_network_mode_ = preferred_mask_new;
+  }
+  auto current_network_mode_new =
+      (ModemTechnology)getModemTechFromPrefer(preferred_mask_new);
+  if (current_network_mode_new != current_network_mode_) {
+    current_network_mode_ = current_network_mode_new;
+    auto saved_state = voice_registration_status_.registration_state;
+    UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
+    signal_strength_.Reset();
+
+    ss << "+CTEC: " << current_network_mode_;
+
+    thread_looper_->PostWithDelay(
+        std::chrono::seconds(1),
+        makeSafeCallback(this, &NetworkService::UpdateRegisterState,
+                         saved_state));
+  }
+}
+
+void NetworkService::applySignalPercentage(double percentd) {
+  switch (current_network_mode_) {
+    case M_MODEM_TECH_GSM:
+      signal_strength_.gsm_rssi = 99;
+      signal_strength_.gsm_ber = 0;
+      SetSignalStrengthValue(signal_strength_.gsm_rssi, kGSMSignalStrength,
+                             percentd);
+      break;
+    case M_MODEM_TECH_CDMA:
+      signal_strength_.cdma_dbm = 125;
+      signal_strength_.cdma_ecio = 165;
+      SetSignalStrengthValue(signal_strength_.cdma_dbm, kCDMASignalStrength,
+                             percentd);
+      break;
+    case M_MODEM_TECH_EVDO:
+      signal_strength_.evdo_dbm = 125;
+      signal_strength_.evdo_ecio = 165;
+      signal_strength_.evdo_snr = -1;
+      SetSignalStrengthValue(signal_strength_.evdo_dbm, kEVDOSignalStrength,
+                             percentd);
+      break;
+    case M_MODEM_TECH_LTE:
+      signal_strength_.lte_rssi = 99;
+      signal_strength_.lte_rsrp = -1;
+      signal_strength_.lte_rsrq = -5;
+      signal_strength_.lte_rssnr = -205;
+      signal_strength_.lte_cqi = -1;
+      signal_strength_.lte_ta = -1;
+      SetSignalStrengthValue(signal_strength_.lte_rssi, kLTESignalStrength,
+                             percentd);
+      break;
+    case M_MODEM_TECH_WCDMA:
+      signal_strength_.tdscdma_rscp = 99;
+      signal_strength_.wcdma_rssi = 99;
+      signal_strength_.wcdma_ber = 0;
+      SetSignalStrengthValue(signal_strength_.wcdma_rssi, kWCDMASignalStrength,
+                             percentd);
+      break;
+    case M_MODEM_TECH_NR:
+      // special for NR: it uses LTE as primary, so LTE signal strength is
+      // needed as well
+      signal_strength_.lte_rssi = 99;
+      signal_strength_.lte_rsrp = -1;
+      signal_strength_.lte_rsrq = -5;
+      signal_strength_.lte_rssnr = -205;
+      signal_strength_.lte_cqi = -1;
+      signal_strength_.lte_ta = -1;
+      SetSignalStrengthValue(signal_strength_.lte_rssi, kLTESignalStrength,
+                             percentd);
+      signal_strength_.nr_ss_rsrp = 0;
+      signal_strength_.nr_ss_rsrq = 0;
+      signal_strength_.nr_ss_sinr = 45;
+      signal_strength_.nr_csi_rsrp = 0;
+      signal_strength_.nr_csi_rsrq = 0;
+      signal_strength_.nr_csi_sinr = 30;
+      SetSignalStrengthValue(signal_strength_.nr_ss_rsrp, kNRSignalStrength,
+                             percentd);
+      break;
+    default:
+      break;
+  }
+}
+
+/* AT+REMOTESIGNAL: percent */
+void NetworkService::HandleReceiveRemoteSignal(const Client& client,
+                                               std::string& command) {
+  (void)client;
+  std::stringstream ss;
+  std::string percents = command.substr(std::string("AT+REMOTESIGNAL:").size());
+  double percentd = std::stoi(percents, nullptr, 10) / 100.0;
+
+  if (percentd >= 0 && percentd <= 1.0) {
+    percentd_ = percentd;
+  } else {
+    LOG(DEBUG) << "out of bound signal strength: " << percentd;
+    return;
+  }
+
+  OnSignalStrengthChanged();
+}
+
+void NetworkService::OnSignalStrengthChanged() {
+  applySignalPercentage(percentd_);
+  auto command = GetSignalStrength();
+  SendUnsolicitedCommand(command);
+}
+
+NetworkService::RegistrationState NetworkService::GetVoiceRegistrationState() const {
+  return voice_registration_status_.registration_state;
+}
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/network_service.h b/host/commands/modem_simulator/network_service.h
new file mode 100644
index 0000000..b64d4b9
--- /dev/null
+++ b/host/commands/modem_simulator/network_service.h
@@ -0,0 +1,320 @@
+//
+// 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 <ctime>
+
+#include "host/commands/modem_simulator/data_service.h"
+#include "host/commands/modem_simulator/misc_service.h"
+#include "host/commands/modem_simulator/modem_service.h"
+#include "host/commands/modem_simulator/sim_service.h"
+
+namespace cuttlefish {
+
+class NetworkService : public ModemService, public std::enable_shared_from_this<NetworkService> {
+ public:
+  NetworkService(int32_t service_id_, ChannelMonitor* channel_monitor,
+                 ThreadLooper* thread_looper);
+  ~NetworkService() = default;
+
+  NetworkService(const NetworkService &) = delete;
+  NetworkService &operator=(const NetworkService &) = delete;
+
+  void SetupDependency(MiscService* misc, SimService* sim, DataService* data);
+
+  void HandleRadioPowerReq(const Client& client);
+  void HandleRadioPower(const Client& client, std::string& command);
+  void HandleSignalStrength(const Client& client);
+  void HandleQueryNetworkSelectionMode(const Client& client);
+  void HandleRequestOperator(const Client& client);
+  void HandleQueryAvailableNetwork(const Client& client);
+  void HandleSetNetworkSelectionMode(const Client& client, std::string& command);
+  void HandleVoiceNetworkRegistration(const Client& client, std::string& command);
+  void HandleDataNetworkRegistration(const Client& client, std::string& command);
+  void HandleGetPreferredNetworkType(const Client& client);
+  void HandleQuerySupportedTechs(const Client& client);
+  void HandleSetPreferredNetworkType(const Client& client, std::string& command);
+  void HandleNetworkRegistration(cuttlefish::SharedFD client, std::string& command);
+
+  void HandleReceiveRemoteVoiceDataReg(const Client& client,
+                                       std::string& command);
+  void HandleReceiveRemoteCTEC(const Client& client, std::string& command);
+  void HandleReceiveRemoteSignal(const Client& client, std::string& command);
+
+  void OnSimStatusChanged(SimService::SimStatus sim_status);
+  void OnVoiceRegisterStateChanged();
+  void OnDataRegisterStateChanged();
+  void OnSignalStrengthChanged();
+
+  enum RegistrationState {
+    NET_REGISTRATION_UNREGISTERED = 0,
+    NET_REGISTRATION_HOME         = 1,
+    NET_REGISTRATION_SEARCHING    = 2,
+    NET_REGISTRATION_DENIED       = 3,
+    NET_REGISTRATION_UNKNOWN      = 4,
+    NET_REGISTRATION_ROAMING      = 5,
+    NET_REGISTRATION_EMERGENCY    = 8
+  };
+  RegistrationState GetVoiceRegistrationState() const;
+
+  bool isRadioOff() const { return radio_state_ == RADIO_STATE_OFF; }
+
+ private:
+  void InitializeServiceState();
+  std::vector<CommandHandler> InitializeCommandHandlers();
+  void InitializeNetworkOperator();
+  void InitializeSimOperator();
+
+  bool WakeupFromSleep();
+  bool IsHasNetwork();
+  void UpdateRegisterState(RegistrationState state);
+  void AdjustSignalStrengthValue(int& value, const std::pair<int, int>& range);
+  void SetSignalStrengthValue(int& value, const std::pair<int, int>& range,
+                              double percentd);
+  std::string GetSignalStrength();
+  void applySignalPercentage(double percentd);
+
+  MiscService* misc_service_ = nullptr;
+  SimService* sim_service_ = nullptr;
+  DataService* data_service_ = nullptr;
+
+  enum RadioState : int32_t {
+    RADIO_STATE_OFF,
+    RADIO_STATE_ON,
+  };
+  RadioState radio_state_;
+
+  /* Operator */
+  struct NetworkOperator {
+    enum OperatorState {
+      OPER_STATE_UNKNOWN    = 0,
+      OPER_STATE_AVAILABLE  = 1,
+      OPER_STATE_CURRENT    = 2,
+      OPER_STATE_FORBIDDEN  = 3
+    };
+
+    std::string numeric;
+    std::string long_name;
+    std::string short_name;
+    OperatorState operator_state;
+
+    NetworkOperator() {}
+
+    NetworkOperator(const std::string& number,
+                    const std::string& ln,
+                    const std::string& sn,
+                    OperatorState state)
+        : numeric(number),
+          long_name(ln),
+          short_name(sn),
+          operator_state(state) {}
+  };
+
+  enum OperatorSelectionMode {
+    OPER_SELECTION_AUTOMATIC = 0,
+    OPER_SELECTION_MANUAL,
+    OPER_SELECTION_DEREGISTRATION,
+    OPER_SELECTION_SET_FORMAT,
+    OPER_SELECTION_MANUAL_AUTOMATIC
+  };
+
+  std::vector<NetworkOperator> operator_list_;
+  std::string current_operator_numeric_ = "";
+  OperatorSelectionMode oper_selection_mode_;
+
+  /* SignalStrength */
+  struct SignalStrength {
+    int gsm_rssi;  /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
+    int gsm_ber;   /* bit error rate (0-7, 99) as defined in TS 27.007 8.5 */
+
+    int cdma_dbm;   /* Valid values are positive integers.  This value is the actual RSSI value
+                     * multiplied by -1.  Example: If the actual RSSI is -75, then this response
+                     * value will be 75.
+                     */
+    int cdma_ecio;  /* Valid values are positive integers.  This value is the actual Ec/Io multiplied
+                     * by -10.  Example: If the actual Ec/Io is -12.5 dB, then this response value
+                     * will be 125.
+                     */
+
+    int evdo_dbm;   /* Refer cdma_dbm */
+    int evdo_ecio;  /* Refer cdma_ecio */
+    int evdo_snr;   /* Valid values are 0-8.  8 is the highest signal to noise ratio. */
+
+    int lte_rssi;   /* Refer gsm_rssi */
+    int lte_rsrp;   /* The current Reference Signal Receive Power in dBm multiplied by -1.
+                     * Range: 44 to 140 dBm
+                     * INT_MAX: 0x7FFFFFFF denotes invalid value.
+                     * Reference: 3GPP TS 36.133 9.1.4 */
+    int lte_rsrq;   /* The current Reference Signal Receive Quality in dB multiplied by -1.
+                     * Range: 20 to 3 dB.
+                     * INT_MAX: 0x7FFFFFFF denotes invalid value.
+                     * Reference: 3GPP TS 36.133 9.1.7 */
+    int lte_rssnr;  /* The current reference signal signal-to-noise ratio in 0.1 dB units.
+                     * Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
+                     * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                     * Reference: 3GPP TS 36.101 8.1.1 */
+    int lte_cqi;    /* The current Channel Quality Indicator.
+                     * Range: 0 to 15.
+                     * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                     * Reference: 3GPP TS 36.101 9.2, 9.3, A.4 */
+    int lte_ta;     /* timing advance in micro seconds for a one way trip from cell to device.
+                     * Approximate distance can be calculated using 300m/us * timingAdvance.
+                     * Range: 0 to 0x7FFFFFFE
+                     * INT_MAX : 0x7FFFFFFF denotes invalid value.
+                     * Reference: 3GPP 36.321 section 6.1.3.5 */
+
+    int tdscdma_rscp;   /* P-CCPCH RSCP as defined in TS 25.225 5.1.1
+                         * Valid values are (0-96, 255) as defined in TS 27.007 8.69
+                         * INT_MAX denotes that the value is invalid/unreported. */
+
+    int wcdma_rssi;  /* Refer gsm_rssi */
+    int wcdma_ber;   /* Refer gsm_ber */
+
+    int32_t nr_ss_rsrp;   /* SS reference signal received power, multiplied by -1.
+                           * Reference: 3GPP TS 38.215.
+                           * Range [44, 140], INT_MAX means invalid/unreported. */
+    int32_t nr_ss_rsrq;   /* SS reference signal received quality, multiplied by -1.
+                           * Reference: 3GPP TS 38.215.
+                           * Range [3, 20], INT_MAX means invalid/unreported. */
+    int32_t nr_ss_sinr;   /* SS signal-to-noise and interference ratio.
+                           * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+                           * Range [-23, 40], INT_MAX means invalid/unreported. */
+    int32_t nr_csi_rsrp;  /* CSI reference signal received power, multiplied by -1.
+                           * Reference: 3GPP TS 38.215.
+                           * Range [44, 140], INT_MAX means invalid/unreported. */
+    int32_t nr_csi_rsrq;  /* CSI reference signal received quality, multiplied by -1.
+                           * Reference: 3GPP TS 38.215.
+                           * Range [3, 20], INT_MAX means invalid/unreported. */
+    int32_t nr_csi_sinr;  /* CSI signal-to-noise and interference ratio.
+                           * Reference: 3GPP TS 138.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+                           * Range [-23, 40], INT_MAX means invalid/unreported. */
+
+    // Default invalid value
+    SignalStrength():
+      gsm_rssi(99),     // [0, 31]
+      gsm_ber(0),       // [7, 99]
+      cdma_dbm(125),    // [0, 120]
+      cdma_ecio(165),   // [0, 160]
+      evdo_dbm(125),    // [0, 120]
+      evdo_ecio(165),   // [0, 160]
+      evdo_snr(-1),     // [0, 8]
+      lte_rssi(99),     // [0, 31]
+      lte_rsrp(-1),     // [43,140]
+      lte_rsrq(-5),     // [-3,34]
+      lte_rssnr(-205),  // [-200, 300]
+      lte_cqi(-1),      // [0, 15]
+      lte_ta(-1),       // [0, 1282]
+      tdscdma_rscp(99), // [0, 96]
+      wcdma_rssi(99),   // [0, 31]
+      wcdma_ber(0),     // [7, 99]
+      nr_ss_rsrp(0),    // [44, 140]
+      nr_ss_rsrq(0),    // [3, 10]
+      nr_ss_sinr(45),   // [-23,40]
+      nr_csi_rsrp(0),   // [44, 140]
+      nr_csi_rsrq(0),   // [3, 20]
+      nr_csi_sinr(30)   // [-23, 23]
+      {}
+
+    // After radio power on, off, or set network mode, reset to invalid value
+    void Reset() {
+      gsm_rssi = INT_MAX;
+      gsm_ber = INT_MAX;
+      cdma_dbm = INT_MAX;
+      cdma_ecio = INT_MAX;
+      evdo_dbm = INT_MAX;
+      evdo_ecio = INT_MAX;
+      evdo_snr = INT_MAX;
+      lte_rssi = INT_MAX;
+      lte_rsrp = INT_MAX;
+      lte_rsrq = INT_MAX;
+      lte_rssnr = INT_MAX;
+      lte_cqi = INT_MAX;
+      lte_ta = INT_MAX;
+      tdscdma_rscp = INT_MAX;
+      wcdma_rssi = INT_MAX;
+      wcdma_ber = INT_MAX;
+      nr_ss_rsrp = INT_MAX;
+      nr_ss_rsrq = INT_MAX;
+      nr_ss_sinr = INT_MAX;
+      nr_csi_rsrp = INT_MAX;
+      nr_csi_rsrq = INT_MAX;
+      nr_csi_sinr = INT_MAX;
+    }
+  };
+
+  double percentd_{0.8};
+  SignalStrength signal_strength_;
+
+  /* Data / voice Registration State */
+  struct NetworkRegistrationStatus {
+    enum RegistrationUnsolMode {
+      REGISTRATION_UNSOL_DISABLED     = 0,
+      REGISTRATION_UNSOL_ENABLED      = 1,
+      REGISTRATION_UNSOL_ENABLED_FULL = 2
+    };
+
+    enum AccessTechnoloy {
+      ACESS_TECH_GSM          = 0,
+      ACESS_TECH_GSM_COMPACT  = 1,
+      ACESS_TECH_UTRAN        = 2,
+      ACESS_TECH_EGPRS        = 3,
+      ACESS_TECH_HSDPA        = 4,
+      ACESS_TECH_HSUPA        = 5,
+      ACESS_TECH_HSPA         = 6,
+      ACESS_TECH_EUTRAN       = 7,
+      ACESS_TECH_EC_GSM_IoT   = 8,
+      ACESS_TECH_E_UTRAN      = 9,
+      ACESS_TECH_E_UTRA       = 10,
+      ACESS_TECH_NR           = 11,
+      ACESS_TECH_NG_RAN       = 12,
+      ACESS_TECH_E_UTRA_NR    = 13
+    };
+
+    NetworkRegistrationStatus() :
+      unsol_mode(REGISTRATION_UNSOL_ENABLED_FULL),
+      registration_state(NET_REGISTRATION_UNREGISTERED),
+      network_type(ACESS_TECH_EUTRAN) {}
+
+    RegistrationUnsolMode unsol_mode;
+    RegistrationState registration_state;
+    AccessTechnoloy network_type;
+  };
+
+  NetworkRegistrationStatus voice_registration_status_;
+  NetworkRegistrationStatus data_registration_status_;
+
+  enum ModemTechnology {
+    M_MODEM_TECH_GSM    = 1 << 0,
+    M_MODEM_TECH_WCDMA  = 1 << 1,
+    M_MODEM_TECH_CDMA   = 1 << 2,
+    M_MODEM_TECH_EVDO   = 1 << 3,
+    M_MODEM_TECH_TDSCDMA= 1 << 4,
+    M_MODEM_TECH_LTE    = 1 << 5,
+    M_MODEM_TECH_NR     = 1 << 6,
+  };
+  ModemTechnology current_network_mode_;
+  int preferred_network_mode_;
+  int modem_radio_capability_;
+
+  NetworkRegistrationStatus::AccessTechnoloy getNetworkTypeFromTech(ModemTechnology modemTech);
+  int getModemTechFromPrefer(int preferred_mask);
+  ModemTechnology getTechFromNetworkType(NetworkRegistrationStatus::AccessTechnoloy act);
+
+  bool first_signal_strength_request_;  // For time update
+  time_t android_last_signal_time_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/nvram_config.cpp b/host/commands/modem_simulator/nvram_config.cpp
new file mode 100644
index 0000000..7efb4c9
--- /dev/null
+++ b/host/commands/modem_simulator/nvram_config.cpp
@@ -0,0 +1,200 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/nvram_config.h"
+
+#include <android-base/logging.h>
+#include <json/json.h>
+
+#include <fstream>
+#include <mutex>
+#include <sstream>
+
+#include "common/libs/utils/files.h"
+#include "host/commands/modem_simulator/device_config.h"
+
+namespace cuttlefish {
+
+const char* kInstances            = "instances";
+const char* kNetworkSelectionMode = "network_selection_mode";
+const char* kOperatorNumeric      = "operator_numeric";
+const char* kModemTechnoloy       = "modem_technoloy";
+const char* kPreferredNetworkMode = "preferred_network_mode";
+const char* kEmergencyMode        = "emergency_mode";
+const char* kSimType              = "sim_type";
+
+const int   kDefaultNetworkSelectionMode  = 0;     // AUTOMATIC
+const std::string kDefaultOperatorNumeric = "";
+const int   kDefaultModemTechnoloy        = 0x10;  // LTE
+const int   kDefaultPreferredNetworkMode  = 0x13;  // LTE | WCDMA | GSM
+const bool  kDefaultEmergencyMode         = false;
+
+/**
+ * Creates the (initially empty) config object and populates it with values from
+ * the config file "modem_nvram.json" located in the cuttlefish instance path,
+ * or uses the default value if the config file not exists,
+ * Returns nullptr if there was an error loading from file
+ */
+NvramConfig* NvramConfig::BuildConfigImpl(size_t num_instances, int sim_type) {
+  auto nvram_config_path =
+      cuttlefish::modem::DeviceConfig::PerInstancePath("modem_nvram.json");
+
+  auto ret = new NvramConfig(num_instances, sim_type);
+  if (ret) {
+    if (!cuttlefish::FileExists(nvram_config_path) ||
+        !cuttlefish::FileHasContent(nvram_config_path.c_str())) {
+      ret->InitDefaultNvramConfig();
+    } else {
+      auto loaded = ret->LoadFromFile(nvram_config_path.c_str());
+      if (!loaded) {
+        delete ret;
+        return nullptr;
+      }
+    }
+  }
+  return ret;
+}
+
+std::unique_ptr<NvramConfig> NvramConfig::s_nvram_config;
+
+void NvramConfig::InitNvramConfigService(size_t num_instances, int sim_type) {
+  static std::once_flag once_flag;
+
+  std::call_once(once_flag, [num_instances, sim_type]() {
+    NvramConfig::s_nvram_config.reset(BuildConfigImpl(num_instances, sim_type));
+  });
+}
+
+/* static */ const NvramConfig* NvramConfig::Get() {
+  return s_nvram_config.get();
+}
+
+void NvramConfig::SaveToFile() {
+  auto nvram_config = Get();
+  auto nvram_config_file = nvram_config->ConfigFileLocation();
+  nvram_config->SaveToFile(nvram_config_file);
+}
+
+NvramConfig::NvramConfig(size_t num_instances, int sim_type)
+    : total_instances_(num_instances),
+      sim_type_(sim_type),
+      dictionary_(new Json::Value()) {}
+// Can't use '= default' on the header because the compiler complains of
+// Json::Value being an incomplete type
+NvramConfig::~NvramConfig() = default;
+
+NvramConfig::NvramConfig(NvramConfig&&) = default;
+NvramConfig& NvramConfig::operator=(NvramConfig&&) = default;
+
+NvramConfig::InstanceSpecific NvramConfig::ForInstance(int num) const {
+  return InstanceSpecific(this, std::to_string(num));
+}
+
+std::string NvramConfig::ConfigFileLocation() const {
+  return cuttlefish::AbsolutePath(
+      cuttlefish::modem::DeviceConfig::PerInstancePath("modem_nvram.json"));
+}
+
+bool NvramConfig::LoadFromFile(const char* file) {
+  auto real_file_path = cuttlefish::AbsolutePath(file);
+  if (real_file_path.empty()) {
+    LOG(ERROR) << "Could not get real path for file " << file;
+    return false;
+  }
+
+  Json::CharReaderBuilder builder;
+  std::ifstream ifs(real_file_path);
+  std::string errorMessage;
+  if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
+    LOG(ERROR) << "Could not read config file " << file << ": "
+               << errorMessage;
+    return false;
+  }
+  return true;
+}
+
+bool NvramConfig::SaveToFile(const std::string& file) const {
+  std::ofstream ofs(file);
+  if (!ofs.is_open()) {
+    LOG(ERROR) << "Unable to write to file " << file;
+    return false;
+  }
+  ofs << *dictionary_;
+  return !ofs.fail();
+}
+
+void NvramConfig::InitDefaultNvramConfig() {
+  for (size_t num = 0; num < total_instances_; num++) {
+    auto instance = ForInstance(num);
+    instance.set_modem_technoloy(kDefaultModemTechnoloy);
+    instance.set_network_selection_mode(kDefaultNetworkSelectionMode);
+    instance.set_preferred_network_mode(kDefaultPreferredNetworkMode);
+    instance.set_emergency_mode(kDefaultEmergencyMode);
+  }
+}
+
+const Json::Value* NvramConfig::InstanceSpecific::Dictionary() const {
+  return &(*config_->dictionary_)[kInstances][id_];
+}
+
+Json::Value* NvramConfig::InstanceSpecific::Dictionary() {
+  return &(*config_->dictionary_)[kInstances][id_];
+}
+
+int NvramConfig::InstanceSpecific::network_selection_mode() const {
+  return (*Dictionary())[kNetworkSelectionMode].asInt();
+}
+
+void NvramConfig::InstanceSpecific::set_network_selection_mode(int mode) {
+  (*Dictionary())[kNetworkSelectionMode] = mode;
+}
+
+std::string NvramConfig::InstanceSpecific::operator_numeric() const {
+  return (*Dictionary())[kOperatorNumeric].asString();
+}
+
+void NvramConfig::InstanceSpecific::set_operator_numeric(std::string& operator_numeric) {
+  (*Dictionary())[kOperatorNumeric] = operator_numeric;
+}
+
+int NvramConfig::InstanceSpecific::modem_technoloy() const {
+  return (*Dictionary())[kModemTechnoloy].asInt();
+}
+
+void NvramConfig::InstanceSpecific::set_modem_technoloy(int technoloy) {
+  (*Dictionary())[kModemTechnoloy] = technoloy;
+}
+
+int NvramConfig::InstanceSpecific::preferred_network_mode() const {
+  return (*Dictionary())[kPreferredNetworkMode].asInt();
+}
+
+void NvramConfig::InstanceSpecific::set_preferred_network_mode(int mode) {
+  (*Dictionary())[kPreferredNetworkMode] = mode;
+}
+
+bool NvramConfig::InstanceSpecific::emergency_mode() const {
+  return (*Dictionary())[kEmergencyMode].asBool();
+}
+
+void NvramConfig::InstanceSpecific::set_emergency_mode(bool mode) {
+  (*Dictionary())[kEmergencyMode] = mode;
+}
+
+int NvramConfig::sim_type() const {
+  return sim_type_;
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/nvram_config.h b/host/commands/modem_simulator/nvram_config.h
new file mode 100644
index 0000000..fc51c80
--- /dev/null
+++ b/host/commands/modem_simulator/nvram_config.h
@@ -0,0 +1,94 @@
+//
+// 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 <json/json.h>
+
+namespace cuttlefish {
+
+// Holds the configuration of modem simulator.
+class NvramConfig {
+
+ public:
+  static void InitNvramConfigService(size_t num_instances, int sim_type);
+  static const NvramConfig* Get();
+  static void SaveToFile();
+
+  NvramConfig(size_t num_instances, int sim_type);
+  NvramConfig(NvramConfig&&);
+  ~NvramConfig();
+  NvramConfig& operator=(NvramConfig&&);
+
+  std::string ConfigFileLocation() const;
+  // Saves the configuration object in a file
+  bool SaveToFile(const std::string& file) const;
+
+  class InstanceSpecific;
+
+  InstanceSpecific ForInstance(int instance_num) const;
+
+  std::vector<InstanceSpecific> Instances() const;
+
+  int sim_type() const;
+
+  // A view into an existing modem simulator object for a particular instance.
+  class InstanceSpecific {
+  public:
+    int network_selection_mode() const;
+    void set_network_selection_mode(int mode);
+
+    std::string operator_numeric() const;
+    void set_operator_numeric(std::string& operator_numeric);
+
+    int modem_technoloy() const;
+    void set_modem_technoloy(int technoloy);
+
+    int preferred_network_mode() const;
+    void set_preferred_network_mode(int mode);
+
+    bool emergency_mode() const;
+    void set_emergency_mode(bool mode);
+
+   private:
+    friend InstanceSpecific NvramConfig::ForInstance(int num) const;
+    friend std::vector<InstanceSpecific> NvramConfig::Instances() const;
+
+    InstanceSpecific(const NvramConfig* config, const std::string& id)
+        : config_(config), id_(id) {}
+
+    Json::Value* Dictionary();
+    const Json::Value* Dictionary() const;
+
+    const NvramConfig* config_;
+    std::string id_;
+  };
+
+ private:
+  static std::unique_ptr<NvramConfig> s_nvram_config;
+  size_t total_instances_;
+  int sim_type_;
+  std::unique_ptr<Json::Value> dictionary_;
+
+  bool LoadFromFile(const char* file);
+  static NvramConfig* BuildConfigImpl(size_t num_instances, int sim_type);
+
+  void InitDefaultNvramConfig();
+
+  NvramConfig(const NvramConfig&) = delete;
+  NvramConfig& operator=(const NvramConfig&) = delete;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/pdu_parser.cpp b/host/commands/modem_simulator/pdu_parser.cpp
new file mode 100644
index 0000000..5cc425e
--- /dev/null
+++ b/host/commands/modem_simulator/pdu_parser.cpp
@@ -0,0 +1,300 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/pdu_parser.h"
+
+#include <algorithm>
+#include <chrono>
+#include <ctime>
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <thread>
+
+namespace cuttlefish {
+
+static const std::string kWithoutServiceCenterAddress     = "00";
+static const std::string kStatusReportIndicator           = "06";
+static const std::string kSRIAndMMSIndicator              = "24";  /* SRI is 1 && MMS is 1*/
+static const std::string kUDHIAndSRIAndMMSIndicator       = "64";  /* UDHI is 1 && SRI is 1 && MMS is 1*/
+
+PDUParser::PDUParser(std::string &pdu) {
+  is_valid_pdu_ = DecodePDU(pdu);
+}
+
+bool PDUParser::IsValidPDU() {
+  return is_valid_pdu_;
+}
+
+/**
+ * PDU format:
+ *         SCA    PDU-Type   MR         OA            PID    DCS   VP    UDL    UD
+ * bytes: 1-12      1        1         2-12            1      1     0     1    0-140
+ * eg.     00       21       00   0B 91 5155255155F4   00     00          0C  AB58AD56ABC962B55A8D06
+ */
+//    00 01 00 05 81 0180F6 00 00 0D 61B2996C0691CD6433190402
+bool PDUParser::DecodePDU(std::string& pdu) {
+  // At least: SCA(1) + PDU-Type(1) + MR(1) + OA(2) + PID(1) + DSC(1) + UDL(1)
+  auto pdu_total_length = pdu.size();
+  if (pdu_total_length < 8) {
+    return false;
+  }
+
+  std::string_view pdu_view = pdu;
+  size_t pos = 0;
+
+  /* 1. SMSC Address Length: 1 byte */
+  std::string temp = pdu.substr(0, 2);
+  pos += 2;
+  if (temp != kWithoutServiceCenterAddress) {
+    auto smsc_length = Hex2ToByte(temp);
+    pos += smsc_length * 2;  // Skip SMSC Address
+  }
+
+  /* 2. PDU-Type: 1 byte */
+  pdu_type_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
+  pos += 2;
+
+  /* 3. MR: 1 byte */
+  message_reference_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
+  pos += 2;
+
+  /* 4. Originator Address Length: 1 byte */
+  temp = pdu_view.substr(std::min(pos, pdu_total_length), 2);
+  auto oa_length = Hex2ToByte(temp);
+  if (oa_length & 0x01) oa_length += 1;
+
+  /* 5. Originator Address including OA length */
+  originator_address_ = pdu_view.substr(std::min(pos, pdu_total_length), (oa_length + 4));
+  pos += (oa_length + 4);
+
+  /* 6. Protocol ID: 1 byte */
+  protocol_id_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
+  pos += 2;
+
+  /* 7. Data Code Scheme: 1 byte */
+  data_code_scheme_ = pdu_view.substr(std::min(pos, pdu_total_length), 2);
+  pos += 2;
+
+  /* 8. User Data Length: 1 byte */
+  temp = pdu_view.substr(std::min(pos, pdu_total_length), 2);
+  auto ud_length = Hex2ToByte(temp);
+
+  /* 9. User Data including UDL */
+  user_data_ = pdu_view.substr(std::min(pos, pdu_total_length));
+
+  if (data_code_scheme_ == "00") {  // GSM_7BIT
+    pos += ud_length * 2 + 2;
+    int offset = ud_length / 8;
+    pos -= offset * 2;
+  } else if (data_code_scheme_ == "08") {  // GSM_UCS2
+    pos += ud_length;
+  } else {
+    pos += ud_length * 2 + 2;
+  }
+  if (pos == pdu_total_length) {
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * The PDU-Type of receiver
+ * BIT      7    6    5    4    3    2    1    0
+ * Param   RP  UDHI  SRI   -    -   MMS  MTI MTI
+ * When SRR bit is 1, it represents that SMS status report should be reported.
+ */
+std::string PDUParser::CreatePDU() {
+  if (!is_valid_pdu_) return "";
+
+  // Ignore SMSC address, default to be '00'
+  std::string pdu = kWithoutServiceCenterAddress;
+  int pdu_type = Hex2ToByte(pdu_type_);
+
+  if (pdu_type & 0x40) {
+    pdu += kUDHIAndSRIAndMMSIndicator;
+  } else {
+    pdu += kSRIAndMMSIndicator;
+  }
+
+  pdu += originator_address_ + protocol_id_ + data_code_scheme_;
+  pdu += GetCurrentTimeStamp();
+  pdu += user_data_;
+
+  return pdu;
+}
+
+/**
+ * the PDU-Type of sender
+ * BIT     7    6    5    4    3    2    1    0
+ * Param   RP  UDHI  SRR  VPF  VPF  RD    MTI MTI
+ * When SRR bit is 1, it represents that SMS status report should be reported.
+ */
+bool PDUParser::IsNeededStatuReport() {
+  if (!is_valid_pdu_) return false;
+
+  int pdu_type = Hex2ToByte(pdu_type_);
+  if (pdu_type & 0x20) {
+    return true;
+  }
+
+  return false;
+}
+
+std::string PDUParser::CreateStatuReport(int message_reference) {
+  if (!is_valid_pdu_) return "";
+
+  std::string pdu = kWithoutServiceCenterAddress;
+  pdu += kStatusReportIndicator;
+
+  std::stringstream ss;
+  ss << std::setfill('0') << std::setw(2) << std::hex << message_reference;
+  pdu += ss.str();
+
+  pdu += originator_address_;
+  pdu += GetCurrentTimeStamp();
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  pdu += GetCurrentTimeStamp();
+  pdu += "00"; /* "00" means that SMS have been sent successfully */
+
+  return pdu;
+}
+
+std::string PDUParser::CreateRemotePDU(std::string& host_port) {
+  if (host_port.size() != 4 || !is_valid_pdu_) {
+    return "";
+  }
+
+  std::string pdu = kWithoutServiceCenterAddress + pdu_type_ + message_reference_;
+
+  // Remove the remote port
+  std::string number = GetPhoneNumberFromAddress();
+  auto new_phone_number = number.substr(0, number.size() - 4);;
+  new_phone_number.append(host_port);
+  if (new_phone_number.size() & 1) {
+    new_phone_number.append("F");
+  }
+
+  // Add OA length and type
+  pdu += originator_address_.substr(0,
+      originator_address_.size() - new_phone_number .size());
+  pdu += BCDToString(new_phone_number);   // Add local host port
+  pdu += protocol_id_;
+  pdu += data_code_scheme_;
+  pdu += user_data_;
+
+  return pdu;
+}
+
+std::string PDUParser::GetPhoneNumberFromAddress() {
+  if (!is_valid_pdu_) return "";
+
+  // Skip OA length and type
+  std::string address;
+  if (originator_address_.size() == 18) {
+    address = originator_address_.substr(6);
+  } else {
+    address = originator_address_.substr(4);
+  }
+
+  return BCDToString(address);
+}
+
+int PDUParser::HexCharToInt(char c) {
+  if (c >= '0' && c <= '9') return (c - '0');
+  if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+  if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+
+  return -1;  // Invalid hex char
+}
+
+int PDUParser::Hex2ToByte(const std::string& hex) {
+  int  hi = HexCharToInt(hex[0]);
+  int  lo = HexCharToInt(hex[1]);
+
+  if (hi < 0 || lo < 0) {
+    return -1;
+  }
+
+  return ( (hi << 4) | lo );
+}
+
+std::string PDUParser::IntToHexString(int value) {
+  int  hi = value / 10;
+  int  lo = value % 10;
+  return std::to_string(lo) + std::to_string(hi);
+}
+
+std::string PDUParser::IntToHexStringTimeZoneDiff(int tzdiff_hour) {
+  // https://en.wikipedia.org/wiki/GSM_03.40
+  int delta = 0;
+  if (tzdiff_hour < 0) {
+    tzdiff_hour = -tzdiff_hour;
+    delta = 8;
+  }
+  const int tzdiff_quarter_hour = 4 * tzdiff_hour;
+  const int hi = tzdiff_quarter_hour / 10 + delta;
+  const int lo = tzdiff_quarter_hour % 10;
+  std::stringstream ss;
+  ss << std::hex << lo;
+  ss << std::hex << hi;
+  return ss.str();
+}
+
+std::string PDUParser::BCDToString(std::string& data) {
+  std::string dst;
+  if (data.empty()) {
+    return "";
+  }
+  int length = data.size();
+  if (length & 0x01) {  /* Must be even */
+    return "";
+  }
+  for (int i = 0; i < length; i += 2) {
+    dst += data[i + 1];
+    dst += data[i];
+  }
+
+  if (dst[length -1] == 'F') {
+    dst.replace(length -1, length, "\0");
+  }
+  return dst;
+}
+
+std::string PDUParser::GetCurrentTimeStamp() {
+  std::string time_stamp;
+  auto now = std::time(0);
+
+  auto local_time = *std::localtime(&now);
+  auto gm_time = *std::gmtime(&now);
+
+  auto t_local_time = std::mktime(&local_time);
+  auto t_gm_time = std::mktime(&gm_time);
+
+  auto tzdiff = (int)std::difftime(t_local_time, t_gm_time) / (60 * 60);
+
+  time_stamp += IntToHexString(local_time.tm_year % 100);
+  time_stamp += IntToHexString(local_time.tm_mon + 1);
+  time_stamp += IntToHexString(local_time.tm_mday);
+  time_stamp += IntToHexString(local_time.tm_hour);
+  time_stamp += IntToHexString(local_time.tm_min);
+  time_stamp += IntToHexString(local_time.tm_sec);
+  time_stamp += IntToHexStringTimeZoneDiff(tzdiff);
+
+  return time_stamp;
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/modem_simulator/pdu_parser.h b/host/commands/modem_simulator/pdu_parser.h
new file mode 100644
index 0000000..5618ba7
--- /dev/null
+++ b/host/commands/modem_simulator/pdu_parser.h
@@ -0,0 +1,57 @@
+//
+// 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 cuttlefish {
+
+class PDUParser {
+ public:
+  explicit PDUParser(std::string &pdu);
+  ~PDUParser() = default;
+
+  bool IsValidPDU();
+  bool IsNeededStatuReport();
+  std::string CreatePDU();
+  std::string CreateRemotePDU(std::string& host_port);
+  std::string CreateStatuReport(int message_reference);
+  std::string GetPhoneNumberFromAddress();
+
+  static std::string BCDToString(std::string& data);
+
+ private:
+  bool DecodePDU(std::string& pdu);
+  int Hex2ToByte(const std::string& hex);
+  int HexCharToInt(char c);
+  std::string IntToHexString(int value);
+
+  // special handling for time zone differance (to GMT)
+  std::string IntToHexStringTimeZoneDiff(int value);
+  std::string GetCurrentTimeStamp();
+
+  bool is_valid_pdu_;
+
+  // Ignore SMSC address, default to be "00" when create PDU
+  std::string pdu_type_;
+  std::string message_reference_;
+  std::string originator_address_;
+  std::string protocol_id_;
+  std::string data_code_scheme_;
+  std::string user_data_;
+};
+
+} // namespace cuttlefish
diff --git a/host/commands/modem_simulator/sim_service.cpp b/host/commands/modem_simulator/sim_service.cpp
new file mode 100644
index 0000000..e6eced5
--- /dev/null
+++ b/host/commands/modem_simulator/sim_service.cpp
@@ -0,0 +1,1697 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/sim_service.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+
+#include "common/libs/utils/files.h"
+#include "host/commands/modem_simulator/device_config.h"
+#include "host/commands/modem_simulator/network_service.h"
+#include "host/commands/modem_simulator/pdu_parser.h"
+#include "host/commands/modem_simulator/nvram_config.h"
+
+namespace cuttlefish {
+
+const std::pair<int, int> kSimPinSizeRange(4, 8);
+constexpr int kSimPukSize = 8;
+constexpr int kSimPinMaxRetryTimes = 3;
+constexpr int kSimPukMaxRetryTimes = 10;
+static const std::string kDefaultPinCode = "1234";
+static const std::string kDefaultPukCode = "12345678";
+
+static const std::string MF_SIM       = "3F00";
+static const std::string DF_TELECOM   = "7F10";
+static const std::string DF_PHONEBOOK = "5F3A";
+static const std::string DF_GRAPHICS  = "5F50";
+static const std::string DF_GSM       = "7F20";
+static const std::string DF_CDMA      = "7F25";
+static const std::string DF_ADF       = "7FFF";  // UICC access
+
+// In an ADN record, everything but the alpha identifier
+// is in a footer that's 14 bytes
+constexpr int kFooterSizeBytes = 14;
+// Maximum size of the un-extended number field
+constexpr int kMaxNumberSizeBytes = 11;
+
+constexpr int kMaxLogicalChannels = 3;
+
+const std::map<SimService::SimStatus, std::string> gSimStatusResponse = {
+    {SimService::SIM_STATUS_ABSENT,     ModemService::kCmeErrorSimNotInserted},
+    {SimService::SIM_STATUS_NOT_READY,  ModemService::kCmeErrorSimBusy},
+    {SimService::SIM_STATUS_READY,      "+CPIN: READY"},
+    {SimService::SIM_STATUS_PIN,        "+CPIN: SIM PIN"},
+    {SimService::SIM_STATUS_PUK,        "+CPIN: SIM PUK"},
+};
+
+/* SimFileSystem */
+XMLElement* SimService::SimFileSystem::GetRootElement() {
+  return doc.RootElement();
+}
+
+std::string SimService::SimFileSystem::GetCommonIccEFPath(EFId efid) {
+  switch (efid) {
+    case EF_ADN:
+    case EF_FDN:
+    case EF_MSISDN:
+    case EF_SDN:
+    case EF_EXT1:
+    case EF_EXT2:
+    case EF_EXT3:
+    case EF_PSI:
+      return MF_SIM + DF_TELECOM;
+
+    case EF_ICCID:
+    case EF_PL:
+      return MF_SIM;
+    case EF_PBR:
+      // we only support global phonebook.
+      return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
+    case EF_IMG:
+      return MF_SIM + DF_TELECOM + DF_GRAPHICS;
+    default:
+      return {};
+  }
+}
+
+std::string SimService::SimFileSystem::GetUsimEFPath(EFId efid) {
+  switch(efid) {
+    case EF_SMS:
+    case EF_EXT5:
+    case EF_EXT6:
+    case EF_MWIS:
+    case EF_MBI:
+    case EF_SPN:
+    case EF_AD:
+    case EF_MBDN:
+    case EF_PNN:
+    case EF_OPL:
+    case EF_SPDI:
+    case EF_SST:
+    case EF_CFIS:
+    case EF_MAILBOX_CPHS:
+    case EF_VOICE_MAIL_INDICATOR_CPHS:
+    case EF_CFF_CPHS:
+    case EF_SPN_CPHS:
+    case EF_SPN_SHORT_CPHS:
+    case EF_FDN:
+    case EF_SDN:
+    case EF_EXT3:
+    case EF_MSISDN:
+    case EF_EXT2:
+    case EF_INFO_CPHS:
+    case EF_CSP_CPHS:
+    case EF_GID1:
+    case EF_GID2:
+    case EF_LI:
+    case EF_PLMN_W_ACT:
+    case EF_OPLMN_W_ACT:
+    case EF_HPLMN_W_ACT:
+    case EF_EHPLMN:
+    case EF_FPLMN:
+    case EF_LRPLMNSI:
+    case EF_HPPLMN:
+      return MF_SIM + DF_ADF;
+
+    case EF_PBR:
+      // we only support global phonebook.
+      return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
+    default:
+      std::string path = GetCommonIccEFPath(efid);
+      if (path.empty()) {
+        // The EFids in USIM phone book entries are decided by the card manufacturer.
+        // So if we don't match any of the cases above and if it's a USIM return
+        // the phone book path.
+        return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
+      }
+      return path;
+  }
+}
+
+XMLElement* SimService::SimFileSystem::FindAttribute(XMLElement *parent,
+                                                     const std::string& attr_name,
+                                                     const std::string& attr_value) {
+  if (parent == nullptr) {
+    return nullptr;
+  }
+
+  XMLElement* child = parent->FirstChildElement();
+  while (child) {
+    const XMLAttribute *attr = child->FindAttribute(attr_name.c_str());
+    if (attr && attr->Value() == attr_value) {
+      break;
+    }
+    child = child->NextSiblingElement();
+  }
+  return child;
+};
+
+XMLElement* SimService::SimFileSystem::AppendNewElement(XMLElement* parent,
+                                                        const char* name) {
+  auto element = doc.NewElement(name);
+  parent->InsertEndChild(element);
+  return element;
+}
+
+XMLElement* SimService::SimFileSystem::AppendNewElementWithText(
+        XMLElement* parent, const char* name, const char* text) {
+  auto element = doc.NewElement(name);
+  auto xml_text = doc.NewText(text);
+  element->InsertEndChild(xml_text);
+  parent->InsertEndChild(element);
+  return element;
+}
+
+/* PinStatus */
+bool SimService::PinStatus::CheckPasswordValid(std::string_view password) {
+  for (int i = 0; i < password.size(); i++) {
+    int c = (int)password[i];
+    if (c >= 48 && c <= 57) {
+      continue;
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool SimService::PinStatus::VerifyPIN(const std::string_view pin) {
+  if (pin.size() < kSimPinSizeRange.first || pin.size() > kSimPinSizeRange.second) {
+    return false;
+  }
+
+  if (!CheckPasswordValid(pin)) {
+    return false;
+  }
+
+  if (pin_remaining_times_ <= 0) {
+    return false;
+  }
+
+  std::string_view temp(pin_);
+  if (pin == temp) {  // C++20 remove Operator!=
+    pin_remaining_times_ = kSimPinMaxRetryTimes;
+    return true;
+  }
+
+  pin_remaining_times_ -= 1;
+  return false;
+}
+
+bool SimService::PinStatus::VerifyPUK(const std::string_view puk) {
+  if (puk.size() != kSimPukSize) {
+    return false;
+  }
+
+  if (!CheckPasswordValid(puk)) {
+    return false;
+  }
+
+  if (puk_remaining_times_ <= 0) {
+    return false;
+  }
+
+  std::string_view temp(puk_);
+  if (puk == temp) {  // C++20 remove Operator!=
+    pin_remaining_times_ = kSimPinMaxRetryTimes;
+    puk_remaining_times_ = kSimPukMaxRetryTimes;
+    return true;
+  }
+
+  puk_remaining_times_ -= 1;
+  return false;
+}
+
+bool SimService::PinStatus::ChangePIN(ChangeMode mode,
+                                      const std::string_view pin_or_puk,
+                                      const std::string_view new_pin) {
+  auto length = new_pin.length();
+  if (length < kSimPinSizeRange.first || length > kSimPinSizeRange.second) {
+    LOG(ERROR) << "Invalid digit number for PIN";
+    return false;
+  }
+
+  bool result = false;
+  if (mode == WITH_PIN) {  // using old pin to change pin
+    result = VerifyPIN(pin_or_puk);
+  } else if (mode == WITH_PUK) {  // using puk to change pin
+    result = VerifyPUK(pin_or_puk);
+  }
+
+  if (!result) {
+    LOG(ERROR) << "Incorrect PIN or PUK";
+    return false;
+  }
+
+  if (!CheckPasswordValid(new_pin)) {
+    return false;
+  }
+
+  std::string temp(new_pin);
+  pin_ = temp;
+  return true;
+}
+
+bool SimService::PinStatus::ChangePUK(const std::string_view puk,
+                                      const std::string_view new_puk) {
+  bool result = VerifyPUK(puk);
+  if (!result) {
+    LOG(ERROR) << "Incorrect PUK or no retry times";
+    return false;
+  }
+
+  if (new_puk.length() != kSimPukSize) {
+    LOG(ERROR) << "Invalid digit number for PUK";
+    return false;
+  }
+
+  std::string temp(new_puk);
+  puk_ = temp;
+  return true;
+};
+
+SimService::SimService(int32_t service_id, ChannelMonitor* channel_monitor,
+                       ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {
+  InitializeServiceState();
+}
+
+std::vector<CommandHandler> SimService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      CommandHandler(
+          "+CPIN?",
+          [this](const Client& client) { this->HandleSIMStatusReq(client); }),
+      CommandHandler("+CPIN=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleChangeOrEnterPIN(client, cmd);
+                     }),
+      CommandHandler("+CRSM=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSIM_IO(client, cmd);
+                     }),
+      CommandHandler("+CSIM=",
+                     [this](const Client& client, std::string& cmd) {
+                     this->HandleCSIM_IO(client, cmd);
+                     }),
+      CommandHandler(
+          "+CIMI",
+          [this](const Client& client) { this->HandleGetIMSI(client); }),
+      CommandHandler(
+          "+CICCID",
+          [this](const Client& client) { this->HandleGetIccId(client); }),
+      CommandHandler("+CLCK=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleFacilityLock(client, cmd);
+                     }),
+      CommandHandler("+CCHO=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleOpenLogicalChannel(client, cmd);
+                     }),
+      CommandHandler("+CCHC=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleCloseLogicalChannel(client, cmd);
+                     }),
+      CommandHandler("+CGLA=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleTransmitLogicalChannel(client, cmd);
+                     }),
+      CommandHandler("+CPWD=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleChangePassword(client, cmd);
+                     }),
+      CommandHandler("+CPINR=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleQueryRemainTimes(client, cmd);
+                     }),
+      CommandHandler("+CCSS",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleCdmaSubscriptionSource(client, cmd);
+                     }),
+      CommandHandler("+WRMP",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleCdmaRoamingPreference(client, cmd);
+                     }),
+      CommandHandler("^MBAU=",
+                    [this](const Client& client, std::string& cmd) {
+                    this->HandleSimAuthentication(client, cmd);
+                    }),
+  };
+  return (command_handlers);
+}
+
+void SimService::InitializeServiceState() {
+  InitializeSimFileSystemAndSimState();
+
+  InitializeFacilityLock();
+
+  // Max logical channels: 3
+  logical_channels_ = {
+      LogicalChannel(1), LogicalChannel(2), LogicalChannel(kMaxLogicalChannels),
+  };
+}
+
+void SimService::InitializeSimFileSystemAndSimState() {
+  auto nvram_config = NvramConfig::Get();
+  auto sim_type = nvram_config->sim_type();
+  std::stringstream ss;
+  if (sim_type == 2) {  // Special sim card for CtsCarrierApiTestCases
+    ss << "iccprofile_for_sim" << service_id_ << "_for_CtsCarrierApiTestCases.xml";
+  } else {
+    ss << "iccprofile_for_sim" << service_id_ << ".xml";
+  }
+  auto icc_profile_name = ss.str();
+
+  auto icc_profile_path = cuttlefish::modem::DeviceConfig::PerInstancePath(
+      icc_profile_name.c_str());
+  std::string file = icc_profile_path;
+
+  if (!cuttlefish::FileExists(icc_profile_path) ||
+      !cuttlefish::FileHasContent(icc_profile_path.c_str())) {
+    ss.clear();
+    ss.str("");
+
+    if (sim_type == 2) {  // Special sim card for CtsCarrierApiTestCases
+      ss << "etc/modem_simulator/files/iccprofile_for_sim" << service_id_
+          << "_for_CtsCarrierApiTestCases.xml";
+    } else {
+      ss << "etc/modem_simulator/files/iccprofile_for_sim" << service_id_ << ".xml";
+    }
+
+    auto etc_file_path =
+        cuttlefish::modem::DeviceConfig::DefaultHostArtifactsPath(ss.str());
+    if (!cuttlefish::FileExists(etc_file_path) || !cuttlefish::FileHasContent(etc_file_path)) {
+      sim_status_ = SIM_STATUS_ABSENT;
+      return;
+    }
+    file = etc_file_path;
+  }
+
+  sim_file_system_.file_path = icc_profile_path;
+  auto err = sim_file_system_.doc.LoadFile(file.c_str());
+  if (err != tinyxml2::XML_SUCCESS) {
+    LOG(ERROR) << "Unable to load XML file '" << file << " ', error " << err;
+    sim_status_ = SIM_STATUS_ABSENT;
+    return;
+  }
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    LOG(ERROR) << "Unable to find root element: IccProfile";
+    sim_status_ = SIM_STATUS_ABSENT;
+    return;
+  }
+
+  // Default value if iccprofile not configure pin state
+  sim_status_ = SIM_STATUS_READY;
+  pin1_status_.pin_ = kDefaultPinCode;
+  pin1_status_.puk_ = kDefaultPukCode;
+  pin1_status_.pin_remaining_times_ = kSimPinMaxRetryTimes;
+  pin1_status_.puk_remaining_times_ = kSimPukMaxRetryTimes;
+  pin2_status_.pin_ = kDefaultPinCode;
+  pin2_status_.puk_ = kDefaultPukCode;
+  pin2_status_.pin_remaining_times_ = kSimPinMaxRetryTimes;
+  pin2_status_.puk_remaining_times_ = kSimPukMaxRetryTimes;
+
+  XMLElement *pin_profile = root->FirstChildElement("PinProfile");
+  if (pin_profile) {
+    // Pin1 status
+    auto pin_state = pin_profile->FirstChildElement("PINSTATE");
+    if (pin_state) {
+      std::string state = pin_state->GetText();
+      if (state == "PINSTATE_ENABLED_NOT_VERIFIED") {
+        sim_status_ = SIM_STATUS_PIN;
+      } else if (state == "PINSTATE_ENABLED_BLOCKED") {
+        sim_status_ = SIM_STATUS_PUK;
+      }
+    }
+    auto pin_code = pin_profile->FirstChildElement("PINCODE");
+    if (pin_code) pin1_status_.pin_ = pin_code->GetText();
+
+    auto puk_code = pin_profile->FirstChildElement("PUKCODE");
+    if (puk_code) pin1_status_.puk_ = puk_code->GetText();
+
+    auto pin_remaining_times = pin_profile->FirstChildElement("PINREMAINTIMES");
+    if (pin_remaining_times) {
+      pin1_status_.pin_remaining_times_ = std::stoi(pin_remaining_times->GetText());
+    }
+
+    auto puk_remaining_times = pin_profile->FirstChildElement("PUKREMAINTIMES");
+    if (puk_remaining_times) {
+      pin1_status_.puk_remaining_times_ = std::stoi(puk_remaining_times->GetText());
+    }
+
+    // Pin2 status
+    auto pin2_code = pin_profile->FirstChildElement("PIN2CODE");
+    if (pin2_code) pin2_status_.pin_ = pin2_code->GetText();
+
+    auto puk2_code = pin_profile->FirstChildElement("PUK2CODE");
+    if (puk2_code) pin2_status_.puk_ = puk2_code->GetText();
+
+    auto pin2_remaining_times = pin_profile->FirstChildElement("PIN2REMAINTIMES");
+    if (pin2_remaining_times) {
+      pin2_status_.pin_remaining_times_ = std::stoi(pin2_remaining_times->GetText());
+    }
+
+    auto puk2_remaining_times = pin_profile->FirstChildElement("PUK2REMAINTIMES");
+    if (puk2_remaining_times) {
+      pin2_status_.puk_remaining_times_ = std::stoi(puk2_remaining_times->GetText());
+    }
+  }
+}
+
+void SimService::InitializeFacilityLock() {
+  /* Default disable */
+  facility_lock_ = {
+      {"SC", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"FD", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"AO", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"OI", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"OX", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"AI", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"IR", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"AB", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"AG", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+      {"AC", FacilityLock(FacilityLock::LockStatus::DISABLE)},
+  };
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    LOG(ERROR) << "Unable to find root element: IccProfile";
+    sim_status_ = SIM_STATUS_ABSENT;
+    return;
+  }
+
+  XMLElement *facility_lock = root->FirstChildElement("FacilityLock");
+  if (!facility_lock) {
+    LOG(ERROR) << "Unable to find element: FacilityLock";
+    return;
+  }
+
+  for (auto iter = facility_lock_.begin(); iter != facility_lock_.end(); ++iter) {
+    auto lock_status = facility_lock->FirstChildElement(iter->first.c_str());
+    if (lock_status) {
+      std::string state = lock_status->GetText();
+      if (state == "ENABLE") {
+        iter->second.lock_status = FacilityLock::LockStatus::ENABLE;
+      }
+    }
+  }
+}
+
+void SimService::SavePinStateToIccProfile() {
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    LOG(ERROR) << "Unable to find root element: IccProfile";
+    sim_status_ = SIM_STATUS_ABSENT;
+    return;
+  }
+
+  XMLElement *pin_profile = root->FirstChildElement("PinProfile");
+  if (!pin_profile) {
+    pin_profile = sim_file_system_.AppendNewElement(root, "PinProfile");
+  }
+
+  const char* text = "PINSTATE_UNKNOWN";
+
+  if (sim_status_ == SIM_STATUS_PUK) {
+    text = "PINSTATE_ENABLED_BLOCKED";
+  } else {
+    auto iter = facility_lock_.find("SC");
+    if (iter != facility_lock_.end()) {
+      if (iter->second.lock_status == FacilityLock::ENABLE) {
+        text = "PINSTATE_ENABLED_NOT_VERIFIED";
+      }
+    }
+  }
+
+  // Pin1 status
+  auto pin_state = pin_profile->FirstChildElement("PINSTATE");
+  if (!pin_state) {
+    pin_state = sim_file_system_.AppendNewElementWithText(pin_profile, "PINSTATE", text);
+  } else {
+    pin_state->SetText(text);
+  }
+
+  auto pin_code = pin_profile->FirstChildElement("PINCODE");
+  if (!pin_code) {
+    pin_code = sim_file_system_.AppendNewElementWithText(pin_profile, "PINCODE",
+        pin1_status_.pin_.c_str());
+  } else {
+    pin_code->SetText(pin1_status_.pin_.c_str());
+  }
+
+  auto puk_code = pin_profile->FirstChildElement("PUKCODE");
+  if (!puk_code) {
+    puk_code = sim_file_system_.AppendNewElementWithText(pin_profile, "PUKCODE",
+        pin1_status_.puk_.c_str());
+  } else {
+    puk_code->SetText(pin1_status_.puk_.c_str());
+  }
+
+  std::stringstream ss;
+  ss << pin1_status_.pin_remaining_times_;
+
+  auto pin_remaining_times = pin_profile->FirstChildElement("PINREMAINTIMES");
+  if (!pin_remaining_times) {
+    pin_remaining_times = sim_file_system_.AppendNewElementWithText(pin_profile,
+        "PINREMAINTIMES", ss.str().c_str());
+  } else {
+    pin_remaining_times->SetText(ss.str().c_str());
+  }
+  ss.clear();
+  ss.str("");
+  ss << pin1_status_.puk_remaining_times_;
+
+  auto puk_remaining_times = pin_profile->FirstChildElement("PUKREMAINTIMES");
+  if (!puk_remaining_times) {
+    puk_remaining_times = sim_file_system_.AppendNewElementWithText(pin_profile,
+        "PUKREMAINTIMES", ss.str().c_str());
+  } else {
+    puk_remaining_times->SetText(ss.str().c_str());
+  }
+
+  // Pin2 status
+  auto pin2_code = pin_profile->FirstChildElement("PIN2CODE");
+  if (!pin2_code) {
+    pin2_code = sim_file_system_.AppendNewElementWithText(pin_profile, "PIN2CODE",
+        pin2_status_.pin_.c_str());
+  } else {
+    pin2_code->SetText(pin2_status_.pin_.c_str());
+  }
+
+  auto puk2_code = pin_profile->FirstChildElement("PUK2CODE");
+  if (!puk2_code) {
+    puk2_code = sim_file_system_.AppendNewElementWithText(pin_profile, "PUK2CODE",
+        pin2_status_.puk_.c_str());
+  } else {
+    puk2_code->SetText(pin2_status_.puk_.c_str());
+  }
+
+  ss.clear();
+  ss.str("");
+  ss << pin2_status_.pin_remaining_times_;
+
+  auto pin2_remaining_times = pin_profile->FirstChildElement("PIN2REMAINTIMES");
+  if (!pin2_remaining_times) {
+    pin2_remaining_times = sim_file_system_.AppendNewElementWithText(pin_profile,
+        "PINREMAINTIMES", ss.str().c_str());
+  } else {
+    pin2_remaining_times->SetText(ss.str().c_str());
+  }
+  ss.clear();
+  ss.str("");
+  ss << pin2_status_.puk_remaining_times_;
+
+  auto puk2_remaining_times = pin_profile->FirstChildElement("PUK2REMAINTIMES");
+  if (!puk2_remaining_times) {
+    puk2_remaining_times = sim_file_system_.AppendNewElementWithText(pin_profile,
+        "PUK2REMAINTIMES", ss.str().c_str());
+  } else {
+    puk2_remaining_times->SetText(ss.str().c_str());
+  }
+
+  // Save file
+  sim_file_system_.doc.SaveFile(sim_file_system_.file_path.c_str());
+}
+
+void SimService::SaveFacilityLockToIccProfile() {
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    LOG(ERROR) << "Unable to find root element: IccProfile";
+    sim_status_ = SIM_STATUS_ABSENT;
+    return;
+  }
+
+  XMLElement *facility_lock = root->FirstChildElement("FacilityLock");
+  if (!facility_lock) {
+    facility_lock = sim_file_system_.AppendNewElement(root, "FacilityLock");
+  }
+
+  const char* text = "DISABLE";
+
+  for (auto iter = facility_lock_.begin(); iter != facility_lock_.end(); ++iter) {
+    if (iter->second.lock_status == FacilityLock::LockStatus::ENABLE) {
+      text = "ENABLE";
+    } else {
+      text = "DISABLE";
+    }
+    auto element = facility_lock->FirstChildElement(iter->first.c_str());
+    if (!element) {
+      element = sim_file_system_.AppendNewElementWithText(facility_lock,
+          iter->first.c_str(), text);
+    } else {
+      element->SetText(text);
+    }
+  }
+
+  sim_file_system_.doc.SaveFile(sim_file_system_.file_path.c_str());
+
+  InitializeSimFileSystemAndSimState();
+  InitializeFacilityLock();
+}
+
+bool SimService::IsFDNEnabled() {
+  auto iter = facility_lock_.find("FD");
+  if (iter != facility_lock_.end() &&
+      iter->second.lock_status == FacilityLock::LockStatus::ENABLE) {
+    return true;
+  }
+  return false;
+}
+
+bool SimService::IsFixedDialNumber(std::string_view number) {
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) return false;
+
+  auto path = SimFileSystem::GetUsimEFPath(SimFileSystem::EFId::EF_FDN);
+
+  size_t pos = 0;
+  auto parent = root;
+  while (pos < path.length()) {
+    std::string sub_path(path.substr(pos, 4));
+    auto app = SimFileSystem::FindAttribute(parent, "path", sub_path);
+    if (!app) return false;
+    pos += 4;
+    parent = app;
+  }
+
+  XMLElement* ef = SimFileSystem::FindAttribute(parent, "id", "6F3B");
+  if (!ef) return false;
+
+  XMLElement *final = ef->FirstChildElement("SIMIO");
+  while (final) {
+    std::string record = final->GetText();
+    int footerOffset = record.length() - kFooterSizeBytes * 2;
+    int numberLength = (record[footerOffset] - '0') * 16 +
+                        record[footerOffset + 1] - '0';
+    if (numberLength > kMaxNumberSizeBytes) {  // Invalid number length
+      final = final->NextSiblingElement("SIMIO");
+      continue;
+    }
+
+    std::string bcd_fdn = "";
+    if (numberLength * 2 == 16) {  // Skip Type(91) and Country Code(68)
+      bcd_fdn = record.substr(footerOffset + 6, numberLength * 2 - 4);
+    } else {  // Skip Type(81)
+      bcd_fdn = record.substr(footerOffset + 4, numberLength * 2 - 2);
+    }
+
+    std::string fdn = PDUParser::BCDToString(bcd_fdn);
+    if (fdn == number) {
+      return true;
+    }
+    final = final->NextSiblingElement("SIMIO");
+  }
+
+  return false;
+}
+
+XMLElement* SimService::GetIccProfile() {
+  return sim_file_system_.GetRootElement();
+}
+
+std::string SimService::GetPhoneNumber() {
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) return "";
+
+  auto path = SimFileSystem::GetUsimEFPath(SimFileSystem::EFId::EF_MSISDN);
+
+  size_t pos = 0;
+  auto parent = root;
+  while (pos < path.length()) {
+    std::string sub_path(path.substr(pos, 4));
+    auto app = SimFileSystem::FindAttribute(parent, "path", sub_path);
+    if (!app) return "";
+    pos += 4;
+    parent = app;
+  }
+
+  XMLElement* ef = SimFileSystem::FindAttribute(parent, "id", "6F40");
+  if (!ef) return "";
+
+  XMLElement *final = SimFileSystem::FindAttribute(ef, "cmd", "B2");;
+  if (!final) return "";
+
+  std::string record = final->GetText();
+  int footerOffset = record.length() - kFooterSizeBytes * 2;
+  int numberLength = (record[footerOffset] - '0') * 16 +
+                      record[footerOffset + 1] - '0';
+  if (numberLength > kMaxNumberSizeBytes) {  // Invalid number length
+    return "";
+  }
+
+  std::string bcd_number = "";
+  if (numberLength * 2 == 16) {  // Skip Type(91) and Country Code(68)
+    bcd_number = record.substr(footerOffset + 6, numberLength * 2 - 4);
+  } else {  // Skip Type(81)
+    bcd_number = record.substr(footerOffset + 4, numberLength * 2 - 2);
+  }
+
+  return PDUParser::BCDToString(bcd_number);
+}
+
+SimService::SimStatus SimService::GetSimStatus() const {
+  return sim_status_;
+}
+
+std::string SimService::GetSimOperator() {
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) return "";
+
+  XMLElement* mf = SimFileSystem::FindAttribute(root, "path", MF_SIM);
+  if (!mf) return "";
+
+  XMLElement* df = SimFileSystem::FindAttribute(mf, "path", DF_ADF);
+  if (!df) return "";
+
+  XMLElement* ef = SimFileSystem::FindAttribute(df, "id", "6F07");
+  if (!ef) return "";
+
+  XMLElement *cimi = ef->FirstChildElement("CIMI");
+  if (!cimi) return "";
+  std::string imsi = cimi->GetText();
+
+  ef = SimFileSystem::FindAttribute(df, "id", "6FAD");
+  if (!ef) return "";
+
+  XMLElement *sim_io = ef->FirstChildElement("SIMIO");
+  while (sim_io) {
+    const XMLAttribute *attr_cmd = sim_io->FindAttribute("cmd");
+    std::string attr_value = attr_cmd ? attr_cmd->Value() : "";
+    if (attr_cmd && attr_value == "B0") {
+      break;
+    }
+
+    sim_io = sim_io->NextSiblingElement("SIMIO");
+  }
+
+  if (!sim_io) return "";
+
+  std::string length = sim_io->GetText();
+  int mnc_size = std::stoi(length.substr(length.size() -2));
+
+  return imsi.substr(0, 3 + mnc_size);
+}
+
+void SimService::SetupDependency(NetworkService* net) {
+  network_service_ = net;
+}
+
+/**
+ * AT+CPIN
+ *   Set command sends to the MT a password which is necessary before it can be
+ * operated.
+ *   Read command returns an alphanumeric string indicating whether some
+ * password is required or not.
+ *
+ * Command                            Possible response(s)
+ * +CPIN=<pin>[,<newpin>]              +CME ERROR: <err>
+ * +CPIN?                              +CPIN: <code>
+ *                                     +CME ERROR: <err>
+ * <pin>, <newpin>: string type values.
+ * <code> values reserved by the present document:
+ *    READY   MT is not pending for any password
+ *   SIM PIN  MT is waiting SIM PIN to be given
+ *   SIM PUK  MT is waiting SIM PUK to be given
+ *
+ * see RIL_REQUEST_GET_SIM_STATUS in RIL
+ */
+void SimService::HandleSIMStatusReq(const Client& client) {
+  std::vector<std::string> responses;
+  auto iter = gSimStatusResponse.find(sim_status_);
+  if (iter != gSimStatusResponse.end()) {
+    responses.push_back(iter->second);
+    responses.push_back("OK");
+  } else {
+    sim_status_ = SIM_STATUS_ABSENT;
+    responses.push_back(kCmeErrorSimNotInserted);
+  }
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CRSM
+ *   By using this command instead of Generic SIM Access +CSIM TE application
+ *   has easier but more limited access to the SIM database.
+ *
+ *   Command                                Possible response(s)
+ * +CRSM=<command>[,<fileid>                +CRSM: <sw1>,<sw2>[,<response>]
+ * [,<P1>,<P2>,<P3>[,<data>[,<pathid>]]]]   +CME ERROR: <err>
+ *
+ * <command>: (command passed on by the MT to the SIM; refer 3GPP TS 51.011 [28]):
+ *   176 READ BINARY
+ *   178 READ RECORD
+ *   192 GET RESPONSE
+ *   214 UPDATE BINARY
+ *   220 UPDATE RECORD
+ *   242 STATUS
+ *   203 RETRIEVE DATA
+ *   219 SET DATA
+ *
+ * <fileid>: integer type; this is the identifier of a elementary datafile on SIM.
+ *           Mandatory for every command except STATUS.
+ *
+ * <P1>, <P2>, <P3>: integer type; parameters passed on by the MT to the SIM.
+ *                   These parameters are mandatory for every command,
+ *                   except GET RESPONSE and STATUS.
+ *
+ * <data>: information which shall be written to the SIM (hexadecimal character format).
+ *
+ * <pathid>: string type; contains the path of an elementary file on the SIM/UICC
+ *           in hexadecimal format.
+ *
+ * <sw1>, <sw2>: integer type; information from the SIM about the execution of
+ *               the actual command.
+ *
+ * <response>: response of a successful completion of the command previously issued
+ *             (hexadecimal character format; refer +CSCS).
+ */
+void SimService::HandleSIM_IO(const Client& client,
+                              const std::string& command) {
+  std::vector<std::string> kFileNotFoud = {"+CRSM: 106,130", "OK"};
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip "AT+CRSM="
+
+  if (*cmd == "242,0,0,0,0") { //  for cts teset
+    responses.push_back("+CRSM: 144,0,62338202782183023F00A50C80016187010183040007DBF08A01058B062F0601020002C60C90016083010183010A83010D8102FFFF");
+    responses.push_back("OK");
+    client.SendCommandResponse(responses);
+    return;
+  }
+
+  auto c = cmd.GetNextStrDeciToHex();
+  auto id = cmd.GetNextStrDeciToHex();
+  auto p1 = cmd.GetNextStrDeciToHex();
+  auto p2 = cmd.GetNextStrDeciToHex();
+  auto p3 = cmd.GetNextStrDeciToHex();
+
+  auto data = cmd.GetNextStr(',');
+  std::string path(cmd.GetNextStr());
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    LOG(ERROR) << "Unable to find root element: IccProfile";
+    client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+    return;
+  }
+
+  SimFileSystem::EFId fileid = (SimFileSystem::EFId)std::stoi(id, nullptr, 16);
+  if (path == "") {
+    path = SimFileSystem::GetUsimEFPath(fileid);
+  }
+  // EF_ADN under DF_PHONEBOOK is mapped to EF_ADN under DF_TELECOM per
+  // 3GPP TS 31.102 4.4.2
+  if (fileid == SimFileSystem::EF_ADN &&
+      path == SimFileSystem::GetUsimEFPath(fileid)) {
+    id = "4F3A";
+    path = MF_SIM + DF_TELECOM + DF_PHONEBOOK;
+  }
+
+  size_t pos = 0;
+  auto parent = root;
+  while (pos < path.length()) {
+    std::string sub_path(path.substr(pos, 4));
+    auto app = SimFileSystem::FindAttribute(parent, "path", sub_path);
+    if (!app) {
+      client.SendCommandResponse(kFileNotFoud);
+      return;
+    }
+    pos += 4;
+    parent = app;
+  }
+
+  XMLElement* ef = SimFileSystem::FindAttribute(parent, "id", id);
+  if (!ef) {
+    client.SendCommandResponse(kFileNotFoud);
+    return;
+  }
+
+  XMLElement *final = ef->FirstChildElement("SIMIO");
+  while (final) {
+    const XMLAttribute *attr_cmd = final->FindAttribute("cmd");
+    const XMLAttribute *attr_p1 = final->FindAttribute("p1");
+    const XMLAttribute *attr_p2 = final->FindAttribute("p2");
+    const XMLAttribute *attr_p3 = final->FindAttribute("p3");
+    const XMLAttribute *attr_data = final->FindAttribute("data");
+
+    if (c != "DC" && c != "D6") {  // Except UPDATE RECORD or UPDATE BINARY
+      if ((attr_cmd && attr_cmd->Value() != c) ||
+          (attr_data && attr_data->Value() != data)) {
+        final = final->NextSiblingElement("SIMIO");
+        continue;
+      }
+    }
+    if (attr_p1 && attr_p1->Value() == p1 &&
+        attr_p2 && attr_p2->Value() == p2 &&
+        attr_p3 && attr_p3->Value() == p3) {
+      break;
+    }
+    final = final->NextSiblingElement("SIMIO");
+  }
+
+  if (!final) {
+    client.SendCommandResponse(kFileNotFoud);
+    return;
+  }
+
+  std::string response = "+CRSM: ";
+  if (c == "DC" || c == "D6") {
+    std::string temp = "144,0,";
+    temp += data;
+    final->SetText(temp.c_str());
+    sim_file_system_.doc.SaveFile(sim_file_system_.file_path.c_str());
+    response.append("144,0");
+  } else {
+    response.append(final->GetText());
+  }
+
+  responses.push_back(response);
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+void SimService::OnSimStatusChanged() {
+  auto ptr = network_service_;
+  if (ptr) {
+    ptr->OnSimStatusChanged(sim_status_);
+  }
+}
+
+bool SimService::checkPin1AndAdjustSimStatus(std::string_view pin) {
+  if (pin1_status_.VerifyPIN(pin) == true) {
+    sim_status_ = SIM_STATUS_READY;
+    OnSimStatusChanged();
+    return true;
+  }
+
+  if (pin1_status_.pin_remaining_times_ <= 0) {
+    sim_status_ = SIM_STATUS_PUK;
+    OnSimStatusChanged();
+  }
+
+  return false;
+}
+
+/* AT+CSIM */
+void SimService::HandleCSIM_IO(const Client& client,
+                              const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip "AT+CSIM="
+
+  cmd.SkipComma();
+  auto data = cmd.GetNextStr();
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    LOG(ERROR) << "Unable to find root element: IccProfile";
+    client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+    return;
+  }
+  // Get aid
+  XMLElement* df = SimFileSystem::FindAttribute(root, "aid", "CSIM");
+  if (!df) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  std::string data_value(data);
+  if (data_value.length() > 10) {  // for open channel with csim
+      responses.push_back("+CSIM: 4,9000");
+      responses.push_back("OK");
+      client.SendCommandResponse(responses);
+      return;
+  }
+  XMLElement* final = SimFileSystem::FindAttribute(df, "cmd", data_value);
+  if (!final) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  auto id = data_value.substr(data_value.length() - 2, 2);
+
+  std::vector<LogicalChannel>::iterator iter = logical_channels_.begin();
+  for (; iter != logical_channels_.end(); ++iter) {
+    if (!iter->is_open) break;
+  }
+
+  if (iter != logical_channels_.end() && iter->session_id ==stoi(id)) {
+    iter->is_open = true;
+    iter->df_name = "CSIM";
+  }
+
+  std::stringstream ss;
+  ss << "+CSIM: " << final->GetText();
+
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+bool SimService::ChangePin1AndAdjustSimStatus(PinStatus::ChangeMode mode,
+                                              std::string_view pin,
+                                              std::string_view new_pin) {
+  if (pin1_status_.ChangePIN(mode, pin, new_pin) == true) {
+    sim_status_ = SIM_STATUS_READY;
+    OnSimStatusChanged();
+    return true;
+  }
+  if (sim_status_ == SIM_STATUS_READY && pin1_status_.pin_remaining_times_ <= 0) {
+    sim_status_ = SIM_STATUS_PIN;
+    OnSimStatusChanged();
+  } else if (sim_status_ == SIM_STATUS_PIN && pin1_status_.puk_remaining_times_ <= 0) {
+    sim_status_ = SIM_STATUS_ABSENT;
+    OnSimStatusChanged();
+  }
+  return false;
+}
+
+void SimService::HandleChangeOrEnterPIN(const Client& client,
+                                        const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip "AT+CPIN="
+  switch (sim_status_) {
+    case SIM_STATUS_ABSENT:
+      responses.push_back(kCmeErrorSimNotInserted);
+      break;
+    case SIM_STATUS_NOT_READY:
+      responses.push_back(kCmeErrorSimBusy);
+      break;
+    case SIM_STATUS_READY: {
+      /*
+       * this may be a request to change the PIN with pin and new pin:
+       *    AT+CPIN=pin,newpin
+       * or a request to enter the PIN2
+       *    AT+CPIN=pin2
+       */
+      auto pos = cmd->find(',');
+      if (pos != std::string_view::npos) {  // change pin with new pin
+        auto pin = cmd.GetNextStr(',');
+        auto new_pin = *cmd;
+
+        if (ChangePin1AndAdjustSimStatus(PinStatus::WITH_PIN, pin, new_pin)) {
+          responses.push_back("OK");
+        } else {
+          responses.push_back(kCmeErrorIncorrectPassword);  /* incorrect PIN */
+        }
+      } else {  // verify pin2
+        if (pin2_status_.VerifyPIN(*cmd) == true) {
+          responses.push_back("OK");
+        } else {
+          responses.push_back(kCmeErrorIncorrectPassword);  /* incorrect PIN2 */
+        }
+      }
+      break;
+    }
+    case SIM_STATUS_PIN: {  /* waiting for PIN */
+      if (checkPin1AndAdjustSimStatus(*cmd) == true) {
+        responses.push_back("OK");
+      } else {
+        responses.push_back(kCmeErrorIncorrectPassword);
+      }
+      break;
+    }
+    case SIM_STATUS_PUK: {
+      /*
+       * this may be a request to unlock the puk with new pin:
+       *    AT+CPIN=puk,newpin
+       */
+      auto pos = cmd->find(',');
+      if (pos != std::string_view::npos) {
+        auto puk = cmd.GetNextStr(',');
+        auto new_pin = *cmd;
+        if (ChangePin1AndAdjustSimStatus(PinStatus::WITH_PUK, puk, new_pin)) {
+          responses.push_back("OK");
+        } else {
+          responses.push_back(kCmeErrorIncorrectPassword);
+        }
+      } else {
+        responses.push_back(kCmeErrorOperationNotAllowed);
+      }
+      break;
+    }
+    default:
+      responses.push_back(kCmeErrorOperationNotAllowed);
+      break;
+  }
+
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CIMI
+ *   Execution command causes the TA to return <IMSI>, which is intended to
+ * permit the TE to identify the individual SIM card or active application in
+ * the UICC (GSM or USIM) which is attached to MT.
+ *
+ * Command                            Possible response(s)
+ * +CIMI                               <IMSI>
+ *                                     +CME ERROR: <err>
+ *
+ * <IMSI>: International Mobile Subscriber Identity (string without double quotes)
+ *
+ * see RIL_REQUEST_GET_IMSI in RIL
+ */
+void SimService::HandleGetIMSI(const Client& client) {
+  std::vector<std::string> responses;
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+    return;
+  }
+
+  XMLElement* mf = SimFileSystem::FindAttribute(root, "path", MF_SIM);
+  if (!mf) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  XMLElement* df = SimFileSystem::FindAttribute(mf, "path", DF_ADF);
+  if (!df) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  XMLElement* ef = SimFileSystem::FindAttribute(df, "id", "6F07");
+  if (!ef) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  XMLElement *final = ef->FirstChildElement("CIMI");
+  if (!final) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  responses.push_back(final->GetText());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CICCID
+ *   Integrated Circuit Card IDentifier (ICCID) is Unique Identifier of the SIM CARD.
+ *  File is located in the SIM card at EFiccid (0x2FE2).
+ *
+ * see RIL_REQUEST_GET_SIM_STATUS in RIL
+ */
+void SimService::HandleGetIccId(const Client& client) {
+  std::vector<std::string> responses;
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+    return;
+  }
+
+  XMLElement* mf = SimFileSystem::FindAttribute(root, "path", MF_SIM);
+  if (!mf) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  XMLElement* ef = SimFileSystem::FindAttribute(mf, "id", "2FE2");
+  if (!ef) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  XMLElement *final = ef->FirstChildElement("CCID");
+  if (!final) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  responses.push_back(final->GetText());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/*
+ * AT+CLCK
+ *   Execute command is used to lock, unlock or interrogate a MT or a network
+ * facility <fac>.
+ *
+ * Command                            Possible response(s)
+ * +CLCK=<fac>, <mode> [, <password>   OK or +CME ERROR: <err>
+ *       [, <class>]]                  +CLCK: <status>[,<class1>[<CR><LF>+CLCK:
+ *                                     <status>,<class2>[...]](when mode=2,it’s
+ *                                     in inquiry status.)
+ * <fac> values reserved by the present document:
+ *    "SC": SIM (lock SIM/UICC card installed in the currently selected card
+ *          slot) (SIM/UICC asks password in MT power‑up and when this lock
+ *          command issued).
+ *    "FD": SIM card or active application in the UICC (GSM or USIM) fixed
+ *          dialling memory feature (if PIN2 authentication has not been done
+ *          during the current session, PIN2 is required as <passwd>).
+ * <mode>: integer type
+ *      0: unlock
+ *      1: lock
+ *      2: query status
+ * <status>: integer type
+ *        0: not active
+ *        1: active
+ * <passwd>: string type; shall be the same as password specified for the
+ *           facility from the MT user interface or with command
+ *           Change Password +CPWD.
+ * <classx> is a sum of integers each representing a class of information
+ *          (default 7 - voice, data and fax):
+ *        1 voice (telephony)
+ *        2 data
+ *        4 fax (facsimile services)
+ *        8 short message service
+ *       16 data circuit sync
+ *       32 data circuit async
+ *       64 dedicated packet access
+ *      128 dedicated PAD access
+ *
+ * see RIL_REQUEST_SET_FACILITY_LOCK in RIL
+ */
+void SimService::HandleFacilityLock(const Client& client,
+                                    const std::string& command) {
+  CommandParser cmd(command);
+  std::string lock(cmd.GetNextStr());
+  int mode = cmd.GetNextInt();
+  auto password = cmd.GetNextStr();
+  // Ignore class from RIL
+
+  auto iter = facility_lock_.find(lock);
+  if (iter == facility_lock_.end()) {
+    client.SendCommandResponse(kCmeErrorOperationNotSupported);
+    return;
+  }
+
+  std::stringstream ss;
+  std::vector<std::string> responses;
+  switch (mode) {
+    case FacilityLock::Mode::QUERY: {
+      ss << "+CLCK: " << iter->second.lock_status;
+      responses.push_back(ss.str());
+      responses.push_back("OK");
+      break;
+    }
+    case FacilityLock::Mode::LOCK:
+    case FacilityLock::Mode::UNLOCK: {
+      if (lock == "SC") {
+        if (checkPin1AndAdjustSimStatus(password) == true) {
+          iter->second.lock_status = (FacilityLock::LockStatus)mode;
+          responses.push_back("OK");
+        } else {
+          responses.push_back(kCmeErrorIncorrectPassword);
+        }
+      } else if (lock == "FD") {
+        if (pin2_status_.VerifyPIN(password) == true) {
+          iter->second.lock_status = (FacilityLock::LockStatus)mode;
+          responses.push_back("OK");
+        } else {
+          responses.push_back(kCmeErrorIncorrectPassword);
+        }
+      } else {  // Don't need password except 'SC' and 'FD'
+        iter->second.lock_status = (FacilityLock::LockStatus)mode;
+        responses.push_back("OK");
+      }
+      break;
+    }
+    default:
+      responses.push_back(kCmeErrorInCorrectParameters);
+      break;
+  }
+
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CCHO
+ *   The currently selected UICC will open a new logical channel; select the
+ * application identified by the <dfname> received with this command and return
+ * a session Id as the response.
+ *
+ * Command                            Possible response(s)
+ * +CCHO=<dfname>                      <sessionid>
+ *                                     +CME ERROR: <err>
+ *
+ * <dfname>: all selectable applications in the UICC are referenced by a DF
+ *           name coded on 1 to 16 bytes.
+ * <sessionid>: integer type; a session Id to be used in order to target a
+ *            specific application on the smart card (e.g. (U)SIM, WIM, ISIM)
+ *            using logical channels mechanism.
+ *
+ * see RIL_REQUEST_SIM_OPEN_CHANNEL in RIL
+ */
+void SimService::HandleOpenLogicalChannel(const Client& client,
+                                          const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip AT+CCHO=
+  if (cmd->empty()) {
+    client.SendCommandResponse(kCmeErrorInCorrectParameters);
+    return;
+  }
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+    return;
+  }
+
+  std::string aid_value(*cmd);
+  XMLElement* df = SimFileSystem::FindAttribute(root, "aid", aid_value);
+  if (!df) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  std::vector<LogicalChannel>::iterator iter = logical_channels_.begin();
+  for (; iter != logical_channels_.end(); ++iter) {
+    if (!iter->is_open) break;
+  }
+
+  if (iter != logical_channels_.end()) {
+    iter->is_open = true;
+    iter->df_name = *cmd;
+
+    std::stringstream ss;
+    ss << iter->session_id;
+    responses.push_back(ss.str());
+    responses.push_back("OK");
+  } else {
+    responses.push_back(kCmeErrorMemoryFull);
+  }
+
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CCHC
+ *   This command asks the ME to close a communication session with the active
+ * UICC.
+ *
+ * Command                            Possible response(s)
+ * +CCHC=<sessionid>                   +CCHC
+ *                                     +CME ERROR: <err>
+ * <sessionid>: see AT+CCHO
+ *
+ * see RIL_REQUEST_SIM_CLOSE_CHANNEL in RIL
+ */
+void SimService::HandleCloseLogicalChannel(const Client& client,
+                                           const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip AT+CCHC=
+
+  int session_id = cmd.GetNextInt();
+  std::vector<LogicalChannel>::iterator iter = logical_channels_.begin();
+  for (; iter != logical_channels_.end(); ++iter) {
+    if (iter->session_id == session_id) break;
+  }
+
+  if (iter != logical_channels_.end() && iter->is_open) {
+    iter->is_open = false;
+    iter->df_name.clear();
+    responses.push_back("+CCHC");
+    responses.push_back("OK");
+  } else {
+    responses.push_back(kCmeErrorNotFound);
+  }
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CGLA
+ *   Set command transmits to the MT the <command> it then shall send as it is
+ * to the selected UICC. In the same manner the UICC <response> shall be sent
+ * back by the MT to the TA as it is.
+ *
+ * Command                            Possible response(s)
+ * +CGLA=<sessionid>,<length>,         +CGLA: <length>,<response>
+ *                                     +CME ERROR: <err>
+ * <sessionid>: AT+CCHO
+ * <length>: integer type; length of the characters that are sent to TE in
+ *         <command> or <response> .
+ * <command>: command passed on by the MT to the UICC in the format as described
+ *          in 3GPP TS 31.101 [65] (hexadecimal character format; refer +CSCS).
+ * <response>: response to the command passed on by the UICC to the MT in the
+ *           format as described in 3GPP TS 31.101 [65] (hexadecimal character
+ *           format; refer +CSCS).
+ *
+ * see RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL in RIL
+ */
+void SimService::HandleTransmitLogicalChannel(const Client& client,
+                                              const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip AT+CGLA=
+
+  int session_id = cmd.GetNextInt();
+  int length = cmd.GetNextInt();
+  if (cmd->length() != length) {
+    client.SendCommandResponse(kCmeErrorInCorrectParameters);
+    return;
+  }
+
+  // Check if session id is opened
+  auto iter = logical_channels_.begin();
+  for (; iter != logical_channels_.end(); ++iter) {
+    if (iter->session_id == session_id && iter->is_open) {
+      break;
+    }
+  }
+
+  if (iter == logical_channels_.end()) {
+    client.SendCommandResponse(kCmeErrorInvalidIndex);
+    return;
+  }
+
+  XMLElement *root = sim_file_system_.GetRootElement();
+  if (!root) {
+    client.SendCommandResponse(kCmeErrorOperationNotAllowed);
+    return;
+  }
+
+  // Get aid
+  XMLElement* df = SimFileSystem::FindAttribute(root, "aid", iter->df_name);
+  if (!df) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  if (iter->df_name != "CSIM") {
+    std::string command_vaule(*cmd);
+    if (command_vaule.substr(2, 2) == "a4") {
+      last_file_id_ = command_vaule.substr(command_vaule.length() - 4, 4);
+    }
+      df = SimFileSystem::FindAttribute(df, "id", last_file_id_);
+      if (!df) {
+      client.SendCommandResponse(kCmeErrorNotFound);
+      return;
+    }
+  }
+
+  std::string attr_value(*cmd);
+  XMLElement* final = SimFileSystem::FindAttribute(df, "cmd", attr_value);
+  if (!final) {
+    client.SendCommandResponse(kCmeErrorNotFound);
+    return;
+  }
+
+  std::stringstream ss;
+  ss << "+CGLA: " << final->GetText();
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CPWD
+ *   Action command sets a new password for the facility lock function defined
+ * by command Facility Lock +CLCK
+ *
+ * Command                              Possible response(s)
+ * +CPWD=<fac>,<oldpwd>,<newpwd>          +CME ERROR: <err>
+ *
+ * <fac>:
+ *   "P2"  SIM PIN2
+ *   refer Facility Lock +CLCK for other values
+ * <oldpwd>, <newpwd>:
+ *   string type; <oldpwd> shall be the same as password specified for the
+ *   facility from the MT user interface or with command Change Password +CPWD
+ *   and <newpwd> is the new password; maximum length of password can be determined
+ *   with <pwdlength>
+ * <pwdlength>: integer type maximum length of the password for the facility
+ */
+void SimService::HandleChangePassword(const Client& client,
+                                      const std::string& command) {
+  std::string response = kCmeErrorIncorrectPassword;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  auto lock = cmd.GetNextStr();
+  auto old_password = cmd.GetNextStr();
+  auto new_password = cmd.GetNextStr();
+
+  if (lock == "SC") {
+    if (ChangePin1AndAdjustSimStatus(PinStatus::WITH_PIN, old_password, new_password)) {
+      response = "OK";
+    }
+  } else if (lock == "P2" || lock == "FD") {
+    if (pin2_status_.ChangePIN(PinStatus::WITH_PIN, old_password, new_password)) {
+      response = "OK";
+    }
+  } else {
+    response = kCmeErrorOperationNotSupported;;
+  }
+
+  client.SendCommandResponse(response);
+}
+
+/**
+ * AT+CPINR
+ *   Execution command cause the MT to return the number of remaining PIN retries
+ * for the MT passwords with intermediate result code
+ *
+ * Command                        Possible response(s)
+ * +CPINR[=<sel_code>]            +CPINR: <code>,<retries>[,<default_retries>]
+ *
+ * <retries>:
+ *   integer type. Number of remaining retries per PIN.
+ * <default_retries>:
+ *   integer type. Number of default/initial retries per PIN.
+ * <code>:
+ *   Type of PIN. All values listed under the description of the AT+CPIN command
+ * <sel_code>: String type. Same values as for the <code> and <ext_code> parameters.
+ *   these values are strings and shall be indicated within double quotes.
+ */
+void SimService::HandleQueryRemainTimes(const Client& client,
+                                        const std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  auto lock_type = cmd.GetNextStr();
+
+  if (lock_type == "SIM PIN") {
+    ss << "+CPINR: SIM PIN," << pin1_status_.pin_remaining_times_ << ","
+                             << kSimPinMaxRetryTimes;
+  } else if (lock_type == "SIM PUK") {
+    ss << "+CPINR: SIM PUK," << pin1_status_.puk_remaining_times_ << ","
+                             << kSimPukMaxRetryTimes;
+  } else if (lock_type == "SIM PIN2") {
+    ss << "+CPINR: SIM PIN2," << pin2_status_.pin_remaining_times_ << ","
+                              << kSimPinMaxRetryTimes;
+  } else if (lock_type == "SIM PUK2") {
+    ss << "+CPINR: SIM PUK2," << pin2_status_.puk_remaining_times_ << ","
+            << kSimPukMaxRetryTimes;
+  } else {
+    responses.push_back(kCmeErrorInCorrectParameters);
+    client.SendCommandResponse(responses);
+    return;
+  }
+
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * see
+ *   RIL_REQUEST_CDMA_SET_SUBSCRIPTION or
+ *   RIL_REQUEST_CDMA_GET_SUBSCRIPTION in RIL
+ */
+void SimService::HandleCdmaSubscriptionSource(const Client& client,
+                                              const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  if (*cmd == "AT+CCSS?") {  // Query
+    std::stringstream ss;
+    ss << "+CCSS: " << cdma_subscription_source_;
+    responses.push_back(ss.str());
+  } else { // Set
+    cdma_subscription_source_ = cmd.GetNextInt();
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * see
+ *   RIL_REQUEST_CDMA_SET_ROAMNING_PREFERENCE or
+ *   RIL_REQUEST_CDMA_GET_ROAMNING_PREFERENCE in RIL
+ */
+void SimService::HandleCdmaRoamingPreference(const Client& client,
+                                             const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  if (*cmd == "AT+WRMP?") {  // Query
+    std::stringstream ss;
+    ss << "+WRMP: " << cdma_roaming_preference_;
+    responses.push_back(ss.str());
+  } else { // Set
+    cdma_roaming_preference_ = cmd.GetNextInt();
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+void SimService::HandleSimAuthentication(const Client& client,
+                                             const std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  // Input format: ^MBAU=<RAND>[,<AUTN>]
+  auto cmds = cmd.GetNextStr();
+  // Output format: ^MBAU: <STATUS>[,<KC>,<SRES>][,<CK>,<IK>,<RES/AUTS>]
+  std::stringstream ss;
+
+  // Authentication challenges done in CTS.
+  if (cmds == "2713AB0BA8E8E7D8F1D74545BA03F563") {
+    // CarrierApiTest#testGetIccAuthentication (base64Challenge)
+    ss << "^MBAU: 0,8F2980FC3872FF89,E9620240";
+  } else if (cmds == "C3718EC16B3C2A66F8A7200A64069F04") {
+    // CarrierApiTest#testGetIccAuthentication (base64Challenge2)
+    ss << "^MBAU: 0,CFDA6C980502DA48,F7E53577";
+  } else if (cmds == "11111111111111111111111111111111") {
+    // CarrierApiTest#testEapSimAuthentication
+    ss << "^MBAU: 0,0000000000000000,00000000";
+  } else if (cmds == "11111111111111111111111111111111,12351417161900001130131215141716") {
+    // CarrierApiTest#testEapAkaAuthentication
+    // Note: the "DB" prefix gets appended where the RIL parses this response.
+    ss << "^MBAU: 0,111013121514171619181B1A1D1C1F1E,1013121514171619181B1A1D1C1F1E11,"
+          "13121514171619181B1A1D1C1F1E1110";
+  }
+
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/sim_service.h b/host/commands/modem_simulator/sim_service.h
new file mode 100644
index 0000000..7cccfcb
--- /dev/null
+++ b/host/commands/modem_simulator/sim_service.h
@@ -0,0 +1,271 @@
+//
+// 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 <tinyxml2.h>
+
+#include "host/commands/modem_simulator/modem_service.h"
+
+namespace cuttlefish {
+
+using namespace tinyxml2;
+
+class NetworkService;
+
+class SimService : public ModemService, public std::enable_shared_from_this<SimService> {
+ public:
+  SimService(int32_t service_id, ChannelMonitor* channel_monitor,
+             ThreadLooper* thread_looper);
+  ~SimService() = default;
+
+  SimService(const SimService &) = delete;
+  SimService &operator=(const SimService &) = delete;
+
+  void SetupDependency(NetworkService* net);
+
+  void HandleSIMStatusReq(const Client& client);
+  void HandleChangeOrEnterPIN(const Client& client, const std::string& command);
+  void HandleSIM_IO(const Client& client, const std::string& command);
+  void HandleCSIM_IO(const Client& client, const std::string& command);
+  void HandleGetIMSI(const Client& client);
+  void HandleGetIccId(const Client& client);
+  void HandleFacilityLock(const Client& client, const std::string& command);
+  void HandleOpenLogicalChannel(const Client& client,
+                                const std::string& command);
+  void HandleCloseLogicalChannel(const Client& client,
+                                 const std::string& command);
+  void HandleTransmitLogicalChannel(const Client& client,
+                                    const std::string& command);
+  void HandleChangePassword(const Client& client, const std::string& command);
+  void HandleQueryRemainTimes(const Client& client, const std::string& command);
+  void HandleCdmaSubscriptionSource(const Client& client,
+                                    const std::string& command);
+  void HandleCdmaRoamingPreference(const Client& client,
+                                   const std::string& command);
+  void HandleSimAuthentication(const Client& client,
+                                   const std::string& command);
+
+  void SavePinStateToIccProfile();
+  void SaveFacilityLockToIccProfile();
+  bool IsFDNEnabled();
+  bool IsFixedDialNumber(std::string_view number);
+  XMLElement* GetIccProfile();
+  std::string GetPhoneNumber();
+
+  enum SimStatus {
+    SIM_STATUS_ABSENT = 0,
+    SIM_STATUS_NOT_READY,
+    SIM_STATUS_READY,
+    SIM_STATUS_PIN,
+    SIM_STATUS_PUK,
+  };
+
+  SimStatus GetSimStatus() const;
+  std::string GetSimOperator();
+
+ private:
+  void InitializeServiceState();
+  std::vector<CommandHandler> InitializeCommandHandlers();
+  void InitializeSimFileSystemAndSimState();
+  void InitializeFacilityLock();
+  void OnSimStatusChanged();
+
+  NetworkService* network_service_;
+
+  /* SimStatus */
+  SimStatus sim_status_;
+
+  /* SimFileSystem */
+  struct SimFileSystem {
+    enum EFId: int32_t {
+      EF_ADN = 0x6F3A,
+      EF_FDN = 0x6F3B,
+      EF_GID1 = 0x6F3E,
+      EF_GID2 = 0x6F3F,
+      EF_SDN = 0x6F49,
+      EF_EXT1 = 0x6F4A,
+      EF_EXT2 = 0x6F4B,
+      EF_EXT3 = 0x6F4C,
+      EF_EXT5 = 0x6F4E,
+      EF_EXT6 = 0x6FC8,   // Ext record for EF[MBDN]
+      EF_MWIS = 0x6FCA,
+      EF_MBDN = 0x6FC7,
+      EF_PNN = 0x6FC5,
+      EF_OPL = 0x6FC6,
+      EF_SPN = 0x6F46,
+      EF_SMS = 0x6F3C,
+      EF_ICCID = 0x2FE2,
+      EF_AD = 0x6FAD,
+      EF_MBI = 0x6FC9,
+      EF_MSISDN = 0x6F40,
+      EF_SPDI = 0x6FCD,
+      EF_SST = 0x6F38,
+      EF_CFIS = 0x6FCB,
+      EF_IMG = 0x4F20,
+
+      // USIM SIM file ids from TS 131.102
+      EF_PBR = 0x4F30,
+      EF_LI = 0x6F05,
+
+      // GSM SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6
+      EF_MAILBOX_CPHS = 0x6F17,
+      EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11,
+      EF_CFF_CPHS = 0x6F13,
+      EF_SPN_CPHS = 0x6F14,
+      EF_SPN_SHORT_CPHS = 0x6F18,
+      EF_INFO_CPHS = 0x6F16,
+      EF_CSP_CPHS = 0x6F15,
+
+      // CDMA RUIM file ids from 3GPP2 C.S0023-0
+      EF_CST = 0x6F32,
+      EF_RUIM_SPN =0x6F41,
+
+      // ETSI TS.102.221
+      EF_PL = 0x2F05,
+      // 3GPP2 C.S0065
+      EF_CSIM_LI = 0x6F3A,
+      EF_CSIM_SPN =0x6F41,
+      EF_CSIM_MDN = 0x6F44,
+      EF_CSIM_IMSIM = 0x6F22,
+      EF_CSIM_CDMAHOME = 0x6F28,
+      EF_CSIM_EPRL = 0x6F5A,
+      EF_CSIM_MIPUPP = 0x6F4D,
+
+      //ISIM access
+      EF_IMPU = 0x6F04,
+      EF_IMPI = 0x6F02,
+      EF_DOMAIN = 0x6F03,
+      EF_IST = 0x6F07,
+      EF_PCSCF = 0x6F09,
+      EF_PSI = 0x6FE5,
+
+      //PLMN Selection Information w/ Access Technology TS 131.102
+      EF_PLMN_W_ACT = 0x6F60,
+      EF_OPLMN_W_ACT = 0x6F61,
+      EF_HPLMN_W_ACT = 0x6F62,
+
+      //Equivalent Home and Forbidden PLMN Lists TS 131.102
+      EF_EHPLMN = 0x6FD9,
+      EF_FPLMN = 0x6F7B,
+
+      // Last Roaming Selection Indicator
+      EF_LRPLMNSI = 0x6FDC,
+
+      //Search interval for higher priority PLMNs
+      EF_HPPLMN = 0x6F31,
+    };
+
+    XMLElement* GetRootElement();
+
+    static std::string GetCommonIccEFPath(EFId efid);
+    static std::string GetUsimEFPath(EFId efid);
+
+    static XMLElement *FindAttribute(XMLElement* parent,
+                                     const std::string& attr_name,
+                                     const std::string& attr_value);
+
+    XMLElement* AppendNewElement(XMLElement* parent, const char* name);
+    XMLElement* AppendNewElementWithText(XMLElement* parent, const char* name,
+                                         const char* text);
+
+    XMLDocument doc;
+    std::string file_path;
+  };
+  SimFileSystem sim_file_system_;
+
+
+  /* PinStatus */
+  struct PinStatus {
+    enum ChangeMode {WITH_PIN, WITH_PUK};
+
+    std::string pin_;
+    std::string puk_;
+    int pin_remaining_times_;
+    int puk_remaining_times_;
+
+    bool CheckPasswordValid(std::string_view password);
+
+    bool VerifyPIN(const std::string_view pin);
+    bool VerifyPUK(const std::string_view puk);
+    bool ChangePIN(ChangeMode mode, const std::string_view pin_or_puk,
+                   const std::string_view new_pin);
+    bool ChangePUK(const std::string_view puk, const std::string_view new_puk);
+  };
+  PinStatus pin1_status_;
+  PinStatus pin2_status_;
+
+  bool checkPin1AndAdjustSimStatus(std::string_view password);
+  bool ChangePin1AndAdjustSimStatus(PinStatus::ChangeMode mode,
+                                    std::string_view pin,
+                                    std::string_view new_pin);
+
+  /*  FacilityLock */
+  struct FacilityLock {
+    enum LockType {
+      AO = 1,  // Barr all outgoing calls
+      OI = 2,  // Barr all outgoing international calls
+      OX = 3,  // Barr all outgoing international calls, except to Home Country
+      AI = 4,  // Barr all incoming calls
+      IR = 5,  // Barr all call, when roaming outside Home Country
+      AB = 6,  // All barring services
+      AG = 7,  // All outgoing barring services
+      AC = 8,  // All incoming barring services
+      SC = 9,  // PIN enable/disable
+      FD = 10,  // SIM fixed FDN dialing lock, PIN2 is required as a password
+    };
+
+    enum Mode {
+      UNLOCK = 0,
+      LOCK = 1,
+      QUERY = 2,
+    };
+
+    enum Class : int32_t {
+      DEFAULT = 7,      // all classes
+      VOICE = 1 << 0,   // telephony
+      DATA = 1 << 1,    // to all bear service
+      FAX = 1 << 2,     // facsimile services
+      SMS = 1 << 3,     // short message services
+    };
+
+    enum LockStatus {
+      DISABLE,
+      ENABLE,
+    };
+
+    LockStatus lock_status;  // Ignore class
+
+    FacilityLock(LockStatus status) : lock_status(status) {}
+  };
+  std::map<std::string, FacilityLock> facility_lock_;
+
+  /* LogicalChannel */
+  struct LogicalChannel {
+    std::string df_name;
+    bool is_open;
+    int session_id;
+
+    LogicalChannel(int session_id) :
+      df_name(""), is_open(false), session_id(session_id) {};
+  };
+  std::vector<LogicalChannel> logical_channels_;
+  std::string last_file_id_;
+
+  int cdma_subscription_source_;
+  int cdma_roaming_preference_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/sms_service.cpp b/host/commands/modem_simulator/sms_service.cpp
new file mode 100644
index 0000000..0da21a6
--- /dev/null
+++ b/host/commands/modem_simulator/sms_service.cpp
@@ -0,0 +1,390 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/sms_service.h"
+
+#include <android-base/logging.h>
+
+#include "host/commands/modem_simulator/pdu_parser.h"
+
+namespace cuttlefish {
+
+SmsService::SmsService(int32_t service_id, ChannelMonitor* channel_monitor,
+                       ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {
+  InitializeServiceState();
+}
+
+std::vector<CommandHandler> SmsService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      CommandHandler("+CMGS",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSendSMS(client, cmd);
+                     }),
+      CommandHandler("+CNMA",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSMSAcknowledge(client, cmd);
+                     }),
+      CommandHandler("+CMGW",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleWriteSMSToSim(client, cmd);
+                     }),
+      CommandHandler("+CMGD",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleDeleteSmsOnSim(client, cmd);
+                     }),
+      CommandHandler("+CSCB",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleBroadcastConfig(client, cmd);
+                     }),
+      CommandHandler(
+          "+CSCA?",
+          [this](const Client& client) { this->HandleGetSmscAddress(client); }),
+      CommandHandler("+CSCA=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSetSmscAddress(client, cmd);
+                     }),
+      CommandHandler("+REMOTESMS",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleReceiveRemoteSMS(client, cmd);
+                     }),
+  };
+  return (command_handlers);
+}
+
+void SmsService::InitializeServiceState() {
+  is_waiting_sms_pdu_ = false;
+  is_waiting_sms_to_sim_ = false;
+  message_id_ = 1;
+  message_reference_ = 1;
+
+  broadcast_config_ = {0, "", ""};
+}
+
+void SmsService::SetupDependency(SimService* sim) { sim_service_ = sim; }
+
+/**
+ * AT+CMGS
+ *   This command sends message from a TE to the network (SMS-SUBMIT).
+ *
+ * Command                            Possible response(s)
+ * +CMGS=<length><CR>                  "> "
+ * PDU is given<ctrl-Z/ESC>            +CMGS: <mr>[,<ackpdu>]<CR>OK
+ *                                     +CMS ERROR: <err>
+ *
+ * <length>:must indicate the number of octets coded in the TP
+ *          layer data unit to be given.
+ *
+ * see RIL_REQUEST_SEND_SMS in RIL
+ */
+void SmsService::HandleSendSMS(const Client& client, std::string& /*command*/) {
+  is_waiting_sms_pdu_ = true;
+
+  std::vector<std::string> responses;
+  responses.push_back("> ");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CNMA
+ *   This command confirms reception of a new message (SMS-DELIVER or
+ * SMS-STATUS-REPORT) which is routed directly to the TE.
+ *
+ * Command                            Possible response(s)
+ * +CNMA [=<n>[, <length> [<CR>        OK
+ * PDU is given<ctrl-Z/ESC>]]]         +CMS ERROR: <err>
+ *
+ * <n>: integer type
+ *   0: command operates similarly as defined for the text mode
+ *   1: send RP-ACK
+ *   2: send RP-ERROR
+ * <length>: ACKPDU length(octet)
+ *
+ * see RIL_REQUEST_SMS_ACKNOWLEDGE in RIL
+ */
+void SmsService::HandleSMSAcknowledge(const Client& client, std::string& /*command*/) {
+  client.SendCommandResponse("OK");
+}
+
+/*
+ * AT+CMGW
+ *   This command stores message (either SMS-DELIVER or SMS-SUBMIT)
+ * to memory storage <mem2>.
+ *
+ * Command                            Possible response(s)
+ * +CMGW=<length>[,<stat>]<CR>         "> "
+ * PDU is given <ctrl-Z/ESC>           +CMGW: <index>
+ *                                     +CMS ERROR: <err>
+ * <length>: the length of TPDU(bit) with a range of 9-160
+ * < stat >: integer:
+ *        0: Unread Message. (MT)
+ *        1: Read Message. (MT)
+ *        2: Unsent Message. (MO)
+ *        3: Sent Message. (MO)
+ * < index>: index id of <mem2>
+ *
+ * see RIL_REQUEST_WRITE_SMS_TO_SIM in RIL
+ */
+void SmsService::HandleWriteSMSToSim(const Client& client, std::string& command) {
+  is_waiting_sms_to_sim_ = true;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip "AT+CMGW="
+  cmd.SkipComma();
+  sms_status_on_sim_ = (SmsMessage::SmsStatus)cmd.GetNextInt();
+  client.SendCommandResponse("> ");
+}
+
+/**
+ * AT+CMGD
+ *   This command deletes message from preferred message storage <mem1>
+ * location <index>.
+ *
+ * Command                            Possible response(s)
+ * +CMGD=<index>[, <DelFlag>]          OK
+ *                                     +CMS ERROR: <err>
+ * < index>: index id of <mem2>
+ *
+ * see RIL_REQUEST_DELETE_SMS_ON_SIM in RIL
+ */
+void SmsService::HandleDeleteSmsOnSim(const Client& client, std::string& command) {
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip "AT+CMGD="
+
+  int index = cmd.GetNextInt();
+  auto iter = messages_on_sim_card_.find(index);
+  if (iter == messages_on_sim_card_.end()) {
+    client.SendCommandResponse(kCmeErrorInvalidIndex);  // No such message
+    return;
+  }
+
+  messages_on_sim_card_.erase(iter);
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * AT+CSCB
+ *   Set command selects which types of CBMs are to be received by the ME.
+ *
+ * Command                            Possible response(s)
+ * +CSCB=[<mode>[,<mids>[,<dcss>]]]    OK
+ * +CSCB?                              +CSCB: <mode>,<mids>,<dcss>
+ *
+ * <mode>:
+ *      0: message types specified in <mids> and <dcss> are accepted
+ *      1: message types specified in <mids> and <dcss> are not accepted
+ * <mids>: string type; all different possible combinations of CBM message
+ *         identifiers (refer <mid>).
+ * <dcss>: string type; all different possible combinations of CBM data coding
+ *         schemes.
+ *
+ * see RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG &
+ *     RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG in RIL
+ * Notes: This command is allowed in TEXT mode.
+ */
+void SmsService::HandleBroadcastConfig(const Client& client, std::string& command) {
+  std::vector<std::string> responses;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  if (*cmd == "AT+CSCB?") {  // Query
+    std::stringstream ss;
+    ss << "+CSCB: " << broadcast_config_.mode << ","
+                    << broadcast_config_.mids << ","
+                    << broadcast_config_.dcss;
+    responses.push_back(ss.str());
+  } else {  // Set
+    broadcast_config_.mode = cmd.GetNextInt();
+    broadcast_config_.mids = cmd.GetNextStr();
+    broadcast_config_.dcss = cmd.GetNextStr();
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CSCA
+ *   Set command updates the SMSC address, through which mobile originated
+ * SMs are transmitted.
+ *
+ * Command                            Possible response(s)
+ * +CSCA=<sca>[,<tosca>]               OK
+ * +CSCA?                              +CSCA: <sca>,<tosca>
+ *
+ * <sca>: service center address, its maximum length is 20.
+ * <tosca>: service center address format,protocol uses 8-bit address integer.
+ *
+ * see RIL_REQUEST_SET_SMSC_ADDRESS in RIL
+ */
+void SmsService::HandleGetSmscAddress(const Client& client) {
+  std::vector<std::string> responses;
+
+  std::stringstream ss;
+  ss << "+CSCA: " << sms_service_center_address_.sca << ","
+                  << sms_service_center_address_.tosca;
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+void SmsService::HandleSetSmscAddress(const Client& client, std::string& command) {
+  CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip "AT+CSCA="
+
+  sms_service_center_address_.sca = cmd.GetNextStr();
+  sms_service_center_address_.tosca = cmd.GetNextInt();
+
+  client.SendCommandResponse("OK");
+}
+
+void SmsService::SendSmsToRemote(std::string remote_port, PDUParser& sms_pdu) {
+  auto remote_client = ConnectToRemoteCvd(remote_port);
+  if (!remote_client->IsOpen()) {
+    return;
+  }
+
+  auto local_host_port = GetHostPort();
+  auto pdu = sms_pdu.CreateRemotePDU(local_host_port);
+
+  std::string command = "AT+REMOTESMS=" + pdu + "\r";
+  std::string token = "REM0";
+  remote_client->Write(token.data(), token.size());
+  remote_client->Write(command.data(), command.size());
+}
+
+/* process AT+CMGS PDU */
+void SmsService::HandleSendSMSPDU(const Client& client, std::string& command) {
+  is_waiting_sms_pdu_ = false;
+
+  std::vector<std::string> responses;
+  PDUParser sms_pdu(command);
+  if (!sms_pdu.IsValidPDU()) {
+    /* Invalid PDU mode parameter */
+    client.SendCommandResponse(kCmsErrorInvalidPDUModeParam);
+    return;
+  }
+
+  std::string phone_number = sms_pdu.GetPhoneNumberFromAddress();
+
+  int port = 0;
+  if (phone_number.length() == 11) {
+    port = std::stoi(phone_number.substr(7));
+  } else if (phone_number.length() == 4) {
+    port = std::stoi(phone_number);
+  }
+
+  if (phone_number == "") {  /* Phone number unknown */
+    LOG(ERROR) << "Failed to get phone number form address";
+    client.SendCommandResponse(kCmsErrorSCAddressUnknown);
+    return;
+  } else if (port >= kRemotePortRange.first &&
+             port <= kRemotePortRange.second) {
+    std::stringstream ss;
+    ss << port;
+    auto remote_host_port = ss.str();
+    if (GetHostPort() == remote_host_port) {  // Send SMS to local host port
+      thread_looper_->PostWithDelay(
+          std::chrono::seconds(1),
+          makeSafeCallback<SmsService>(this, [&sms_pdu](SmsService* me) {
+            me->HandleReceiveSMS(sms_pdu);
+          }));
+    } else {  // Send SMS to remote host port
+      SendSmsToRemote(remote_host_port, sms_pdu);
+    }
+  } else if (sim_service_ && phone_number == sim_service_->GetPhoneNumber()) {
+    /* Local phone number */
+    thread_looper_->PostWithDelay(
+        std::chrono::seconds(1),
+        makeSafeCallback<SmsService>(this, [sms_pdu](SmsService* me) {
+          me->HandleReceiveSMS(sms_pdu);
+        }));
+  } /* else pretend send SMS success */
+
+  std::stringstream ss;
+  ss << "+CMGS: " << ++message_reference_;
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+
+  if (sms_pdu.IsNeededStatuReport()) {
+    int ref = message_reference_;
+    thread_looper_->PostWithDelay(
+        std::chrono::seconds(1),
+        makeSafeCallback<SmsService>(this, [sms_pdu, ref](SmsService* me) {
+          me->HandleSMSStatuReport(sms_pdu, ref);
+        }));
+  }
+}
+
+/* AT+CMGS callback function */
+void SmsService::HandleReceiveSMS(PDUParser sms_pdu) {
+  std::string pdu = sms_pdu.CreatePDU();
+  if (pdu != "") {
+    SendUnsolicitedCommand("+CMT: 0");
+    SendUnsolicitedCommand(pdu);
+  }
+}
+
+/* Process AT+CMGW PDU */
+void SmsService::HandleWriteSMSPduToSim(const Client& client, std::string& command) {
+  is_waiting_sms_to_sim_ = false;
+
+  SmsMessage message;
+  message.status = sms_status_on_sim_;
+  message.message = command;
+  int index = message_id_++;
+  messages_on_sim_card_[index] = message;
+
+  std::vector<std::string> responses;
+  std::stringstream ss;
+  ss << "+CMGW: " << index;
+  responses.push_back(ss.str());
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/* SMS Status Report */
+void SmsService::HandleSMSStatuReport(PDUParser sms_pdu, int message_reference) {
+  std::string response;
+  std::stringstream ss;
+
+  auto pdu = sms_pdu.CreateStatuReport(message_reference);
+  auto pdu_length = (pdu.size() - 2) / 2;  // Not Including SMSC Address
+  if (pdu != "" && pdu_length > 0) {
+    ss << "+CDS: " << pdu_length;
+    SendUnsolicitedCommand(ss.str());
+    SendUnsolicitedCommand(pdu);
+  }
+}
+
+/* AT+REMOTESMS=PDU */
+void SmsService::HandleReceiveRemoteSMS(const Client& /*client*/, std::string& command) {
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  std::string pdu(*cmd);
+  PDUParser sms_pdu(pdu);
+  if (!sms_pdu.IsValidPDU()) {
+    LOG(ERROR) << "Failed to decode PDU";
+    return;
+  }
+  pdu = sms_pdu.CreatePDU();
+  if (pdu != "") {
+    SendUnsolicitedCommand("+CMT: 0");
+    SendUnsolicitedCommand(pdu);
+  }
+}
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/sms_service.h b/host/commands/modem_simulator/sms_service.h
new file mode 100644
index 0000000..6602553
--- /dev/null
+++ b/host/commands/modem_simulator/sms_service.h
@@ -0,0 +1,89 @@
+//
+// 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 "host/commands/modem_simulator/modem_service.h"
+#include "host/commands/modem_simulator/pdu_parser.h"
+#include "host/commands/modem_simulator/sim_service.h"
+
+namespace cuttlefish {
+
+class SmsService : public ModemService , public std::enable_shared_from_this<SmsService> {
+ public:
+  SmsService(int32_t service_id, ChannelMonitor* channel_monitor,
+             ThreadLooper* thread_looper);
+  ~SmsService() = default;
+
+  SmsService(const SmsService &) = delete;
+  SmsService &operator=(const SmsService &) = delete;
+
+  void SetupDependency(SimService* sim);
+
+  void HandleSendSMS(const Client& client, std::string& command);
+  void HandleSendSMSPDU(const Client& client, std::string& command);
+  void HandleSMSAcknowledge(const Client& client, std::string& command);
+  void HandleWriteSMSToSim(const Client& client, std::string& command);
+  void HandleDeleteSmsOnSim(const Client& client, std::string& command);
+  void HandleBroadcastConfig(const Client& client, std::string& command);
+  void HandleGetSmscAddress(const Client& client);
+  void HandleSetSmscAddress(const Client& client, std::string& command);
+  void HandleWriteSMSPduToSim(const Client& client, std::string& command);
+  void HandleReceiveRemoteSMS(const Client& client, std::string& command);
+
+  bool IsWaitingSmsPdu() { return is_waiting_sms_pdu_; }
+  bool IsWaitingSmsToSim() { return is_waiting_sms_to_sim_; }
+
+ private:
+  void InitializeServiceState();
+  std::vector<CommandHandler> InitializeCommandHandlers();
+
+  void HandleReceiveSMS(PDUParser sms_pdu);
+  void HandleSMSStatuReport(PDUParser sms_pdu, int message_reference);
+  void SendSmsToRemote(std::string remote_port, PDUParser& sms_pdu);
+
+  SimService* sim_service_;
+
+  struct SmsMessage {
+    enum SmsStatus { kUnread = 0, kRead = 1, kUnsent = 2, kSent = 3 };
+
+    std::string message;
+    SmsStatus status;
+  };
+
+  struct BroadcastConfig {
+    int mode;
+    std::string mids;
+    std::string dcss;
+  };
+
+  struct SmsServiceCenterAddress {
+    std::string sca;
+    int tosca;
+  };
+
+  bool is_waiting_sms_pdu_;
+  bool is_waiting_sms_to_sim_;
+  int message_id_;
+  int message_reference_;
+  SmsMessage::SmsStatus sms_status_on_sim_;
+
+  BroadcastConfig broadcast_config_;
+  SmsServiceCenterAddress sms_service_center_address_;
+
+  std::map<int, SmsMessage> messages_on_sim_card_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/stk_service.cpp b/host/commands/modem_simulator/stk_service.cpp
new file mode 100644
index 0000000..6002c6d
--- /dev/null
+++ b/host/commands/modem_simulator/stk_service.cpp
@@ -0,0 +1,284 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/stk_service.h"
+
+#include <android-base/logging.h>
+namespace cuttlefish {
+
+StkService::StkService(int32_t service_id, ChannelMonitor* channel_monitor,
+                       ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {}
+
+std::vector<CommandHandler> StkService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      CommandHandler("+CUSATD?",
+                     [this](const Client& client) {
+                       this->HandleReportStkServiceIsRunning(client);
+                     }),
+      CommandHandler("+CUSATE=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSendEnvelope(client, cmd);
+                     }),
+      CommandHandler("+CUSATT=",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSendTerminalResponseToSim(client, cmd);
+                     }),
+  };
+  return (command_handlers);
+}
+
+void StkService::SetupDependency(SimService* sim) { sim_service_ = sim; }
+
+/**
+ * AT+CUSATD
+ *   This command determines if, and optionally which profile should be downloaded
+ * to the UICC automatically upon start-up.
+ *
+ * Command                             Possible response(s)
+ * +CUSATD=[<download>[,<reporting>]]  +CME ERROR: <err>
+ * +CUSATD?                            +CUSATD: <download>,<reporting>
+ *
+ * <download>: integer type.
+ *   0   Download MT default profile automatically during next start-up.
+ *   1   Download the combined TE and MT profile
+ *   2   Halt next UICC start-up when ready for profile download.
+ * <reporting>: integer type.
+ *   0   Disable +CUSATS, i.e. no notification.
+ *   1   Enable +CUSATS, i.e. notify TE.
+ *
+ * see RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING in RIL
+ */
+void StkService::HandleReportStkServiceIsRunning(const Client& client) {
+  std::vector<std::string> response = {{"+CUSATD: 0,1"}, {"OK"}};
+  client.SendCommandResponse(response);
+
+  if (!sim_service_) return;
+
+  XMLElement *root = sim_service_->GetIccProfile();
+  if (!root) return;
+
+  XMLElement *setup_menu = root->FirstChildElement("SETUPMENU");
+  auto text = setup_menu->FindAttribute("text");
+
+  std::string unsol_command = "+CUSATP:";
+  unsol_command += text ? text->Value() : "";
+  SendUnsolicitedCommand(unsol_command);
+}
+
+/**
+ * AT+CUSATE
+ *   Execution command allows the TE to send a USAT envelope command to the MT
+ *
+ * Command                      Possible response(s)
+ * +CUSATE=<envelope_command>   +CUSATE: <envelope_response>[,<busy>]
+ *                              [<CR><LF>+CUSATE2: <sw1>,<sw2>]
+ *                              +CME ERROR: <err>
+ *
+ * <envelope_command>: string type in hexadecimal character format.
+ * <envelope_response>: string type in hexadecimal character format.
+ * <busy>: integer type.
+ *   0   UICC indicated normal ending of the command.
+ *   1   UICC responded with USAT is busy, no retry by the MT.
+ *   2   UICC responded with USAT is busy even after one or more retries by the MT.
+ * <sw1>: integer type.
+ * <sw2>: integer type.
+ *
+ * see RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND in RIL
+ */
+void StkService::HandleSendEnvelope(const Client& client , std::string& command) {
+  std::vector<std::string> response = {{"+CUSATE: 0"}, {"OK"}};
+  client.SendCommandResponse(response);
+
+  if (!sim_service_) return;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  auto data = cmd.GetNextStr();
+  std::string menu_id(data.substr(data.size() - 2));  // get the last two char
+
+  XMLElement *root = sim_service_->GetIccProfile();
+  if (!root) return;
+
+  XMLElement *setup_menu = root->FirstChildElement("SETUPMENU");
+  if (!setup_menu) return;
+
+  auto select_item = setup_menu->FirstChildElement("SELECTITEM");
+  while (select_item) {
+    auto menu_id_attr = select_item->FindAttribute("menuId");
+    if (menu_id_attr && menu_id_attr->Value() == menu_id) {
+      break;
+    }
+    select_item = select_item->NextSiblingElement("SELECTITEM");
+  }
+  if (!select_item) {
+    LOG(ERROR) << "Not found menu id: " << menu_id;
+    return;
+  }
+
+  auto select_item_cmd = select_item->FindAttribute("cmd");
+  if (select_item_cmd) {
+    std::string cmd_str = select_item_cmd->Value();
+    if (cmd_str == "24") {  // SELECT_ITEM
+      current_select_item_menu_ids_.push_back(menu_id);
+    }
+  }
+
+  std::string unsol_command = "+CUSATP:";
+  auto text = select_item->FindAttribute("text");
+  std::string text_value = text ? text->Value() : "";
+  unsol_command.append(text_value);
+  SendUnsolicitedCommand(unsol_command);
+}
+
+/**
+ * AT+CUSATT
+ *   Execution command sends a USAT terminal response to the MT as an answer to
+ * a preceding USAT proactive command sent from the UICC with unsolicited result
+ * code +CUSATP: <proactive_command>
+ *
+ * Command                        Possible response(s)
+ * +CUSATT=<terminal_response>    +CME ERROR: <err>
+ *
+ * <terminal_response>: string type in hexadecimal character format.
+ *
+ * see RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE in RIL
+ */
+void StkService::HandleSendTerminalResponseToSim(const Client& client, std::string& command) {
+  std::vector<std::string> response = {{"+CUSATT: 0"}, {"OK"}};
+  client.SendCommandResponse(response);
+
+  OnUnsolicitedCommandForTR(command);
+}
+
+XMLElement* StkService::GetCurrentSelectItem() {
+  if (!sim_service_) return nullptr;
+
+  XMLElement *root = sim_service_->GetIccProfile();
+  if (!root) {
+    current_select_item_menu_ids_.clear();
+    return nullptr;
+  }
+
+  XMLElement *menu = root->FirstChildElement("SETUPMENU");
+  if (!menu) {
+    current_select_item_menu_ids_.clear();
+    return nullptr;
+  }
+
+  /**
+   * e.g. current_select_item_menu_ids_: {"1", "02"}
+   * <SELECTITEM id="1">
+   *   <SELECTITEM id="01">
+   *   </SELECTITEM>
+   *   <SELECTITEM id="02">
+   *   </SELECTITEM>
+   * </SELECTITEM>
+   */
+  XMLElement* select_item = nullptr;
+  auto iter = current_select_item_menu_ids_.begin();
+  for (; iter != current_select_item_menu_ids_.end(); ++iter) {
+    select_item = menu->FirstChildElement("SELECTITEM");
+    while (select_item) {
+      auto menu_id_attr = select_item->FindAttribute("menuId");
+      if (menu_id_attr && menu_id_attr->Value() == *iter) {
+        auto menu_id_str = menu_id_attr->Value();
+        if (menu_id_str == *iter) break;
+      }
+      select_item = select_item->NextSiblingElement("SELECTITEM");
+    }
+    if (!select_item) break;
+    menu = select_item;
+  }
+
+  return select_item;
+}
+
+void StkService::OnUnsolicitedCommandForTR(std::string& command) {
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  auto data = cmd.GetNextStr();
+  auto menu_id = data.substr(data.size() - 2);
+
+  // '10': UICC_SESSION_TERM_BY_USER
+  // '12': NO_RESPONSE_FROM_USER
+  if (menu_id == "10" || menu_id == "12") {
+    current_select_item_menu_ids_.clear();
+    SendUnsolicitedCommand("+CUSATEND");
+    return;
+  }
+
+  XMLElement *select_item = GetCurrentSelectItem();
+  if (!select_item) {
+    current_select_item_menu_ids_.clear();
+    SendUnsolicitedCommand("+CUSATEND");
+    return;
+  }
+
+  if (menu_id == "11") {  // BACKWARD_MOVE_BY_USER
+    current_select_item_menu_ids_.pop_back();
+    if (current_select_item_menu_ids_.size() >= 1) {
+      select_item = GetCurrentSelectItem();
+      auto text = select_item->FindAttribute("text");
+      if (text) {
+        std::string unsol_command = "+CUSATP: ";
+        unsol_command += text->Value();
+        SendUnsolicitedCommand(unsol_command);
+      }
+    } else {
+      SendUnsolicitedCommand("+CUSATEND");
+    }
+    return;
+  } else if (menu_id == "00") {  // OK
+    auto text = select_item->FindAttribute("text");
+    if (text) {
+      std::string unsol_command = "+CUSATP: ";
+      unsol_command += text->Value();
+      SendUnsolicitedCommand(unsol_command);
+    }
+    return;
+  }
+
+  auto final = select_item->FirstChildElement();
+  while (final) {
+    auto attr = final->FindAttribute("menuId");
+    if (attr && attr->Value() == menu_id) {
+      std::string attr_value = attr->Value();
+      if (attr_value == menu_id) break;
+    }
+    final = final->NextSiblingElement();
+  }
+  if (!final) {
+    current_select_item_menu_ids_.clear();
+    SendUnsolicitedCommand("+CUSATEND");
+    return;
+  }
+
+  auto cmd_attr = final->FindAttribute("cmd");
+  if (cmd_attr) {
+    std::string cmd_attr_str = cmd_attr->Value();
+    if (cmd_attr_str == "24") {
+      std::string menu_id_str(menu_id);
+      current_select_item_menu_ids_.push_back(menu_id_str);
+    }
+  }
+  auto text = final->FindAttribute("text");
+  std::string unsol_command = "+CUSATP:";
+  unsol_command += text ? text->Value() : "";
+  SendUnsolicitedCommand(unsol_command);
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/stk_service.h b/host/commands/modem_simulator/stk_service.h
new file mode 100644
index 0000000..225fbc1
--- /dev/null
+++ b/host/commands/modem_simulator/stk_service.h
@@ -0,0 +1,76 @@
+//
+// 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 "host/commands/modem_simulator/modem_service.h"
+#include "host/commands/modem_simulator/sim_service.h"
+
+namespace cuttlefish {
+
+class StkService : public ModemService, public std::enable_shared_from_this<StkService> {
+ public:
+  StkService(int32_t service_id, ChannelMonitor* channel_monitor,
+             ThreadLooper* thread_looper);
+  ~StkService() = default;
+
+  StkService(const StkService &) = delete;
+  StkService &operator=(const StkService &) = delete;
+
+  void SetupDependency(SimService* sim);
+
+  void HandleReportStkServiceIsRunning(const Client& client);
+  void HandleSendEnvelope(const Client& client, std::string& command);
+  void HandleSendTerminalResponseToSim(const Client& client, std::string& command);
+
+ private:
+  std::vector<CommandHandler> InitializeCommandHandlers();
+
+  SimService* sim_service_;
+
+  // For now, only support DISPLAY_TEXT, SELECT_ITEM and SETUP_MENU
+  enum CommandType {
+    DISPLAY_TEXT        = 0x21,
+    GET_INKEY           = 0x22,
+    GET_INPUT           = 0x23,
+    LAUNCH_BROWSER      = 0x15,
+    PLAY_TONE           = 0x20,
+    REFRESH             = 0x01,
+    SELECT_ITEM         = 0x24,
+    SEND_SS             = 0x11,
+    SEND_USSD           = 0x12,
+    SEND_SMS            = 0x13,
+    RUN_AT              = 0x34,
+    SEND_DTMF           = 0x14,
+    SET_UP_EVENT_LIST   = 0x05,
+    SET_UP_IDLE_MODE_TEXT = 0x28,
+    SET_UP_MENU         = 0x25,
+    SET_UP_CALL         = 0x10,
+    PROVIDE_LOCAL_INFORMATION = 0x26,
+    LANGUAGE_NOTIFICATION = 0x35,
+    OPEN_CHANNEL        = 0x40,
+    CLOSE_CHANNEL       = 0x41,
+    RECEIVE_DATA        = 0x42,
+    SEND_DATA           = 0x43,
+    GET_CHANNEL_STATUS  = 0x44
+  };
+
+  std::vector<std::string> current_select_item_menu_ids_;
+
+  XMLElement* GetCurrentSelectItem();
+  void OnUnsolicitedCommandForTR(std::string& command);
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/sup_service.cpp b/host/commands/modem_simulator/sup_service.cpp
new file mode 100644
index 0000000..eb5de18
--- /dev/null
+++ b/host/commands/modem_simulator/sup_service.cpp
@@ -0,0 +1,320 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/sup_service.h"
+
+namespace cuttlefish {
+
+SupService::SupService(int32_t service_id, ChannelMonitor* channel_monitor,
+                       ThreadLooper* thread_looper)
+    : ModemService(service_id, this->InitializeCommandHandlers(),
+                   channel_monitor, thread_looper) {
+  InitializeServiceState();
+}
+
+std::vector<CommandHandler> SupService::InitializeCommandHandlers() {
+  std::vector<CommandHandler> command_handlers = {
+      CommandHandler("+CUSD",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleUSSD(client, cmd);
+                     }),
+      CommandHandler("+CLIR",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleCLIR(client, cmd);
+                     }),
+      CommandHandler("+CCWA",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleCallWaiting(client, cmd);
+                     }),
+      CommandHandler(
+          "+CLIP?", [this](const Client& client) { this->HandleCLIP(client); }),
+      CommandHandler("+CCFCU",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleCallForward(client, cmd);
+                     }),
+      CommandHandler("+CSSN",
+                     [this](const Client& client, std::string& cmd) {
+                       this->HandleSuppServiceNotifications(client, cmd);
+                     }),
+  };
+  return (command_handlers);
+}
+
+void SupService::InitializeServiceState() {
+  call_forward_infos_ = {
+    CallForwardInfo(CallForwardInfo::Reason::CFU),
+    CallForwardInfo(CallForwardInfo::Reason::CFB),
+    CallForwardInfo(CallForwardInfo::Reason::CFNR),
+    CallForwardInfo(CallForwardInfo::Reason::CFNRC)
+  };
+}
+
+/**
+ * AT+CUSD
+ *   This command allows control of the Unstructured Supplementary Service Data (USSD)
+ * according to 3GPP TS 22.090 [23], 3GPP TS 24.090 [148] and 3GPP TS 24.390 [131].
+ * Both network and mobile initiated operations are supported.
+ *
+ * Command                        Possible response(s)
+ * +CUSD=[<n>[,<str>[,<dcs>]]]      +CME ERROR: <err>
+ * +CUSD?                           +CUSD: <n>
+ *
+ * <n>: integer type (sets/shows the result code presentation status to the TE).
+ *   0 disable the result code presentation to the TE
+ *   1 enable the result code presentation to the TE
+ *   2 cancel session (not applicable to read command response)
+ * <str>: string type USSD string
+ *   when <str> parameter is not given, network is not interrogated
+ * <dcs>: integer type (shows Cell Broadcast Data Coding Scheme, see 3GPP TS 23.038 [25]).
+ *   Default value is 0.
+ *
+ * see RIL_REQUEST_SEND_USSD or RIL_REQUEST_CANCEL_USSD in RIL
+ */
+void SupService::HandleUSSD(const Client& client, std::string& /*command*/) {
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * AT+CLIR
+ *   This command refers to CLIR‑service according to 3GPP TS 22.081 that allows
+ * a calling subscriber to enable or disable the presentation of the CLI to the
+ * called party when originating a call.
+ *
+ * Command                        Possible response(s)
+ * +CLIR: <n>
+ * +CLIR?                         +CLIR: <n>,<m>
+ *
+ * <n>: integer type (parameter sets the adjustment for outgoing calls).
+ *   0 presentation indicator is used according to the subscription of the CLIR service
+ *   1 CLIR invocation
+ *   2 CLIR suppression
+ * <m>: integer type (parameter shows the subscriber CLIR / OIR service status in the network).
+ *   0 CLIR / OIR not provisioned
+ *   1 CLIR / OIR provisioned in permanent mode
+ *   2 unknown (e.g. no network, etc.)
+ *   3 CLIR / OIR temporary mode presentation restricted
+ *   4 CLIR / OIR temporary mode presentation allowed
+ *
+ * see RIL_REQUEST_SET_CLIR or RIL_REQUEST_GET_CLIR in RIL
+ */
+void SupService::HandleCLIR(const Client& client, std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  if (*cmd == "AT+CLIR?") {
+    ss << "+CLIR:" << clir_status_.type << "," << clir_status_.status;
+    responses.push_back(ss.str());
+  } else {
+    clir_status_.type = (ClirStatusInfo::ClirType)cmd.GetNextInt();
+  }
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CLIP
+ *   This command refers to the supplementary service CLIP (Calling Line
+ * Identification Presentation) according to 3GPP TS 22.081 [3] and OIP
+ * (Originating Identification Presentation) according to 3GPP TS 24.607 [119]
+ * that enables a called subscriber to get the calling line identity (CLI) of
+ * the calling party when receiving a mobile terminated call.
+ *
+ * Command                        Possible response(s)
+ * +CLIP?                         +CLIP: <n>,<m>
+ *
+ * <n>: integer type (parameter sets/shows the result code presentation status to the TE).
+ *   0 disable
+ *   1 enable
+ * <m>: integer type (parameter shows the subscriber CLIR / OIR service status in the network).
+ *   0 CLIP / OIP not provisioned
+ *   1 CLIP / OIP provisioned
+ *   2 unknown (e.g. no network, etc.)
+ *
+ * see RIL_REQUEST_QUERY_CLIP in RIL
+ */
+void SupService::HandleCLIP(const Client& client) {
+  std::vector<std::string> responses = {"+CLIP: 0, 0", "OK"};
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CSSN
+ *   This command refers to supplementary service related network initiated
+ * notifications. The set command enables/disables the presentation of
+ * notification result codes from TA to TE.
+ *
+ * Command                        Possible response(s)
+ * +CSSN: [<n>[,<m>]]
+ *
+ * <n>: integer type (parameter sets/shows the +CSSI intermediate result code
+ *                    presentation status to the TE)
+ *   0   disable
+ *   1   enable
+ * <m>: integer type (parameter sets/shows the +CSSU unsolicited result code
+ *                    presentation status to the TE)
+ *   0   disable
+ *   1   enable
+ *
+ * see RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION in RIL
+ */
+void SupService::HandleSuppServiceNotifications(const Client& client, std::string& /*command*/) {
+  client.SendCommandResponse("OK");
+}
+
+/**
+ * AT+CCFCU
+ *   The command allows control of the communication forwarding supplementary service
+ * according to 3GPP TS 22.072 [31], 3GPP TS 22.082 [4] and 3GPP TS 24.604 [132].
+ *
+ * Command                            Possible response(s)
+ * +CCFCU=<reason>,<mode>               +CME ERROR: <err>
+ * [,<numbertype>,<ton>,<number>        when <mode>=2 and command successful:
+ * [,<class>,<ruleset>                  +CCFCU: <status>,<class1>[,<numbertype>,
+ * [,<subaddr>[,<satype>[,<time>]]]]]           <ton>,<number>[,<subaddr>,<satype>[,<time>]]]
+ * [,<class>,<ruleset>
+ *
+ * see SupService::CallForwardInfo
+ *
+ * see RIL_REQUEST_SET_CALL_FORWARD or RIL_REQUEST_QUERY_CALL_FORWARD_STATUS in RIL
+ */
+void SupService::HandleCallForward(const Client& client, std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+
+  int reason = cmd.GetNextInt();
+  int status = cmd.GetNextInt();
+  int number_type = cmd.GetNextInt();
+  int ton = cmd.GetNextInt();
+  std::string_view number = cmd.GetNextStr();
+  int classx = cmd.GetNextInt();
+
+  switch (reason) {
+    case CallForwardInfo::Reason::ALL_CF: {
+      if (status == CallForwardInfo::CallForwardInfoStatus::INTERROGATE) {
+        auto iter = call_forward_infos_.begin();
+        for (; iter != call_forward_infos_.end(); ++iter) {
+          ss.clear();
+          ss << "+CCFCU: " << iter->status << "," << classx << "," << number_type
+                  << "," << ton << ",\"" << iter->number << "\"";
+          if (iter->reason == CallForwardInfo::Reason::CFNR) {
+            ss << ",,," << iter->timeSeconds;
+          }
+          responses.push_back(ss.str());
+          ss.str("");
+        }
+      }
+      break;
+    }
+    case CallForwardInfo::Reason::CFU:
+    case CallForwardInfo::Reason::CFB:
+    case CallForwardInfo::Reason::CFNR:
+    case CallForwardInfo::Reason::CFNRC: {
+      if (status == CallForwardInfo::CallForwardInfoStatus::INTERROGATE) {
+        ss << "+CCFCU: " << call_forward_infos_[reason].status
+           << "," << classx << "," << number_type << "," << ton << ",\""
+           << call_forward_infos_[reason].number << "\"";
+        if (reason == CallForwardInfo::Reason::CFNR) {
+          ss << ",,," << call_forward_infos_[reason].timeSeconds;
+        }
+        responses.push_back(ss.str());
+      } else {
+        if (status == CallForwardInfo::CallForwardInfoStatus::REGISTRATION) {
+          call_forward_infos_[reason].status
+                = CallForwardInfo::CallForwardInfoStatus::ENABLE;
+        } else {
+          call_forward_infos_[reason].status =
+                (CallForwardInfo::CallForwardInfoStatus)status;
+        }
+        call_forward_infos_[reason].number_type = number_type;
+        call_forward_infos_[reason].ton = ton;
+        call_forward_infos_[reason].number = number;
+        if (reason == CallForwardInfo::Reason::CFNR) {
+          cmd.SkipComma();
+          cmd.SkipComma();
+          cmd.SkipComma();
+          int timeSeconds = cmd.GetNextInt();
+          call_forward_infos_[reason].timeSeconds = timeSeconds >= 0 ? timeSeconds : 0;
+        }
+      }
+      break;
+    }
+    default:
+      client.SendCommandResponse(kCmeErrorInCorrectParameters);
+      return;
+  }
+
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+/**
+ * AT+CCWA
+ *   This command allows control of the supplementary service Call Waiting
+ * according to 3GPP TS 22.083 [5] and Communication Waiting according to
+ * 3GPP TS 24.607 [137]. Activation, deactivation and status query are supported.
+ *
+ * Command                        Possible response(s)
+ * +CCWA=[<n>[,<mode>[,<class>]]] +CME ERROR: <err>
+ *                                when <mode>=2 and command successful
+                                  +CCWA: <status>,<class1>
+                                      [<CR><LF>+CCWA: <status>,<class2>
+ * <n>: integer type (sets/shows the result code presentation status to the TE).
+ *  0   disable
+ *  1   enable
+ * <mode>: integer type (when <mode> parameter is not given, network is not interrogated).
+ *  0   disable
+ *  1   enable
+ *  2   query status
+ * <classx>: a sum of integers each representing a class of information
+ *           (default 7 - voice, data and fax).
+ * <status>: integer type
+ *  0   not active
+ *  1   active
+ *
+ * see RIL_REQUEST_QUERY_CALL_WAITING and RIL_REQUEST_SET_CALL_WAITING in RIL
+ */
+void SupService::HandleCallWaiting(const Client& client, std::string& command) {
+  std::vector<std::string> responses;
+  std::stringstream ss;
+
+  CommandParser cmd(command);
+  cmd.SkipPrefix();
+  cmd.SkipComma();
+  int mode = cmd.GetNextInt();
+  int classx = cmd.GetNextInt();
+
+  if (mode == 2) {  // Query
+    if (classx == -1) {
+      classx = 7;
+    }
+    ss << "+CCWA: " << call_waiting_info_.mode << "," << classx;
+    responses.push_back(ss.str());
+  } else if (mode == 0 || mode == 1) {  // Enable or disable
+    call_waiting_info_.mode = mode;
+    if (classx != -1) {
+      call_waiting_info_.classx = classx;
+    }
+  }
+
+  responses.push_back("OK");
+  client.SendCommandResponse(responses);
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/sup_service.h b/host/commands/modem_simulator/sup_service.h
new file mode 100644
index 0000000..f7be447
--- /dev/null
+++ b/host/commands/modem_simulator/sup_service.h
@@ -0,0 +1,108 @@
+//
+// 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 "host/commands/modem_simulator/modem_service.h"
+
+namespace cuttlefish {
+
+class SupService : public ModemService, public std::enable_shared_from_this<SupService> {
+ public:
+  SupService(int32_t service_id, ChannelMonitor* channel_monitor,
+             ThreadLooper* thread_looper);
+  ~SupService() = default;
+
+  SupService(const SupService &) = delete;
+  SupService &operator=(const SupService &) = delete;
+
+  void HandleUSSD(const Client& client, std::string& command);
+  void HandleCLIR(const Client& client, std::string& command);
+  void HandleCallWaiting(const Client& client, std::string& command);
+  void HandleCLIP(const Client& client);
+  void HandleCallForward(const Client& client, std::string& command);
+  void HandleSuppServiceNotifications(const Client& client, std::string& command);
+
+ private:
+  std::vector<CommandHandler> InitializeCommandHandlers();
+  void InitializeServiceState();
+
+  struct ClirStatusInfo {
+    enum ClirType {
+      DEFAULT = 0,                  // "use subscription default value"
+      CLIR_INVOCATION        = 1,   // restrict CLI presentation
+      CLIR_SUPPRESSION       = 2,   // allow CLI presentation
+    };
+
+    enum ClirStatus {
+      CLIR_NOT_PROVISIONED         = 0,
+      CLIR_PROVISIONED             = 1,
+      UNKNOWN                       = 2,
+      CLIR_PRESENTATION_RESTRICTED = 3,
+      CLIR_PRESENTATION_ALLOWED    = 4,
+    };
+
+    ClirType type;
+    ClirStatus status;
+  };
+  ClirStatusInfo clir_status_;
+
+  struct CallForwardInfo {
+    enum CallForwardInfoStatus {
+      DISABLE       = 0,
+      ENABLE        = 1,
+      INTERROGATE   = 2,
+      REGISTRATION  = 3,
+      ERASURE       = 4,
+    };
+
+    enum Reason {
+      CFU         = 0,  // communication forwarding unconditional
+      CFB         = 1,  //communication forwarding on busy user
+      CFNR        = 2,  // communication forwarding on no reply
+      CFNRC       = 3,  // communication forwarding on subscriber not reachable
+      ALL_CF      = 4,  // all call forwarding
+      ALL_CONDITIONAL_CF = 5, //all conditional call forwarding
+      CD          = 6,  // communication deflection
+      CFNL        = 7,  // communication forwarding on not logged-in
+    };
+
+    CallForwardInfoStatus status;
+    Reason reason;
+    int number_type;    // From 27.007 +CCFC/+CLCK "class"
+    int ton;            // "type" from TS 27.007 7.11
+    std::string number; // "number" from TS 27.007 7.11. May be NULL
+    int timeSeconds;    // for CF no reply only
+
+    CallForwardInfo(Reason reason) :
+      status(DISABLE), reason(reason), number_type(2), ton(129), number(""),
+        timeSeconds(0){};
+  };
+  std::vector<CallForwardInfo> call_forward_infos_;
+
+  struct CallWaitingInfo {
+    int presentation_status;  // sets / shows the result code presentation status to the TE,
+                              // 0: disable; 1: enable
+    int mode;                 // 0: disable; 1: enable; 2: query status
+    int classx;               // a sum of integers each representing a class of information
+                              // default 7-voice, data and fax, see FacilityLock::Class
+
+    CallWaitingInfo() :
+      presentation_status(1), mode(0), classx(7) {};
+  };
+  CallWaitingInfo call_waiting_info_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/thread_looper.cpp b/host/commands/modem_simulator/thread_looper.cpp
new file mode 100644
index 0000000..d9df9df
--- /dev/null
+++ b/host/commands/modem_simulator/thread_looper.cpp
@@ -0,0 +1,130 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/thread_looper.h"
+
+#include <android-base/logging.h>
+
+namespace cuttlefish {
+
+ThreadLooper::ThreadLooper()
+  :   stopped_(false), next_serial_(1) {
+  looper_thread_ = std::thread([this]() { ThreadLoop(); });
+}
+
+ThreadLooper::~ThreadLooper() { Stop(); }
+
+bool ThreadLooper::Event::operator<=(const Event &other) const {
+  return when <= other.when;
+}
+
+ThreadLooper::Serial ThreadLooper::Post(Callback cb) {
+  CHECK(cb != nullptr);
+
+  auto serial = next_serial_++;
+  // If it's the time to process event with delay exactly when posting
+  // a event without delay. Looper would process the event without delay firstly
+  // if when set to be std::nullptr. so set when_ to be now.
+  Insert({ std::chrono::steady_clock::now(), cb, serial });
+
+  return serial;
+}
+
+ThreadLooper::Serial ThreadLooper::PostWithDelay(
+        std::chrono::steady_clock::duration delay, Callback cb) {
+  CHECK(cb != nullptr);
+
+  auto serial = next_serial_++;
+  Insert({ std::chrono::steady_clock::now() + delay, cb, serial });
+
+  return serial;
+}
+
+bool ThreadLooper::CancelSerial(Serial serial) {
+  std::lock_guard<std::mutex> autolock(lock_);
+
+  bool found = false;
+  for (auto iter = queue_.begin(); iter != queue_.end(); ++iter) {
+    if (iter->serial == serial) {
+      queue_.erase(iter);
+      cond_.notify_all();
+
+      found = true;
+      break;
+    }
+  }
+
+  return found;
+}
+
+void ThreadLooper::Insert(const Event &event) {
+  std::lock_guard<std::mutex> autolock(lock_);
+
+  auto iter = queue_.begin();
+  while (iter != queue_.end() && *iter <= event) {
+    ++iter;
+  }
+
+  queue_.insert(iter, event);
+  cond_.notify_all();
+}
+
+void ThreadLooper::ThreadLoop() {
+  for(;;) {
+    Callback cb;
+    {
+      std::unique_lock<std::mutex> lock(lock_);
+
+      if (stopped_) {
+        break;
+      }
+
+      if (queue_.empty()) {
+        cond_.wait(lock);
+        continue;
+      }
+
+      auto time_to_wait = queue_.front().when - std::chrono::steady_clock::now();
+      if (time_to_wait.count() > 0) {
+        // wait with timeout
+        auto durationMs =
+            std::chrono::duration_cast<std::chrono::milliseconds>(time_to_wait);
+        cond_.wait_for(lock, durationMs);
+        continue;
+      }
+      cb = queue_.front().cb; // callback at front of queue
+      queue_.pop_front();
+    }
+    cb();
+  }
+}
+
+void ThreadLooper::Stop() {
+  if (stopped_) {
+    return;
+  }
+  CHECK(looper_thread_.get_id() != std::this_thread::get_id())
+      << "Destructor called from looper thread";
+  {
+    std::lock_guard<std::mutex> autolock(lock_);
+    stopped_ = true;
+  }
+  cond_.notify_all();
+  if (looper_thread_.joinable()) {
+    looper_thread_.join();
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/thread_looper.h b/host/commands/modem_simulator/thread_looper.h
new file mode 100644
index 0000000..dbfd201
--- /dev/null
+++ b/host/commands/modem_simulator/thread_looper.h
@@ -0,0 +1,92 @@
+//
+// 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <deque>
+#include <functional>
+#include <mutex>
+#include <thread>
+
+namespace cuttlefish {
+
+template <typename T>
+std::function<void()> makeSafeCallback(T *me, std::function<void(T *)> f) {
+  return [f, me] {
+    if (me) {
+      f(me);
+    }
+  };
+}
+
+template<typename T, typename... Params>
+std::function<void()> makeSafeCallback(
+    T *obj, void (T::*f)(const Params&...), const Params&... params) {
+  return makeSafeCallback<T>(obj,
+                             [f, params...](T *me) { (me->*f)(params...); });
+}
+
+template<typename T, typename... Params>
+std::function<void()> makeSafeCallback(
+      T *obj, void (T::*f)(Params...), const Params&... params) {
+  return makeSafeCallback<T>(obj,
+                             [f, params...](T *me) { (me->*f)(params...); });
+}
+
+class ThreadLooper {
+ public:
+  ThreadLooper();
+  ~ThreadLooper();
+
+  ThreadLooper(const ThreadLooper &) = delete;
+  ThreadLooper &operator=(const ThreadLooper &) = delete;
+
+  typedef std::function<void()> Callback;
+  typedef int32_t Serial;
+
+  Serial Post(Callback cb);
+  Serial PostWithDelay(std::chrono::steady_clock::duration delay, Callback cb);
+
+  void Stop();
+
+  // Returns true if matching event was canceled.
+  bool CancelSerial(Serial serial);
+
+ private:
+  struct Event {
+      std::chrono::steady_clock::time_point when;
+      Callback cb;
+      Serial serial;
+
+      bool operator<=(const Event &other) const;
+  };
+
+  bool stopped_;
+  std::thread looper_thread_;
+
+  std::mutex lock_;
+  std::condition_variable cond_;
+  std::deque<Event> queue_;
+  std::atomic<Serial> next_serial_;
+
+  void ThreadLoop();
+
+  void Insert(const Event &event);
+};
+
+};  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/unittest/command_parser_test.cpp b/host/commands/modem_simulator/unittest/command_parser_test.cpp
new file mode 100644
index 0000000..6d53fed
--- /dev/null
+++ b/host/commands/modem_simulator/unittest/command_parser_test.cpp
@@ -0,0 +1,103 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/command_parser.h"
+
+#include <gtest/gtest.h>
+
+TEST(CommandParserUnitTest, SkipPrefix) {
+  std::string command = "AT+SPUSATENVECMD=\"D3078202018190014E\"";
+
+  cuttlefish::CommandParser cmd(command);
+  cmd.SkipPrefix();
+  std::string result(*cmd);
+  ASSERT_STREQ("\"D3078202018190014E\"", result.c_str());
+}
+
+TEST(CommandParserUnitTest, SkipPrefixAT) {
+  std::string command = "AT+SPUSATENVECMD=\"D3078202018190014E\"";
+
+  cuttlefish::CommandParser cmd(command);
+  cmd.SkipPrefixAT();
+  std::string result(*cmd);
+  ASSERT_STREQ("+SPUSATENVECMD=\"D3078202018190014E\"", result.c_str());
+}
+
+TEST(CommandParserUnitTest, SkipComma) {
+  std::string command = "+COPS: 0,1,\"CMCC\",7";
+
+  cuttlefish::CommandParser cmd(command);
+  cmd.SkipComma();
+  std::string result(*cmd);
+  ASSERT_STREQ("1,\"CMCC\",7", result.c_str());
+}
+
+TEST(CommandParserUnitTest, SkipWhiteSpace) {
+  std::string command = "+COPS: 0,1,\"CMCC\",7";
+  cuttlefish::CommandParser cmd(command);
+
+  cmd.GetNextStr(':');
+  cmd.SkipWhiteSpace();
+  std::string result(*cmd);
+  ASSERT_STREQ("0,1,\"CMCC\",7", result.c_str());
+}
+
+TEST(CommandParserUnitTest, GetNextStr_default) {
+  std::string command = "+COPS: 0,1,\"CMCC\",7";
+
+  cuttlefish::CommandParser cmd(command);
+  std::string result(cmd.GetNextStr());
+  ASSERT_STREQ("CMCC", result.c_str());
+}
+
+TEST(CommandParserUnitTest, GetNextStr_withparam) {
+  std::string command = "+COPS: 0,1,\"CMCC\",7";
+
+  cuttlefish::CommandParser cmd(command);
+  std::string result(cmd.GetNextStr(','));
+  ASSERT_STREQ("+COPS: 0", result.c_str());
+
+  std::string result2(cmd.GetNextStr(';'));
+  ASSERT_STREQ("1,\"CMCC\",7", result2.c_str());
+}
+
+TEST(CommandParserUnitTest, GetNextInt) {
+  std::string command = "AT+CRSM=192,28421,0,0,15,0,\"3F007FFF\"";
+
+  cuttlefish::CommandParser cmd(command);
+  cmd.SkipPrefix();  // skip "AT+CRSM="
+  ASSERT_EQ(192, cmd.GetNextInt());
+  ASSERT_EQ(28421, cmd.GetNextInt());
+}
+
+TEST(CommandParserUnitTest, GetNextHexInt) {  // Hexadecimal string to decimal value
+  std::string command = "C0,6F05";
+
+  cuttlefish::CommandParser cmd(command);
+  ASSERT_EQ(192, cmd.GetNextHexInt());
+  ASSERT_EQ(28421, cmd.GetNextHexInt());
+}
+
+TEST(CommandParserUnitTest, GetNextStrDeciToHex) {
+  std::string command = "AT+CRSM=192,28421,0,0,15,0,\"3F007FFF\"";
+
+  cuttlefish::CommandParser cmd(command);
+  cmd.SkipPrefix();
+  std::string result(cmd.GetNextStrDeciToHex());
+  ASSERT_STREQ("C0", result.c_str());  // 192
+
+  std::string result2(cmd.GetNextStrDeciToHex());
+  ASSERT_STREQ("6F05", result2.c_str());  // 28421
+}
diff --git a/host/commands/modem_simulator/unittest/iccfile.txt b/host/commands/modem_simulator/unittest/iccfile.txt
new file mode 100755
index 0000000..48e2a02
--- /dev/null
+++ b/host/commands/modem_simulator/unittest/iccfile.txt
@@ -0,0 +1,176 @@
+R"(<IccProfile>
+<MF path="3F00">
+    <EF name="EF_DIR" id="2F00" structure="linear fixed">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A8205422100300483022F008A01058B032F0601800200C08801F0</SIMIO>
+        <SIMIO cmd="B2" p1="1" p2="4" p3="30" data="">144,0,61184F10A0000003431002FF86FF0389FFFFFFFF50044353494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="2" p2="4" p3="30" data="">144,0,61184F10A0000000871002FF86FF0389FFFFFFFF50045553494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="3" p2="4" p3="30" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+        <SIMIO cmd="B2" p1="4" p2="4" p3="30" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+    </EF>
+    <EF name="EF_ICCID" id="2FE2" structure="transparent">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183022FE28A01058B032F06038002000A880110</SIMIO>
+        <SIMIO cmd="B0" p1="0" p2="0" p3="A" data="">144,0,98683081462002318379</SIMIO>
+        <!-- Special ATC to read ICCID from modem cache -->
+        <CCID>89860318640220133897</CCID>
+    </EF>
+    <EF name="EF_PL" id="2F05" structure="transparent">
+        <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183022F058A01058B032F060280020004880128</SIMIO>
+        <SIMIO cmd="B0" p1="0" p2="0" p3="4" data="">144,0,FFFFFFFF</SIMIO>
+    </EF>
+
+    <DF name="TELECOM" path="7F10">
+        <DF name="PHONEBOOK" path="5F3A">
+            <EF name="EF_PBR" id="4F30" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62198205422100400283024F308A01058B036F0606800200808800</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="40" data="">144,0,A81EC0034F3A01C1034F3306C5034F0902C4034F1104C6034F2503C9034F3107A905CA034F5008AA0FC2034F4A09C7034F4B0AC8034F4C0BFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="40" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_GAS" id="4F4C" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A8205422100140A83024F4C8A01058B036F060E800200C8880158</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="3" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="4" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="5" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="6" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="7" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="8" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="9" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="A" p2="4" p3="E" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_ADN" id="4F3A" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A82054221001C1483024F3A8A01058B036F060E80020230880108</SIMIO>
+                <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="2" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="3" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="4" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="5" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="6" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="7" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="8" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="9" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="A" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="B" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="C" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="D" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="E" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="F" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="10" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="11" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="12" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="13" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+                <SIMIO cmd="B2" p1="14" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+            </EF>
+            <EF name="EF_IAP" id="4F33" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A820542210001FA83024F338A01058B036F060E800200FA880130</SIMIO>
+            </EF>
+            <EF name="EF_PBC" id="4F09" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A820542210002FA83024F098A01058B036F060E800201F4880110</SIMIO>
+            </EF>
+            <EF name="EF_ANR" id="4F11" structure="linear fixed">
+                <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621A82054221000FFA83024F118A01058B036F060E80020EA6880120</SIMIO>
+            </EF>
+            <!-- EF_SNE, EF_AAS, EF_EXT1, EF_GRP, EF_UID, EF_EMAIL, EF_CCP1, EF_PUR1 ... -->
+        </DF>
+    </DF>
+
+    <ADF name="USIM" path="7FFF" aid="A0000000871002FF86FF0389FFFFFFFF">
+        <EF name="EF_IMSI" id="6F07" structure="transparent">
+            <CIMI>460110031689666</CIMI>
+        </EF>
+        <EF name="EF_MSISDN" id="6F40" structure="linear fixed">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621982054221001C0283026F408A01058B036F0605800200388800</SIMIO>
+            <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,00000000000000000000000000000891688118109844F0FFFFFFFFFF</SIMIO>
+        </EF>
+        <EF name="EF_MBI" id="6FC9" structure="linear fixed">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">106,130</SIMIO>
+       </EF>
+       <EF name="EF_AD" id="6FAD" structure="transparent">
+            <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62178202412183026FAD8A01058B036F060180020004880118</SIMIO>
+            <SIMIO cmd="B0" p1="0" p2="0" p3="4" data="">144,0,00000002</SIMIO>
+       </EF>
+       <EF name="EF_MWIS" id="6FCA" structure="linear fixed">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,62198205422100050183026FCA8A01058B036F060E800200058800</SIMIO>
+           <SIMIO cmd="B2" p1="1" p2="4" p3="5" data="">144,0,0000000000</SIMIO>
+       </EF>
+       <EF name="EF_VOICE_MAIL_INDICATOR_CPHS" id="6F11" structure="transparent">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">106,130</SIMIO>
+       </EF>
+       <EF name="EF_FPLMN" id="6F7B" structure="transparent">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621C8202412183026F7BA5038001718A01058B036F06038002001E880168</SIMIO>
+           <SIMIO cmd="B0" p1="0" p2="0" p3="1E" data="">144,0,64F00064F02064F04064F07064F080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+       </EF>
+       <EF name="EF_FDN" id="6F3B" structure="linear fixed">
+           <SIMIO cmd="C0" p1="0" p2="0" p3="F" data="">144,0,621982054221001C0A83026F3B8A01058B036F0605800201188800</SIMIO>
+           <SIMIO cmd="B2" p1="1" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="2" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="3" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="4" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="5" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="6" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="7" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="8" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="9" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+           <SIMIO cmd="B2" p1="A" p2="4" p3="1C" data="">144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</SIMIO>
+       </EF>
+       <!-- Other USIM files... -->
+     </ADF>
+</MF>
+
+<ADF name="PKCS15" aid="A000000063504B43532D3135">
+    <CGLA cmd="A40004025031">4,6124</CGLA>
+    <CGLA cmd="C0000024">76,62228202412183025031A503C001408A01058B066F0601010001800200108102002288009000 </CGLA>
+    <CGLA cmd="B0000010">36,A706300404024401A5063004040244029000</CGLA>
+</ADF>
+
+<ADF name="" aid="">
+    <CSIM cmd='10,"0070000001"'>6,019000</CSIM>
+    <CGLA cmd='1,14,"81F2FF0000"'>4,6b00</CGLA>
+    <!-- more CGLA Command -->
+</ADF>
+
+<PinProfile>
+    <!-- PIN: PINSTATE_ENABLED_NOT_VERIFIED -->
+    <!-- PUK: PINSTATE_ENABLED_BLOCKED -->
+    <!-- Ready: PINSTATE_UNKNOWN -->
+    <PINSTATE>PINSTATE_UNKNOWN</PINSTATE>
+    <PINCODE>1234</PINCODE>
+    <PUKCODE>12345678</PUKCODE>
+    <PINREMAINTIMES>3</PINREMAINTIMES>
+    <PUKREMAINTIMES>10</PUKREMAINTIMES>
+    <PIN2CODE>1234</PIN2CODE>
+    <PUK2CODE>12345678</PUK2CODE>
+    <PIN2REMAINTIMES>3</PIN2REMAINTIMES>
+    <PUK2REMAINTIMES>10</PUK2REMAINTIMES>
+</PinProfile>
+
+<FacilityLock>
+    <SC>DISABLE</SC>
+    <FD>DISABLE</FD>
+    <AO>DISABLE</AO>
+    <OI>DISABLE</OI>
+    <AI>DISABLE</AI>
+    <IR>DISABLE</IR>
+    <AB>DISABLE</AB>
+    <AG>DISABLE</AG>
+    <AC>DISABLE</AC>
+</FacilityLock>
+
+<SETUPMENU cmd="25" text="D0388103012500820281820509804E2D56FD79FB52A88F10508000530049004D5FEB6377786E8BA48F104E80005500530049004D53614FE1606F">
+    <SELECTITEM id="1" cmd="24" menuId="50" text="D02D8103012400820281828F0A018053E34EE48BBE7F6E8F0A02804E1A52A14ECB7ECD8F0A0380724867434FE1606F">
+        <SELECTITEM id="1" cmd="24" menuId="01" text="D0218103012400820281828F0A01806DFB52A083DC53558F0A02805220966483DC5355">
+            <DISPLAYTEXT id="1" cmd="21" menuId="01" text="D0228103012181820281028D1708662F542666F465B04E0B8F7D83DC535552178868FF1F"></DISPLAYTEXT>
+            <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D01A8103012101820281028D0F0883DC5355522096646210529FFF01"></DISPLAYTEXT>
+        </SELECTITEM>
+        <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D081BB8103012181820281028D81AF08201C00530049004D5FEB6377786E8BA4201D662F4E2D56FD79FB52A863D04F9B7684FF0C57FA4E8E624B673A00530049004D53617684727982725B8951688EAB4EFD8BA48BC1670D52A1300276F86BD44F207EDF75286237540D5BC678018BA48BC165B95F0FFF0C5B83517767094E0D53EF62E6622A30014E0D4F208F935BC6780130014F7F75285FEB63777B49727970B9FF0C662F60A87545884C4E9280547F5176848EAB4EFD536B58EB3002"></DISPLAYTEXT>
+        <DISPLAYTEXT id="3" cmd="21" menuId="03" text="D02E8103012181820281028D23084E2D56FD79FB52A8901A4FE167099650516C53F8FF0C0031002E00307248672C3002">
+        </DISPLAYTEXT>
+    </SELECTITEM>
+    <SELECTITEM id="2" cmd="24" menuId="4E" text="D04E810301240082028182850F80005500530049004D53614FE1606F8F0A0180536172477C7B578B8F14028075358BDD53F7780153CA77ED4FE15BB991CF8F100380004F00540041529F80FD4ECB7ECD">
+        <DISPLAYTEXT id="1" cmd="21" menuId="01" text="D03A8103012181820281028D2F08666E901A005500530049004D5361002000560032002E003000410027FF0C652F6301004F005400410033529F80FD"></DISPLAYTEXT>
+        <DISPLAYTEXT id="2" cmd="21" menuId="02" text="D05C8103012181820281028D510875358BDD53F77801672C5B5850A85BB991CF0035003000306761FF0C5DF2752875358BDD672C003100336761FF0C77ED4FE15B5850A85BB991CF003500306761FF0C5DF2752877ED4FE1003400396761"></DISPLAYTEXT>
+        <DISPLAYTEXT id="3" cmd="21" menuId="03" text="D05E8103012181820281028D5308004F00540041529F80FD53EF5229752877ED4FE1606F901A9053FF0C5E2E52A95BA262375B9E73B0005500530049004D536151854E1A52A183DC5355768452A860014E0B8F7D3001522096644E0E66F465B0"></DISPLAYTEXT>
+    </SELECTITEM>
+</SETUPMENU>
+
+</IccProfile>)"
diff --git a/host/commands/modem_simulator/unittest/main_test.cpp b/host/commands/modem_simulator/unittest/main_test.cpp
new file mode 100644
index 0000000..7afadb4
--- /dev/null
+++ b/host/commands/modem_simulator/unittest/main_test.cpp
@@ -0,0 +1,24 @@
+//
+// 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.
+
+#include <gtest/gtest.h>
+#include <gflags/gflags.h>
+
+DEFINE_int32(instance_number, 1, "modem simulator instance numbers");
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/host/commands/modem_simulator/unittest/pdu_parser_test.cpp b/host/commands/modem_simulator/unittest/pdu_parser_test.cpp
new file mode 100644
index 0000000..4129aa1
--- /dev/null
+++ b/host/commands/modem_simulator/unittest/pdu_parser_test.cpp
@@ -0,0 +1,55 @@
+//
+// 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.
+
+#include "host/commands/modem_simulator/pdu_parser.h"
+
+#include <gtest/gtest.h>
+
+TEST(PDUParserTest, IsValidPDU_true) {
+  std::string pdu = "0001000D91688118109844F0000017AFD7903AB55A9BBA69D639D4ADCBF99E3DCCAE9701";
+  cuttlefish::PDUParser smspdu(pdu);
+  EXPECT_TRUE(smspdu.IsValidPDU());
+}
+
+TEST(PDUParserTest, IsValidPDU_false) {
+  std::string pdu = "000100fD91688118109844F0000017AFD7903AB55A9BBA69D639D4ADCBF99E3DCCAE9701";
+  cuttlefish::PDUParser smspdu(pdu);
+  EXPECT_FALSE(smspdu.IsValidPDU());
+}
+
+TEST(PDUParserTest, CreatePDU) {
+  std::string pdu = "0001000D91688118109844F0000017AFD7903AB55A9BBA69D639D4ADCBF99E3DCCAE9701";
+  cuttlefish::PDUParser smspdu(pdu);
+  EXPECT_TRUE(smspdu.IsValidPDU());
+  std::string new_pdu = smspdu.CreatePDU();
+  const char *expect = "";
+  ASSERT_STRNE(new_pdu.c_str(), expect);
+}
+
+TEST(PDUParserTest, GetPhoneNumberFromAddress) {
+  std::string pdu = "0001000D91688118109844F0000017AFD7903AB55A9BBA69D639D4ADCBF99E3DCCAE9701";
+  cuttlefish::PDUParser smspdu(pdu);
+  EXPECT_TRUE(smspdu.IsValidPDU());
+  std::string phone_number = smspdu.GetPhoneNumberFromAddress();
+  const char *expect = "18810189440";
+  ASSERT_STREQ(phone_number.c_str(), expect);
+}
+
+TEST(PDUParserTest, BCDToString) {
+  std::string value = "12345678";
+  std::string process_value = cuttlefish::PDUParser::BCDToString(value);
+  const char *expect = "21436587";
+  ASSERT_STREQ(process_value.c_str(), expect);
+}
diff --git a/host/commands/modem_simulator/unittest/service_test.cpp b/host/commands/modem_simulator/unittest/service_test.cpp
new file mode 100644
index 0000000..5801586
--- /dev/null
+++ b/host/commands/modem_simulator/unittest/service_test.cpp
@@ -0,0 +1,774 @@
+//
+// 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.
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <stdlib.h>
+
+#include <filesystem>
+#include <fstream>
+
+#include "common/libs/fs/shared_select.h"
+#include "common/libs/utils/files.h"
+#include "host/commands/modem_simulator/channel_monitor.h"
+#include "host/commands/modem_simulator/modem_simulator.h"
+#include "host/libs/config/cuttlefish_config.h"
+namespace fs = std::filesystem;
+
+static const char *myiccfile =
+#include "iccfile.txt"
+    ;
+
+static const std::string tmp_test_dir = std::string(fs::temp_directory_path()) +
+                                        std::string("/cuttlefish_modem_test");
+using namespace cuttlefish;
+
+class ModemServiceTest : public ::testing::Test {
+ protected:
+  static void SetUpTestSuite() {
+    {
+      cuttlefish::CuttlefishConfig tmp_config_obj;
+      std::string config_file = tmp_test_dir + "/.cuttlefish_config.json";
+      std::string instance_dir = tmp_test_dir + "/cuttlefish_runtime.1";
+      fs::create_directories(instance_dir);
+      tmp_config_obj.set_ril_dns("8.8.8.8");
+      std::vector<int> instance_nums;
+      for (int i = 0; i < 1; i++) {
+        instance_nums.push_back(cuttlefish::GetInstance() + i);
+      }
+      for (const auto &num : instance_nums) {
+        auto instance = tmp_config_obj.ForInstance(num);
+        instance.set_instance_dir(instance_dir);
+      }
+
+      for (auto instance : tmp_config_obj.Instances()) {
+        if (!tmp_config_obj.SaveToFile(
+                instance.PerInstancePath("cuttlefish_config.json"))) {
+          LOG(ERROR) << "Unable to save copy config object";
+          return;
+        }
+      }
+      fs::copy_file(instance_dir + "/cuttlefish_config.json", config_file,
+                    fs::copy_options::overwrite_existing);
+      std::string icfilename = instance_dir + "/iccprofile_for_sim0.xml";
+      std::ofstream offile(icfilename, std::ofstream::out);
+      offile << std::string(myiccfile);
+      offile.close();
+
+      ::setenv("CUTTLEFISH_CONFIG_FILE", config_file.c_str(), 1);
+    }
+    cuttlefish::SharedFD ril_shared_fd, modem_shared_fd;
+    if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &ril_shared_fd,
+                              &modem_shared_fd)) {
+      LOG(ERROR) << "Unable to create client socket pair: " << strerror(errno);
+    }
+    ASSERT_TRUE(ril_shared_fd->IsOpen());
+    ASSERT_TRUE(modem_shared_fd->IsOpen());
+
+    NvramConfig::InitNvramConfigService(1, 1);
+
+    ril_side_ = new Client(ril_shared_fd);
+    modem_side_ = new Client(modem_shared_fd);
+    modem_simulator_ = new ModemSimulator(0);
+
+    cuttlefish::SharedFD server;
+    auto channel_monitor =
+        std::make_unique<ChannelMonitor>(modem_simulator_, server);
+    modem_simulator_->Initialize(std::move(channel_monitor));
+  }
+
+  static void TearDownTestSuite() {
+    delete ril_side_;
+    delete modem_side_;
+    delete modem_simulator_;
+    fs::remove_all(tmp_test_dir);
+  };
+
+  void SendCommand(std::string command, std::string prefix = "") {
+    command_prefix_ = prefix;
+    modem_simulator_->DispatchCommand(*modem_side_, command);
+  }
+
+  void ReadCommandResponse(std::vector<std::string>& response) {
+    do {
+      std::vector<char> buffer(4096);  // kMaxCommandLength
+      auto bytes_read = ril_side_->client_fd->Read(buffer.data(), buffer.size());
+      if (bytes_read <= 0) {
+        // Close here to ensure the other side gets reset if it's still
+        // connected
+        ril_side_->client_fd->Close();
+        LOG(WARNING) << "Detected close from the other side";
+        break;
+      }
+
+      std::string& incomplete_command = ril_side_->incomplete_command;
+
+      // Add the incomplete command from the last read
+      auto commands = std::string{incomplete_command.data()};
+      commands.append(buffer.data());
+
+      incomplete_command.clear();
+      incomplete_command.resize(0);
+
+      // replacing '\n' with '\r'
+      commands = android::base::StringReplace(commands, "\n", "\r", true);
+
+      // split into commands and dispatch
+      size_t pos = 0, r_pos = 0;  // '\r' or '\n'
+      while (r_pos != std::string::npos) {
+        r_pos = commands.find('\r', pos);
+        if (r_pos != std::string::npos) {
+          auto command = commands.substr(pos, r_pos - pos);
+          if (command.size() > 0) {  // "\r\r" ?
+            LOG(DEBUG) << "AT< " << command;
+            if (IsFinalResponseSuccess(command) || IsFinalResponseError(command)) {
+              response.push_back(command);
+              return;
+            } else if (IsIntermediateResponse(command)) {
+              response.push_back(command);
+            } else {
+              ; // Ignore unsolicited command
+            }
+          }
+          pos = r_pos + 1;  // skip '\r'
+        } else if (pos < commands.length()) {  // incomplete command
+          incomplete_command = commands.substr(pos);
+          LOG(VERBOSE) << "incomplete command: " << incomplete_command;
+        }
+      }
+    } while (true);
+
+    // read response
+  }
+
+  inline bool IsFinalResponseSuccess(std::string response) {
+    auto iter = kFinalResponseSuccess.begin();
+    for (; iter != kFinalResponseSuccess.end(); ++iter) {
+      if (*iter == response) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  inline bool IsFinalResponseError(std::string response) {
+    auto iter = kFinalResponseError.begin();
+    for (; iter != kFinalResponseError.end(); ++iter) {
+      if (response.compare(0, iter->size(), *iter) == 0) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  inline bool IsIntermediateResponse(std::string response) {
+    if (response.compare(0, command_prefix_.size(), command_prefix_) == 0) {
+      return true;
+    }
+
+    return false;
+  }
+
+  int openLogicalChannel(std::string& name) {
+    // Create and send command
+    std::string command = "AT+CCHO=";
+    command.append(name);
+    std::vector<std::string> response;
+    SendCommand(command);
+    ReadCommandResponse(response);
+    int channel = std::stoi(response[0]);
+    return channel;
+  }
+
+  bool closeLogicalChannel(int channel) {
+    std::string command = "AT+CCHC=";
+    command += std::to_string(channel);
+    std::vector<std::string> response;
+    SendCommand(command);
+    ReadCommandResponse(response);
+    std::string expect = "+CCHC";
+    return (response[0].compare(0, expect.size(), expect) == 0);
+  }
+
+  const std::vector<std::string> kFinalResponseSuccess = {"OK", "CONNECT", "> "};
+  const std::vector<std::string> kFinalResponseError = {
+      "ERROR",
+      "+CMS ERROR:",
+      "+CME ERROR:",
+      "NO CARRIER", /* sometimes! */
+      "NO ANSWER",
+      "NO DIALTONE",
+  };
+
+  static Client* ril_side_;
+  static Client* modem_side_;
+  static ModemSimulator* modem_simulator_;
+
+  // For distinguishing the response from command response or unsolicited command
+  std::string command_prefix_;
+};
+
+ModemSimulator* ModemServiceTest::modem_simulator_ = nullptr;
+Client* ModemServiceTest::ril_side_ = nullptr;
+Client* ModemServiceTest::modem_side_ = nullptr;
+
+/* Sim Service Test */
+TEST_F(ModemServiceTest, GetIccCardStatus) {
+  const char *expects[]  = {"+CPIN: READY",
+                            "OK"};
+
+  std::string command = "AT+CPIN?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CPIN:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[0].c_str(), expects[0]);
+  ASSERT_STREQ(response[1].c_str(), expects[1]);
+}
+
+TEST_F(ModemServiceTest, ChangeOrEnterPIN) {
+  std::vector<std::string> commands = {"AT+CPIN=1234,0000",
+                                       "AT+CPIN=1111,2222",};
+  std::vector<std::string> expects  = {"OK",
+                                       "+CME ERROR: 16",};
+  std::vector<std::string> response;
+  auto expects_iter = expects.begin();
+  for (auto iter = commands.begin(); iter != commands.end(); ++iter, ++expects_iter) {
+    SendCommand(*iter);
+    ReadCommandResponse(response);
+    ASSERT_STREQ(response[0].c_str(), (*expects_iter).c_str());
+    response.clear();
+  }
+}
+
+TEST_F(ModemServiceTest, SIM_IO) {
+  std::vector<std::string> commands = {"AT+CRSM=192,12258,0,0,15",
+                                       "AT+CRSM=192,28436,0,0,15",
+                                       "AT+CRSM=220,28618,1,4,5,0000000000"};
+  std::vector<std::string> expects  = {"+CRSM: 144,0,62178202412183022FE28A01058B032F06038002000A880110",
+                                       "+CRSM: 106,130",
+                                       "+CRSM: 144,0"};
+
+  std::vector<std::string> response;
+  auto expects_iter = expects.begin();
+  for (auto iter = commands.begin(); iter != commands.end(); ++iter, ++expects_iter) {
+    SendCommand(*iter);
+    ReadCommandResponse(response);
+    ASSERT_EQ(response.size(), 2);
+    ASSERT_STREQ(response[0].c_str(), (*expects_iter).c_str());
+    response.clear();
+  }
+}
+
+TEST_F(ModemServiceTest, GetIMSI) {
+  std::string command = "AT+CIMI";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *expect = "460110031689666";
+  ASSERT_STREQ(response[0].c_str(),expect);
+}
+
+TEST_F(ModemServiceTest, GetIccId) {
+  std::string command = "AT+CICCID";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *expect = "89860318640220133897";
+  ASSERT_STREQ(response[0].c_str(),expect);
+}
+
+TEST_F(ModemServiceTest, FacilityLock) {
+  std::vector<std::string> commands =
+        { "AT+CLCK=\"FD\",2,"",7",
+          "AT+CLCK=\"SC\",2,"",7",
+          "AT+CLCK=\"SC\",1,\"1234\",7",
+          "AT+CLCK=\"SC\",1,\"023000\",7"
+  };
+  std::vector<std::string> expects =
+        { "+CLCK: 0",
+          "+CLCK: 0",
+          "+CME ERROR: 16",
+          "+CME ERROR: 16"
+  };
+  std::vector<std::string> response;
+  auto expects_iter = expects.begin();
+  for (auto iter = commands.begin(); iter != commands.end(); ++iter, ++expects_iter) {
+    SendCommand(*iter);
+    ReadCommandResponse(response);
+    ASSERT_STREQ(response[0].c_str(), (*expects_iter).c_str());
+    response.clear();
+  }
+}
+
+TEST_F(ModemServiceTest, OpenLogicalChannel) {
+  std::string command= "A000000063504B43532D3135";
+  int firstChannel = openLogicalChannel(command);
+  ASSERT_EQ(firstChannel, 1);
+
+  command= "A000000063504B43532D3135";
+  int secondChannel = openLogicalChannel(command);
+  ASSERT_GE(secondChannel, 1);
+
+  closeLogicalChannel(firstChannel);
+  closeLogicalChannel(secondChannel);
+}
+
+TEST_F(ModemServiceTest, CloseLogicalChannel) {
+  std::string command= "A000000063504B43532D3135";
+  int channel = openLogicalChannel(command);
+  ASSERT_EQ(channel, 1);
+
+  ASSERT_FALSE(closeLogicalChannel(channel + 3));
+  ASSERT_TRUE(closeLogicalChannel(channel));
+}
+
+TEST_F(ModemServiceTest, TransmitLogicalChannel) {
+  std::string command= "A000000063504B43532D3135";
+  int channel = openLogicalChannel(command);
+  ASSERT_EQ(channel, 1);
+  command = "AT+CGLA=";
+  command += channel;
+  command += ",10,80caff4000";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *expect = "+CME ERROR: 21";
+  ASSERT_STREQ(response[0].c_str(),expect);
+  ASSERT_TRUE(closeLogicalChannel(channel));
+}
+
+/* Network Service Test */
+TEST_F(ModemServiceTest, testRadioPowerReq) {
+  std::string command = "AT+CFUN?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CFUN:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testSetRadioPower) {
+  std::string command = "AT+CFUN=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testSignalStrength) {
+  std::string command = "AT+CSQ";
+  std::vector<std::string> response;
+  SendCommand(command, "+CSQ:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testQueryNetworkSelectionMode) {
+  std::string command = "AT+COPS?";
+  std::vector<std::string> response;
+  SendCommand(command, "+COPS:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testRequestOperator) {
+  std::string command = "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?";
+  std::vector<std::string> response;
+  SendCommand(command, "+COPS:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 4);
+}
+
+TEST_F(ModemServiceTest, testVoiceNetworkRegistration) {
+  std::string command = "AT+CREG?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CREG:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testDataNetworkRegistration) {
+  std::string command = "AT+CGREG?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CGREG:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testDataNetworkRegistrationWithLte2) {
+  std::string command = "AT+CEREG?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CEREG:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testGetPreferredNetworkType) {
+  std::string command = "AT+CTEC?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CTEC:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testQuerySupportedTechs) {
+  std::string command = "AT+CTEC=?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CTEC:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testSetPreferredNetworkType) {
+  std::string command = "AT+CTEC=1,\"201\"";
+  std::vector<std::string> response;
+  SendCommand(command, "+CTEC:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+/* Call Service Test */
+TEST_F(ModemServiceTest, testCurrentCalls) {
+  std::string command = "AT+CLCC";
+  std::vector<std::string> response;
+  SendCommand(command, "+CLCC:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+}
+
+TEST_F(ModemServiceTest, testHangup) {
+  for (int i = 0; i < 5; i ++) {
+    std::stringstream ss;
+    ss.clear();
+    ss << "AT+CHLD=" << i;
+    SendCommand(ss.str());
+  }
+  std::vector<std::string> response;
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testMute) {
+  std::string command = "AT+CMUT=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testSendDtmf) {
+  std::string command = "AT+VTS=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testExitEmergencyMode) {
+  std::string command = "AT+WSOS=0";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+/* Data Service Test */
+TEST_F(ModemServiceTest, SetPDPContext) {
+  std::string command = "AT+CGDCONT=1,\"IPV4V6\",\"ctlte\",,0,0";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response.at(0).c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, QueryPDPContextList) {
+  for (int i = 1; i < 5; i ++) {
+    std::stringstream ss;
+    ss.clear();
+    ss << "AT+CGDCONT=" << i << ",\"IPV4V6\",\"ctlte\",,0,0";
+    SendCommand(ss.str());
+  }
+  std::string command = "AT+CGDCONT?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CGDCONT:");
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, ActivateDataCall) {
+  std::string command = "AT+CGACT= 1,0";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[0].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, QueryDataCallList) {
+  std::string command = "AT+CGACT?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CGACT:");
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, ReadDynamicParamTrue) {
+  std::string command = "AT+CGCONTRDP=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, ReadDynamicParamFalse) {
+  std::string command = "AT+CGCONTRDP=10";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  const char *expect = "+CME ERROR: 21";
+  ASSERT_STREQ(result, expect);
+}
+
+TEST_F(ModemServiceTest, EnterDataState) {
+  std::string command = "AT+CGDATA=1,1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[1].c_str());
+}
+
+/* SMS Service Test */
+TEST_F(ModemServiceTest, SendSMS) {
+  std::string command = "AT+CMGS=35";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  const char *expect = "> ";
+  ASSERT_STREQ(result, expect);
+  command = "0001000D91688118109844F0000017AFD7903AB55A9BBA69D639D4ADCBF99E3DCCAE9701^Z";
+  //command += '\032';
+  SendCommand(command);
+  ReadCommandResponse(response);
+  // TODO (bohu) for some reason the follwoing asserts fail, fix them
+  // ASSERT_EQ(response.size(), 3);
+  // ASSERT_STREQ(response[response.size() - 1].c_str(),
+  // kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, WriteSMSToSim) {
+  std::string command = "AT+CMGW=24,3";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  const char *expect = "> ";
+  ASSERT_STREQ(result, expect);
+  command = "00240B815123106351F100000240516054410005C8329BFD06^Z";
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 3);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, SMSAcknowledge) {
+  std::string command = "AT+CNMA=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, DeleteSmsOnSimTure) {
+  std::string command = "AT+CMGD=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[0].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, DeleteSmsOnSimFalse) {
+  std::string command = "AT+CMGD=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[0].c_str();
+  const char *expect = "+CME ERROR: 21";
+  ASSERT_STREQ(result, expect);
+}
+
+TEST_F(ModemServiceTest, SetBroadcastConfig) {
+  std::string command = "AT+CSCB=0,\"4356\",\"0-255\"";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  const char *result = response[0].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, GetBroadcastConfig) {
+  std::string command = "AT+CSCB?";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, SetSmscAddress) {
+  std::string command = "AT+CSCA=\"91688115667566F4\",16";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, GetSmscAddress) {
+  std::string command = "AT+CSCA?";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *result = response[response.size() - 1].c_str();
+  ASSERT_STREQ(result, kFinalResponseSuccess[0].c_str());
+}
+
+/* SUP Service Test */
+TEST_F(ModemServiceTest, testUSSD) {
+  std::string command = "AT+CUSD=1";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testCLIR) {
+  std::string command = "AT+CLIR=2";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testQueryCLIR) {
+  std::string command = "AT+CLIR?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CLIR:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+}
+
+TEST_F(ModemServiceTest, testCallWaiting) {
+  std::string command = "AT+CCWA";
+  std::vector<std::string> response;
+  SendCommand(command, "+CCWA:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+  ASSERT_STREQ(response[response.size() - 1].c_str(), kFinalResponseSuccess[0].c_str());
+}
+
+TEST_F(ModemServiceTest, testCLIP) {
+  std::string command = "AT+CLIP?";
+  std::vector<std::string> response;
+  SendCommand(command, "+CLIP:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+}
+
+TEST_F(ModemServiceTest, testCallForward) {
+  std::string command = "AT+CCFCU=1,1,2,145,\"10086\"";
+  std::vector<std::string> response;
+  SendCommand(command, "+CCFCU:");
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 1);
+}
+
+/* STK Service Test */
+TEST_F(ModemServiceTest, ReportStkServiceIsRunning) {
+  std::string command = "AT+CUSATD?";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *result = response[0].c_str();
+  const char *expect = "+CUSATD: 0,1";
+  ASSERT_STREQ(result, expect);
+}
+
+TEST_F(ModemServiceTest, SendEnvelope) {
+  std::string command = "AT+CUSATT=\"810301250002028281830100\"";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *result = response[0].c_str();
+  const char *expect = "+CUSATT: 0";
+  ASSERT_STREQ(result, expect);
+}
+
+TEST_F(ModemServiceTest, GetSendTerminalResponseToSim) {
+  std::string command = "AT+CUSATE=\"D3078202018190014E\"";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *result = response[0].c_str();
+  const char *expect = "+CUSATE: 0";
+  ASSERT_STREQ(result, expect);
+}
+
+/* Misc Service Test */
+TEST_F(ModemServiceTest, GetIMEI) {
+  std::string command = "AT+CGSN";
+  std::vector<std::string> response;
+  SendCommand(command);
+  ReadCommandResponse(response);
+  ASSERT_EQ(response.size(), 2);
+  const char *result = response[0].c_str();
+  const char *expect = "867400022047199";
+  ASSERT_STREQ(result, expect);
+}
diff --git a/host/commands/powerwash_cvd/Android.bp b/host/commands/powerwash_cvd/Android.bp
new file mode 100644
index 0000000..adaacb9
--- /dev/null
+++ b/host/commands/powerwash_cvd/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2018 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "powerwash_cvd",
+    srcs: [
+        "powerwash_cvd.cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libjsoncpp",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libcuttlefish_vm_manager",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+}
diff --git a/host/commands/powerwash_cvd/powerwash_cvd.cc b/host/commands/powerwash_cvd/powerwash_cvd.cc
new file mode 100644
index 0000000..b2e322b
--- /dev/null
+++ b/host/commands/powerwash_cvd/powerwash_cvd.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <fstream>
+#include <iomanip>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <gflags/gflags.h>
+#include <android-base/logging.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/fs/shared_select.h"
+#include "common/libs/utils/environment.h"
+#include "host/commands/run_cvd/runner_defs.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/vm_manager/vm_manager.h"
+
+DEFINE_int32(instance_num, cuttlefish::GetInstance(),
+             "Which instance to powerwash");
+
+DEFINE_int32(wait_for_launcher, 30,
+             "How many seconds to wait for the launcher to respond to the status "
+             "command. A value of zero means wait indefinetly");
+
+DEFINE_int32(boot_timeout, 1000, "How many seconds to wait for the device to "
+                                 "reboot.");
+
+namespace cuttlefish {
+namespace {
+
+int PowerwashCvdMain(int argc, char** argv) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  auto config = CuttlefishConfig::Get();
+  if (!config) {
+    LOG(ERROR) << "Failed to obtain config object";
+    return 1;
+  }
+
+  auto instance = config->ForInstance(FLAGS_instance_num);
+  auto monitor_path = instance.launcher_monitor_socket_path();
+  if (monitor_path.empty()) {
+    LOG(ERROR) << "No path to launcher monitor found";
+    return 2;
+  }
+  auto monitor_socket = SharedFD::SocketLocalClient(
+      monitor_path.c_str(), false, SOCK_STREAM, FLAGS_wait_for_launcher);
+  if (!monitor_socket->IsOpen()) {
+    LOG(ERROR) << "Unable to connect to launcher monitor at " << monitor_path
+               << ": " << monitor_socket->StrError();
+    return 3;
+  }
+  auto request = LauncherAction::kPowerwash;
+  auto bytes_sent = monitor_socket->Send(&request, sizeof(request), 0);
+  if (bytes_sent < 0) {
+    LOG(ERROR) << "Error sending launcher monitor the status command: "
+               << monitor_socket->StrError();
+    return 4;
+  }
+  // Perform a select with a timeout to guard against launcher hanging
+  SharedFDSet read_set;
+  read_set.Set(monitor_socket);
+  struct timeval timeout = {FLAGS_wait_for_launcher, 0};
+  int selected = Select(&read_set, nullptr, nullptr,
+                        FLAGS_wait_for_launcher <= 0 ? nullptr : &timeout);
+  if (selected < 0){
+    LOG(ERROR) << "Failed communication with the launcher monitor: "
+               << strerror(errno);
+    return 5;
+  }
+  if (selected == 0) {
+    LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
+    return 6;
+  }
+  LauncherResponse response;
+  auto bytes_recv = monitor_socket->Recv(&response, sizeof(response), 0);
+  if (bytes_recv < 0) {
+    LOG(ERROR) << "Error receiving response from launcher monitor: "
+               << monitor_socket->StrError();
+    return 7;
+  }
+  LOG(INFO) << "Requesting powerwash";
+  if (response != LauncherResponse::kSuccess) {
+    LOG(ERROR) << "Received '" << static_cast<char>(response)
+               << "' response from launcher monitor for powerwash request";
+    return 8;
+  }
+  LOG(INFO) << "Waiting for device to boot up again";
+
+  read_set.Set(monitor_socket);
+  timeout = {FLAGS_boot_timeout, 0};
+  selected = Select(&read_set, nullptr, nullptr,
+                    FLAGS_boot_timeout <= 0 ? nullptr : &timeout);
+  if (selected < 0){
+    LOG(ERROR) << "Failed communication with the launcher monitor: "
+               << strerror(errno);
+    return 5;
+  }
+  if (selected == 0) {
+    LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
+    return 6;
+  }
+
+  RunnerExitCodes exit_code;
+  bytes_recv = ReadExactBinary(monitor_socket, &exit_code);
+  if (bytes_recv < 0) {
+    LOG(ERROR) << "Error in stream response: " << monitor_socket->StrError();
+    return 9;
+  } else if (bytes_recv == 0) {
+    LOG(ERROR) << "Launcher socket closed unexpectedly";
+    return 10;
+  } else if (bytes_recv != sizeof(exit_code)) {
+    LOG(ERROR) << "Launcher response was too short";
+    return 11;
+  } else if (exit_code == RunnerExitCodes::kVirtualDeviceBootFailed) {
+    LOG(ERROR) << "Boot failed";
+    return 12;
+  } else if (exit_code != RunnerExitCodes::kSuccess) {
+    LOG(ERROR) << "Unknown response: " << (int) exit_code;
+    return 13;
+  }
+  LOG(INFO) << "Powerwash successful";
+  return 0;
+}
+
+} // namespace
+} // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::PowerwashCvdMain(argc, argv);
+}
diff --git a/host/commands/restart_cvd/Android.bp b/host/commands/restart_cvd/Android.bp
new file mode 100644
index 0000000..dc7a044
--- /dev/null
+++ b/host/commands/restart_cvd/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2021 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "restart_cvd",
+    srcs: [
+        "restart_cvd.cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libjsoncpp",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libcuttlefish_vm_manager",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+}
diff --git a/host/commands/restart_cvd/restart_cvd.cc b/host/commands/restart_cvd/restart_cvd.cc
new file mode 100644
index 0000000..68ff3e6
--- /dev/null
+++ b/host/commands/restart_cvd/restart_cvd.cc
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <fstream>
+#include <iomanip>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <gflags/gflags.h>
+#include <android-base/logging.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/fs/shared_select.h"
+#include "common/libs/utils/environment.h"
+#include "host/commands/run_cvd/runner_defs.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/vm_manager/vm_manager.h"
+
+DEFINE_int32(instance_num, cuttlefish::GetInstance(),
+             "Which instance to restart");
+
+DEFINE_int32(wait_for_launcher, 30,
+             "How many seconds to wait for the launcher to respond to the status "
+             "command. A value of zero means wait indefinetly");
+
+DEFINE_int32(boot_timeout, 1000, "How many seconds to wait for the device to "
+                                 "reboot.");
+
+namespace cuttlefish {
+namespace {
+
+int RestartCvdMain(int argc, char** argv) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  auto config = CuttlefishConfig::Get();
+  if (!config) {
+    LOG(ERROR) << "Failed to obtain config object";
+    return 1;
+  }
+
+  auto instance = config->ForInstance(FLAGS_instance_num);
+  auto monitor_path = instance.launcher_monitor_socket_path();
+  if (monitor_path.empty()) {
+    LOG(ERROR) << "No path to launcher monitor found";
+    return 2;
+  }
+  // This may hang if the server never picks up the connection.
+  auto monitor_socket = SharedFD::SocketLocalClient(
+      monitor_path.c_str(), false, SOCK_STREAM, FLAGS_wait_for_launcher);
+  if (!monitor_socket->IsOpen()) {
+    LOG(ERROR) << "Unable to connect to launcher monitor at " << monitor_path
+               << ": " << monitor_socket->StrError();
+    return 3;
+  }
+  auto request = LauncherAction::kRestart;
+  auto bytes_sent = monitor_socket->Send(&request, sizeof(request), 0);
+  if (bytes_sent < 0) {
+    LOG(ERROR) << "Error sending launcher monitor the status command: "
+               << monitor_socket->StrError();
+    return 4;
+  }
+  // Perform a select with a timeout to guard against launcher hanging
+  SharedFDSet read_set;
+  read_set.Set(monitor_socket);
+  struct timeval timeout = {FLAGS_wait_for_launcher, 0};
+  int selected = Select(&read_set, nullptr, nullptr,
+                        FLAGS_wait_for_launcher <= 0 ? nullptr : &timeout);
+  if (selected < 0){
+    LOG(ERROR) << "Failed communication with the launcher monitor: "
+               << strerror(errno);
+    return 5;
+  }
+  if (selected == 0) {
+    LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
+    return 6;
+  }
+  LauncherResponse response;
+  auto bytes_recv = monitor_socket->Recv(&response, sizeof(response), 0);
+  if (bytes_recv < 0) {
+    LOG(ERROR) << "Error receiving response from launcher monitor: "
+               << monitor_socket->StrError();
+    return 7;
+  }
+  LOG(INFO) << "Requesting restart";
+  if (response != LauncherResponse::kSuccess) {
+    LOG(ERROR) << "Received '" << static_cast<char>(response)
+               << "' response from launcher monitor for restart request";
+    return 8;
+  }
+  LOG(INFO) << "Waiting for device to boot up again";
+
+  read_set.Set(monitor_socket);
+  timeout = {FLAGS_boot_timeout, 0};
+  selected = Select(&read_set, nullptr, nullptr,
+                    FLAGS_boot_timeout <= 0 ? nullptr : &timeout);
+  if (selected < 0){
+    LOG(ERROR) << "Failed communication with the launcher monitor: "
+               << strerror(errno);
+    return 5;
+  }
+  if (selected == 0) {
+    LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
+    return 6;
+  }
+
+  RunnerExitCodes exit_code;
+  bytes_recv = ReadExactBinary(monitor_socket, &exit_code);
+  if (bytes_recv < 0) {
+    LOG(ERROR) << "Error in stream response: " << monitor_socket->StrError();
+    return 9;
+  } else if (bytes_recv == 0) {
+    LOG(ERROR) << "Launcher socket closed unexpectedly";
+    return 10;
+  } else if (bytes_recv != sizeof(exit_code)) {
+    LOG(ERROR) << "Launcher response was too short";
+    return 11;
+  } else if (exit_code == RunnerExitCodes::kVirtualDeviceBootFailed) {
+    LOG(ERROR) << "Boot failed";
+    return 12;
+  } else if (exit_code != RunnerExitCodes::kSuccess) {
+    LOG(ERROR) << "Unknown response: " << (int) exit_code;
+    return 13;
+  }
+  LOG(INFO) << "Restart successful";
+  return 0;
+}
+
+} // namespace
+} // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::RestartCvdMain(argc, argv);
+}
diff --git a/host/commands/run_cvd/Android.bp b/host/commands/run_cvd/Android.bp
index c338f08..09b11d5 100644
--- a/host/commands/run_cvd/Android.bp
+++ b/host/commands/run_cvd/Android.bp
@@ -13,29 +13,37 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "run_cvd",
     srcs: [
-        "kernel_args.cc",
+        "boot_state_machine.cc",
         "launch.cc",
+        "launch_adb.cpp",
+        "launch_modem.cpp",
+        "launch_streamer.cpp",
         "main.cc",
         "process_monitor.cc",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
+        "server_loop.cpp",
     ],
     shared_libs: [
         "libcuttlefish_fs",
         "libcuttlefish_utils",
+        "libcuttlefish_kernel_log_monitor_utils",
         "libbase",
-        "libnl"
+        "libjsoncpp",
+        "libnl",
     ],
     static_libs: [
         "libcuttlefish_host_config",
         "libcuttlefish_vm_manager",
         "libgflags",
-        "libxml2",
-        "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only", "cuttlefish_libicuuc"],
+    defaults: [
+        "cuttlefish_host",
+        "cuttlefish_libicuuc",
+    ],
 }
diff --git a/host/commands/run_cvd/boot_state_machine.cc b/host/commands/run_cvd/boot_state_machine.cc
new file mode 100644
index 0000000..64eb893
--- /dev/null
+++ b/host/commands/run_cvd/boot_state_machine.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/commands/run_cvd/boot_state_machine.h"
+
+#include <memory>
+#include <thread>
+
+#include "android-base/logging.h"
+#include "common/libs/fs/shared_fd.h"
+#include "host/commands/kernel_log_monitor/kernel_log_server.h"
+#include "host/commands/kernel_log_monitor/utils.h"
+#include "host/commands/run_cvd/runner_defs.h"
+
+namespace cuttlefish {
+
+CvdBootStateMachine::CvdBootStateMachine(SharedFD fg_launcher_pipe,
+                                         SharedFD reboot_notification,
+                                         SharedFD boot_events_pipe)
+    : fg_launcher_pipe_(fg_launcher_pipe),
+      reboot_notification_(reboot_notification),
+      state_(kBootStarted) {
+  boot_event_handler_ = std::thread([this, boot_events_pipe]() {
+    while (true) {
+      SharedFDSet fd_set;
+      fd_set.Set(boot_events_pipe);
+      int result = Select(&fd_set, nullptr, nullptr, nullptr);
+      if (result < 0) {
+        PLOG(FATAL) << "Failed to call Select";
+        return;
+      }
+      if (!fd_set.IsSet(boot_events_pipe)) {
+        continue;
+      }
+      auto sent_code = OnBootEvtReceived(boot_events_pipe);
+      if (sent_code) {
+        break;
+      }
+    }
+  });
+}
+
+CvdBootStateMachine::~CvdBootStateMachine() { boot_event_handler_.join(); }
+
+// Returns true if the machine is left in a final state
+bool CvdBootStateMachine::OnBootEvtReceived(SharedFD boot_events_pipe) {
+  std::optional<monitor::ReadEventResult> read_result =
+      monitor::ReadEvent(boot_events_pipe);
+  if (!read_result) {
+    LOG(ERROR) << "Failed to read a complete kernel log boot event.";
+    state_ |= kGuestBootFailed;
+    return MaybeWriteNotification();
+  }
+
+  if (read_result->event == monitor::Event::BootCompleted) {
+    LOG(INFO) << "Virtual device booted successfully";
+    state_ |= kGuestBootCompleted;
+  } else if (read_result->event == monitor::Event::BootFailed) {
+    LOG(ERROR) << "Virtual device failed to boot";
+    state_ |= kGuestBootFailed;
+  }  // Ignore the other signals
+
+  return MaybeWriteNotification();
+}
+
+bool CvdBootStateMachine::BootCompleted() const {
+  return state_ & kGuestBootCompleted;
+}
+
+bool CvdBootStateMachine::BootFailed() const {
+  return state_ & kGuestBootFailed;
+}
+
+void CvdBootStateMachine::SendExitCode(RunnerExitCodes exit_code, SharedFD fd) {
+  fd->Write(&exit_code, sizeof(exit_code));
+  // The foreground process will exit after receiving the exit code, if we try
+  // to write again we'll get a SIGPIPE
+  fd->Close();
+}
+
+bool CvdBootStateMachine::MaybeWriteNotification() {
+  std::vector<SharedFD> fds = {reboot_notification_, fg_launcher_pipe_};
+  for (auto& fd : fds) {
+    if (fd->IsOpen()) {
+      if (BootCompleted()) {
+        SendExitCode(RunnerExitCodes::kSuccess, fd);
+      } else if (state_ & kGuestBootFailed) {
+        SendExitCode(RunnerExitCodes::kVirtualDeviceBootFailed, fd);
+      }
+    }
+  }
+  // Either we sent the code before or just sent it, in any case the state is
+  // final
+  return BootCompleted() || (state_ & kGuestBootFailed);
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/boot_state_machine.h b/host/commands/run_cvd/boot_state_machine.h
new file mode 100644
index 0000000..0d02e72
--- /dev/null
+++ b/host/commands/run_cvd/boot_state_machine.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 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 <memory>
+#include <thread>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/commands/run_cvd/runner_defs.h"
+
+namespace cuttlefish {
+
+// Maintains the state of the boot process, once a final state is reached
+// (success or failure) it sends the appropriate exit code to the foreground
+// launcher process
+class CvdBootStateMachine {
+ public:
+  CvdBootStateMachine(SharedFD fg_launcher_pipe, SharedFD reboot_notification,
+                      SharedFD boot_events_pipe);
+  ~CvdBootStateMachine();
+
+ private:
+  // Returns true if the machine is left in a final state
+  bool OnBootEvtReceived(SharedFD boot_events_pipe);
+  bool BootCompleted() const;
+  bool BootFailed() const;
+
+  void SendExitCode(RunnerExitCodes exit_code, SharedFD fd);
+  bool MaybeWriteNotification();
+
+  std::thread boot_event_handler_;
+  SharedFD fg_launcher_pipe_;
+  SharedFD reboot_notification_;
+  int state_;
+  static const int kBootStarted = 0;
+  static const int kGuestBootCompleted = 1 << 0;
+  static const int kGuestBootFailed = 1 << 1;
+};
+
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/kernel_args.cc b/host/commands/run_cvd/kernel_args.cc
deleted file mode 100644
index 308ef8a..0000000
--- a/host/commands/run_cvd/kernel_args.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "host/commands/run_cvd/kernel_args.h"
-
-#include <array>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "common/libs/utils/files.h"
-#include "host/commands/run_cvd/launch.h"
-#include "host/commands/run_cvd/runner_defs.h"
-#include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/vm_manager/vm_manager.h"
-
-template<typename T>
-static void AppendVector(std::vector<T>* destination, const std::vector<T>& source) {
-  destination->insert(destination->end(), source.begin(), source.end());
-}
-
-template<typename S, typename T>
-static std::string concat(const S& s, const T& t) {
-  std::ostringstream os;
-  os << s << t;
-  return os.str();
-}
-
-static std::string mac_to_str(const std::array<unsigned char, 6>& mac) {
-  std::ostringstream stream;
-  stream << std::hex << (int) mac[0];
-  for (int i = 1; i < 6; i++) {
-    stream << ":" << std::hex << (int) mac[i];
-  }
-  return stream.str();
-}
-
-std::vector<std::string> KernelCommandLineFromConfig(const vsoc::CuttlefishConfig& config) {
-  auto instance = config.ForDefaultInstance();
-  std::vector<std::string> kernel_cmdline;
-
-  AppendVector(&kernel_cmdline, config.boot_image_kernel_cmdline());
-  AppendVector(&kernel_cmdline,
-               vm_manager::VmManager::ConfigureGpuMode(config.vm_manager(), config.gpu_mode()));
-  AppendVector(&kernel_cmdline, vm_manager::VmManager::ConfigureBootDevices(config.vm_manager()));
-
-  kernel_cmdline.push_back(concat("androidboot.serialno=", instance.serial_number()));
-  kernel_cmdline.push_back(concat("androidboot.lcd_density=", config.dpi()));
-  if (config.logcat_mode() == cvd::kLogcatVsockMode) {
-  }
-  kernel_cmdline.push_back(concat(
-      "androidboot.setupwizard_mode=", config.setupwizard_mode()));
-  if (!config.use_bootloader()) {
-    std::string slot_suffix;
-    if (config.boot_slot().empty()) {
-      slot_suffix = "_a";
-    } else {
-      slot_suffix = "_" + config.boot_slot();
-    }
-    kernel_cmdline.push_back(concat("androidboot.slot_suffix=", slot_suffix));
-  }
-  kernel_cmdline.push_back(concat("loop.max_part=", config.loop_max_part()));
-  if (config.guest_enforce_security()) {
-    kernel_cmdline.push_back("enforcing=1");
-  } else {
-    kernel_cmdline.push_back("enforcing=0");
-    kernel_cmdline.push_back("androidboot.selinux=permissive");
-  }
-  if (config.guest_audit_security()) {
-    kernel_cmdline.push_back("audit=1");
-  } else {
-    kernel_cmdline.push_back("audit=0");
-  }
-  if (config.guest_force_normal_boot()) {
-    kernel_cmdline.push_back("androidboot.force_normal_boot=1");
-  }
-
-  if (config.enable_vehicle_hal_grpc_server() && instance.vehicle_hal_server_port() &&
-      cvd::FileExists(config.vehicle_hal_grpc_server_binary())) {
-    constexpr int vehicle_hal_server_cid = 2;
-    kernel_cmdline.push_back(concat("androidboot.vendor.vehiclehal.server.cid=", vehicle_hal_server_cid));
-    kernel_cmdline.push_back(concat("androidboot.vendor.vehiclehal.server.port=", instance.vehicle_hal_server_port()));
-  }
-
-  // TODO(b/158131610): Set this in crosvm instead
-  kernel_cmdline.push_back(concat("androidboot.wifi_mac_address=",
-                                  mac_to_str(instance.wifi_mac_address())));
-
-  AppendVector(&kernel_cmdline, config.extra_kernel_cmdline());
-
-  return kernel_cmdline;
-}
-
-std::vector<std::string> KernelCommandLineFromStreamer(
-    const StreamerLaunchResult& streamer_launch) {
-  std::vector<std::string> kernel_args;
-  if (streamer_launch.frames_server_vsock_port) {
-    kernel_args.push_back(concat("androidboot.vsock_frames_port=",
-                                 *streamer_launch.frames_server_vsock_port));
-  }
-  if (streamer_launch.touch_server_vsock_port) {
-    kernel_args.push_back(concat("androidboot.vsock_touch_port=",
-                                 *streamer_launch.touch_server_vsock_port));
-  }
-  if (streamer_launch.keyboard_server_vsock_port) {
-    kernel_args.push_back(concat("androidboot.vsock_keyboard_port=",
-                                 *streamer_launch.keyboard_server_vsock_port));
-  }
-  return kernel_args;
-}
-
-std::vector<std::string> KernelCommandLineFromTombstone(const TombstoneReceiverPorts& tombstone) {
-  if (!tombstone.server_vsock_port) {
-    return { "androidboot.tombstone_transmit=0" };
-  }
-  return {
-    "androidboot.tombstone_transmit=1",
-    concat("androidboot.vsock_tombstone_port=", *tombstone.server_vsock_port),
-  };
-}
-
-std::vector<std::string> KernelCommandLineFromConfigServer(const ConfigServerPorts& config_server) {
-  if (!config_server.server_vsock_port) {
-    return {};
-  }
-  return {
-    concat("androidboot.cuttlefish_config_server_port=", *config_server.server_vsock_port),
-  };
-}
-
-std::vector<std::string> KernelCommandLineFromLogcatServer(const LogcatServerPorts& logcat_server) {
-  if (!logcat_server.server_vsock_port) {
-    return {};
-  }
-  return {
-    concat("androidboot.vsock_logcat_port=", *logcat_server.server_vsock_port),
-  };
-}
diff --git a/host/commands/run_cvd/kernel_args.h b/host/commands/run_cvd/kernel_args.h
deleted file mode 100644
index b5d1595..0000000
--- a/host/commands/run_cvd/kernel_args.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 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>
-#include <vector>
-
-#include "host/commands/run_cvd/launch.h"
-#include "host/libs/config/cuttlefish_config.h"
-
-std::vector<std::string> KernelCommandLineFromConfig(const vsoc::CuttlefishConfig& config);
-std::vector<std::string> KernelCommandLineFromStreamer(const StreamerLaunchResult& vnc_config);
-std::vector<std::string> KernelCommandLineFromTombstone(const TombstoneReceiverPorts& tombstone);
-std::vector<std::string> KernelCommandLineFromConfigServer(const ConfigServerPorts& config_server);
-std::vector<std::string> KernelCommandLineFromLogcatServer(const LogcatServerPorts& config_server);
diff --git a/host/commands/run_cvd/launch.cc b/host/commands/run_cvd/launch.cc
index 5ae66a9..a6184b2 100644
--- a/host/commands/run_cvd/launch.cc
+++ b/host/commands/run_cvd/launch.cc
@@ -1,140 +1,46 @@
+//
+// Copyright (C) 2019 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.
+
 #include "host/commands/run_cvd/launch.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <glog/logging.h>
+#include <android-base/logging.h>
+#include <utility>
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/files.h"
-#include "common/libs/utils/size_utils.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/commands/run_cvd/process_monitor.h"
 #include "host/commands/run_cvd/runner_defs.h"
-#include "host/commands/run_cvd/pre_launch_initializers.h"
-#include "host/libs/vm_manager/crosvm_manager.h"
-#include "host/libs/vm_manager/qemu_manager.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/known_paths.h"
 
-using cvd::RunnerExitCodes;
-using cvd::MonitorEntry;
+namespace cuttlefish {
 
 namespace {
 
-std::string GetAdbConnectorTcpArg(const vsoc::CuttlefishConfig& config) {
-  auto instance = config.ForDefaultInstance();
-  return std::string{"127.0.0.1:"} + std::to_string(instance.host_port());
+template <typename T>
+std::vector<T> single_element_emplace(T&& element) {
+  std::vector<T> vec;
+  vec.emplace_back(std::move(element));
+  return vec;
 }
 
-std::string GetAdbConnectorVsockArg(const vsoc::CuttlefishConfig& config) {
-  auto instance = config.ForDefaultInstance();
-  return std::string{"vsock:"}
-      + std::to_string(instance.vsock_guest_cid())
-      + std::string{":5555"};
-}
+}  // namespace
 
-bool AdbModeEnabled(const vsoc::CuttlefishConfig& config, vsoc::AdbMode mode) {
-  return config.adb_mode().count(mode) > 0;
-}
-
-bool AdbVsockTunnelEnabled(const vsoc::CuttlefishConfig& config) {
-  auto instance = config.ForDefaultInstance();
-  return instance.vsock_guest_cid() > 2
-      && AdbModeEnabled(config, vsoc::AdbMode::VsockTunnel);
-}
-
-bool AdbVsockHalfTunnelEnabled(const vsoc::CuttlefishConfig& config) {
-  auto instance = config.ForDefaultInstance();
-  return instance.vsock_guest_cid() > 2
-      && AdbModeEnabled(config, vsoc::AdbMode::VsockHalfTunnel);
-}
-
-bool AdbTcpConnectorEnabled(const vsoc::CuttlefishConfig& config) {
-  bool vsock_tunnel = AdbVsockTunnelEnabled(config);
-  bool vsock_half_tunnel = AdbVsockHalfTunnelEnabled(config);
-  return config.run_adb_connector() && (vsock_tunnel || vsock_half_tunnel);
-}
-
-bool AdbVsockConnectorEnabled(const vsoc::CuttlefishConfig& config) {
-  return config.run_adb_connector()
-      && AdbModeEnabled(config, vsoc::AdbMode::NativeVsock);
-}
-
-cvd::OnSocketReadyCb GetOnSubprocessExitCallback(
-    const vsoc::CuttlefishConfig& config) {
-  if (config.restart_subprocesses()) {
-    return cvd::ProcessMonitor::RestartOnExitCb;
-  } else {
-    return cvd::ProcessMonitor::DoNotMonitorCb;
-  }
-}
-
-cvd::SharedFD CreateUnixInputServer(const std::string& path) {
-  auto server = cvd::SharedFD::SocketLocalServer(path.c_str(), false, SOCK_STREAM, 0666);
-  if (!server->IsOpen()) {
-    LOG(ERROR) << "Unable to create unix input server: "
-               << server->StrError();
-    return cvd::SharedFD();
-  }
-  return server;
-}
-
-// Creates the frame and input sockets and add the relevant arguments to the vnc
-// server and webrtc commands
-StreamerLaunchResult CreateStreamerServers(cvd::Command* cmd,
-                                           const vsoc::CuttlefishConfig& config) {
-  StreamerLaunchResult server_ret;
-  cvd::SharedFD touch_server;
-  cvd::SharedFD keyboard_server;
-
-  auto instance = config.ForDefaultInstance();
-  if (config.vm_manager() == vm_manager::QemuManager::name()) {
-    cmd->AddParameter("-write_virtio_input");
-
-    touch_server = cvd::SharedFD::VsockServer(SOCK_STREAM);
-    server_ret.touch_server_vsock_port = touch_server->VsockServerPort();
-
-    keyboard_server = cvd::SharedFD::VsockServer(SOCK_STREAM);
-    server_ret.keyboard_server_vsock_port = keyboard_server->VsockServerPort();
-  } else {
-    touch_server = CreateUnixInputServer(instance.touch_socket_path());
-    keyboard_server = CreateUnixInputServer(instance.keyboard_socket_path());
-  }
-  if (!touch_server->IsOpen()) {
-    LOG(ERROR) << "Could not open touch server: " << touch_server->StrError();
-    return {};
-  }
-  cmd->AddParameter("-touch_fd=", touch_server);
-
-  if (!keyboard_server->IsOpen()) {
-    LOG(ERROR) << "Could not open keyboard server: " << keyboard_server->StrError();
-    return {};
-  }
-  cmd->AddParameter("-keyboard_fd=", keyboard_server);
-
-  cvd::SharedFD frames_server;
-  if (config.gpu_mode() == vsoc::kGpuModeDrmVirgl ||
-      config.gpu_mode() == vsoc::kGpuModeGfxStream) {
-    frames_server = CreateUnixInputServer(instance.frames_socket_path());
-  } else {
-    frames_server = cvd::SharedFD::VsockServer(SOCK_STREAM);
-    server_ret.frames_server_vsock_port = frames_server->VsockServerPort();
-  }
-  if (!frames_server->IsOpen()) {
-    LOG(ERROR) << "Could not open frames server: " << frames_server->StrError();
-    return {};
-  }
-  cmd->AddParameter("-frame_server_fd=", frames_server);
-  return server_ret;
-}
-
-} // namespace
-
-bool LogcatReceiverEnabled(const vsoc::CuttlefishConfig& config) {
-  return config.logcat_mode() == cvd::kLogcatVsockMode;
-}
-
-std::vector<cvd::SharedFD> LaunchKernelLogMonitor(
-    const vsoc::CuttlefishConfig& config,
-    cvd::ProcessMonitor* process_monitor,
-    unsigned int number_of_event_pipes) {
+KernelLogMonitorData LaunchKernelLogMonitor(
+    const CuttlefishConfig& config, unsigned int number_of_event_pipes) {
   auto instance = config.ForDefaultInstance();
   auto log_name = instance.kernel_log_pipe_name();
   if (mkfifo(log_name.c_str(), 0600) != 0) {
@@ -143,83 +49,101 @@
     return {};
   }
 
-  cvd::SharedFD pipe;
+  SharedFD pipe;
   // Open the pipe here (from the launcher) to ensure the pipe is not deleted
   // due to the usage counters in the kernel reaching zero. If this is not done
   // and the kernel_log_monitor crashes for some reason the VMM may get SIGPIPE.
-  pipe = cvd::SharedFD::Open(log_name.c_str(), O_RDWR);
-  cvd::Command command(config.kernel_log_monitor_binary());
+  pipe = SharedFD::Open(log_name.c_str(), O_RDWR);
+  Command command(KernelLogMonitorBinary());
   command.AddParameter("-log_pipe_fd=", pipe);
 
-  std::vector<cvd::SharedFD> ret;
+  KernelLogMonitorData ret;
 
   if (number_of_event_pipes > 0) {
-    auto param_builder = command.GetParameterBuilder();
-    param_builder << "-subscriber_fds=";
+    command.AddParameter("-subscriber_fds=");
     for (unsigned int i = 0; i < number_of_event_pipes; ++i) {
-      cvd::SharedFD event_pipe_write_end, event_pipe_read_end;
-      if (!cvd::SharedFD::Pipe(&event_pipe_read_end, &event_pipe_write_end)) {
-        LOG(ERROR) << "Unable to create boot events pipe: " << strerror(errno);
+      SharedFD event_pipe_write_end, event_pipe_read_end;
+      if (!SharedFD::Pipe(&event_pipe_read_end, &event_pipe_write_end)) {
+        LOG(ERROR) << "Unable to create kernel log events pipe: " << strerror(errno);
         std::exit(RunnerExitCodes::kPipeIOError);
       }
       if (i > 0) {
-        param_builder << ",";
+        command.AppendToLastParameter(",");
       }
-      param_builder << event_pipe_write_end;
-      ret.push_back(event_pipe_read_end);
+      command.AppendToLastParameter(event_pipe_write_end);
+      ret.pipes.push_back(event_pipe_read_end);
     }
-    param_builder.Build();
   }
 
-  process_monitor->StartSubprocess(std::move(command),
-                                   GetOnSubprocessExitCallback(config));
+  ret.commands.emplace_back(std::move(command));
 
   return ret;
 }
 
-LogcatServerPorts LaunchLogcatReceiverIfEnabled(const vsoc::CuttlefishConfig& config,
-                                                cvd::ProcessMonitor* process_monitor) {
-  if (!LogcatReceiverEnabled(config)) {
+std::vector<Command> LaunchRootCanal(const CuttlefishConfig& config) {
+  if (!config.enable_host_bluetooth()) {
     return {};
   }
-  auto socket = cvd::SharedFD::VsockServer(SOCK_STREAM);
-  if (!socket->IsOpen()) {
-    LOG(ERROR) << "Unable to create logcat server socket: "
-               << socket->StrError();
-    std::exit(RunnerExitCodes::kLogcatServerError);
-  }
-  cvd::Command cmd(config.logcat_receiver_binary());
-  cmd.AddParameter("-server_fd=", socket);
-  process_monitor->StartSubprocess(std::move(cmd),
-                                   GetOnSubprocessExitCallback(config));
-  return { socket->VsockServerPort() };
+
+  auto instance = config.ForDefaultInstance();
+  Command command(RootCanalBinary());
+
+  // Test port
+  command.AddParameter(instance.rootcanal_test_port());
+  // HCI server port
+  command.AddParameter(instance.rootcanal_hci_port());
+  // Link server port
+  command.AddParameter(instance.rootcanal_link_port());
+  // Bluetooth controller properties file
+  command.AddParameter("--controller_properties_file=",
+                       instance.rootcanal_config_file());
+  // Default commands file
+  command.AddParameter("--default_commands_file=",
+                       instance.rootcanal_default_commands_file());
+
+  return single_element_emplace(std::move(command));
 }
 
-ConfigServerPorts LaunchConfigServer(const vsoc::CuttlefishConfig& config,
-                                     cvd::ProcessMonitor* process_monitor) {
-  auto socket = cvd::SharedFD::VsockServer(SOCK_STREAM);
+std::vector<Command> LaunchLogcatReceiver(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  auto log_name = instance.logcat_pipe_name();
+  if (mkfifo(log_name.c_str(), 0600) != 0) {
+    LOG(ERROR) << "Unable to create named pipe at " << log_name << ": "
+               << strerror(errno);
+    return {};
+  }
+
+  SharedFD pipe;
+  // Open the pipe here (from the launcher) to ensure the pipe is not deleted
+  // due to the usage counters in the kernel reaching zero. If this is not done
+  // and the logcat_receiver crashes for some reason the VMM may get SIGPIPE.
+  pipe = SharedFD::Open(log_name.c_str(), O_RDWR);
+  Command command(LogcatReceiverBinary());
+  command.AddParameter("-log_pipe_fd=", pipe);
+
+  return single_element_emplace(std::move(command));
+}
+
+std::vector<Command> LaunchConfigServer(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  auto port = instance.config_server_port();
+  auto socket = SharedFD::VsockServer(port, SOCK_STREAM);
   if (!socket->IsOpen()) {
     LOG(ERROR) << "Unable to create configuration server socket: "
                << socket->StrError();
     std::exit(RunnerExitCodes::kConfigServerError);
   }
-  cvd::Command cmd(config.config_server_binary());
+  Command cmd(ConfigServerBinary());
   cmd.AddParameter("-server_fd=", socket);
-  process_monitor->StartSubprocess(std::move(cmd),
-                                   GetOnSubprocessExitCallback(config));
-  return { socket->VsockServerPort() };
+  return single_element_emplace(std::move(cmd));
 }
 
-TombstoneReceiverPorts LaunchTombstoneReceiverIfEnabled(
-    const vsoc::CuttlefishConfig& config, cvd::ProcessMonitor* process_monitor) {
-  if (!config.enable_tombstone_receiver()) {
-    return {};
-  }
+std::vector<Command> LaunchTombstoneReceiver(const CuttlefishConfig& config) {
   auto instance = config.ForDefaultInstance();
 
   std::string tombstoneDir = instance.PerInstancePath("tombstones");
-  if (!cvd::DirectoryExists(tombstoneDir.c_str())) {
-    LOG(INFO) << "Setting up " << tombstoneDir;
+  if (!DirectoryExists(tombstoneDir.c_str())) {
+    LOG(DEBUG) << "Setting up " << tombstoneDir;
     if (mkdir(tombstoneDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) <
         0) {
       LOG(ERROR) << "Failed to create tombstone directory: " << tombstoneDir
@@ -229,139 +153,221 @@
     }
   }
 
-  auto socket = cvd::SharedFD::VsockServer(SOCK_STREAM);
+  auto port = instance.tombstone_receiver_port();
+  auto socket = SharedFD::VsockServer(port, SOCK_STREAM);
   if (!socket->IsOpen()) {
     LOG(ERROR) << "Unable to create tombstone server socket: "
                << socket->StrError();
     std::exit(RunnerExitCodes::kTombstoneServerError);
     return {};
   }
-  cvd::Command cmd(config.tombstone_receiver_binary());
+  Command cmd(TombstoneReceiverBinary());
   cmd.AddParameter("-server_fd=", socket);
   cmd.AddParameter("-tombstone_dir=", tombstoneDir);
 
-  process_monitor->StartSubprocess(std::move(cmd),
-                                   GetOnSubprocessExitCallback(config));
-  return { socket->VsockServerPort() };
+  return single_element_emplace(std::move(cmd));
 }
 
-StreamerLaunchResult LaunchVNCServer(
-    const vsoc::CuttlefishConfig& config,
-    cvd::ProcessMonitor* process_monitor,
-    std::function<bool(MonitorEntry*)> callback) {
+std::vector<Command> LaunchMetrics() {
+  return single_element_emplace(Command(MetricsBinary()));
+}
+
+std::vector<Command> LaunchGnssGrpcProxyServerIfEnabled(
+    const CuttlefishConfig& config) {
+  if (!config.enable_gnss_grpc_proxy() || !FileExists(GnssGrpcProxyBinary())) {
+    return {};
+  }
+
+  Command gnss_grpc_proxy_cmd(GnssGrpcProxyBinary());
   auto instance = config.ForDefaultInstance();
-  // Launch the vnc server, don't wait for it to complete
-  auto port_options = "-port=" + std::to_string(instance.vnc_server_port());
-  cvd::Command vnc_server(config.vnc_server_binary());
-  vnc_server.AddParameter(port_options);
 
-  auto server_ret = CreateStreamerServers(&vnc_server, config);
+  auto gnss_in_pipe_name = instance.gnss_in_pipe_name();
+  if (mkfifo(gnss_in_pipe_name.c_str(), 0600) != 0) {
+    auto error = errno;
+    LOG(ERROR) << "Failed to create gnss input fifo for crosvm: "
+               << strerror(error);
+    return {};
+  }
 
-  process_monitor->StartSubprocess(std::move(vnc_server), callback);
-  server_ret.launched = true;
-  return server_ret;
+  auto gnss_out_pipe_name = instance.gnss_out_pipe_name();
+  if (mkfifo(gnss_out_pipe_name.c_str(), 0660) != 0) {
+    auto error = errno;
+    LOG(ERROR) << "Failed to create gnss output fifo for crosvm: "
+               << strerror(error);
+    return {};
+  }
+
+  // These fds will only be read from or written to, but open them with
+  // read and write access to keep them open in case the subprocesses exit
+  SharedFD gnss_grpc_proxy_in_wr =
+      SharedFD::Open(gnss_in_pipe_name.c_str(), O_RDWR);
+  if (!gnss_grpc_proxy_in_wr->IsOpen()) {
+    LOG(ERROR) << "Failed to open gnss_grpc_proxy input fifo for writes: "
+               << gnss_grpc_proxy_in_wr->StrError();
+    return {};
+  }
+
+  SharedFD gnss_grpc_proxy_out_rd =
+      SharedFD::Open(gnss_out_pipe_name.c_str(), O_RDWR);
+  if (!gnss_grpc_proxy_out_rd->IsOpen()) {
+    LOG(ERROR) << "Failed to open gnss_grpc_proxy output fifo for reads: "
+               << gnss_grpc_proxy_out_rd->StrError();
+    return {};
+  }
+
+  const unsigned gnss_grpc_proxy_server_port =
+      instance.gnss_grpc_proxy_server_port();
+  gnss_grpc_proxy_cmd.AddParameter("--gnss_in_fd=", gnss_grpc_proxy_in_wr);
+  gnss_grpc_proxy_cmd.AddParameter("--gnss_out_fd=", gnss_grpc_proxy_out_rd);
+  gnss_grpc_proxy_cmd.AddParameter("--gnss_grpc_port=",
+                                   gnss_grpc_proxy_server_port);
+  if (!instance.gnss_file_path().empty()) {
+    // If path is provided, proxy will start as local mode.
+    gnss_grpc_proxy_cmd.AddParameter("--gnss_file_path=",
+                                     instance.gnss_file_path());
+  }
+  return single_element_emplace(std::move(gnss_grpc_proxy_cmd));
 }
 
-void LaunchAdbConnectorIfEnabled(cvd::ProcessMonitor* process_monitor,
-                                 const vsoc::CuttlefishConfig& config,
-                                 cvd::SharedFD adbd_events_pipe) {
-  cvd::Command adb_connector(config.adb_connector_binary());
-  adb_connector.AddParameter("-adbd_events_fd=", adbd_events_pipe);
-  std::set<std::string> addresses;
-
-  if (AdbTcpConnectorEnabled(config)) {
-    addresses.insert(GetAdbConnectorTcpArg(config));
-  }
-  if (AdbVsockConnectorEnabled(config)) {
-    addresses.insert(GetAdbConnectorVsockArg(config));
-  }
-
-  if (addresses.size() > 0) {
-    std::string address_arg = "--addresses=";
-    for (auto& arg : addresses) {
-      address_arg += arg + ",";
-    }
-    address_arg.pop_back();
-    adb_connector.AddParameter(address_arg);
-    process_monitor->StartSubprocess(std::move(adb_connector),
-                                     GetOnSubprocessExitCallback(config));
-  }
-}
-
-StreamerLaunchResult LaunchWebRTC(cvd::ProcessMonitor* process_monitor,
-                                  const vsoc::CuttlefishConfig& config) {
-  cvd::Command webrtc(config.webrtc_binary());
-
-  if (!config.webrtc_certs_dir().empty()) {
-      webrtc.AddParameter("--certs_dir=", config.webrtc_certs_dir());
-  }
-
-  webrtc.AddParameter("--http_server_port=", vsoc::ForCurrentInstance(8443));
-  webrtc.AddParameter("--public_ip=", config.webrtc_public_ip());
-  webrtc.AddParameter("--assets_dir=", config.webrtc_assets_dir());
-
-  auto server_ret = CreateStreamerServers(&webrtc, config);
-
-  if (config.webrtc_enable_adb_websocket()) {
-      auto instance = config.ForDefaultInstance();
-      webrtc.AddParameter("--adb=", instance.adb_ip_and_port());
-  }
-
-  process_monitor->StartSubprocess(std::move(webrtc),
-                                   GetOnSubprocessExitCallback(config));
-  server_ret.launched = true;
-
-  return server_ret;
-}
-
-void LaunchSocketVsockProxyIfEnabled(cvd::ProcessMonitor* process_monitor,
-                                 const vsoc::CuttlefishConfig& config) {
+std::vector<Command> LaunchBluetoothConnector(const CuttlefishConfig& config) {
   auto instance = config.ForDefaultInstance();
-  if (AdbVsockTunnelEnabled(config)) {
-    cvd::Command adb_tunnel(config.socket_vsock_proxy_binary());
-    adb_tunnel.AddParameter("--server=tcp");
-    adb_tunnel.AddParameter("--vsock_port=6520");
-    adb_tunnel.AddParameter(
-        std::string{"--tcp_port="} + std::to_string(instance.host_port()));
-    adb_tunnel.AddParameter(std::string{"--vsock_cid="} +
-                            std::to_string(instance.vsock_guest_cid()));
-    process_monitor->StartSubprocess(std::move(adb_tunnel),
-                                     GetOnSubprocessExitCallback(config));
-  }
-  if (AdbVsockHalfTunnelEnabled(config)) {
-    cvd::Command adb_tunnel(config.socket_vsock_proxy_binary());
-    adb_tunnel.AddParameter("--server=tcp");
-    adb_tunnel.AddParameter("--vsock_port=5555");
-    adb_tunnel.AddParameter(
-        std::string{"--tcp_port="} + std::to_string(instance.host_port()));
-    adb_tunnel.AddParameter(std::string{"--vsock_cid="} +
-                            std::to_string(instance.vsock_guest_cid()));
-    process_monitor->StartSubprocess(std::move(adb_tunnel),
-                                     GetOnSubprocessExitCallback(config));
-  }
-}
-
-void LaunchVerhicleHalServerIfEnabled(const vsoc::CuttlefishConfig& config,
-                                                        cvd::ProcessMonitor* process_monitor) {
-    if (!config.enable_vehicle_hal_grpc_server() &&
-        !cvd::FileExists(config.vehicle_hal_grpc_server_binary())) {
-        return;
+  std::vector<std::string> fifo_paths = {
+      instance.PerInstanceInternalPath("bt_fifo_vm.in"),
+      instance.PerInstanceInternalPath("bt_fifo_vm.out"),
+  };
+  std::vector<SharedFD> fifos;
+  for (const auto& path : fifo_paths) {
+    unlink(path.c_str());
+    if (mkfifo(path.c_str(), 0660) < 0) {
+      PLOG(ERROR) << "Could not create " << path;
+      return {};
     }
+    auto fd = SharedFD::Open(path, O_RDWR);
+    if (!fd->IsOpen()) {
+      LOG(ERROR) << "Could not open " << path << ": " << fd->StrError();
+      return {};
+    }
+    fifos.push_back(fd);
+  }
 
-    cvd::Command grpc_server(config.vehicle_hal_grpc_server_binary());
-    auto instance = config.ForDefaultInstance();
-
-    const unsigned vhal_server_cid = 2;
-    const unsigned vhal_server_port = instance.vehicle_hal_server_port();
-    const std::string vhal_server_power_state_file =
-        cvd::AbsolutePath(instance.PerInstancePath("power_state"));
-    const std::string vhal_server_power_state_socket =
-        cvd::AbsolutePath(instance.PerInstancePath("power_state_socket"));
-
-    grpc_server.AddParameter("--server_cid=", vhal_server_cid);
-    grpc_server.AddParameter("--server_port=", vhal_server_port);
-    grpc_server.AddParameter("--power_state_file=", vhal_server_power_state_file);
-    grpc_server.AddParameter("--power_state_socket=", vhal_server_power_state_socket);
-    process_monitor->StartSubprocess(std::move(grpc_server),
-                                     GetOnSubprocessExitCallback(config));
+  Command command(DefaultHostArtifactsPath("bin/bt_connector"));
+  command.AddParameter("-bt_out=", fifos[0]);
+  command.AddParameter("-bt_in=", fifos[1]);
+  command.AddParameter("-hci_port=", instance.rootcanal_hci_port());
+  command.AddParameter("-link_port=", instance.rootcanal_link_port());
+  command.AddParameter("-test_port=", instance.rootcanal_test_port());
+  return single_element_emplace(std::move(command));
 }
+
+std::vector<Command> LaunchSecureEnvironment(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  std::vector<std::string> fifo_paths = {
+    instance.PerInstanceInternalPath("keymaster_fifo_vm.in"),
+    instance.PerInstanceInternalPath("keymaster_fifo_vm.out"),
+    instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
+    instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
+  };
+  std::vector<SharedFD> fifos;
+  for (const auto& path : fifo_paths) {
+    unlink(path.c_str());
+    if (mkfifo(path.c_str(), 0600) < 0) {
+      PLOG(ERROR) << "Could not create " << path;
+      return {};
+    }
+    auto fd = SharedFD::Open(path, O_RDWR);
+    if (!fd->IsOpen()) {
+      LOG(ERROR) << "Could not open " << path << ": " << fd->StrError();
+      return {};
+    }
+    fifos.push_back(fd);
+  }
+
+  Command command(HostBinaryPath("secure_env"));
+  command.AddParameter("-keymaster_fd_out=", fifos[0]);
+  command.AddParameter("-keymaster_fd_in=", fifos[1]);
+  command.AddParameter("-gatekeeper_fd_out=", fifos[2]);
+  command.AddParameter("-gatekeeper_fd_in=", fifos[3]);
+
+  const auto& secure_hals = config.secure_hals();
+  bool secure_keymint = secure_hals.count(SecureHal::Keymint) > 0;
+  command.AddParameter("-keymint_impl=", secure_keymint ? "tpm" : "software");
+  bool secure_gatekeeper = secure_hals.count(SecureHal::Gatekeeper) > 0;
+  auto gatekeeper_impl = secure_gatekeeper ? "tpm" : "software";
+  command.AddParameter("-gatekeeper_impl=", gatekeeper_impl);
+
+  return single_element_emplace(std::move(command));
+}
+
+std::vector<Command> LaunchVehicleHalServerIfEnabled(
+    const CuttlefishConfig& config) {
+  if (!config.enable_vehicle_hal_grpc_server() ||
+    !FileExists(config.vehicle_hal_grpc_server_binary())) {
+    return {};
+  }
+
+  Command grpc_server(config.vehicle_hal_grpc_server_binary());
+  auto instance = config.ForDefaultInstance();
+
+  const unsigned vhal_server_cid = 2;
+  const unsigned vhal_server_port = instance.vehicle_hal_server_port();
+  const std::string vhal_server_power_state_file =
+      AbsolutePath(instance.PerInstancePath("power_state"));
+  const std::string vhal_server_power_state_socket =
+      AbsolutePath(instance.PerInstancePath("power_state_socket"));
+
+  grpc_server.AddParameter("--server_cid=", vhal_server_cid);
+  grpc_server.AddParameter("--server_port=", vhal_server_port);
+  grpc_server.AddParameter("--power_state_file=", vhal_server_power_state_file);
+  grpc_server.AddParameter("--power_state_socket=", vhal_server_power_state_socket);
+  return single_element_emplace(std::move(grpc_server));
+}
+
+std::vector<Command> LaunchConsoleForwarderIfEnabled(
+    const CuttlefishConfig& config) {
+  if (!config.console()) {
+    return {};
+  }
+
+  Command console_forwarder_cmd(ConsoleForwarderBinary());
+  auto instance = config.ForDefaultInstance();
+
+  auto console_in_pipe_name = instance.console_in_pipe_name();
+  if (mkfifo(console_in_pipe_name.c_str(), 0600) != 0) {
+    auto error = errno;
+    LOG(ERROR) << "Failed to create console input fifo for crosvm: "
+               << strerror(error);
+    return {};
+  }
+
+  auto console_out_pipe_name = instance.console_out_pipe_name();
+  if (mkfifo(console_out_pipe_name.c_str(), 0660) != 0) {
+    auto error = errno;
+    LOG(ERROR) << "Failed to create console output fifo for crosvm: "
+               << strerror(error);
+    return {};
+  }
+
+  // These fds will only be read from or written to, but open them with
+  // read and write access to keep them open in case the subprocesses exit
+  SharedFD console_forwarder_in_wr =
+      SharedFD::Open(console_in_pipe_name.c_str(), O_RDWR);
+  if (!console_forwarder_in_wr->IsOpen()) {
+    LOG(ERROR) << "Failed to open console_forwarder input fifo for writes: "
+               << console_forwarder_in_wr->StrError();
+    return {};
+  }
+
+  SharedFD console_forwarder_out_rd =
+      SharedFD::Open(console_out_pipe_name.c_str(), O_RDWR);
+  if (!console_forwarder_out_rd->IsOpen()) {
+    LOG(ERROR) << "Failed to open console_forwarder output fifo for reads: "
+               << console_forwarder_out_rd->StrError();
+    return {};
+  }
+
+  console_forwarder_cmd.AddParameter("--console_in_fd=", console_forwarder_in_wr);
+  console_forwarder_cmd.AddParameter("--console_out_fd=", console_forwarder_out_rd);
+  return single_element_emplace(std::move(console_forwarder_cmd));
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/run_cvd/launch.h b/host/commands/run_cvd/launch.h
index 0a8756f..30d5aff 100644
--- a/host/commands/run_cvd/launch.h
+++ b/host/commands/run_cvd/launch.h
@@ -1,55 +1,65 @@
+//
+// Copyright (C) 2019 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 <functional>
-#include <set>
 #include <string>
+#include <vector>
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/subprocess.h"
-#include "host/commands/run_cvd/process_monitor.h"
 #include "host/libs/config/cuttlefish_config.h"
 
-std::vector <cvd::SharedFD> LaunchKernelLogMonitor(
-    const vsoc::CuttlefishConfig& config,
-    cvd::ProcessMonitor* process_monitor,
-    unsigned int number_of_event_pipes);
-void LaunchAdbConnectorIfEnabled(cvd::ProcessMonitor* process_monitor,
-                                 const vsoc::CuttlefishConfig& config,
-                                 cvd::SharedFD adbd_events_pipe);
-void LaunchSocketVsockProxyIfEnabled(cvd::ProcessMonitor* process_monitor,
-                                 const vsoc::CuttlefishConfig& config);
+namespace cuttlefish {
 
-struct StreamerLaunchResult {
-  bool launched = false;
-  std::optional<unsigned int> frames_server_vsock_port;
-  std::optional<unsigned int> touch_server_vsock_port;
-  std::optional<unsigned int> keyboard_server_vsock_port;
+struct KernelLogMonitorData {
+  std::vector<SharedFD> pipes;
+  std::vector<Command> commands;
 };
-StreamerLaunchResult LaunchVNCServer(
-    const vsoc::CuttlefishConfig& config,
-    cvd::ProcessMonitor* process_monitor,
-    std::function<bool(cvd::MonitorEntry*)> callback);
 
-struct TombstoneReceiverPorts {
-  std::optional<unsigned int> server_vsock_port;
-};
-TombstoneReceiverPorts LaunchTombstoneReceiverIfEnabled(
-    const vsoc::CuttlefishConfig& config, cvd::ProcessMonitor* process_monitor);
+KernelLogMonitorData LaunchKernelLogMonitor(const CuttlefishConfig& config,
+                                            unsigned int number_of_event_pipes);
+std::vector<Command> LaunchAdbConnectorIfEnabled(
+    const CuttlefishConfig& config);
+std::vector<Command> LaunchSocketVsockProxyIfEnabled(
+    const CuttlefishConfig& config, SharedFD adbd_events_pipe);
+std::vector<Command> LaunchModemSimulatorIfEnabled(
+    const CuttlefishConfig& config);
 
-struct ConfigServerPorts {
-  std::optional<unsigned int> server_vsock_port;
-};
-ConfigServerPorts LaunchConfigServer(const vsoc::CuttlefishConfig& config,
-                                     cvd::ProcessMonitor* process_monitor);
+std::vector<Command> LaunchVNCServer(const CuttlefishConfig& config);
 
-struct LogcatServerPorts {
-  std::optional<unsigned int> server_vsock_port;
-};
-LogcatServerPorts LaunchLogcatReceiverIfEnabled(const vsoc::CuttlefishConfig& config,
-                                                cvd::ProcessMonitor* process_monitor);
+std::vector<Command> LaunchTombstoneReceiver(const CuttlefishConfig& config);
+std::vector<Command> LaunchRootCanal(const CuttlefishConfig& config);
+std::vector<Command> LaunchLogcatReceiver(const CuttlefishConfig& config);
+std::vector<Command> LaunchConfigServer(const CuttlefishConfig& config);
 
-StreamerLaunchResult LaunchWebRTC(cvd::ProcessMonitor* process_monitor,
-                                  const vsoc::CuttlefishConfig& config);
+std::vector<Command> LaunchWebRTC(const CuttlefishConfig& config,
+                                  SharedFD kernel_log_events_pipe);
 
-void LaunchVerhicleHalServerIfEnabled(const vsoc::CuttlefishConfig& config,
-                                      cvd::ProcessMonitor* process_monitor);
+std::vector<Command> LaunchMetrics();
+
+std::vector<Command> LaunchGnssGrpcProxyServerIfEnabled(
+    const CuttlefishConfig& config);
+
+std::vector<Command> LaunchSecureEnvironment(const CuttlefishConfig& config);
+
+std::vector<Command> LaunchBluetoothConnector(const CuttlefishConfig& config);
+std::vector<Command> LaunchVehicleHalServerIfEnabled(
+    const CuttlefishConfig& config);
+
+std::vector<Command> LaunchConsoleForwarderIfEnabled(
+    const CuttlefishConfig& config);
+
+} // namespace cuttlefish
diff --git a/host/commands/run_cvd/launch_adb.cpp b/host/commands/run_cvd/launch_adb.cpp
new file mode 100644
index 0000000..b7996ee
--- /dev/null
+++ b/host/commands/run_cvd/launch_adb.cpp
@@ -0,0 +1,156 @@
+//
+// Copyright (C) 2019 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.
+
+#include "host/commands/run_cvd/launch.h"
+
+#include <android-base/logging.h>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/known_paths.h"
+
+namespace cuttlefish {
+
+namespace {
+
+std::string GetAdbConnectorTcpArg(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  return std::string{"0.0.0.0:"} + std::to_string(instance.host_port());
+}
+
+std::string GetAdbConnectorVsockArg(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  return std::string{"vsock:"} + std::to_string(instance.vsock_guest_cid()) +
+         std::string{":5555"};
+}
+
+bool AdbModeEnabled(const CuttlefishConfig& config, AdbMode mode) {
+  return config.adb_mode().count(mode) > 0;
+}
+
+bool AdbVsockTunnelEnabled(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  return instance.vsock_guest_cid() > 2 &&
+         AdbModeEnabled(config, AdbMode::VsockTunnel);
+}
+
+bool AdbVsockHalfTunnelEnabled(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  return instance.vsock_guest_cid() > 2 &&
+         AdbModeEnabled(config, AdbMode::VsockHalfTunnel);
+}
+
+bool AdbTcpConnectorEnabled(const CuttlefishConfig& config) {
+  bool vsock_tunnel = AdbVsockTunnelEnabled(config);
+  bool vsock_half_tunnel = AdbVsockHalfTunnelEnabled(config);
+  return config.run_adb_connector() && (vsock_tunnel || vsock_half_tunnel);
+}
+
+bool AdbVsockConnectorEnabled(const CuttlefishConfig& config) {
+  return config.run_adb_connector() &&
+         AdbModeEnabled(config, AdbMode::NativeVsock);
+}
+
+}  // namespace
+
+std::vector<Command> LaunchAdbConnectorIfEnabled(
+    const CuttlefishConfig& config) {
+  Command adb_connector(AdbConnectorBinary());
+  std::set<std::string> addresses;
+
+  if (AdbTcpConnectorEnabled(config)) {
+    addresses.insert(GetAdbConnectorTcpArg(config));
+  }
+  if (AdbVsockConnectorEnabled(config)) {
+    addresses.insert(GetAdbConnectorVsockArg(config));
+  }
+
+  if (addresses.size() == 0) {
+    return {};
+  }
+  std::string address_arg = "--addresses=";
+  for (auto& arg : addresses) {
+    address_arg += arg + ",";
+  }
+  address_arg.pop_back();
+  adb_connector.AddParameter(address_arg);
+  std::vector<Command> commands;
+  commands.emplace_back(std::move(adb_connector));
+  return std::move(commands);
+}
+
+std::vector<Command> LaunchSocketVsockProxyIfEnabled(
+    const CuttlefishConfig& config, SharedFD adbd_events_pipe) {
+  auto instance = config.ForDefaultInstance();
+  auto append = [](const std::string& s, const int i) -> std::string {
+    return s + std::to_string(i);
+  };
+  auto tcp_server =
+      SharedFD::SocketLocalServer(instance.host_port(), SOCK_STREAM);
+  CHECK(tcp_server->IsOpen())
+      << "Unable to create socket_vsock_proxy server socket: "
+      << tcp_server->StrError();
+  std::vector<Command> commands;
+  if (AdbVsockTunnelEnabled(config)) {
+    Command adb_tunnel(SocketVsockProxyBinary());
+    adb_tunnel.AddParameter("-adbd_events_fd=", adbd_events_pipe);
+    /**
+     * This socket_vsock_proxy (a.k.a. sv proxy) runs on the host. It assumes
+     * that another sv proxy runs inside the guest. see:
+     * shared/config/init.vendor.rc The sv proxy in the guest exposes
+     * vsock:cid:6520 across the cuttlefish instances in multi-tenancy. cid is
+     * different per instance.
+     *
+     * This host sv proxy should cooperate with the guest sv proxy. Thus, one
+     * end of the tunnel is vsock:cid:6520 regardless of instance number.
+     * Another end faces the host adb daemon via tcp. Thus, the server type is
+     * tcp here. The tcp port differs from instance to instance, and is
+     * instance.host_port()
+     *
+     */
+    adb_tunnel.AddParameter("--server=tcp");
+    adb_tunnel.AddParameter("--vsock_port=6520");
+    adb_tunnel.AddParameter(std::string{"--server_fd="}, tcp_server);
+    adb_tunnel.AddParameter(std::string{"--vsock_cid="} +
+                            std::to_string(instance.vsock_guest_cid()));
+    commands.emplace_back(std::move(adb_tunnel));
+  }
+  if (AdbVsockHalfTunnelEnabled(config)) {
+    Command adb_tunnel(SocketVsockProxyBinary());
+    adb_tunnel.AddParameter("-adbd_events_fd=", adbd_events_pipe);
+    /*
+     * This socket_vsock_proxy (a.k.a. sv proxy) runs on the host, and
+     * cooperates with the adbd inside the guest. See this file:
+     *  shared/device.mk, especially the line says "persist.adb.tcp.port="
+     *
+     * The guest adbd is listening on vsock:cid:5555 across cuttlefish
+     * instances. Sv proxy faces the host adb daemon via tcp. The server type
+     * should be therefore tcp, and the port should differ from instance to
+     * instance and be equal to instance.host_port()
+     */
+    adb_tunnel.AddParameter("--server=tcp");
+    adb_tunnel.AddParameter(append("--vsock_port=", 5555));
+    adb_tunnel.AddParameter(std::string{"--server_fd="}, tcp_server);
+    adb_tunnel.AddParameter(append("--vsock_cid=", instance.vsock_guest_cid()));
+    commands.emplace_back(std::move(adb_tunnel));
+  }
+  return commands;
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/launch_modem.cpp b/host/commands/run_cvd/launch_modem.cpp
new file mode 100644
index 0000000..fb9af70
--- /dev/null
+++ b/host/commands/run_cvd/launch_modem.cpp
@@ -0,0 +1,117 @@
+//
+// Copyright (C) 2019 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.
+
+#include "host/commands/run_cvd/launch.h"
+
+#include <android-base/logging.h>
+#include <string.h>
+#include <sstream>
+#include <string>
+#include <utility>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/known_paths.h"
+
+namespace cuttlefish {
+
+static bool StopModemSimulator() {
+  auto config = CuttlefishConfig::Get();
+  auto instance = config->ForDefaultInstance();
+
+  std::string monitor_socket_name = "modem_simulator";
+  std::stringstream ss;
+  ss << instance.host_port();
+  monitor_socket_name.append(ss.str());
+  auto monitor_sock = SharedFD::SocketLocalClient(monitor_socket_name.c_str(),
+                                                  true, SOCK_STREAM);
+  if (!monitor_sock->IsOpen()) {
+    LOG(ERROR) << "The connection to modem simulator is closed";
+    return false;
+  }
+  std::string msg("STOP");
+  if (monitor_sock->Write(msg.data(), msg.size()) < 0) {
+    monitor_sock->Close();
+    LOG(ERROR) << "Failed to send 'STOP' to modem simulator";
+    return false;
+  }
+  char buf[64] = {0};
+  if (monitor_sock->Read(buf, sizeof(buf)) <= 0) {
+    monitor_sock->Close();
+    LOG(ERROR) << "Failed to read message from modem simulator";
+    return false;
+  }
+  if (strcmp(buf, "OK")) {
+    monitor_sock->Close();
+    LOG(ERROR) << "Read '" << buf << "' instead of 'OK' from modem simulator";
+    return false;
+  }
+
+  return true;
+}
+
+std::vector<Command> LaunchModemSimulatorIfEnabled(
+    const CuttlefishConfig& config) {
+  if (!config.enable_modem_simulator()) {
+    LOG(DEBUG) << "Modem simulator not enabled";
+    return {};
+  }
+
+  int instance_number = config.modem_simulator_instance_number();
+  if (instance_number > 3 /* max value */ || instance_number < 0) {
+    LOG(ERROR)
+        << "Modem simulator instance number should range between 1 and 3";
+    return {};
+  }
+
+  Command cmd(ModemSimulatorBinary(), [](Subprocess* proc) {
+    auto stopped = StopModemSimulator();
+    if (stopped) {
+      return true;
+    }
+    LOG(WARNING) << "Failed to stop modem simulator nicely, "
+                 << "attempting to KILL";
+    return KillSubprocess(proc);
+  });
+
+  auto sim_type = config.modem_simulator_sim_type();
+  cmd.AddParameter(std::string{"-sim_type="} + std::to_string(sim_type));
+
+  auto instance = config.ForDefaultInstance();
+  auto ports = instance.modem_simulator_ports();
+  cmd.AddParameter("-server_fds=");
+  for (int i = 0; i < instance_number; ++i) {
+    auto pos = ports.find(',');
+    auto temp = (pos != std::string::npos) ? ports.substr(0, pos - 1) : ports;
+    auto port = std::stoi(temp);
+    ports = ports.substr(pos + 1);
+
+    auto socket = SharedFD::VsockServer(port, SOCK_STREAM);
+    CHECK(socket->IsOpen())
+        << "Unable to create modem simulator server socket: "
+        << socket->StrError();
+    if (i > 0) {
+      cmd.AppendToLastParameter(",");
+    }
+    cmd.AppendToLastParameter(socket);
+  }
+
+  std::vector<Command> commands;
+  commands.emplace_back(std::move(cmd));
+  return commands;
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/launch_streamer.cpp b/host/commands/run_cvd/launch_streamer.cpp
new file mode 100644
index 0000000..bf0d77d
--- /dev/null
+++ b/host/commands/run_cvd/launch_streamer.cpp
@@ -0,0 +1,224 @@
+//
+// Copyright (C) 2019 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.
+
+#include "host/commands/run_cvd/launch.h"
+
+#include <android-base/logging.h>
+#include <string>
+#include <utility>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/files.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/known_paths.h"
+#include "host/libs/vm_manager/crosvm_manager.h"
+#include "host/libs/vm_manager/qemu_manager.h"
+
+namespace cuttlefish {
+
+namespace {
+
+SharedFD CreateUnixInputServer(const std::string& path) {
+  auto server =
+      SharedFD::SocketLocalServer(path.c_str(), false, SOCK_STREAM, 0666);
+  if (!server->IsOpen()) {
+    LOG(ERROR) << "Unable to create unix input server: " << server->StrError();
+    return {};
+  }
+  return server;
+}
+
+// Creates the frame and input sockets and add the relevant arguments to the vnc
+// server and webrtc commands
+void CreateStreamerServers(Command* cmd, const CuttlefishConfig& config) {
+  SharedFD touch_server;
+  SharedFD keyboard_server;
+
+  auto instance = config.ForDefaultInstance();
+  if (config.vm_manager() == vm_manager::QemuManager::name()) {
+    cmd->AddParameter("-write_virtio_input");
+
+    touch_server =
+        SharedFD::VsockServer(instance.touch_server_port(), SOCK_STREAM);
+    keyboard_server =
+        SharedFD::VsockServer(instance.keyboard_server_port(), SOCK_STREAM);
+  } else {
+    touch_server = CreateUnixInputServer(instance.touch_socket_path());
+    keyboard_server = CreateUnixInputServer(instance.keyboard_socket_path());
+  }
+  if (!touch_server->IsOpen()) {
+    LOG(ERROR) << "Could not open touch server: " << touch_server->StrError();
+    return;
+  }
+  cmd->AddParameter("-touch_fd=", touch_server);
+
+  if (!keyboard_server->IsOpen()) {
+    LOG(ERROR) << "Could not open keyboard server: "
+               << keyboard_server->StrError();
+    return;
+  }
+  cmd->AddParameter("-keyboard_fd=", keyboard_server);
+
+  if (config.enable_webrtc() &&
+      config.vm_manager() == vm_manager::CrosvmManager::name()) {
+    SharedFD switches_server =
+        CreateUnixInputServer(instance.switches_socket_path());
+    if (!switches_server->IsOpen()) {
+      LOG(ERROR) << "Could not open switches server: "
+                 << switches_server->StrError();
+      return;
+    }
+    cmd->AddParameter("-switches_fd=", switches_server);
+  }
+
+  SharedFD frames_server = CreateUnixInputServer(instance.frames_socket_path());
+  if (!frames_server->IsOpen()) {
+    LOG(ERROR) << "Could not open frames server: " << frames_server->StrError();
+    return;
+  }
+  cmd->AddParameter("-frame_server_fd=", frames_server);
+
+  if (config.enable_audio()) {
+    auto path = config.ForDefaultInstance().audio_server_path();
+    auto audio_server =
+        SharedFD::SocketLocalServer(path.c_str(), false, SOCK_SEQPACKET, 0666);
+    if (!audio_server->IsOpen()) {
+      LOG(ERROR) << "Could not create audio server: "
+                 << audio_server->StrError();
+      return;
+    }
+    cmd->AddParameter("--audio_server_fd=", audio_server);
+  }
+}
+
+std::vector<Command> LaunchCustomActionServers(Command& webrtc_cmd,
+                                               const CuttlefishConfig& config) {
+  bool first = true;
+  std::vector<Command> commands;
+  for (const auto& custom_action : config.custom_actions()) {
+    if (custom_action.server) {
+      // Create a socket pair that will be used for communication between
+      // WebRTC and the action server.
+      SharedFD webrtc_socket, action_server_socket;
+      if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &webrtc_socket,
+                                &action_server_socket)) {
+        LOG(ERROR) << "Unable to create custom action server socket pair: "
+                   << strerror(errno);
+        continue;
+      }
+
+      // Launch the action server, providing its socket pair fd as the only
+      // argument.
+      std::string binary = "bin/" + *(custom_action.server);
+      Command command(DefaultHostArtifactsPath(binary));
+      command.AddParameter(action_server_socket);
+      commands.emplace_back(std::move(command));
+
+      // Pass the WebRTC socket pair fd to WebRTC.
+      if (first) {
+        first = false;
+        webrtc_cmd.AddParameter("-action_servers=", *custom_action.server, ":",
+                                webrtc_socket);
+      } else {
+        webrtc_cmd.AppendToLastParameter(",", *custom_action.server, ":",
+                                         webrtc_socket);
+      }
+    }
+  }
+  return commands;
+}
+
+}  // namespace
+
+std::vector<Command> LaunchVNCServer(const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  // Launch the vnc server, don't wait for it to complete
+  auto port_options = "-port=" + std::to_string(instance.vnc_server_port());
+  Command vnc_server(VncServerBinary());
+  vnc_server.AddParameter(port_options);
+
+  CreateStreamerServers(&vnc_server, config);
+
+  std::vector<Command> commands;
+  commands.emplace_back(std::move(vnc_server));
+  return std::move(commands);
+}
+
+std::vector<Command> LaunchWebRTC(const CuttlefishConfig& config,
+                                  SharedFD kernel_log_events_pipe) {
+  std::vector<Command> commands;
+  if (config.ForDefaultInstance().start_webrtc_sig_server()) {
+    Command sig_server(WebRtcSigServerBinary());
+    sig_server.AddParameter("-assets_dir=", config.webrtc_assets_dir());
+    if (!config.webrtc_certs_dir().empty()) {
+      sig_server.AddParameter("-certs_dir=", config.webrtc_certs_dir());
+    }
+    sig_server.AddParameter("-http_server_port=", config.sig_server_port());
+    commands.emplace_back(std::move(sig_server));
+  }
+
+  // Currently there is no way to ensure the signaling server will already have
+  // bound the socket to the port by the time the webrtc process runs (the
+  // common technique of doing it from the launcher is not possible here as the
+  // server library being used creates its own sockets). However, this issue is
+  // mitigated slightly by doing some retrying and backoff in the webrtc process
+  // when connecting to the websocket, so it shouldn't be an issue most of the
+  // time.
+  SharedFD client_socket;
+  SharedFD host_socket;
+  CHECK(SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &client_socket,
+                             &host_socket))
+      << "Could not open command socket for webRTC";
+
+  auto stopper = [host_socket = std::move(host_socket)](Subprocess* proc) {
+    struct timeval timeout;
+    timeout.tv_sec = 3;
+    timeout.tv_usec = 0;
+    CHECK(host_socket->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO, &timeout,
+                                  sizeof(timeout)) == 0)
+        << "Could not set receive timeout";
+
+    WriteAll(host_socket, "C");
+    char response[1];
+    int read_ret = host_socket->Read(response, sizeof(response));
+    if (read_ret != 0) {
+      LOG(ERROR) << "Failed to read response from webrtc";
+    }
+    cuttlefish::KillSubprocess(proc);
+    return true;
+  };
+
+  Command webrtc(WebRtcBinary(), SubprocessStopper(stopper));
+
+  webrtc.UnsetFromEnvironment({"http_proxy"});
+
+  CreateStreamerServers(&webrtc, config);
+
+  webrtc.AddParameter("--command_fd=", client_socket);
+  webrtc.AddParameter("-kernel_log_events_fd=", kernel_log_events_pipe);
+
+  auto actions = LaunchCustomActionServers(webrtc, config);
+
+  // TODO get from launcher params
+  commands.emplace_back(std::move(webrtc));
+  for (auto& action : actions) {
+    commands.emplace_back(std::move(action));
+  }
+
+  return commands;
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/main.cc b/host/commands/run_cvd/main.cc
index b45b22c..f40226a 100644
--- a/host/commands/run_cvd/main.cc
+++ b/host/commands/run_cvd/main.cc
@@ -14,147 +14,51 @@
  * limitations under the License.
  */
 
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h>
 #include <unistd.h>
-
-#include <algorithm>
-#include <functional>
-#include <iostream>
 #include <fstream>
-#include <iomanip>
+#include <iostream>
 #include <memory>
-#include <sstream>
 #include <string>
-#include <thread>
+#include <utility>
 #include <vector>
 
+#include <android-base/logging.h>
 #include <android-base/strings.h>
 #include <gflags/gflags.h>
-#include <glog/logging.h>
 
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
-#include "common/libs/fs/shared_select.h"
-#include "common/libs/fs/tee.h"
 #include "common/libs/utils/environment.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/network.h"
-#include "common/libs/utils/subprocess.h"
 #include "common/libs/utils/size_utils.h"
-#include "host/commands/run_cvd/kernel_args.h"
+#include "common/libs/utils/subprocess.h"
+#include "common/libs/utils/tee_logging.h"
+#include "host/commands/run_cvd/boot_state_machine.h"
 #include "host/commands/run_cvd/launch.h"
-#include "host/commands/run_cvd/runner_defs.h"
 #include "host/commands/run_cvd/process_monitor.h"
+#include "host/commands/run_cvd/runner_defs.h"
+#include "host/commands/run_cvd/server_loop.h"
 #include "host/libs/config/cuttlefish_config.h"
-#include "host/commands/kernel_log_monitor/kernel_log_server.h"
-#include <host/libs/vm_manager/crosvm_manager.h>
+#include "host/libs/vm_manager/host_configuration.h"
 #include "host/libs/vm_manager/vm_manager.h"
-#include "host/libs/vm_manager/qemu_manager.h"
 
-using vsoc::ForCurrentInstance;
-using cvd::RunnerExitCodes;
+DEFINE_int32(reboot_notification_fd, -1,
+             "A file descriptor to notify when boot completes.");
+
+namespace cuttlefish {
+
+using vm_manager::GetVmManager;
+using vm_manager::ValidateHostConfiguration;
 
 namespace {
 
-cvd::OnSocketReadyCb GetOnSubprocessExitCallback(
-    const vsoc::CuttlefishConfig& config) {
-  if (config.restart_subprocesses()) {
-    return cvd::ProcessMonitor::RestartOnExitCb;
-  } else {
-    return cvd::ProcessMonitor::DoNotMonitorCb;
-  }
-}
+constexpr char kGreenColor[] = "\033[1;32m";
+constexpr char kResetColor[] = "\033[0m";
 
-// Maintains the state of the boot process, once a final state is reached
-// (success or failure) it sends the appropriate exit code to the foreground
-// launcher process
-class CvdBootStateMachine {
- public:
-  CvdBootStateMachine(cvd::SharedFD fg_launcher_pipe)
-      : fg_launcher_pipe_(fg_launcher_pipe), state_(kBootStarted) {}
-
-  // Returns true if the machine is left in a final state
-  bool OnBootEvtReceived(cvd::SharedFD boot_events_pipe) {
-    monitor::BootEvent evt;
-    auto bytes_read = boot_events_pipe->Read(&evt, sizeof(evt));
-    if (bytes_read != sizeof(evt)) {
-      LOG(ERROR) << "Fail to read a complete event, read " << bytes_read
-                 << " bytes only instead of the expected " << sizeof(evt);
-      state_ |= kGuestBootFailed;
-    } else if (evt == monitor::BootEvent::BootCompleted) {
-      LOG(INFO) << "Virtual device booted successfully";
-      state_ |= kGuestBootCompleted;
-    } else if (evt == monitor::BootEvent::BootFailed) {
-      LOG(ERROR) << "Virtual device failed to boot";
-      state_ |= kGuestBootFailed;
-    }  // Ignore the other signals
-
-    return MaybeWriteToForegroundLauncher();
-  }
-
-  bool BootCompleted() const {
-    return state_ & kGuestBootCompleted;
-  }
-
-  bool BootFailed() const {
-    return state_ & kGuestBootFailed;
-  }
-
- private:
-  void SendExitCode(cvd::RunnerExitCodes exit_code) {
-    fg_launcher_pipe_->Write(&exit_code, sizeof(exit_code));
-    // The foreground process will exit after receiving the exit code, if we try
-    // to write again we'll get a SIGPIPE
-    fg_launcher_pipe_->Close();
-  }
-  bool MaybeWriteToForegroundLauncher() {
-    if (fg_launcher_pipe_->IsOpen()) {
-      if (BootCompleted()) {
-        SendExitCode(cvd::RunnerExitCodes::kSuccess);
-      } else if (state_ & kGuestBootFailed) {
-        SendExitCode(cvd::RunnerExitCodes::kVirtualDeviceBootFailed);
-      } else {
-        // No final state was reached
-        return false;
-      }
-    }
-    // Either we sent the code before or just sent it, in any case the state is
-    // final
-    return true;
-  }
-
-  cvd::SharedFD fg_launcher_pipe_;
-  int state_;
-  static const int kBootStarted = 0;
-  static const int kGuestBootCompleted = 1 << 0;
-  static const int kGuestBootFailed = 1 << 1;
-};
-
-// Abuse the process monitor to make it call us back when boot events are ready
-void SetUpHandlingOfBootEvents(
-    cvd::ProcessMonitor* process_monitor, cvd::SharedFD boot_events_pipe,
-    std::shared_ptr<CvdBootStateMachine> state_machine) {
-  process_monitor->MonitorExistingSubprocess(
-      // A dummy command, so logs are desciptive
-      cvd::Command("boot_events_listener"),
-      // A dummy subprocess, with the boot events pipe as control socket
-      cvd::Subprocess(-1, boot_events_pipe),
-      [boot_events_pipe, state_machine](cvd::MonitorEntry*) {
-        auto sent_code = state_machine->OnBootEvtReceived(boot_events_pipe);
-        return !sent_code;
-      });
-}
-
-bool WriteCuttlefishEnvironment(const vsoc::CuttlefishConfig& config) {
-  auto env = cvd::SharedFD::Open(config.cuttlefish_env_path().c_str(),
-                                 O_CREAT | O_RDWR, 0755);
+bool WriteCuttlefishEnvironment(const CuttlefishConfig& config) {
+  auto env = SharedFD::Open(config.cuttlefish_env_path().c_str(),
+                            O_CREAT | O_RDWR, 0755);
   if (!env->IsOpen()) {
     LOG(ERROR) << "Unable to create cuttlefish.env file";
     return false;
@@ -169,12 +73,12 @@
 
 // Forks and returns the write end of a pipe to the child process. The parent
 // process waits for boot events to come through the pipe and exits accordingly.
-cvd::SharedFD DaemonizeLauncher(const vsoc::CuttlefishConfig& config) {
+SharedFD DaemonizeLauncher(const CuttlefishConfig& config) {
   auto instance = config.ForDefaultInstance();
-  cvd::SharedFD read_end, write_end;
-  if (!cvd::SharedFD::Pipe(&read_end, &write_end)) {
+  SharedFD read_end, write_end;
+  if (!SharedFD::Pipe(&read_end, &write_end)) {
     LOG(ERROR) << "Unable to create pipe";
-    return cvd::SharedFD(); // a closed FD
+    return {}; // a closed FD
   }
   auto pid = fork();
   if (pid) {
@@ -195,9 +99,9 @@
       LOG(ERROR) << "Unexpected exit code: " << exit_code;
     }
     if (exit_code == RunnerExitCodes::kSuccess) {
-      LOG(INFO) << vsoc::kBootCompletedMessage;
+      LOG(INFO) << kBootCompletedMessage;
     } else {
-      LOG(INFO) << vsoc::kBootFailedMessage;
+      LOG(INFO) << kBootFailedMessage;
     }
     std::exit(exit_code);
   } else {
@@ -208,14 +112,15 @@
     }
     // Redirect standard I/O
     auto log_path = instance.launcher_log_path();
-    auto log =
-        cvd::SharedFD::Open(log_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC,
-                            S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+    auto log = SharedFD::Open(log_path.c_str(), O_CREAT | O_WRONLY | O_APPEND,
+                              S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
     if (!log->IsOpen()) {
       LOG(ERROR) << "Failed to create launcher log file: " << log->StrError();
       std::exit(RunnerExitCodes::kDaemonizationError);
     }
-    auto dev_null = cvd::SharedFD::Open("/dev/null", O_RDONLY);
+    ::android::base::SetLogger(
+        TeeLogger({{LogFileSeverity(), log, MetadataLevel::FULL}}));
+    auto dev_null = SharedFD::Open("/dev/null", O_RDONLY);
     if (!dev_null->IsOpen()) {
       LOG(ERROR) << "Failed to open /dev/null: " << dev_null->StrError();
       std::exit(RunnerExitCodes::kDaemonizationError);
@@ -238,70 +143,50 @@
   }
 }
 
-void ServerLoop(cvd::SharedFD server,
-                cvd::ProcessMonitor* process_monitor) {
-  while (true) {
-    // TODO: use select to handle simultaneous connections.
-    auto client = cvd::SharedFD::Accept(*server);
-    cvd::LauncherAction action;
-    while (client->IsOpen() && client->Read(&action, sizeof(action)) > 0) {
-      switch (action) {
-        case cvd::LauncherAction::kStop:
-          if (process_monitor->StopMonitoredProcesses()) {
-            auto response = cvd::LauncherResponse::kSuccess;
-            client->Write(&response, sizeof(response));
-            std::exit(0);
-          } else {
-            auto response = cvd::LauncherResponse::kError;
-            client->Write(&response, sizeof(response));
-          }
-          break;
-        case cvd::LauncherAction::kStatus: {
-          // TODO(schuffelen): Return more information on a side channel
-          auto response = cvd::LauncherResponse::kSuccess;
-          client->Write(&response, sizeof(response));
-          break;
-        }
-        default:
-          LOG(ERROR) << "Unrecognized launcher action: "
-                     << static_cast<char>(action);
-          auto response = cvd::LauncherResponse::kError;
-          client->Write(&response, sizeof(response));
-      }
-    }
-  }
-}
-
-std::string GetConfigFilePath(const vsoc::CuttlefishConfig& config) {
+std::string GetConfigFilePath(const CuttlefishConfig& config) {
   auto instance = config.ForDefaultInstance();
   return instance.PerInstancePath("cuttlefish_config.json");
 }
 
+void PrintStreamingInformation(const CuttlefishConfig& config) {
+  if (config.ForDefaultInstance().start_webrtc_sig_server()) {
+    // TODO (jemoreira): Change this when webrtc is moved to the debian package.
+    LOG(INFO) << kGreenColor << "Point your browser to https://"
+              << config.sig_server_address() << ":" << config.sig_server_port()
+              << " to interact with the device." << kResetColor;
+  } else if (config.enable_vnc_server()) {
+    LOG(INFO) << kGreenColor << "VNC server started on port "
+              << config.ForDefaultInstance().vnc_server_port() << kResetColor;
+  }
+  // When WebRTC is enabled but an operator other than the one launched by
+  // run_cvd is used there is no way to know the url to which to point the
+  // browser to.
+}
+
 }  // namespace
 
-int main(int argc, char** argv) {
+int RunCvdMain(int argc, char** argv) {
+  setenv("ANDROID_LOG_TAGS", "*:v", /* overwrite */ 0);
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   google::ParseCommandLineFlags(&argc, &argv, false);
 
   if (isatty(0)) {
     LOG(FATAL) << "stdin was a tty, expected to be passed the output of a previous stage. "
                << "Did you mean to run launch_cvd?";
-    return cvd::RunnerExitCodes::kInvalidHostConfiguration;
+    return RunnerExitCodes::kInvalidHostConfiguration;
   } else {
     int error_num = errno;
     if (error_num == EBADF) {
       LOG(FATAL) << "stdin was not a valid file descriptor, expected to be passed the output "
                  << "of assemble_cvd. Did you mean to run launch_cvd?";
-      return cvd::RunnerExitCodes::kInvalidHostConfiguration;
+      return RunnerExitCodes::kInvalidHostConfiguration;
     }
   }
 
-  cvd::TeeStderrToFile stderr_tee;
-
   std::string input_files_str;
   {
-    auto input_fd = cvd::SharedFD::Dup(0);
-    auto bytes_read = cvd::ReadAll(input_fd, &input_files_str);
+    auto input_fd = SharedFD::Dup(0);
+    auto bytes_read = ReadAll(input_fd, &input_files_str);
     if (bytes_read < 0) {
       LOG(FATAL) << "Failed to read input files. Error was \"" << input_fd->StrError() << "\"";
     }
@@ -311,18 +196,28 @@
   for (const auto& file : input_files) {
     if (file.find("cuttlefish_config.json") != std::string::npos) {
       found_config = true;
-      setenv(vsoc::kCuttlefishConfigEnvVarName, file.c_str(), /* overwrite */ false);
+      setenv(kCuttlefishConfigEnvVarName, file.c_str(), /* overwrite */ false);
     }
   }
   if (!found_config) {
     return RunnerExitCodes::kCuttlefishConfigurationInitError;
   }
 
-  auto config = vsoc::CuttlefishConfig::Get();
+  auto config = CuttlefishConfig::Get();
   auto instance = config->ForDefaultInstance();
 
-  auto runner_log_path = instance.PerInstancePath("run_cvd.log");
-  stderr_tee.SetFile(cvd::SharedFD::Creat(runner_log_path.c_str(), 0755));
+  auto log_path = instance.launcher_log_path();
+
+  {
+    std::ofstream launcher_log_ofstream(log_path.c_str());
+    auto assembly_path = config->AssemblyPath("assemble_cvd.log");
+    std::ifstream assembly_log_ifstream(assembly_path);
+    if (assembly_log_ifstream) {
+      auto assemble_log = ReadFile(assembly_path);
+      launcher_log_ofstream << assemble_log;
+    }
+  }
+  ::android::base::SetLogger(LogToStderrAndFiles({log_path}));
 
   // Change working directory to the instance directory as early as possible to
   // ensure all host processes have the same working dir. This helps stop_cvd
@@ -336,20 +231,24 @@
     return RunnerExitCodes::kInstanceDirCreationError;
   }
 
-  auto used_tap_devices = cvd::TapInterfacesInUse();
+  auto used_tap_devices = TapInterfacesInUse();
   if (used_tap_devices.count(instance.wifi_tap_name())) {
     LOG(ERROR) << "Wifi TAP device already in use";
     return RunnerExitCodes::kTapDeviceInUse;
   } else if (used_tap_devices.count(instance.mobile_tap_name())) {
     LOG(ERROR) << "Mobile TAP device already in use";
     return RunnerExitCodes::kTapDeviceInUse;
+  } else if (config->ethernet() &&
+             used_tap_devices.count(instance.ethernet_tap_name())) {
+    LOG(ERROR) << "Ethernet TAP device already in use";
   }
 
-  auto vm_manager = vm_manager::VmManager::Get(config->vm_manager(), config);
+  auto vm_manager = GetVmManager(config->vm_manager(), config->target_arch());
 
+#ifndef __ANDROID__
   // Check host configuration
   std::vector<std::string> config_commands;
-  if (!vm_manager->ValidateHostConfiguration(&config_commands)) {
+  if (!ValidateHostConfiguration(&config_commands)) {
     LOG(ERROR) << "Validation of user configuration failed";
     std::cout << "Execute the following to correctly configure:" << std::endl;
     for (auto& command : config_commands) {
@@ -359,31 +258,51 @@
               << std::endl;
     return RunnerExitCodes::kInvalidHostConfiguration;
   }
+#endif
 
   if (!WriteCuttlefishEnvironment(*config)) {
     LOG(ERROR) << "Unable to write cuttlefish environment file";
   }
 
-  LOG(INFO) << "The following files contain useful debugging information:";
-  if (config->run_as_daemon()) {
-    LOG(INFO) << "  Launcher log: " << instance.launcher_log_path();
+  PrintStreamingInformation(*config);
+
+  if (config->console()) {
+    LOG(INFO) << kGreenColor << "To access the console run: screen "
+              << instance.console_path() << kResetColor;
+  } else {
+    LOG(INFO) << kGreenColor
+              << "Serial console is disabled; use -console=true to enable it"
+              << kResetColor;
   }
-  LOG(INFO) << "  Android's logcat output: " << instance.logcat_path();
-  LOG(INFO) << "  Kernel log: " << instance.PerInstancePath("kernel.log");
-  LOG(INFO) << "  Instance configuration: " << GetConfigFilePath(*config);
-  LOG(INFO) << "  Instance environment: " << config->cuttlefish_env_path();
-  LOG(INFO) << "To access the console run: socat file:$(tty),raw,echo=0 "
-            << instance.console_path();
+
+  LOG(INFO) << kGreenColor
+            << "The following files contain useful debugging information:"
+            << kResetColor;
+  LOG(INFO) << kGreenColor
+            << "  Launcher log: " << instance.launcher_log_path()
+            << kResetColor;
+  LOG(INFO) << kGreenColor
+            << "  Android's logcat output: " << instance.logcat_path()
+            << kResetColor;
+  LOG(INFO) << kGreenColor
+            << "  Kernel log: " << instance.PerInstancePath("kernel.log")
+            << kResetColor;
+  LOG(INFO) << kGreenColor
+            << "  Instance configuration: " << GetConfigFilePath(*config)
+            << kResetColor;
+  LOG(INFO) << kGreenColor
+            << "  Instance environment: " << config->cuttlefish_env_path()
+            << kResetColor;
 
   auto launcher_monitor_path = instance.launcher_monitor_socket_path();
-  auto launcher_monitor_socket = cvd::SharedFD::SocketLocalServer(
+  auto launcher_monitor_socket = SharedFD::SocketLocalServer(
       launcher_monitor_path.c_str(), false, SOCK_STREAM, 0666);
   if (!launcher_monitor_socket->IsOpen()) {
     LOG(ERROR) << "Error when opening launcher server: "
                << launcher_monitor_socket->StrError();
-    return cvd::RunnerExitCodes::kMonitorCreationFailed;
+    return RunnerExitCodes::kMonitorCreationFailed;
   }
-  cvd::SharedFD foreground_launcher_pipe;
+  SharedFD foreground_launcher_pipe;
   if (config->run_as_daemon()) {
     foreground_launcher_pipe = DaemonizeLauncher(*config);
     if (!foreground_launcher_pipe->IsOpen()) {
@@ -401,69 +320,70 @@
     }
   }
 
-  auto boot_state_machine =
-      std::make_shared<CvdBootStateMachine>(foreground_launcher_pipe);
+  SharedFD reboot_notification;
+  if (FLAGS_reboot_notification_fd >= 0) {
+    reboot_notification = SharedFD::Dup(FLAGS_reboot_notification_fd);
+    close(FLAGS_reboot_notification_fd);
+  }
 
   // Monitor and restart host processes supporting the CVD
-  cvd::ProcessMonitor process_monitor;
+  ProcessMonitor process_monitor(config->restart_subprocesses());
 
-  auto event_pipes =
-      LaunchKernelLogMonitor(*config, &process_monitor, 2);
-  cvd::SharedFD boot_events_pipe = event_pipes[0];
-  cvd::SharedFD adbd_events_pipe = event_pipes[1];
-  event_pipes.clear();
+  if (config->enable_metrics() == CuttlefishConfig::kYes) {
+    process_monitor.AddCommands(LaunchMetrics());
+  }
+  process_monitor.AddCommands(LaunchModemSimulatorIfEnabled(*config));
 
-  std::set<std::string> extra_kernel_cmdline;
+  auto kernel_log_monitor = LaunchKernelLogMonitor(*config, 3);
+  SharedFD boot_events_pipe = kernel_log_monitor.pipes[0];
+  SharedFD adbd_events_pipe = kernel_log_monitor.pipes[1];
+  SharedFD webrtc_events_pipe = kernel_log_monitor.pipes[2];
+  kernel_log_monitor.pipes.clear();
+  process_monitor.AddCommands(std::move(kernel_log_monitor.commands));
 
-  SetUpHandlingOfBootEvents(&process_monitor, boot_events_pipe,
-                            boot_state_machine);
+  CvdBootStateMachine boot_state_machine(foreground_launcher_pipe,
+                                         reboot_notification, boot_events_pipe);
 
-  auto logcat_server = LaunchLogcatReceiverIfEnabled(*config, &process_monitor);
-  auto logcat_server_args = KernelCommandLineFromLogcatServer(logcat_server);
-
-  auto config_server = LaunchConfigServer(*config, &process_monitor);
-  auto config_server_args = KernelCommandLineFromConfigServer(config_server);
-
-  auto tombstone_server = LaunchTombstoneReceiverIfEnabled(*config, &process_monitor);
-  auto tombstone_kernel_args = KernelCommandLineFromTombstone(tombstone_server);
-
-  LaunchVerhicleHalServerIfEnabled(*config, &process_monitor);
+  process_monitor.AddCommands(LaunchRootCanal(*config));
+  process_monitor.AddCommands(LaunchLogcatReceiver(*config));
+  process_monitor.AddCommands(LaunchConfigServer(*config));
+  process_monitor.AddCommands(LaunchTombstoneReceiver(*config));
+  process_monitor.AddCommands(LaunchGnssGrpcProxyServerIfEnabled(*config));
+  process_monitor.AddCommands(LaunchSecureEnvironment(*config));
+  if (config->enable_host_bluetooth()) {
+    process_monitor.AddCommands(LaunchBluetoothConnector(*config));
+  }
+  process_monitor.AddCommands(LaunchVehicleHalServerIfEnabled(*config));
+  process_monitor.AddCommands(LaunchConsoleForwarderIfEnabled(*config));
 
   // The streamer needs to launch before the VMM because it serves on several
   // sockets (input devices, vsock frame server) when using crosvm.
-  StreamerLaunchResult streamer_config;
   if (config->enable_vnc_server()) {
-    streamer_config = LaunchVNCServer(
-      *config, &process_monitor, GetOnSubprocessExitCallback(*config));
+    process_monitor.AddCommands(LaunchVNCServer(*config));
   }
   if (config->enable_webrtc()) {
-    streamer_config = LaunchWebRTC(&process_monitor, *config);
+    process_monitor.AddCommands(LaunchWebRTC(*config, webrtc_events_pipe));
   }
 
-  auto streamer_kernel_args = KernelCommandLineFromStreamer(streamer_config);
-
-  auto kernel_args = KernelCommandLineFromConfig(*config);
-  kernel_args.insert(kernel_args.end(), streamer_kernel_args.begin(),
-                     streamer_kernel_args.end());
-  kernel_args.insert(kernel_args.end(), tombstone_kernel_args.begin(),
-                     tombstone_kernel_args.end());
-  kernel_args.insert(kernel_args.end(), config_server_args.begin(), config_server_args.end());
-  kernel_args.insert(kernel_args.end(), logcat_server_args.begin(), logcat_server_args.end());
-
   // Start the guest VM
-  vm_manager->WithFrontend(streamer_config.launched);
-  vm_manager->WithKernelCommandLine(android::base::Join(kernel_args, " "));
-  auto vmm_commands = vm_manager->StartCommands();
-  for (auto& vmm_cmd: vmm_commands) {
-      process_monitor.StartSubprocess(std::move(vmm_cmd),
-                                      GetOnSubprocessExitCallback(*config));
-  }
+  process_monitor.AddCommands(vm_manager->StartCommands(*config));
 
   // Start other host processes
-  LaunchSocketVsockProxyIfEnabled(&process_monitor, *config);
-  LaunchAdbConnectorIfEnabled(&process_monitor, *config, adbd_events_pipe);
+  process_monitor.AddCommands(
+      LaunchSocketVsockProxyIfEnabled(*config, adbd_events_pipe));
+  process_monitor.AddCommands(LaunchAdbConnectorIfEnabled(*config));
+
+  CHECK(process_monitor.StartAndMonitorProcesses())
+      << "Could not start subprocesses";
 
   ServerLoop(launcher_monitor_socket, &process_monitor); // Should not return
   LOG(ERROR) << "The server loop returned, it should never happen!!";
-  return cvd::RunnerExitCodes::kServerError;
+
+  return RunnerExitCodes::kServerError;
+}
+
+} // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::RunCvdMain(argc, argv);
 }
diff --git a/host/commands/run_cvd/pre_launch_initializers.h b/host/commands/run_cvd/pre_launch_initializers.h
deleted file mode 100644
index 79f6eed..0000000
--- a/host/commands/run_cvd/pre_launch_initializers.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <memory>
-
-#include <host/libs/config/cuttlefish_config.h>
-
-// Handles initialization of regions that require it strictly before the virtual
-// machine is started.
-// To add initializers for more regions declare here, implement in its own
-// source file and call from PreLaunchInitializers::Initialize().
-void InitializeScreenRegion(const vsoc::CuttlefishConfig& config);
-
-class PreLaunchInitializers {
- public:
-  static void Initialize(const vsoc::CuttlefishConfig& config) {
-    InitializeScreenRegion(config);
-  }
-};
diff --git a/host/commands/run_cvd/process_monitor.cc b/host/commands/run_cvd/process_monitor.cc
index 93b6881..a4f7f72 100644
--- a/host/commands/run_cvd/process_monitor.cc
+++ b/host/commands/run_cvd/process_monitor.cc
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include "host/commands/run_cvd/process_monitor.h"
+
+#include <sys/prctl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
@@ -22,199 +25,194 @@
 #include <signal.h>
 #include <stdio.h>
 
-#include <map>
+#include <algorithm>
+#include <thread>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
+#include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_select.h"
-#include "host/commands/run_cvd/process_monitor.h"
 
-namespace cvd {
+namespace cuttlefish {
 
-namespace {
+struct ParentToChildMessage {
+  bool stop;
+};
 
-void NotifyThread(SharedFD fd) {
-  // The restarter thread is (likely) blocked on a call to select, to make it
-  // wake up and do some work we write something (anything, the content is not
-  // important) into the main side of the socket pair so that the call to select
-  // returns and the notification fd (restarter side of the socket pair) is
-  // marked as ready to read.
-  char buffer = 'a';
-  fd->Write(&buffer, sizeof(buffer));
+ProcessMonitor::ProcessMonitor(bool restart_subprocesses)
+    : restart_subprocesses_(restart_subprocesses), monitor_(-1) {
 }
 
-void ConsumeNotifications(SharedFD fd) {
-  // Once the starter thread is waken up due to a notification, the calls to
-  // select will continue to return immediately unless we read what was written
-  // on the main side of the socket pair. More than one notification can
-  // accumulate before the restarter thread consumes them, so we attempt to read
-  // more than it's written to consume them all at once. In the unlikely case of
-  // more than 8 notifications acummulating we simply read the first 8 and have
-  // another iteration on the restarter thread loop.
-  char buffer[8];
-  fd->Read(buffer, sizeof(buffer));
-}
+void ProcessMonitor::AddCommand(Command cmd) {
+  CHECK(monitor_ == -1) << "The monitor process is already running.";
+  CHECK(!monitor_socket_->IsOpen()) << "The monitor socket is already open.";
 
-}  // namespace
-
-ProcessMonitor::ProcessMonitor() {
-  if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &thread_comm_main_,
-                            &thread_comm_monitor_)) {
-    LOG(ERROR) << "Unable to create restarter communication socket pair: "
-               << strerror(errno);
-    return;
-  }
-  monitor_thread_ = std::thread([this]() { MonitorRoutine(); });
-}
-
-void ProcessMonitor::StartSubprocess(Command cmd, OnSocketReadyCb callback) {
-  cvd::SubprocessOptions options;
-  options.InGroup(true);
-  options.WithControlSocket(true);
-  auto proc = cmd.Start(options);
-  if (!proc.Started()) {
-    LOG(ERROR) << "Failed to start process";
-    return;
-  }
-  MonitorExistingSubprocess(std::move(cmd), std::move(proc), callback);
-}
-
-void ProcessMonitor::MonitorExistingSubprocess(Command cmd, Subprocess proc,
-                                               OnSocketReadyCb callback) {
-  {
-    std::lock_guard<std::mutex> lock(processes_mutex_);
-    monitored_processes_.push_back(MonitorEntry());
-    auto& entry = monitored_processes_.back();
-    entry.cmd.reset(new Command(std::move(cmd)));
-    entry.proc.reset(new Subprocess(std::move(proc)));
-    entry.on_control_socket_ready_cb = callback;
-  }
-  // Wake the restarter thread up so that it starts monitoring this subprocess
-  // Do this after releasing the lock so that the restarter thread is free to
-  // begin work as soon as select returns.
-  NotifyThread(thread_comm_main_);
+  monitored_processes_.push_back(MonitorEntry());
+  auto& entry = monitored_processes_.back();
+  entry.cmd.reset(new Command(std::move(cmd)));
 }
 
 bool ProcessMonitor::StopMonitoredProcesses() {
-  // Because the mutex is held while this function executes, the restarter
-  // thread is kept blocked and by the time it resumes execution there are no
-  // more processes to monitor
-  std::lock_guard<std::mutex> lock(processes_mutex_);
-  bool result = true;
-  // Processes were started in the order they appear in the vector, stop them in
-  // reverse order for symmetry.
-  for (auto entry_it = monitored_processes_.rbegin();
-       entry_it != monitored_processes_.rend(); ++entry_it) {
-    auto& entry = *entry_it;
-    result = result && entry.proc->Stop();
+  if (monitor_ == -1) {
+    LOG(ERROR) << "The monitor process is already dead.";
+    return false;
   }
-  // Wait for all processes to actually exit.
-  for (auto& entry : monitored_processes_) {
-    // Most processes are being killed by signals, calling Wait(void) would be
-    // too verbose on the logs.
-    int wstatus;
-    auto ret = entry.proc->Wait(&wstatus, 0);
-    if (ret < 0) {
-      LOG(WARNING) << "Failed to wait for process "
-                   << entry.cmd->GetShortName();
-    }
+  if (!monitor_socket_->IsOpen()) {
+    LOG(ERROR) << "The monitor socket is already closed.";
+    return false;
   }
-  // Clear the list to ensure they are not started again
-  monitored_processes_.clear();
-  return result;
-}
-
-bool ProcessMonitor::RestartOnExitCb(MonitorEntry* entry) {
-  // Make sure the process actually exited
-  char buffer[16];
-  auto bytes_read = entry->proc->control_socket()->Read(buffer, sizeof(buffer));
-  if (bytes_read > 0) {
-    LOG(WARNING) << "Subprocess " << entry->cmd->GetShortName() << " wrote "
-                 << bytes_read
-                 << " bytes on the control socket, this is unexpected";
-    // The process may not have exited, continue monitoring without restarting
-    return true;
+  ParentToChildMessage message;
+  message.stop = true;
+  if (WriteAllBinary(monitor_socket_, &message) != sizeof(message)) {
+    LOG(ERROR) << "Failed to communicate with monitor socket: "
+                << monitor_socket_->StrError();
+    return false;
   }
-
-  LOG(INFO) << "Detected exit of monitored subprocess";
-  // Make sure the subprocess isn't left in a zombie state, and that the
-  // pid is logged
+  pid_t last_monitor = monitor_;
+  monitor_ = -1;
+  monitor_socket_->Close();
   int wstatus;
-  auto wait_ret = TEMP_FAILURE_RETRY(entry->proc->Wait(&wstatus, 0));
-  // None of the error conditions specified on waitpid(2) apply
-  assert(wait_ret > 0);
-  if (WIFEXITED(wstatus)) {
-    LOG(INFO) << "Subprocess " << entry->cmd->GetShortName() << " (" << wait_ret
-              << ") has exited with exit code " << WEXITSTATUS(wstatus);
-  } else if (WIFSIGNALED(wstatus)) {
-    LOG(ERROR) << "Subprocess " << entry->cmd->GetShortName() << " ("
-               << wait_ret
-               << ") was interrupted by a signal: " << WTERMSIG(wstatus);
-  } else {
-    LOG(INFO) << "subprocess " << entry->cmd->GetShortName() << " (" << wait_ret
-              << ") has exited for unknown reasons";
+  if (waitpid(last_monitor, &wstatus, 0) != last_monitor) {
+    LOG(ERROR) << "Failed to wait for monitor process";
+    return false;
   }
-  cvd::SubprocessOptions options;
-  options.WithControlSocket(true);
-  entry->proc.reset(new Subprocess(entry->cmd->Start(options)));
+  if (WIFSIGNALED(wstatus)) {
+    LOG(ERROR) << "Monitor process exited due to a signal";
+    return false;
+  }
+  if (!WIFEXITED(wstatus)) {
+    LOG(ERROR) << "Monitor process exited for unknown reasons";
+    return false;
+  }
+  if (WEXITSTATUS(wstatus) != 0) {
+    LOG(ERROR) << "Monitor process exited with code " << WEXITSTATUS(wstatus);
+    return false;
+  }
   return true;
 }
 
-bool ProcessMonitor::DoNotMonitorCb(MonitorEntry*) { return false; }
-
-void ProcessMonitor::MonitorRoutine() {
-  LOG(INFO) << "Started monitoring subprocesses";
-  do {
-    SharedFDSet read_set;
-    read_set.Set(thread_comm_monitor_);
-    {
-      std::lock_guard<std::mutex> lock(processes_mutex_);
-      for (auto& monitored_process : monitored_processes_) {
-        auto control_socket = monitored_process.proc->control_socket();
-        if (!control_socket->IsOpen()) {
-          LOG(ERROR) << "The control socket for "
-                     << monitored_process.cmd->GetShortName()
-                     << " is closed, it's effectively NOT being monitored";
-        }
-        read_set.Set(control_socket);
-      }
-    }
-    // We can't call select while holding the lock as it would lead to a
-    // deadlock (restarter thread waiting for notifications from main thread,
-    // main thread waiting for the lock)
-    int num_fds = cvd::Select(&read_set, nullptr, nullptr, nullptr);
-    if (num_fds < 0) {
-      LOG(ERROR) << "Select call returned error on restarter thread: "
-                 << strerror(errno);
-    }
-    if (num_fds > 0) {
-      // Try the communication fd, it's the most likely to be set
-      if (read_set.IsSet(thread_comm_monitor_)) {
-        --num_fds;
-        ConsumeNotifications(thread_comm_monitor_);
-      }
-    }
-    {
-      std::lock_guard<std::mutex> lock(processes_mutex_);
-      // Keep track of the number of file descriptors ready for read, chances
-      // are we don't need to go over the entire list of subprocesses
-      auto it = monitored_processes_.begin();
-      while (it != monitored_processes_.end()) {
-        auto control_socket = it->proc->control_socket();
-        bool keep_monitoring = true;
-        if (read_set.IsSet(control_socket)) {
-          --num_fds;
-          keep_monitoring = it->on_control_socket_ready_cb(&(*it));
-        }
-        if (keep_monitoring) {
-          ++it;
-        } else {
-          it = monitored_processes_.erase(it);
-        }
-      }
-    }
-    assert(num_fds == 0);
-  } while (true);
+bool ProcessMonitor::StartAndMonitorProcesses() {
+  if (monitor_ != -1) {
+    LOG(ERROR) << "The monitor process was already started";
+    return false;
+  }
+  if (monitor_socket_->IsOpen()) {
+    LOG(ERROR) << "The monitor socket was already opened.";
+    return false;
+  }
+  SharedFD client_pipe, host_pipe;
+  if (!SharedFD::Pipe(&client_pipe, &host_pipe)) {
+    LOG(ERROR) << "Could not create the monitor socket.";
+    return false;
+  }
+  monitor_ = fork();
+  if (monitor_ == 0) {
+    monitor_socket_ = client_pipe;
+    host_pipe->Close();
+    std::exit(MonitorRoutine() ? 0 : 1);
+  } else {
+    client_pipe->Close();
+    monitor_socket_ = host_pipe;
+    return true;
+  }
 }
 
-}  // namespace cvd
+static void LogSubprocessExit(const std::string& name, pid_t pid, int wstatus) {
+  LOG(INFO) << "Detected exit of monitored subprocess " << name;
+  if (WIFEXITED(wstatus)) {
+    LOG(INFO) << "Subprocess " << name << " (" << pid
+              << ") has exited with exit code " << WEXITSTATUS(wstatus);
+  } else if (WIFSIGNALED(wstatus)) {
+    LOG(ERROR) << "Subprocess " << name << " (" << pid
+               << ") was interrupted by a signal: " << WTERMSIG(wstatus);
+  } else {
+    LOG(INFO) << "subprocess " << name << " (" << pid
+              << ") has exited for unknown reasons";
+  }
+}
+
+bool ProcessMonitor::MonitorRoutine() {
+  // Make this process a subreaper to reliably catch subprocess exits.
+  // See https://man7.org/linux/man-pages/man2/prctl.2.html
+  prctl(PR_SET_CHILD_SUBREAPER, 1);
+  prctl(PR_SET_PDEATHSIG, SIGHUP); // Die when parent dies
+
+  LOG(DEBUG) << "Starting monitoring subprocesses";
+  for (auto& monitored : monitored_processes_) {
+    cuttlefish::SubprocessOptions options;
+    options.InGroup(true);
+    monitored.proc.reset(new Subprocess(monitored.cmd->Start(options)));
+    CHECK(monitored.proc->Started()) << "Failed to start process";
+  }
+
+  bool running = true;
+  std::thread parent_comms_thread([&running, this]() {
+    LOG(DEBUG) << "Waiting for a `stop` message from the parent.";
+    while (running) {
+      ParentToChildMessage message;
+      CHECK(ReadExactBinary(monitor_socket_, &message) == sizeof(message))
+          << "Could not read message from parent.";
+      if (message.stop) {
+        running = false;
+        // Wake up the wait() loop by giving it an exited child process
+        if (fork() == 0) {
+          std::exit(0);
+        }
+      }
+    }
+  });
+
+  auto& monitored = monitored_processes_;
+
+  LOG(DEBUG) << "Monitoring subprocesses";
+  while(running) {
+    int wstatus;
+    pid_t pid = wait(&wstatus);
+    int error_num = errno;
+    CHECK(pid != -1) << "Wait failed: " << strerror(error_num);
+    if (!WIFSIGNALED(wstatus) && !WIFEXITED(wstatus)) {
+      LOG(DEBUG) << "Unexpected status from wait: " << wstatus
+                  << " for pid " << pid;
+      continue;
+    }
+    if (!running) { // Avoid extra restarts near the end
+      break;
+    }
+    auto matches = [pid](const auto& it) { return it.proc->pid() == pid; };
+    auto it = std::find_if(monitored.begin(), monitored.end(), matches);
+    if (it == monitored.end()) {
+      LogSubprocessExit("(unknown)", pid, wstatus);
+    } else {
+      LogSubprocessExit(it->cmd->GetShortName(), it->proc->pid(), wstatus);
+      if (restart_subprocesses_) {
+        cuttlefish::SubprocessOptions options;
+        options.InGroup(true);
+        it->proc.reset(new Subprocess(it->cmd->Start(options)));
+      } else {
+        monitored_processes_.erase(it);
+      }
+    }
+  }
+
+  parent_comms_thread.join(); // Should have exited if `running` is false
+  // Processes were started in the order they appear in the vector, stop them in
+  // reverse order for symmetry.
+  auto stop = [](const auto& it) {
+    if (!it.proc->Stop()) {
+      LOG(WARNING) << "Error in stopping \"" << it.cmd->GetShortName() << "\"";
+      return false;
+    }
+    int wstatus = 0;
+    auto ret = it.proc->Wait(&wstatus, 0);
+    if (ret < 0) {
+      LOG(WARNING) << "Failed to wait for process " << it.cmd->GetShortName();
+      return false;
+    }
+    return true;
+  };
+  size_t stopped = std::count_if(monitored.rbegin(), monitored.rend(), stop);
+  LOG(DEBUG) << "Done monitoring subprocesses";
+  return stopped == monitored.size();
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/process_monitor.h b/host/commands/run_cvd/process_monitor.h
index 5683c61..18b8ab8 100644
--- a/host/commands/run_cvd/process_monitor.h
+++ b/host/commands/run_cvd/process_monitor.h
@@ -22,44 +22,43 @@
 
 #include <common/libs/utils/subprocess.h>
 
-namespace cvd {
+namespace cuttlefish {
 
 struct MonitorEntry;
-using OnSocketReadyCb = std::function<bool(MonitorEntry*)>;
+using OnSocketReadyCb = std::function<bool(MonitorEntry*, int)>;
 
 struct MonitorEntry {
   std::unique_ptr<Command> cmd;
   std::unique_ptr<Subprocess> proc;
-  OnSocketReadyCb on_control_socket_ready_cb;
 };
 
 // Keeps track of launched subprocesses, restarts them if they unexpectedly exit
 class ProcessMonitor {
  public:
-  ProcessMonitor();
-  // Starts a managed subprocess with a controlling socket.
-  // The on_control_socket_ready_cb callback will be called when data is ready
-  // to be read from the socket or the subprocess has ended. No member functions
-  // of the process monitor object should be called from the callback as it may
-  // lead to a deadlock. If the callback returns false the subprocess will no
-  // longer be monitored.
-  void StartSubprocess(Command cmd, OnSocketReadyCb on_control_socket_ready_cb);
-  // Monitors an already started subprocess
-  void MonitorExistingSubprocess(Command cmd, Subprocess sub_process,
-                                 OnSocketReadyCb on_control_socket_ready_cb);
+  ProcessMonitor(bool restart_subprocesses);
+  // Adds a command to the list of commands to be run and monitored. The
+  // callback will be called when the subprocess has ended.  If the callback
+  // returns false the subprocess will no longer be monitored. Can only be
+  // called before StartAndMonitorProcesses is called. OnSocketReadyCb will be
+  // called inside a forked process.
+  void AddCommand(Command cmd);
+  template <typename T>
+  void AddCommands(T&& commands) {
+    for (auto& command : commands) {
+      AddCommand(std::move(command));
+    }
+  }
+
+  // Start all processes given by AddCommand.
+  bool StartAndMonitorProcesses();
   // Stops all monitored subprocesses.
   bool StopMonitoredProcesses();
-  static bool RestartOnExitCb(MonitorEntry* entry);
-  static bool DoNotMonitorCb(MonitorEntry* entry);
-
  private:
-  void MonitorRoutine();
+  bool MonitorRoutine();
 
+  bool restart_subprocesses_;
   std::vector<MonitorEntry> monitored_processes_;
-  // Used for communication with the restarter thread
-  cvd::SharedFD thread_comm_main_, thread_comm_monitor_;
-  std::thread monitor_thread_;
-  // Protects access to the monitored_processes_
-  std::mutex processes_mutex_;
+  pid_t monitor_;
+  SharedFD monitor_socket_;
 };
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/runner_defs.h b/host/commands/run_cvd/runner_defs.h
index daf8868..b51e894 100644
--- a/host/commands/run_cvd/runner_defs.h
+++ b/host/commands/run_cvd/runner_defs.h
@@ -15,10 +15,7 @@
  */
 #pragma once
 
-namespace cvd {
-
-constexpr char kLogcatSerialMode[] = "serial";
-constexpr char kLogcatVsockMode[] = "vsock";
+namespace cuttlefish {
 
 enum RunnerExitCodes : int {
   kSuccess = 0,
@@ -45,10 +42,15 @@
   kTombstoneDirCreationError = 21,
   kInitRamFsConcatError = 22,
   kTapDeviceInUse = 23,
+  kTpmPassthroughError = 24,
+  kModemSimulatorServerError = 25,
+  kSocketProxyServerError = 26,
 };
 
 // Actions supported by the launcher server
 enum class LauncherAction : char {
+  kPowerwash = 'P',
+  kRestart = 'R',
   kStatus = 'I',
   kStop = 'X',
 };
@@ -59,4 +61,4 @@
   kError = 'E',
   kUnknownAction = 'U',
 };
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/server_loop.cpp b/host/commands/run_cvd/server_loop.cpp
new file mode 100644
index 0000000..5e77b9d
--- /dev/null
+++ b/host/commands/run_cvd/server_loop.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "host/commands/run_cvd/server_loop.h"
+
+#include <gflags/gflags.h>
+#include <unistd.h>
+#include <string>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/commands/run_cvd/runner_defs.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/data_image.h"
+
+namespace cuttlefish {
+
+namespace {
+
+bool CreateQcowOverlay(const std::string& crosvm_path,
+                       const std::string& backing_file,
+                       const std::string& output_overlay_path) {
+  Command crosvm_qcow2_cmd(crosvm_path);
+  crosvm_qcow2_cmd.AddParameter("create_qcow2");
+  crosvm_qcow2_cmd.AddParameter("--backing_file=", backing_file);
+  crosvm_qcow2_cmd.AddParameter(output_overlay_path);
+  int success = crosvm_qcow2_cmd.Start().Wait();
+  if (success != 0) {
+    LOG(ERROR) << "Unable to run crosvm create_qcow2. Exited with status "
+               << success;
+    return false;
+  }
+  return true;
+}
+
+void DeleteFifos(const CuttlefishConfig::InstanceSpecific& instance) {
+  // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd.
+  std::vector<std::string> pipes = {
+      instance.kernel_log_pipe_name(),
+      instance.console_in_pipe_name(),
+      instance.console_out_pipe_name(),
+      instance.logcat_pipe_name(),
+      instance.PerInstanceInternalPath("keymaster_fifo_vm.in"),
+      instance.PerInstanceInternalPath("keymaster_fifo_vm.out"),
+      instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
+      instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
+      instance.PerInstanceInternalPath("bt_fifo_vm.in"),
+      instance.PerInstanceInternalPath("bt_fifo_vm.out"),
+  };
+  for (const auto& pipe : pipes) {
+    unlink(pipe.c_str());
+  }
+}
+
+bool PowerwashFiles() {
+  auto config = CuttlefishConfig::Get();
+  if (!config) {
+    LOG(ERROR) << "Could not load the config.";
+    return false;
+  }
+  auto instance = config->ForDefaultInstance();
+
+  DeleteFifos(instance);
+
+  // TODO(schuffelen): Clean up duplication with assemble_cvd
+  auto kregistry_path = instance.access_kregistry_path();
+  unlink(kregistry_path.c_str());
+  CreateBlankImage(kregistry_path, 2 /* mb */, "none");
+
+  auto pstore_path = instance.pstore_path();
+  unlink(pstore_path.c_str());
+  CreateBlankImage(pstore_path, 2 /* mb */, "none");
+
+  auto sdcard_path = instance.sdcard_path();
+  auto sdcard_size = FileSize(sdcard_path);
+  unlink(sdcard_path.c_str());
+  // round up
+  auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
+  LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
+  CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
+
+  auto overlay_path = instance.PerInstancePath("overlay.img");
+  unlink(overlay_path.c_str());
+  if (!CreateQcowOverlay(config->crosvm_binary(),
+                         instance.os_composite_disk_path(), overlay_path)) {
+    LOG(ERROR) << "CreateQcowOverlay failed";
+    return false;
+  }
+  return true;
+}
+
+void RestartRunCvd(const CuttlefishConfig& config, int notification_fd) {
+  auto config_path = config.AssemblyPath("cuttlefish_config.json");
+  auto followup_stdin = SharedFD::MemfdCreate("pseudo_stdin");
+  WriteAll(followup_stdin, config_path + "\n");
+  followup_stdin->LSeek(0, SEEK_SET);
+  followup_stdin->UNMANAGED_Dup2(0);
+
+  auto argv_vec = gflags::GetArgvs();
+  char** argv = new char*[argv_vec.size() + 2];
+  for (size_t i = 0; i < argv_vec.size(); i++) {
+    argv[i] = argv_vec[i].data();
+  }
+  // Will take precedence over any earlier arguments.
+  std::string reboot_notification =
+      "-reboot_notification_fd=" + std::to_string(notification_fd);
+  argv[argv_vec.size()] = reboot_notification.data();
+  argv[argv_vec.size() + 1] = nullptr;
+
+  execv("/proc/self/exe", argv);
+  // execve should not return, so something went wrong.
+  PLOG(ERROR) << "execv returned: ";
+}
+
+}  // namespace
+
+void ServerLoop(SharedFD server, ProcessMonitor* process_monitor) {
+  while (true) {
+    // TODO: use select to handle simultaneous connections.
+    auto client = SharedFD::Accept(*server);
+    LauncherAction action;
+    while (client->IsOpen() && client->Read(&action, sizeof(action)) > 0) {
+      switch (action) {
+        case LauncherAction::kStop:
+          if (process_monitor->StopMonitoredProcesses()) {
+            auto response = LauncherResponse::kSuccess;
+            client->Write(&response, sizeof(response));
+            std::exit(0);
+          } else {
+            auto response = LauncherResponse::kError;
+            client->Write(&response, sizeof(response));
+          }
+          break;
+        case LauncherAction::kStatus: {
+          // TODO(schuffelen): Return more information on a side channel
+          auto response = LauncherResponse::kSuccess;
+          client->Write(&response, sizeof(response));
+          break;
+        }
+        case LauncherAction::kPowerwash: {
+          LOG(INFO) << "Received a Powerwash request from the monitor socket";
+          if (!process_monitor->StopMonitoredProcesses()) {
+            LOG(ERROR) << "Stopping processes failed.";
+            auto response = LauncherResponse::kError;
+            client->Write(&response, sizeof(response));
+            break;
+          }
+          if (!PowerwashFiles()) {
+            LOG(ERROR) << "Powerwashing files failed.";
+            auto response = LauncherResponse::kError;
+            client->Write(&response, sizeof(response));
+            break;
+          }
+          auto response = LauncherResponse::kSuccess;
+          client->Write(&response, sizeof(response));
+
+          auto config = CuttlefishConfig::Get();
+          CHECK(config) << "Could not load config";
+          RestartRunCvd(*config, client->UNMANAGED_Dup());
+          // RestartRunCvd should not return, so something went wrong.
+          response = LauncherResponse::kError;
+          client->Write(&response, sizeof(response));
+          LOG(FATAL) << "run_cvd in a bad state";
+          break;
+        }
+        case LauncherAction::kRestart: {
+          if (!process_monitor->StopMonitoredProcesses()) {
+            LOG(ERROR) << "Stopping processes failed.";
+            auto response = LauncherResponse::kError;
+            client->Write(&response, sizeof(response));
+            break;
+          }
+
+          auto config = CuttlefishConfig::Get();
+          CHECK(config) << "Could not load config";
+          auto instance = config->ForDefaultInstance();
+          DeleteFifos(instance);
+
+          auto response = LauncherResponse::kSuccess;
+          client->Write(&response, sizeof(response));
+          CHECK(config) << "Could not load config";
+          RestartRunCvd(*config, client->UNMANAGED_Dup());
+          // RestartRunCvd should not return, so something went wrong.
+          response = LauncherResponse::kError;
+          client->Write(&response, sizeof(response));
+          LOG(FATAL) << "run_cvd in a bad state";
+          break;
+        }
+        default:
+          LOG(ERROR) << "Unrecognized launcher action: "
+                     << static_cast<char>(action);
+          auto response = LauncherResponse::kError;
+          client->Write(&response, sizeof(response));
+      }
+    }
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/run_cvd/server_loop.h b/host/commands/run_cvd/server_loop.h
new file mode 100644
index 0000000..327aff4
--- /dev/null
+++ b/host/commands/run_cvd/server_loop.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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 "common/libs/fs/shared_fd.h"
+#include "host/commands/run_cvd/process_monitor.h"
+
+namespace cuttlefish {
+
+void ServerLoop(SharedFD server, ProcessMonitor* process_monitor);
+
+}
diff --git a/host/commands/secure_env/Android.bp b/host/commands/secure_env/Android.bp
new file mode 100644
index 0000000..3ceeda5
--- /dev/null
+++ b/host/commands/secure_env/Android.bp
@@ -0,0 +1,77 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary_host {
+    name: "secure_env",
+    srcs: [
+        "composite_serialization.cpp",
+        "device_tpm.cpp",
+        "encrypted_serializable.cpp",
+        "fragile_tpm_storage.cpp",
+        "gatekeeper_responder.cpp",
+        "hmac_serializable.cpp",
+        "in_process_tpm.cpp",
+        "insecure_fallback_storage.cpp",
+        "json_serializable.cpp",
+        "keymaster_responder.cpp",
+        "primary_key_builder.cpp",
+        "secure_env.cpp",
+        "tpm_attestation_record.cpp",
+        "tpm_auth.cpp",
+        "tpm_commands.cpp",
+        "tpm_encrypt_decrypt.cpp",
+        "tpm_gatekeeper.cpp",
+        "tpm_hmac.cpp",
+        "tpm_key_blob_maker.cpp",
+        "tpm_keymaster_context.cpp",
+        "tpm_keymaster_enforcement.cpp",
+        "tpm_random_source.cpp",
+        "tpm_resource_manager.cpp",
+        "tpm_serialize.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_security",
+        "libcuttlefish_utils",
+        "libgatekeeper",
+        "libjsoncpp",
+        "libkeymaster_portable",
+        "libkeymaster_messages",
+        "libsoft_attestation_cert",
+        "liblog",
+        "libcrypto",
+        "libcutils",
+        "libpuresoftkeymasterdevice_host",
+        "ms-tpm-20-ref-lib",
+        "tpm2-tss2-esys",
+        "tpm2-tss2-mu",
+        "tpm2-tss2-rc",
+        "tpm2-tss2-tcti",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+        "libscrypt_static",
+    ],
+    defaults: ["cuttlefish_buildhost_only"],
+    cflags: [
+        "-fno-rtti", // Required for libkeymaster_portable
+    ],
+}
diff --git a/host/commands/secure_env/OWNERS b/host/commands/secure_env/OWNERS
new file mode 100644
index 0000000..f9d83f2
--- /dev/null
+++ b/host/commands/secure_env/OWNERS
@@ -0,0 +1,2 @@
+include platform/system/keymaster:/OWNERS
+include platform/system/gatekeeper:/OWNERS
diff --git a/host/commands/secure_env/composite_serialization.cpp b/host/commands/secure_env/composite_serialization.cpp
new file mode 100644
index 0000000..e3d6e43
--- /dev/null
+++ b/host/commands/secure_env/composite_serialization.cpp
@@ -0,0 +1,48 @@
+//
+// 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.
+
+#include "composite_serialization.h"
+
+using keymaster::Serializable;
+
+CompositeSerializable::CompositeSerializable(
+    const std::vector<Serializable*>& members) : members_(members) {
+}
+
+size_t CompositeSerializable::SerializedSize() const {
+  size_t sum = 0;
+  for (const auto& member : members_) {
+    sum += member->SerializedSize();
+  }
+  return sum;
+}
+
+uint8_t* CompositeSerializable::Serialize(
+    uint8_t* buf, const uint8_t* end) const {
+  for (const auto& member : members_) {
+    buf = member->Serialize(buf, end);
+  }
+  return buf;
+}
+
+bool CompositeSerializable::Deserialize(
+    const uint8_t** buf_ptr, const uint8_t* end) {
+  for (const auto& member : members_) {
+    if (!member->Deserialize(buf_ptr, end)) {
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/host/commands/secure_env/composite_serialization.h b/host/commands/secure_env/composite_serialization.h
new file mode 100644
index 0000000..dfe2883
--- /dev/null
+++ b/host/commands/secure_env/composite_serialization.h
@@ -0,0 +1,39 @@
+//
+// 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 <vector>
+
+#include "keymaster/serializable.h"
+
+/**
+ * A keymaster::Serializable type that refers to multiple other
+ * keymaster::Serializable instances by pointer. When data is serialized or
+ * deserialized, it's delegated to the instances pointed to.
+ *
+ * The serialization format is to put the instances one after the other in
+ * the byte stream.
+ */
+class CompositeSerializable : public keymaster::Serializable {
+public:
+  CompositeSerializable(const std::vector<keymaster::Serializable*>&);
+
+  size_t SerializedSize() const override;
+  uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+  bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+private:
+  std::vector<keymaster::Serializable*> members_;
+};
diff --git a/host/commands/secure_env/device_tpm.cpp b/host/commands/secure_env/device_tpm.cpp
new file mode 100644
index 0000000..6e4b4be
--- /dev/null
+++ b/host/commands/secure_env/device_tpm.cpp
@@ -0,0 +1,54 @@
+//
+// 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.
+
+#include "host/commands/secure_env/device_tpm.h"
+
+#include <android-base/logging.h>
+#include <tss2/tss2_rc.h>
+#include <tss2/tss2_tcti.h>
+#include <tss2/tss2_tcti_device.h>
+
+static void FinalizeTcti(TSS2_TCTI_CONTEXT* tcti_context) {
+  if (tcti_context == nullptr) {
+    return;
+  }
+  auto finalize_fn = TSS2_TCTI_FINALIZE(tcti_context);
+  if (finalize_fn != nullptr) {
+    finalize_fn(tcti_context);
+  }
+  delete[] (char*) tcti_context;
+}
+
+DeviceTpm::DeviceTpm(const std::string& path) : tpm_(nullptr, &FinalizeTcti) {
+  size_t size = 0;
+  auto rc = Tss2_Tcti_Device_Init(nullptr, &size, path.c_str());
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Could not get Device TCTI size: " << Tss2_RC_Decode(rc)
+               << "(" << rc << ")";
+    return;
+  }
+  tpm_.reset(reinterpret_cast<TSS2_TCTI_CONTEXT*>(new char[size]));
+  rc = Tss2_Tcti_Device_Init(tpm_.get(), &size, path.c_str());
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Could not create Device TCTI: " << Tss2_RC_Decode(rc)
+               << "(" << rc << ")";
+    delete[] (char*) tpm_.release();
+    return;
+  }
+}
+
+TSS2_TCTI_CONTEXT* DeviceTpm::TctiContext() {
+  return tpm_.get();
+}
diff --git a/host/commands/secure_env/device_tpm.h b/host/commands/secure_env/device_tpm.h
new file mode 100644
index 0000000..a52666e
--- /dev/null
+++ b/host/commands/secure_env/device_tpm.h
@@ -0,0 +1,35 @@
+//
+// 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 <memory>
+
+#include <tss2/tss2_tcti.h>
+
+#include "host/commands/secure_env/tpm.h"
+
+/*
+ * Exposes a TSS2_TCTI_CONTEXT for interacting with a TPM device node.
+ */
+class DeviceTpm : public Tpm {
+public:
+  DeviceTpm(const std::string& path);
+  ~DeviceTpm() = default;
+
+  TSS2_TCTI_CONTEXT* TctiContext() override;
+private:
+  std::unique_ptr<TSS2_TCTI_CONTEXT, void(*)(TSS2_TCTI_CONTEXT*)> tpm_;
+};
diff --git a/host/commands/secure_env/encrypted_serializable.cpp b/host/commands/secure_env/encrypted_serializable.cpp
new file mode 100644
index 0000000..3845212
--- /dev/null
+++ b/host/commands/secure_env/encrypted_serializable.cpp
@@ -0,0 +1,300 @@
+//
+// 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.
+
+#include "encrypted_serializable.h"
+
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include "host/commands/secure_env/tpm_auth.h"
+#include "host/commands/secure_env/tpm_encrypt_decrypt.h"
+#include "host/commands/secure_env/tpm_serialize.h"
+
+EncryptedSerializable::EncryptedSerializable(
+    TpmResourceManager& resource_manager,
+    std::function<TpmObjectSlot(TpmResourceManager&)> parent_key_fn,
+    Serializable& wrapped) :
+    resource_manager_(resource_manager),
+    parent_key_fn_(parent_key_fn),
+    wrapped_(wrapped) {
+}
+
+static bool CreateKey(
+    TpmResourceManager& resource_manager, // in
+    ESYS_TR parent_key, // in
+    TPM2B_PUBLIC* key_public_out, // out
+    TPM2B_PRIVATE* key_private_out, // out
+    TpmObjectSlot* key_slot_out) { // out
+  TPM2B_AUTH authValue = {};
+  auto rc = Esys_TR_SetAuth(resource_manager.Esys(), parent_key, &authValue);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return false;
+  }
+
+  TPMT_PUBLIC public_area = {
+    .type = TPM2_ALG_SYMCIPHER,
+    .nameAlg = TPM2_ALG_SHA256,
+    .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
+                         TPMA_OBJECT_DECRYPT |
+                         TPMA_OBJECT_SIGN_ENCRYPT |
+                         TPMA_OBJECT_FIXEDTPM |
+                         TPMA_OBJECT_FIXEDPARENT |
+                         TPMA_OBJECT_SENSITIVEDATAORIGIN),
+    .authPolicy.size = 0,
+    .parameters.symDetail.sym = {
+      .algorithm = TPM2_ALG_AES,
+      .keyBits.aes = 128, // The default maximum AES key size in the simulator.
+      .mode.aes = TPM2_ALG_CFB,
+    },
+  };
+
+  TPM2B_TEMPLATE public_template = {};
+  size_t offset = 0;
+  rc = Tss2_MU_TPMT_PUBLIC_Marshal(&public_area, &public_template.buffer[0],
+                                   sizeof(public_template.buffer), &offset);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Tss2_MU_TPMT_PUBLIC_Marshal failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return false;
+  }
+  public_template.size = offset;
+
+  TPM2B_SENSITIVE_CREATE in_sensitive = {};
+
+  auto key_slot = resource_manager.ReserveSlot();
+  if (!key_slot) {
+    LOG(ERROR) << "No slots available";
+    return false;
+  }
+  ESYS_TR raw_handle;
+  // TODO(b/154956668): Define better ACLs on these keys.
+  TPM2B_PUBLIC* key_public = nullptr;
+  TPM2B_PRIVATE* key_private = nullptr;
+  // TODO(schuffelen): Use Esys_Create when key_slot is NULL
+  rc = Esys_CreateLoaded(
+    /* esysContext */ resource_manager.Esys(),
+    /* primaryHandle */ parent_key,
+    /* shandle1 */ ESYS_TR_PASSWORD,
+    /* shandle2 */ ESYS_TR_NONE,
+    /* shandle3 */ ESYS_TR_NONE,
+    /* inSensitive */ &in_sensitive,
+    /* inPublic */ &public_template,
+    /* objectHandle */ &raw_handle,
+    /* outPrivate */ &key_private,
+    /* outPublic */ &key_public);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return false;
+  }
+  CHECK(key_public != nullptr) << "key_public was not assigned.";
+  CHECK(key_private != nullptr) << "key_private was not assigned.";
+  *key_public_out = *key_public;
+  *key_private_out = *key_private;
+  key_slot->set(raw_handle);
+  Esys_Free(key_public);
+  Esys_Free(key_private);
+  if (key_slot_out) {
+    rc = Esys_TR_SetAuth(resource_manager.Esys(), raw_handle, &authValue);
+    if (rc != TSS2_RC_SUCCESS) {
+      LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
+                << " (" << Tss2_RC_Decode(rc) << ")";
+      return false;
+    }
+  }
+  if (key_slot_out) {
+    *key_slot_out = key_slot;
+  }
+  return true;
+}
+
+static TpmObjectSlot LoadKey(
+    TpmResourceManager& resource_manager,
+    ESYS_TR parent_key,
+    const TPM2B_PUBLIC* key_public,
+    const TPM2B_PRIVATE* key_private) {
+  // TODO
+  ESYS_TR raw_handle;
+  auto key_slot = resource_manager.ReserveSlot();
+  if (!key_slot) {
+    LOG(ERROR) << "No slots available";
+    return {};
+  }
+  auto rc = Esys_Load(
+      resource_manager.Esys(),
+      parent_key,
+      ESYS_TR_PASSWORD,
+      ESYS_TR_NONE,
+      ESYS_TR_NONE,
+      key_private,
+      key_public,
+      &raw_handle);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_Load failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return {};
+  }
+  key_slot->set(raw_handle);
+  return key_slot;
+}
+
+static constexpr uint32_t BLOCK_SIZE = 16;
+
+static uint32_t RoundUpToBlockSize(uint32_t num) {
+  return num % BLOCK_SIZE == 0 ? num : num + (BLOCK_SIZE - (num % BLOCK_SIZE));
+}
+
+size_t EncryptedSerializable::SerializedSize() const {
+  TPM2B_PUBLIC key_public;
+  TPM2B_PRIVATE key_private;
+  auto parent = parent_key_fn_(resource_manager_);
+  if (!CreateKey(
+      resource_manager_, parent->get(), &key_public, &key_private, nullptr)) {
+    LOG(ERROR) << "Unable to create key";
+    return 0;
+  }
+  // Assumes all created keys will have the same size.
+  SerializeTpmKeyPublic serialize_public(&key_public);
+  SerializeTpmKeyPrivate serialize_private(&key_private);
+  auto encrypted_size = RoundUpToBlockSize(wrapped_.SerializedSize());
+  return serialize_public.SerializedSize()
+    + serialize_private.SerializedSize()
+    + sizeof(uint32_t)
+    + sizeof(uint32_t)
+    + encrypted_size;
+}
+
+uint8_t* EncryptedSerializable::Serialize(
+    uint8_t* buf, const uint8_t* end) const {
+  TPM2B_PUBLIC key_public;
+  TPM2B_PRIVATE key_private;
+  auto parent = parent_key_fn_(resource_manager_);
+  if (!parent) {
+    LOG(ERROR) << "Unable to load encryption parent key";
+    return buf;
+  }
+  TpmObjectSlot key_slot;
+  if (!CreateKey(
+      resource_manager_, parent->get(), &key_public, &key_private, &key_slot)) {
+    LOG(ERROR) << "Unable to create key";
+    return buf;
+  }
+
+  auto wrapped_size = wrapped_.SerializedSize();
+  auto encrypted_size = RoundUpToBlockSize(wrapped_size);
+  std::vector<uint8_t> unencrypted(encrypted_size + 1, 0);
+  auto unencrypted_buf = unencrypted.data();
+  auto unencrypted_buf_end = unencrypted_buf + unencrypted.size();
+  auto next_buf = wrapped_.Serialize(unencrypted_buf, unencrypted_buf_end);
+  if (next_buf - unencrypted_buf != wrapped_size) {
+    LOG(ERROR) << "Size mismatch on wrapped data";
+    return buf;
+  }
+  std::vector<uint8_t> encrypted(encrypted_size, 0);
+  if (!TpmEncrypt(
+      resource_manager_.Esys(),
+      key_slot->get(),
+      TpmAuth(ESYS_TR_PASSWORD),
+      unencrypted.data(),
+      encrypted.data(),
+      encrypted_size)) {
+    LOG(ERROR) << "Encryption failed";
+    return buf;
+  }
+  SerializeTpmKeyPublic serialize_public(&key_public);
+  SerializeTpmKeyPrivate serialize_private(&key_private);
+
+  buf = serialize_public.Serialize(buf, end);
+  buf = serialize_private.Serialize(buf, end);
+  buf = keymaster::append_uint32_to_buf(buf, end, BLOCK_SIZE);
+  buf = keymaster::append_uint32_to_buf(buf, end, wrapped_size);
+  buf = keymaster::append_to_buf(buf, end, encrypted.data(), encrypted_size);
+  return buf;
+}
+
+bool EncryptedSerializable::Deserialize(
+    const uint8_t** buf_ptr, const uint8_t* end) {
+  auto parent_key = parent_key_fn_(resource_manager_);
+  if (!parent_key) {
+    LOG(ERROR) << "Unable to load encryption parent key";
+    return false;
+  }
+  TPM2B_PUBLIC key_public;
+  SerializeTpmKeyPublic serialize_public(&key_public);
+  if (!serialize_public.Deserialize(buf_ptr, end)) {
+    LOG(ERROR) << "Unable to deserialize key public part";
+    return false;
+  }
+  TPM2B_PRIVATE key_private;
+  SerializeTpmKeyPrivate serialize_private(&key_private);
+  if (!serialize_private.Deserialize(buf_ptr, end)) {
+    LOG(ERROR) << "Unable to deserialize key private part";
+    return false;
+  }
+  auto key_slot =
+      LoadKey(resource_manager_, parent_key->get(), &key_public, &key_private);
+  if (!key_slot) {
+    LOG(ERROR) << "Failed to load key into TPM";
+    return false;
+  }
+  uint32_t block_size = 0;
+  if (!keymaster::copy_uint32_from_buf(buf_ptr, end, &block_size)) {
+    LOG(ERROR) << "Failed to read block size";
+    return false;
+  }
+  if (block_size != BLOCK_SIZE) {
+    LOG(ERROR) << "Unexpected block size: was " << block_size
+               << ", expected " << BLOCK_SIZE;
+    return false;
+  }
+  uint32_t wrapped_size = 0;
+  if (!keymaster::copy_uint32_from_buf(buf_ptr, end, &wrapped_size)) {
+    LOG(ERROR) << "Failed to read wrapped size";
+    return false;
+  }
+  uint32_t encrypted_size = RoundUpToBlockSize(wrapped_size);
+  std::vector<uint8_t> encrypted_data(encrypted_size, 0);
+  if (!keymaster::copy_from_buf(
+      buf_ptr, end, encrypted_data.data(), encrypted_size)) {
+    LOG(ERROR) << "Failed to read encrypted data";
+    return false;
+  }
+  std::vector<uint8_t> decrypted_data(encrypted_size, 0);
+  if (!TpmDecrypt(
+      resource_manager_.Esys(),
+      key_slot->get(),
+      TpmAuth(ESYS_TR_PASSWORD),
+      encrypted_data.data(),
+      decrypted_data.data(),
+      encrypted_size)) {
+    LOG(ERROR) << "Failed to decrypt encrypted data";
+    return false;
+  }
+  auto decrypted_buf = decrypted_data.data();
+  auto decrypted_buf_end = decrypted_data.data() + wrapped_size;
+  if (!wrapped_.Deserialize(
+      const_cast<const uint8_t **>(&decrypted_buf), decrypted_buf_end)) {
+    LOG(ERROR) << "Failed to deserialize wrapped type";
+    return false;
+  }
+  if (decrypted_buf != decrypted_buf_end) {
+    LOG(ERROR) << "Inner type did not use all data";
+    return false;
+  }
+  return true;
+}
diff --git a/host/commands/secure_env/encrypted_serializable.h b/host/commands/secure_env/encrypted_serializable.h
new file mode 100644
index 0000000..c4a2e08
--- /dev/null
+++ b/host/commands/secure_env/encrypted_serializable.h
@@ -0,0 +1,59 @@
+//
+// 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 <keymaster/serializable.h>
+
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/**
+ * A keymaster::Serializable that wraps another keymaster::Serializable,
+ * encrypting the data with a TPM to ensure privacy.
+ *
+ * This implementation randomly generates a unique key which only exists inside
+ * the TPM, and uses it to encrypt the data from the other Serializable
+ * instance. The encrypted data, together with information about the unique key
+ * is stored in the output data. The unique key information is something that
+ * can only be decoded using a TPM, which will detect if the key is corrupted.
+ * However, this implementation will not detect if the encrypted data is
+ * corrupted, which could break the other Serializable instance on
+ * deserialization. This class should be used with something else to verify
+ * that the data hasn't been tampered with.
+ *
+ * The serialization format is:
+ * [tpm key public data] [tpm key private data]
+ * [uint32_t: block_size]
+ * [uint32_t: encrypted_length] [encrypted_data]
+ *
+ * The actual length of [encrypted_data] in the serialized format is
+ * [encrypted_length] rounded up to the nearest multiple of [block_size].
+ * [encrypted_length] is the true length of the data before encryption, without
+ * padding.
+ */
+class EncryptedSerializable : public keymaster::Serializable {
+public:
+  EncryptedSerializable(TpmResourceManager&,
+                        std::function<TpmObjectSlot(TpmResourceManager&)>,
+                        Serializable&);
+
+  size_t SerializedSize() const override;
+  uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+  bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+private:
+  TpmResourceManager& resource_manager_;
+  std::function<TpmObjectSlot(TpmResourceManager&)> parent_key_fn_;
+  keymaster::Serializable& wrapped_;
+};
diff --git a/host/commands/secure_env/fragile_tpm_storage.cpp b/host/commands/secure_env/fragile_tpm_storage.cpp
new file mode 100644
index 0000000..ae66164
--- /dev/null
+++ b/host/commands/secure_env/fragile_tpm_storage.cpp
@@ -0,0 +1,240 @@
+//
+// 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.
+
+#include "host/commands/secure_env/fragile_tpm_storage.h"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <tss2/tss2_rc.h>
+
+#include "host/commands/secure_env/json_serializable.h"
+#include "host/commands/secure_env/tpm_random_source.h"
+
+static constexpr char kEntries[] = "entries";
+static constexpr char kKey[] = "key";
+static constexpr char kHandle[] = "handle";
+
+FragileTpmStorage::FragileTpmStorage(
+    TpmResourceManager& resource_manager, const std::string& index_file)
+    : resource_manager_(resource_manager), index_file_(index_file) {
+  index_ = ReadProtectedJsonFromFile(resource_manager_, index_file);
+  if (!index_.isMember(kEntries)
+      || index_[kEntries].type() != Json::arrayValue) {
+    if (index_.empty()) {
+      LOG(DEBUG) << "Initializing secure index file";
+    } else {
+      LOG(WARNING) << "Index file missing entries, likely corrupted.";
+    }
+    index_[kEntries] = Json::Value(Json::arrayValue);
+  } else {
+    LOG(DEBUG) << "Restoring index from file";
+  }
+}
+
+TPM2_HANDLE FragileTpmStorage::GenerateRandomHandle() {
+  TpmRandomSource random_source{resource_manager_.Esys()};
+  TPM2_HANDLE handle = 0;
+  random_source.GenerateRandom(
+      reinterpret_cast<uint8_t*>(&handle), sizeof(handle));
+  if (handle == 0) {
+    LOG(WARNING) << "TPM randomness failed. Falling back to software RNG.";
+    handle = rand();
+  }
+  handle = handle % (TPM2_NV_INDEX_LAST + 1 - TPM2_NV_INDEX_FIRST);
+  handle += TPM2_NV_INDEX_FIRST;
+  return handle;
+}
+
+static constexpr size_t MAX_HANDLE_ATTEMPTS = 1;
+
+bool FragileTpmStorage::Allocate(const Json::Value& key, uint16_t size) {
+  if (HasKey(key)) {
+    LOG(WARNING) << "Key " << key << " is already defined.";
+    return false;
+  }
+  TPM2_HANDLE handle;
+  for (int i = 0; i < MAX_HANDLE_ATTEMPTS; i++) {
+    handle = GenerateRandomHandle();
+    TPM2B_NV_PUBLIC public_info = {
+      .size = 0,
+      .nvPublic = {
+        .nvIndex = handle,
+        .nameAlg = TPM2_ALG_SHA1,
+        .attributes = TPMA_NV_AUTHWRITE | TPMA_NV_AUTHREAD,
+        .authPolicy = { .size = 0, .buffer = {} },
+        .dataSize = size,
+      }
+    };
+    TPM2B_AUTH auth = { .size = 0, .buffer = {} };
+    Esys_TR_SetAuth(resource_manager_.Esys(), ESYS_TR_RH_OWNER, &auth);
+    ESYS_TR nv_handle;
+    auto rc = Esys_NV_DefineSpace(
+      /* esysContext */ resource_manager_.Esys(),
+      /* authHandle */ ESYS_TR_RH_OWNER,
+      /* shandle1 */ ESYS_TR_PASSWORD,
+      /* shandle2 */ ESYS_TR_NONE,
+      /* shandle3 */ ESYS_TR_NONE,
+      /* auth */ &auth,
+      /* publicInfo */ &public_info,
+      /* nvHandle */ &nv_handle);
+    if (rc == TPM2_RC_NV_DEFINED) {
+      LOG(VERBOSE) << "Esys_NV_DefineSpace failed with TPM2_RC_NV_DEFINED";
+      continue;
+    } else if (rc == TPM2_RC_SUCCESS) {
+      Esys_TR_Close(resource_manager_.Esys(), &nv_handle);
+      break;
+    } else {
+      LOG(DEBUG) << "Esys_NV_DefineSpace failed with " << rc << ": "
+                 << Tss2_RC_Decode(rc);
+    }
+  }
+  Json::Value entry(Json::objectValue);
+  entry[kKey] = key;
+  entry[kHandle] = handle;
+  index_[kEntries].append(entry);
+
+  if (!WriteProtectedJsonToFile(resource_manager_, index_file_, index_)) {
+    LOG(ERROR) << "Failed to save changes to " << index_file_;
+    return false;
+  }
+  return true;
+}
+
+TPM2_HANDLE FragileTpmStorage::GetHandle(const Json::Value& key) const {
+  for (const auto& entry : index_[kEntries]) {
+    if (!entry.isMember(kKey)) {
+      LOG(ERROR) << "Index was corrupted";
+      return 0;
+    }
+    if (entry[kKey] != key) {
+      continue;
+    }
+    if (!entry.isMember(kHandle)) {
+      LOG(ERROR) << "Index was corrupted";
+      return 0;
+    }
+    return entry[kHandle].asUInt();
+  }
+  return 0;
+}
+
+bool FragileTpmStorage::HasKey(const Json::Value& key) const {
+  return GetHandle(key) != 0;
+}
+
+std::unique_ptr<TPM2B_MAX_NV_BUFFER> FragileTpmStorage::Read(
+    const Json::Value& key) const {
+  auto handle = GetHandle(key);
+  if (handle == 0) {
+    LOG(WARNING) << "Could not read from " << key;
+    return {};
+  }
+  auto close_tr = [this](ESYS_TR* handle) {
+    Esys_TR_Close(resource_manager_.Esys(), handle);
+    delete handle;
+  };
+  std::unique_ptr<ESYS_TR, decltype(close_tr)> nv_handle(new ESYS_TR, close_tr);
+  auto rc = Esys_TR_FromTPMPublic(
+      /* esysContext */ resource_manager_.Esys(),
+      /* tpm_handle */ handle,
+      /* optionalSession1 */ ESYS_TR_NONE,
+      /* optionalSession2 */ ESYS_TR_NONE,
+      /* optionalSession3 */ ESYS_TR_NONE,
+      /* object */ nv_handle.get());
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_TR_FromTPMPublic failed: " << rc << ": "
+               << Tss2_RC_Decode(rc);
+    return {};
+  }
+  TPM2B_AUTH auth = { .size = 0, .buffer = {} };
+  Esys_TR_SetAuth(resource_manager_.Esys(), *nv_handle, &auth);
+
+  TPM2B_NV_PUBLIC* public_area;
+  rc = Esys_NV_ReadPublic(
+      /* esysContext */ resource_manager_.Esys(),
+      /* nvIndex */ *nv_handle,
+      /* shandle1 */ ESYS_TR_NONE,
+      /* shandle2 */ ESYS_TR_NONE,
+      /* shandle3 */ ESYS_TR_NONE,
+      /* nvPublic */ &public_area,
+      /* nvName */ nullptr);
+  if (rc != TPM2_RC_SUCCESS || public_area == nullptr) {
+    LOG(ERROR) << "Esys_NV_ReadPublic failed: " << rc << ": "
+               << Tss2_RC_Decode(rc);
+    return {};
+  }
+  std::unique_ptr<TPM2B_NV_PUBLIC, decltype(Esys_Free)*>
+      public_deleter(public_area, Esys_Free);
+  TPM2B_MAX_NV_BUFFER* buffer = nullptr;
+  rc = Esys_NV_Read(
+      /* esysContext */ resource_manager_.Esys(),
+      /* authHandle */ *nv_handle,
+      /* nvIndex */ *nv_handle,
+      /* shandle1 */ ESYS_TR_PASSWORD,
+      /* shandle2 */ ESYS_TR_NONE,
+      /* shandle3 */ ESYS_TR_NONE,
+      /* size */ public_area->nvPublic.dataSize,
+      /* offset */ 0,
+      /* data */ &buffer);
+  if (rc != TSS2_RC_SUCCESS || buffer == nullptr) {
+    LOG(ERROR) << "Esys_NV_Read failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return {};
+  }
+  auto ret = std::make_unique<TPM2B_MAX_NV_BUFFER>(*buffer);
+  return ret;
+}
+
+bool FragileTpmStorage::Write(
+    const Json::Value& key, const TPM2B_MAX_NV_BUFFER& data) {
+  auto handle = GetHandle(key);
+  if (handle == 0) {
+    LOG(WARNING) << "Could not read from " << key;
+    return false;
+  }
+  ESYS_TR nv_handle;
+  auto rc = Esys_TR_FromTPMPublic(
+      /* esysContext */ resource_manager_.Esys(),
+      /* tpm_handle */ handle,
+      /* optionalSession1 */ ESYS_TR_NONE,
+      /* optionalSession2 */ ESYS_TR_NONE,
+      /* optionalSession3 */ ESYS_TR_NONE,
+      /* object */ &nv_handle);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_TR_FromTPMPublic failed: " << rc << ": "
+               << Tss2_RC_Decode(rc);
+    return false;
+  }
+  TPM2B_AUTH auth = { .size = 0, .buffer = {} };
+  Esys_TR_SetAuth(resource_manager_.Esys(), nv_handle, &auth);
+
+  rc = Esys_NV_Write(
+      /* esysContext */ resource_manager_.Esys(),
+      /* authHandle */ nv_handle,
+      /* nvIndex */ nv_handle,
+      /* shandle1 */ ESYS_TR_PASSWORD,
+      /* shandle2 */ ESYS_TR_NONE,
+      /* shandle3 */ ESYS_TR_NONE,
+      /* data */ &data,
+      /* offset */ 0);
+  Esys_TR_Close(resource_manager_.Esys(), &nv_handle);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_NV_Write failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return false;
+  }
+  return true;
+}
diff --git a/host/commands/secure_env/fragile_tpm_storage.h b/host/commands/secure_env/fragile_tpm_storage.h
new file mode 100644
index 0000000..b52b373
--- /dev/null
+++ b/host/commands/secure_env/fragile_tpm_storage.h
@@ -0,0 +1,60 @@
+//
+// 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 <memory>
+#include <string>
+#include <vector>
+
+#include <tss2/tss2_esys.h>
+#include <tss2/tss2_tpm2_types.h>
+#include <json/json.h>
+
+#include "host/commands/secure_env/gatekeeper_storage.h"
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/**
+ * Manager for data stored inside the TPM with an index outside of the TPM. The
+ * contents of the data cannot be corrupted or decrypted by accessing the index,
+ * but the index can be corrupted by an attacker.
+ *
+ * As the actual data is stored inside the TPM, a replay attack can be used to
+ * restore deleted index entries or hide revert to before an index entry was
+ * added, but not change the contents that an index points to if it still
+ * exists.
+ *
+ * This class is not thread-safe, and should be synchronized externally if it
+ * is going to be used from multiple threads.
+ */
+class FragileTpmStorage : public GatekeeperStorage {
+public:
+  FragileTpmStorage(TpmResourceManager&, const std::string& index_file);
+  ~FragileTpmStorage() = default;
+
+  bool Allocate(const Json::Value& key, uint16_t size) override;
+  bool HasKey(const Json::Value& key) const override;
+
+  std::unique_ptr<TPM2B_MAX_NV_BUFFER> Read(const Json::Value& key) const
+      override;
+  bool Write(const Json::Value& key, const TPM2B_MAX_NV_BUFFER& data) override;
+private:
+  TPM2_HANDLE GetHandle(const Json::Value& key) const;
+  TPM2_HANDLE GenerateRandomHandle();
+
+  TpmResourceManager& resource_manager_;
+  std::string index_file_;
+  Json::Value index_;
+};
diff --git a/host/commands/secure_env/gatekeeper_responder.cpp b/host/commands/secure_env/gatekeeper_responder.cpp
new file mode 100644
index 0000000..7d43a18
--- /dev/null
+++ b/host/commands/secure_env/gatekeeper_responder.cpp
@@ -0,0 +1,62 @@
+//
+// 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.
+
+#include "gatekeeper_responder.h"
+
+#include <android-base/logging.h>
+#include <gatekeeper/gatekeeper_messages.h>
+
+GatekeeperResponder::GatekeeperResponder(
+    cuttlefish::GatekeeperChannel& channel, gatekeeper::GateKeeper& gatekeeper)
+    : channel_(channel), gatekeeper_(gatekeeper) {
+}
+
+bool GatekeeperResponder::ProcessMessage() {
+  auto request = channel_.ReceiveMessage();
+  if (!request) {
+    LOG(ERROR) << "Could not receive message";
+    return false;
+  }
+  const uint8_t* buffer = request->payload;
+  const uint8_t* buffer_end = request->payload + request->payload_size;
+  switch(request->cmd) {
+    using namespace gatekeeper;
+    case ENROLL: {
+      EnrollRequest enroll_request;
+      auto rc = enroll_request.Deserialize(buffer, buffer_end);
+      if (rc != ERROR_NONE) {
+        LOG(ERROR) << "Failed to deserialize Enroll Request";
+        return false;
+      }
+      EnrollResponse response;
+      gatekeeper_.Enroll(enroll_request, &response);
+      return channel_.SendResponse(ENROLL, response);
+    }
+    case VERIFY: {
+      VerifyRequest verify_request;
+      auto rc = verify_request.Deserialize(buffer, buffer_end);
+      if (rc != ERROR_NONE) {
+        LOG(ERROR) << "Failed to deserialize Verify Request";
+        return false;
+      }
+      VerifyResponse response;
+      gatekeeper_.Verify(verify_request, &response);
+      return channel_.SendResponse(VERIFY, response);
+    }
+    default:
+      LOG(ERROR) << "Unrecognized message id " << request->cmd;
+      return false;
+  }
+}
diff --git a/host/commands/secure_env/gatekeeper_responder.h b/host/commands/secure_env/gatekeeper_responder.h
new file mode 100644
index 0000000..bd27955
--- /dev/null
+++ b/host/commands/secure_env/gatekeeper_responder.h
@@ -0,0 +1,31 @@
+//
+// 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 <gatekeeper/gatekeeper.h>
+
+#include "common/libs/security/gatekeeper_channel.h"
+
+class GatekeeperResponder {
+private:
+  cuttlefish::GatekeeperChannel& channel_;
+  gatekeeper::GateKeeper& gatekeeper_;
+public:
+  GatekeeperResponder(cuttlefish::GatekeeperChannel& channel,
+                      gatekeeper::GateKeeper& gatekeeper);
+
+  bool ProcessMessage();
+};
diff --git a/host/commands/secure_env/gatekeeper_storage.h b/host/commands/secure_env/gatekeeper_storage.h
new file mode 100644
index 0000000..d272f71
--- /dev/null
+++ b/host/commands/secure_env/gatekeeper_storage.h
@@ -0,0 +1,42 @@
+//
+// 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>
+
+#include <json/json.h>
+#include <tss2/tss2_tpm2_types.h>
+
+/**
+ * Data storage tailored to Gatekeeper's storage needs: storing binary blobs
+ * that can be destroyed without a trace or corrupted with an obvious trace, but
+ * not silently tampered with or read by an unauthorized user.
+ *
+ * Data can be stored through Write and retrieved through Read. To delete data,
+ * issue a Write that overwrites the data to destroy it.
+ */
+class GatekeeperStorage {
+public:
+  virtual ~GatekeeperStorage() = default;
+
+  virtual bool Allocate(const Json::Value& key, uint16_t size) = 0;
+  virtual bool HasKey(const Json::Value& key) const = 0;
+
+  virtual std::unique_ptr<TPM2B_MAX_NV_BUFFER> Read(const Json::Value& key)
+      const = 0;
+  virtual bool Write(const Json::Value& key, const TPM2B_MAX_NV_BUFFER& data)
+      = 0;
+};
diff --git a/host/commands/secure_env/hmac_serializable.cpp b/host/commands/secure_env/hmac_serializable.cpp
new file mode 100644
index 0000000..c40b736
--- /dev/null
+++ b/host/commands/secure_env/hmac_serializable.cpp
@@ -0,0 +1,127 @@
+//
+// 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.
+
+#include "hmac_serializable.h"
+
+#include <android-base/logging.h>
+
+#include "host/commands/secure_env/tpm_auth.h"
+#include "host/commands/secure_env/tpm_hmac.h"
+
+HmacSerializable::HmacSerializable(
+    TpmResourceManager& resource_manager,
+    std::function<TpmObjectSlot(TpmResourceManager&)> signing_key_fn,
+    uint32_t digest_size,
+    Serializable* wrapped) :
+    resource_manager_(resource_manager),
+    signing_key_fn_(signing_key_fn),
+    digest_size_(digest_size),
+    wrapped_(wrapped) {
+}
+
+size_t HmacSerializable::SerializedSize() const {
+  auto digest_size = sizeof(uint32_t) + digest_size_;
+  auto data_size = sizeof(uint32_t) + wrapped_->SerializedSize();
+  return digest_size + data_size;
+}
+
+uint8_t* HmacSerializable::Serialize(uint8_t* buf, const uint8_t* end) const {
+  auto wrapped_size = wrapped_->SerializedSize();
+  buf = keymaster::append_uint32_to_buf(buf, end, wrapped_size);
+  auto signed_data = buf;
+  buf = wrapped_->Serialize(buf, end);
+  if (buf - signed_data != wrapped_size) {
+    LOG(ERROR) << "Serialized wrapped data did not match expected size.";
+    return buf;
+  }
+  auto key = signing_key_fn_(resource_manager_);
+  if (!key) {
+    LOG(ERROR) << "Could not retrieve key";
+    return buf;
+  }
+  auto hmac_data =
+    TpmHmac(
+        resource_manager_,
+        key->get(),
+        TpmAuth(ESYS_TR_PASSWORD),
+        signed_data,
+        wrapped_size);
+  if (!hmac_data) {
+    LOG(ERROR) << "Failed to produce hmac";
+    return buf;
+  }
+  if (hmac_data->size != digest_size_) {
+    LOG(ERROR) << "Unexpected digest size. Wanted " << digest_size_
+               << ", TPM produced " << hmac_data->size;
+    return buf;
+  }
+  return keymaster::append_size_and_data_to_buf(
+      buf, end, hmac_data->buffer, digest_size_);
+}
+
+bool HmacSerializable::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+  size_t signed_data_size;
+  keymaster::UniquePtr<uint8_t[]> signed_data;
+  bool success =
+      keymaster::copy_size_and_data_from_buf(
+          buf_ptr, end, &signed_data_size, &signed_data);
+  if (!success) {
+    LOG(ERROR) << "Failed to retrieve signed data";
+    return false;
+  }
+  size_t signature_size;
+  keymaster::UniquePtr<uint8_t[]> signature;
+  success =
+      keymaster::copy_size_and_data_from_buf(
+          buf_ptr, end, &signature_size, &signature);
+  if (!success) {
+    LOG(ERROR) << "Failed to retrieve signature";
+    return false;
+  }
+  if (signature_size != digest_size_) {
+    LOG(ERROR) << "Digest size did not match expected size.";
+    return false;
+  }
+  auto key = signing_key_fn_(resource_manager_);
+  if (!key) {
+    LOG(ERROR) << "Could not retrieve key";
+    return false;
+  }
+  auto hmac_check =
+    TpmHmac(
+        resource_manager_,
+        key->get(),
+        TpmAuth(ESYS_TR_PASSWORD),
+        signed_data.get(),
+        signed_data_size);
+  if (!hmac_check) {
+    LOG(ERROR) << "Unable to calculate signature check";
+    return false;
+  }
+  if (hmac_check->size != digest_size_) {
+    LOG(ERROR) << "Unexpected signature check size. Wanted " << digest_size_
+               << ", TPM produced " << hmac_check->size;
+    return false;
+  }
+  if (memcmp(signature.get(), hmac_check->buffer, digest_size_) != 0) {
+    LOG(ERROR) << "Signature check did not match original signature.";
+    return false;
+  }
+  // Now that we've validated integrity on the data, do the inner deserialization
+  auto inner_buf = signed_data.get();
+  auto inner_buf_end = inner_buf + signed_data_size;
+  return wrapped_->Deserialize(
+      const_cast<const uint8_t**>(&inner_buf), inner_buf_end);
+}
diff --git a/host/commands/secure_env/hmac_serializable.h b/host/commands/secure_env/hmac_serializable.h
new file mode 100644
index 0000000..4b90124
--- /dev/null
+++ b/host/commands/secure_env/hmac_serializable.h
@@ -0,0 +1,54 @@
+//
+// 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 <keymaster/serializable.h>
+
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/**
+ * A keymaster::Serializable that wraps another keymaster::Serializable,
+ * protecting it from tampering while it is stored elsewhere. This stores
+ * the serialized data of the other type together with a signature over that
+ * serialized data. When deserializing, it will attempt to make the same
+ * signature over the data. If the signature or data has been tampered with,
+ * the signatures won't match and it won't attempt to deserialize the wrapped
+ * type.
+ *
+ * The serialization format is:
+ * [uint32_t: wrapped_size] [wrapped_data]
+ * [uint32_t: signature_size] [signature_data]
+ *
+ * While this class currently assumes all signatures will use the same key
+ * and algorithm and therefore be the same size, the serialization format is
+ * future-proof to accommodate signature changes.
+ */
+class HmacSerializable : public keymaster::Serializable {
+public:
+  HmacSerializable(TpmResourceManager&,
+                   std::function<TpmObjectSlot(TpmResourceManager&)>,
+                   uint32_t digest_size,
+                   Serializable*);
+
+  size_t SerializedSize() const override;
+  uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+  bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+private:
+  TpmResourceManager& resource_manager_;
+  std::function<TpmObjectSlot(TpmResourceManager&)> signing_key_fn_;
+  uint32_t digest_size_;
+  keymaster::Serializable* wrapped_;
+};
diff --git a/host/commands/secure_env/in_process_tpm.cpp b/host/commands/secure_env/in_process_tpm.cpp
new file mode 100644
index 0000000..f240c08
--- /dev/null
+++ b/host/commands/secure_env/in_process_tpm.cpp
@@ -0,0 +1,156 @@
+//
+// 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.
+
+#include "in_process_tpm.h"
+
+#include <endian.h>
+#include <stddef.h>
+
+#include <tss2/tss2_esys.h>
+#include <tss2/tss2_rc.h>
+
+#include "host/commands/secure_env/tpm_commands.h"
+
+extern "C" {
+typedef int SOCKET;
+#include "TpmBuildSwitches.h"
+#include "TpmTcpProtocol.h"
+#include "Simulator_fp.h"
+#include "Manufacture_fp.h"
+#define delete delete_
+#include "Platform_fp.h"
+#undef delete
+#undef DEBUG
+}
+
+#include <android-base/logging.h>
+
+struct __attribute__((__packed__)) tpm_message_header {
+  uint16_t tag;
+  uint32_t length;
+  uint32_t ordinal;
+};
+
+struct InProcessTpm::Impl {
+  static Impl* FromContext(TSS2_TCTI_CONTEXT* context) {
+    auto offset = offsetof(Impl, tcti_context_);
+    char* context_char = reinterpret_cast<char*>(context);
+    return reinterpret_cast<Impl*>(context_char - offset);
+  }
+
+  static TSS2_RC Transmit(
+      TSS2_TCTI_CONTEXT *context, size_t size, uint8_t const *command) {
+    auto impl = FromContext(context);
+    std::lock_guard lock(impl->queue_mutex_);
+    impl->command_queue_.emplace_back(command, command + size);
+    return TSS2_RC_SUCCESS;
+  }
+
+  static TSS2_RC Receive(
+      TSS2_TCTI_CONTEXT *context,
+      size_t* size,
+      uint8_t* response,
+      int32_t /* timeout */) {
+    auto impl = FromContext(context);
+    // TODO(schuffelen): Use the timeout argument
+    std::vector<uint8_t> request;
+    {
+      std::lock_guard lock(impl->queue_mutex_);
+      if (impl->command_queue_.empty()) {
+        return TSS2_TCTI_RC_GENERAL_FAILURE;
+      }
+      request = std::move(impl->command_queue_.front());
+      impl->command_queue_.pop_front();
+    }
+    auto header = reinterpret_cast<tpm_message_header*>(request.data());
+    LOG(VERBOSE) << "Sending TPM command "
+                << TpmCommandName(be32toh(header->ordinal));
+    _IN_BUFFER input = {
+        .BufferSize = request.size(),
+        .Buffer = request.data(),
+    };
+    _OUT_BUFFER output = {
+        .BufferSize = (uint32_t) *size,
+        .Buffer = response,
+    };
+    _rpc__Send_Command(3, input, &output);
+    *size = output.BufferSize;
+    header = reinterpret_cast<tpm_message_header*>(response);
+    auto rc = be32toh(header->ordinal);
+    LOG(VERBOSE) << "Received TPM response " << Tss2_RC_Decode(rc)
+                << " (" << rc << ")";
+    return TSS2_RC_SUCCESS;
+  }
+
+  TSS2_TCTI_CONTEXT_COMMON_CURRENT tcti_context_;
+  std::list<std::vector<uint8_t>> command_queue_;
+  std::mutex queue_mutex_;
+};
+
+InProcessTpm::InProcessTpm() : impl_(new Impl()) {
+  impl_->tcti_context_.v1.magic = 0xFAD;
+  impl_->tcti_context_.v1.version = 1;
+  impl_->tcti_context_.v1.transmit = Impl::Transmit;
+  impl_->tcti_context_.v1.receive = Impl::Receive;
+  _plat__NVEnable(NULL);
+  if (_plat__NVNeedsManufacture()) {
+    // Can't use android logging here due to a macro conflict with TPM internals
+    LOG(DEBUG) << "Manufacturing TPM state";
+    if (TPM_Manufacture(1)) {
+      LOG(FATAL) << "Failed to manufacture TPM state";
+    }
+  }
+  _rpc__Signal_PowerOn(false);
+  _rpc__Signal_NvOn();
+
+  ESYS_CONTEXT* esys = nullptr;
+  auto rc = Esys_Initialize(&esys, TctiContext(), nullptr);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(FATAL) << "Could not initialize esys: " << Tss2_RC_Decode(rc)
+               << " (" << rc << ")";
+  }
+
+  rc = Esys_Startup(esys, TPM2_SU_CLEAR);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(FATAL) << "TPM2_Startup failed: " << Tss2_RC_Decode(rc)
+               << " (" << rc << ")";
+  }
+
+  TPM2B_AUTH auth = {};
+  Esys_TR_SetAuth(esys, ESYS_TR_RH_LOCKOUT, &auth);
+
+  rc = Esys_DictionaryAttackLockReset(
+    /* esysContext */ esys,
+    /* lockHandle */ ESYS_TR_RH_LOCKOUT,
+    /* shandle1 */ ESYS_TR_PASSWORD,
+    /* shandle2 */ ESYS_TR_NONE,
+    /* shandle3 */ ESYS_TR_NONE);
+
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(FATAL) << "Could not reset TPM lockout: " << Tss2_RC_Decode(rc)
+               << " (" << rc << ")";
+  }
+
+  Esys_Finalize(&esys);
+}
+
+InProcessTpm::~InProcessTpm() {
+  _rpc__Signal_NvOff();
+  _rpc__Signal_PowerOff();
+}
+
+TSS2_TCTI_CONTEXT* InProcessTpm::TctiContext() {
+  return reinterpret_cast<TSS2_TCTI_CONTEXT*>(&impl_->tcti_context_);
+}
diff --git a/host/commands/secure_env/in_process_tpm.h b/host/commands/secure_env/in_process_tpm.h
new file mode 100644
index 0000000..35fecfb
--- /dev/null
+++ b/host/commands/secure_env/in_process_tpm.h
@@ -0,0 +1,47 @@
+//
+// 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 <list>
+#include <mutex>
+#include <vector>
+
+#include <tss2/tss2_tcti.h>
+
+#include "host/commands/secure_env/tpm.h"
+
+/*
+ * Exposes a TSS2_TCTI_CONTEXT for interacting with an in-process TPM simulator.
+ *
+ * TSS2_TCTI_CONTEXT is the abstraction for "communication channel to a TPM".
+ * It is not safe to create more than one of these per process or per working
+ * directory, as the TPM simulator implementation relies heavily on global
+ * variables and files saved in the working directory.
+ *
+ * TODO(schuffelen): Consider moving this to a separate process with its own
+ * working directory.
+ */
+class InProcessTpm : public Tpm {
+public:
+  InProcessTpm();
+  ~InProcessTpm();
+
+  TSS2_TCTI_CONTEXT* TctiContext() override;
+private:
+  struct Impl;
+
+  std::unique_ptr<Impl> impl_;
+};
diff --git a/host/commands/secure_env/insecure_fallback_storage.cpp b/host/commands/secure_env/insecure_fallback_storage.cpp
new file mode 100644
index 0000000..f906bd5
--- /dev/null
+++ b/host/commands/secure_env/insecure_fallback_storage.cpp
@@ -0,0 +1,149 @@
+//
+// 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.
+
+#include "host/commands/secure_env/insecure_fallback_storage.h"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <tss2/tss2_rc.h>
+
+#include "host/commands/secure_env/json_serializable.h"
+#include "host/commands/secure_env/tpm_random_source.h"
+
+static constexpr char kEntries[] = "entries";
+static constexpr char kKey[] = "key";
+static constexpr char kValue[] = "value";
+
+InsecureFallbackStorage::InsecureFallbackStorage(
+    TpmResourceManager& resource_manager, const std::string& index_file)
+    : resource_manager_(resource_manager), index_file_(index_file) {
+  index_ = ReadProtectedJsonFromFile(resource_manager_, index_file);
+  if (!index_.isMember(kEntries)
+      || index_[kEntries].type() != Json::arrayValue) {
+    if (index_.empty()) {
+      LOG(DEBUG) << "Initializing secure index file";
+    } else {
+      LOG(WARNING) << "Index file missing entries, likely corrupted.";
+    }
+    index_[kEntries] = Json::Value(Json::arrayValue);
+  } else {
+    LOG(DEBUG) << "Restoring index from file";
+  }
+}
+
+bool InsecureFallbackStorage::Allocate(const Json::Value& key, uint16_t size) {
+  if (HasKey(key)) {
+    LOG(WARNING) << "Key " << key << " is already defined.";
+    return false;
+  }
+  if (size > sizeof(((TPM2B_MAX_NV_BUFFER*)nullptr)->buffer)) {
+    LOG(ERROR) << "Size " << size << " was too large.";
+    return false;
+  }
+  Json::Value entry(Json::objectValue);
+  entry[kKey] = key;
+  Json::Value value(Json::arrayValue);
+  for (int i = 0; i < size; i++) {
+    value.append(0);
+  }
+  entry[kValue] = value;
+  index_[kEntries].append(entry);
+
+  if (!WriteProtectedJsonToFile(resource_manager_, index_file_, index_)) {
+    LOG(ERROR) << "Failed to save changes to " << index_file_;
+    return false;
+  }
+  return true;
+}
+
+const Json::Value* InsecureFallbackStorage::GetEntry(
+    const Json::Value& key) const {
+  for (auto& entry : index_[kEntries]) {
+    if (!entry.isMember(kKey)) {
+      LOG(WARNING) << "Index was corrupted";
+      return nullptr;
+    }
+    if (entry[kKey] != key) {
+      continue;
+    }
+    if (!entry.isMember(kValue) || entry[kValue].type() != Json::arrayValue) {
+      LOG(WARNING) << "Index was corrupted";
+      return nullptr;
+    }
+    return &entry;
+  }
+  return nullptr;
+}
+
+Json::Value* InsecureFallbackStorage::GetEntry(const Json::Value& key) {
+  return const_cast<Json::Value*>(
+      static_cast<const InsecureFallbackStorage&>(*this).GetEntry(key));
+}
+
+bool InsecureFallbackStorage::HasKey(const Json::Value& key) const {
+  return static_cast<bool>(GetEntry(key));
+}
+
+std::unique_ptr<TPM2B_MAX_NV_BUFFER> InsecureFallbackStorage::Read(
+    const Json::Value& key) const {
+  auto entry = GetEntry(key);
+  if (!entry) {
+    LOG(WARNING) << "Could not read from " << key;
+    return {};
+  }
+  const auto& value = (*entry)[kValue];
+  if (value.type() != Json::arrayValue) {
+    LOG(WARNING) << "Index was corrupted";
+    return {};
+  }
+  auto ret = std::make_unique<TPM2B_MAX_NV_BUFFER>();
+  if (value.size() > sizeof(ret->buffer)) {
+    LOG(ERROR) << "Index was corrupted: size of data was too large";
+    return {};
+  }
+  ret->size = value.size();
+  for (unsigned int i = 0; i < value.size(); i++) {
+    ret->buffer[i] = value[i].asUInt();
+  }
+  return ret;
+}
+
+bool InsecureFallbackStorage::Write(
+    const Json::Value& key, const TPM2B_MAX_NV_BUFFER& data) {
+  auto entry = GetEntry(key);
+  if (!entry) {
+    LOG(WARNING) << "Could not read from " << key;
+    return false;
+  }
+  auto& value = (*entry)[kValue];
+  if (value.type() != Json::arrayValue) {
+    LOG(WARNING) << "Index was corrupted";
+    return false;
+  }
+  if (data.size != value.size()) {
+    LOG(ERROR) << "Size of data given was incorrect";
+    return false;
+  };
+  for (unsigned int i = 0; i < value.size(); i++) {
+    value[i] = data.buffer[i];
+  }
+
+  if (!WriteProtectedJsonToFile(resource_manager_, index_file_, index_)) {
+    LOG(ERROR) << "Failed to save changes to " << index_file_;
+    return false;
+  }
+  return true;
+}
diff --git a/host/commands/secure_env/insecure_fallback_storage.h b/host/commands/secure_env/insecure_fallback_storage.h
new file mode 100644
index 0000000..93788a0
--- /dev/null
+++ b/host/commands/secure_env/insecure_fallback_storage.h
@@ -0,0 +1,56 @@
+//
+// 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>
+
+#include <json/json.h>
+#include <tss2/tss2_tpm2_types.h>
+
+#include "host/commands/secure_env/gatekeeper_storage.h"
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/**
+ * A GatekeeperStorage fallback implementation that is less secure. It uses an
+ * index file that is signed and encrypted by the TPM and the sensitive data
+ * is contained inside the index file. This file can be deleted or corrupted
+ * to lose access to the data inside, and is also susceptible to replay attacks.
+ * If the index file is replaced with an older version and the secure
+ * environment is restarted, it will still accept the old file with the old
+ * data.
+ *
+ * This class is not thread-safe, and should be synchronized externally if it
+ * is going to be used from multiple threads.
+ */
+class InsecureFallbackStorage : public GatekeeperStorage {
+public:
+  InsecureFallbackStorage(TpmResourceManager&, const std::string& index_file);
+  ~InsecureFallbackStorage() = default;
+
+  bool Allocate(const Json::Value& key, uint16_t size) override;
+  bool HasKey(const Json::Value& key) const override;
+
+  std::unique_ptr<TPM2B_MAX_NV_BUFFER> Read(const Json::Value& key) const
+      override;
+  bool Write(const Json::Value& key, const TPM2B_MAX_NV_BUFFER& data) override;
+private:
+  Json::Value* GetEntry(const Json::Value& key);
+  const Json::Value* GetEntry(const Json::Value& key) const;
+
+  TpmResourceManager& resource_manager_;
+  std::string index_file_;
+  Json::Value index_;
+};
diff --git a/host/commands/secure_env/json_serializable.cpp b/host/commands/secure_env/json_serializable.cpp
new file mode 100644
index 0000000..d4f2fd8
--- /dev/null
+++ b/host/commands/secure_env/json_serializable.cpp
@@ -0,0 +1,153 @@
+//
+// 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.
+
+#include "host/commands/secure_env/json_serializable.h"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <keymaster/serializable.h>
+
+#include "host/commands/secure_env/encrypted_serializable.h"
+#include "host/commands/secure_env/hmac_serializable.h"
+#include "host/commands/secure_env/primary_key_builder.h"
+
+static constexpr char kUniqueKey[] = "JsonSerializable";
+
+class JsonSerializable : public keymaster::Serializable {
+public:
+  JsonSerializable(Json::Value& json);
+
+  size_t SerializedSize() const override;
+
+  uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+
+  bool Deserialize(const uint8_t** buf_ptr, const uint8_t* buf_end) override;
+private:
+  Json::Value& json_;
+};
+
+JsonSerializable::JsonSerializable(Json::Value& json) : json_(json) {}
+
+size_t JsonSerializable::SerializedSize() const {
+  Json::StreamWriterBuilder factory;
+  auto serialized = Json::writeString(factory, json_);
+  return serialized.size() + sizeof(uint32_t);
+}
+
+uint8_t* JsonSerializable::Serialize(uint8_t* buf, const uint8_t* end) const {
+  Json::StreamWriterBuilder factory;
+  auto serialized = Json::writeString(factory, json_);
+  if (end - buf < serialized.size() + sizeof(uint32_t)) {
+    LOG(ERROR) << "Not enough space to serialize json";
+    return buf;
+  }
+  return keymaster::append_size_and_data_to_buf(
+      buf, end, serialized.data(), serialized.size());
+}
+
+bool JsonSerializable::Deserialize(
+    const uint8_t** buf_ptr, const uint8_t* buf_end) {
+  size_t size;
+  keymaster::UniquePtr<uint8_t[]> json_bytes;
+  bool success = keymaster::copy_size_and_data_from_buf(
+      buf_ptr, buf_end, &size, &json_bytes);
+  if (!success) {
+    LOG(ERROR) << "Failed to deserialize json bytes";
+    return false;
+  }
+  auto doc_begin = reinterpret_cast<const char*>(json_bytes.get());
+  auto doc_end = doc_begin + size;
+  Json::CharReaderBuilder builder;
+  std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
+  std::string errorMessage;
+  if (!reader->parse(doc_begin, doc_end, &json_, &errorMessage)) {
+    LOG(ERROR) << "Failed to parse json: " << errorMessage;
+    return false;
+  }
+  return true;
+}
+
+bool WriteProtectedJsonToFile(
+    TpmResourceManager& resource_manager,
+    const std::string& filename,
+    Json::Value json) {
+  JsonSerializable sensitive_material(json);
+  auto parent_key_fn = ParentKeyCreator(kUniqueKey);
+  EncryptedSerializable encryption(
+      resource_manager, parent_key_fn, sensitive_material);
+  auto signing_key_fn = SigningKeyCreator(kUniqueKey);
+  HmacSerializable sign_check(
+      resource_manager, signing_key_fn, TPM2_SHA256_DIGEST_SIZE, &encryption);
+
+  auto size = sign_check.SerializedSize();
+  LOG(INFO) << "size : " << size;
+  std::vector<uint8_t> data(size + 1);
+  uint8_t* buf = data.data();
+  uint8_t* buf_end = buf + data.size();
+  buf = sign_check.Serialize(buf, buf_end);
+  if (buf != (buf_end - 1)) {
+    LOG(ERROR) << "Serialized size did not match up with actual usage.";
+    return false;
+  }
+
+  std::ofstream file_stream(filename, std::ios::trunc | std::ios::binary);
+  file_stream.write(reinterpret_cast<char*>(data.data()), data.size() - 1);
+  if (!file_stream) {
+    LOG(ERROR) << "Failed to save data to " << filename;
+    return false;
+  }
+  return true;
+}
+
+Json::Value ReadProtectedJsonFromFile(
+    TpmResourceManager& resource_manager, const std::string& filename) {
+  std::ifstream file_stream(filename, std::ios::binary | std::ios::ate);
+  std::streamsize size = file_stream.tellg();
+  file_stream.seekg(0, std::ios::beg);
+
+  if (size <= 0) {
+    LOG(VERBOSE) << "File " << filename << " was empty.";
+    return {};
+  }
+
+  std::vector<char> buffer(size);
+  if (!file_stream.read(buffer.data(), size)) {
+    LOG(ERROR) << "Unable to read from " << filename;
+    return {};
+  }
+  if (!file_stream) {
+    LOG(ERROR) << "Unable to read from " << filename;
+    return {};
+  }
+
+  Json::Value json;
+  JsonSerializable sensitive_material(json);
+  auto parent_key_fn = ParentKeyCreator(kUniqueKey);
+  EncryptedSerializable encryption(
+      resource_manager, parent_key_fn, sensitive_material);
+  auto signing_key_fn = SigningKeyCreator(kUniqueKey);
+  HmacSerializable sign_check(
+      resource_manager, signing_key_fn, TPM2_SHA256_DIGEST_SIZE, &encryption);
+
+  auto buf = reinterpret_cast<const uint8_t*>(buffer.data());
+  auto buf_end = buf + buffer.size();
+  if (!sign_check.Deserialize(&buf, buf_end)) {
+    LOG(ERROR) << "Failed to deserialize json data from " << filename;
+    return {};
+  }
+
+  return json;
+}
diff --git a/host/commands/secure_env/json_serializable.h b/host/commands/secure_env/json_serializable.h
new file mode 100644
index 0000000..f96aab3
--- /dev/null
+++ b/host/commands/secure_env/json_serializable.h
@@ -0,0 +1,25 @@
+//
+// 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 <json/json.h>
+
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+bool WriteProtectedJsonToFile(
+    TpmResourceManager&, const std::string& filename, Json::Value);
+Json::Value ReadProtectedJsonFromFile(
+    TpmResourceManager&, const std::string& filename);
diff --git a/host/commands/secure_env/keymaster_responder.cpp b/host/commands/secure_env/keymaster_responder.cpp
new file mode 100644
index 0000000..a564254
--- /dev/null
+++ b/host/commands/secure_env/keymaster_responder.cpp
@@ -0,0 +1,109 @@
+//
+// 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.
+
+#include "keymaster_responder.h"
+
+#include <android-base/logging.h>
+#include <keymaster/android_keymaster_messages.h>
+
+KeymasterResponder::KeymasterResponder(
+    cuttlefish::KeymasterChannel& channel, keymaster::AndroidKeymaster& keymaster)
+    : channel_(channel), keymaster_(keymaster) {
+}
+
+bool KeymasterResponder::ProcessMessage() {
+  auto request = channel_.ReceiveMessage();
+  if (!request) {
+    LOG(ERROR) << "Could not receive message";
+    return false;
+  }
+  const uint8_t* buffer = request->payload;
+  const uint8_t* end = request->payload + request->payload_size;
+  switch(request->cmd) {
+    using namespace keymaster;
+#define HANDLE_MESSAGE(ENUM_NAME, METHOD_NAME) \
+    case ENUM_NAME: {\
+      METHOD_NAME##Request request(keymaster_.message_version()); \
+      if (!request.Deserialize(&buffer, end)) { \
+        LOG(ERROR) << "Failed to deserialize " #METHOD_NAME "Request"; \
+        return false; \
+      } \
+      METHOD_NAME##Response response(keymaster_.message_version()); \
+      keymaster_.METHOD_NAME(request, &response); \
+      return channel_.SendResponse(ENUM_NAME, response); \
+    }
+    HANDLE_MESSAGE(GENERATE_KEY, GenerateKey)
+    HANDLE_MESSAGE(BEGIN_OPERATION, BeginOperation)
+    HANDLE_MESSAGE(UPDATE_OPERATION, UpdateOperation)
+    HANDLE_MESSAGE(FINISH_OPERATION, FinishOperation)
+    HANDLE_MESSAGE(ABORT_OPERATION, AbortOperation)
+    HANDLE_MESSAGE(IMPORT_KEY, ImportKey)
+    HANDLE_MESSAGE(EXPORT_KEY, ExportKey)
+    HANDLE_MESSAGE(GET_VERSION, GetVersion)
+    HANDLE_MESSAGE(GET_SUPPORTED_ALGORITHMS, SupportedAlgorithms)
+    HANDLE_MESSAGE(GET_SUPPORTED_BLOCK_MODES, SupportedBlockModes)
+    HANDLE_MESSAGE(GET_SUPPORTED_PADDING_MODES, SupportedPaddingModes)
+    HANDLE_MESSAGE(GET_SUPPORTED_DIGESTS, SupportedDigests)
+    HANDLE_MESSAGE(GET_SUPPORTED_IMPORT_FORMATS, SupportedImportFormats)
+    HANDLE_MESSAGE(GET_SUPPORTED_EXPORT_FORMATS, SupportedExportFormats)
+    HANDLE_MESSAGE(GET_KEY_CHARACTERISTICS, GetKeyCharacteristics)
+    HANDLE_MESSAGE(ATTEST_KEY, AttestKey)
+    HANDLE_MESSAGE(UPGRADE_KEY, UpgradeKey)
+    HANDLE_MESSAGE(CONFIGURE, Configure)
+    HANDLE_MESSAGE(DELETE_KEY, DeleteKey)
+    HANDLE_MESSAGE(DELETE_ALL_KEYS, DeleteAllKeys)
+    HANDLE_MESSAGE(IMPORT_WRAPPED_KEY, ImportWrappedKey)
+    HANDLE_MESSAGE(GENERATE_TIMESTAMP_TOKEN, GenerateTimestampToken)
+#undef HANDLE_MESSAGE
+#define HANDLE_MESSAGE_W_RETURN(ENUM_NAME, METHOD_NAME) \
+    case ENUM_NAME: {\
+    METHOD_NAME##Request request(keymaster_.message_version());     \
+      if (!request.Deserialize(&buffer, end)) { \
+        LOG(ERROR) << "Failed to deserialize " #METHOD_NAME "Request"; \
+        return false; \
+      } \
+      auto response = keymaster_.METHOD_NAME(request); \
+      return channel_.SendResponse(ENUM_NAME, response); \
+    }
+    HANDLE_MESSAGE_W_RETURN(COMPUTE_SHARED_HMAC, ComputeSharedHmac)
+    HANDLE_MESSAGE_W_RETURN(VERIFY_AUTHORIZATION, VerifyAuthorization)
+    HANDLE_MESSAGE_W_RETURN(DEVICE_LOCKED, DeviceLocked)
+    HANDLE_MESSAGE_W_RETURN(GET_VERSION_2, GetVersion2)
+#undef HANDLE_MESSAGE
+#define HANDLE_MESSAGE_W_RETURN_NO_ARG(ENUM_NAME, METHOD_NAME) \
+    case ENUM_NAME: {\
+      auto response = keymaster_.METHOD_NAME(); \
+      return channel_.SendResponse(ENUM_NAME, response); \
+    }
+    HANDLE_MESSAGE_W_RETURN_NO_ARG(GET_HMAC_SHARING_PARAMETERS, GetHmacSharingParameters)
+    HANDLE_MESSAGE_W_RETURN_NO_ARG(EARLY_BOOT_ENDED, EarlyBootEnded)
+#undef HANDLE_MESSAGE
+    case ADD_RNG_ENTROPY: {
+      AddEntropyRequest request(keymaster_.message_version());
+      if (!request.Deserialize(&buffer, end)) {
+        LOG(ERROR) << "Failed to deserialize AddEntropyRequest";
+        return false;
+      }
+      AddEntropyResponse response(keymaster_.message_version());;
+      keymaster_.AddRngEntropy(request, &response);
+      return channel_.SendResponse(ADD_RNG_ENTROPY, response);
+    }
+    case DESTROY_ATTESTATION_IDS:
+      // Cuttlefish doesn't support ID attestation.
+    default:
+      LOG(ERROR) << "Unknown request type: " << request->cmd;
+      return false;
+  }
+}
diff --git a/host/commands/secure_env/keymaster_responder.h b/host/commands/secure_env/keymaster_responder.h
new file mode 100644
index 0000000..f8fb6ec
--- /dev/null
+++ b/host/commands/secure_env/keymaster_responder.h
@@ -0,0 +1,31 @@
+//
+// 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 <keymaster/android_keymaster.h>
+
+#include "common/libs/security/keymaster_channel.h"
+
+class KeymasterResponder {
+private:
+  cuttlefish::KeymasterChannel& channel_;
+  keymaster::AndroidKeymaster& keymaster_;
+public:
+  KeymasterResponder(cuttlefish::KeymasterChannel& channel,
+                     keymaster::AndroidKeymaster& keymaster);
+
+  bool ProcessMessage();
+};
diff --git a/host/commands/secure_env/primary_key_builder.cpp b/host/commands/secure_env/primary_key_builder.cpp
new file mode 100644
index 0000000..a44ff24
--- /dev/null
+++ b/host/commands/secure_env/primary_key_builder.cpp
@@ -0,0 +1,135 @@
+//
+// 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.
+
+#include "host/commands/secure_env/primary_key_builder.h"
+
+#include <android-base/logging.h>
+#include <tss2/tss2_mu.h>
+#include <tss2/tss2_rc.h>
+
+PrimaryKeyBuilder::PrimaryKeyBuilder() : public_area_({}) {
+  public_area_.nameAlg = TPM2_ALG_SHA256;
+};
+
+void PrimaryKeyBuilder::SigningKey() {
+  public_area_.type = TPM2_ALG_KEYEDHASH;
+  public_area_.objectAttributes |= TPMA_OBJECT_SIGN_ENCRYPT;
+  public_area_.objectAttributes |= TPMA_OBJECT_USERWITHAUTH;
+  public_area_.objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN;
+  public_area_.parameters.keyedHashDetail.scheme = (TPMT_KEYEDHASH_SCHEME) {
+    .scheme = TPM2_ALG_HMAC,
+    .details.hmac.hashAlg = TPM2_ALG_SHA256,
+  };
+}
+
+void PrimaryKeyBuilder::ParentKey() {
+  public_area_.type = TPM2_ALG_SYMCIPHER;
+  public_area_.objectAttributes |= TPMA_OBJECT_USERWITHAUTH;
+  public_area_.objectAttributes |= TPMA_OBJECT_RESTRICTED;
+  public_area_.objectAttributes |= TPMA_OBJECT_DECRYPT;
+  public_area_.objectAttributes |= TPMA_OBJECT_FIXEDTPM;
+  public_area_.objectAttributes |= TPMA_OBJECT_FIXEDPARENT;
+  public_area_.objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN;
+  public_area_.parameters.symDetail.sym = (TPMT_SYM_DEF_OBJECT) {
+    .algorithm = TPM2_ALG_AES,
+    .keyBits.aes = 128, // The default maximum AES key size in the simulator.
+    .mode.aes = TPM2_ALG_CFB,
+  };
+}
+
+void PrimaryKeyBuilder::UniqueData(const std::string& data) {
+  if (data.size() > TPM2_SHA256_DIGEST_SIZE) {
+    LOG(FATAL) << "Unique data size was too large";
+  }
+  /* The unique field normally has a precise size to go with the type of the
+   * object. During primary key creation the unique field accepts any short byte
+   * string to let the user introduce variability into the primary key creation
+   * process which is otherwise determinstic relative to secret TPM state. */
+  public_area_.unique.sym.size = data.size();
+  memcpy(&public_area_.unique.sym.buffer, data.data(), data.size());
+}
+
+TpmObjectSlot PrimaryKeyBuilder::CreateKey(
+    TpmResourceManager& resource_manager) {
+  TPM2B_AUTH authValue = {};
+  auto rc =
+      Esys_TR_SetAuth(resource_manager.Esys(), ESYS_TR_RH_OWNER, &authValue);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return {};
+  }
+
+  TPM2B_TEMPLATE public_template = {};
+  size_t offset = 0;
+  rc = Tss2_MU_TPMT_PUBLIC_Marshal(&public_area_, &public_template.buffer[0],
+                                   sizeof(public_template.buffer), &offset);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Tss2_MU_TPMT_PUBLIC_Marshal failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return {};
+  }
+  public_template.size = offset;
+
+  TPM2B_SENSITIVE_CREATE in_sensitive = {};
+
+  auto key_slot = resource_manager.ReserveSlot();
+  if (!key_slot) {
+    LOG(ERROR) << "No slots available";
+    return {};
+  }
+  ESYS_TR raw_handle;
+  // TODO(b/154956668): Define better ACLs on these keys.
+  // Since this is a primary key, it's generated deterministically. It would
+  // also be possible to generate this once and hold it in storage.
+  rc = Esys_CreateLoaded(
+    /* esysContext */ resource_manager.Esys(),
+    /* primaryHandle */ ESYS_TR_RH_OWNER,
+    /* shandle1 */ ESYS_TR_PASSWORD,
+    /* shandle2 */ ESYS_TR_NONE,
+    /* shandle3 */ ESYS_TR_NONE,
+    /* inSensitive */ &in_sensitive,
+    /* inPublic */ &public_template,
+    /* objectHandle */ &raw_handle,
+    /* outPrivate */ nullptr,
+    /* outPublic */ nullptr);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
+               << " (" << Tss2_RC_Decode(rc) << ")";
+    return {};
+  }
+  key_slot->set(raw_handle);
+  return key_slot;
+}
+
+std::function<TpmObjectSlot(TpmResourceManager&)>
+SigningKeyCreator(const std::string& unique) {
+  return [unique](TpmResourceManager& resource_manager) {
+    PrimaryKeyBuilder key_builder;
+    key_builder.SigningKey();
+    key_builder.UniqueData(unique);
+    return key_builder.CreateKey(resource_manager);
+  };
+}
+
+std::function<TpmObjectSlot(TpmResourceManager&)>
+ParentKeyCreator(const std::string& unique) {
+  return [unique](TpmResourceManager& resource_manager) {
+    PrimaryKeyBuilder key_builder;
+    key_builder.ParentKey();
+    key_builder.UniqueData(unique);
+    return key_builder.CreateKey(resource_manager);
+  };
+}
diff --git a/host/commands/secure_env/primary_key_builder.h b/host/commands/secure_env/primary_key_builder.h
new file mode 100644
index 0000000..46e5461
--- /dev/null
+++ b/host/commands/secure_env/primary_key_builder.h
@@ -0,0 +1,42 @@
+//
+// 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 <functional>
+#include <string>
+
+#include <tss2/tss2_esys.h>
+
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+class PrimaryKeyBuilder {
+public:
+  PrimaryKeyBuilder();
+
+  void SigningKey();
+  void ParentKey();
+  void UniqueData(const std::string&);
+
+  TpmObjectSlot CreateKey(TpmResourceManager&);
+private:
+  TPMT_PUBLIC public_area_;
+};
+
+std::function<TpmObjectSlot(TpmResourceManager&)>
+SigningKeyCreator(const std::string& unique);
+
+std::function<TpmObjectSlot(TpmResourceManager&)>
+ParentKeyCreator(const std::string& unique);
diff --git a/host/commands/secure_env/secure_env.cpp b/host/commands/secure_env/secure_env.cpp
new file mode 100644
index 0000000..c050c58
--- /dev/null
+++ b/host/commands/secure_env/secure_env.cpp
@@ -0,0 +1,182 @@
+//
+// 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.
+
+#include <thread>
+
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
+#include <keymaster/android_keymaster.h>
+#include <keymaster/soft_keymaster_logger.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <tss2/tss2_esys.h>
+#include <tss2/tss2_rc.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/gatekeeper_channel.h"
+#include "common/libs/security/keymaster_channel.h"
+#include "host/commands/secure_env/device_tpm.h"
+#include "host/commands/secure_env/fragile_tpm_storage.h"
+#include "host/commands/secure_env/gatekeeper_responder.h"
+#include "host/commands/secure_env/insecure_fallback_storage.h"
+#include "host/commands/secure_env/in_process_tpm.h"
+#include "host/commands/secure_env/keymaster_responder.h"
+#include "host/commands/secure_env/soft_gatekeeper.h"
+#include "host/commands/secure_env/tpm_gatekeeper.h"
+#include "host/commands/secure_env/tpm_keymaster_context.h"
+#include "host/commands/secure_env/tpm_keymaster_enforcement.h"
+#include "host/commands/secure_env/tpm_resource_manager.h"
+#include "host/libs/config/logging.h"
+
+// Copied from AndroidKeymaster4Device
+constexpr size_t kOperationTableSize = 16;
+
+DEFINE_int32(keymaster_fd_in, -1, "A pipe for keymaster communication");
+DEFINE_int32(keymaster_fd_out, -1, "A pipe for keymaster communication");
+DEFINE_int32(gatekeeper_fd_in, -1, "A pipe for gatekeeper communication");
+DEFINE_int32(gatekeeper_fd_out, -1, "A pipe for gatekeeper communication");
+
+DEFINE_string(tpm_impl,
+              "in_memory",
+              "The TPM implementation. \"in_memory\" or \"host_device\"");
+
+DEFINE_string(keymint_impl, "tpm",
+              "The keymaster implementation. \"tpm\" or \"software\"");
+
+DEFINE_string(gatekeeper_impl, "tpm",
+              "The gatekeeper implementation. \"tpm\" or \"software\"");
+
+int main(int argc, char** argv) {
+  cuttlefish::DefaultSubprocessLogging(argv);
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
+  keymaster::SoftKeymasterLogger km_logger;
+
+  std::unique_ptr<Tpm> tpm;
+  if (FLAGS_tpm_impl == "in_memory") {
+    tpm.reset(new InProcessTpm());
+  } else if (FLAGS_tpm_impl == "host_device") {
+    tpm.reset(new DeviceTpm("/dev/tpm0"));
+  } else {
+    LOG(FATAL) << "Unknown TPM implementation: " << FLAGS_tpm_impl;
+  }
+
+  if (tpm->TctiContext() == nullptr) {
+    LOG(FATAL) << "Unable to connect to TPM implementation.";
+  }
+
+  std::unique_ptr<TpmResourceManager> resource_manager;
+  std::unique_ptr<ESYS_CONTEXT, void(*)(ESYS_CONTEXT*)> esys(
+      nullptr, [](ESYS_CONTEXT* esys) { Esys_Finalize(&esys); });
+  if (FLAGS_keymint_impl == "tpm" || FLAGS_gatekeeper_impl == "tpm") {
+    ESYS_CONTEXT* esys_ptr = nullptr;
+    auto rc = Esys_Initialize(&esys_ptr, tpm->TctiContext(), nullptr);
+    if (rc != TPM2_RC_SUCCESS) {
+      LOG(FATAL) << "Could not initialize esys: " << Tss2_RC_Decode(rc)
+                 << " (" << rc << ")";
+    }
+    esys.reset(esys_ptr);
+    resource_manager.reset(new TpmResourceManager(esys.get()));
+  }
+
+  std::unique_ptr<GatekeeperStorage> secure_storage;
+  std::unique_ptr<GatekeeperStorage> insecure_storage;
+  std::unique_ptr<gatekeeper::GateKeeper> gatekeeper;
+  std::unique_ptr<keymaster::KeymasterEnforcement> keymaster_enforcement;
+  if (FLAGS_gatekeeper_impl == "software") {
+    gatekeeper.reset(new gatekeeper::SoftGateKeeper);
+    keymaster_enforcement.reset(
+        new keymaster::SoftKeymasterEnforcement(64, 64));
+  } else if (FLAGS_gatekeeper_impl == "tpm") {
+    secure_storage.reset(
+        new FragileTpmStorage(*resource_manager, "gatekeeper_secure"));
+    insecure_storage.reset(
+        new InsecureFallbackStorage(*resource_manager, "gatekeeper_insecure"));
+    TpmGatekeeper* tpm_gatekeeper =
+        new TpmGatekeeper(*resource_manager, *secure_storage, *insecure_storage);
+    gatekeeper.reset(tpm_gatekeeper);
+    keymaster_enforcement.reset(
+        new TpmKeymasterEnforcement(*resource_manager, *tpm_gatekeeper));
+  }
+
+  // keymaster::AndroidKeymaster puts the given pointer into a UniquePtr,
+  // taking ownership.
+  keymaster::KeymasterContext* keymaster_context;
+  if (FLAGS_keymint_impl == "software") {
+    // TODO: See if this is the right KM version.
+    keymaster_context =
+        new keymaster::PureSoftKeymasterContext(keymaster::KmVersion::KEYMASTER_4,
+                                                KM_SECURITY_LEVEL_SOFTWARE);
+  } else if (FLAGS_keymint_impl == "tpm") {
+    keymaster_context =
+        new TpmKeymasterContext(*resource_manager, *keymaster_enforcement);
+  } else {
+    LOG(FATAL) << "Unknown keymaster implementation " << FLAGS_keymint_impl;
+    return -1;
+  }
+  keymaster::AndroidKeymaster keymaster{
+      keymaster_context, kOperationTableSize,
+      keymaster::MessageVersion(keymaster::KmVersion::KEYMINT_1,
+                                0 /* km_date */)};
+
+  CHECK(FLAGS_keymaster_fd_in != -1);
+  auto keymaster_in = cuttlefish::SharedFD::Dup(FLAGS_keymaster_fd_in);
+  CHECK(keymaster_in->IsOpen()) << "Could not dup input fd: "
+                                << keymaster_in->StrError();
+  close(FLAGS_keymaster_fd_in);
+
+  CHECK(FLAGS_keymaster_fd_out != -1);
+  auto keymaster_out = cuttlefish::SharedFD::Dup(FLAGS_keymaster_fd_out);
+  CHECK(keymaster_out->IsOpen()) << "Could not dup output fd: "
+                                 << keymaster_out->StrError();
+  close(FLAGS_keymaster_fd_out);
+
+  CHECK(FLAGS_gatekeeper_fd_in != -1);
+  auto gatekeeper_in = cuttlefish::SharedFD::Dup(FLAGS_gatekeeper_fd_in);
+  CHECK(gatekeeper_in->IsOpen()) << "Could not dup input fd: "
+                                << gatekeeper_in->StrError();
+  close(FLAGS_gatekeeper_fd_in);
+
+  CHECK(FLAGS_gatekeeper_fd_out != -1);
+  auto gatekeeper_out = cuttlefish::SharedFD::Dup(FLAGS_gatekeeper_fd_out);
+  CHECK(gatekeeper_out->IsOpen()) << "Could not dup output fd: "
+                                  << keymaster_out->StrError();
+  close(FLAGS_gatekeeper_fd_out);
+
+  std::thread keymaster_thread([keymaster_in, keymaster_out, &keymaster]() {
+    while (true) {
+      cuttlefish::KeymasterChannel keymaster_channel(
+          keymaster_in, keymaster_out);
+
+      KeymasterResponder keymaster_responder(keymaster_channel, keymaster);
+
+      while (keymaster_responder.ProcessMessage()) {
+      }
+    }
+  });
+
+  std::thread gatekeeper_thread([gatekeeper_in, gatekeeper_out, &gatekeeper]() {
+    while (true) {
+      cuttlefish::GatekeeperChannel gatekeeper_channel(
+          gatekeeper_in, gatekeeper_out);
+
+      GatekeeperResponder gatekeeper_responder(gatekeeper_channel, *gatekeeper);
+
+      while (gatekeeper_responder.ProcessMessage()) {
+      }
+    }
+  });
+
+  keymaster_thread.join();
+  gatekeeper_thread.join();
+}
diff --git a/host/commands/secure_env/soft_gatekeeper.h b/host/commands/secure_env/soft_gatekeeper.h
new file mode 100644
index 0000000..c3322e8
--- /dev/null
+++ b/host/commands/secure_env/soft_gatekeeper.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2015 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
+
+extern "C" {
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include <crypto_scrypt.h>
+}
+
+#include <android-base/memory.h>
+#include <gatekeeper/gatekeeper.h>
+
+#include <iostream>
+#include <memory>
+#include <unordered_map>
+
+namespace gatekeeper {
+
+struct fast_hash_t {
+    uint64_t salt;
+    uint8_t digest[SHA256_DIGEST_LENGTH];
+};
+
+class SoftGateKeeper : public GateKeeper {
+  public:
+    static const uint32_t SIGNATURE_LENGTH_BYTES = 32;
+
+    // scrypt params
+    static const uint64_t N = 16384;
+    static const uint32_t r = 8;
+    static const uint32_t p = 1;
+
+    static const int MAX_UINT_32_CHARS = 11;
+
+    SoftGateKeeper() {
+        key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]);
+        memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES);
+    }
+
+    virtual ~SoftGateKeeper() {}
+
+    virtual bool GetAuthTokenKey(const uint8_t** auth_token_key, uint32_t* length) const {
+        if (auth_token_key == NULL || length == NULL) return false;
+        *auth_token_key = key_.get();
+        *length = SIGNATURE_LENGTH_BYTES;
+        return true;
+    }
+
+    virtual void GetPasswordKey(const uint8_t** password_key, uint32_t* length) {
+        if (password_key == NULL || length == NULL) return;
+        *password_key = key_.get();
+        *length = SIGNATURE_LENGTH_BYTES;
+    }
+
+    virtual void ComputePasswordSignature(uint8_t* signature, uint32_t signature_length,
+                                          const uint8_t*, uint32_t, const uint8_t* password,
+                                          uint32_t password_length, salt_t salt) const {
+        if (signature == NULL) return;
+        crypto_scrypt(password, password_length, reinterpret_cast<uint8_t*>(&salt), sizeof(salt), N,
+                      r, p, signature, signature_length);
+    }
+
+    virtual void GetRandom(void* random, uint32_t requested_length) const {
+        if (random == NULL) return;
+        RAND_pseudo_bytes((uint8_t*)random, requested_length);
+    }
+
+    virtual void ComputeSignature(uint8_t* signature, uint32_t signature_length, const uint8_t*,
+                                  uint32_t, const uint8_t*, const uint32_t) const {
+        if (signature == NULL) return;
+        memset(signature, 0, signature_length);
+    }
+
+    virtual uint64_t GetMillisecondsSinceBoot() const {
+        struct timespec time;
+        int res = clock_gettime(CLOCK_BOOTTIME, &time);
+        if (res < 0) return 0;
+        return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
+    }
+
+    virtual bool IsHardwareBacked() const { return false; }
+
+    virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t* record,
+                                  bool /* secure */) {
+        failure_record_t* stored = &failure_map_[uid];
+        if (user_id != stored->secure_user_id) {
+            stored->secure_user_id = user_id;
+            stored->last_checked_timestamp = 0;
+            stored->failure_counter = 0;
+        }
+        memcpy(record, stored, sizeof(*record));
+        return true;
+    }
+
+    virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) {
+        failure_record_t* stored = &failure_map_[uid];
+        stored->secure_user_id = user_id;
+        stored->last_checked_timestamp = 0;
+        stored->failure_counter = 0;
+        return true;
+    }
+
+    virtual bool WriteFailureRecord(uint32_t uid, failure_record_t* record, bool /* secure */) {
+        failure_map_[uid] = *record;
+        return true;
+    }
+
+    fast_hash_t ComputeFastHash(const SizedBuffer& password, uint64_t salt) {
+        fast_hash_t fast_hash;
+        size_t digest_size = password.size() + sizeof(salt);
+        std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]);
+        memcpy(digest.get(), &salt, sizeof(salt));
+        memcpy(digest.get() + sizeof(salt), password.Data<uint8_t>(), password.size());
+
+        SHA256(digest.get(), digest_size, (uint8_t*)&fast_hash.digest);
+
+        fast_hash.salt = salt;
+        return fast_hash;
+    }
+
+    bool VerifyFast(const fast_hash_t& fast_hash, const SizedBuffer& password) {
+        fast_hash_t computed = ComputeFastHash(password, fast_hash.salt);
+        return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0;
+    }
+
+    bool DoVerify(const password_handle_t* expected_handle, const SizedBuffer& password) {
+        uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id);
+        FastHashMap::const_iterator it = fast_hash_map_.find(user_id);
+        if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
+            return true;
+        } else {
+            if (GateKeeper::DoVerify(expected_handle, password)) {
+                uint64_t salt;
+                GetRandom(&salt, sizeof(salt));
+                fast_hash_map_[user_id] = ComputeFastHash(password, salt);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+  private:
+    typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
+    typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
+
+    std::unique_ptr<uint8_t[]> key_;
+    FailureRecordMap failure_map_;
+    FastHashMap fast_hash_map_;
+};
+}  // namespace gatekeeper
diff --git a/host/commands/secure_env/tpm.h b/host/commands/secure_env/tpm.h
new file mode 100644
index 0000000..201e5e7
--- /dev/null
+++ b/host/commands/secure_env/tpm.h
@@ -0,0 +1,25 @@
+//
+// 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 <tss2/tss2_tcti.h>
+
+class Tpm {
+public:
+  virtual ~Tpm() = default;
+
+  virtual TSS2_TCTI_CONTEXT* TctiContext() = 0;
+};
diff --git a/host/commands/secure_env/tpm_attestation_record.cpp b/host/commands/secure_env/tpm_attestation_record.cpp
new file mode 100644
index 0000000..f47a0ef
--- /dev/null
+++ b/host/commands/secure_env/tpm_attestation_record.cpp
@@ -0,0 +1,81 @@
+//
+// 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.
+
+#include "host/commands/secure_env/tpm_attestation_record.h"
+
+#include <keymaster/contexts/soft_attestation_cert.h>
+
+#include <android-base/logging.h>
+
+using keymaster::AuthorizationSet;
+
+keymaster_security_level_t TpmAttestationRecordContext::GetSecurityLevel() const {
+  return KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+}
+
+keymaster_error_t TpmAttestationRecordContext::VerifyAndCopyDeviceIds(
+    const AuthorizationSet& attestation_params,
+    AuthorizationSet* attestation) const {
+  LOG(DEBUG) << "TODO(schuffelen): Implement VerifyAndCopyDeviceIds";
+  attestation->Difference(attestation_params);
+  attestation->Union(attestation_params);
+  if (int index = attestation->find(keymaster::TAG_ATTESTATION_APPLICATION_ID)) {
+    attestation->erase(index);
+  }
+  return KM_ERROR_OK;
+}
+
+keymaster::Buffer TpmAttestationRecordContext::GenerateUniqueId(
+    uint64_t, const keymaster_blob_t&, bool, keymaster_error_t* error) const {
+  LOG(ERROR) << "TODO(schuffelen): Implement GenerateUniqueId";
+  *error = KM_ERROR_UNIMPLEMENTED;
+  return {};
+}
+
+const keymaster::AttestationContext::VerifiedBootParams*
+TpmAttestationRecordContext::GetVerifiedBootParams(keymaster_error_t* error) const {
+  LOG(DEBUG) << "TODO(schuffelen): Implement GetVerifiedBootParams";
+  if (!vb_params_) {
+      vb_params_.reset(new VerifiedBootParams{});
+
+      // TODO(schuffelen): Get this data out of vbmeta
+      static uint8_t fake_vb_key[32];
+      static bool fake_vb_key_initialized = false;
+      if (!fake_vb_key_initialized) {
+        for (int i = 0; i < sizeof(fake_vb_key); i++) {
+          fake_vb_key[i] = rand();
+        }
+        fake_vb_key_initialized = true;
+      }
+      vb_params_->verified_boot_key = {fake_vb_key, sizeof(fake_vb_key)};
+      vb_params_->verified_boot_hash = {fake_vb_key, sizeof(fake_vb_key)};
+      vb_params_->verified_boot_state = KM_VERIFIED_BOOT_VERIFIED;
+      vb_params_->device_locked = true;
+  }
+  *error = KM_ERROR_OK;
+  return vb_params_.get();
+}
+
+keymaster::KeymasterKeyBlob
+TpmAttestationRecordContext::GetAttestationKey(keymaster_algorithm_t algorithm,
+                                               keymaster_error_t* error) const {
+  return keymaster::KeymasterKeyBlob(*keymaster::getAttestationKey(algorithm, error));
+}
+
+keymaster::CertificateChain
+TpmAttestationRecordContext::GetAttestationChain(keymaster_algorithm_t algorithm,
+                                                 keymaster_error_t* error) const {
+  return keymaster::getAttestationChain(algorithm, error);
+}
diff --git a/host/commands/secure_env/tpm_attestation_record.h b/host/commands/secure_env/tpm_attestation_record.h
new file mode 100644
index 0000000..01e31d7
--- /dev/null
+++ b/host/commands/secure_env/tpm_attestation_record.h
@@ -0,0 +1,43 @@
+//
+// 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 <memory>
+
+#include <keymaster/attestation_context.h>
+
+class TpmAttestationRecordContext : public keymaster::AttestationContext {
+public:
+ TpmAttestationRecordContext()
+     : keymaster::AttestationContext(::keymaster::KmVersion::KEYMINT_1) {}
+ ~TpmAttestationRecordContext() = default;
+
+ keymaster_security_level_t GetSecurityLevel() const override;
+ keymaster_error_t VerifyAndCopyDeviceIds(
+     const keymaster::AuthorizationSet&,
+     keymaster::AuthorizationSet*) const override;
+ keymaster::Buffer GenerateUniqueId(uint64_t, const keymaster_blob_t&, bool,
+                                    keymaster_error_t*) const override;
+ const VerifiedBootParams* GetVerifiedBootParams(
+     keymaster_error_t* error) const override;
+ keymaster::KeymasterKeyBlob GetAttestationKey(
+     keymaster_algorithm_t algorithm, keymaster_error_t* error) const override;
+ keymaster::CertificateChain GetAttestationChain(
+     keymaster_algorithm_t algorithm, keymaster_error_t* error) const override;
+
+private:
+    mutable std::unique_ptr<VerifiedBootParams> vb_params_;
+};
diff --git a/host/commands/secure_env/tpm_auth.cpp b/host/commands/secure_env/tpm_auth.cpp
new file mode 100644
index 0000000..10f4b2d
--- /dev/null
+++ b/host/commands/secure_env/tpm_auth.cpp
@@ -0,0 +1,43 @@
+//
+// 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.
+
+#include "tpm_auth.h"
+
+#include <tuple>
+
+TpmAuth::TpmAuth(ESYS_TR auth): TpmAuth(auth, ESYS_TR_NONE, ESYS_TR_NONE) {}
+TpmAuth::TpmAuth(ESYS_TR auth1, ESYS_TR auth2)
+    : TpmAuth(auth1, auth2, ESYS_TR_NONE) {}
+TpmAuth::TpmAuth(ESYS_TR auth1, ESYS_TR auth2, ESYS_TR auth3) {
+  if (auth2 == ESYS_TR_NONE && auth3 != ESYS_TR_NONE) {
+    std::swap(auth2, auth3);
+  }
+  if (auth1 == ESYS_TR_NONE && auth2 != ESYS_TR_NONE) {
+    std::swap(auth1, auth2);
+  }
+  std::tie(auth1_, auth2_, auth3_) = std::make_tuple(auth1, auth2, auth3);
+}
+
+ESYS_TR TpmAuth::auth1() const {
+  return auth1_;
+}
+
+ESYS_TR TpmAuth::auth2() const {
+  return auth2_;
+}
+
+ESYS_TR TpmAuth::auth3() const {
+  return auth3_;
+}
diff --git a/host/commands/secure_env/tpm_auth.h b/host/commands/secure_env/tpm_auth.h
new file mode 100644
index 0000000..196b5fd
--- /dev/null
+++ b/host/commands/secure_env/tpm_auth.h
@@ -0,0 +1,43 @@
+//
+// 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 <tss2/tss2_esys.h>
+
+/**
+ * Authorization wrapper for TPM2 calls.
+ *
+ * Most methods in tss2_esys.h take 3 ESYS_TR values for sessions and
+ * authorization, with constraints that unused authorizations are all
+ * ESYS_TR_NONE and are all at the end.
+ *
+ * This class is a convenience for specifying between 1 and 3
+ * authorizations concisely and enforcing that the constraints are met.
+ */
+class TpmAuth {
+public:
+  TpmAuth(ESYS_TR auth1);
+  TpmAuth(ESYS_TR auth1, ESYS_TR auth2);
+  TpmAuth(ESYS_TR auth1, ESYS_TR auth2, ESYS_TR auth3);
+
+  ESYS_TR auth1() const;
+  ESYS_TR auth2() const;
+  ESYS_TR auth3() const;
+private:
+  ESYS_TR auth1_;
+  ESYS_TR auth2_;
+  ESYS_TR auth3_;
+};
diff --git a/host/commands/secure_env/tpm_commands.cpp b/host/commands/secure_env/tpm_commands.cpp
new file mode 100644
index 0000000..78e9d7f
--- /dev/null
+++ b/host/commands/secure_env/tpm_commands.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+#include "tpm_commands.h"
+
+#include <tss2/tss2_tpm2_types.h>
+
+#include <cstddef>
+#include <string>
+
+std::string TpmCommandName(std::uint32_t command_num) {
+  switch(command_num) {
+    #define MATCH_TPM_COMMAND(name) case name: return #name;
+    MATCH_TPM_COMMAND(TPM2_CC_NV_UndefineSpaceSpecial)
+    MATCH_TPM_COMMAND(TPM2_CC_EvictControl)
+    MATCH_TPM_COMMAND(TPM2_CC_HierarchyControl)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_UndefineSpace)
+    MATCH_TPM_COMMAND(TPM2_CC_ChangeEPS)
+    MATCH_TPM_COMMAND(TPM2_CC_ChangePPS)
+    MATCH_TPM_COMMAND(TPM2_CC_Clear)
+    MATCH_TPM_COMMAND(TPM2_CC_ClearControl)
+    MATCH_TPM_COMMAND(TPM2_CC_ClockSet)
+    MATCH_TPM_COMMAND(TPM2_CC_HierarchyChangeAuth)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_DefineSpace)
+    MATCH_TPM_COMMAND(TPM2_CC_PCR_Allocate)
+    MATCH_TPM_COMMAND(TPM2_CC_PCR_SetAuthPolicy)
+    MATCH_TPM_COMMAND(TPM2_CC_PP_Commands)
+    MATCH_TPM_COMMAND(TPM2_CC_SetPrimaryPolicy)
+    MATCH_TPM_COMMAND(TPM2_CC_FieldUpgradeStart)
+    MATCH_TPM_COMMAND(TPM2_CC_ClockRateAdjust)
+    MATCH_TPM_COMMAND(TPM2_CC_CreatePrimary)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_GlobalWriteLock)
+    MATCH_TPM_COMMAND(TPM2_CC_GetCommandAuditDigest)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_Increment)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_SetBits)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_Extend)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_Write)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_WriteLock)
+    MATCH_TPM_COMMAND(TPM2_CC_DictionaryAttackLockReset)
+    MATCH_TPM_COMMAND(TPM2_CC_DictionaryAttackParameters)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_ChangeAuth)
+    MATCH_TPM_COMMAND(TPM2_CC_PCR_Event)
+    MATCH_TPM_COMMAND(TPM2_CC_PCR_Reset)
+    MATCH_TPM_COMMAND(TPM2_CC_SequenceComplete)
+    MATCH_TPM_COMMAND(TPM2_CC_SetAlgorithmSet)
+    MATCH_TPM_COMMAND(TPM2_CC_SetCommandCodeAuditStatus)
+    MATCH_TPM_COMMAND(TPM2_CC_FieldUpgradeData)
+    MATCH_TPM_COMMAND(TPM2_CC_IncrementalSelfTest)
+    MATCH_TPM_COMMAND(TPM2_CC_SelfTest)
+    MATCH_TPM_COMMAND(TPM2_CC_Startup)
+    MATCH_TPM_COMMAND(TPM2_CC_Shutdown)
+    MATCH_TPM_COMMAND(TPM2_CC_StirRandom)
+    MATCH_TPM_COMMAND(TPM2_CC_ActivateCredential)
+    MATCH_TPM_COMMAND(TPM2_CC_Certify)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyNV)
+    MATCH_TPM_COMMAND(TPM2_CC_CertifyCreation)
+    MATCH_TPM_COMMAND(TPM2_CC_Duplicate)
+    MATCH_TPM_COMMAND(TPM2_CC_GetTime)
+    MATCH_TPM_COMMAND(TPM2_CC_GetSessionAuditDigest)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_Read)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_ReadLock)
+    MATCH_TPM_COMMAND(TPM2_CC_ObjectChangeAuth)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicySecret)
+    MATCH_TPM_COMMAND(TPM2_CC_Rewrap)
+    MATCH_TPM_COMMAND(TPM2_CC_Create)
+    MATCH_TPM_COMMAND(TPM2_CC_ECDH_ZGen)
+    MATCH_TPM_COMMAND(TPM2_CC_HMAC)
+    MATCH_TPM_COMMAND(TPM2_CC_Import)
+    MATCH_TPM_COMMAND(TPM2_CC_Load)
+    MATCH_TPM_COMMAND(TPM2_CC_Quote)
+    MATCH_TPM_COMMAND(TPM2_CC_RSA_Decrypt)
+    MATCH_TPM_COMMAND(TPM2_CC_HMAC_Start)
+    MATCH_TPM_COMMAND(TPM2_CC_SequenceUpdate)
+    MATCH_TPM_COMMAND(TPM2_CC_Sign)
+    MATCH_TPM_COMMAND(TPM2_CC_Unseal)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicySigned)
+    MATCH_TPM_COMMAND(TPM2_CC_ContextLoad)
+    MATCH_TPM_COMMAND(TPM2_CC_ContextSave)
+    MATCH_TPM_COMMAND(TPM2_CC_ECDH_KeyGen)
+    MATCH_TPM_COMMAND(TPM2_CC_EncryptDecrypt)
+    MATCH_TPM_COMMAND(TPM2_CC_FlushContext)
+    MATCH_TPM_COMMAND(TPM2_CC_LoadExternal)
+    MATCH_TPM_COMMAND(TPM2_CC_MakeCredential)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_ReadPublic)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyAuthorize)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyAuthValue)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyCommandCode)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyCounterTimer)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyCpHash)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyLocality)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyNameHash)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyOR)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyTicket)
+    MATCH_TPM_COMMAND(TPM2_CC_ReadPublic)
+    MATCH_TPM_COMMAND(TPM2_CC_RSA_Encrypt)
+    MATCH_TPM_COMMAND(TPM2_CC_StartAuthSession)
+    MATCH_TPM_COMMAND(TPM2_CC_VerifySignature)
+    MATCH_TPM_COMMAND(TPM2_CC_ECC_Parameters)
+    MATCH_TPM_COMMAND(TPM2_CC_FirmwareRead)
+    MATCH_TPM_COMMAND(TPM2_CC_GetCapability)
+    MATCH_TPM_COMMAND(TPM2_CC_GetRandom)
+    MATCH_TPM_COMMAND(TPM2_CC_GetTestResult)
+    MATCH_TPM_COMMAND(TPM2_CC_Hash)
+    MATCH_TPM_COMMAND(TPM2_CC_PCR_Read)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyPCR)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyRestart)
+    MATCH_TPM_COMMAND(TPM2_CC_ReadClock)
+    MATCH_TPM_COMMAND(TPM2_CC_PCR_Extend)
+    MATCH_TPM_COMMAND(TPM2_CC_PCR_SetAuthValue)
+    MATCH_TPM_COMMAND(TPM2_CC_NV_Certify)
+    MATCH_TPM_COMMAND(TPM2_CC_EventSequenceComplete)
+    MATCH_TPM_COMMAND(TPM2_CC_HashSequenceStart)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyPhysicalPresence)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyDuplicationSelect)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyGetDigest)
+    MATCH_TPM_COMMAND(TPM2_CC_TestParms)
+    MATCH_TPM_COMMAND(TPM2_CC_Commit)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyPassword)
+    MATCH_TPM_COMMAND(TPM2_CC_ZGen_2Phase)
+    MATCH_TPM_COMMAND(TPM2_CC_EC_Ephemeral)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyNvWritten)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyTemplate)
+    MATCH_TPM_COMMAND(TPM2_CC_CreateLoaded)
+    MATCH_TPM_COMMAND(TPM2_CC_PolicyAuthorizeNV)
+    MATCH_TPM_COMMAND(TPM2_CC_EncryptDecrypt2)
+    MATCH_TPM_COMMAND(TPM2_CC_AC_GetCapability)
+    MATCH_TPM_COMMAND(TPM2_CC_AC_Send)
+    MATCH_TPM_COMMAND(TPM2_CC_Policy_AC_SendSelect)
+    MATCH_TPM_COMMAND(TPM2_CC_Vendor_TCG_Test)
+    #undef MATCH_TPM_COMMAND
+    default:
+      return "Unknown";
+  }
+}
diff --git a/host/commands/secure_env/tpm_commands.h b/host/commands/secure_env/tpm_commands.h
new file mode 100644
index 0000000..ee75844
--- /dev/null
+++ b/host/commands/secure_env/tpm_commands.h
@@ -0,0 +1,22 @@
+/*
+ * 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 <cstddef>
+#include <string>
+
+std::string TpmCommandName(std::uint32_t command_num);
diff --git a/host/commands/secure_env/tpm_encrypt_decrypt.cpp b/host/commands/secure_env/tpm_encrypt_decrypt.cpp
new file mode 100644
index 0000000..4a1711e
--- /dev/null
+++ b/host/commands/secure_env/tpm_encrypt_decrypt.cpp
@@ -0,0 +1,100 @@
+//
+// 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.
+
+#include "tpm_encrypt_decrypt.h"
+
+#include <algorithm>
+#include <cstring>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <tss2/tss2_rc.h>
+
+using keymaster::KeymasterBlob;
+
+static bool TpmEncryptDecrypt(
+    ESYS_CONTEXT* esys,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    uint8_t* data_in,
+    uint8_t* data_out,
+    size_t data_size,
+    bool decrypt) {
+  // TODO(schuffelen): Pipeline this for performance. Will require reevaluating
+  // the initialization vector logic.
+  std::vector<unsigned char> converted(data_size);
+  // malloc for parity with Esys_EncryptDecrypt2
+  TPM2B_IV* init_vector_in = (TPM2B_IV*) malloc(sizeof(TPM2B_IV));
+  *init_vector_in = {};
+  init_vector_in->size = 16;
+  for (auto processed = 0; processed < data_size;) {
+    TPM2B_MAX_BUFFER in_data;
+    in_data.size =
+        std::min(data_size - processed, sizeof(in_data.buffer));
+    std::memcpy(in_data.buffer, &data_in[processed], in_data.size);
+    TPM2B_IV* init_vector_out = nullptr;
+    TPM2B_MAX_BUFFER* out_data = nullptr;
+    auto rc = Esys_EncryptDecrypt2(
+        esys,
+        key_handle,
+        auth.auth1(),
+        auth.auth2(),
+        auth.auth3(),
+        &in_data,
+        decrypt ? TPM2_YES : TPM2_NO,
+        TPM2_ALG_NULL,
+        init_vector_in,
+        &out_data,
+        &init_vector_out);
+    if (rc != TPM2_RC_SUCCESS) {
+      LOG(ERROR) << "Esys_EncryptDecrypt2 failed: " << Tss2_RC_Decode(rc)
+                 << "(" << rc << ")";
+      Esys_Free(init_vector_in);
+      return false;
+    }
+    CHECK(init_vector_out != nullptr) << "init_vector_out was NULL";
+    CHECK(out_data != nullptr) << "out_data was NULL";
+    CHECK(out_data->size == in_data.size) << "data size mismatch";
+    std::memcpy(&data_out[processed], out_data->buffer, out_data->size);
+    Esys_Free(out_data);
+    Esys_Free(init_vector_in);
+    init_vector_in = init_vector_out;
+    processed += in_data.size;
+  }
+  Esys_Free(init_vector_in);
+  return true;
+}
+
+bool TpmEncrypt(
+    ESYS_CONTEXT* esys,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    uint8_t* data_in,
+    uint8_t* data_out,
+    size_t data_size) {
+  return TpmEncryptDecrypt(
+      esys, key_handle, auth, data_in, data_out, data_size, false);
+}
+
+bool TpmDecrypt(
+    ESYS_CONTEXT* esys,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    uint8_t* data_in,
+    uint8_t* data_out,
+    size_t data_size) {
+  return TpmEncryptDecrypt(
+      esys, key_handle, auth, data_in, data_out, data_size, true);
+}
diff --git a/host/commands/secure_env/tpm_encrypt_decrypt.h b/host/commands/secure_env/tpm_encrypt_decrypt.h
new file mode 100644
index 0000000..b75bafb
--- /dev/null
+++ b/host/commands/secure_env/tpm_encrypt_decrypt.h
@@ -0,0 +1,50 @@
+//
+// 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 <keymaster/android_keymaster_utils.h>
+#include <tss2/tss2_esys.h>
+
+#include "host/commands/secure_env/tpm_auth.h"
+
+/**
+ * Encrypt `data_in` to `data_out`, which are both buffers of size `data_size`.
+ *
+ * There are no integrity guarantees on this data: if the encrypted data is
+ * corrupted, decrypting it could either fail or produce corrupted output.
+ */
+bool TpmEncrypt(
+    ESYS_CONTEXT* esys,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    uint8_t* data_in,
+    uint8_t* data_out,
+    size_t data_size);
+
+
+/**
+ * Decrypt `data_in` to `data_out`, which are both buffers of size `data_size`.
+ *
+ * There are no integrity guarantees on this data: if the encrypted data is
+ * corrupted, decrypting it could either fail or produce corrupted output.
+ */
+bool TpmDecrypt(
+    ESYS_CONTEXT* esys,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    uint8_t* data_in,
+    uint8_t* data_out,
+    size_t data_size);
diff --git a/host/commands/secure_env/tpm_gatekeeper.cpp b/host/commands/secure_env/tpm_gatekeeper.cpp
new file mode 100644
index 0000000..e4f61e7
--- /dev/null
+++ b/host/commands/secure_env/tpm_gatekeeper.cpp
@@ -0,0 +1,242 @@
+//
+// 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.
+
+#include "tpm_gatekeeper.h"
+
+#include <algorithm>
+#include <optional>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <tss2/tss2_esys.h>
+#include <tss2/tss2_mu.h>
+#include <tss2/tss2_rc.h>
+
+#include "host/commands/secure_env/primary_key_builder.h"
+#include "host/commands/secure_env/tpm_auth.h"
+#include "host/commands/secure_env/tpm_hmac.h"
+#include "host/commands/secure_env/tpm_random_source.h"
+
+TpmGatekeeper::TpmGatekeeper(
+    TpmResourceManager& resource_manager,
+    GatekeeperStorage& secure_storage,
+    GatekeeperStorage& insecure_storage)
+    : resource_manager_(resource_manager)
+    , secure_storage_(secure_storage)
+    , insecure_storage_(insecure_storage) {
+}
+
+/*
+ * The reinterpret_cast and kPasswordUnique data is combined together with TPM
+ * internal state to create the actual key used for Gatekeeper operations.
+ */
+
+bool TpmGatekeeper::GetAuthTokenKey(
+    const uint8_t** auth_token_key, uint32_t* length) const {
+  static constexpr char kAuthTokenUnique[] = "TpmGatekeeper auth token key";
+  *auth_token_key = reinterpret_cast<const uint8_t*>(kAuthTokenUnique);
+  *length = sizeof(kAuthTokenUnique);
+  return true;
+}
+
+void TpmGatekeeper::GetPasswordKey(
+    const uint8_t** password_key, uint32_t* length) {
+  static constexpr char kPasswordUnique[] = "TpmGatekeeper password key";
+  *password_key = reinterpret_cast<const uint8_t*>(kPasswordUnique);
+  *length = sizeof(kPasswordUnique);
+}
+
+void TpmGatekeeper::ComputePasswordSignature(
+    uint8_t* signature,
+    uint32_t signature_length,
+    const uint8_t* key,
+    uint32_t key_length,
+    const uint8_t* password,
+    uint32_t password_length,
+    gatekeeper::salt_t salt) const {
+  std::vector<uint8_t> message(password_length + sizeof(salt));
+  memcpy(message.data(), password, password_length);
+  memcpy(message.data() + password_length, &salt, sizeof(salt));
+  return ComputeSignature(
+      signature,
+      signature_length,
+      key,
+      key_length,
+      message.data(),
+      message.size());
+}
+
+void TpmGatekeeper::GetRandom(void* random, uint32_t requested_size) const {
+  auto random_uint8 = reinterpret_cast<uint8_t*>(random);
+  TpmRandomSource(resource_manager_.Esys())
+      .GenerateRandom(random_uint8, requested_size);
+}
+
+void TpmGatekeeper::ComputeSignature(
+    uint8_t* signature,
+    uint32_t signature_length,
+    const uint8_t* key,
+    uint32_t key_length,
+    const uint8_t* message,
+    uint32_t length) const {
+  memset(signature, 0, signature_length);
+  std::string key_unique(reinterpret_cast<const char*>(key), key_length);
+  PrimaryKeyBuilder key_builder;
+  key_builder.UniqueData(key_unique);
+  key_builder.SigningKey();
+  auto key_slot = key_builder.CreateKey(resource_manager_);
+  if (!key_slot) {
+    LOG(ERROR) << "Unable to load signing key into TPM memory";
+    return;
+  }
+  auto calculated_signature =
+      TpmHmac(
+          resource_manager_,
+          key_slot->get(),
+          TpmAuth(ESYS_TR_PASSWORD),
+          message,
+          length);
+  if (!calculated_signature) {
+    LOG(ERROR) << "Failure in calculating signature";
+    return;
+  }
+  memcpy(
+      signature,
+      calculated_signature->buffer,
+      std::min((int) calculated_signature->size, (int) signature_length));
+}
+
+uint64_t TpmGatekeeper::GetMillisecondsSinceBoot() const {
+  struct timespec time;
+  int res = clock_gettime(CLOCK_BOOTTIME, &time);
+  if (res < 0) return 0;
+  return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
+}
+
+gatekeeper::failure_record_t DefaultRecord(
+    gatekeeper::secure_id_t secure_user_id) {
+  return (gatekeeper::failure_record_t) {
+    .secure_user_id = secure_user_id,
+    .last_checked_timestamp = 0,
+    .failure_counter = 0,
+  };
+}
+
+static std::unique_ptr<TPM2B_MAX_NV_BUFFER> RecordToNvBuffer(
+    const gatekeeper::failure_record_t& record) {
+  auto ret = std::make_unique<TPM2B_MAX_NV_BUFFER>();
+  static_assert(sizeof(ret->buffer) >= sizeof(record));
+  ret->size = sizeof(record);
+  std::memcpy(ret->buffer, &record, sizeof(record));
+  return ret;
+}
+
+static std::optional<gatekeeper::failure_record_t> NvBufferToRecord(
+    const TPM2B_MAX_NV_BUFFER& buffer) {
+  gatekeeper::failure_record_t ret;
+  if (buffer.size != sizeof(ret)) {
+    LOG(ERROR) << "NV Buffer had an incorrect size.";
+    return {};
+  }
+  memcpy(&ret, buffer.buffer, sizeof(ret));
+  return ret;
+}
+
+static bool GetFailureRecordImpl(
+    GatekeeperStorage& storage,
+    uint32_t uid,
+    gatekeeper::secure_id_t secure_user_id,
+    gatekeeper::failure_record_t *record) {
+  Json::Value key{std::to_string(uid)}; // jsoncpp integer comparisons are janky
+  if (!storage.HasKey(key)) {
+    if (!storage.Allocate(key, sizeof(gatekeeper::failure_record_t))) {
+      LOG(ERROR) << "Allocation failed for user " << uid;
+      return false;
+    }
+    auto buf = RecordToNvBuffer(DefaultRecord(secure_user_id));
+    if (!storage.Write(key, *buf)) {
+      LOG(ERROR) << "Failed to write record for " << uid;
+      return false;
+    }
+  }
+  auto record_read = storage.Read(key);
+  if (!record_read) {
+    LOG(ERROR) << "Failed to read record for " << uid;
+    return false;
+  }
+  auto record_decoded = NvBufferToRecord(*record_read);
+  if (!record_decoded) {
+    LOG(ERROR) << "Failed to deserialize record for " << uid;
+    return false;
+  }
+  if (record_decoded->secure_user_id == secure_user_id) {
+    *record = *record_decoded;
+    return true;
+  }
+  LOG(DEBUG) << "User id mismatch for " << uid;
+  auto buf = RecordToNvBuffer(DefaultRecord(secure_user_id));
+  if (!storage.Write(key, *buf)) {
+    LOG(ERROR) << "Failed to write record for " << uid;
+    return false;
+  }
+  *record = DefaultRecord(secure_user_id);
+  return true;
+}
+
+bool TpmGatekeeper::GetFailureRecord(
+    uint32_t uid,
+    gatekeeper::secure_id_t secure_user_id,
+    gatekeeper::failure_record_t *record,
+    bool secure) {
+  GatekeeperStorage& storage = secure ? secure_storage_ : insecure_storage_;
+  return GetFailureRecordImpl(storage, uid, secure_user_id, record);
+}
+
+static bool WriteFailureRecordImpl(
+    GatekeeperStorage& storage,
+    uint32_t uid,
+    gatekeeper::failure_record_t* record) {
+  Json::Value key{std::to_string(uid)}; // jsoncpp integer comparisons are janky
+  if (!storage.HasKey(key)) {
+    if (!storage.Allocate(key, sizeof(gatekeeper::failure_record_t))) {
+      LOG(ERROR) << "Allocation failed for user " << uid;
+      return false;
+    }
+  }
+  auto buf = RecordToNvBuffer(*record);
+  if (!storage.Write(key, *buf)) {
+    LOG(ERROR) << "Failed to write record for " << uid;
+    return false;
+  }
+  return true;
+}
+
+bool TpmGatekeeper::ClearFailureRecord(
+    uint32_t uid, gatekeeper::secure_id_t secure_user_id, bool secure) {
+  GatekeeperStorage& storage = secure ? secure_storage_ : insecure_storage_;
+  gatekeeper::failure_record_t record = DefaultRecord(secure_user_id);
+  return WriteFailureRecordImpl(storage, uid, &record);
+}
+
+bool TpmGatekeeper::WriteFailureRecord(
+    uint32_t uid, gatekeeper::failure_record_t *record, bool secure) {
+  GatekeeperStorage& storage = secure ? secure_storage_ : insecure_storage_;
+  return WriteFailureRecordImpl(storage, uid, record);
+}
+
+bool TpmGatekeeper::IsHardwareBacked() const {
+  return true;
+}
+
diff --git a/host/commands/secure_env/tpm_gatekeeper.h b/host/commands/secure_env/tpm_gatekeeper.h
new file mode 100644
index 0000000..021ab58
--- /dev/null
+++ b/host/commands/secure_env/tpm_gatekeeper.h
@@ -0,0 +1,83 @@
+//
+// 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 "gatekeeper/gatekeeper.h"
+#include "tss2/tss2_esys.h"
+
+#include "host/commands/secure_env/gatekeeper_storage.h"
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/**
+ * See method descriptions for this class in
+ * system/gatekeeper/include/gatekeeper/gatekeeper.h
+ */
+class TpmGatekeeper : public gatekeeper::GateKeeper {
+public:
+  TpmGatekeeper(
+      TpmResourceManager& resource_manager,
+      GatekeeperStorage& secure_storage,
+      GatekeeperStorage& insecure_storage);
+
+  bool GetAuthTokenKey(
+      const uint8_t** auth_token_key, uint32_t* length) const override;
+
+  void GetPasswordKey(const uint8_t** pasword_key, uint32_t* length) override;
+
+  void ComputePasswordSignature(
+      uint8_t* signature,
+      uint32_t signature_length,
+      const uint8_t* key,
+      uint32_t key_length,
+      const uint8_t* password,
+      uint32_t password_length,
+      gatekeeper::salt_t salt) const override;
+
+  void GetRandom(void* random, uint32_t requested_size) const override;
+
+  void ComputeSignature(
+      uint8_t* signature,
+      uint32_t signature_length,
+      const uint8_t* key,
+      uint32_t key_length,
+      const uint8_t* message,
+      uint32_t length) const override;
+
+  uint64_t GetMillisecondsSinceBoot() const override;
+
+  /**
+   * Retrieves the failure record for user `uid`, assuming a user secret value
+   * of `user_id`. If the secret value `user_id` is incorrect, the original
+   * secret `user_id` value will be lost and cannot be recovered.
+   */
+  bool GetFailureRecord(
+      uint32_t uid,
+      gatekeeper::secure_id_t user_id,
+      gatekeeper::failure_record_t *record,
+      bool secure) override;
+
+  bool ClearFailureRecord(
+      uint32_t uid, gatekeeper::secure_id_t user_id, bool secure) override;
+
+  bool WriteFailureRecord(
+      uint32_t uid, gatekeeper::failure_record_t *record, bool secure) override;
+
+  bool IsHardwareBacked() const override;
+private:
+  TpmResourceManager& resource_manager_;
+  GatekeeperStorage& secure_storage_;
+  GatekeeperStorage& insecure_storage_;
+};
diff --git a/host/commands/secure_env/tpm_hmac.cpp b/host/commands/secure_env/tpm_hmac.cpp
new file mode 100644
index 0000000..80003d0
--- /dev/null
+++ b/host/commands/secure_env/tpm_hmac.cpp
@@ -0,0 +1,155 @@
+//
+// 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.
+
+#include "tpm_hmac.h"
+
+#include <android-base/logging.h>
+#include <tss2/tss2_rc.h>
+
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/* For data large enough to fit in a single TPM2_HMAC call. */
+static UniqueEsysPtr<TPM2B_DIGEST> OneshotHmac(
+    TpmResourceManager& resource_manager,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    const uint8_t* data,
+    size_t data_size) {
+  if (data_size  > TPM2_MAX_DIGEST_BUFFER) {
+    LOG(ERROR) << "Logic error: OneshotSign called with data_size "
+               << data_size << " (> " << TPM2_MAX_DIGEST_BUFFER << ")";
+    return {};
+  }
+  TPM2B_MAX_BUFFER buffer;
+  static_assert(sizeof(buffer.buffer) >= TPM2_MAX_DIGEST_BUFFER);
+  buffer.size = data_size;
+  memcpy(buffer.buffer, data, data_size);
+  TPM2B_DIGEST* out_hmac = nullptr;
+  auto rc = Esys_HMAC(
+      resource_manager.Esys(),
+      key_handle,
+      auth.auth1(),
+      auth.auth2(),
+      auth.auth3(),
+      &buffer,
+      TPM2_ALG_NULL,
+      &out_hmac);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "TPM2_HMAC failed: " << Tss2_RC_Decode(rc) << "(" << rc << ")";
+    return {};
+  }
+  if (out_hmac == nullptr) {
+    LOG(ERROR) << "out_hmac unset";
+    return {};
+  }
+  return UniqueEsysPtr<TPM2B_DIGEST>(out_hmac);
+}
+
+/* For data too large to fit in a single TPM2_HMAC call. */
+static UniqueEsysPtr<TPM2B_DIGEST> SegmentedHmac(
+    TpmResourceManager& resource_manager,
+    ESYS_TR key_handle,
+    TpmAuth key_auth,
+    const uint8_t* data,
+    size_t data_size) {
+  // TODO(schuffelen): Pipeline commands where possible.
+  TPM2B_AUTH sequence_auth;
+  sequence_auth.size = sizeof(rand());
+  *reinterpret_cast<decltype(rand())*>(sequence_auth.buffer) = rand();
+  ESYS_TR sequence_handle;
+  auto slot = resource_manager.ReserveSlot();
+  if (!slot) {
+    LOG(ERROR) << "No slots available";
+    return {};
+  }
+  auto rc = Esys_HMAC_Start(
+      resource_manager.Esys(),
+      key_handle,
+      key_auth.auth1(),
+      key_auth.auth2(),
+      key_auth.auth3(),
+      &sequence_auth,
+      TPM2_ALG_NULL,
+      &sequence_handle);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "TPM2_HMAC_Start failed: " << Tss2_RC_Decode(rc)
+               << "(" << rc << ")";
+    return {};
+  }
+  slot->set(sequence_handle);
+  rc = Esys_TR_SetAuth(
+      resource_manager.Esys(), sequence_handle, &sequence_auth);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_TR_SetAuth failed: " << Tss2_RC_Decode(rc)
+               << "(" << rc << ")";
+    return {};
+  }
+  auto hashed = 0;
+  TPM2B_MAX_BUFFER buffer;
+  while (data_size - hashed > TPM2_MAX_DIGEST_BUFFER) {
+    buffer.size = TPM2_MAX_DIGEST_BUFFER;
+    memcpy(buffer.buffer, &data[hashed], TPM2_MAX_DIGEST_BUFFER);
+    hashed += TPM2_MAX_DIGEST_BUFFER;
+    rc = Esys_SequenceUpdate(
+        resource_manager.Esys(),
+        sequence_handle,
+        ESYS_TR_PASSWORD,
+        ESYS_TR_NONE,
+        ESYS_TR_NONE,
+        &buffer);
+    if (rc != TPM2_RC_SUCCESS) {
+      LOG(ERROR) << "Esys_SequenceUpdate failed: " << Tss2_RC_Decode(rc)
+                << "(" << rc << ")";
+      return {};
+    }
+  }
+  buffer.size = data_size - hashed;
+  memcpy(buffer.buffer, &data[hashed], buffer.size);
+  TPM2B_DIGEST* out_hmac = nullptr;
+  TPMT_TK_HASHCHECK* validation = nullptr;
+  rc = Esys_SequenceComplete(
+      resource_manager.Esys(),
+      sequence_handle,
+      ESYS_TR_PASSWORD,
+      ESYS_TR_NONE,
+      ESYS_TR_NONE,
+      &buffer,
+      TPM2_RH_OWNER,
+      &out_hmac,
+      &validation);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_SequenceComplete failed: " << Tss2_RC_Decode(rc)
+               << "(" << rc << ")";
+    return {};
+  }
+  // TPM2_SequenceComplete already flushes the sequence context on success.
+  slot->set(ESYS_TR_NONE);
+  if (out_hmac == nullptr) {
+    LOG(ERROR) << "out_hmac was null";
+    return {};
+  }
+  Esys_Free(validation);
+  return UniqueEsysPtr<TPM2B_DIGEST>(out_hmac);
+}
+
+UniqueEsysPtr<TPM2B_DIGEST> TpmHmac(
+    TpmResourceManager& resource_manager,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    const uint8_t* data,
+    size_t data_size) {
+  auto fn = data_size > TPM2_MAX_DIGEST_BUFFER ? SegmentedHmac : OneshotHmac;
+  return fn(resource_manager, key_handle, auth, data, data_size);
+}
diff --git a/host/commands/secure_env/tpm_hmac.h b/host/commands/secure_env/tpm_hmac.h
new file mode 100644
index 0000000..e4686b6
--- /dev/null
+++ b/host/commands/secure_env/tpm_hmac.h
@@ -0,0 +1,51 @@
+//
+// 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 <memory>
+
+#include <tss2/tss2_esys.h>
+
+#include "host/commands/secure_env/tpm_auth.h"
+
+class TpmResourceManager;
+
+struct EsysDeleter {
+  void operator()(void* data) { Esys_Free(data); }
+};
+
+template<typename T>
+using UniqueEsysPtr = std::unique_ptr<T, EsysDeleter>;
+
+/**
+ * Returns a HMAC signature for `data` with the key loaded into the TPM at
+ * `key_handle`.
+ *
+ * The signature is a byte string that certifies a process that can make TPM
+ * API calls has signed off on using another byte string (`data`) for some
+ * purpose, which is implicitly tied to the signing key. In this case, the
+ * secure_env process is the only process that should have TPM access.
+ * secure_env can then transmit some data together with a signature over that
+ * data, an external system (Android) can hold onto this data and the signature,
+ * and then the secure_env process can receive the data back. The signature
+ * is used to check that the data has not been tampered with.
+ */
+UniqueEsysPtr<TPM2B_DIGEST> TpmHmac(
+    TpmResourceManager& resource_manager,
+    ESYS_TR key_handle,
+    TpmAuth auth,
+    const uint8_t* data,
+    size_t data_size);
diff --git a/host/commands/secure_env/tpm_key_blob_maker.cpp b/host/commands/secure_env/tpm_key_blob_maker.cpp
new file mode 100644
index 0000000..64f344a
--- /dev/null
+++ b/host/commands/secure_env/tpm_key_blob_maker.cpp
@@ -0,0 +1,192 @@
+//
+// 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.
+
+#include "tpm_key_blob_maker.h"
+
+#include <vector>
+
+#include <android-base/logging.h>
+#include <tss2/tss2_mu.h>
+#include <tss2/tss2_rc.h>
+
+#include "host/commands/secure_env/composite_serialization.h"
+#include "host/commands/secure_env/encrypted_serializable.h"
+#include "host/commands/secure_env/hmac_serializable.h"
+#include "host/commands/secure_env/primary_key_builder.h"
+
+using keymaster::AuthorizationSet;
+using keymaster::KeymasterKeyBlob;
+using keymaster::Serializable;
+
+static constexpr char kUniqueKey[] = "TpmKeyBlobMaker";
+
+/**
+ * Distinguish what properties the secure_env implementation handles. If
+ * secure_env handles it, the property is put in `hw_enforced`. Otherwise, the
+ * property is put in `sw_enforced`, and the Keystore process inside Android
+ * will try to enforce the property.
+ */
+static keymaster_error_t SplitEnforcedProperties(
+    const keymaster::AuthorizationSet& key_description,
+    keymaster::AuthorizationSet* hw_enforced,
+    keymaster::AuthorizationSet* sw_enforced) {
+  for (auto& entry : key_description) {
+    switch (entry.tag) {
+      case KM_TAG_PURPOSE:
+      case KM_TAG_ALGORITHM:
+      case KM_TAG_KEY_SIZE:
+      case KM_TAG_RSA_PUBLIC_EXPONENT:
+      case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+      case KM_TAG_DIGEST:
+      case KM_TAG_PADDING:
+      case KM_TAG_BLOCK_MODE:
+      case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+      case KM_TAG_MAX_USES_PER_BOOT:
+      case KM_TAG_USER_SECURE_ID:
+      case KM_TAG_NO_AUTH_REQUIRED:
+      case KM_TAG_AUTH_TIMEOUT:
+      case KM_TAG_CALLER_NONCE:
+      case KM_TAG_MIN_MAC_LENGTH:
+      case KM_TAG_KDF:
+      case KM_TAG_EC_CURVE:
+      case KM_TAG_ECIES_SINGLE_HASH_MODE:
+      case KM_TAG_USER_AUTH_TYPE:
+      case KM_TAG_ORIGIN:
+      case KM_TAG_OS_VERSION:
+      case KM_TAG_OS_PATCHLEVEL:
+      case KM_TAG_EARLY_BOOT_ONLY:
+      case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+        hw_enforced->push_back(entry);
+        break;
+      default:
+        sw_enforced->push_back(entry);
+    }
+  }
+  return KM_ERROR_OK;
+}
+
+static KeymasterKeyBlob SerializableToKeyBlob(
+    const Serializable& serializable) {
+  std::vector<uint8_t> data(serializable.SerializedSize() + 1);
+  uint8_t* buf = data.data();
+  uint8_t* buf_end = buf + data.size();
+  buf = serializable.Serialize(buf, buf_end);
+  if (buf != (buf_end - 1)) {
+    LOG(ERROR) << "Serialized size did not match up with actual usage.";
+    return {};
+  }
+  return KeymasterKeyBlob(data.data(), buf - data.data());
+}
+
+
+TpmKeyBlobMaker::TpmKeyBlobMaker(TpmResourceManager& resource_manager)
+    : resource_manager_(resource_manager) {
+}
+
+keymaster_error_t TpmKeyBlobMaker::CreateKeyBlob(
+    const AuthorizationSet& key_description,
+    keymaster_key_origin_t origin,
+    const KeymasterKeyBlob& key_material,
+    KeymasterKeyBlob* blob,
+    AuthorizationSet* hw_enforced,
+    AuthorizationSet* sw_enforced) const {
+  std::set<keymaster_tag_t> protected_tags = {
+    KM_TAG_ROOT_OF_TRUST,
+    KM_TAG_ORIGIN,
+    KM_TAG_OS_VERSION,
+    KM_TAG_OS_PATCHLEVEL,
+  };
+  for (auto tag : protected_tags) {
+    if (key_description.Contains(tag)) {
+      LOG(ERROR) << "Invalid tag " << tag;
+      return KM_ERROR_INVALID_TAG;
+    }
+  }
+  auto rc =
+      SplitEnforcedProperties(key_description, hw_enforced, sw_enforced);
+  if (rc != KM_ERROR_OK) {
+    return rc;
+  }
+  hw_enforced->push_back(keymaster::TAG_ORIGIN, origin);
+
+  // TODO(schuffelen): Set the os level and patch level properly.
+  hw_enforced->push_back(keymaster::TAG_OS_VERSION, os_version_);
+  hw_enforced->push_back(keymaster::TAG_OS_PATCHLEVEL, os_patchlevel_);
+
+  return UnvalidatedCreateKeyBlob(key_material, *hw_enforced, *sw_enforced,
+                                  blob);
+}
+
+keymaster_error_t TpmKeyBlobMaker::UnvalidatedCreateKeyBlob(
+    const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+    const AuthorizationSet& sw_enforced, KeymasterKeyBlob* blob) const {
+  keymaster::Buffer key_material_buffer(
+      key_material.key_material, key_material.key_material_size);
+  AuthorizationSet hw_enforced_mutable = hw_enforced;
+  AuthorizationSet sw_enforced_mutable = sw_enforced;
+  CompositeSerializable sensitive_material(
+      {&key_material_buffer, &hw_enforced_mutable, &sw_enforced_mutable});
+  auto parent_key_fn = ParentKeyCreator(kUniqueKey);
+  EncryptedSerializable encryption(
+      resource_manager_, parent_key_fn, sensitive_material);
+  auto signing_key_fn = SigningKeyCreator(kUniqueKey);
+  HmacSerializable sign_check(
+      resource_manager_, signing_key_fn, TPM2_SHA256_DIGEST_SIZE, &encryption);
+  auto generated_blob = SerializableToKeyBlob(sign_check);
+  LOG(VERBOSE) << "Keymaster key size: " << generated_blob.key_material_size;
+  if (generated_blob.key_material_size != 0) {
+    *blob = generated_blob;
+    return KM_ERROR_OK;
+  }
+  LOG(ERROR) << "Failed to serialize key.";
+  return KM_ERROR_UNKNOWN_ERROR;
+}
+
+keymaster_error_t TpmKeyBlobMaker::UnwrapKeyBlob(
+    const keymaster_key_blob_t& blob,
+    AuthorizationSet* hw_enforced,
+    AuthorizationSet* sw_enforced,
+    KeymasterKeyBlob* key_material) const {
+  keymaster::Buffer key_material_buffer(blob.key_material_size);
+  CompositeSerializable sensitive_material(
+      {&key_material_buffer, hw_enforced, sw_enforced});
+  auto parent_key_fn = ParentKeyCreator(kUniqueKey);
+  EncryptedSerializable encryption(
+      resource_manager_, parent_key_fn, sensitive_material);
+  auto signing_key_fn = SigningKeyCreator(kUniqueKey);
+  HmacSerializable sign_check(
+      resource_manager_, signing_key_fn, TPM2_SHA256_DIGEST_SIZE, &encryption);
+  auto buf = blob.key_material;
+  auto buf_end = buf + blob.key_material_size;
+  if (!sign_check.Deserialize(&buf, buf_end)) {
+    LOG(ERROR) << "Failed to deserialize key.";
+    return KM_ERROR_UNKNOWN_ERROR;
+  }
+  if (key_material_buffer.available_read() == 0) {
+    LOG(ERROR) << "Key material was corrupted and the size was too large";
+    return KM_ERROR_UNKNOWN_ERROR;
+  }
+  *key_material = KeymasterKeyBlob(
+      key_material_buffer.peek_read(), key_material_buffer.available_read());
+  return KM_ERROR_OK;
+}
+
+keymaster_error_t TpmKeyBlobMaker::SetSystemVersion(
+    uint32_t os_version, uint32_t os_patchlevel) {
+  // TODO(b/155697375): Only accept new values of these from the bootloader
+  os_version_ = os_version;
+  os_patchlevel_ = os_patchlevel;
+  return KM_ERROR_OK;
+}
diff --git a/host/commands/secure_env/tpm_key_blob_maker.h b/host/commands/secure_env/tpm_key_blob_maker.h
new file mode 100644
index 0000000..a0483b4
--- /dev/null
+++ b/host/commands/secure_env/tpm_key_blob_maker.h
@@ -0,0 +1,70 @@
+//
+// 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 <keymaster/soft_key_factory.h>
+
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/**
+ * Encrypts key data using a TPM-resident key and signs it with a TPM-resident
+ * key for privacy and integrity.
+ *
+ * This class is used to encrypt KeyMint data when it leaves the secure_env
+ * process, and is sent for storage to Android. When the data comes back, this
+ * class decrypts it again for use in Keymaster and other HAL API calls.
+ */
+class TpmKeyBlobMaker : public keymaster::SoftwareKeyBlobMaker {
+public:
+  TpmKeyBlobMaker(TpmResourceManager& resource_manager);
+
+  keymaster_error_t CreateKeyBlob(
+      const keymaster::AuthorizationSet& key_description,
+      keymaster_key_origin_t origin,
+      const keymaster::KeymasterKeyBlob& key_material,
+      keymaster::KeymasterKeyBlob* blob,
+      keymaster::AuthorizationSet* hw_enforced,
+      keymaster::AuthorizationSet* sw_enforced) const override;
+
+  keymaster_error_t UnvalidatedCreateKeyBlob(
+      const keymaster::KeymasterKeyBlob& key_material,
+      const keymaster::AuthorizationSet& hw_enforced,
+      const keymaster::AuthorizationSet& sw_enforced,
+      keymaster::KeymasterKeyBlob* blob) const;
+
+  /**
+   * Intermediate function between KeymasterContext::ParseKeyBlob and
+   * KeyFactory::LoadKey, The inputs of this function match the outputs of
+   * KeymasterContext::ParseKeyBlob and the outputs of this function match the
+   * inputs of KeyFactory::LoadKey.
+   *
+   * KeymasterContext::ParseKeyBlob is the common entry point for decoding all
+   * keys, and is expected to delegate to a KeyFactory depending on the type of
+   * the serialized key. This method performs decryption operations shared
+   * between all TPM-Keymaster keys.
+   */
+  keymaster_error_t UnwrapKeyBlob(
+      const keymaster_key_blob_t& blob,
+      keymaster::AuthorizationSet* hw_enforced,
+      keymaster::AuthorizationSet* sw_enforced,
+      keymaster::KeymasterKeyBlob* key_material) const;
+
+  keymaster_error_t SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel);
+private:
+  TpmResourceManager& resource_manager_;
+  uint32_t os_version_;
+  uint32_t os_patchlevel_;
+};
diff --git a/host/commands/secure_env/tpm_keymaster_context.cpp b/host/commands/secure_env/tpm_keymaster_context.cpp
new file mode 100644
index 0000000..850d48b
--- /dev/null
+++ b/host/commands/secure_env/tpm_keymaster_context.cpp
@@ -0,0 +1,321 @@
+//
+// 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.
+
+#include "tpm_keymaster_context.h"
+
+#include <android-base/logging.h>
+#include <keymaster/contexts/soft_attestation_cert.h>
+#include <keymaster/km_openssl/aes_key.h>
+#include <keymaster/km_openssl/asymmetric_key.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+#include <keymaster/km_openssl/certificate_utils.h>
+#include <keymaster/km_openssl/ec_key_factory.h>
+#include <keymaster/km_openssl/hmac_key.h>
+#include <keymaster/km_openssl/rsa_key_factory.h>
+#include <keymaster/km_openssl/soft_keymaster_enforcement.h>
+#include <keymaster/km_openssl/triple_des_key.h>
+
+#include "host/commands/secure_env/tpm_attestation_record.h"
+#include "host/commands/secure_env/tpm_random_source.h"
+#include "host/commands/secure_env/tpm_key_blob_maker.h"
+
+using keymaster::AuthorizationSet;
+using keymaster::KeymasterKeyBlob;
+using keymaster::KeyFactory;
+using keymaster::OperationFactory;
+
+TpmKeymasterContext::TpmKeymasterContext(
+    TpmResourceManager& resource_manager,
+    keymaster::KeymasterEnforcement& enforcement)
+    : resource_manager_(resource_manager)
+    , enforcement_(enforcement)
+    , key_blob_maker_(new TpmKeyBlobMaker(resource_manager_))
+    , random_source_(new TpmRandomSource(resource_manager_.Esys()))
+    , attestation_context_(new TpmAttestationRecordContext()) {
+  key_factories_.emplace(
+      KM_ALGORITHM_RSA, new keymaster::RsaKeyFactory(*key_blob_maker_, *this));
+  key_factories_.emplace(
+      KM_ALGORITHM_EC, new keymaster::EcKeyFactory(*key_blob_maker_, *this));
+  key_factories_.emplace(
+      KM_ALGORITHM_AES,
+      new keymaster::AesKeyFactory(*key_blob_maker_, *random_source_));
+  key_factories_.emplace(
+      KM_ALGORITHM_TRIPLE_DES,
+      new keymaster::TripleDesKeyFactory(*key_blob_maker_, *random_source_));
+  key_factories_.emplace(
+      KM_ALGORITHM_HMAC,
+      new keymaster::HmacKeyFactory(*key_blob_maker_, *random_source_));
+  for (const auto& it : key_factories_) {
+    supported_algorithms_.push_back(it.first);
+  }
+}
+
+keymaster_error_t TpmKeymasterContext::SetSystemVersion(
+    uint32_t os_version, uint32_t os_patchlevel) {
+  // TODO(b/155697375): Only accept new values of these from the bootloader
+  os_version_ = os_version;
+  os_patchlevel_ = os_patchlevel;
+  key_blob_maker_->SetSystemVersion(os_version, os_patchlevel);
+  return KM_ERROR_OK;
+}
+
+void TpmKeymasterContext::GetSystemVersion(
+    uint32_t* os_version, uint32_t* os_patchlevel) const {
+  *os_version = os_version_;
+  *os_patchlevel = os_patchlevel_;
+}
+
+const KeyFactory* TpmKeymasterContext::GetKeyFactory(
+    keymaster_algorithm_t algorithm) const {
+  auto it = key_factories_.find(algorithm);
+  if (it == key_factories_.end()) {
+    LOG(ERROR) << "Could not find key factory for " << algorithm;
+    return nullptr;
+  }
+  return it->second.get();
+}
+
+const OperationFactory* TpmKeymasterContext::GetOperationFactory(
+    keymaster_algorithm_t algorithm, keymaster_purpose_t purpose) const {
+  auto key_factory = GetKeyFactory(algorithm);
+  if (key_factory == nullptr) {
+    LOG(ERROR) << "Tried to get operation factory for " << purpose
+              << " for invalid algorithm " << algorithm;
+    return nullptr;
+  }
+  auto operation_factory = key_factory->GetOperationFactory(purpose);
+  if (operation_factory == nullptr) {
+    LOG(ERROR) << "Could not get operation factory for " << purpose
+               << " from key factory for " << algorithm;
+  }
+  return operation_factory;
+}
+
+const keymaster_algorithm_t* TpmKeymasterContext::GetSupportedAlgorithms(
+      size_t* algorithms_count) const {
+  *algorithms_count = supported_algorithms_.size();
+  return supported_algorithms_.data();
+}
+
+// Based on https://cs.android.com/android/platform/superproject/+/master:system/keymaster/key_blob_utils/software_keyblobs.cpp;l=44;drc=master
+
+static bool UpgradeIntegerTag(
+    keymaster_tag_t tag,
+    uint32_t value,
+    AuthorizationSet* set,
+    bool* set_changed) {
+  int index = set->find(tag);
+  if (index == -1) {
+    keymaster_key_param_t param;
+    param.tag = tag;
+    param.integer = value;
+    set->push_back(param);
+    *set_changed = true;
+    return true;
+  }
+
+  if (set->params[index].integer > value) {
+    return false;
+  }
+
+  if (set->params[index].integer != value) {
+    set->params[index].integer = value;
+    *set_changed = true;
+  }
+  return true;
+}
+
+// Based on https://cs.android.com/android/platform/superproject/+/master:system/keymaster/key_blob_utils/software_keyblobs.cpp;l=310;drc=master
+
+keymaster_error_t TpmKeymasterContext::UpgradeKeyBlob(
+    const KeymasterKeyBlob& blob_to_upgrade,
+    const AuthorizationSet& upgrade_params,
+    KeymasterKeyBlob* upgraded_key) const {
+  keymaster::UniquePtr<keymaster::Key> key;
+  auto error = ParseKeyBlob(blob_to_upgrade, upgrade_params, &key);
+  if (error != KM_ERROR_OK) {
+    LOG(ERROR) << "Failed to parse key blob";
+    return error;
+  }
+
+  bool set_changed = false;
+
+  if (os_version_ == 0) {
+    // We need to allow "upgrading" OS version to zero, to support upgrading
+    // from proper numbered releases to unnumbered development and preview
+    // releases.
+
+    int key_os_version_pos = key->hw_enforced().find(keymaster::TAG_OS_VERSION);
+    if (key_os_version_pos != -1) {
+      uint32_t key_os_version = key->hw_enforced()[key_os_version_pos].integer;
+      if (key_os_version != 0) {
+        key->hw_enforced()[key_os_version_pos].integer = os_version_;
+        set_changed = true;
+      }
+    }
+  }
+
+  auto update_os = UpgradeIntegerTag(keymaster::TAG_OS_VERSION, os_version_,
+                                     &key->hw_enforced(), &set_changed);
+
+  auto update_patchlevel =
+      UpgradeIntegerTag(keymaster::TAG_OS_PATCHLEVEL, os_patchlevel_,
+                        &key->hw_enforced(), &set_changed);
+
+  if (!update_os || !update_patchlevel) {
+    LOG(ERROR) << "One of the version fields would have been a downgrade. "
+               << "Not allowed.";
+    return KM_ERROR_INVALID_ARGUMENT;
+  }
+
+  if (!set_changed) {
+    // Don't need an upgrade.
+    return KM_ERROR_OK;
+  }
+
+  return key_blob_maker_->UnvalidatedCreateKeyBlob(
+      key->key_material(), key->hw_enforced(), key->sw_enforced(),
+      upgraded_key);
+}
+
+keymaster_error_t TpmKeymasterContext::ParseKeyBlob(
+    const KeymasterKeyBlob& blob,
+    const AuthorizationSet& additional_params,
+    keymaster::UniquePtr<keymaster::Key>* key) const {
+  keymaster::AuthorizationSet hw_enforced;
+  keymaster::AuthorizationSet sw_enforced;
+  keymaster::KeymasterKeyBlob key_material;
+
+  auto rc =
+      key_blob_maker_->UnwrapKeyBlob(
+          blob,
+          &hw_enforced,
+          &sw_enforced,
+          &key_material);
+  if (rc != KM_ERROR_OK) {
+    LOG(ERROR) << "Failed to unwrap key: " << rc;
+    return rc;
+  }
+
+  keymaster_algorithm_t algorithm;
+  if (!hw_enforced.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm) &&
+      !sw_enforced.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm)) {
+    LOG(ERROR) << "No TAG_ALGORITHM value in hw_enforced or sw_enforced.";
+    return KM_ERROR_UNKNOWN_ERROR;
+  }
+
+  auto factory = GetKeyFactory(algorithm);
+  if (factory == nullptr) {
+    LOG(ERROR) << "Unable to find key factory for " << algorithm;
+    return KM_ERROR_UNSUPPORTED_ALGORITHM;
+  }
+  rc =
+      factory->LoadKey(
+          std::move(key_material),
+          additional_params,
+          std::move(hw_enforced),
+          std::move(sw_enforced),
+          key);
+  if (rc != KM_ERROR_OK) {
+    LOG(ERROR) << "Unable to load unwrapped key: " << rc;
+  }
+  return rc;
+}
+
+keymaster_error_t TpmKeymasterContext::AddRngEntropy(
+    const uint8_t* buffer, size_t size) const {
+  return random_source_->AddRngEntropy(buffer, size);
+}
+
+keymaster::KeymasterEnforcement* TpmKeymasterContext::enforcement_policy() {
+  return &enforcement_;
+}
+
+// Based on https://cs.android.com/android/platform/superproject/+/master:system/keymaster/contexts/pure_soft_keymaster_context.cpp;l=261;drc=8367d5351c4d417a11f49b12394b63a413faa02d
+
+keymaster::CertificateChain TpmKeymasterContext::GenerateAttestation(
+    const keymaster::Key& key, const keymaster::AuthorizationSet& attest_params,
+    keymaster::UniquePtr<keymaster::Key> /* attest_key */,
+    const keymaster::KeymasterBlob& /* issuer_subject */,
+    keymaster_error_t* error) const {
+  LOG(INFO) << "TODO(b/155697200): Link attestation back to the TPM";
+  keymaster_algorithm_t key_algorithm;
+  if (!key.authorizations().GetTagValue(keymaster::TAG_ALGORITHM,
+                                        &key_algorithm)) {
+    *error = KM_ERROR_UNKNOWN_ERROR;
+    return {};
+  }
+
+  if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
+    *error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
+    return {};
+  }
+
+  // We have established that the given key has the correct algorithm, and
+  // because this is the TpmKeymasterContext we can assume that the Key is an
+  // AsymmetricKey. So we can downcast.
+  const keymaster::AsymmetricKey& asymmetric_key =
+      static_cast<const keymaster::AsymmetricKey&>(key);
+
+  // DEVICE_UNIQUE_ATTESTATION is only allowed for strongbox devices. See
+  // hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl:845
+  // at commit beefae4790ccd4f1ee75ea69603d4c9c2a45c0aa .
+  // While the specification says to return ErrorCode::INVALID_ARGUMENT , the
+  // relevant VTS test actually tests for ErrorCode::UNIMPLEMENTED . See
+  // hardware/interfaces/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp:203
+  // at commit 36dcf1a404a9cf07ca5a2a6ad92371507194fe1b .
+  if (attest_params.find(keymaster::TAG_DEVICE_UNIQUE_ATTESTATION) != -1) {
+    *error = KM_ERROR_UNIMPLEMENTED;
+    return {};
+  }
+
+  return keymaster::generate_attestation(asymmetric_key, attest_params,
+                                         {} /* attest_key */,
+                                         *attestation_context_, error);
+}
+
+keymaster::CertificateChain TpmKeymasterContext::GenerateSelfSignedCertificate(
+    const keymaster::Key& key, const keymaster::AuthorizationSet& cert_params,
+    bool fake_signature, keymaster_error_t* error) const {
+  keymaster_algorithm_t key_algorithm;
+  if (!key.authorizations().GetTagValue(keymaster::TAG_ALGORITHM, &key_algorithm)) {
+      *error = KM_ERROR_UNKNOWN_ERROR;
+      return {};
+  }
+
+  if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
+      *error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
+      return {};
+  }
+
+  // We have established that the given key has the correct algorithm, and because this is the
+  // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast.
+  const keymaster::AsymmetricKey& asymmetric_key =
+      static_cast<const keymaster::AsymmetricKey&>(key);
+
+  return generate_self_signed_cert(asymmetric_key, cert_params, fake_signature, error);
+}
+
+keymaster_error_t TpmKeymasterContext::UnwrapKey(
+    const KeymasterKeyBlob&,
+    const KeymasterKeyBlob&,
+    const AuthorizationSet&,
+    const KeymasterKeyBlob&,
+    AuthorizationSet*,
+    keymaster_key_format_t*,
+    KeymasterKeyBlob*) const {
+  LOG(ERROR) << "TODO(b/155697375): Implement UnwrapKey";
+  return KM_ERROR_UNIMPLEMENTED;
+}
diff --git a/host/commands/secure_env/tpm_keymaster_context.h b/host/commands/secure_env/tpm_keymaster_context.h
new file mode 100644
index 0000000..54ba973
--- /dev/null
+++ b/host/commands/secure_env/tpm_keymaster_context.h
@@ -0,0 +1,105 @@
+//
+// 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 <map>
+#include <vector>
+
+#include <keymaster/keymaster_context.h>
+#include <keymaster/km_openssl/attestation_record.h>
+
+#include "tpm_attestation_record.h"
+
+class TpmAttestationRecordContext;
+class TpmResourceManager;
+class TpmKeyBlobMaker;
+class TpmRandomSource;
+
+/**
+ * Implementation of KeymasterContext that wraps its keys with a TPM.
+ *
+ * See the parent class for details:
+ * https://cs.android.com/android/platform/superproject/+/master:system/keymaster/include/keymaster/keymaster_context.h;drc=821acb74d7febb886a9b7cefee4ee3df4cc8c556
+ */
+class TpmKeymasterContext : public keymaster::KeymasterContext {
+private:
+  TpmResourceManager& resource_manager_;
+  keymaster::KeymasterEnforcement& enforcement_;
+  std::unique_ptr<TpmKeyBlobMaker> key_blob_maker_;
+  std::unique_ptr<TpmRandomSource> random_source_;
+  std::unique_ptr<TpmAttestationRecordContext> attestation_context_;
+  std::map<keymaster_algorithm_t, std::unique_ptr<keymaster::KeyFactory>> key_factories_;
+  std::vector<keymaster_algorithm_t> supported_algorithms_;
+  uint32_t os_version_;
+  uint32_t os_patchlevel_;
+public:
+  TpmKeymasterContext(TpmResourceManager&, keymaster::KeymasterEnforcement&);
+  ~TpmKeymasterContext() = default;
+
+  keymaster::KmVersion GetKmVersion() const override {
+    return attestation_context_->GetKmVersion();
+  }
+
+  keymaster_error_t SetSystemVersion(
+      uint32_t os_version, uint32_t os_patchlevel) override;
+  void GetSystemVersion(
+      uint32_t* os_version, uint32_t* os_patchlevel) const override;
+
+  const keymaster::KeyFactory* GetKeyFactory(
+      keymaster_algorithm_t algorithm) const override;
+  const keymaster::OperationFactory* GetOperationFactory(
+      keymaster_algorithm_t algorithm,
+      keymaster_purpose_t purpose) const override;
+  const keymaster_algorithm_t* GetSupportedAlgorithms(
+      size_t* algorithms_count) const override;
+
+  keymaster_error_t UpgradeKeyBlob(
+      const keymaster::KeymasterKeyBlob& key_to_upgrade,
+      const keymaster::AuthorizationSet& upgrade_params,
+      keymaster::KeymasterKeyBlob* upgraded_key) const override;
+
+  keymaster_error_t ParseKeyBlob(
+      const keymaster::KeymasterKeyBlob& blob,
+      const keymaster::AuthorizationSet& additional_params,
+      keymaster::UniquePtr<keymaster::Key>* key) const override;
+
+  keymaster_error_t AddRngEntropy(
+      const uint8_t* buf, size_t length) const override;
+
+  keymaster::KeymasterEnforcement* enforcement_policy() override;
+
+  keymaster::CertificateChain GenerateAttestation(
+      const keymaster::Key& key,
+      const keymaster::AuthorizationSet& attest_params,
+      keymaster::UniquePtr<keymaster::Key> attest_key,
+      const keymaster::KeymasterBlob& issuer_subject,
+      keymaster_error_t* error) const override;
+
+  keymaster::CertificateChain GenerateSelfSignedCertificate(
+      const keymaster::Key& key,
+      const keymaster::AuthorizationSet& cert_params,
+      bool fake_signature,
+      keymaster_error_t* error) const override;
+
+  keymaster_error_t UnwrapKey(
+      const keymaster::KeymasterKeyBlob& wrapped_key_blob,
+      const keymaster::KeymasterKeyBlob& wrapping_key_blob,
+      const keymaster::AuthorizationSet& wrapping_key_params,
+      const keymaster::KeymasterKeyBlob& masking_key,
+      keymaster::AuthorizationSet* wrapped_key_params,
+      keymaster_key_format_t* wrapped_key_format,
+      keymaster::KeymasterKeyBlob* wrapped_key_material) const override;
+};
diff --git a/host/commands/secure_env/tpm_keymaster_enforcement.cpp b/host/commands/secure_env/tpm_keymaster_enforcement.cpp
new file mode 100644
index 0000000..f5b8903
--- /dev/null
+++ b/host/commands/secure_env/tpm_keymaster_enforcement.cpp
@@ -0,0 +1,334 @@
+//
+// 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.
+
+#include "host/commands/secure_env/tpm_keymaster_enforcement.h"
+
+#include <android-base/logging.h>
+#if defined(__BIONIC__)
+#include <sys/endian.h> // for be64toh
+#endif
+
+#include "host/commands/secure_env/primary_key_builder.h"
+#include "host/commands/secure_env/tpm_hmac.h"
+#include "host/commands/secure_env/tpm_key_blob_maker.h"
+#include "host/commands/secure_env/tpm_random_source.h"
+
+using keymaster::km_id_t;
+using keymaster::HmacSharingParameters;
+using keymaster::HmacSharingParametersArray;
+using keymaster::KeymasterBlob;
+using keymaster::KeymasterEnforcement;
+using keymaster::VerifyAuthorizationRequest;
+using keymaster::VerifyAuthorizationResponse;
+namespace {
+inline bool operator==(const keymaster_blob_t& a, const keymaster_blob_t& b) {
+  if (!a.data_length && !b.data_length) return true;
+  if (!(a.data && b.data)) return a.data == b.data;
+  return (a.data_length == b.data_length &&
+          !memcmp(a.data, b.data, a.data_length));
+}
+
+bool operator==(const HmacSharingParameters& a,
+                const HmacSharingParameters& b) {
+  return a.seed == b.seed && !memcmp(a.nonce, b.nonce, sizeof(a.nonce));
+}
+}  // namespace
+class CompareHmacSharingParams {
+public:
+  bool operator()(
+      const HmacSharingParameters& a, const HmacSharingParameters& b) const {
+    if (a.seed.data_length != b.seed.data_length) {
+      return a.seed.data_length < b.seed.data_length;
+    }
+    auto res = memcmp(a.seed.data, b.seed.data, a.seed.data_length);
+    if (res != 0) {
+      return res < 0;
+    }
+    static_assert(sizeof(a.nonce) == sizeof(b.nonce));
+    return memcmp(a.nonce, b.nonce, sizeof(a.nonce)) < 0;
+  }
+};
+
+namespace {
+
+uint64_t timespec_to_ms(const struct timespec& tp) {
+  if (tp.tv_sec < 0) {
+    return 0;
+  }
+  return static_cast<uint64_t>(tp.tv_sec) * 1000 +
+         static_cast<uint64_t>(tp.tv_nsec) / 1000000;
+}
+
+uint64_t get_wall_clock_time_ms() {
+  struct timespec tp;
+  int err = clock_gettime(CLOCK_REALTIME, &tp);
+  if (err) {
+    return 0;
+  }
+  return timespec_to_ms(tp);
+}
+
+}  // namespace
+
+TpmKeymasterEnforcement::TpmKeymasterEnforcement(
+    TpmResourceManager& resource_manager, TpmGatekeeper& gatekeeper)
+    : KeymasterEnforcement(64, 64),
+      resource_manager_(resource_manager),
+      gatekeeper_(gatekeeper) {
+}
+
+TpmKeymasterEnforcement::~TpmKeymasterEnforcement() {
+}
+
+bool TpmKeymasterEnforcement::activation_date_valid(
+    uint64_t activation_date) const {
+  return activation_date < get_wall_clock_time_ms();
+}
+
+bool TpmKeymasterEnforcement::expiration_date_passed(
+    uint64_t expiration_date) const {
+  return expiration_date > get_wall_clock_time_ms();
+}
+
+bool TpmKeymasterEnforcement::auth_token_timed_out(
+    const hw_auth_token_t& token, uint32_t timeout) const {
+  // timeout comes in seconds, token.timestamp comes in milliseconds
+  uint64_t timeout_ms = 1000 * (uint64_t) timeout;
+  return (be64toh(token.timestamp) + timeout_ms) < get_current_time_ms();
+}
+
+uint64_t TpmKeymasterEnforcement::get_current_time_ms() const {
+  struct timespec tp;
+  int err = clock_gettime(CLOCK_BOOTTIME, &tp);
+  if (err) {
+    return 0;
+  }
+  return timespec_to_ms(tp);
+}
+
+keymaster_security_level_t TpmKeymasterEnforcement::SecurityLevel() const {
+  return KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+}
+
+bool TpmKeymasterEnforcement::ValidateTokenSignature(
+    const hw_auth_token_t& token) const {
+  hw_auth_token_t comparison_token = token;
+  memset(comparison_token.hmac, 0, sizeof(comparison_token.hmac));
+
+  /*
+   * Should match implementation in system/gatekeeper/gatekeeper.cpp
+   * GateKeeper::MintAuthToken
+   */
+
+  const uint8_t *auth_token_key = nullptr;
+  uint32_t auth_token_key_len = 0;
+  if (!gatekeeper_.GetAuthTokenKey(&auth_token_key, &auth_token_key_len)) {
+    LOG(WARNING) << "Unable to get gatekeeper auth token";
+    return false;
+  }
+
+
+  constexpr uint32_t hashable_length = sizeof(token.version) +
+                                       sizeof(token.challenge) +
+                                       sizeof(token.user_id) +
+                                       sizeof(token.authenticator_id) +
+                                       sizeof(token.authenticator_type) +
+                                       sizeof(token.timestamp);
+
+  static_assert(
+      offsetof(hw_auth_token_t, hmac) == hashable_length,
+      "hw_auth_token_t does not appear to be packed");
+
+
+  gatekeeper_.ComputeSignature(
+      comparison_token.hmac,
+      sizeof(comparison_token.hmac),
+      auth_token_key,
+      auth_token_key_len,
+      reinterpret_cast<uint8_t*>(&comparison_token),
+      hashable_length);
+
+  static_assert(sizeof(token.hmac) == sizeof(comparison_token.hmac));
+
+  return memcmp(token.hmac, comparison_token.hmac, sizeof(token.hmac)) == 0;
+}
+
+keymaster_error_t TpmKeymasterEnforcement::GetHmacSharingParameters(
+    HmacSharingParameters* params) {
+  if (!have_saved_params_) {
+    saved_params_.seed = {};
+    TpmRandomSource random_source{resource_manager_.Esys()};
+    auto rc =
+        random_source.GenerateRandom(
+            saved_params_.nonce, sizeof(saved_params_.nonce));
+    if (rc != KM_ERROR_OK) {
+      LOG(ERROR) << "Failed to generate HmacSharingParameters nonce";
+      return rc;
+    }
+    have_saved_params_ = true;
+  }
+  params->seed = saved_params_.seed;
+  memcpy(params->nonce, saved_params_.nonce, sizeof(params->nonce));
+  return KM_ERROR_OK;
+}
+
+keymaster_error_t TpmKeymasterEnforcement::ComputeSharedHmac(
+    const HmacSharingParametersArray& hmac_array,
+    KeymasterBlob* sharingCheck) {
+  std::set<HmacSharingParameters, CompareHmacSharingParams> sorted_hmac_inputs;
+  bool found_mine = false;
+  for (int i = 0; i < hmac_array.num_params; i++) {
+    HmacSharingParameters sharing_params;
+    sharing_params.seed =
+        keymaster::KeymasterBlob(hmac_array.params_array[i].seed);
+    memcpy(
+        sharing_params.nonce,
+        hmac_array.params_array[i].nonce,
+        sizeof(sharing_params.nonce));
+    found_mine = found_mine || (sharing_params == saved_params_);
+    sorted_hmac_inputs.emplace(std::move(sharing_params));
+  }
+
+  if (!found_mine) return KM_ERROR_INVALID_ARGUMENT;
+
+  // unique data has a low maximum size, so combine the hmac parameters
+  char unique_data[] = "\0\0\0\0\0\0\0\0\0\0";
+  int unique_index = 0;
+  for (const auto& hmac_sharing : sorted_hmac_inputs) {
+    for (size_t j = 0; j < hmac_sharing.seed.data_length; j++) {
+      unique_data[unique_index % sizeof(unique_data)] ^=
+          hmac_sharing.seed.data[j];
+      unique_index++;
+    }
+    for (auto nonce_byte : hmac_sharing.nonce) {
+      unique_data[unique_index % sizeof(unique_data)] ^= nonce_byte;
+      unique_index++;
+    }
+  }
+
+
+  auto signing_key_builder = PrimaryKeyBuilder();
+  signing_key_builder.SigningKey();
+  signing_key_builder.UniqueData(std::string(unique_data, sizeof(unique_data)));
+  auto signing_key = signing_key_builder.CreateKey(resource_manager_);
+  if (!signing_key) {
+    LOG(ERROR) << "Could not make signing key for key id";
+    return KM_ERROR_UNKNOWN_ERROR;
+  }
+
+  static const uint8_t signing_input[] = "Keymaster HMAC Verification";
+
+  auto hmac = TpmHmac(
+      resource_manager_,
+      signing_key->get(),
+      TpmAuth(ESYS_TR_PASSWORD),
+      signing_input,
+      sizeof(signing_input));
+
+  if (!hmac) {
+    LOG(ERROR) << "Unable to complete signing check";
+    return KM_ERROR_UNKNOWN_ERROR;
+  }
+
+  *sharingCheck = KeymasterBlob(hmac->buffer, hmac->size);
+
+  return KM_ERROR_OK;
+}
+
+VerifyAuthorizationResponse TpmKeymasterEnforcement::VerifyAuthorization(
+    const VerifyAuthorizationRequest& request) {
+  struct VerificationData {
+    uint64_t challenge;
+    uint64_t timestamp;
+    keymaster_security_level_t security_level;
+  };
+  VerifyAuthorizationResponse response(keymaster::kDefaultMessageVersion);
+  response.error = KM_ERROR_UNKNOWN_ERROR;
+  response.token.challenge = request.challenge;
+  response.token.timestamp = get_current_time_ms();
+  response.token.security_level = SecurityLevel();
+
+  VerificationData verify_data {
+    .challenge = response.token.challenge,
+    .timestamp = response.token.timestamp,
+    .security_level = response.token.security_level,
+  };
+
+  auto signing_key_builder = PrimaryKeyBuilder();
+  signing_key_builder.SigningKey();
+  signing_key_builder.UniqueData("verify_authorization");
+  auto signing_key = signing_key_builder.CreateKey(resource_manager_);
+  if (!signing_key) {
+    LOG(ERROR) << "Could not make signing key for verifying authorization";
+    return response;
+  }
+  auto hmac = TpmHmac(
+      resource_manager_,
+      signing_key->get(),
+      TpmAuth(ESYS_TR_PASSWORD),
+      reinterpret_cast<uint8_t*>(&verify_data),
+      sizeof(verify_data));
+
+  if (!hmac) {
+    LOG(ERROR) << "Could not calculate verification hmac";
+    return response;
+  } else if (hmac->size == 0) {
+    LOG(ERROR) << "hmac was too short";
+    return response;
+  }
+  response.token.mac = KeymasterBlob(hmac->buffer, hmac->size);
+  response.error = KM_ERROR_OK;
+
+  return response;
+}
+
+bool TpmKeymasterEnforcement::CreateKeyId(
+    const keymaster_key_blob_t& key_blob, km_id_t* keyid) const {
+  keymaster::AuthorizationSet hw_enforced;
+  keymaster::AuthorizationSet sw_enforced;
+  keymaster::KeymasterKeyBlob key_material;
+  auto rc =
+      TpmKeyBlobMaker(resource_manager_)
+          .UnwrapKeyBlob(key_blob, &hw_enforced, &sw_enforced, &key_material);
+  if (rc != KM_ERROR_OK) {
+    LOG(ERROR) << "Could not unwrap key: " << rc;
+    return false;
+  }
+  auto signing_key_builder = PrimaryKeyBuilder();
+  signing_key_builder.SigningKey();
+  signing_key_builder.UniqueData("key_id");
+  auto signing_key = signing_key_builder.CreateKey(resource_manager_);
+  if (!signing_key) {
+    LOG(ERROR) << "Could not make signing key for key id";
+    return false;
+  }
+  auto hmac = TpmHmac(
+      resource_manager_,
+      signing_key->get(),
+      TpmAuth(ESYS_TR_PASSWORD),
+      key_material.key_material,
+      key_material.key_material_size);
+  if (!hmac) {
+    LOG(ERROR) << "Failed to make a signature for a key id";
+    return false;
+  }
+  if (hmac->size < sizeof(km_id_t)) {
+    LOG(ERROR) << "hmac return size was less than " << sizeof(km_id_t)
+               << ", got " << hmac->size;
+    return false;
+  }
+  memcpy(keyid, hmac->buffer, sizeof(km_id_t));
+  return true;
+}
diff --git a/host/commands/secure_env/tpm_keymaster_enforcement.h b/host/commands/secure_env/tpm_keymaster_enforcement.h
new file mode 100644
index 0000000..1d6a1e5
--- /dev/null
+++ b/host/commands/secure_env/tpm_keymaster_enforcement.h
@@ -0,0 +1,61 @@
+//
+// 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 <keymaster/keymaster_enforcement.h>
+
+#include "host/commands/secure_env/tpm_gatekeeper.h"
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+/**
+ * Implementation of keymaster::KeymasterEnforcement that depends on having a
+ * TPM available. See the definitions in
+ * system/keymaster/include/keymaster/keymaster_enforcement.h
+ */
+class TpmKeymasterEnforcement : public keymaster::KeymasterEnforcement {
+public:
+  TpmKeymasterEnforcement(
+      TpmResourceManager& resource_manager, TpmGatekeeper& gatekeeper);
+  ~TpmKeymasterEnforcement();
+
+  bool activation_date_valid(uint64_t activation_date) const override;
+  bool expiration_date_passed(uint64_t expiration_date) const override;
+  bool auth_token_timed_out(
+      const hw_auth_token_t& token, uint32_t timeout) const override;
+  uint64_t get_current_time_ms() const override;
+
+  keymaster_security_level_t SecurityLevel() const override;
+  bool ValidateTokenSignature(const hw_auth_token_t& token) const override;
+
+  keymaster_error_t GetHmacSharingParameters(
+        keymaster::HmacSharingParameters* params) override;
+  keymaster_error_t ComputeSharedHmac(
+      const keymaster::HmacSharingParametersArray& params_array,
+      keymaster::KeymasterBlob* sharingCheck) override;
+
+  keymaster::VerifyAuthorizationResponse VerifyAuthorization(
+      const keymaster::VerifyAuthorizationRequest& request) override;
+
+  bool CreateKeyId(
+      const keymaster_key_blob_t& key_blob,
+      keymaster::km_id_t* keyid) const override;
+
+private:
+  TpmResourceManager& resource_manager_;
+  TpmGatekeeper& gatekeeper_;
+  bool have_saved_params_ = false;
+  keymaster::HmacSharingParameters saved_params_;
+};
diff --git a/host/commands/secure_env/tpm_random_source.cpp b/host/commands/secure_env/tpm_random_source.cpp
new file mode 100644
index 0000000..8695e4a
--- /dev/null
+++ b/host/commands/secure_env/tpm_random_source.cpp
@@ -0,0 +1,99 @@
+//
+// 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.
+
+#include "tpm_random_source.h"
+
+#include <android-base/logging.h>
+#include "tss2/tss2_esys.h"
+#include "tss2/tss2_rc.h"
+
+TpmRandomSource::TpmRandomSource(ESYS_CONTEXT* esys) : esys_(esys) {
+}
+
+keymaster_error_t TpmRandomSource::GenerateRandom(
+    uint8_t* random, size_t requested_length) const {
+  if (requested_length == 0) {
+    return KM_ERROR_OK;
+  }
+  // TODO(b/158790549): Pipeline these calls.
+  TPM2B_DIGEST* generated = nullptr;
+  while (requested_length > sizeof(generated->buffer)) {
+    auto rc = Esys_GetRandom(esys_, ESYS_TR_NONE, ESYS_TR_NONE,
+                             ESYS_TR_NONE, sizeof(generated->buffer),
+                             &generated);
+    if (rc != TSS2_RC_SUCCESS) {
+      LOG(ERROR) << "Esys_GetRandom failed with " << rc << " ("
+                 << Tss2_RC_Decode(rc) << ")";
+      // TODO(b/158790404): Return a better error code.
+      return KM_ERROR_UNKNOWN_ERROR;
+    }
+    memcpy(random, generated->buffer, sizeof(generated->buffer));
+    random = (uint8_t*) random + sizeof(generated->buffer);
+    requested_length -= sizeof(generated->buffer);
+    Esys_Free(generated);
+  }
+  auto rc = Esys_GetRandom(esys_, ESYS_TR_NONE, ESYS_TR_NONE,
+                           ESYS_TR_NONE, requested_length, &generated);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_GetRandom failed with " << rc << " ("
+                << Tss2_RC_Decode(rc) << ")";
+    // TODO(b/158790404): Return a better error code.
+    return KM_ERROR_UNKNOWN_ERROR;
+  }
+  memcpy(random, generated->buffer, requested_length);
+  Esys_Free(generated);
+  return KM_ERROR_OK;
+}
+
+// From TPM2_StirRandom specification.
+static int MAX_STIR_RANDOM_BUFFER_SIZE = 128;
+
+keymaster_error_t TpmRandomSource::AddRngEntropy(
+    const uint8_t* buffer, size_t size) const {
+  TPM2B_SENSITIVE_DATA in_data;
+  while (size > MAX_STIR_RANDOM_BUFFER_SIZE) {
+    memcpy(in_data.buffer, buffer, MAX_STIR_RANDOM_BUFFER_SIZE);
+    in_data.size = MAX_STIR_RANDOM_BUFFER_SIZE;
+    buffer += MAX_STIR_RANDOM_BUFFER_SIZE;
+    size -= MAX_STIR_RANDOM_BUFFER_SIZE;
+    auto rc = Esys_StirRandom(
+        esys_,
+        ESYS_TR_NONE,
+        ESYS_TR_NONE,
+        ESYS_TR_NONE,
+        &in_data);
+    if (rc != TSS2_RC_SUCCESS) {
+      LOG(ERROR) << "Esys_StirRandom failed with " << rc << "("
+                 << Tss2_RC_Decode(rc) << ")";
+      return KM_ERROR_UNKNOWN_ERROR;
+    }
+  }
+  if (size == 0) {
+    return KM_ERROR_OK;
+  }
+  memcpy(in_data.buffer, buffer, size);
+  auto rc = Esys_StirRandom(
+      esys_,
+      ESYS_TR_NONE,
+      ESYS_TR_NONE,
+      ESYS_TR_NONE,
+      &in_data);
+  if (rc != TSS2_RC_SUCCESS) {
+    LOG(ERROR) << "Esys_StirRandom failed with " << rc << "("
+                << Tss2_RC_Decode(rc) << ")";
+    return KM_ERROR_UNKNOWN_ERROR;
+  }
+  return KM_ERROR_OK;
+}
diff --git a/host/commands/secure_env/tpm_random_source.h b/host/commands/secure_env/tpm_random_source.h
new file mode 100644
index 0000000..2e7d8a1
--- /dev/null
+++ b/host/commands/secure_env/tpm_random_source.h
@@ -0,0 +1,38 @@
+//
+// 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 <keymaster/random_source.h>
+
+struct ESYS_CONTEXT;
+
+/**
+ * Secure random number generator, pulling data from a TPM.
+ *
+ * RandomSource is used by the OpenSSL HMAC key and AES key implementations.
+ */
+class TpmRandomSource : public keymaster::RandomSource {
+public:
+  TpmRandomSource(ESYS_CONTEXT* esys);
+  virtual ~TpmRandomSource() = default;
+
+  keymaster_error_t GenerateRandom(
+      uint8_t* buffer, size_t length) const override;
+
+  keymaster_error_t AddRngEntropy(const uint8_t*, size_t) const;
+private:
+  ESYS_CONTEXT* esys_;
+};
diff --git a/host/commands/secure_env/tpm_resource_manager.cpp b/host/commands/secure_env/tpm_resource_manager.cpp
new file mode 100644
index 0000000..3651ec8
--- /dev/null
+++ b/host/commands/secure_env/tpm_resource_manager.cpp
@@ -0,0 +1,77 @@
+//
+// 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.
+
+#include "tpm_resource_manager.h"
+
+#include <android-base/logging.h>
+#include <tss2/tss2_rc.h>
+
+TpmResourceManager::ObjectSlot::ObjectSlot(TpmResourceManager* resource_manager)
+    : ObjectSlot(resource_manager, ESYS_TR_NONE) {
+}
+
+TpmResourceManager::ObjectSlot::ObjectSlot(TpmResourceManager* resource_manager,
+                                           ESYS_TR resource)
+    : resource_manager_(resource_manager), resource_(resource) {
+  LOG(VERBOSE) << "Resource allocated";
+}
+
+TpmResourceManager::ObjectSlot::~ObjectSlot() {
+  if (resource_ != ESYS_TR_NONE) {
+    LOG(VERBOSE) << "Freeing resource";
+    auto rc = Esys_FlushContext(resource_manager_->esys_, resource_);
+    if (rc != TPM2_RC_SUCCESS) {
+      LOG(ERROR) << "Esys_FlushContext failed: " << Tss2_RC_Decode(rc)
+                << "(" << rc << ")";
+    }
+  } else {
+    LOG(VERBOSE) << "Resource is NONE";
+  }
+  resource_manager_->used_slots_--;
+}
+
+ESYS_TR TpmResourceManager::ObjectSlot::get() {
+  return resource_;
+}
+
+void TpmResourceManager::ObjectSlot::set(ESYS_TR resource) {
+  resource_ = resource;
+}
+
+TpmResourceManager::TpmResourceManager(ESYS_CONTEXT* esys)
+    : esys_(esys), maximum_object_slots_(3), used_slots_(0) {
+  // TODO(b/158791154): Find maximum_object_slots dynamically using
+  // TPM2_GetCapability. Now equal to MAX_LOADED_OBJECTS from TpmProfile.h.
+}
+
+TpmResourceManager::~TpmResourceManager() {
+  if (used_slots_ > 0) {
+    LOG(FATAL) << "Outstanding TpmResourceManager::ObjectSlot instances. "
+                  "These hold a dangling pointer to this instance.";
+  }
+}
+
+ESYS_CONTEXT* TpmResourceManager::Esys() {
+  return esys_;
+}
+
+TpmObjectSlot TpmResourceManager::ReserveSlot() {
+  auto slot_num = used_slots_.fetch_add(1);
+  if (slot_num >= maximum_object_slots_) {
+      used_slots_--;
+      return nullptr;
+  }
+  return TpmObjectSlot{new ObjectSlot(this)};
+}
diff --git a/host/commands/secure_env/tpm_resource_manager.h b/host/commands/secure_env/tpm_resource_manager.h
new file mode 100644
index 0000000..e1ed83f
--- /dev/null
+++ b/host/commands/secure_env/tpm_resource_manager.h
@@ -0,0 +1,62 @@
+//
+// 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 <cstdint>
+#include <memory>
+#include <set>
+
+#include <tss2/tss2_esys.h>
+
+/**
+ * Object slot manager for TPM memory. The TPM can only hold a fixed number of
+ * objects at once. Some TPM operations are defined to consume slots either
+ * temporarily or until the resource is explicitly unloaded.
+ *
+ * This implementation is intended for future extension, to track what objects
+ * are resident if we run out of space, or implement optimizations like LRU
+ * caching to avoid re-loading often-used resources.
+ */
+class TpmResourceManager {
+public:
+  class ObjectSlot {
+  public:
+    friend class TpmResourceManager;
+
+    ~ObjectSlot();
+
+    ESYS_TR get();
+    void set(ESYS_TR resource);
+  private:
+    ObjectSlot(TpmResourceManager* resource_manager);
+    ObjectSlot(TpmResourceManager* resource_manager, ESYS_TR resource);
+
+    TpmResourceManager* resource_manager_;
+    ESYS_TR resource_;
+  };
+
+  TpmResourceManager(ESYS_CONTEXT* esys);
+  ~TpmResourceManager();
+
+  ESYS_CONTEXT* Esys();
+  std::shared_ptr<ObjectSlot> ReserveSlot();
+private:
+  ESYS_CONTEXT* esys_;
+  const std::uint32_t maximum_object_slots_;
+  std::atomic<std::uint32_t> used_slots_;
+};
+
+using TpmObjectSlot = std::shared_ptr<TpmResourceManager::ObjectSlot>;
diff --git a/host/commands/secure_env/tpm_serialize.cpp b/host/commands/secure_env/tpm_serialize.cpp
new file mode 100644
index 0000000..1cf07ff
--- /dev/null
+++ b/host/commands/secure_env/tpm_serialize.cpp
@@ -0,0 +1,84 @@
+//
+// 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.
+
+#include "tpm_serialize.h"
+
+#include <cstring>
+
+#include <android-base/logging.h>
+#include "tss2/tss2_mu.h"
+#include "tss2/tss2_rc.h"
+
+template<typename T>
+int MarshalFn = 0; // Break code without an explicit specialization.
+
+template<typename T>
+int UnmarshalFn = 0; // Break code without an explicit specialization.
+
+template<>
+auto MarshalFn<TPM2B_PRIVATE> = Tss2_MU_TPM2B_PRIVATE_Marshal;
+
+template<>
+auto UnmarshalFn<TPM2B_PRIVATE> = Tss2_MU_TPM2B_PRIVATE_Unmarshal;
+
+template<>
+auto MarshalFn<TPM2B_PUBLIC> = Tss2_MU_TPM2B_PUBLIC_Marshal;
+
+template<>
+auto UnmarshalFn<TPM2B_PUBLIC> = Tss2_MU_TPM2B_PUBLIC_Unmarshal;
+
+template<typename T>
+TpmSerializable<T>::TpmSerializable(T* instance) : instance_(instance) {}
+
+template<typename T>
+size_t TpmSerializable<T>::SerializedSize() const {
+  std::size_t size = 0;
+  auto rc = MarshalFn<T>(instance_, nullptr, sizeof(T), &size);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "tss2 marshalling failed: " << Tss2_RC_Decode(rc)
+                << "(" << rc << ")";
+    return -1;
+  }
+  return size;
+}
+
+template<typename T>
+uint8_t* TpmSerializable<T>::Serialize(uint8_t* buf, const uint8_t* end) const {
+  std::size_t offset = 0;
+  auto rc = MarshalFn<T>(instance_, buf, end - buf, &offset);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "tss2 marshalling failed: " << Tss2_RC_Decode(rc)
+                << "(" << rc << ")";
+    return buf;
+  }
+  return buf + offset;
+}
+
+template<typename T>
+bool TpmSerializable<T>::Deserialize(
+    const uint8_t** buf_ptr, const uint8_t* end) {
+  std::size_t offset = 0;
+  auto rc = UnmarshalFn<T>(*buf_ptr, end - *buf_ptr, &offset, instance_);
+  if (rc != TPM2_RC_SUCCESS) {
+    LOG(ERROR) << "tss2 unmarshalling failed: " << Tss2_RC_Decode(rc)
+                << "(" << rc << ")";
+    return false;
+  }
+  *buf_ptr += offset;
+  return true;
+}
+
+template class TpmSerializable<TPM2B_PRIVATE>;
+template class TpmSerializable<TPM2B_PUBLIC>;
diff --git a/host/commands/secure_env/tpm_serialize.h b/host/commands/secure_env/tpm_serialize.h
new file mode 100644
index 0000000..17884a5
--- /dev/null
+++ b/host/commands/secure_env/tpm_serialize.h
@@ -0,0 +1,52 @@
+//
+// 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 <cstddef>
+
+#include "keymaster/serializable.h"
+#include "tss2/tss2_mu.h"
+#include "tss2/tss2_rc.h"
+#include "tss2/tss2_tpm2_types.h"
+
+#include <android-base/logging.h>
+
+/**
+ * An implementation of a keymaster::Serializable type that refers to a TPM type
+ * by an unmanaged pointer. When the TpmSerializable serializes or deserializes
+ * data, it loads it from and saves it to the pointed at instance.
+ *
+ * The serialization format is the same as the one used in the command protocol
+ * for TPM messages.
+ *
+ * This is a template class, specialized in the corresponding implementation
+ * file for the TPM types necessary to serialize as part of larger Keymaster
+ * serializable types.
+ */
+template<typename Type>
+class TpmSerializable : public keymaster::Serializable {
+public:
+  TpmSerializable(Type*);
+
+  size_t SerializedSize() const override;
+  uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+  bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+private:
+  Type* instance_;
+};
+
+using SerializeTpmKeyPrivate = TpmSerializable<TPM2B_PRIVATE>;
+using SerializeTpmKeyPublic = TpmSerializable<TPM2B_PUBLIC>;
diff --git a/host/commands/stop_cvd/Android.bp b/host/commands/stop_cvd/Android.bp
index ad279bb..a670a25 100644
--- a/host/commands/stop_cvd/Android.bp
+++ b/host/commands/stop_cvd/Android.bp
@@ -13,25 +13,26 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "stop_cvd",
     srcs: [
         "main.cc",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
+        "libcuttlefish_allocd_utils",
+        "libjsoncpp",
     ],
     static_libs: [
         "libcuttlefish_host_config",
         "libcuttlefish_vm_manager",
-        "libjsoncpp",
         "libgflags",
-        "libxml2",
     ],
-    defaults: ["cuttlefish_host_only", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
 }
diff --git a/host/commands/stop_cvd/main.cc b/host/commands/stop_cvd/main.cc
index 65dbeb7..9e4fdd4 100644
--- a/host/commands/stop_cvd/main.cc
+++ b/host/commands/stop_cvd/main.cc
@@ -38,12 +38,14 @@
 
 #include <android-base/strings.h>
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/fs/shared_select.h"
 #include "common/libs/utils/environment.h"
 #include "host/commands/run_cvd/runner_defs.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/allocd/utils.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/vm_manager/vm_manager.h"
 
@@ -51,11 +53,12 @@
              "How many seconds to wait for the launcher to respond to the stop "
              "command. A value of zero means wait indefinetly");
 
+namespace cuttlefish {
 namespace {
 
 std::set<std::string> FallbackPaths() {
   std::set<std::string> paths;
-  std::string parent_path = cvd::StringFromEnv("HOME", ".");
+  std::string parent_path = StringFromEnv("HOME", ".");
   paths.insert(parent_path + "/cuttlefish_assembly");
   paths.insert(parent_path + "/cuttlefish_assembly/*");
 
@@ -73,13 +76,15 @@
     // Add files in the tombstone directory
     paths.insert(instance_dir + "/tombstones/*");
     // Add files in the internal directory
-    paths.insert(instance_dir + "/" + std::string(vsoc::kInternalDirName) + "/*");
+    paths.insert(instance_dir + "/" + std::string(kInternalDirName) + "/*");
+    // Add files in the shared directory
+    paths.insert(instance_dir + "/" + std::string(kSharedDirName) + "/*");
   }
   return paths;
 }
 
-std::set<std::string> PathsForInstance(const vsoc::CuttlefishConfig& config,
-                                       const vsoc::CuttlefishConfig::InstanceSpecific instance) {
+std::set<std::string> PathsForInstance(const CuttlefishConfig& config,
+                                       const CuttlefishConfig::InstanceSpecific instance) {
   return {
     config.assembly_dir(),
     config.assembly_dir() + "/*",
@@ -89,6 +94,8 @@
     instance.PerInstancePath("tombstones/*"),
     instance.instance_internal_dir(),
     instance.PerInstanceInternalPath("*"),
+    instance.PerInstancePath(kSharedDirName),
+    instance.PerInstancePath(kSharedDirName) + "/*",
   };
 }
 
@@ -138,20 +145,20 @@
   return exit_code;
 }
 
-bool CleanStopInstance(const vsoc::CuttlefishConfig::InstanceSpecific& instance) {
+bool CleanStopInstance(const CuttlefishConfig::InstanceSpecific& instance) {
   auto monitor_path = instance.launcher_monitor_socket_path();
   if (monitor_path.empty()) {
     LOG(ERROR) << "No path to launcher monitor found";
     return false;
   }
-  auto monitor_socket = cvd::SharedFD::SocketLocalClient(monitor_path.c_str(),
-                                                         false, SOCK_STREAM);
+  auto monitor_socket = SharedFD::SocketLocalClient(
+      monitor_path.c_str(), false, SOCK_STREAM, FLAGS_wait_for_launcher);
   if (!monitor_socket->IsOpen()) {
     LOG(ERROR) << "Unable to connect to launcher monitor at " << monitor_path
                << ": " << monitor_socket->StrError();
     return false;
   }
-  auto request = cvd::LauncherAction::kStop;
+  auto request = LauncherAction::kStop;
   auto bytes_sent = monitor_socket->Send(&request, sizeof(request), 0);
   if (bytes_sent < 0) {
     LOG(ERROR) << "Error sending launcher monitor the stop command: "
@@ -159,11 +166,11 @@
     return false;
   }
   // Perform a select with a timeout to guard against launcher hanging
-  cvd::SharedFDSet read_set;
+  SharedFDSet read_set;
   read_set.Set(monitor_socket);
   struct timeval timeout = {FLAGS_wait_for_launcher, 0};
-  int selected = cvd::Select(&read_set, nullptr, nullptr,
-                             FLAGS_wait_for_launcher <= 0 ? nullptr : &timeout);
+  int selected = Select(&read_set, nullptr, nullptr,
+                        FLAGS_wait_for_launcher <= 0 ? nullptr : &timeout);
   if (selected < 0){
     LOG(ERROR) << "Failed communication with the launcher monitor: "
                << strerror(errno);
@@ -173,14 +180,14 @@
     LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
     return false;
   }
-  cvd::LauncherResponse response;
+  LauncherResponse response;
   auto bytes_recv = monitor_socket->Recv(&response, sizeof(response), 0);
   if (bytes_recv < 0) {
     LOG(ERROR) << "Error receiving response from launcher monitor: "
                << monitor_socket->StrError();
     return false;
   }
-  if (response != cvd::LauncherResponse::kSuccess) {
+  if (response != LauncherResponse::kSuccess) {
     LOG(ERROR) << "Received '" << static_cast<char>(response)
                << "' response from launcher monitor";
     return false;
@@ -189,8 +196,8 @@
   return true;
 }
 
-int StopInstance(const vsoc::CuttlefishConfig& config,
-                 const vsoc::CuttlefishConfig::InstanceSpecific& instance) {
+int StopInstance(const CuttlefishConfig& config,
+                 const CuttlefishConfig::InstanceSpecific& instance) {
   bool res = CleanStopInstance(instance);
   if (!res) {
     return FallBackStop(PathsForInstance(config, instance));
@@ -198,13 +205,34 @@
   return 0;
 }
 
-}  // anonymous namespace
+/// Send a StopSession request to allocd
+void ReleaseAllocdResources(SharedFD allocd_sock, uint32_t session_id) {
+  if (!allocd_sock->IsOpen() || session_id == -1) {
+    return;
+  }
+  Json::Value config;
+  Json::Value request_list;
+  Json::Value req;
+  req["request_type"] =
+      ReqTyToStr(RequestType::StopSession);
+  req["session_id"] = session_id;
+  request_list.append(req);
+  config["config_request"]["request_list"] = request_list;
+  SendJsonMsg(allocd_sock, config);
+  auto resp_opt = RecvJsonMsg(allocd_sock);
+  if (!resp_opt.has_value()) {
+    LOG(ERROR) << "Bad response from allocd";
+    return;
+  }
+  auto resp = resp_opt.value();
+  LOG(INFO) << "Stop Session operation: " << resp["config_status"];
+}
 
-int main(int argc, char** argv) {
+int StopCvdMain(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   google::ParseCommandLineFlags(&argc, &argv, true);
 
-  auto config = vsoc::CuttlefishConfig::Get();
+  auto config = CuttlefishConfig::Get();
   if (!config) {
     LOG(ERROR) << "Failed to obtain config object";
     return FallBackStop(FallbackPaths());
@@ -212,8 +240,29 @@
 
   int ret = 0;
   for (const auto& instance : config->Instances()) {
-    ret |= StopInstance(*config, instance);
+    auto session_id = instance.session_id();
+    int exit_status = StopInstance(*config, instance);
+    if (exit_status == 0 && instance.use_allocd()) {
+      // only release session resources if the instance was stopped
+      SharedFD allocd_sock =
+          SharedFD::SocketLocalClient(kDefaultLocation, false, SOCK_STREAM);
+      if (!allocd_sock->IsOpen()) {
+        LOG(ERROR) << "Unable to connect to allocd on "
+                   << kDefaultLocation << ": "
+                   << allocd_sock->StrError();
+      }
+
+      ReleaseAllocdResources(allocd_sock, session_id);
+    }
+    ret |= exit_status;
   }
 
   return ret;
 }
+
+} // namespace
+} // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::StopCvdMain(argc, argv);
+}
diff --git a/host/commands/tapsetiff/Android.bp b/host/commands/tapsetiff/Android.bp
index c860241..1d7dedb 100644
--- a/host/commands/tapsetiff/Android.bp
+++ b/host/commands/tapsetiff/Android.bp
@@ -13,6 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 sh_binary_host {
     name: "tapsetiff",
     src: "tapsetiff.py",
diff --git a/host/commands/tapsetiff/tapsetiff.py b/host/commands/tapsetiff/tapsetiff.py
index 3e7c9e4..8a0999e 100755
--- a/host/commands/tapsetiff/tapsetiff.py
+++ b/host/commands/tapsetiff/tapsetiff.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 # Copyright (C) 2020 The Android Open Source Project
 #
@@ -26,5 +26,5 @@
 tun_fd = int(sys.argv[1])
 tap_name = sys.argv[2]
 
-ifr = struct.pack('16sH', tap_name, IFF_TAP | IFF_NO_PI | IFF_VNET_HDR)
+ifr = struct.pack('16sH', tap_name.encode('utf-8'), IFF_TAP | IFF_NO_PI | IFF_VNET_HDR)
 fcntl.ioctl(tun_fd, TUNSETIFF, ifr)
diff --git a/host/commands/tombstone_receiver/Android.bp b/host/commands/tombstone_receiver/Android.bp
index 66a353a..51830fc 100644
--- a/host/commands/tombstone_receiver/Android.bp
+++ b/host/commands/tombstone_receiver/Android.bp
@@ -13,22 +13,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "tombstone_receiver",
     srcs: [
         "main.cpp",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
+        "libjsoncpp",
         "liblog",
         "libcuttlefish_utils",
     ],
     static_libs: [
+        "libcuttlefish_host_config",
         "libgflags",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/tombstone_receiver/main.cpp b/host/commands/tombstone_receiver/main.cpp
index 25da1a3..2e0ea69 100644
--- a/host/commands/tombstone_receiver/main.cpp
+++ b/host/commands/tombstone_receiver/main.cpp
@@ -15,13 +15,14 @@
  */
 
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include <chrono>
 #include <fstream>
 #include <iomanip>
 #include <sstream>
 
+#include "host/libs/config/logging.h"
 #include "common/libs/fs/shared_fd.h"
 
 DEFINE_int32(
@@ -49,26 +50,26 @@
     num_tombstones_in_last_second = 0;
   }
 
-  LOG(INFO) << "Creating " << retval;
+  LOG(DEBUG) << "Creating " << retval;
   return retval;
 }
 
 #define CHUNK_RECV_MAX_LEN (1024)
 int main(int argc, char** argv) {
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  cuttlefish::DefaultSubprocessLogging(argv);
   google::ParseCommandLineFlags(&argc, &argv, true);
 
-  cvd::SharedFD server_fd = cvd::SharedFD::Dup(FLAGS_server_fd);
+  cuttlefish::SharedFD server_fd = cuttlefish::SharedFD::Dup(FLAGS_server_fd);
   close(FLAGS_server_fd);
 
   CHECK(server_fd->IsOpen()) << "Error inheriting tombstone server: "
                              << server_fd->StrError();
-  LOG(INFO) << "Host is starting server on port "
-            << server_fd->VsockServerPort();
+  LOG(DEBUG) << "Host is starting server on port "
+             << server_fd->VsockServerPort();
 
   // Server loop
   while (true) {
-    auto conn = cvd::SharedFD::Accept(*server_fd);
+    auto conn = cuttlefish::SharedFD::Accept(*server_fd);
     std::ofstream file(next_tombstone_path(),
                        std::ofstream::out | std::ofstream::binary);
 
diff --git a/host/example_custom_actions/Android.bp b/host/example_custom_actions/Android.bp
new file mode 100644
index 0000000..36161f6
--- /dev/null
+++ b/host/example_custom_actions/Android.bp
@@ -0,0 +1,28 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary_host {
+    name: "cuttlefish_example_action_server",
+    srcs: ["main.cpp"],
+    defaults: [
+        "cuttlefish_buildhost_only",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+        "libjsoncpp",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+    ],
+}
+
+prebuilt_etc_host {
+    name: "cuttlefish_example_action_config.json",
+    src: "custom_action_config.json",
+    sub_dir: "cvd_custom_action_config",
+}
diff --git a/host/example_custom_actions/README.md b/host/example_custom_actions/README.md
new file mode 100644
index 0000000..de3764d
--- /dev/null
+++ b/host/example_custom_actions/README.md
@@ -0,0 +1,12 @@
+To try out the custom action config and action server in this path, set the
+following build vars:
+
+```
+SOONG_CONFIG_NAMESPACES += cvd
+SOONG_CONFIG_cvd += custom_action_config custom_action_servers
+
+SOONG_CONFIG_cvd_custom_action_config := cuttlefish_example_action_config.json
+SOONG_CONFIG_cvd_custom_action_servers += cuttlefish_example_action_server
+```
+
+See `device/google/cuttlefish/build/README.md` for more information.
diff --git a/host/example_custom_actions/custom_action_config.json b/host/example_custom_actions/custom_action_config.json
new file mode 100644
index 0000000..56dae0d
--- /dev/null
+++ b/host/example_custom_actions/custom_action_config.json
@@ -0,0 +1,25 @@
+[
+	{
+		"shell_command":"am start -a android.intent.action.VIEW -d https://www.android.com/",
+		"button":{
+			"command":"web",
+			"title":"Web Page",
+			"icon_name":"language"
+		}
+	},
+	{
+		"server":"cuttlefish_example_action_server",
+		"buttons":[
+			{
+				"command":"settings",
+				"title":"Quick Settings",
+				"icon_name":"settings"
+			},
+			{
+				"command":"alert",
+				"title":"Do Not Disturb",
+				"icon_name":"notifications_paused"
+			}
+		]
+	}
+]
diff --git a/host/example_custom_actions/main.cpp b/host/example_custom_actions/main.cpp
new file mode 100644
index 0000000..c6d3b3c
--- /dev/null
+++ b/host/example_custom_actions/main.cpp
@@ -0,0 +1,78 @@
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <sys/socket.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+// Messages are always 128 bytes.
+#define MESSAGE_SIZE 128
+
+using cuttlefish::SharedFD;
+
+int main(int argc, char** argv) {
+  if (argc <= 1) {
+    return 1;
+  }
+
+  // Connect to WebRTC
+  int fd = std::atoi(argv[1]);
+  LOG(INFO) << "Connecting to WebRTC server...";
+  SharedFD webrtc_socket = SharedFD::Dup(fd);
+  close(fd);
+  if (webrtc_socket->IsOpen()) {
+    LOG(INFO) << "Connected";
+  } else {
+    LOG(ERROR) << "Could not connect, exiting...";
+    return 1;
+  }
+
+  // Track state for our two commands.
+  bool statusbar_expanded = false;
+  bool dnd_on = false;
+
+  char buf[MESSAGE_SIZE];
+  while (1) {
+    // Read the command message from the socket.
+    if (!webrtc_socket->IsOpen()) {
+      LOG(WARNING) << "WebRTC was closed.";
+      break;
+    }
+    if (cuttlefish::ReadExact(webrtc_socket, buf, MESSAGE_SIZE) !=
+        MESSAGE_SIZE) {
+      LOG(WARNING) << "Failed to read the correct number of bytes.";
+      break;
+    }
+    auto split = android::base::Split(buf, ":");
+    std::string command = split[0];
+    std::string state = split[1];
+
+    // Ignore button-release events, when state != down.
+    if (state != "down") {
+      continue;
+    }
+
+    // Demonstrate two commands. For demonstration purposes these two
+    // commands use adb shell, but commands can execute any action you choose.
+    std::string adb_shell_command =
+        cuttlefish::HostBinaryPath("adb");
+    if (command == "settings") {
+      adb_shell_command += " shell cmd statusbar ";
+      adb_shell_command += statusbar_expanded ? "collapse" : "expand-settings";
+      statusbar_expanded = !statusbar_expanded;
+    } else if (command == "alert") {
+      adb_shell_command += " shell cmd notification set_dnd ";
+      adb_shell_command += dnd_on ? "off" : "on";
+      dnd_on = !dnd_on;
+    } else {
+      LOG(WARNING) << "Unexpected command: " << buf;
+    }
+
+    if (!adb_shell_command.empty()) {
+      if (system(adb_shell_command.c_str()) != 0) {
+        LOG(ERROR) << "Failed to run command: " << adb_shell_command;
+      }
+    }
+  }
+}
diff --git a/host/frontend/Android.bp b/host/frontend/Android.bp
deleted file mode 100644
index 19d7f9b..0000000
--- a/host/frontend/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "gcastv2",
-    "vnc_server",
-    "adb_connector",
-]
diff --git a/host/frontend/adb_connector/Android.bp b/host/frontend/adb_connector/Android.bp
index c0f04cd..d0927af 100644
--- a/host/frontend/adb_connector/Android.bp
+++ b/host/frontend/adb_connector/Android.bp
@@ -13,22 +13,26 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "adb_connector",
     srcs: [
         "adb_connection_maintainer.cpp",
         "main.cpp"
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     static_libs: [
+        "libcuttlefish_host_config",
         "libgflags",
+        "libjsoncpp",
     ],
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
+        "libcuttlefish_utils",
         "liblog",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/frontend/adb_connector/adb_connection_maintainer.cpp b/host/frontend/adb_connector/adb_connection_maintainer.cpp
index 6b60e34..5f9ff1d 100644
--- a/host/frontend/adb_connector/adb_connection_maintainer.cpp
+++ b/host/frontend/adb_connector/adb_connection_maintainer.cpp
@@ -20,7 +20,7 @@
 #include <string>
 #include <memory>
 #include <vector>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include <unistd.h>
 
@@ -49,11 +49,11 @@
 }
 
 std::string MakeDisconnectMessage(const std::string& address) {
-  return MakeMessage("host:connect:" + address);
+  return MakeMessage("host:disconnect:" + address);
 }
 
 // returns true if successfully sent the whole message
-bool SendAll(cvd::SharedFD sock, const std::string& msg) {
+bool SendAll(cuttlefish::SharedFD sock, const std::string& msg) {
   ssize_t total_written{};
   while (total_written < static_cast<ssize_t>(msg.size())) {
     if (!sock->IsOpen()) {
@@ -69,7 +69,7 @@
   return true;
 }
 
-std::string RecvAll(cvd::SharedFD sock, const size_t count) {
+std::string RecvAll(cuttlefish::SharedFD sock, const size_t count) {
   size_t total_read{};
   std::unique_ptr<char[]> data(new char[count]);
   while (total_read < count) {
@@ -93,7 +93,7 @@
 
 constexpr int kAdbDaemonPort = 5037;
 
-bool AdbSendMessage(cvd::SharedFD sock, const std::string& message) {
+bool AdbSendMessage(cuttlefish::SharedFD sock, const std::string& message) {
   if (!sock->IsOpen()) {
     return false;
   }
@@ -105,7 +105,7 @@
 }
 
 bool AdbSendMessage(const std::string& message) {
-  auto sock = cvd::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
+  auto sock = cuttlefish::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
   return AdbSendMessage(sock, message);
 }
 
@@ -123,7 +123,7 @@
 }
 
 // assumes the OKAY/FAIL status has already been read
-std::string RecvAdbResponse(cvd::SharedFD sock) {
+std::string RecvAdbResponse(cuttlefish::SharedFD sock) {
   auto length_as_hex_str = RecvAll(sock, kAdbMessageLengthLength);
   if (!IsInteger(length_as_hex_str)) {
     return {};
@@ -134,13 +134,13 @@
 
 // Returns a negative value if uptime result couldn't be read for
 // any reason.
-int RecvUptimeResult(cvd::SharedFD sock) {
+int RecvUptimeResult(cuttlefish::SharedFD sock) {
   std::vector<char> uptime_vec{};
   std::vector<char> just_read(16);
   do {
     auto count = sock->Read(just_read.data(), just_read.size());
     if (count < 0) {
-      LOG(INFO) << "couldn't receive adb shell output";
+      LOG(WARNING) << "couldn't receive adb shell output";
       return -1;
     }
     just_read.resize(count);
@@ -148,7 +148,7 @@
   } while (!just_read.empty());
 
   if (uptime_vec.empty()) {
-    LOG(INFO) << "empty adb shell result";
+    LOG(WARNING) << "empty adb shell result";
     return -1;
   }
 
@@ -156,7 +156,7 @@
 
   auto uptime_str = std::string{uptime_vec.data(), uptime_vec.size()};
   if (!IsInteger(uptime_str)) {
-    LOG(INFO) << "non-numeric: uptime result: " << uptime_str;
+    LOG(WARNING) << "non-numeric: uptime result: " << uptime_str;
     return -1;
   }
 
@@ -169,46 +169,46 @@
 static constexpr int kAdbCommandGapTime = 5;
 
 void EstablishConnection(const std::string& address) {
-  LOG(INFO) << "Attempting to connect to device with address " << address;
+  LOG(DEBUG) << "Attempting to connect to device with address " << address;
   while (!AdbConnect(address)) {
     sleep(kAdbCommandGapTime);
   }
-  LOG(INFO) << "adb connect message for " << address << " successfully sent";
+  LOG(DEBUG) << "adb connect message for " << address << " successfully sent";
   sleep(kAdbCommandGapTime);
 }
 
 void WaitForAdbDisconnection(const std::string& address) {
   // adb daemon doesn't seem to handle quick, successive messages well. The
   // sleeps stabilize the communication.
-  LOG(INFO) << "Watching for disconnect on " << address;
+  LOG(DEBUG) << "Watching for disconnect on " << address;
   while (true) {
-    auto sock = cvd::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
+    auto sock = cuttlefish::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
     if (!AdbSendMessage(sock, MakeTransportMessage(address))) {
-      LOG(INFO) << "transport message failed, response body: "
-                << RecvAdbResponse(sock);
+      LOG(WARNING) << "transport message failed, response body: "
+                   << RecvAdbResponse(sock);
       break;
     }
     if (!AdbSendMessage(sock, MakeShellUptimeMessage())) {
-      LOG(INFO) << "adb shell uptime message failed";
+      LOG(WARNING) << "adb shell uptime message failed";
       break;
     }
 
     auto uptime = RecvUptimeResult(sock);
     if (uptime < 0) {
-      LOG(INFO) << "couldn't read uptime result";
+      LOG(WARNING) << "couldn't read uptime result";
       break;
     }
-    LOG(DEBUG) << "device on " << address << " uptime " << uptime;
+    LOG(VERBOSE) << "device on " << address << " uptime " << uptime;
     sleep(kAdbCommandGapTime);
   }
-  LOG(INFO) << "Sending adb disconnect";
+  LOG(DEBUG) << "Sending adb disconnect";
   AdbDisconnect(address);
   sleep(kAdbCommandGapTime);
 }
 
 }  // namespace
 
-[[noreturn]] void cvd::EstablishAndMaintainConnection(std::string address) {
+[[noreturn]] void cuttlefish::EstablishAndMaintainConnection(std::string address) {
   while (true) {
     EstablishConnection(address);
     WaitForAdbDisconnection(address);
diff --git a/host/frontend/adb_connector/adb_connection_maintainer.h b/host/frontend/adb_connector/adb_connection_maintainer.h
index ca5584f..23a7b44 100644
--- a/host/frontend/adb_connector/adb_connection_maintainer.h
+++ b/host/frontend/adb_connector/adb_connection_maintainer.h
@@ -15,8 +15,8 @@
  */
 #pragma once
 
-namespace cvd {
+namespace cuttlefish {
 
 [[noreturn]] void EstablishAndMaintainConnection(std::string address);
 
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/adb_connector/main.cpp b/host/frontend/adb_connector/main.cpp
index a6f8ebe..aaca8cf 100644
--- a/host/frontend/adb_connector/main.cpp
+++ b/host/frontend/adb_connector/main.cpp
@@ -21,25 +21,24 @@
 #include <thread>
 #include <vector>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include <gflags/gflags.h>
 
 #include <unistd.h>
 #include <host/commands/kernel_log_monitor/kernel_log_server.h>
+#include <host/commands/kernel_log_monitor/utils.h>
 
 #include "common/libs/fs/shared_fd.h"
 #include "host/frontend/adb_connector/adb_connection_maintainer.h"
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/logging.h"
 
 DEFINE_string(addresses, "", "Comma-separated list of addresses to "
                              "'adb connect' to");
-DEFINE_int32(adbd_events_fd, -1, "A file descriptor. If set it will wait for "
-                                 "AdbdStarted boot event from the kernel log "
-                                 "monitor before trying to connect adb");
 
 namespace {
 void LaunchConnectionMaintainerThread(const std::string& address) {
-  std::thread(cvd::EstablishAndMaintainConnection, address).detach();
+  std::thread(cuttlefish::EstablishAndMaintainConnection, address).detach();
 }
 
 std::vector<std::string> ParseAddressList(std::string ports) {
@@ -55,35 +54,13 @@
   }
 }
 
-void WaitForAdbdToBeStarted(int events_fd) {
-  auto evt_shared_fd = cvd::SharedFD::Dup(events_fd);
-  close(events_fd);
-  while (evt_shared_fd->IsOpen()) {
-    monitor::BootEvent event;
-    auto bytes_read = evt_shared_fd->Read(&event, sizeof(event));
-    if (bytes_read != sizeof(event)) {
-      LOG(ERROR) << "Fail to read a complete event, read " << bytes_read
-                 << " bytes only instead of the expected " << sizeof(event);
-      // The file descriptor can't be trusted anymore, stop waiting and try to
-      // connect
-      return;
-    }
-    if (event == monitor::BootEvent::AdbdStarted) {
-      LOG(INFO) << "Adbd has started in the guest, connecting adb";
-      return;
-    }
-  }
-}
 }  // namespace
 
 int main(int argc, char* argv[]) {
+  cuttlefish::DefaultSubprocessLogging(argv);
   gflags::ParseCommandLineFlags(&argc, &argv, true);
   CHECK(!FLAGS_addresses.empty()) << "Must specify --addresses flag";
 
-  if (FLAGS_adbd_events_fd >= 0) {
-    WaitForAdbdToBeStarted(FLAGS_adbd_events_fd);
-  }
-
   for (auto address : ParseAddressList(FLAGS_addresses)) {
     LaunchConnectionMaintainerThread(address);
   }
diff --git a/host/frontend/gcastv2/https/Android.bp b/host/frontend/gcastv2/https/Android.bp
deleted file mode 100644
index e4d135a..0000000
--- a/host/frontend/gcastv2/https/Android.bp
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// Copyright (C) 2019 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.
-
-cc_library_static {
-    name: "libhttps",
-    host_supported: true,
-    srcs: [
-        "BaseConnection.cpp",
-        "BufferedSocket.cpp",
-        "ClientSocket.cpp",
-        "HTTPClientConnection.cpp",
-        "HTTPRequestResponse.cpp",
-        "HTTPServer.cpp",
-        "PlainSocket.cpp",
-        "SSLSocket.cpp",
-        "ServerSocket.cpp",
-        "WebSocketHandler.cpp",
-        "RunLoop.cpp",
-        "Support.cpp",
-    ],
-    defaults: ["cuttlefish_host_only"],
-    header_libs: [
-	"cuttlefish_glog",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcrypto",
-        "libssl",
-	"liblog",
-    ],
-    local_include_dirs: ["include"],
-    export_include_dirs: ["include"],
-}
-
diff --git a/host/frontend/gcastv2/https/BaseConnection.cpp b/host/frontend/gcastv2/https/BaseConnection.cpp
deleted file mode 100644
index 4041b97..0000000
--- a/host/frontend/gcastv2/https/BaseConnection.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/BaseConnection.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/PlainSocket.h>
-
-BaseConnection::BaseConnection(std::shared_ptr<RunLoop> runLoop, int sock)
-    : mRunLoop(runLoop),
-      mSocket(std::make_unique<PlainSocket>(mRunLoop, sock)),
-      mInBufferLen(0),
-      mSendPending(false) {
-}
-
-void BaseConnection::run() {
-    receiveClientRequest();
-}
-
-void BaseConnection::receiveClientRequest() {
-    mSocket->postRecv(makeSafeCallback(this, &BaseConnection::onClientRequest));
-}
-
-void BaseConnection::onClientRequest() {
-    static constexpr size_t kMaxChunkSize = 8192;
-
-    mInBuffer.resize(mInBufferLen + kMaxChunkSize);
-
-    ssize_t n;
-    do {
-        n = mSocket->recv(&mInBuffer[mInBufferLen], kMaxChunkSize);
-    } while (n < 0 && errno == EINTR);
-
-    if (n <= 0) {
-        onDisconnect((n < 0) ? -errno : 0);
-        return;
-    }
-
-    mInBufferLen += static_cast<size_t>(n);
-
-    while (mInBufferLen > 0) {
-        n = processClientRequest(mInBuffer.data(), mInBufferLen);
-
-        if (n <= 0) {
-            break;
-        }
-
-        mInBuffer.erase(mInBuffer.begin(), mInBuffer.begin() + n);
-        mInBufferLen -= n;
-    }
-
-    if (n <= 0 && n != -EAGAIN && n != EWOULDBLOCK) {
-        onDisconnect(n);
-        return;
-    }
-
-    receiveClientRequest();
-}
-
-void BaseConnection::send(const void *_data, size_t size) {
-    const uint8_t *data = static_cast<const uint8_t *>(_data);
-    std::copy(data, data + size, std::back_inserter(mOutBuffer));
-
-    if (!mSendPending) {
-        mSendPending = true;
-        mSocket->postSend(
-                makeSafeCallback(this, &BaseConnection::sendOutputData));
-    }
-}
-
-void BaseConnection::sendOutputData() {
-    mSendPending = false;
-
-    const size_t size = mOutBuffer.size();
-    size_t offset = 0;
-
-    while (offset < size) {
-        ssize_t n = mSocket->send(mOutBuffer.data() + offset, size - offset);
-
-        if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
-
-            assert(!"Should not be here");
-        } else if (n == 0) {
-            // The remote seems gone, clear the output buffer and disconnect.
-            offset = size;
-            break;
-        }
-
-        offset += static_cast<size_t>(n);
-    }
-
-    mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + offset);
-
-    if (!mOutBuffer.empty()) {
-        mSendPending = true;
-
-        mSocket->postSend(
-                makeSafeCallback(this, &BaseConnection::sendOutputData));
-        return;
-    }
-}
-
-int BaseConnection::fd() const {
-    return mSocket->fd();
-}
-
diff --git a/host/frontend/gcastv2/https/BufferedSocket.cpp b/host/frontend/gcastv2/https/BufferedSocket.cpp
deleted file mode 100644
index 0156b1c..0000000
--- a/host/frontend/gcastv2/https/BufferedSocket.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/BufferedSocket.h>
-
-#include <cassert>
-#include <unistd.h>
-
-BufferedSocket::BufferedSocket(std::shared_ptr<RunLoop> rl, int sock)
-    : mRunLoop(rl),
-      mSock(sock) {
-    assert(mSock >= 0);
-}
-
-BufferedSocket::~BufferedSocket() {
-    mRunLoop->cancelSocket(mSock);
-
-    close(mSock);
-    mSock = -1;
-}
-
-int BufferedSocket::fd() const {
-    return mSock;
-}
-
-RunLoop *BufferedSocket::runLoop() {
-    return mRunLoop.get();
-}
diff --git a/host/frontend/gcastv2/https/ClientSocket.cpp b/host/frontend/gcastv2/https/ClientSocket.cpp
deleted file mode 100644
index 8529461..0000000
--- a/host/frontend/gcastv2/https/ClientSocket.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/ClientSocket.h>
-
-#include <https/HTTPServer.h>
-#include <https/RunLoop.h>
-#include <https/SafeCallbackable.h>
-#include <https/ServerSocket.h>
-
-#include <glog/logging.h>
-
-#include <cstdlib>
-
-ClientSocket::ClientSocket(
-        std::shared_ptr<RunLoop> rl,
-        HTTPServer *server,
-        ServerSocket *parent,
-        const sockaddr_in &addr,
-        int sock)
-    : mRunLoop(rl),
-      mServer(server),
-      mParent(parent),
-      mRemoteAddr(addr),
-      mInBufferLen(0),
-      mSendPending(false),
-      mDisconnecting(false) {
-    if (parent->transportType() == ServerSocket::TransportType::TLS) {
-        mImplSSL = std::make_shared<SSLSocket>(
-                mRunLoop,
-                sock,
-                *server->certificate_pem_path(),
-                *server->private_key_pem_path());
-    } else {
-        mImplPlain = std::make_shared<PlainSocket>(mRunLoop, sock);
-    }
-}
-
-void ClientSocket::run() {
-    getImpl()->postRecv(makeSafeCallback(this, &ClientSocket::handleIncomingData));
-}
-
-int ClientSocket::fd() const {
-    return getImpl()->fd();
-}
-
-void ClientSocket::setWebSocketHandler(
-        std::shared_ptr<WebSocketHandler> handler) {
-    mWebSocketHandler = handler;
-    mWebSocketHandler->setClientSocket(shared_from_this());
-}
-
-void ClientSocket::handleIncomingData() {
-    mInBuffer.resize(mInBufferLen + 1024);
-
-    ssize_t n;
-    do {
-        n = getImpl()->recv(mInBuffer.data() + mInBufferLen, 1024);
-    } while (n < 0 && errno == EINTR);
-
-    if (n == 0) {
-        if (errno == 0) {
-            // Don't process any data if there was an actual failure.
-            // This could be an authentication failure for example...
-            // We shouldn't trust anything the client says.
-            (void)handleRequest(true /* sawEOS */);
-        }
-
-        disconnect();
-        return;
-    } else if (n < 0) {
-        LOG(ERROR)
-            << "recv returned error "
-            << errno
-            << " ("
-            << strerror(errno)
-            << ")";
-
-        mParent->onClientSocketClosed(fd());
-        return;
-    }
-
-    mInBufferLen += static_cast<size_t>(n);
-    const bool closeConnection = handleRequest(false /* sawEOS */);
-
-    if (closeConnection) {
-        disconnect();
-    } else {
-        getImpl()->postRecv(
-                makeSafeCallback(this, &ClientSocket::handleIncomingData));
-    }
-}
-
-void ClientSocket::disconnect() {
-    if (mDisconnecting) {
-        return;
-    }
-
-    mDisconnecting = true;
-
-    finishDisconnect();
-}
-
-void ClientSocket::finishDisconnect() {
-    if (!mSendPending) {
-        // Our output queue may now be empty, but the underlying socket
-        // implementation may still buffer something that we need to flush
-        // first.
-        getImpl()->postFlush(
-                makeSafeCallback<ClientSocket>(this, [](ClientSocket *me) {
-                    me->mParent->onClientSocketClosed(me->fd());
-                }));
-    }
-}
-
-bool ClientSocket::handleRequest(bool isEOS) {
-    if (mWebSocketHandler) {
-        ssize_t n = mWebSocketHandler->handleRequest(
-                mInBuffer.data(), mInBufferLen, isEOS);
-
-        LOG(VERBOSE)
-            << "handleRequest returned "
-            << n
-            << " when called with "
-            << mInBufferLen
-            << ", eos="
-            << isEOS;
-
-        if (n > 0) {
-            mInBuffer.erase(mInBuffer.begin(), mInBuffer.begin() + n);
-            mInBufferLen -= n;
-        }
-
-        // NOTE: Do not return true, i.e. disconnect, if the json handler
-        // returns 0 bytes read, it simply means we need more data to continue.
-        return n < 0;
-    }
-
-    size_t len = mInBufferLen;
-
-    if (!isEOS) {
-        static const char kPattern[] = "\r\n\r\n";
-
-        // Don't count the trailing NUL.
-        static constexpr size_t kPatternLength = sizeof(kPattern) - 1;
-
-        size_t i = 0;
-        while (i + kPatternLength <= mInBufferLen
-                && memcmp(mInBuffer.data() + i, kPattern, kPatternLength)) {
-            ++i;
-        }
-
-        if (i + kPatternLength > mInBufferLen) {
-            return false;
-        }
-
-        // Found a match.
-        len = i + kPatternLength;
-    }
-
-    const bool closeConnection =
-        mServer->handleSingleRequest(this, mInBuffer.data(), len, isEOS);
-
-    mInBuffer.clear();
-    mInBufferLen = 0;
-
-    return closeConnection;
-}
-
-void ClientSocket::queueOutputData(const uint8_t *data, size_t size) {
-    std::copy(data, data + size, std::back_inserter(mOutBuffer));
-
-    if (!mSendPending) {
-        mSendPending = true;
-        getImpl()->postSend(makeSafeCallback(this, &ClientSocket::sendOutputData));
-    }
-}
-
-sockaddr_in ClientSocket::remoteAddr() const {
-    return mRemoteAddr;
-}
-
-void ClientSocket::queueResponse(
-        const std::string &response, const std::string &body) {
-    std::copy(response.begin(), response.end(), std::back_inserter(mOutBuffer));
-    std::copy(body.begin(), body.end(), std::back_inserter(mOutBuffer));
-
-    if (!mSendPending) {
-        mSendPending = true;
-        getImpl()->postSend(makeSafeCallback(this, &ClientSocket::sendOutputData));
-    }
-}
-
-void ClientSocket::sendOutputData() {
-    mSendPending = false;
-
-    const size_t size = mOutBuffer.size();
-    size_t offset = 0;
-
-    while (offset < size) {
-        ssize_t n = getImpl()->send(mOutBuffer.data() + offset, size - offset);
-
-        if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
-
-            assert(!"Should not be here");
-        } else if (n == 0) {
-            // The remote seems gone, clear the output buffer and disconnect.
-            offset = size;
-            mDisconnecting = true;
-            break;
-        }
-
-        offset += static_cast<size_t>(n);
-    }
-
-    mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + offset);
-
-    if (!mOutBuffer.empty()) {
-        mSendPending = true;
-        getImpl()->postSend(makeSafeCallback(this, &ClientSocket::sendOutputData));
-        return;
-    }
-
-    if (mDisconnecting) {
-        finishDisconnect();
-    }
-}
-
diff --git a/host/frontend/gcastv2/https/HTTPClientConnection.cpp b/host/frontend/gcastv2/https/HTTPClientConnection.cpp
deleted file mode 100644
index cc29c6e..0000000
--- a/host/frontend/gcastv2/https/HTTPClientConnection.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/HTTPClientConnection.h>
-
-#include <https/HTTPRequestResponse.h>
-#include <https/PlainSocket.h>
-#include <https/RunLoop.h>
-#include <https/SafeCallbackable.h>
-#include <https/SSLSocket.h>
-
-#include <https/Support.h>
-
-#include <glog/logging.h>
-
-#include <arpa/inet.h>
-#include <cerrno>
-#include <netinet/in.h>
-#include <unistd.h>
-
-using namespace android;
-
-HTTPClientConnection::HTTPClientConnection(
-        std::shared_ptr<RunLoop> rl,
-        std::shared_ptr<WebSocketHandler> webSocketHandler,
-        std::string_view path,
-        ServerSocket::TransportType transportType,
-        const std::optional<std::string> &trusted_pem_path)
-    : mInitCheck(-ENODEV),
-      mRunLoop(rl),
-      mWebSocketHandler(webSocketHandler),
-      mPath(path),
-      mTransportType(transportType),
-      mSendPending(false),
-      mInBufferLen(0),
-      mWebSocketMode(false) {
-    int sock;
-
-    sock = socket(PF_INET, SOCK_STREAM, 0);
-    if (sock < 0) {
-        mInitCheck = -errno;
-        goto bail;
-    }
-
-    makeFdNonblocking(sock);
-
-    if (mTransportType == ServerSocket::TransportType::TLS) {
-        CHECK(trusted_pem_path.has_value());
-
-        mImpl = std::make_shared<SSLSocket>(
-                mRunLoop, sock, 0 /* flags */, *trusted_pem_path);
-    } else {
-        mImpl = std::make_shared<PlainSocket>(mRunLoop, sock);
-    }
-
-    mInitCheck = 0;
-    return;
-
-bail:
-    ;
-}
-
-int HTTPClientConnection::initCheck() const {
-    return mInitCheck;
-}
-
-int HTTPClientConnection::connect(const char *host, uint16_t port) {
-    if (mInitCheck < 0) {
-        return mInitCheck;
-    }
-
-    sockaddr_in addr;
-    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = inet_addr(host);
-
-    mRemoteAddr = addr;
-
-    int res = ::connect(
-            mImpl->fd(), reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
-
-    if (res < 0 && errno != EINPROGRESS) {
-        return -errno;
-    }
-
-    mImpl->postSend(makeSafeCallback(this, &HTTPClientConnection::sendRequest));
-
-    return 0;
-}
-
-void HTTPClientConnection::sendRequest() {
-    std::string request;
-    request =
-        "GET " + mPath + " HTTP/1.1\r\n"
-        "Connection: Upgrade\r\n"
-        "Upgrade: websocket\r\n"
-        "Sec-WebSocket-Version: 13\r\n"
-        "Sec-WebSocket-Key: foobar\r\n"
-        "\r\n";
-
-    CHECK(mRunLoop->isCurrentThread());
-    std::copy(request.begin(), request.end(), std::back_inserter(mOutBuffer));
-
-    if (!mSendPending) {
-        mSendPending = true;
-        mImpl->postSend(
-                makeSafeCallback(this, &HTTPClientConnection::sendOutputData));
-    }
-
-    mImpl->postRecv(
-            makeSafeCallback(this, &HTTPClientConnection::receiveResponse));
-}
-
-void HTTPClientConnection::receiveResponse() {
-    mInBuffer.resize(mInBufferLen + 1024);
-
-    ssize_t n;
-    do {
-        n = mImpl->recv(mInBuffer.data() + mInBufferLen, 1024);
-    } while (n < 0 && errno == EINTR);
-
-    if (n == 0) {
-        (void)handleResponse(true /* isEOS */);
-        return;
-    } else if (n < 0) {
-        LOG(ERROR) << "recv returned error '" << strerror(errno) << "'.";
-        return;
-    }
-
-    mInBufferLen += static_cast<size_t>(n);
-
-    if (!handleResponse(false /* isEOS */)) {
-        mImpl->postRecv(
-                makeSafeCallback(this, &HTTPClientConnection::receiveResponse));
-    }
-}
-
-bool HTTPClientConnection::handleResponse(bool isEOS) {
-    if (mWebSocketMode) {
-        ssize_t n = mWebSocketHandler->handleRequest(
-                mInBuffer.data(), mInBufferLen, isEOS);
-
-        if (n > 0) {
-            mInBuffer.erase(mInBuffer.begin(), mInBuffer.begin() + n);
-            mInBufferLen -= n;
-        }
-
-        return n <= 0;
-    }
-
-    size_t len = mInBufferLen;
-
-    if (!isEOS) {
-        static const char kPattern[] = "\r\n\r\n";
-
-        // Don't count the trailing NUL.
-        static constexpr size_t kPatternLength = sizeof(kPattern) - 1;
-
-        size_t i = 0;
-        while (i + kPatternLength <= mInBufferLen
-                && memcmp(mInBuffer.data() + i, kPattern, kPatternLength)) {
-            ++i;
-        }
-
-        if (i + kPatternLength > mInBufferLen) {
-            return false;
-        }
-
-        // Found a match.
-        len = i + kPatternLength;
-    }
-
-    HTTPResponse response;
-    if (response.setTo(mInBuffer.data(), len) < 0) {
-        LOG(ERROR) << "failed to get valid server response.";
-
-        mInBuffer.clear();
-        mInBufferLen = 0;
-
-        return true;
-    } else {
-        LOG(INFO)
-            << "got response: "
-            << response.getVersion()
-            << ", "
-            << response.getStatusCode()
-            << ", "
-            << response.getStatusMessage();
-
-        hexdump(mInBuffer.data(), len);
-
-        mInBuffer.erase(mInBuffer.begin(), mInBuffer.begin() + len);
-        mInBufferLen -= len;
-
-        size_t contentLength = response.getContentLength();
-        LOG(VERBOSE) << "contentLength = " << contentLength;
-        assert(mInBufferLen >= contentLength);
-
-        hexdump(mInBuffer.data(), contentLength);
-        mInBuffer.clear();
-
-        if (response.getStatusCode() == 101) {
-            mWebSocketMode = true;
-
-            mWebSocketHandler->setOutputCallback(
-                    mRemoteAddr,
-                    [this](const uint8_t *data, size_t size) {
-                        queueOutputData(data, size);
-                    });
-
-            const std::string msg = "\"message\":\"Hellow, world!\"";
-            mWebSocketHandler->sendMessage(msg.c_str(), msg.size());
-
-            return false;
-        }
-    }
-
-    return true;
-}
-
-void HTTPClientConnection::queueOutputData(const uint8_t *data, size_t size) {
-    CHECK(mRunLoop->isCurrentThread());
-    std::copy(data, &data[size], std::back_inserter(mOutBuffer));
-
-    if (!mSendPending) {
-        mSendPending = true;
-        mImpl->postSend(
-                makeSafeCallback(this, &HTTPClientConnection::sendOutputData));
-    }
-}
-
-void HTTPClientConnection::sendOutputData() {
-    mSendPending = false;
-
-    const size_t size = mOutBuffer.size();
-    size_t offset = 0;
-
-    while (offset < size) {
-        ssize_t n = mImpl->send(mOutBuffer.data() + offset, size - offset);
-
-        if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
-
-            if (errno == EAGAIN) {
-                break;
-            }
-
-            // The remote is gone (due to error), clear the output buffer and disconnect.
-            offset = size;
-            break;
-        } else if (n == 0) {
-            // The remote seems gone, clear the output buffer and disconnect.
-            offset = size;
-            break;
-        }
-
-        offset += static_cast<size_t>(n);
-    }
-
-    mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + offset);
-
-    if (!mOutBuffer.empty()) {
-        mSendPending = true;
-        mImpl->postSend(
-                makeSafeCallback(this, &HTTPClientConnection::sendOutputData));
-
-        return;
-    }
-}
-
diff --git a/host/frontend/gcastv2/https/HTTPRequestResponse.cpp b/host/frontend/gcastv2/https/HTTPRequestResponse.cpp
deleted file mode 100644
index 3f05065..0000000
--- a/host/frontend/gcastv2/https/HTTPRequestResponse.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/HTTPRequestResponse.h>
-
-#include <cerrno>
-#include <iostream>
-#include <regex>
-
-HTTPRequestResponse::HTTPRequestResponse()
-    : mInitCheck(-ENODEV),
-      mContentLength(0) {
-}
-
-int HTTPRequestResponse::setTo(const uint8_t *data, size_t size) {
-    mInitCheck = -EINVAL;
-
-    bool sawEmptyLine = false;
-
-    size_t start = 0;
-    while (start < size) {
-        size_t end = start;
-        while (end + 1 < size && memcmp(&data[end], "\r\n", 2)) {
-            ++end;
-        }
-
-        if ((end + 1) == size) {
-            return mInitCheck;
-        }
-
-        std::string line(
-                reinterpret_cast<const char *>(&data[start]), end - start);
-
-        if (start == 0) {
-            // Parse the request/response line.
-
-            if (!parseRequestResponseLine(line)) {
-                return mInitCheck;
-            }
-
-        } else if (end > start) {
-            std::regex re("([a-zA-Z0-9-]+): (.*)");
-            std::smatch match;
-
-            if (!std::regex_match(line, match, re)) {
-                return mInitCheck;
-            }
-
-            auto key = match[1];
-            auto value = match[2];
-            mHeaders[key] = value;
-        }
-
-        sawEmptyLine = line.empty();
-
-        start = end + 2;
-    }
-
-    if (!sawEmptyLine) {
-        return mInitCheck;
-    }
-
-    std::string stringValue;
-    if (getHeaderField("Content-Length", &stringValue)) {
-        char *end;
-        unsigned long value = strtoul(stringValue.c_str(), &end, 10);
-
-        if (end == stringValue.c_str() || *end != '\0') {
-            return mInitCheck;
-        }
-
-        mContentLength = value;
-    }
-
-    mInitCheck = 0;
-    return mInitCheck;
-}
-
-int HTTPRequestResponse::initCheck() const {
-    return mInitCheck;
-}
-
-bool HTTPRequestResponse::getHeaderField(
-        std::string_view key, std::string *value) const {
-    auto it = mHeaders.find(std::string(key));
-
-    if (it != mHeaders.end()) {
-        *value = it->second;
-        return true;
-    }
-
-    return false;
-}
-
-size_t HTTPRequestResponse::getContentLength() const {
-    return mContentLength;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-std::string HTTPRequest::getMethod() const {
-    return mMethod;
-}
-
-std::string HTTPRequest::getPath() const {
-    return mPath;
-}
-
-std::string HTTPRequest::getVersion() const {
-    return mVersion;
-}
-
-bool HTTPRequest::parseRequestResponseLine(const std::string &line) {
-    std::regex re("(GET|HEAD) ([a-zA-Z_/.0-9?&=]+) (HTTP/1\\.1)");
-    std::smatch match;
-
-    if (!std::regex_match(line, match, re)) {
-        return false;
-    }
-
-    mMethod = match[1];
-    mPath = match[2];
-    mVersion = match[3];
-
-    return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-std::string HTTPResponse::getVersion() const {
-    return mVersion;
-}
-
-int32_t HTTPResponse::getStatusCode() const {
-    return mStatusCode;
-}
-
-std::string HTTPResponse::getStatusMessage() const {
-    return mStatusMessage;
-}
-
-bool HTTPResponse::parseRequestResponseLine(const std::string &line) {
-    std::regex re(
-            "(HTTP/1\\.1) ([1-9][0-9][0-9]) ([a-zA-Z _0-9.]+)");
-
-    std::smatch match;
-
-    if (!std::regex_match(line, match, re)) {
-        return false;
-    }
-
-    mVersion = match[1];
-    std::string statusString = match[2];
-    mStatusMessage = match[3];
-
-    mStatusCode =
-        static_cast<int32_t>(strtol(statusString.c_str(), nullptr, 10));
-
-    return true;
-}
-
diff --git a/host/frontend/gcastv2/https/HTTPServer.cpp b/host/frontend/gcastv2/https/HTTPServer.cpp
deleted file mode 100644
index 1a40420..0000000
--- a/host/frontend/gcastv2/https/HTTPServer.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/HTTPServer.h>
-
-#include <https/ClientSocket.h>
-#include <https/HTTPRequestResponse.h>
-#include <https/Support.h>
-
-#include <glog/logging.h>
-
-#include <iostream>
-#include <map>
-#include <string>
-
-#include <openssl/sha.h>
-
-#define CC_SHA1_CTX     SHA_CTX
-#define CC_SHA1_Init    SHA1_Init
-#define CC_SHA1_Update  SHA1_Update
-#define CC_SHA1_Final   SHA1_Final
-#define CC_LONG         size_t
-
-HTTPServer::HTTPServer(
-        std::shared_ptr<RunLoop> runLoop,
-        const char *iface,
-        uint16_t port,
-        ServerSocket::TransportType transportType,
-        const std::optional<std::string> &certificate_pem_path,
-        const std::optional<std::string> &private_key_pem_path)
-    : mRunLoop(runLoop),
-      mLocalPort(port),
-      mSocketTLS(
-              std::make_shared<ServerSocket>(
-                  this,
-                  transportType,
-                  iface ? iface : "0.0.0.0",
-                  port,
-                  certificate_pem_path,
-                  private_key_pem_path)) {
-    CHECK(mSocketTLS->initCheck() == 0);
-}
-
-uint16_t HTTPServer::getLocalPort() const {
-    return mLocalPort;
-}
-
-void HTTPServer::run() {
-    mSocketTLS->run(mRunLoop);
-}
-
-bool HTTPServer::handleSingleRequest(
-        ClientSocket *clientSocket,
-        const uint8_t *data,
-        size_t size,
-        bool isEOS) {
-    (void)isEOS;
-
-    static const std::unordered_map<int32_t, std::string> kStatusMessage {
-        { 101, "Switching Protocols" },
-        { 200, "OK" },
-        { 400, "Bad Request" },
-        { 404, "Not Found" },
-        { 405, "Method Not Allowed" },
-        { 503, "Service Unavailable" },
-        { 505, "HTTP Version Not Supported" },
-    };
-
-    HTTPRequest request;
-    request.setTo(data, size);
-
-    int32_t httpResultCode;
-    std::string body;
-    std::unordered_map<std::string, std::string> responseHeaders;
-
-    if (request.initCheck() < 0) {
-        httpResultCode = 400;  // Bad Request
-    } else if (request.getMethod() != "GET") {
-        httpResultCode = 405;  // Method Not Allowed
-    } else if (request.getVersion() != "HTTP/1.1") {
-        httpResultCode = 505;  // HTTP Version Not Supported
-    } else {
-        httpResultCode = 404;
-
-        auto path = request.getPath();
-
-        std::string query;
-
-        auto separatorPos = path.find('?');
-        if (separatorPos != std::string::npos) {
-            query = path.substr(separatorPos);
-            path.erase(separatorPos);
-        }
-
-        if (path == "/") { path = "/index.html"; }
-
-        bool done = false;
-
-        {
-            std::lock_guard autoLock(mContentLock);
-
-            auto it = mStaticFiles.find(path);
-
-            if (it != mStaticFiles.end()) {
-                handleStaticFileRequest(
-                        it->second,
-                        request,
-                        &httpResultCode,
-                        &responseHeaders,
-                        &body);
-
-                done = true;
-            }
-        }
-
-        if (!done) {
-            std::lock_guard autoLock(mContentLock);
-
-            auto it = mWebSocketHandlerFactories.find(path);
-
-            if (it != mWebSocketHandlerFactories.end()) {
-                handleWebSocketRequest(
-                        clientSocket,
-                        it->second,
-                        request,
-                        &httpResultCode,
-                        &responseHeaders,
-                        &body);
-
-                done = true;
-            }
-        }
-
-        const auto remoteAddr = clientSocket->remoteAddr();
-        uint32_t ip = ntohl(remoteAddr.sin_addr.s_addr);
-
-        LOG(INFO)
-            << (ip >> 24)
-            << "."
-            << ((ip >> 16) & 0xff)
-            << "."
-            << ((ip >> 8) & 0xff)
-            << "."
-            << (ip & 0xff)
-            << ":"
-            << ntohs(remoteAddr.sin_port)
-            << " "
-            << httpResultCode << " \"" << path << "\"";
-    }
-
-    const std::string status =
-        std::to_string(httpResultCode)
-            + " "
-            + kStatusMessage.find(httpResultCode)->second;
-
-    bool closeConnection = false;
-
-    if (httpResultCode != 200 && httpResultCode != 101) {
-        body = "<h1>" + status + "</h1>";
-
-        responseHeaders["Connection"] = "close";
-        responseHeaders["Content-Type"] = "text/html";
-
-        closeConnection = true;
-    }
-
-    std::string value;
-    if (request.getHeaderField("Connection", &value) && value == "close") {
-        LOG(VERBOSE) << "Closing connection per client's request.";
-        closeConnection = true;
-    }
-
-    responseHeaders["Content-Length"] = std::to_string(body.size());
-
-    if (closeConnection) {
-        responseHeaders["Connection"] = "close";
-    }
-
-    std::string response;
-    response = "HTTP/1.1 " + status + "\r\n";
-
-    for (const auto &pair : responseHeaders) {
-        response += pair.first + ": " + pair.second + "\r\n";
-    }
-
-    response += "\r\n";
-
-    clientSocket->queueResponse(response, body);
-
-    return closeConnection;
-}
-
-void HTTPServer::addStaticFile(
-        const char *at, const char *path, std::optional<std::string> mimeType) {
-    std::lock_guard autoLock(mContentLock);
-    mStaticFiles[at] = { path, mimeType };
-}
-
-void HTTPServer::addStaticContent(
-        const char *at,
-        const void *_data,
-        size_t size,
-        std::optional<std::string> mimeType) {
-    if (!mimeType) {
-        // Note: unlike for static, file-based content, we guess the mime type
-        // based on the path we're mapping the content at, not the path it's
-        // originating from (since we don't know that for memory based content).
-        mimeType = GuessMimeType(at);
-    }
-
-    auto data = static_cast<const uint8_t *>(_data);
-
-    std::lock_guard autoLock(mContentLock);
-    mStaticFiles[at] = { std::vector<uint8_t>(data, data + size), mimeType };
-}
-
-void HTTPServer::addWebSocketHandlerFactory(
-        const char *at, WebSocketHandlerFactory factory) {
-    std::lock_guard autoLock(mContentLock);
-    mWebSocketHandlerFactories[at] = factory;
-}
-
-void HTTPServer::handleWebSocketRequest(
-        ClientSocket *clientSocket,
-        WebSocketHandlerFactory factory,
-        const HTTPRequest &request,
-        int32_t *httpResultCode,
-        std::unordered_map<std::string, std::string> *responseHeaders,
-        std::string *body) {
-    (void)body;
-
-    auto [status, handler] = factory();
-
-    if (status != 0 || !handler) {
-        *httpResultCode = 503;  // Service unavailable.
-        return;
-    }
-
-    *httpResultCode = 400;
-
-    std::string value;
-    if (!request.getHeaderField("Connection", &value)
-            || (value != "Upgrade" && value != "keep-alive, Upgrade")) {
-        return;
-    }
-
-    if (!request.getHeaderField("Upgrade", &value) || value != "websocket") {
-        return;
-    }
-
-    if (!request.getHeaderField("Sec-WebSocket-Version", &value)) {
-        return;
-    }
-
-    char *end;
-    long version = strtol(value.c_str(), &end, 10);
-
-    if (end == value.c_str() || *end != '\0' || version < 13) {
-        return;
-    }
-
-    if (!request.getHeaderField("Sec-WebSocket-Key", &value)) {
-        return;
-    }
-
-    *httpResultCode = 101;
-
-    (*responseHeaders)["Connection"] = "Upgrade";
-    (*responseHeaders)["Upgrade"] = "websocket";
-
-    std::string tmp = value;
-    tmp += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
-
-    CC_SHA1_CTX ctx;
-    int res = CC_SHA1_Init(&ctx);
-    CHECK_EQ(res, 1);
-
-    res = CC_SHA1_Update(
-                &ctx, tmp.c_str(), static_cast<CC_LONG>(tmp.size()));
-
-    CHECK_EQ(res, 1);
-
-    unsigned char digest[20];  // 160 bit
-    res = CC_SHA1_Final(digest, &ctx);
-    CHECK_EQ(res, 1);
-
-    std::string acceptKey;
-    encodeBase64(digest, sizeof(digest), &acceptKey);
-
-    (*responseHeaders)["Sec-WebSocket-Accept"] = acceptKey;
-
-    clientSocket->setWebSocketHandler(handler);
-}
-
-void HTTPServer::handleStaticFileRequest(
-        const StaticFileInfo &info,
-        const HTTPRequest &request,
-        int32_t *httpResultCode,
-        std::unordered_map<std::string, std::string> *responseHeaders,
-        std::string *body) {
-    (void)request;
-
-    if (std::holds_alternative<std::string>(info.mPathOrContent)) {
-        const auto &path = std::get<std::string>(info.mPathOrContent);
-
-        std::unique_ptr<FILE, std::function<int(FILE *)>> file(
-                fopen(path.c_str(), "r"),
-                fclose);
-
-        if (!file) {
-            *httpResultCode = 404;
-            return;
-        }
-
-        fseek(file.get(), 0, SEEK_END);
-        long fileSize = ftell(file.get());
-        fseek(file.get(), 0, SEEK_SET);
-
-        (*responseHeaders)["Content-Length"] = std::to_string(fileSize);
-
-        if (info.mMimeType) {
-            (*responseHeaders)["Content-Type"] = *info.mMimeType;
-        } else {
-            (*responseHeaders)["Content-Type"] = GuessMimeType(path);
-        }
-
-        while (!feof(file.get())) {
-            char buffer[1024];
-            auto n = fread(buffer, 1, sizeof(buffer), file.get());
-
-            body->append(buffer, n);
-        }
-    } else {
-        CHECK(std::holds_alternative<std::vector<uint8_t>>(
-                    info.mPathOrContent));
-
-        const auto &content =
-            std::get<std::vector<uint8_t>>(info.mPathOrContent);
-
-        body->append(content.begin(), content.end());
-
-        (*responseHeaders)["Content-Length"] = std::to_string(content.size());
-    }
-
-    *httpResultCode = 200;
-}
-
-// static
-std::string HTTPServer::GuessMimeType(const std::string &path) {
-    auto dotPos = path.rfind('.');
-    if (dotPos != std::string::npos) {
-        auto extension = std::string(path, dotPos + 1);
-
-        static std::unordered_map<std::string, std::string>
-            sMimeTypeByExtension {
-
-            { "html", "text/html" },
-            { "htm", "text/html" },
-            { "css", "text/css" },
-            { "js", "text/javascript" },
-        };
-
-        auto it = sMimeTypeByExtension.find(extension);
-        if (it != sMimeTypeByExtension.end()) {
-            return it->second;
-        }
-    }
-
-    return "application/octet-stream";
-}
-
-std::optional<std::string> HTTPServer::certificate_pem_path() const {
-    return mSocketTLS->certificate_pem_path();
-}
-
-std::optional<std::string> HTTPServer::private_key_pem_path() const {
-    return mSocketTLS->private_key_pem_path();
-}
diff --git a/host/frontend/gcastv2/https/PlainSocket.cpp b/host/frontend/gcastv2/https/PlainSocket.cpp
deleted file mode 100644
index 26ee574..0000000
--- a/host/frontend/gcastv2/https/PlainSocket.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/PlainSocket.h>
-
-#include <sys/socket.h>
-
-PlainSocket::PlainSocket(std::shared_ptr<RunLoop> rl, int sock)
-    : BufferedSocket(rl, sock) {
-}
-
-void PlainSocket::postRecv(RunLoop::AsyncFunction fn) {
-    runLoop()->postSocketRecv(fd(), fn);
-}
-
-void PlainSocket::postSend(RunLoop::AsyncFunction fn) {
-    runLoop()->postSocketSend(fd(), fn);
-}
-
-ssize_t PlainSocket::recvfrom(
-        void *data,
-        size_t size,
-        sockaddr *address,
-        socklen_t *addressLen) {
-    return ::recvfrom(fd(), data, size, 0, address, addressLen);
-}
-
-ssize_t PlainSocket::sendto(
-        const void *data,
-        size_t size,
-        const sockaddr *addr,
-        socklen_t addrLen) {
-    if (!addr) {
-        return ::send(fd(), data, size, 0);
-    }
-    return ::sendto(fd(), data, size, 0, addr, addrLen);
-}
-
-void PlainSocket::postFlush(RunLoop::AsyncFunction fn) {
-    fn();
-}
diff --git a/host/frontend/gcastv2/https/README b/host/frontend/gcastv2/https/README
deleted file mode 100644
index 49fefc6..0000000
--- a/host/frontend/gcastv2/https/README
+++ /dev/null
@@ -1,5 +0,0 @@
-Test using
-
-    curl --cacert certs/server.crt https://localhost:443/
-
-
diff --git a/host/frontend/gcastv2/https/RunLoop.cpp b/host/frontend/gcastv2/https/RunLoop.cpp
deleted file mode 100644
index 9027343..0000000
--- a/host/frontend/gcastv2/https/RunLoop.cpp
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/RunLoop.h>
-
-#include <https/Support.h>
-
-#include <glog/logging.h>
-
-#include <cstring>
-#include <fcntl.h>
-#include <iostream>
-#include <unistd.h>
-
-#include <mutex>
-#include <condition_variable>
-
-bool RunLoop::QueueElem::operator<=(const QueueElem &other) const {
-    if (mWhen) {
-        if (other.mWhen) {
-            return mWhen <= other.mWhen;
-        }
-
-        return false;
-    }
-
-    if (other.mWhen) {
-        return true;
-    }
-
-    // This ensures that two events posted without a trigger time are queued in
-    // the order they were post()ed in.
-    return true;
-}
-
-RunLoop::RunLoop()
-    : mDone(false),
-      mPThread(0),
-      mNextToken(1) {
-    int res = pipe(mControlFds);
-    CHECK_GE(res, 0);
-
-    makeFdNonblocking(mControlFds[0]);
-}
-
-RunLoop::RunLoop(std::string_view name)
-    : RunLoop() {
-    mName = name;
-
-    mThread = std::thread([this]{ run(); });
-}
-
-RunLoop::~RunLoop() {
-    stop();
-
-    close(mControlFds[1]);
-    mControlFds[1] = -1;
-
-    close(mControlFds[0]);
-    mControlFds[0] = -1;
-}
-
-void RunLoop::stop() {
-    mDone = true;
-    interrupt();
-
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-}
-
-RunLoop::Token RunLoop::post(AsyncFunction fn) {
-    CHECK(fn != nullptr);
-
-    auto token = mNextToken++;
-    insert({ std::nullopt, fn, token });
-
-    return token;
-}
-
-bool RunLoop::postAndAwait(AsyncFunction fn) {
-    if (isCurrentThread()) {
-        // To wait from the runloop's thread would cause deadlock
-        post(fn);
-        return false;
-    }
-
-    std::mutex mtx;
-    bool ran = false;
-    std::condition_variable cond_var;
-
-    post([&cond_var, &mtx, &ran, fn](){
-        fn();
-        {
-            std::unique_lock<std::mutex> lock(mtx);
-            ran = true;
-            // Notify while holding the mutex, otherwise the condition variable
-            // could be destroyed before the call to notify_all.
-            cond_var.notify_all();
-        }
-    });
-
-    {
-        std::unique_lock<std::mutex> lock(mtx);
-        cond_var.wait(lock, [&ran](){ return ran;});
-    }
-    return ran;
-}
-
-RunLoop::Token RunLoop::postWithDelay(
-        std::chrono::steady_clock::duration delay, AsyncFunction fn) {
-    CHECK(fn != nullptr);
-
-    auto token = mNextToken++;
-    insert({ std::chrono::steady_clock::now() + delay, fn, token });
-
-    return token;
-}
-
-bool RunLoop::cancelToken(Token token) {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    bool found = false;
-    for (auto it = mQueue.begin(); it != mQueue.end(); ++it) {
-        if (it->mToken == token) {
-            mQueue.erase(it);
-
-            if (it == mQueue.begin()) {
-                interrupt();
-            }
-
-            found = true;
-            break;
-        }
-    }
-
-    return found;
-}
-
-void RunLoop::postSocketRecv(int sock, AsyncFunction fn) {
-    CHECK_GE(sock, 0);
-    CHECK(fn != nullptr);
-
-    std::lock_guard<std::mutex> autoLock(mLock);
-    mAddInfos.push_back({ sock, InfoType::RECV, fn });
-    interrupt();
-}
-
-void RunLoop::postSocketSend(int sock, AsyncFunction fn) {
-    CHECK_GE(sock, 0);
-    CHECK(fn != nullptr);
-
-    std::lock_guard<std::mutex> autoLock(mLock);
-    mAddInfos.push_back({ sock, InfoType::SEND, fn });
-    interrupt();
-}
-
-void RunLoop::cancelSocket(int sock) {
-    CHECK_GE(sock, 0);
-
-    std::lock_guard<std::mutex> autoLock(mLock);
-    mAddInfos.push_back({ sock, InfoType::CANCEL, nullptr });
-    interrupt();
-}
-
-void RunLoop::insert(const QueueElem &elem) {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    auto it = mQueue.begin();
-    while (it != mQueue.end() && *it <= elem) {
-        ++it;
-    }
-
-    if (it == mQueue.begin()) {
-        interrupt();
-    }
-
-    mQueue.insert(it, elem);
-}
-
-void RunLoop::run() {
-    mPThread = pthread_self();
-
-    std::map<int, SocketCallbacks> socketCallbacksByFd;
-    std::vector<pollfd> pollFds;
-
-    auto removePollFdAt = [&socketCallbacksByFd, &pollFds](size_t i) {
-        if (i + 1 == pollFds.size()) {
-            pollFds.pop_back();
-        } else {
-            // Instead of leaving a hole in the middle of the
-            // pollFds vector, we copy the last item into
-            // that hole and reduce the size of the vector by 1,
-            // taking are of updating the corresponding callback
-            // with the correct, new index.
-            pollFds[i] = pollFds.back();
-            pollFds.pop_back();
-            socketCallbacksByFd[pollFds[i].fd].mPollFdIndex = i;
-        }
-    };
-
-    // The control channel's pollFd will always be at index 0.
-    pollFds.push_back({ mControlFds[0], POLLIN, 0 });
-
-    for (;;) {
-        int timeoutMs = -1;  // wait Forever
-
-        {
-            std::lock_guard<std::mutex> autoLock(mLock);
-
-            if (mDone) {
-                break;
-            }
-
-            for (const auto &addInfo : mAddInfos) {
-                const int sock = addInfo.mSock;
-                const auto fn = addInfo.mFn;
-
-                auto it = socketCallbacksByFd.find(sock);
-
-                switch (addInfo.mType) {
-                    case InfoType::RECV:
-                    {
-                        if (it == socketCallbacksByFd.end()) {
-                            socketCallbacksByFd[sock] = { fn, nullptr, pollFds.size() };
-                            pollFds.push_back({ sock, POLLIN, 0 });
-                        } else {
-                            // There's already a pollFd for this socket.
-                            CHECK(it->second.mSendFn != nullptr);
-
-                            CHECK(it->second.mRecvFn == nullptr);
-                            it->second.mRecvFn = fn;
-
-                            pollFds[it->second.mPollFdIndex].events |= POLLIN;
-                        }
-                        break;
-                    }
-
-                    case InfoType::SEND:
-                    {
-                        if (it == socketCallbacksByFd.end()) {
-                            socketCallbacksByFd[sock] = { nullptr, fn, pollFds.size() };
-                            pollFds.push_back({ sock, POLLOUT, 0 });
-                        } else {
-                            // There's already a pollFd for this socket.
-                            if (it->second.mRecvFn == nullptr) {
-                                LOG(ERROR)
-                                    << "There's an entry but no recvFn "
-                                       "notification for socket "
-                                    << sock;
-                            }
-
-                            CHECK(it->second.mRecvFn != nullptr);
-
-                            if (it->second.mSendFn != nullptr) {
-                                LOG(ERROR)
-                                    << "There's already a pending send "
-                                       "notification for socket "
-                                    << sock;
-                            }
-                            CHECK(it->second.mSendFn == nullptr);
-                            it->second.mSendFn = fn;
-
-                            pollFds[it->second.mPollFdIndex].events |= POLLOUT;
-                        }
-                        break;
-                    }
-
-                    case InfoType::CANCEL:
-                    {
-                        if (it != socketCallbacksByFd.end()) {
-                            const size_t i = it->second.mPollFdIndex;
-
-                            socketCallbacksByFd.erase(it);
-                            removePollFdAt(i);
-                        }
-                        break;
-                    }
-                }
-            }
-
-            mAddInfos.clear();
-
-            if (!mQueue.empty()) {
-                timeoutMs = 0;
-
-                if (mQueue.front().mWhen) {
-                    auto duration =
-                        *mQueue.front().mWhen - std::chrono::steady_clock::now();
-
-                    auto durationMs =
-                        std::chrono::duration_cast<std::chrono::milliseconds>(duration);
-
-                    if (durationMs.count() > 0) {
-                        timeoutMs = static_cast<int>(durationMs.count());
-                    }
-                }
-            }
-        }
-
-        int pollRes = 0;
-        if (timeoutMs != 0) {
-            // NOTE: The inequality is on purpose, we'll want to execute this
-            // code if timeoutMs == -1 (infinite) or timeoutMs > 0, but not
-            // if it's 0.
-
-            pollRes = poll(
-                    pollFds.data(),
-                    static_cast<nfds_t>(pollFds.size()),
-                    timeoutMs);
-        }
-
-        if (pollRes < 0) {
-            if (errno != EINTR) {
-                std::cerr
-                    << "poll FAILED w/ "
-                    << errno
-                    << " ("
-                    << strerror(errno)
-                    << ")"
-                    << std::endl;
-            }
-
-            CHECK_EQ(errno, EINTR);
-            continue;
-        }
-
-        std::vector<AsyncFunction> fnArray;
-
-        {
-            std::lock_guard<std::mutex> autoLock(mLock);
-
-            if (pollRes > 0) {
-                if (pollFds[0].revents & POLLIN) {
-                    ssize_t res;
-                    do {
-                        uint8_t c[32];
-                        while ((res = read(mControlFds[0], c, sizeof(c))) < 0
-                                && errno == EINTR) {
-                        }
-                    } while (res > 0);
-                    CHECK(res < 0 && errno == EWOULDBLOCK);
-
-                    --pollRes;
-                }
-
-                // NOTE: Skip index 0, as we already handled it above.
-                // Also, bail early if we exhausted all actionable pollFds
-                // according to pollRes.
-                for (size_t i = pollFds.size(); pollRes && i-- > 1;) {
-                    pollfd &pollFd = pollFds[i];
-                    const short revents = pollFd.revents;
-
-                    if (revents) {
-                        --pollRes;
-                    }
-
-                    const bool readable = (revents & POLLIN);
-                    const bool writable = (revents & POLLOUT);
-                    const bool dead = (revents & POLLNVAL);
-
-                    bool removeCallback = dead;
-
-                    if (readable || writable || dead) {
-                        const int sock = pollFd.fd;
-
-                        const auto &it = socketCallbacksByFd.find(sock);
-                        auto &cb = it->second;
-                        CHECK_EQ(cb.mPollFdIndex, i);
-
-                        if (readable) {
-                            CHECK(cb.mRecvFn != nullptr);
-                            fnArray.push_back(cb.mRecvFn);
-                            cb.mRecvFn = nullptr;
-                            pollFd.events &= ~POLLIN;
-
-                            removeCallback |= (cb.mSendFn == nullptr);
-                        }
-
-                        if (writable) {
-                            CHECK(cb.mSendFn != nullptr);
-                            fnArray.push_back(cb.mSendFn);
-                            cb.mSendFn = nullptr;
-                            pollFd.events &= ~POLLOUT;
-
-                            removeCallback |= (cb.mRecvFn == nullptr);
-                        }
-
-                        if (removeCallback) {
-                            socketCallbacksByFd.erase(it);
-                            removePollFdAt(i);
-                        }
-                    }
-                }
-            } else {
-                // No interrupt, no socket notifications.
-                fnArray.push_back(mQueue.front().mFn);
-                mQueue.pop_front();
-            }
-        }
-
-        for (const auto &fn : fnArray) {
-            fn();
-        }
-    }
-}
-
-void RunLoop::interrupt() {
-    uint8_t c = 1;
-    ssize_t res;
-    while ((res = write(mControlFds[1], &c, 1)) < 0 && errno == EINTR) {
-    }
-
-    CHECK_EQ(res, 1);
-}
-
-struct MainRunLoop : public RunLoop {
-};
-
-static std::mutex gLock;
-static std::shared_ptr<RunLoop> gMainRunLoop;
-
-// static
-std::shared_ptr<RunLoop> RunLoop::main() {
-    std::lock_guard<std::mutex> autoLock(gLock);
-    if (!gMainRunLoop) {
-        gMainRunLoop = std::make_shared<MainRunLoop>();
-    }
-    return gMainRunLoop;
-}
-
-bool RunLoop::isCurrentThread() const {
-    return pthread_equal(pthread_self(), mPThread);
-}
-
diff --git a/host/frontend/gcastv2/https/SSLSocket.cpp b/host/frontend/gcastv2/https/SSLSocket.cpp
deleted file mode 100644
index 38ad1c4..0000000
--- a/host/frontend/gcastv2/https/SSLSocket.cpp
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/SSLSocket.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-#include <glog/logging.h>
-#include <sstream>
-#include <sys/socket.h>
-
-// static
-void SSLSocket::Init() {
-    SSL_library_init();
-    SSL_load_error_strings();
-}
-
-// static
-SSL_CTX *SSLSocket::CreateSSLContext() {
-    SSL_CTX *ctx = SSL_CTX_new(SSLv23_method());
-
-     /* Recommended to avoid SSLv2 & SSLv3 */
-     SSL_CTX_set_options(
-            ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
-
-    return ctx;
-}
-
-SSLSocket::SSLSocket(
-        std::shared_ptr<RunLoop> rl, Mode mode, int sock, uint32_t flags)
-    : BufferedSocket(rl, sock),
-      mMode(mode),
-      mFlags(flags),
-      mCtx(CreateSSLContext(), SSL_CTX_free),
-      mSSL(SSL_new(mCtx.get()), SSL_free),
-      mBioR(BIO_new(BIO_s_mem())),
-      mBioW(BIO_new(BIO_s_mem())),
-      mEOS(false),
-      mFinalErrno(0),
-      mRecvPending(false),
-      mRecvCallback(nullptr),
-      mSendPending(false),
-      mFlushFn(nullptr) {
-    if (mMode == Mode::ACCEPT) {
-        SSL_set_accept_state(mSSL.get());
-    } else {
-        SSL_set_connect_state(mSSL.get());
-    }
-    SSL_set_bio(mSSL.get(), mBioR, mBioW);
-}
-
-bool SSLSocket::useCertificate(const std::string &path) {
-    return 1 == SSL_use_certificate_file(
-                mSSL.get(), path.c_str(), SSL_FILETYPE_PEM);
-}
-
-bool SSLSocket::usePrivateKey(const std::string &path) {
-    return 1 == SSL_use_PrivateKey_file(
-            mSSL.get(), path.c_str(), SSL_FILETYPE_PEM)
-        && 1 == SSL_check_private_key(mSSL.get());
-}
-
-bool SSLSocket::useTrustedCertificates(const std::string &path) {
-    return 1 == SSL_CTX_load_verify_locations(
-            mCtx.get(),
-            path.c_str(),
-            nullptr /* CApath */);
-}
-
-SSLSocket::SSLSocket(
-        std::shared_ptr<RunLoop> rl,
-        int sock,
-        const std::string &certificate_pem_path,
-        const std::string &private_key_pem_path,
-        uint32_t flags)
-    : SSLSocket(rl, Mode::ACCEPT, sock, flags) {
-
-    // This flag makes no sense for a server.
-    CHECK(!(mFlags & FLAG_DONT_CHECK_PEER_CERTIFICATE));
-
-    CHECK(useCertificate(certificate_pem_path)
-            && usePrivateKey(private_key_pem_path));
-}
-
-SSLSocket::SSLSocket(
-        std::shared_ptr<RunLoop> rl,
-        int sock,
-        uint32_t flags,
-        const std::optional<std::string> &trusted_pem_path)
-    : SSLSocket(rl, Mode::CONNECT, sock, flags) {
-
-    if (!(mFlags & FLAG_DONT_CHECK_PEER_CERTIFICATE)) {
-        CHECK(trusted_pem_path.has_value());
-        CHECK(useTrustedCertificates(*trusted_pem_path));
-    }
-}
-
-SSLSocket::~SSLSocket() {
-    SSL_shutdown(mSSL.get());
-
-    mBioW = mBioR = nullptr;
-}
-
-void SSLSocket::postRecv(RunLoop::AsyncFunction fn) {
-    char tmp[128];
-    int n = SSL_peek(mSSL.get(), tmp, sizeof(tmp));
-
-    if (n > 0) {
-        fn();
-        return;
-    }
-
-    CHECK(mRecvCallback == nullptr);
-    mRecvCallback = fn;
-
-    if (!mRecvPending) {
-        mRecvPending = true;
-        runLoop()->postSocketRecv(
-                fd(),
-                makeSafeCallback(this, &SSLSocket::handleIncomingData));
-    }
-}
-
-void SSLSocket::handleIncomingData() {
-    mRecvPending = false;
-
-    uint8_t buffer[1024];
-    ssize_t len;
-    do {
-        len = ::recv(fd(), buffer, sizeof(buffer), 0);
-    } while (len < 0 && errno == EINTR);
-
-    if (len <= 0) {
-        mEOS = true;
-        mFinalErrno = (len < 0) ? errno : 0;
-
-        sendRecvCallback();
-        return;
-    }
-
-    size_t offset = 0;
-    while (len > 0) {
-        int n = BIO_write(mBioR, &buffer[offset], len);
-        CHECK_GT(n, 0);
-
-        offset += n;
-        len -= n;
-
-        if (!SSL_is_init_finished(mSSL.get())) {
-            if (mMode == Mode::ACCEPT) {
-                n = SSL_accept(mSSL.get());
-            } else {
-                n = SSL_connect(mSSL.get());
-            }
-
-            auto err = SSL_get_error(mSSL.get(), n);
-
-            switch (err) {
-                case SSL_ERROR_WANT_READ:
-                {
-                    CHECK_EQ(len, 0);
-                    queueOutputDataFromSSL();
-
-                    mRecvPending = true;
-
-                    runLoop()->postSocketRecv(
-                            fd(),
-                            makeSafeCallback(
-                                this, &SSLSocket::handleIncomingData));
-
-                    return;
-                }
-
-                case SSL_ERROR_WANT_WRITE:
-                {
-                    CHECK_EQ(len, 0);
-
-                    mRecvPending = true;
-
-                    runLoop()->postSocketRecv(
-                            fd(),
-                            makeSafeCallback(
-                                this, &SSLSocket::handleIncomingData));
-
-                    return;
-                }
-
-                case SSL_ERROR_NONE:
-                    break;
-
-                case SSL_ERROR_SYSCALL:
-                default:
-                {
-                    // This is where we end up if the client doesn't trust us.
-                    mEOS = true;
-                    mFinalErrno = ECONNREFUSED;
-
-                    sendRecvCallback();
-                    return;
-                }
-            }
-
-            CHECK(SSL_is_init_finished(mSSL.get()));
-
-            drainOutputBufferPlain();
-
-            if (!(mFlags & FLAG_DONT_CHECK_PEER_CERTIFICATE)
-                    && !isPeerCertificateValid()) {
-                mEOS = true;
-                mFinalErrno = ECONNREFUSED;
-                sendRecvCallback();
-            }
-        }
-    }
-
-    int n = SSL_peek(mSSL.get(), buffer, sizeof(buffer));
-
-    if (n > 0) {
-        sendRecvCallback();
-        return;
-    }
-
-    auto err = SSL_get_error(mSSL.get(), n);
-
-    switch (err) {
-        case SSL_ERROR_WANT_READ:
-        {
-            queueOutputDataFromSSL();
-
-            mRecvPending = true;
-
-            runLoop()->postSocketRecv(
-                    fd(),
-                    makeSafeCallback(this, &SSLSocket::handleIncomingData));
-
-            break;
-        }
-
-        case SSL_ERROR_WANT_WRITE:
-        {
-            mRecvPending = true;
-
-            runLoop()->postSocketRecv(
-                    fd(),
-                    makeSafeCallback(this, &SSLSocket::handleIncomingData));
-
-            break;
-        }
-
-        case SSL_ERROR_ZERO_RETURN:
-        {
-            mEOS = true;
-            mFinalErrno = 0;
-
-            sendRecvCallback();
-            break;
-        }
-
-        case SSL_ERROR_NONE:
-            break;
-
-        case SSL_ERROR_SYSCALL:
-        default:
-        {
-            // This is where we end up if the client doesn't trust us.
-            mEOS = true;
-            mFinalErrno = ECONNREFUSED;
-
-            sendRecvCallback();
-            break;
-        }
-    }
-}
-
-void SSLSocket::sendRecvCallback() {
-    const auto cb = mRecvCallback;
-    mRecvCallback = nullptr;
-    if (cb != nullptr) {
-        cb();
-    }
-}
-
-void SSLSocket::postSend(RunLoop::AsyncFunction fn) {
-    runLoop()->post(fn);
-}
-
-ssize_t SSLSocket::recvfrom(
-        void *data,
-        size_t size,
-        sockaddr *address,
-        socklen_t *addressLen) {
-    if (address || addressLen) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    if (mEOS) {
-        errno = mFinalErrno;
-        return (mFinalErrno == 0) ? 0 : -1;
-    }
-
-    int n = SSL_read(mSSL.get(), data, size);
-
-    // We should only get here after SSL_peek signaled that there's data to
-    // be read.
-    CHECK_GT(n, 0);
-
-    return n;
-}
-
-void SSLSocket::queueOutputDataFromSSL() {
-    int n;
-    do {
-        char buf[1024];
-        n = BIO_read(mBioW, buf, sizeof(buf));
-
-        if (n > 0) {
-            queueOutputData(buf, n);
-        } else if (BIO_should_retry(mBioW)) {
-            continue;
-        } else {
-            LOG(FATAL) << "Should not be here.";
-        }
-    } while (n > 0);
-}
-
-void SSLSocket::queueOutputData(const void *data, size_t size) {
-    if (!size) {
-        return;
-    }
-
-    const size_t pos = mOutBuffer.size();
-    mOutBuffer.resize(pos + size);
-    memcpy(mOutBuffer.data() + pos, data, size);
-
-    if (!mSendPending) {
-        mSendPending = true;
-        runLoop()->postSocketSend(
-                fd(),
-                makeSafeCallback(this, &SSLSocket::sendOutputData));
-    }
-}
-
-void SSLSocket::sendOutputData() {
-    mSendPending = false;
-
-    const size_t size = mOutBuffer.size();
-    size_t offset = 0;
-
-    while (offset < size) {
-        ssize_t n = ::send(
-                fd(), mOutBuffer.data() + offset, size - offset, 0);
-
-        if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
-                break;
-            }
-
-            LOG(FATAL) << "Should not be here.";
-        }
-
-        offset += static_cast<size_t>(n);
-    }
-
-    mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + offset);
-
-    if (!mOutBufferPlain.empty()) {
-        drainOutputBufferPlain();
-    }
-
-    if (!mOutBuffer.empty()) {
-        mSendPending = true;
-        runLoop()->postSocketSend(
-                fd(),
-                makeSafeCallback(this, &SSLSocket::sendOutputData));
-
-        return;
-    }
-
-    auto fn = mFlushFn;
-    mFlushFn = nullptr;
-    if (fn != nullptr) {
-        fn();
-    }
-}
-
-ssize_t SSLSocket::sendto(
-        const void *data,
-        size_t size,
-        const sockaddr *addr,
-        socklen_t addrLen) {
-    if (addr || addrLen) {
-        errno = -EINVAL;
-        return -1;
-    }
-
-    if (mEOS) {
-        errno = mFinalErrno;
-        return (mFinalErrno == 0) ? 0 : -1;
-    }
-
-    const size_t pos = mOutBufferPlain.size();
-    mOutBufferPlain.resize(pos + size);
-    memcpy(&mOutBufferPlain[pos], data, size);
-
-    drainOutputBufferPlain();
-
-    return size;
-}
-
-void SSLSocket::drainOutputBufferPlain() {
-    size_t offset = 0;
-    const size_t size = mOutBufferPlain.size();
-
-    while (offset < size) {
-        int n = SSL_write(mSSL.get(), &mOutBufferPlain[offset], size - offset);
-
-        if (!SSL_is_init_finished(mSSL.get())) {
-            if (mMode == Mode::ACCEPT) {
-                n = SSL_accept(mSSL.get());
-            } else {
-                n = SSL_connect(mSSL.get());
-            }
-
-            auto err = SSL_get_error(mSSL.get(), n);
-
-            switch (err) {
-                case SSL_ERROR_WANT_WRITE:
-                {
-                    mOutBufferPlain.erase(
-                            mOutBufferPlain.begin(),
-                            mOutBufferPlain.begin() + offset);
-
-                    queueOutputDataFromSSL();
-                    return;
-                }
-
-                case SSL_ERROR_WANT_READ:
-                {
-                    mOutBufferPlain.erase(
-                            mOutBufferPlain.begin(),
-                            mOutBufferPlain.begin() + offset);
-
-                    queueOutputDataFromSSL();
-
-                    if (!mRecvPending) {
-                        mRecvPending = true;
-
-                        runLoop()->postSocketRecv(
-                                fd(),
-                                makeSafeCallback(
-                                    this, &SSLSocket::handleIncomingData));
-                    }
-                    return;
-                }
-
-                case SSL_ERROR_SYSCALL:
-                {
-                    // This is where we end up if the client doesn't trust us.
-                    mEOS = true;
-                    mFinalErrno = ECONNREFUSED;
-
-                    LOG(FATAL) << "Should not be here.";
-                    return;
-                }
-
-                case SSL_ERROR_NONE:
-                    break;
-
-                default:
-                    LOG(FATAL) << "Should not be here.";
-            }
-
-            CHECK(SSL_is_init_finished(mSSL.get()));
-
-            if (!isPeerCertificateValid()) {
-                mEOS = true;
-                mFinalErrno = ECONNREFUSED;
-                sendRecvCallback();
-            }
-        }
-
-        offset += n;
-    }
-
-    mOutBufferPlain.erase(
-            mOutBufferPlain.begin(), mOutBufferPlain.begin() + offset);
-
-    queueOutputDataFromSSL();
-}
-
-bool SSLSocket::isPeerCertificateValid() {
-    if (mMode == Mode::ACCEPT || (mFlags & FLAG_DONT_CHECK_PEER_CERTIFICATE)) {
-        // For now we won't validate the client if we are the server.
-        return true;
-    }
-
-    std::unique_ptr<X509, std::function<void(X509 *)>> cert(
-            SSL_get_peer_certificate(mSSL.get()), X509_free);
-
-    if (!cert) {
-        LOG(ERROR) << "SSLSocket::isPeerCertificateValid no certificate.";
-
-        return false;
-    }
-
-    int res = SSL_get_verify_result(mSSL.get());
-
-    bool valid = (res == X509_V_OK);
-
-    if (!valid) {
-        LOG(ERROR) << "SSLSocket::isPeerCertificateValid invalid certificate.";
-
-        const EVP_MD *digest = EVP_get_digestbyname("sha256");
-
-        unsigned char md[EVP_MAX_MD_SIZE];
-        unsigned int n;
-        int res = X509_digest(cert.get(), digest, md, &n);
-        CHECK_EQ(res, 1);
-
-        std::stringstream ss;
-        for (unsigned int i = 0; i < n; ++i) {
-            if (i > 0) {
-                ss << ":";
-            }
-
-            auto byte = md[i];
-
-            auto nibble = byte >> 4;
-            ss << (char)((nibble < 10) ? ('0' + nibble) : ('A' + nibble - 10));
-
-            nibble = byte & 0x0f;
-            ss << (char)((nibble < 10) ? ('0' + nibble) : ('A' + nibble - 10));
-        }
-
-        LOG(ERROR)
-            << "Server offered certificate w/ fingerprint "
-            << ss.str();
-    }
-
-    return valid;
-}
-
-void SSLSocket::postFlush(RunLoop::AsyncFunction fn) {
-    CHECK(mFlushFn == nullptr);
-
-    if (!mSendPending) {
-        fn();
-        return;
-    }
-
-    mFlushFn = fn;
-}
-
diff --git a/host/frontend/gcastv2/https/ServerSocket.cpp b/host/frontend/gcastv2/https/ServerSocket.cpp
deleted file mode 100644
index 8928475..0000000
--- a/host/frontend/gcastv2/https/ServerSocket.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/ServerSocket.h>
-
-#include <https/ClientSocket.h>
-#include <https/RunLoop.h>
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-#include <glog/logging.h>
-
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <iostream>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-ServerSocket::ServerSocket(
-        HTTPServer *server,
-        TransportType transportType,
-        const char *iface,
-        uint16_t port,
-        const std::optional<std::string> &certificate_pem_path,
-        const std::optional<std::string> &private_key_pem_path)
-    : mInitCheck(-ENODEV),
-      mServer(server),
-      mCertificatePath(certificate_pem_path),
-      mPrivateKeyPath(private_key_pem_path),
-      mSocket(-1),
-      mTransportType(transportType) {
-    if (mTransportType == TransportType::TLS) {
-        CHECK(mCertificatePath.has_value());
-        CHECK(mPrivateKeyPath.has_value());
-    }
-
-    sockaddr_in addr;
-    int res;
-
-    mSocket = socket(PF_INET, SOCK_STREAM, 0);
-    if (mSocket < 0) {
-        mInitCheck = -errno;
-        goto bail;
-    }
-
-    makeFdNonblocking(mSocket);
-
-    static constexpr int yes = 1;
-    res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
-    if (res < 0) {
-        mInitCheck = -errno;
-        goto bail2;
-    }
-
-    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = inet_addr(iface);
-
-    res = bind(mSocket, reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
-    if (res < 0) {
-        mInitCheck = -errno;
-        goto bail2;
-    }
-
-    res = listen(mSocket, 4);
-    if (res < 0) {
-        mInitCheck = -errno;
-        goto bail2;
-    }
-
-    mInitCheck = 0;
-    return;
-
-bail2:
-    close(mSocket);
-    mSocket = -1;
-
-bail:
-    ;
-}
-
-ServerSocket::~ServerSocket() {
-    if (mSocket >= 0) {
-        close(mSocket);
-        mSocket = -1;
-    }
-}
-
-int ServerSocket::initCheck() const {
-    return mInitCheck;
-}
-
-ServerSocket::TransportType ServerSocket::transportType() const {
-    return mTransportType;
-}
-
-int ServerSocket::run(std::shared_ptr<RunLoop> rl) {
-    if (mInitCheck < 0) {
-        return mInitCheck;
-    }
-
-    if (mRunLoop) {
-        return -EBUSY;
-    }
-
-    mRunLoop = rl;
-    mRunLoop->postSocketRecv(
-            mSocket,
-            makeSafeCallback(this, &ServerSocket::acceptIncomingConnection));
-
-    return 0;
-}
-
-void ServerSocket::acceptIncomingConnection() {
-    sockaddr_in addr;
-    socklen_t addrLen = sizeof(addr);
-
-    int s = accept(mSocket, reinterpret_cast<sockaddr *>(&addr), &addrLen);
-
-    if (s >= 0) {
-        uint32_t ip = ntohl(addr.sin_addr.s_addr);
-
-        LOG(VERBOSE)
-            << "Accepted incoming connection from "
-            << (ip >> 24)
-            << "."
-            << ((ip >> 16) & 0xff)
-            << "."
-            << ((ip >> 8) & 0xff)
-            << "."
-            << (ip & 0xff)
-            << ":"
-            << ntohs(addr.sin_port);
-
-        makeFdNonblocking(s);
-
-        auto clientSocket =
-            std::make_shared<ClientSocket>(mRunLoop, mServer, this, addr, s);
-
-        clientSocket->run();
-
-        mClientSockets.push_back(clientSocket);
-    }
-
-    mRunLoop->postSocketRecv(
-            mSocket,
-            makeSafeCallback(this, &ServerSocket::acceptIncomingConnection));
-}
-
-void ServerSocket::onClientSocketClosed(int sock) {
-    for (size_t i = mClientSockets.size(); i--;) {
-        if (mClientSockets[i]->fd() == sock) {
-            LOG(VERBOSE) << "Closing client connection.";
-            mClientSockets.erase(mClientSockets.begin() + i);
-            break;
-        }
-    }
-}
-
-std::optional<std::string> ServerSocket::certificate_pem_path() const {
-    return mCertificatePath;
-}
-
-std::optional<std::string> ServerSocket::private_key_pem_path() const {
-    return mPrivateKeyPath;
-}
-
diff --git a/host/frontend/gcastv2/https/Support.cpp b/host/frontend/gcastv2/https/Support.cpp
deleted file mode 100644
index 0138365..0000000
--- a/host/frontend/gcastv2/https/Support.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/Support.h>
-
-#include <cassert>
-#include <cstdint>
-#include <cstdio>
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/errno.h>
-
-void makeFdNonblocking(int fd) {
-    int flags = fcntl(fd, F_GETFL, 0);
-    if (flags < 0) { flags = 0; }
-    DEBUG_ONLY(int res = )fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-    assert(res >= 0);
-}
-
-void hexdump(const void *_data, size_t size) {
-  const uint8_t *data = static_cast<const uint8_t *>(_data);
-
-  size_t offset = 0;
-  while (offset < size) {
-    printf("%08zx: ", offset);
-
-    for (size_t col = 0; col < 16; ++col) {
-      if (offset + col < size) {
-        printf("%02x ", data[offset + col]);
-      } else {
-        printf("   ");
-      }
-
-      if (col == 7) {
-        printf(" ");
-      }
-    }
-
-    printf(" ");
-
-    for (size_t col = 0; col < 16; ++col) {
-      if (offset + col < size && isprint(data[offset + col])) {
-        printf("%c", data[offset + col]);
-      } else if (offset + col < size) {
-        printf(".");
-      }
-    }
-
-    printf("\n");
-
-    offset += 16;
-  }
-}
-
-static char encode6Bit(unsigned x) {
-  static char base64[] =
-      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-  return base64[x & 63];
-}
-
-void encodeBase64(const void *_data, size_t size, std::string *out) {
-    out->clear();
-    out->reserve(((size+2)/3)*4);
-
-    const uint8_t *data = (const uint8_t *)_data;
-
-    size_t i;
-    for (i = 0; i < (size / 3) * 3; i += 3) {
-        uint8_t x1 = data[i];
-        uint8_t x2 = data[i + 1];
-        uint8_t x3 = data[i + 2];
-
-        out->append(1, encode6Bit(x1 >> 2));
-        out->append(1, encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
-        out->append(1, encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
-        out->append(1, encode6Bit(x3 & 0x3f));
-    }
-    switch (size % 3) {
-        case 0:
-            break;
-        case 2:
-        {
-            uint8_t x1 = data[i];
-            uint8_t x2 = data[i + 1];
-            out->append(1, encode6Bit(x1 >> 2));
-            out->append(1, encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
-            out->append(1, encode6Bit((x2 << 2) & 0x3f));
-            out->append(1, '=');
-            break;
-        }
-        default:
-        {
-            uint8_t x1 = data[i];
-            out->append(1, encode6Bit(x1 >> 2));
-            out->append(1, encode6Bit((x1 << 4) & 0x3f));
-            out->append("==");
-            break;
-        }
-    }
-}
-
-uint16_t U16_AT(const uint8_t *ptr) {
-    return ptr[0] << 8 | ptr[1];
-}
-
-uint32_t U32_AT(const uint8_t *ptr) {
-    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
-}
-
-uint64_t U64_AT(const uint8_t *ptr) {
-    return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
-}
-
-uint16_t U16LE_AT(const uint8_t *ptr) {
-    return ptr[0] | (ptr[1] << 8);
-}
-
-uint32_t U32LE_AT(const uint8_t *ptr) {
-    return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
-}
-
-uint64_t U64LE_AT(const uint8_t *ptr) {
-    return ((uint64_t)U32LE_AT(ptr + 4)) << 32 | U32LE_AT(ptr);
-}
diff --git a/host/frontend/gcastv2/https/WebSocketHandler.cpp b/host/frontend/gcastv2/https/WebSocketHandler.cpp
deleted file mode 100644
index fe8c74e..0000000
--- a/host/frontend/gcastv2/https/WebSocketHandler.cpp
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/WebSocketHandler.h>
-
-#include <https/ClientSocket.h>
-#include <https/Support.h>
-
-#include <iostream>
-#include <sstream>
-
-ssize_t WebSocketHandler::handleRequest(
-        uint8_t *data, size_t size, bool isEOS) {
-    (void)isEOS;
-
-    size_t offset = 0;
-    while (offset + 1 < size) {
-        uint8_t *packet = &data[offset];
-        const size_t avail = size - offset;
-
-        size_t packetOffset = 0;
-        const uint8_t headerByte = packet[packetOffset];
-
-        const bool hasMask = (packet[packetOffset + 1] & 0x80) != 0;
-        size_t payloadLen = packet[packetOffset + 1] & 0x7f;
-        packetOffset += 2;
-
-        if (payloadLen == 126) {
-            if (packetOffset + 1 >= avail) {
-                break;
-            }
-
-            payloadLen = U16_AT(&packet[packetOffset]);
-            packetOffset += 2;
-        } else if (payloadLen == 127) {
-            if (packetOffset + 7 >= avail) {
-                break;
-            }
-
-            payloadLen = U64_AT(&packet[packetOffset]);
-            packetOffset += 8;
-        }
-
-        uint32_t mask = 0;
-        if (hasMask) {
-            if (packetOffset + 3 >= avail) {
-                break;
-            }
-
-            mask = U32_AT(&packet[packetOffset]);
-            packetOffset += 4;
-        }
-
-        if (packetOffset + payloadLen > avail) {
-            break;
-        }
-
-        if (mask) {
-            for (size_t i = 0; i < payloadLen; ++i) {
-                packet[packetOffset + i] ^= ((mask >> (8 * (3 - (i % 4)))) & 0xff);
-            }
-        }
-
-        int err = handleMessage(headerByte, &packet[packetOffset], payloadLen);
-
-        offset += packetOffset + payloadLen;
-
-        if (err < 0) {
-            return err;
-        }
-    }
-
-    return offset;
-}
-
-bool WebSocketHandler::isConnected() {
-    return mOutputCallback != nullptr || mClientSocket.lock() != nullptr;
-}
-
-void WebSocketHandler::setClientSocket(std::weak_ptr<ClientSocket> clientSocket) {
-    mClientSocket = clientSocket;
-}
-
-void WebSocketHandler::setOutputCallback(
-        const sockaddr_in &remoteAddr, OutputCallback fn) {
-    mOutputCallback = fn;
-    mRemoteAddr = remoteAddr;
-}
-
-int WebSocketHandler::handleMessage(
-        uint8_t headerByte, const uint8_t *msg, size_t len) {
-    std::cerr
-        << "WebSocketHandler::handleMessage(0x"
-        << std::hex
-        << (unsigned)headerByte
-        << std::dec
-        << ")"
-        << std::endl;
-
-    hexdump(msg, len);
-
-    const uint8_t opcode = headerByte & 0x0f;
-    if (opcode == 8) {
-        // Connection close.
-        return -1;
-    }
-
-    return 0;
-}
-
-int WebSocketHandler::sendMessage(
-        const void *data, size_t size, SendMode mode) {
-    static constexpr bool kUseMask = false;
-
-    size_t numHeaderBytes = 2 + (kUseMask ? 4 : 0);
-    if (size > 65535) {
-        numHeaderBytes += 8;
-    } else if (size > 125) {
-        numHeaderBytes += 2;
-    }
-
-    static constexpr uint8_t kOpCodeBySendMode[] = {
-        0x1,  // text
-        0x2,  // binary
-        0x8,  // closeConnection
-    };
-
-    auto opcode = kOpCodeBySendMode[static_cast<uint8_t>(mode)];
-
-    std::unique_ptr<uint8_t[]> buffer(new uint8_t[numHeaderBytes + size]);
-    uint8_t *msg = buffer.get();
-    msg[0] = 0x80 | opcode;  // FIN==1
-    msg[1] = kUseMask ? 0x80 : 0x00;
-
-    if (size > 65535) {
-        msg[1] |= 127;
-        msg[2] = 0x00;
-        msg[3] = 0x00;
-        msg[4] = 0x00;
-        msg[5] = 0x00;
-        msg[6] = (size >> 24) & 0xff;
-        msg[7] = (size >> 16) & 0xff;
-        msg[8] = (size >> 8) & 0xff;
-        msg[9] = size & 0xff;
-    } else if (size > 125) {
-        msg[1] |= 126;
-        msg[2] = (size >> 8) & 0xff;
-        msg[3] = size & 0xff;
-    } else {
-        msg[1] |= size;
-    }
-
-    if (kUseMask) {
-        uint32_t mask = rand();
-        msg[numHeaderBytes - 4] = (mask >> 24) & 0xff;
-        msg[numHeaderBytes - 3] = (mask >> 16) & 0xff;
-        msg[numHeaderBytes - 2] = (mask >> 8) & 0xff;
-        msg[numHeaderBytes - 1] = mask & 0xff;
-
-        for (size_t i = 0; i < size; ++i) {
-            msg[numHeaderBytes + i] =
-                ((const uint8_t *)data)[i]
-                    ^ ((mask >> (8 * (3 - (i % 4)))) & 0xff);
-        }
-    } else {
-        memcpy(&msg[numHeaderBytes], data, size);
-    }
-
-    if (mOutputCallback) {
-        mOutputCallback(msg, numHeaderBytes + size);
-    } else {
-        auto clientSocket = mClientSocket.lock();
-        if (clientSocket) {
-            clientSocket->queueOutputData(msg, numHeaderBytes + size);
-        }
-    }
-
-    return 0;
-}
-
-std::string WebSocketHandler::remoteHost() const {
-    sockaddr_in remoteAddr;
-
-    if (mOutputCallback) {
-        remoteAddr = mRemoteAddr;
-    } else {
-        auto clientSocket = mClientSocket.lock();
-        if (clientSocket) {
-            remoteAddr = clientSocket->remoteAddr();
-        } else {
-            return "0.0.0.0";
-        }
-    }
-
-    const uint32_t ipAddress = ntohl(remoteAddr.sin_addr.s_addr);
-
-    std::stringstream ss;
-    ss << (ipAddress >> 24)
-       << "."
-       << ((ipAddress >> 16) & 0xff)
-       << "."
-       << ((ipAddress >> 8) & 0xff)
-       << "."
-       << (ipAddress & 0xff);
-
-    return ss.str();
-}
-
diff --git a/host/frontend/gcastv2/https/certs/create_certs.sh b/host/frontend/gcastv2/https/certs/create_certs.sh
deleted file mode 100755
index 9f85e40..0000000
--- a/host/frontend/gcastv2/https/certs/create_certs.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-# As explained in
-#  https://gist.github.com/darrenjs/4645f115d10aa4b5cebf57483ec82eca
-
-openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
-openssl rsa -passin pass:x -in server.pass.key -out server.key
-rm -f server.pass.key
-
-openssl req \
-    -subj "/C=US/ST=California/L=Santa Clara/O=Beyond Aggravated/CN=localhost" \
-    -new -key server.key -out server.csr
-
-openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
-rm -f server.csr
-
-# Now create the list of certificates we trust as a client.
-
-rm trusted.pem
-
-# For now we just trust our own server.
-openssl x509 -in server.crt -text >> trusted.pem
-
-# Also add the system standard CA cert chain.
-# cat /opt/local/etc/openssl/cert.pem >> trusted.pem
-
-# Convert .pem to .der
-# openssl x509 -outform der -in trusted.pem -out trusted.der
-
-# Convert .crt and .key to .p12 for use by Security.framework
-# Enter password "foo"!
-openssl pkcs12 -export -inkey server.key -in server.crt -name localhost -out server.p12
diff --git a/host/frontend/gcastv2/https/certs/server.crt b/host/frontend/gcastv2/https/certs/server.crt
deleted file mode 100644
index 93108a7..0000000
--- a/host/frontend/gcastv2/https/certs/server.crt
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDVzCCAj8CFBlyltiL2iwsm/yiGCMKdiHNfnhkMA0GCSqGSIb3DQEBCwUAMGgx
-CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50
-YSBDbGFyYTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxv
-Y2FsaG9zdDAeFw0xOTA4MjExNjQzNTdaFw0yMDA4MjAxNjQzNTdaMGgxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50YSBDbGFy
-YTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxvY2FsaG9z
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANspCLPC//6LNZIArmxS
-YRrojSPiizASN0svdh1376Bgp9KjUw1NFQhMcq+IobGJjXlxvTqRiXaf3P0dJKZV
-Mdcyc9AOmCNwH8H86OmZTHwV3MdVVqPH2eYl+otWa2eLh8A0J7eN/xn9cl7xtG8u
-UqWc/0Qna7bp4kUOq70M4Kn1NGvlLhtT6jo6DJrpZTj64TTB2c420e86K6UBWSDW
-KPLmarV1mDrYo7gxSu1zqLssYit/X8Xdi8ESQ0WRe1QWNUxMk7qLFTQh1fSUGv6a
-pjWLLrGK9DeYdHsdXX2ttRAlDUtllGctypjCKc0Wcg4ZGfSXZoTlV2k8aEyjYFxu
-VbkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAwo6JLn09RZsTbMoMeCY6JXRMCff8
-mKN3gUao4ob8r6dmZjGDzhBK4oc04OZ28j/5VmnYnLgY0g/+MzbY7hCy35gee/rr
-6Z540m9vYtOrAKyquoOxrS43SciZMjpuL1PKT7Cvo7b6B26x81WSDLkms2NMltUZ
-V9Ayal61cIZOEsUd9JQesYrchoYqJjlqWhGcEe/Gy0O6rTt+ZaHHxS3RwCaQTDfw
-q3d2Z+WozMlOkFGvqhflI7uNuxiAFlwIrvWpn/k//f13x+jFfNLOUUPnzgFPxtWN
-v+yNlVX8KSG5mjgBrDKua5P8s+7zzmoprQk6+/SkUyieS6GgPO/aUF9lPg==
------END CERTIFICATE-----
diff --git a/host/frontend/gcastv2/https/certs/server.key b/host/frontend/gcastv2/https/certs/server.key
deleted file mode 100644
index 3c49d41..0000000
--- a/host/frontend/gcastv2/https/certs/server.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEA2ykIs8L//os1kgCubFJhGuiNI+KLMBI3Sy92HXfvoGCn0qNT
-DU0VCExyr4ihsYmNeXG9OpGJdp/c/R0kplUx1zJz0A6YI3Afwfzo6ZlMfBXcx1VW
-o8fZ5iX6i1ZrZ4uHwDQnt43/Gf1yXvG0by5SpZz/RCdrtuniRQ6rvQzgqfU0a+Uu
-G1PqOjoMmullOPrhNMHZzjbR7zorpQFZINYo8uZqtXWYOtijuDFK7XOouyxiK39f
-xd2LwRJDRZF7VBY1TEyTuosVNCHV9JQa/pqmNYsusYr0N5h0ex1dfa21ECUNS2WU
-Zy3KmMIpzRZyDhkZ9JdmhOVXaTxoTKNgXG5VuQIDAQABAoIBADSgKNfJlmEQGoAB
-q+CU835bozCfwJ59cUubjPhMiXzwWLwqvdGu1cMVYGCoJXOVPSSRXEgJFIIopw8c
-hWVvhbVQByFJr9yqmuWhDmixh/0v3sD6zAAuCDPMoNn+mXHWvnU30OWxsjUSd/k2
-fwZHkE72YRGDicj1ZoEAodqWkggdSIDSxenT7U7SdoIMzEX7s68g9rt338zjgHdx
-r8qYvYqSB6qufNk8vQ/Rq5cz6gBNCrqrJkoC+pzZY0Ps61fEOX7HiyjAxmUSHViq
-6d1+BcAhtoXCy47WmuUH5XD0JixaYtrwon+LTxS/57X9Te+iKFCeLeTkEL++w9TW
-U92DEQECgYEA8MrKzdH79i4dduIIVecwvOE1EPb3Clz89bihFK3aRMPQn1sRMoLB
-glOLnygAn6m3FvIBQYOLwu77+Hfu20Wn0AHHboZ6TOzOLw14bIegA8JUpWmGFKp8
-QGRLBCbFDe/Jzldbmnz5+czmfGC976ZnrAcltchliLqIY51Tlcy7iWECgYEA6QB9
-lDfwpzRHkv9Higcr5ek/jJh6yxa/lolJ8da18HXz8CNsESIUQzQ5NafiH0UKmHNb
-lU0d3XNUWbciauIkZBp/hI7a3qpBvBpMIibhVbbYZwffHIcB2sl9aMNvbRepGSin
-8RhS1/gjYGpDZUFAb9nI+Q9ds1LhtDuVNYWlc1kCgYBnFstA1vfCa/fdX+Qlsvcg
-xmJLww/89dau9L6x9cSO0C7PKtPwBh8GxvHtz9iEgsqKHk3/WGxLprllpSMz6Vxx
-J3HUlepiaLfVWTUHcgFF2rsWnljzHBJaFxYuztJqpxCFMM1dFMiI8/pxoZFvupSE
-CANTElq18PZXf5G7fo2DwQKBgEmEFBteAxpejm69CQ9t79Xc4GY1/hhyFwUiUChz
-/HfgX5VXN9O4EviZU6uwStJe8FblnvHeoRusNeMQu1VKAP1stutWP4yd35vAGGF2
-LwbiaCkp/KV9m4IyrNUPROsA2iPMBiE18X2fF1pmbNlX20LvTk/3HzNjZT9+xTdb
-8bYRAoGBANKwX+QCpCQCNf+hxTPUjf4reShz5w/Wpk2xPxa+FnVxe3jtyxAOZ5uW
-lUWe7UXyNSWh8oiH8japwMkgN+dGnrzW5rMiXwpBFROAqgblRdbvLafebyGQBwAV
-2l6G4RfgG7LJAWsHu0rA74ZwOknfXfebxtrcLhfU7UYdl7fus71D
------END RSA PRIVATE KEY-----
diff --git a/host/frontend/gcastv2/https/certs/trusted.pem b/host/frontend/gcastv2/https/certs/trusted.pem
deleted file mode 100644
index 3429b75..0000000
--- a/host/frontend/gcastv2/https/certs/trusted.pem
+++ /dev/null
@@ -1,70 +0,0 @@
-Certificate:
-    Data:
-        Version: 1 (0x0)
-        Serial Number:
-            19:72:96:d8:8b:da:2c:2c:9b:fc:a2:18:23:0a:76:21:cd:7e:78:64
-        Signature Algorithm: sha256WithRSAEncryption
-        Issuer: C = US, ST = California, L = Santa Clara, O = Beyond Aggravated, CN = localhost
-        Validity
-            Not Before: Aug 21 16:43:57 2019 GMT
-            Not After : Aug 20 16:43:57 2020 GMT
-        Subject: C = US, ST = California, L = Santa Clara, O = Beyond Aggravated, CN = localhost
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-                RSA Public-Key: (2048 bit)
-                Modulus:
-                    00:db:29:08:b3:c2:ff:fe:8b:35:92:00:ae:6c:52:
-                    61:1a:e8:8d:23:e2:8b:30:12:37:4b:2f:76:1d:77:
-                    ef:a0:60:a7:d2:a3:53:0d:4d:15:08:4c:72:af:88:
-                    a1:b1:89:8d:79:71:bd:3a:91:89:76:9f:dc:fd:1d:
-                    24:a6:55:31:d7:32:73:d0:0e:98:23:70:1f:c1:fc:
-                    e8:e9:99:4c:7c:15:dc:c7:55:56:a3:c7:d9:e6:25:
-                    fa:8b:56:6b:67:8b:87:c0:34:27:b7:8d:ff:19:fd:
-                    72:5e:f1:b4:6f:2e:52:a5:9c:ff:44:27:6b:b6:e9:
-                    e2:45:0e:ab:bd:0c:e0:a9:f5:34:6b:e5:2e:1b:53:
-                    ea:3a:3a:0c:9a:e9:65:38:fa:e1:34:c1:d9:ce:36:
-                    d1:ef:3a:2b:a5:01:59:20:d6:28:f2:e6:6a:b5:75:
-                    98:3a:d8:a3:b8:31:4a:ed:73:a8:bb:2c:62:2b:7f:
-                    5f:c5:dd:8b:c1:12:43:45:91:7b:54:16:35:4c:4c:
-                    93:ba:8b:15:34:21:d5:f4:94:1a:fe:9a:a6:35:8b:
-                    2e:b1:8a:f4:37:98:74:7b:1d:5d:7d:ad:b5:10:25:
-                    0d:4b:65:94:67:2d:ca:98:c2:29:cd:16:72:0e:19:
-                    19:f4:97:66:84:e5:57:69:3c:68:4c:a3:60:5c:6e:
-                    55:b9
-                Exponent: 65537 (0x10001)
-    Signature Algorithm: sha256WithRSAEncryption
-         c2:8e:89:2e:7d:3d:45:9b:13:6c:ca:0c:78:26:3a:25:74:4c:
-         09:f7:fc:98:a3:77:81:46:a8:e2:86:fc:af:a7:66:66:31:83:
-         ce:10:4a:e2:87:34:e0:e6:76:f2:3f:f9:56:69:d8:9c:b8:18:
-         d2:0f:fe:33:36:d8:ee:10:b2:df:98:1e:7b:fa:eb:e9:9e:78:
-         d2:6f:6f:62:d3:ab:00:ac:aa:ba:83:b1:ad:2e:37:49:c8:99:
-         32:3a:6e:2f:53:ca:4f:b0:af:a3:b6:fa:07:6e:b1:f3:55:92:
-         0c:b9:26:b3:63:4c:96:d5:19:57:d0:32:6a:5e:b5:70:86:4e:
-         12:c5:1d:f4:94:1e:b1:8a:dc:86:86:2a:26:39:6a:5a:11:9c:
-         11:ef:c6:cb:43:ba:ad:3b:7e:65:a1:c7:c5:2d:d1:c0:26:90:
-         4c:37:f0:ab:77:76:67:e5:a8:cc:c9:4e:90:51:af:aa:17:e5:
-         23:bb:8d:bb:18:80:16:5c:08:ae:f5:a9:9f:f9:3f:fd:fd:77:
-         c7:e8:c5:7c:d2:ce:51:43:e7:ce:01:4f:c6:d5:8d:bf:ec:8d:
-         95:55:fc:29:21:b9:9a:38:01:ac:32:ae:6b:93:fc:b3:ee:f3:
-         ce:6a:29:ad:09:3a:fb:f4:a4:53:28:9e:4b:a1:a0:3c:ef:da:
-         50:5f:65:3e
------BEGIN CERTIFICATE-----
-MIIDVzCCAj8CFBlyltiL2iwsm/yiGCMKdiHNfnhkMA0GCSqGSIb3DQEBCwUAMGgx
-CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50
-YSBDbGFyYTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxv
-Y2FsaG9zdDAeFw0xOTA4MjExNjQzNTdaFw0yMDA4MjAxNjQzNTdaMGgxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50YSBDbGFy
-YTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxvY2FsaG9z
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANspCLPC//6LNZIArmxS
-YRrojSPiizASN0svdh1376Bgp9KjUw1NFQhMcq+IobGJjXlxvTqRiXaf3P0dJKZV
-Mdcyc9AOmCNwH8H86OmZTHwV3MdVVqPH2eYl+otWa2eLh8A0J7eN/xn9cl7xtG8u
-UqWc/0Qna7bp4kUOq70M4Kn1NGvlLhtT6jo6DJrpZTj64TTB2c420e86K6UBWSDW
-KPLmarV1mDrYo7gxSu1zqLssYit/X8Xdi8ESQ0WRe1QWNUxMk7qLFTQh1fSUGv6a
-pjWLLrGK9DeYdHsdXX2ttRAlDUtllGctypjCKc0Wcg4ZGfSXZoTlV2k8aEyjYFxu
-VbkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAwo6JLn09RZsTbMoMeCY6JXRMCff8
-mKN3gUao4ob8r6dmZjGDzhBK4oc04OZ28j/5VmnYnLgY0g/+MzbY7hCy35gee/rr
-6Z540m9vYtOrAKyquoOxrS43SciZMjpuL1PKT7Cvo7b6B26x81WSDLkms2NMltUZ
-V9Ayal61cIZOEsUd9JQesYrchoYqJjlqWhGcEe/Gy0O6rTt+ZaHHxS3RwCaQTDfw
-q3d2Z+WozMlOkFGvqhflI7uNuxiAFlwIrvWpn/k//f13x+jFfNLOUUPnzgFPxtWN
-v+yNlVX8KSG5mjgBrDKua5P8s+7zzmoprQk6+/SkUyieS6GgPO/aUF9lPg==
------END CERTIFICATE-----
diff --git a/host/frontend/gcastv2/https/content/index.html b/host/frontend/gcastv2/https/content/index.html
deleted file mode 100644
index 081f46a..0000000
--- a/host/frontend/gcastv2/https/content/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<script>
-
-var sock = new WebSocket("wss://localhost:8443/control", "protocolOne");
-
-sock.onopen = function(event) {
-    // Close connection after 5 secs.
-    // setTimeout(function() { sock.close(); }, 5000);
-
-    sock.send("Here's some sample text");
-}
-
-sock.onmessage = function(event) {
-    console.log(event.data);
-}
-
-</script>
-
-<h1>Test</h1>
-
diff --git a/host/frontend/gcastv2/https/include/https/BaseConnection.h b/host/frontend/gcastv2/https/include/https/BaseConnection.h
deleted file mode 100644
index 7dd7dc6..0000000
--- a/host/frontend/gcastv2/https/include/https/BaseConnection.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/BufferedSocket.h>
-#include <https/RunLoop.h>
-
-#include <memory>
-#include <vector>
-
-struct BaseConnection : public std::enable_shared_from_this<BaseConnection> {
-    explicit BaseConnection(std::shared_ptr<RunLoop> runLoop, int sock);
-    virtual ~BaseConnection() = default;
-
-    void run();
-
-    BaseConnection(const BaseConnection &) = delete;
-    BaseConnection &operator=(const BaseConnection &) = delete;
-
-protected:
-    // Return -EAGAIN to indicate that not enough data was provided (yet).
-    // Return a positive (> 0) value to drain some amount of data.
-    // Return values <= 0 are considered an error.
-    virtual ssize_t processClientRequest(const void *data, size_t size) = 0;
-
-    virtual void onDisconnect(int err) = 0;
-
-    void send(const void *_data, size_t size);
-
-    int fd() const;
-
-private:
-    std::shared_ptr<RunLoop> mRunLoop;
-
-    std::unique_ptr<BufferedSocket> mSocket;
-
-    std::vector<uint8_t> mInBuffer;
-    size_t mInBufferLen;
-
-    bool mSendPending;
-    std::vector<uint8_t> mOutBuffer;
-
-    void receiveClientRequest();
-    void sendOutputData();
-
-    void onClientRequest();
-};
diff --git a/host/frontend/gcastv2/https/include/https/BufferedSocket.h b/host/frontend/gcastv2/https/include/https/BufferedSocket.h
deleted file mode 100644
index f6095ff..0000000
--- a/host/frontend/gcastv2/https/include/https/BufferedSocket.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/RunLoop.h>
-
-#include <sys/socket.h>
-
-struct BufferedSocket {
-    explicit BufferedSocket(std::shared_ptr<RunLoop> rl, int sock);
-    virtual ~BufferedSocket();
-
-    BufferedSocket(const BufferedSocket &) = delete;
-    BufferedSocket &operator=(const BufferedSocket &) = delete;
-
-    virtual void postRecv(RunLoop::AsyncFunction fn) = 0;
-    virtual void postSend(RunLoop::AsyncFunction fn) = 0;
-
-    ssize_t recv(void *data, size_t size) {
-        return recvfrom(data, size, nullptr, nullptr);
-    }
-
-    virtual ssize_t recvfrom(
-            void *data,
-            size_t size,
-            sockaddr *address,
-            socklen_t *addressLen) = 0;
-
-    ssize_t send(const void *data, size_t size) {
-        return sendto(data, size, nullptr, 0);
-    }
-
-    virtual ssize_t sendto(
-            const void *data,
-            size_t size,
-            const sockaddr *addr,
-            socklen_t addrLen) = 0;
-
-    virtual void postFlush(RunLoop::AsyncFunction fn) = 0;
-
-    int fd() const;
-
-protected:
-    RunLoop *runLoop();
-
-private:
-    std::shared_ptr<RunLoop> mRunLoop;
-    int mSock;
-};
diff --git a/host/frontend/gcastv2/https/include/https/ClientSocket.h b/host/frontend/gcastv2/https/include/https/ClientSocket.h
deleted file mode 100644
index fd29daf..0000000
--- a/host/frontend/gcastv2/https/include/https/ClientSocket.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/BufferedSocket.h>
-
-#include <https/WebSocketHandler.h>
-
-#include <arpa/inet.h>
-#include <vector>
-#include <memory>
-
-#include <https/PlainSocket.h>
-#include <https/SSLSocket.h>
-
-struct HTTPServer;
-struct RunLoop;
-struct ServerSocket;
-
-struct ClientSocket : public std::enable_shared_from_this<ClientSocket> {
-    explicit ClientSocket(
-            std::shared_ptr<RunLoop> rl,
-            HTTPServer *server,
-            ServerSocket *parent,
-            const sockaddr_in &addr,
-            int sock);
-
-    ClientSocket(const ClientSocket &) = delete;
-    ClientSocket &operator=(const ClientSocket &) = delete;
-
-    void run();
-
-    int fd() const;
-
-    void queueResponse(const std::string &response, const std::string &body);
-    void setWebSocketHandler(std::shared_ptr<WebSocketHandler> handler);
-
-    void queueOutputData(const uint8_t *data, size_t size);
-
-    sockaddr_in remoteAddr() const;
-
-private:
-    std::shared_ptr<RunLoop> mRunLoop;
-    HTTPServer *mServer;
-    ServerSocket *mParent;
-    sockaddr_in mRemoteAddr;
-
-    std::shared_ptr<BufferedSocket> mImplPlain;
-    std::shared_ptr<SSLSocket> mImplSSL;
-
-    std::vector<uint8_t> mInBuffer;
-    size_t mInBufferLen;
-
-    std::vector<uint8_t> mOutBuffer;
-    bool mSendPending;
-
-    bool mDisconnecting;
-
-    std::shared_ptr<WebSocketHandler> mWebSocketHandler;
-
-    void handleIncomingData();
-
-    // Returns true iff the client should close the connection.
-    bool handleRequest(bool isEOS);
-
-    void sendOutputData();
-
-    void disconnect();
-    void finishDisconnect();
-
-    BufferedSocket *getImpl() const {
-        return mImplSSL ? mImplSSL.get() : mImplPlain.get();
-    }
-};
diff --git a/host/frontend/gcastv2/https/include/https/HTTPClientConnection.h b/host/frontend/gcastv2/https/include/https/HTTPClientConnection.h
deleted file mode 100644
index 357136f..0000000
--- a/host/frontend/gcastv2/https/include/https/HTTPClientConnection.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2019 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 <arpa/inet.h>
-#include <https/BufferedSocket.h>
-#include <https/ServerSocket.h>
-#include <https/WebSocketHandler.h>
-
-#include <memory>
-#include <optional>
-#include <string>
-
-struct HTTPClientConnection
-    : public std::enable_shared_from_this<HTTPClientConnection> {
-
-    explicit HTTPClientConnection(
-            std::shared_ptr<RunLoop> rl,
-            std::shared_ptr<WebSocketHandler> webSocketHandler,
-            std::string_view path,
-            ServerSocket::TransportType transportType,
-            const std::optional<std::string> &trusted_pem_path =  std::nullopt);
-
-    HTTPClientConnection(const HTTPClientConnection &) = delete;
-    HTTPClientConnection &operator=(const HTTPClientConnection &) = delete;
-
-    int initCheck() const;
-
-    int connect(const char *host, uint16_t port);
-
-private:
-    int mInitCheck;
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    std::shared_ptr<WebSocketHandler> mWebSocketHandler;
-    std::string mPath;
-    ServerSocket::TransportType mTransportType;
-    std::shared_ptr<BufferedSocket> mImpl;
-
-    std::vector<uint8_t> mOutBuffer;
-    bool mSendPending;
-
-    std::vector<uint8_t> mInBuffer;
-    size_t mInBufferLen;
-
-    sockaddr_in mRemoteAddr;
-
-    bool mWebSocketMode;
-
-    void sendRequest();
-    void receiveResponse();
-
-    // Returns true iff response was received fully.
-    bool handleResponse(bool isEOS);
-
-    void queueOutputData(const uint8_t *data, size_t size);
-    void sendOutputData();
-};
-
diff --git a/host/frontend/gcastv2/https/include/https/HTTPRequestResponse.h b/host/frontend/gcastv2/https/include/https/HTTPRequestResponse.h
deleted file mode 100644
index e353cbc..0000000
--- a/host/frontend/gcastv2/https/include/https/HTTPRequestResponse.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2019 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 <cstdint>
-#include <map>
-#include <string>
-#include <string_view>
-
-struct HTTPRequestResponse {
-    explicit HTTPRequestResponse();
-    virtual ~HTTPRequestResponse() = default;
-
-    HTTPRequestResponse(const HTTPRequestResponse &) = delete;
-    HTTPRequestResponse &operator=(const HTTPRequestResponse &) = delete;
-
-    int setTo(const uint8_t *data, size_t size);
-    int initCheck() const;
-
-    bool getHeaderField(std::string_view key, std::string *value) const;
-
-    size_t getContentLength() const;
-
-protected:
-    virtual bool parseRequestResponseLine(const std::string &line) = 0;
-
-private:
-    struct CaseInsensitiveCompare {
-        bool operator()(const std::string &a, const std::string &b) const {
-            return strcasecmp(a.c_str(), b.c_str()) < 0;
-        }
-    };
-
-    int mInitCheck;
-
-    size_t mContentLength;
-
-    std::map<std::string, std::string, CaseInsensitiveCompare> mHeaders;
-};
-
-struct HTTPRequest : public HTTPRequestResponse {
-    std::string getMethod() const;
-    std::string getPath() const;
-    std::string getVersion() const;
-
-protected:
-    bool parseRequestResponseLine(const std::string &line) override;
-
-private:
-    std::string mMethod;
-    std::string mPath;
-    std::string mVersion;
-};
-
-struct HTTPResponse : public HTTPRequestResponse {
-    std::string getVersion() const;
-    int32_t getStatusCode() const;
-    std::string getStatusMessage() const;
-
-protected:
-    bool parseRequestResponseLine(const std::string &line) override;
-
-private:
-    std::string mVersion;
-    std::string mStatusMessage;
-    int32_t mStatusCode;
-};
-
diff --git a/host/frontend/gcastv2/https/include/https/HTTPServer.h b/host/frontend/gcastv2/https/include/https/HTTPServer.h
deleted file mode 100644
index d003e87..0000000
--- a/host/frontend/gcastv2/https/include/https/HTTPServer.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/ServerSocket.h>
-#include <https/WebSocketHandler.h>
-
-#include <functional>
-#include <mutex>
-#include <optional>
-#include <string>
-#include <unordered_map>
-#include <variant>
-#include <vector>
-
-struct HTTPRequest;
-
-struct HTTPServer {
-    explicit HTTPServer(
-            std::shared_ptr<RunLoop> runLoop,
-            const char *iface = nullptr, // defaults to 0.0.0.0, i.e. INADDR_ANY
-            uint16_t port = 8443,
-            ServerSocket::TransportType transportType =
-                    ServerSocket::TransportType::TLS,
-            const std::optional<std::string> &certificate_pem_path =
-                    std::nullopt,
-            const std::optional<std::string> &private_key_pem_path =
-                    std::nullopt);
-
-    HTTPServer(const HTTPServer &) = delete;
-    HTTPServer &operator=(const HTTPServer &) = delete;
-
-    uint16_t getLocalPort() const;
-
-    void run();
-
-    // Returns true iff the client should close the connection.
-    bool handleSingleRequest(
-            ClientSocket *client, const uint8_t *data, size_t size, bool isEOS);
-
-    void addStaticFile(
-            const char *at,
-            const char *path,
-            std::optional<std::string> mimeType = std::nullopt);
-
-    void addStaticContent(
-            const char *at,
-            const void *data,
-            size_t size,
-            std::optional<std::string> mimeType = std::nullopt);
-
-    using WebSocketHandlerFactory =
-        std::function<std::pair<int32_t, std::shared_ptr<WebSocketHandler>>()>;
-
-    void addWebSocketHandlerFactory(
-            const char *at, WebSocketHandlerFactory factory);
-
-    std::optional<std::string> certificate_pem_path() const;
-    std::optional<std::string> private_key_pem_path() const;
-
-private:
-    struct StaticFileInfo {
-        std::variant<std::string, std::vector<uint8_t>> mPathOrContent;
-        std::optional<std::string> mMimeType;
-    };
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    uint16_t mLocalPort;
-
-    std::shared_ptr<ServerSocket> mSocketTLS;
-
-    // Protects mStaticFiles and mWebSocketHandlerFactories below.
-    std::mutex mContentLock;
-
-    std::unordered_map<std::string, StaticFileInfo> mStaticFiles;
-
-    std::unordered_map<std::string, WebSocketHandlerFactory>
-        mWebSocketHandlerFactories;
-
-    void handleWebSocketRequest(
-            ClientSocket *clientSocket,
-            WebSocketHandlerFactory factory,
-            const HTTPRequest &request,
-            int32_t *httpResultCode,
-            std::unordered_map<std::string, std::string> *responseHeaders,
-            std::string *body);
-
-    void handleStaticFileRequest(
-            const StaticFileInfo &info,
-            const HTTPRequest &request,
-            int32_t *httpResultCode,
-            std::unordered_map<std::string, std::string> *responseHeaders,
-            std::string *body);
-
-    static std::string GuessMimeType(const std::string &path);
-};
diff --git a/host/frontend/gcastv2/https/include/https/PlainSocket.h b/host/frontend/gcastv2/https/include/https/PlainSocket.h
deleted file mode 100644
index 634c5a7..0000000
--- a/host/frontend/gcastv2/https/include/https/PlainSocket.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/BufferedSocket.h>
-
-struct PlainSocket : public BufferedSocket {
-    explicit PlainSocket(std::shared_ptr<RunLoop> rl, int sock);
-
-    PlainSocket(const PlainSocket &) = delete;
-    PlainSocket &operator=(const PlainSocket &) = delete;
-
-    void postRecv(RunLoop::AsyncFunction fn) override;
-    void postSend(RunLoop::AsyncFunction fn) override;
-
-    ssize_t recvfrom(
-            void *data,
-            size_t size,
-            sockaddr *address,
-            socklen_t *addressLen) override;
-
-    ssize_t sendto(
-            const void *data,
-            size_t size,
-            const sockaddr *addr,
-            socklen_t addrLen) override;
-
-    void postFlush(RunLoop::AsyncFunction fn) override;
-};
diff --git a/host/frontend/gcastv2/https/include/https/RunLoop.h b/host/frontend/gcastv2/https/include/https/RunLoop.h
deleted file mode 100644
index 7987cde..0000000
--- a/host/frontend/gcastv2/https/include/https/RunLoop.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2019 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 <atomic>
-#include <chrono>
-#include <deque>
-#include <functional>
-#include <map>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <poll.h>
-#include <string>
-#include <string_view>
-#include <thread>
-#include <vector>
-
-#include <sys/select.h>
-
-struct MainRunLoop;
-
-struct RunLoop {
-    explicit RunLoop(std::string_view name);
-    ~RunLoop();
-
-    static std::shared_ptr<RunLoop> main();
-
-    // For public use on the main RunLoop only.
-    void stop();
-    void run();
-
-    RunLoop(const RunLoop &) = delete;
-    RunLoop &operator=(const RunLoop &) = delete;
-
-    typedef std::function<void()> AsyncFunction;
-    typedef int32_t Token;
-
-    Token post(AsyncFunction fn);
-    // Post a callback to the run loop and wait for it to be executed. Returns
-    // whether it actually waited for the execution to happen (if posted from
-    // the same run loop's thread it won't wait to avoid a deadlock).
-    // WARNING: This function can cause the calling thread to wait forever if
-    // the run loop is stopped.
-    bool postAndAwait(AsyncFunction fn);
-
-    Token postWithDelay(
-            std::chrono::steady_clock::duration delay, AsyncFunction fn);
-
-    // Returns true iff matching event was cancelled.
-    bool cancelToken(Token token);
-
-    void postSocketRecv(int sock, AsyncFunction fn);
-    void postSocketSend(int sock, AsyncFunction fn);
-    void cancelSocket(int sock);
-
-    bool isCurrentThread() const;
-
-private:
-    friend struct MainRunLoop;
-
-    struct QueueElem {
-        std::optional<std::chrono::steady_clock::time_point> mWhen;
-        AsyncFunction mFn;
-        Token mToken;
-
-        bool operator<=(const QueueElem &other) const;
-    };
-
-    struct SocketCallbacks {
-        AsyncFunction mRecvFn;
-        AsyncFunction mSendFn;
-        size_t mPollFdIndex;
-    };
-
-    enum class InfoType {
-        RECV,
-        SEND,
-        CANCEL,
-    };
-
-    struct AddSocketCallbackInfo {
-        int mSock;
-        InfoType mType;
-        AsyncFunction mFn;
-    };
-
-    std::string mName;
-
-    int mControlFds[2];
-
-    std::mutex mLock;
-    std::deque<QueueElem> mQueue;
-    std::vector<AddSocketCallbackInfo> mAddInfos;
-
-    std::atomic<bool> mDone;
-    std::thread mThread;
-    pthread_t mPThread;
-
-    std::atomic<Token> mNextToken;
-
-    explicit RunLoop();  // constructor for the main RunLoop.
-
-    void interrupt();
-    void insert(const QueueElem &elem);
-    void addPollFd_l(int sock);
-};
-
diff --git a/host/frontend/gcastv2/https/include/https/SSLSocket.h b/host/frontend/gcastv2/https/include/https/SSLSocket.h
deleted file mode 100644
index 7b204d8..0000000
--- a/host/frontend/gcastv2/https/include/https/SSLSocket.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <https/BufferedSocket.h>
-
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#include <openssl/pem.h>
-#include <openssl/ssl.h>
-
-#include <memory>
-
-struct SSLSocket
-    : public BufferedSocket,
-      public std::enable_shared_from_this<SSLSocket> {
-    static void Init();
-
-    enum {
-        // Client only.
-        FLAG_DONT_CHECK_PEER_CERTIFICATE = 1,
-    };
-
-    explicit SSLSocket(
-            std::shared_ptr<RunLoop> rl,
-            int sock,
-            const std::string &certificate_pem_path,
-            const std::string &private_key_pem_path,
-            uint32_t flags = 0);
-
-    explicit SSLSocket(
-            std::shared_ptr<RunLoop> rl,
-            int sock,
-            uint32_t flags = 0,
-            const std::optional<std::string> &trusted_pem_path = std::nullopt);
-
-    ~SSLSocket() override;
-
-    SSLSocket(const SSLSocket &) = delete;
-    SSLSocket &operator=(const SSLSocket &) = delete;
-
-    void postRecv(RunLoop::AsyncFunction fn) override;
-    void postSend(RunLoop::AsyncFunction fn) override;
-
-    ssize_t recvfrom(
-            void *data,
-            size_t size,
-            sockaddr *address,
-            socklen_t *addressLen) override;
-
-    ssize_t sendto(
-            const void *data,
-            size_t size,
-            const sockaddr *addr,
-            socklen_t addrLen) override;
-
-    void postFlush(RunLoop::AsyncFunction fn) override;
-
-private:
-    enum class Mode {
-        CONNECT,
-        ACCEPT,
-    };
-
-    Mode mMode;
-    uint32_t mFlags;
-
-    std::unique_ptr<SSL_CTX, std::function<void(SSL_CTX *)>> mCtx;
-    std::unique_ptr<SSL, std::function<void(SSL *)>> mSSL;
-
-    // These are owned by the SSL object.
-    BIO *mBioR;
-    BIO *mBioW;
-
-    bool mEOS;
-    int mFinalErrno;
-
-    bool mRecvPending;
-    RunLoop::AsyncFunction mRecvCallback;
-
-    bool mSendPending;
-    std::vector<uint8_t> mOutBuffer;
-
-    // This is as yet unencrypted data that has yet to be submitted to SSL_write.
-    std::vector<uint8_t> mOutBufferPlain;
-
-    RunLoop::AsyncFunction mFlushFn;
-
-    explicit SSLSocket(
-            std::shared_ptr<RunLoop> rl, Mode mode, int sock, uint32_t flags);
-
-    void handleIncomingData();
-    void sendRecvCallback();
-
-    void queueOutputDataFromSSL();
-
-    void queueOutputData(const void *data, size_t size);
-    void sendOutputData();
-
-    void drainOutputBufferPlain();
-    bool isPeerCertificateValid();
-
-    static SSL_CTX *CreateSSLContext();
-
-    bool useCertificate(const std::string &path);
-    bool usePrivateKey(const std::string &path);
-    bool useTrustedCertificates(const std::string &path);
-};
diff --git a/host/frontend/gcastv2/https/include/https/SafeCallbackable.h b/host/frontend/gcastv2/https/include/https/SafeCallbackable.h
deleted file mode 100644
index 9e88813..0000000
--- a/host/frontend/gcastv2/https/include/https/SafeCallbackable.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2019 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 <memory>
-
-template<typename T>
-std::function<void()> makeSafeCallback(T *obj, std::function<void(T *)> f) {
-    auto weak_me = std::weak_ptr<T>(obj->shared_from_this());
-    return [f, weak_me]{
-        auto me = weak_me.lock();
-        if (me) {
-            f(me.get());
-        }
-    };
-}
-
-template<typename T, typename... Params>
-std::function<void()> makeSafeCallback(
-        T *obj, void (T::*f)(const Params&...), const Params&... params) {
-    return makeSafeCallback<T>(
-            obj,
-            [f, params...](T *me) {
-                (me->*f)(params...);
-            });
-}
-
-template<typename T, typename... Params>
-std::function<void()> makeSafeCallback(
-        T *obj, void (T::*f)(Params...), const Params&... params) {
-    return makeSafeCallback<T>(
-            obj,
-            [f, params...](T *me) {
-                (me->*f)(params...);
-            });
-}
diff --git a/host/frontend/gcastv2/https/include/https/ServerSocket.h b/host/frontend/gcastv2/https/include/https/ServerSocket.h
deleted file mode 100644
index d422a82..0000000
--- a/host/frontend/gcastv2/https/include/https/ServerSocket.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2019 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 <cstdint>
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-
-struct ClientSocket;
-struct HTTPServer;
-struct RunLoop;
-
-struct ServerSocket : public std::enable_shared_from_this<ServerSocket> {
-    enum class TransportType {
-        TCP,
-        TLS,
-    };
-
-    explicit ServerSocket(
-            HTTPServer *server,
-            TransportType transportType,
-            const char *iface,
-            uint16_t port,
-            const std::optional<std::string> &certificate_pem_path,
-            const std::optional<std::string> &private_key_pem_path);
-
-    ~ServerSocket();
-
-    ServerSocket(const ServerSocket &) = delete;
-    ServerSocket &operator=(const ServerSocket &) = delete;
-
-    int initCheck() const;
-
-    TransportType transportType() const;
-
-    int run(std::shared_ptr<RunLoop> rl);
-
-    void onClientSocketClosed(int sock);
-
-    std::optional<std::string> certificate_pem_path() const;
-    std::optional<std::string> private_key_pem_path() const;
-
-private:
-    int mInitCheck;
-    HTTPServer *mServer;
-    std::optional<std::string> mCertificatePath, mPrivateKeyPath;
-    int mSocket;
-    TransportType mTransportType;
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    std::vector<std::shared_ptr<ClientSocket>> mClientSockets;
-
-    void acceptIncomingConnection();
-};
-
diff --git a/host/frontend/gcastv2/https/include/https/Support.h b/host/frontend/gcastv2/https/include/https/Support.h
deleted file mode 100644
index 6ab5520..0000000
--- a/host/frontend/gcastv2/https/include/https/Support.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 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 <sys/types.h>
-
-#include <string>
-
-#ifdef NDEBUG
-#define DEBUG_ONLY(x)
-#else
-#define DEBUG_ONLY(x)   x
-#endif
-
-void makeFdNonblocking(int fd);
-void hexdump(const void *_data, size_t size);
-
-void encodeBase64(const void *_data, size_t size, std::string *out);
-
-uint16_t U16_AT(const uint8_t *ptr);
-uint32_t U32_AT(const uint8_t *ptr);
-uint64_t U64_AT(const uint8_t *ptr);
-
-uint16_t U16LE_AT(const uint8_t *ptr);
-uint32_t U32LE_AT(const uint8_t *ptr);
-uint64_t U64LE_AT(const uint8_t *ptr);
diff --git a/host/frontend/gcastv2/https/include/https/WebSocketHandler.h b/host/frontend/gcastv2/https/include/https/WebSocketHandler.h
deleted file mode 100644
index 7670876..0000000
--- a/host/frontend/gcastv2/https/include/https/WebSocketHandler.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 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 <arpa/inet.h>
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <string>
-#include <sys/types.h>
-
-struct ClientSocket;
-
-struct WebSocketHandler {
-    virtual ~WebSocketHandler() = default;
-
-    // Returns number bytes processed or error.
-    ssize_t handleRequest(uint8_t *data, size_t size, bool isEOS);
-
-    bool isConnected();
-
-    virtual void setClientSocket(std::weak_ptr<ClientSocket> client);
-
-    typedef std::function<void(const uint8_t *, size_t)> OutputCallback;
-    void setOutputCallback(const sockaddr_in &remoteAddr, OutputCallback fn);
-
-    enum class SendMode {
-        text,
-        binary,
-        closeConnection,
-    };
-    int sendMessage(
-            const void *data, size_t size, SendMode mode = SendMode::text);
-
-    std::string remoteHost() const;
-
-protected:
-    virtual int handleMessage(
-            uint8_t headerByte, const uint8_t *msg, size_t len) = 0;
-
-private:
-    std::weak_ptr<ClientSocket> mClientSocket;
-
-    OutputCallback mOutputCallback;
-    sockaddr_in mRemoteAddr;
-};
diff --git a/host/frontend/gcastv2/libsource/Android.bp b/host/frontend/gcastv2/libsource/Android.bp
deleted file mode 100644
index 671e4ba..0000000
--- a/host/frontend/gcastv2/libsource/Android.bp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2018 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.
-
-cc_library_host_static {
-    name: "libsource",
-    srcs: [
-        "AudioSource.cpp",
-        "InputSink.cpp",
-        "KeyboardSink.cpp",
-        "TouchSink.cpp",
-        "FrameBufferSource.cpp",
-        "HostToGuestComms.cpp",
-        "StreamingSource.cpp",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
-    shared_libs: [
-        "libbase",
-        "libyuv",
-        "libopus",
-        "libvpx",
-    ],
-    static_libs: [
-        "libcuttlefish_host_config",
-        "libgflags",
-        "libhttps",
-    ],
-    local_include_dirs: ["include"],
-    export_include_dirs: ["include"],
-    defaults: ["cuttlefish_host_only"],
-}
-
diff --git a/host/frontend/gcastv2/libsource/AudioSource.cpp b/host/frontend/gcastv2/libsource/AudioSource.cpp
deleted file mode 100644
index c3f40dd..0000000
--- a/host/frontend/gcastv2/libsource/AudioSource.cpp
+++ /dev/null
@@ -1,836 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <source/AudioSource.h>
-
-#include <libyuv/convert.h>
-
-#include <system/audio.h>
-
-#include "host/libs/config/cuttlefish_config.h"
-
-#include <opus.h>
-
-#include <gflags/gflags.h>
-#include <cmath>
-
-#define LOG_AUDIO       0
-
-namespace android {
-
-namespace {
-
-// These definitions are deleted in master, copying here temporarily
-typedef uint32_t size32_t;
-
-struct timespec32 {
-  uint32_t tv_sec;
-  uint32_t tv_nsec;
-
-  timespec32() = default;
-
-  timespec32(const timespec &from)
-      : tv_sec(from.tv_sec),
-        tv_nsec(from.tv_nsec) {
-  }
-};
-
-struct gce_audio_message {
-//  static const size32_t kMaxAudioFrameLen = 65536;
-  enum message_t {
-    UNKNOWN = 0,
-    DATA_SAMPLES = 1,
-    OPEN_INPUT_STREAM = 2,
-    OPEN_OUTPUT_STREAM = 3,
-    CLOSE_INPUT_STREAM = 4,
-    CLOSE_OUTPUT_STREAM = 5,
-    CONTROL_PAUSE = 100
-  };
-  // Size of the header + data. Used to frame when we're on TCP.
-  size32_t total_size;
-  // Size of the audio header
-  size32_t header_size;
-  message_t message_type;
-  // Identifier for the stream.
-  uint32_t stream_number;
-  // HAL assigned frame number, starts from 0.
-  int64_t frame_num;
-  // MONOTONIC_TIME when these frames were presented to the HAL.
-  timespec32 time_presented;
-  // Sample rate from the audio configuration.
-  uint32_t frame_rate;
-  // Channel mask from the audio configuration.
-  audio_channel_mask_t channel_mask;
-  // Format from the audio configuration.
-  audio_format_t format;
-  // Size of each frame in bytes.
-  size32_t frame_size;
-  // Number of frames that were presented to the HAL.
-  size32_t num_frames_presented;
-  // Number of frames that the HAL accepted.
-  //   For blocking audio this will be the same as num_frames.
-  //   For non-blocking audio this may be less.
-  size32_t num_frames_accepted;
-  // Count of the number of packets that were dropped because they would
-  // have blocked the HAL or exceeded the maximum message size.
-  size32_t num_packets_dropped;
-  // Count of the number of packets that were shortened to fit within
-  // kMaxAudioFrameLen.
-  size32_t num_packets_shortened;
-  // num_frames_presented (not num_frames_accepted) will follow here.
-
-  gce_audio_message() :
-      total_size(sizeof(gce_audio_message)),
-      header_size(sizeof(gce_audio_message)),
-      message_type(UNKNOWN),
-      stream_number(0),
-      frame_num(0),
-      frame_rate(0),
-      channel_mask(0),
-      format(AUDIO_FORMAT_DEFAULT),
-      frame_size(0),
-      num_frames_presented(0),
-      num_frames_accepted(0),
-      num_packets_dropped(0),
-      num_packets_shortened(0) {
-    time_presented.tv_sec = 0;
-    time_presented.tv_nsec = 0;
-  }
-};
-  
-}
-
-struct AudioSource::Encoder {
-    explicit Encoder();
-    virtual ~Encoder() = default;
-
-    virtual int32_t initCheck() const = 0;
-    virtual void encode(const void *data, size_t size) = 0;
-    virtual void reset() = 0;
-
-    void setFrameCallback(
-            std::function<void(const std::shared_ptr<SBuffer> &)> onFrameFn);
-
-protected:
-    std::function<void(const std::shared_ptr<SBuffer> &)> mOnFrameFn;
-};
-
-AudioSource::Encoder::Encoder()
-    : mOnFrameFn(nullptr) {
-}
-
-void AudioSource::Encoder::setFrameCallback(
-        std::function<void(const std::shared_ptr<SBuffer> &)> onFrameFn) {
-    mOnFrameFn = onFrameFn;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct Upsampler {
-    explicit Upsampler(int32_t from = 44100, int32_t to = 48000)
-        : mFrom(from),
-          mTo(to),
-          mCounter(0) {
-    }
-
-    void append(const int16_t *data, size_t numFrames) {
-        for (size_t i = 0; i < numFrames; ++i) {
-            int16_t l = *data++;
-            int16_t r = *data++;
-
-            mCounter += mTo;
-            while (mCounter >= mFrom) {
-                mCounter -= mFrom;
-
-                mBuffer.push_back(l);
-                mBuffer.push_back(r);
-            }
-        }
-    }
-
-    const int16_t *data() const { return mBuffer.data(); }
-
-    size_t numFramesAvailable() const { return mBuffer.size() / 2; }
-
-    void drain(size_t numFrames) {
-        CHECK_LE(numFrames, numFramesAvailable());
-
-        mBuffer.erase(mBuffer.begin(), mBuffer.begin() + numFrames * 2);
-    }
-
-private:
-    int32_t mFrom;
-    int32_t mTo;
-
-    std::vector<int16_t> mBuffer;
-
-    int32_t mCounter;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct AudioSource::OPUSEncoder : public AudioSource::Encoder {
-    explicit OPUSEncoder();
-    ~OPUSEncoder() override;
-
-    int32_t initCheck() const override;
-
-    OPUSEncoder(const OPUSEncoder &) = delete;
-    OPUSEncoder &operator=(const OPUSEncoder &) = delete;
-
-    void encode(const void *data, size_t size) override;
-    void reset() override;
-
-private:
-    int32_t mInitCheck;
-
-    gce_audio_message mPrevHeader;
-    bool mPrevHeaderValid;
-
-    size_t mChannelCount;
-
-    OpusEncoder *mImpl;
-
-    std::unique_ptr<Upsampler> mUpSampler;
-
-    FILE *mLogFile;
-};
-
-AudioSource::OPUSEncoder::OPUSEncoder()
-    : mInitCheck(-ENODEV),
-      mImpl(nullptr),
-      mLogFile(nullptr) {
-    reset();
-    mInitCheck = 0;
-}
-
-AudioSource::OPUSEncoder::~OPUSEncoder() {
-    reset();
-}
-
-int32_t AudioSource::OPUSEncoder::initCheck() const {
-    return mInitCheck;
-}
-
-void AudioSource::OPUSEncoder::reset() {
-    if (mLogFile != nullptr) {
-        fclose(mLogFile);
-        mLogFile = nullptr;
-    }
-
-    mUpSampler.reset();
-
-    if (mImpl) {
-        opus_encoder_destroy(mImpl);
-        mImpl = nullptr;
-    }
-
-    mPrevHeaderValid = false;
-    mChannelCount = 0;
-}
-
-void AudioSource::OPUSEncoder::encode(const void *_data, size_t size) {
-    auto data = static_cast<const uint8_t *>(_data);
-
-    CHECK_GE(size, sizeof(gce_audio_message));
-
-    gce_audio_message hdr;
-    std::memcpy(&hdr, data, sizeof(gce_audio_message));
-
-    if (hdr.message_type != gce_audio_message::DATA_SAMPLES) {
-        return;
-    }
-
-    static int64_t timeUs = 0;
-
-    static int64_t prevTimeUs = 0;
-
-    LOG(VERBOSE)
-        << "encode received "
-        << ((size - sizeof(gce_audio_message)) / (2 * sizeof(int16_t)))
-        << " frames, "
-        << " deltaTime = "
-        << (((timeUs - prevTimeUs) * hdr.frame_rate) / 1000000ll)
-        << " frames";
-
-    prevTimeUs = timeUs;
-
-    if (!mPrevHeaderValid
-            || mPrevHeader.frame_size != hdr.frame_size
-            || mPrevHeader.frame_rate != hdr.frame_rate
-            || mPrevHeader.stream_number != hdr.stream_number) {
-
-        if (mPrevHeaderValid) {
-            LOG(INFO)
-                << "Found audio data in a different configuration than before!"
-                << " frame_size="
-                << hdr.frame_size
-                << " vs. "
-                << mPrevHeader.frame_size
-                << ", frame_rate="
-                << hdr.frame_rate
-                << " vs. "
-                << mPrevHeader.frame_rate
-                << ", stream_number="
-                << hdr.stream_number
-                << " vs. "
-                << mPrevHeader.stream_number;
-
-            // reset?
-            return;
-        }
-
-        mPrevHeaderValid = true;
-        mPrevHeader = hdr;
-
-        const size_t numChannels = hdr.frame_size / sizeof(int16_t);
-
-#if LOG_AUDIO
-        mLogFile = fopen("/tmp/log_remote.opus", "wb");
-        CHECK(mLogFile != nullptr);
-#endif
-
-        LOG(INFO)
-            << "Calling opus_encoder_create w/ "
-            << "hdr.frame_rate = "
-            << hdr.frame_rate
-            << ", numChannels = "
-            << numChannels;
-
-        int err;
-        mImpl = opus_encoder_create(
-                48000,
-                numChannels,
-                OPUS_APPLICATION_AUDIO,
-                &err);
-
-        CHECK_EQ(err, OPUS_OK);
-
-        mChannelCount = numChannels;
-
-        static_assert(sizeof(int16_t) == sizeof(opus_int16));
-
-        err = opus_encoder_ctl(mImpl, OPUS_SET_INBAND_FEC(true));
-        CHECK_EQ(err, OPUS_OK);
-
-        err = opus_encoder_ctl(mImpl, OPUS_SET_PACKET_LOSS_PERC(10));
-        CHECK_EQ(err, OPUS_OK);
-
-        err = opus_encoder_ctl(
-                mImpl, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
-
-        CHECK_EQ(err, OPUS_OK);
-
-        CHECK_LE(hdr.frame_rate, 48000);
-        mUpSampler = std::make_unique<Upsampler>(hdr.frame_rate, 48000);
-    }
-
-    // {2.5, 5, 10, 20, 40, 60, 80, 100, 120} ms
-    static constexpr size_t kNumFramesPerOutputBuffer = 48 * 20;
-
-    const size_t offset = sizeof(gce_audio_message);
-    mUpSampler->append(
-            reinterpret_cast<const int16_t *>(&data[offset]),
-            (size - offset) / (mChannelCount * sizeof(int16_t)));
-
-    while (mUpSampler->numFramesAvailable() >= kNumFramesPerOutputBuffer) {
-        size_t copyFrames =
-            std::min(mUpSampler->numFramesAvailable(),
-                    kNumFramesPerOutputBuffer);
-
-        static constexpr size_t kMaxPacketSize = 8192;
-
-        std::shared_ptr<SBuffer> outBuffer(new SBuffer(kMaxPacketSize));
-
-        auto outSize = opus_encode(
-                mImpl,
-                reinterpret_cast<const opus_int16 *>(mUpSampler->data()),
-                copyFrames,
-                outBuffer->data(),
-                outBuffer->capacity());
-
-        CHECK_GT(outSize, 0);
-
-        outBuffer->resize(outSize);
-
-        outBuffer->time_us(timeUs);
-
-        mUpSampler->drain(copyFrames);
-
-        timeUs += (copyFrames * 1000ll) / 48;
-
-#if LOG_AUDIO
-        fwrite(outBuffer->data(), 1, outBuffer->size(), mLogFile);
-        fflush(mLogFile);
-#endif
-
-        if (mOnFrameFn) {
-            mOnFrameFn(outBuffer);
-        }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct Downsampler {
-    explicit Downsampler(int32_t from = 44100, int32_t to = 8000)
-        : mFrom(from),
-          mTo(to),
-          mCounter(0) {
-    }
-
-    void append(const int16_t *data, size_t numFrames) {
-        for (size_t i = 0; i < numFrames; ++i) {
-            int16_t l = *data++;
-            int16_t r = *data++;
-
-            mCounter += mTo;
-            if (mCounter >= mFrom) {
-                mCounter -= mFrom;
-
-                auto mono = (l + r) / 2;
-                mBuffer.push_back(mono);
-            }
-        }
-    }
-
-    const int16_t *data() const { return mBuffer.data(); }
-
-    size_t numFramesAvailable() const { return mBuffer.size(); }
-
-    void drain(size_t numFrames) {
-        CHECK_LE(numFrames, numFramesAvailable());
-
-        mBuffer.erase(mBuffer.begin(), mBuffer.begin() + numFrames);
-    }
-
-private:
-    int32_t mFrom;
-    int32_t mTo;
-
-    std::vector<int16_t> mBuffer;
-
-    int32_t mCounter;
-};
-
-struct AudioSource::G711Encoder : public AudioSource::Encoder {
-    enum class Mode {
-        ALAW,
-        ULAW,
-    };
-
-    explicit G711Encoder(Mode mode);
-
-    int32_t initCheck() const override;
-
-    G711Encoder(const G711Encoder &) = delete;
-    G711Encoder &operator=(const G711Encoder &) = delete;
-
-    void encode(const void *data, size_t size) override;
-    void reset() override;
-
-private:
-    static constexpr size_t kNumFramesPerBuffer = 512;
-
-    int32_t mInitCheck;
-    Mode mMode;
-
-    gce_audio_message mPrevHeader;
-    bool mPrevHeaderValid;
-
-    size_t mChannelCount;
-
-    std::shared_ptr<SBuffer> mOutputFrame;
-    Downsampler mDownSampler;
-
-    void doEncode(const int16_t *src, size_t numFrames);
-};
-
-AudioSource::G711Encoder::G711Encoder(Mode mode)
-    : mInitCheck(-ENODEV),
-      mMode(mode) {
-    reset();
-    mInitCheck = 0;
-}
-
-int32_t AudioSource::G711Encoder::initCheck() const {
-    return mInitCheck;
-}
-
-void AudioSource::G711Encoder::reset() {
-    mPrevHeaderValid = false;
-    mChannelCount = 0;
-}
-
-void AudioSource::G711Encoder::encode(const void *_data, size_t size) {
-    auto data = static_cast<const uint8_t *>(_data);
-
-    CHECK_GE(size, sizeof(gce_audio_message));
-
-    gce_audio_message hdr;
-    std::memcpy(&hdr, data, sizeof(gce_audio_message));
-
-    if (hdr.message_type != gce_audio_message::DATA_SAMPLES) {
-        return;
-    }
-
-    static int64_t timeUs = 0;
-
-    static int64_t prevTimeUs = 0;
-
-    LOG(VERBOSE)
-        << "encode received "
-        << ((size - sizeof(gce_audio_message)) / (2 * sizeof(int16_t)))
-        << " frames, "
-        << " deltaTime = "
-        << ((timeUs - prevTimeUs) * 441) / 10000
-        << " frames";
-
-    prevTimeUs = timeUs;
-
-    if (!mPrevHeaderValid
-            || mPrevHeader.frame_size != hdr.frame_size
-            || mPrevHeader.frame_rate != hdr.frame_rate
-            || mPrevHeader.stream_number != hdr.stream_number) {
-
-        if (mPrevHeaderValid) {
-            LOG(INFO)
-                << "Found audio data in a different configuration than before!"
-                << " frame_size="
-                << hdr.frame_size
-                << " vs. "
-                << mPrevHeader.frame_size
-                << ", frame_rate="
-                << hdr.frame_rate
-                << " vs. "
-                << mPrevHeader.frame_rate
-                << ", stream_number="
-                << hdr.stream_number
-                << " vs. "
-                << mPrevHeader.stream_number;
-
-            // reset?
-            return;
-        }
-
-        mPrevHeaderValid = true;
-        mPrevHeader = hdr;
-
-        mChannelCount = hdr.frame_size / sizeof(int16_t);
-
-        // mono, 8-bit output samples.
-        mOutputFrame.reset(new SBuffer(kNumFramesPerBuffer));
-    }
-
-    const size_t offset = sizeof(gce_audio_message);
-    mDownSampler.append(
-            reinterpret_cast<const int16_t *>(&data[offset]),
-            (size - offset) / (mChannelCount * sizeof(int16_t)));
-
-    while (mDownSampler.numFramesAvailable() >= kNumFramesPerBuffer) {
-        doEncode(mDownSampler.data(), kNumFramesPerBuffer);
-
-        mOutputFrame->time_us(timeUs);
-
-        mDownSampler.drain(kNumFramesPerBuffer);
-
-        timeUs += (kNumFramesPerBuffer * 1000ll) / 8;
-
-        if (mOnFrameFn) {
-            mOnFrameFn(mOutputFrame);
-        }
-    }
-}
-
-static unsigned clz16(uint16_t x) {
-    unsigned n = 0;
-    if ((x & 0xff00) == 0) {
-        n += 8;
-        x <<= 8;
-    }
-    if ((x & 0xf000) == 0) {
-        n += 4;
-        x <<= 4;
-    }
-
-    static const unsigned kClzNibble[] = {
-        4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
-    };
-
-    return n + kClzNibble[n >> 12];
-}
-
-void AudioSource::G711Encoder::doEncode(const int16_t *src, size_t numFrames) {
-    switch (mMode) {
-        case Mode::ALAW:
-        {
-            uint8_t *dst = mOutputFrame->data();
-
-            for (size_t i = numFrames; i--;) {
-                uint16_t in = (*src++) >> 3;  // Convert from 16-bit to 13-bit.
-                uint8_t inverseSign = 0x80;
-
-                if (in & 0x8000) {
-                    in = ~in;
-                    inverseSign = 0x00;
-                }
-
-                auto numLeadingZeroes = clz16(in);
-                auto suffixLength = 16 - numLeadingZeroes;
-
-                static constexpr uint8_t kMask = 0x55;
-
-                if (suffixLength <= 5) {
-                    *dst++ = (((in >> 1) & 0x0f) | inverseSign) ^ kMask;
-                } else {
-                    auto shift = suffixLength - 5;
-                    auto abcd = (in >> shift) & 0x0f;
-                    *dst++ = (abcd | (shift << 4) | inverseSign) ^ kMask;
-                }
-            }
-            break;
-        }
-
-        case Mode::ULAW:
-        {
-            uint8_t *dst = mOutputFrame->data();
-
-            for (size_t i = numFrames; i--;) {
-                uint16_t in = (*src++) >> 2;  // Convert from 16-bit to 14-bit.
-                uint8_t inverseSign = 0x80;
-
-                if (in & 0x8000) {
-                    in = ~in;
-                    inverseSign = 0x00;
-                }
-
-                in += 33;
-
-                auto numLeadingZeroes = clz16(in);
-                auto suffixLength = 16 - numLeadingZeroes;
-
-                static constexpr uint8_t kMask = 0xff;
-
-                if (suffixLength <= 6) {
-                    *dst++ = (((in >> 1) & 0x0f) | inverseSign) ^ kMask;
-                } else {
-                    auto shift = suffixLength - 5;
-                    auto abcd = (in >> shift) & 0x0f;
-                    *dst++ = (abcd | ((shift - 1) << 4) | inverseSign) ^ kMask;
-                }
-            }
-            break;
-        }
-
-        default:
-            LOG(FATAL) << "Should not be here.";
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-AudioSource::AudioSource(Format format, bool useADTSFraming)
-    : mInitCheck(-ENODEV),
-      mState(STOPPED)
-#if SIMULATE_AUDIO
-      ,mPhase(0)
-#endif
-{
-    switch (format) {
-        case Format::OPUS:
-        {
-            CHECK(!useADTSFraming);
-            mEncoder.reset(new OPUSEncoder);
-            break;
-        }
-
-        case Format::G711_ALAW:
-        case Format::G711_ULAW:
-        {
-            CHECK(!useADTSFraming);
-
-            mEncoder.reset(
-                    new G711Encoder(
-                        (format == Format::G711_ALAW)
-                            ? G711Encoder::Mode::ALAW
-                            : G711Encoder::Mode::ULAW));
-            break;
-        }
-
-        default:
-            LOG(FATAL) << "Should not be here.";
-    }
-
-    mEncoder->setFrameCallback([this](const std::shared_ptr<SBuffer> &accessUnit) {
-        StreamingSource::onAccessUnit(accessUnit);
-    });
-
-    mInitCheck = 0;
-}
-
-AudioSource::~AudioSource() {
-    stop();
-}
-
-int32_t AudioSource::initCheck() const {
-    return mInitCheck;
-}
-
-int32_t AudioSource::start() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    if (mState != STOPPED) {
-        return 0;
-    }
-
-    mEncoder->reset();
-
-    mState = RUNNING;
-
-#if SIMULATE_AUDIO
-    mThread.reset(
-            new std::thread([this]{
-                auto startTime = std::chrono::steady_clock::now();
-
-                std::vector<uint8_t> raw(
-                        sizeof(gce_audio_message)
-                            + kNumFramesPerBuffer * kNumChannels * sizeof(int16_t));
-
-                gce_audio_message *buffer =
-                        reinterpret_cast<gce_audio_message *>(raw.data());
-
-                buffer->message_type = gce_audio_message::DATA_SAMPLES;
-                buffer->frame_size = kNumChannels * sizeof(int16_t);
-                buffer->frame_rate = kSampleRate;
-                buffer->stream_number = 0;
-
-                const double k = (double)kFrequency / kSampleRate * (2.0 * M_PI);
-
-                while (mState != STOPPING) {
-                    std::chrono::microseconds durationSinceStart(
-                            (mPhase  * 1000000ll) / kSampleRate);
-
-                    auto time = startTime + durationSinceStart;
-                    auto now = std::chrono::steady_clock::now();
-                    auto delayUs = std::chrono::duration_cast<
-                            std::chrono::microseconds>(time - now).count();
-
-                    if (delayUs > 0) {
-                        usleep(delayUs);
-                    }
-
-                    auto usSinceStart =
-                        std::chrono::duration_cast<std::chrono::microseconds>(
-                                std::chrono::steady_clock::now() - startTime).count();
-
-                    buffer->time_presented.tv_sec = usSinceStart / 1000000ll;
-
-                    buffer->time_presented.tv_nsec =
-                        (usSinceStart % 1000000ll) * 1000;
-
-                    int16_t *ptr =
-                        reinterpret_cast<int16_t *>(
-                                raw.data() + sizeof(gce_audio_message));
-
-                    double x = mPhase * k;
-                    for (size_t i = 0; i < kNumFramesPerBuffer; ++i) {
-                        int16_t amplitude = (int16_t)(32767.0 * sin(x));
-
-                        *ptr++ = amplitude;
-                        if (kNumChannels == 2) {
-                            *ptr++ = amplitude;
-                        }
-
-                        x += k;
-                    }
-
-                    mEncoder->encode(raw.data(), raw.size());
-
-                    mPhase += kNumFramesPerBuffer;
-                }
-            }));
-#else
-/*
-    if (mRegionView) {
-        mThread.reset(
-                new std::thread([this]{
-                    while (mState != STOPPING) {
-                        uint8_t buffer[4096];
-
-                        struct timespec absTimeLimit;
-                        vsoc::RegionView::GetFutureTime(
-                                1000000000ll ns_from_now, &absTimeLimit);
-
-                        intptr_t res = mRegionView->data()->audio_queue.Read(
-                                mRegionView,
-                                reinterpret_cast<char *>(buffer),
-                                sizeof(buffer),
-                                &absTimeLimit);
-
-                        if (res < 0) {
-                            if (res == -ETIMEDOUT) {
-                                LOG(VERBOSE) << "AudioSource read timed out";
-                            }
-                            continue;
-                        }
-
-                        if (mState == RUNNING) {
-                            mEncoder->encode(buffer, static_cast<size_t>(res));
-                        }
-                    }
-            }));
-    }
-    */
-#endif  // SIMULATE_AUDIO
-
-    return 0;
-}
-
-int32_t AudioSource::stop() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    if (mState == STOPPED) {
-        return 0;
-    }
-
-    mState = STOPPING;
-
-    if (mThread) {
-        mThread->join();
-        mThread.reset();
-    }
-
-    mState = STOPPED;
-
-    return 0;
-}
-
-int32_t AudioSource::requestIDRFrame() {
-    return 0;
-}
-
-void AudioSource::inject(const void *data, size_t size) {
-    // Only used in the case of CrosVM operation.
-
-    std::lock_guard<std::mutex> autoLock(mLock);
-    if (mState != State::RUNNING) {
-        return;
-    }
-
-    mEncoder->encode(static_cast<const uint8_t *>(data), size);
-}
-
-}  // namespace android
diff --git a/host/frontend/gcastv2/libsource/FrameBufferSource.cpp b/host/frontend/gcastv2/libsource/FrameBufferSource.cpp
deleted file mode 100644
index 9b742cc..0000000
--- a/host/frontend/gcastv2/libsource/FrameBufferSource.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <source/FrameBufferSource.h>
-
-#include <algorithm>
-#include <chrono>
-
-#include <libyuv/convert.h>
-
-#include "host/libs/config/cuttlefish_config.h"
-
-#include "vpx/vpx_encoder.h"
-#include "vpx/vpx_codec.h"
-#include "vpx/vp8cx.h"
-
-#include <gflags/gflags.h>
-
-#define ENABLE_LOGGING          0
-
-namespace android {
-
-namespace {
-    int64_t GetNowUs() {
-        auto now = std::chrono::steady_clock::now().time_since_epoch();
-        return std::chrono::duration_cast<std::chrono::microseconds>(now).count();
-    }
-}
-
-struct FrameBufferSource::Encoder {
-    Encoder() = default;
-    virtual ~Encoder() = default;
-
-    virtual void forceIDRFrame() = 0;
-    virtual bool isForcingIDRFrame() const = 0;
-
-    virtual void storeFrame(const void* frame) = 0;
-    virtual std::shared_ptr<SBuffer> encodeStoredFrame(int64_t timeUs) = 0;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct FrameBufferSource::VPXEncoder : public FrameBufferSource::Encoder {
-    VPXEncoder(int width, int height, int rateHz);
-    ~VPXEncoder() override;
-
-    void forceIDRFrame() override;
-    bool isForcingIDRFrame() const override;
-
-    void storeFrame(const void* frame) override;
-    std::shared_ptr<SBuffer> encodeStoredFrame(int64_t timeUs) override;
-
-private:
-    int mWidth, mHeight, mRefreshRateHz;
-
-    int mSizeY, mSizeUV;
-    void *mI420Data;
-
-    vpx_codec_iface_t *mCodecInterface;
-    std::unique_ptr<vpx_codec_enc_cfg_t> mCodecConfiguration;
-
-    using contextFreeFunc = std::function<vpx_codec_err_t(vpx_codec_ctx_t *)>;
-    std::unique_ptr<vpx_codec_ctx_t, contextFreeFunc> mCodecContext;
-
-    std::atomic<bool> mForceIDRFrame;
-    bool mFirstFrame;
-    bool mStoredFrame;
-    int64_t mLastTimeUs;
-};
-
-static int GetCPUCoreCount() {
-    int cpuCoreCount;
-
-#if defined(_SC_NPROCESSORS_ONLN)
-    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
-#else
-    // _SC_NPROC_ONLN must be defined...
-    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
-#endif
-
-    CHECK_GE(cpuCoreCount, 1);
-    return cpuCoreCount;
-}
-
-FrameBufferSource::VPXEncoder::VPXEncoder(int width, int height, int rateHz)
-    : mWidth(width),
-      mHeight(height),
-      mRefreshRateHz(rateHz),
-      mCodecContext(nullptr, vpx_codec_destroy),
-      mForceIDRFrame(false),
-      mFirstFrame(true),
-      mStoredFrame(false),
-      mLastTimeUs(0) {
-
-    CHECK((width & 1) == 0);
-    CHECK((height & 1) == 0);
-    mSizeY = width * height;
-    mSizeUV = (width / 2) * (height / 2);
-    size_t totalSize = mSizeY + 2 * mSizeUV;
-    mI420Data = malloc(totalSize);
-
-    mCodecInterface = vpx_codec_vp8_cx();
-    mCodecConfiguration = std::make_unique<vpx_codec_enc_cfg_t>();
-
-    auto res = vpx_codec_enc_config_default(
-            mCodecInterface, mCodecConfiguration.get(), 0 /* usage */);
-
-    mCodecConfiguration->g_w = width;
-    mCodecConfiguration->g_h = height;
-    mCodecConfiguration->g_threads = std::min(GetCPUCoreCount(), 64);
-    mCodecConfiguration->g_error_resilient = false;
-    mCodecConfiguration->g_timebase.num = 1;
-    mCodecConfiguration->g_timebase.den = 1000000;
-    mCodecConfiguration->rc_target_bitrate = 2500;  // This appears to match x264
-    mCodecConfiguration->rc_end_usage = VPX_VBR;
-    mCodecConfiguration->rc_dropframe_thresh = 0;
-    mCodecConfiguration->g_lag_in_frames = 0;
-
-    mCodecConfiguration->g_profile = 0;
-
-    CHECK_EQ(res, VPX_CODEC_OK);
-
-    mCodecContext.reset(new vpx_codec_ctx_t);
-
-    res = vpx_codec_enc_init(
-            mCodecContext.get(),
-            mCodecInterface,
-            mCodecConfiguration.get(),
-            0 /* flags */);
-
-    CHECK_EQ(res, VPX_CODEC_OK);
-
-    res = vpx_codec_control(mCodecContext.get(), VP8E_SET_TOKEN_PARTITIONS, 0);
-    CHECK_EQ(res, VPX_CODEC_OK);
-}
-
-FrameBufferSource::VPXEncoder::~VPXEncoder() {
-    free(mI420Data);
-    mI420Data = nullptr;
-}
-
-void FrameBufferSource::VPXEncoder::forceIDRFrame() {
-    mForceIDRFrame = true;
-}
-
-bool FrameBufferSource::VPXEncoder::isForcingIDRFrame() const {
-    return mForceIDRFrame;
-}
-
-void FrameBufferSource::VPXEncoder::storeFrame(const void *frame) {
-    uint8_t *yPlane = static_cast<uint8_t *>(mI420Data);
-    uint8_t *uPlane = yPlane + mSizeY;
-    uint8_t *vPlane = uPlane + mSizeUV;
-
-    libyuv::ABGRToI420(
-            static_cast<const uint8_t *>(frame),
-            mWidth * 4,
-            yPlane,
-            mWidth,
-            uPlane,
-            mWidth / 2,
-            vPlane,
-            mWidth / 2,
-            mWidth,
-            mHeight);
-    mStoredFrame = true;
-}
-
-std::shared_ptr<SBuffer> FrameBufferSource::VPXEncoder::encodeStoredFrame(
-        int64_t timeUs) {
-    if (!mStoredFrame) {
-        return nullptr;
-    }
-    vpx_image_t raw_frame;
-    vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
-                 2 /* stride_align */,
-                 reinterpret_cast<unsigned char *>(mI420Data));
-
-    vpx_enc_frame_flags_t flags = 0;
-
-    if (mForceIDRFrame.exchange(false)) {
-        flags |= VPX_EFLAG_FORCE_KF;
-    }
-
-    uint32_t frameDuration;
-
-    if (!mFirstFrame) {
-        frameDuration = timeUs - mLastTimeUs;
-    } else {
-        frameDuration = 1000000 / mRefreshRateHz;
-        mFirstFrame = false;
-    }
-
-    mLastTimeUs = timeUs;
-
-    auto res = vpx_codec_encode(
-            mCodecContext.get(),
-            &raw_frame,
-            timeUs,
-            frameDuration,
-            flags,
-            VPX_DL_REALTIME);
-
-    if (res != VPX_CODEC_OK) {
-        LOG(ERROR) << "vpx_codec_encode failed w/ " << res;
-        return nullptr;
-    }
-
-    vpx_codec_iter_t iter = nullptr;
-    const vpx_codec_cx_pkt_t *packet;
-
-    std::shared_ptr<SBuffer> accessUnit;
-
-    while ((packet = vpx_codec_get_cx_data(mCodecContext.get(), &iter)) !=
-            nullptr) {
-        if (packet->kind == VPX_CODEC_CX_FRAME_PKT) {
-            LOG(VERBOSE)
-                << "vpx_codec_encode returned packet of size "
-                << packet->data.frame.sz;
-
-            if (accessUnit != nullptr) {
-                LOG(ERROR)
-                    << "vpx_codec_encode returned more than one packet of "
-                        "compressed data!";
-
-                return nullptr;
-            }
-
-            accessUnit.reset(new SBuffer(packet->data.frame.sz));
-
-            memcpy(accessUnit->data(),
-                   packet->data.frame.buf,
-                   packet->data.frame.sz);
-
-            accessUnit->time_us(timeUs);
-        } else {
-            LOG(INFO)
-                << "vpx_codec_encode returned a packet of type "
-                << packet->kind;
-        }
-    }
-
-    return accessUnit;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-FrameBufferSource::FrameBufferSource(Format format)
-    : mInitCheck(-ENODEV),
-      mState(STOPPED),
-      mFormat(format),
-      mScreenWidth(0),
-      mScreenHeight(0),
-      mScreenDpi(0),
-      mScreenRate(0),
-      mNumConsumers(0),
-      mOnFrameFn(nullptr) {
-    mInitCheck = 0;
-}
-
-FrameBufferSource::~FrameBufferSource() {
-    stop();
-}
-
-int32_t FrameBufferSource::initCheck() const {
-    return mInitCheck;
-}
-
-int32_t FrameBufferSource::start() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    if (mState != STOPPED) {
-        return 0;
-    }
-
-    switch (mFormat) {
-        case Format::VP8:
-        {
-            mEncoder.reset(
-                    new VPXEncoder(mScreenWidth, mScreenHeight, mScreenRate));
-
-            break;
-        }
-
-        default:
-            LOG(FATAL) << "Should not be here.";
-    }
-
-    mState = RUNNING;
-
-    return 0;
-}
-
-int32_t FrameBufferSource::stop() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    if (mState == STOPPED) {
-        return 0;
-    }
-
-    mState = STOPPING;
-
-    mState = STOPPED;
-
-    mEncoder.reset();
-
-    return 0;
-}
-
-int32_t FrameBufferSource::pause() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    if (mState == PAUSED) {
-        return 0;
-    }
-
-    if (mState != RUNNING) {
-        return -EINVAL;
-    }
-
-    mState = PAUSED;
-
-    LOG(VERBOSE) << "Now paused.";
-
-    return 0;
-}
-
-int32_t FrameBufferSource::resume() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-
-    if (mState == RUNNING) {
-        return 0;
-    }
-
-    if (mState != PAUSED) {
-        return -EINVAL;
-    }
-
-    mState = RUNNING;
-
-    LOG(VERBOSE) << "Now running.";
-
-    return 0;
-}
-
-bool FrameBufferSource::paused() const {
-    return mState == PAUSED;
-}
-
-int32_t FrameBufferSource::requestIDRFrame() {
-    mEncoder->forceIDRFrame();
-
-    return 0;
-}
-
-void FrameBufferSource::setScreenParams(const int32_t screenParams[4]) {
-    mScreenWidth = screenParams[0];
-    mScreenHeight = screenParams[1];
-    mScreenDpi = screenParams[2];
-    mScreenRate = screenParams[3];
-}
-
-void FrameBufferSource::injectFrame(const void *data, size_t size) {
-    // Only used in the case of CrosVM operation.
-    (void)size;
-
-    std::lock_guard<std::mutex> autoLock(mLock);
-    if (mState != State::RUNNING) {
-        return;
-    }
-
-    mEncoder->storeFrame(data);
-    // Only encode and forward the frame when there are consumers connected
-    if (mNumConsumers) {
-        auto accessUnit = mEncoder->encodeStoredFrame(GetNowUs());
-        StreamingSource::onAccessUnit(accessUnit);
-    }
-}
-
-void FrameBufferSource::notifyNewStreamConsumer() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-    ++mNumConsumers;
-    if (mState != State::RUNNING) {
-        return;
-    }
-
-    mEncoder->forceIDRFrame();
-    auto accessUnit = mEncoder->encodeStoredFrame(GetNowUs());
-    if (!accessUnit) {
-        // nullptr means there isn't a stored frame to encode.
-        return;
-    }
-
-    StreamingSource::onAccessUnit(accessUnit);
-}
-
-void FrameBufferSource::notifyStreamConsumerDisconnected() {
-    std::lock_guard<std::mutex> autoLock(mLock);
-    --mNumConsumers;
-}
-
-}  // namespace android
diff --git a/host/frontend/gcastv2/libsource/HostToGuestComms.cpp b/host/frontend/gcastv2/libsource/HostToGuestComms.cpp
deleted file mode 100644
index 44b9b5b..0000000
--- a/host/frontend/gcastv2/libsource/HostToGuestComms.cpp
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <source/HostToGuestComms.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-#include <android-base/logging.h>
-
-HostToGuestComms::HostToGuestComms(
-        std::shared_ptr<RunLoop> runLoop,
-        bool isServer,
-        int fd,
-        ReceiveCb onReceive)
-    : mRunLoop(runLoop),
-      mIsServer(isServer),
-      mOnReceive(onReceive),
-      mServerSock(-1),
-      mSock(-1),
-      mInBufferLen(0),
-      mSendPending(false),
-      mConnected(false) {
-    makeFdNonblocking(fd);
-    if (mIsServer) {
-        mServerSock = fd;
-    } else {
-        mSock = fd;
-    }
-}
-
-HostToGuestComms::HostToGuestComms(
-        std::shared_ptr<RunLoop> runLoop,
-        bool isServer,
-        uint32_t cid,
-        uint16_t port,
-        ReceiveCb onReceive)
-    : mRunLoop(runLoop),
-      mIsServer(isServer),
-      mOnReceive(onReceive),
-      mServerSock(-1),
-      mSock(-1),
-      mInBufferLen(0),
-      mSendPending(false),
-      mConnected(false) {
-    int s = socket(AF_VSOCK, SOCK_STREAM, 0);
-    CHECK_GE(s, 0);
-
-    LOG(INFO) << "HostToGuestComms created socket " << s;
-
-    makeFdNonblocking(s);
-
-    sockaddr_vm addr;
-    memset(&addr, 0, sizeof(addr));
-    addr.svm_family = AF_VSOCK;
-    addr.svm_port = port;
-    addr.svm_cid = cid;
-
-    int res;
-    if (mIsServer) {
-        LOG(INFO)
-            << "Binding to cid "
-            << (addr.svm_cid == VMADDR_CID_ANY)
-                    ? "VMADDR_CID_ANY" : std::to_string(addr.svm_cid);
-
-        res = bind(s, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr));
-
-        if (res) {
-            LOG(ERROR)
-                << (mIsServer ? "bind" : "connect")
-                << " FAILED w/ errno "
-                << errno
-                << " ("
-                << strerror(errno)
-                << ")";
-        }
-
-        CHECK(!res);
-
-        res = listen(s, 4);
-        CHECK(!res);
-
-        mServerSock = s;
-    } else {
-        mSock = s;
-        mConnectToAddr = addr;
-    }
-}
-
-HostToGuestComms::~HostToGuestComms() {
-    if (mSock >= 0) {
-        mRunLoop->cancelSocket(mSock);
-
-        close(mSock);
-        mSock = -1;
-    }
-
-    if (mServerSock >= 0) {
-        mRunLoop->cancelSocket(mServerSock);
-
-        close(mServerSock);
-        mServerSock = -1;
-    }
-}
-
-void HostToGuestComms::start() {
-    if (mIsServer) {
-        mRunLoop->postSocketRecv(
-                mServerSock,
-                makeSafeCallback(this, &HostToGuestComms::onServerConnection));
-    } else {
-        mRunLoop->postWithDelay(
-                std::chrono::milliseconds(5000), 
-                makeSafeCallback(
-                    this,
-                    &HostToGuestComms::onAttemptToConnect,
-                    mConnectToAddr));
-    }
-}
-
-void HostToGuestComms::send(const void *data, size_t size, bool addFraming) {
-    if (!size) {
-        return;
-    }
-
-    std::lock_guard autoLock(mLock);
-
-    size_t offset = mOutBuffer.size();
-
-    if (addFraming) {
-        uint32_t packetLen = size;
-        size_t totalSize = sizeof(packetLen) + size;
-
-        mOutBuffer.resize(offset + totalSize);
-        memcpy(mOutBuffer.data() + offset, &packetLen, sizeof(packetLen));
-        memcpy(mOutBuffer.data() + offset + sizeof(packetLen), data, size);
-    } else {
-        mOutBuffer.resize(offset + size);
-        memcpy(mOutBuffer.data() + offset, data, size);
-    }
-
-    if (mSock >= 0 && (mIsServer || mConnected) && !mSendPending) {
-        mSendPending = true;
-        mRunLoop->postSocketSend(
-                mSock,
-                makeSafeCallback(this, &HostToGuestComms::onSocketSend));
-    }
-}
-
-void HostToGuestComms::onServerConnection() {
-    int s = accept(mServerSock, nullptr, nullptr);
-
-    if (s >= 0) {
-        if (mSock >= 0) {
-            LOG(INFO) << "Rejecting client, we already have one.";
-
-            // We already have a client.
-            close(s);
-            s = -1;
-        } else {
-            LOG(INFO) << "Accepted client socket " << s << ".";
-
-            makeFdNonblocking(s);
-
-            mSock = s;
-            mRunLoop->postSocketRecv(
-                    mSock,
-                    makeSafeCallback(this, &HostToGuestComms::onSocketReceive));
-
-            std::lock_guard autoLock(mLock);
-            if (!mOutBuffer.empty()) {
-                CHECK(!mSendPending);
-
-                mSendPending = true;
-                mRunLoop->postSocketSend(
-                        mSock,
-                        makeSafeCallback(
-                            this, &HostToGuestComms::onSocketSend));
-            }
-        }
-    }
-
-    mRunLoop->postSocketRecv(
-            mServerSock,
-            makeSafeCallback(this, &HostToGuestComms::onServerConnection));
-}
-
-void HostToGuestComms::onSocketReceive() {
-    ssize_t n;
-    for (;;) {
-        static constexpr size_t kChunkSize = 65536;
-
-        mInBuffer.resize(mInBufferLen + kChunkSize);
-
-        do {
-            n = recv(mSock, mInBuffer.data() + mInBufferLen, kChunkSize, 0);
-        } while (n < 0 && errno == EINTR);
-
-        if (n <= 0) {
-            break;
-        }
-
-        mInBufferLen += static_cast<size_t>(n);
-    }
-
-    int savedErrno = errno;
-
-    drainInBuffer();
-
-    if ((n < 0 && savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)
-            || n == 0) {
-        LOG(ERROR) << "Client is gone.";
-
-        // Client is gone.
-        mRunLoop->cancelSocket(mSock);
-
-        mSendPending = false;
-
-        close(mSock);
-        mSock = -1;
-        return;
-    }
-
-    mRunLoop->postSocketRecv(
-            mSock,
-            makeSafeCallback(this, &HostToGuestComms::onSocketReceive));
-}
-
-void HostToGuestComms::drainInBuffer() {
-    for (;;) {
-        uint32_t packetLen;
-
-        if (mInBufferLen < sizeof(packetLen)) {
-            return;
-        }
-
-        memcpy(&packetLen, mInBuffer.data(), sizeof(packetLen));
-
-        size_t totalLen = sizeof(packetLen) + packetLen;
-
-        if (mInBufferLen < totalLen) {
-            return;
-        }
-
-        if (mOnReceive) {
-            // LOG(INFO) << "Dispatching packet of size " << packetLen;
-
-            mOnReceive(mInBuffer.data() + sizeof(packetLen), packetLen);
-        }
-
-        mInBuffer.erase(mInBuffer.begin(), mInBuffer.begin() + totalLen);
-        mInBufferLen -= totalLen;
-    }
-}
-
-void HostToGuestComms::onSocketSend() {
-    std::lock_guard autoLock(mLock);
-
-    CHECK(mSendPending);
-    mSendPending = false;
-
-    if (mSock < 0) {
-        return;
-    }
-
-    ssize_t n;
-    while (!mOutBuffer.empty()) {
-        do {
-            n = ::send(mSock, mOutBuffer.data(), mOutBuffer.size(), 0);
-        } while (n < 0 && errno == EINTR);
-
-        if (n <= 0) {
-            break;
-        }
-
-        mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + n);
-    }
-
-    if ((n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || n == 0) {
-        LOG(ERROR) << "Client is gone.";
-
-        // Client is gone.
-        mRunLoop->cancelSocket(mSock);
-
-        close(mSock);
-        mSock = -1;
-        return;
-    }
-
-    if (!mOutBuffer.empty()) {
-        mSendPending = true;
-        mRunLoop->postSocketSend(
-                mSock,
-                makeSafeCallback(this, &HostToGuestComms::onSocketSend));
-    }
-}
-
-void HostToGuestComms::onAttemptToConnect(const sockaddr_vm &addr) {
-    LOG(VERBOSE) << "Attempting to connect to cid " << addr.svm_cid;
-
-    int res;
-    do {
-        res = connect(
-            mSock, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr));
-    } while (res < 0 && errno == EINTR);
-
-    if (res < 0) {
-        if (errno == EINPROGRESS) {
-            LOG(VERBOSE) << "EINPROGRESS, waiting to check the connection.";
-
-            mRunLoop->postSocketSend(
-                    mSock,
-                    makeSafeCallback(
-                        this, &HostToGuestComms::onCheckConnection, addr));
-
-            return;
-        }
-
-        LOG(INFO)
-            << "Our attempt to connect to the guest FAILED w/ error "
-            << errno
-            << " ("
-            << strerror(errno)
-            << "), will try again shortly.";
-
-        mRunLoop->postWithDelay(
-                std::chrono::milliseconds(5000),
-                makeSafeCallback(
-                    this, &HostToGuestComms::onAttemptToConnect, addr));
-
-        return;
-    }
-
-    onConnected();
-}
-
-void HostToGuestComms::onCheckConnection(const sockaddr_vm &addr) {
-    int err;
-
-    int res;
-    do {
-        socklen_t errSize = sizeof(err);
-
-        res = getsockopt(mSock, SOL_SOCKET, SO_ERROR, &err, &errSize);
-    } while (res < 0 && errno == EINTR);
-
-    CHECK(!res);
-
-    if (!err) {
-        onConnected();
-    } else {
-        LOG(VERBOSE)
-            << "Connection failed w/ error "
-            << err
-            << " ("
-            << strerror(err)
-            << "), will try again shortly.";
-
-        // Is there a better way of cancelling the (failed) connection that
-        // somehow is still in progress on the socket and restarting it?
-        mRunLoop->cancelSocket(mSock);
-
-        close(mSock);
-        mSock = socket(AF_VSOCK, SOCK_STREAM, 0);
-        CHECK_GE(mSock, 0);
-
-        makeFdNonblocking(mSock);
-
-        mRunLoop->postWithDelay(
-                std::chrono::milliseconds(5000),
-                makeSafeCallback(
-                    this, &HostToGuestComms::onAttemptToConnect, addr));
-    }
-}
-
-void HostToGuestComms::onConnected() {
-    LOG(INFO) << "Connected to guest.";
-
-    std::lock_guard autoLock(mLock);
-
-    mConnected = true;
-    CHECK(!mSendPending);
-
-    if (!mOutBuffer.empty()) {
-        mSendPending = true;
-        mRunLoop->postSocketSend(
-                mSock,
-                makeSafeCallback(this, &HostToGuestComms::onSocketSend));
-    }
-
-    mRunLoop->postSocketRecv(
-            mSock,
-            makeSafeCallback(this, &HostToGuestComms::onSocketReceive));
-}
-
diff --git a/host/frontend/gcastv2/libsource/InputSink.cpp b/host/frontend/gcastv2/libsource/InputSink.cpp
deleted file mode 100644
index ce9597d..0000000
--- a/host/frontend/gcastv2/libsource/InputSink.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <source/InputSink.h>
-
-#include <linux/input.h>
-
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <glog/logging.h>
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-namespace android {
-
-namespace {
-
-// TODO de-dup this from vnc server and here
-struct virtio_input_event {
-  uint16_t type;
-  uint16_t code;
-  int32_t value;
-};
-
-template <typename T>
-struct InputEventBufferImpl : public InputEventBuffer {
-  InputEventBufferImpl() {
-    buffer_.reserve(6);  // 6 is usually enough even for multi-touch
-  }
-  void addEvent(uint16_t type, uint16_t code, int32_t value) override {
-    buffer_.push_back({.type = type, .code = code, .value = value});
-  }
-  T* data() { return buffer_.data(); }
-  const void* data() const override { return buffer_.data(); }
-  std::size_t size() const override { return buffer_.size() * sizeof(T); }
-
- private:
-  std::vector<T> buffer_;
-};
-
-}  // namespace
-
-InputSink::InputSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
-                     bool write_virtio_input)
-    : mRunLoop(runLoop),
-      mServerFd(serverFd),
-      mClientFd(-1),
-      mSendPending(false),
-      mWriteVirtioInput(write_virtio_input) {
-  if (mServerFd >= 0) {
-    makeFdNonblocking(mServerFd);
-  }
-}
-
-InputSink::~InputSink() {
-  if (mClientFd >= 0) {
-    mRunLoop->cancelSocket(mClientFd);
-
-    close(mClientFd);
-    mClientFd = -1;
-  }
-
-  if (mServerFd >= 0) {
-    mRunLoop->cancelSocket(mServerFd);
-
-    close(mServerFd);
-    mServerFd = -1;
-  }
-}
-
-void InputSink::start() {
-  if (mServerFd < 0) {
-    return;
-  }
-
-  mRunLoop->postSocketRecv(
-      mServerFd, makeSafeCallback(this, &InputSink::onServerConnection));
-}
-
-std::unique_ptr<InputEventBuffer> InputSink::getEventBuffer() const {
-  InputEventBuffer* raw_ptr;
-  if (mWriteVirtioInput) {
-    raw_ptr = new InputEventBufferImpl<virtio_input_event>();
-  } else {
-    raw_ptr = new InputEventBufferImpl<input_event>();
-  }
-  return std::unique_ptr<InputEventBuffer>(raw_ptr);
-}
-
-void InputSink::SendEvents(std::unique_ptr<InputEventBuffer> evt_buffer) {
-  sendRawEvents(evt_buffer->data(), evt_buffer->size());
-}
-
-void InputSink::onServerConnection() {
-  int s = accept(mServerFd, nullptr, nullptr);
-
-  if (s >= 0) {
-    if (mClientFd >= 0) {
-      LOG(INFO) << "Rejecting client, we already have one.";
-
-      // We already have a client.
-      close(s);
-      s = -1;
-    } else {
-      LOG(INFO) << "Accepted client socket " << s << ".";
-
-      makeFdNonblocking(s);
-
-      mClientFd = s;
-      mRunLoop->postSocketRecv(
-        mClientFd, makeSafeCallback(this, &InputSink::onSocketRecv));
-    }
-  }
-
-  mRunLoop->postSocketRecv(
-      mServerFd, makeSafeCallback(this, &InputSink::onServerConnection));
-}
-
-void InputSink::sendRawEvents(const void* evt_buffer, size_t size) {
-  if (size <= 0) return;
-
-  std::lock_guard autoLock(mLock);
-
-  if (mClientFd < 0) {
-    return;
-  }
-
-  size_t offset = mOutBuffer.size();
-  mOutBuffer.resize(offset + size);
-  memcpy(mOutBuffer.data() + offset, evt_buffer, size);
-
-  if (!mSendPending) {
-    mSendPending = true;
-
-    mRunLoop->postSocketSend(mClientFd,
-                             makeSafeCallback(this, &InputSink::onSocketSend));
-  }
-}
-
-void InputSink::onSocketRecv() {
-  if (mClientFd < 0) return;
-
-  char buff[512];
-  auto n = recv(mClientFd, buff, sizeof(buff), 0 /* flags */);
-  if (n > 0) {
-    LOG(INFO) << "Discarding " << n << " bytes received from the input device.";
-    mRunLoop->postSocketRecv(
-        mClientFd, makeSafeCallback(this, &InputSink::onSocketRecv));
-  } else {
-    // Client disconnected
-    if (n < 0) {
-      auto errno_save = errno;
-      LOG(ERROR) << "Error receiving from socket: " << strerror(errno_save);
-    }
-    mRunLoop->cancelSocket(mClientFd);
-    close(mClientFd);
-    mClientFd = -1;
-  }
-}
-
-void InputSink::onSocketSend() {
-  std::lock_guard autoLock(mLock);
-
-  CHECK(mSendPending);
-  mSendPending = false;
-
-  if (mClientFd < 0) {
-    return;
-  }
-
-  ssize_t n;
-  while (!mOutBuffer.empty()) {
-    do {
-      n = ::send(mClientFd, mOutBuffer.data(), mOutBuffer.size(), 0);
-    } while (n < 0 && errno == EINTR);
-
-    if (n <= 0) {
-      break;
-    }
-
-    mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + n);
-  }
-
-  if ((n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || n == 0) {
-    LOG(ERROR) << "Client is gone.";
-
-    // Client is gone.
-    mRunLoop->cancelSocket(mClientFd);
-
-    close(mClientFd);
-    mClientFd = -1;
-    return;
-  }
-
-  if (!mOutBuffer.empty()) {
-    mSendPending = true;
-    mRunLoop->postSocketSend(mClientFd,
-                             makeSafeCallback(this, &InputSink::onSocketSend));
-  }
-}
-
-}  // namespace android
diff --git a/host/frontend/gcastv2/libsource/KeyboardSink.cpp b/host/frontend/gcastv2/libsource/KeyboardSink.cpp
deleted file mode 100644
index 526ade3..0000000
--- a/host/frontend/gcastv2/libsource/KeyboardSink.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-#include <source/KeyboardSink.h>
-
-#include <linux/input.h>
-
-#include <glog/logging.h>
-
-namespace android {
-
-KeyboardSink::KeyboardSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
-                           bool write_virtio_input)
-    : sink_(
-          std::make_shared<InputSink>(runLoop, serverFd, write_virtio_input)) {}
-
-void KeyboardSink::injectEvent(bool down, uint16_t code) {
-    LOG(VERBOSE)
-        << "Received keyboard (down="
-        << down
-        << ", code="
-        << code;
-    auto buffer = sink_->getEventBuffer();
-    buffer->addEvent(EV_KEY, code, down);
-    buffer->addEvent(EV_SYN, 0, 0);
-    sink_->SendEvents(std::move(buffer));
-}
-
-}  // namespace android
-
diff --git a/host/frontend/gcastv2/libsource/StreamingSource.cpp b/host/frontend/gcastv2/libsource/StreamingSource.cpp
deleted file mode 100644
index d96bf2b..0000000
--- a/host/frontend/gcastv2/libsource/StreamingSource.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <source/StreamingSource.h>
-
-namespace android {
-
-StreamingSource::StreamingSource()
-    : mCallbackFn(nullptr) {
-}
-
-void StreamingSource::setCallback(std::function<void(const std::shared_ptr<SBuffer> &)> cb) {
-    CHECK(cb);
-    mCallbackFn = cb;
-}
-
-void StreamingSource::onAccessUnit(const std::shared_ptr<SBuffer> &accessUnit) {
-    if (mCallbackFn) {
-        mCallbackFn(accessUnit);
-    }
-}
-
-}  // namespace android
diff --git a/host/frontend/gcastv2/libsource/TouchSink.cpp b/host/frontend/gcastv2/libsource/TouchSink.cpp
deleted file mode 100644
index a66744f..0000000
--- a/host/frontend/gcastv2/libsource/TouchSink.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <source/TouchSink.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-#include <android-base/logging.h>
-
-#include <linux/input.h>
-
-#include <sys/socket.h>
-#include <unistd.h>
-
-namespace android {
-
-TouchSink::TouchSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
-                     bool write_virtio_input)
-    : sink_(
-          std::make_shared<InputSink>(runLoop, serverFd, write_virtio_input)) {}
-
-void TouchSink::injectTouchEvent(int32_t x, int32_t y, bool down) {
-    LOG(VERBOSE)
-        << "Received touch (down="
-        << down
-        << ", x="
-        << x
-        << ", y="
-        << y;
-
-    auto buffer = sink_->getEventBuffer();
-    buffer->addEvent(EV_ABS, ABS_X, x);
-    buffer->addEvent(EV_ABS, ABS_Y, y);
-    buffer->addEvent(EV_KEY, BTN_TOUCH, down);
-    buffer->addEvent(EV_SYN, 0, 0);
-    sink_->SendEvents(std::move(buffer));
-}
-
-void TouchSink::injectMultiTouchEvent(int32_t /*id*/, int32_t /*slot*/,
-                                      int32_t x, int32_t y, bool initialDown) {
-  // TODO (muntsinger): Enable multitouch
-  return injectTouchEvent(x, y, initialDown);
-}
-
-}  // namespace android
-
diff --git a/host/frontend/gcastv2/libsource/include/source/AudioSource.h b/host/frontend/gcastv2/libsource/include/source/AudioSource.h
deleted file mode 100644
index 7c7771e..0000000
--- a/host/frontend/gcastv2/libsource/include/source/AudioSource.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2018, 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 <source/StreamingSource.h>
-
-#include <memory>
-#include <thread>
-
-#define SIMULATE_AUDIO          0
-
-namespace vsoc {
-    class RegionWorker;
-    namespace audio_data {
-        class AudioDataRegionView;
-    }
-}
-
-namespace android {
-
-struct AudioSource : public StreamingSource {
-    using AudioDataRegionView = vsoc::audio_data::AudioDataRegionView;
-
-    enum class Format {
-        OPUS,
-        G711_ALAW,
-        G711_ULAW,
-    };
-    // ADTS framing is only supported for AAC.
-    explicit AudioSource(Format format, bool useADTSFraming = false);
-
-    AudioSource(const AudioSource &) = delete;
-    AudioSource &operator=(const AudioSource &) = delete;
-
-    ~AudioSource() override;
-
-    int32_t initCheck() const override;
-
-    int32_t start() override;
-    int32_t stop() override;
-
-    int32_t requestIDRFrame() override;
-    void notifyNewStreamConsumer() override {}
-    void notifyStreamConsumerDisconnected() override {}
-
-    void inject(const void *data, size_t size);
-
-private:
-    enum State {
-        STOPPING,
-        STOPPED,
-        RUNNING,
-        PAUSED
-    };
-
-    struct Encoder;
-    struct OPUSEncoder;
-    struct G711Encoder;
-
-    int32_t mInitCheck;
-    State mState;
-    std::unique_ptr<Encoder> mEncoder;
-
-    std::mutex mLock;
-    std::unique_ptr<std::thread> mThread;
-
-#if SIMULATE_AUDIO
-    static constexpr int32_t kSampleRate = 44100;
-    static constexpr int32_t kNumChannels = 2;
-    static constexpr size_t kNumFramesPerBuffer = 400;
-    static constexpr int32_t kFrequency = 500;
-    size_t mPhase;
-#endif
-};
-
-}  // namespace android
-
-
diff --git a/host/frontend/gcastv2/libsource/include/source/FrameBufferSource.h b/host/frontend/gcastv2/libsource/include/source/FrameBufferSource.h
deleted file mode 100644
index 7990be4..0000000
--- a/host/frontend/gcastv2/libsource/include/source/FrameBufferSource.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2018, 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 <source/StreamingSource.h>
-
-#include <functional>
-#include <memory>
-#include <thread>
-
-namespace android {
-
-struct FrameBufferSource : public StreamingSource {
-    enum class Format {
-        VP8,
-    };
-
-    explicit FrameBufferSource(Format format);
-
-    FrameBufferSource(const FrameBufferSource &) = delete;
-    FrameBufferSource &operator=(const FrameBufferSource &) = delete;
-
-    ~FrameBufferSource() override;
-
-    int32_t initCheck() const override;
-
-    int32_t start() override;
-    int32_t stop() override;
-
-    int32_t pause() override;
-    int32_t resume() override;
-
-    bool paused() const override;
-
-    int32_t requestIDRFrame() override;
-    void notifyNewStreamConsumer() override;
-    void notifyStreamConsumerDisconnected() override;
-
-    void setScreenParams(const int32_t screenParams[4]);
-    void injectFrame(const void *data, size_t size);
-
-private:
-    enum State {
-        STOPPING,
-        STOPPED,
-        RUNNING,
-        PAUSED
-    };
-
-    struct Encoder;
-    struct VPXEncoder;
-
-    int32_t mInitCheck;
-    State mState;
-    Format mFormat;
-    std::unique_ptr<Encoder> mEncoder;
-
-    std::mutex mLock;
-
-    int32_t mScreenWidth, mScreenHeight, mScreenDpi, mScreenRate, mNumConsumers;
-
-    std::function<void(const std::shared_ptr<SBuffer> &)> mOnFrameFn;
-};
-
-}  // namespace android
-
-
diff --git a/host/frontend/gcastv2/libsource/include/source/HostToGuestComms.h b/host/frontend/gcastv2/libsource/include/source/HostToGuestComms.h
deleted file mode 100644
index 2325608..0000000
--- a/host/frontend/gcastv2/libsource/include/source/HostToGuestComms.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/RunLoop.h>
-
-#include <sys/socket.h>
-#include "common/libs/fs/vm_sockets.h"
-
-#include <memory>
-
-struct HostToGuestComms : std::enable_shared_from_this<HostToGuestComms> {
-    using ReceiveCb = std::function<void(const void *data, size_t size)>;
-
-    explicit HostToGuestComms(
-            std::shared_ptr<RunLoop> runLoop,
-            bool isServer,
-            uint32_t cid,
-            uint16_t port,
-            ReceiveCb onReceive);
-
-    explicit HostToGuestComms(
-            std::shared_ptr<RunLoop> runLoop,
-            bool isServer,
-            int fd,
-            ReceiveCb onReceive);
-
-    ~HostToGuestComms();
-
-    void start();
-
-    void send(const void *data, size_t size, bool addFraming = true);
-
-private:
-    std::shared_ptr<RunLoop> mRunLoop;
-    bool mIsServer;
-    ReceiveCb mOnReceive;
-
-    int mServerSock;
-    int mSock;
-    sockaddr_vm mConnectToAddr;
-
-    std::vector<uint8_t> mInBuffer;
-    size_t mInBufferLen;
-
-    std::mutex mLock;
-    std::vector<uint8_t> mOutBuffer;
-    bool mSendPending;
-
-    bool mConnected;
-
-    void onServerConnection();
-    void onSocketReceive();
-    void onSocketSend();
-    void drainInBuffer();
-
-    void onAttemptToConnect(const sockaddr_vm &addr);
-    void onCheckConnection(const sockaddr_vm &addr);
-    void onConnected();
-};
-
diff --git a/host/frontend/gcastv2/libsource/include/source/InputSink.h b/host/frontend/gcastv2/libsource/include/source/InputSink.h
deleted file mode 100644
index 38af13b..0000000
--- a/host/frontend/gcastv2/libsource/include/source/InputSink.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 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 <array>
-#include <cinttypes>
-#include <functional>
-#include <memory>
-#include <vector>
-
-#include <https/RunLoop.h>
-
-namespace android {
-
-struct InputEventBuffer {
-  virtual ~InputEventBuffer() = default;
-  virtual void addEvent(uint16_t type, uint16_t code, int32_t value) = 0;
-  virtual size_t size() const = 0;
-  virtual const void* data() const = 0;
-};
-
-struct InputSink : public std::enable_shared_from_this<InputSink> {
-  explicit InputSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
-                     bool write_virtio_input);
-  ~InputSink();
-  void start();
-
-  std::unique_ptr<InputEventBuffer> getEventBuffer() const;
-  void SendEvents(std::unique_ptr<InputEventBuffer> evt_buffer);
-
- private:
-  std::shared_ptr<RunLoop> mRunLoop;
-  int mServerFd;
-
-  int mClientFd;
-
-  std::mutex mLock;
-  std::vector<uint8_t> mOutBuffer;
-  bool mSendPending;
-  bool mWriteVirtioInput;
-
-  void onServerConnection();
-  void onSocketRecv();
-  void onSocketSend();
-
-  void sendRawEvents(const void* evt_buffer, size_t length);
-};
-
-}  // namespace android
diff --git a/host/frontend/gcastv2/libsource/include/source/KeyboardSink.h b/host/frontend/gcastv2/libsource/include/source/KeyboardSink.h
deleted file mode 100644
index cbc9936..0000000
--- a/host/frontend/gcastv2/libsource/include/source/KeyboardSink.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 <cinttypes>
-#include <memory>
-
-#include <https/RunLoop.h>
-#include <source/InputSink.h>
-
-namespace android {
-
-struct KeyboardSink {
-  explicit KeyboardSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
-                        bool write_virtio_input);
-  ~KeyboardSink() = default;
-
-  void start() {sink_->start();}
-
-  void injectEvent(bool down, uint16_t code);
-
- private:
-  std::shared_ptr<InputSink> sink_;
-};
-
-}  // namespace android
-
diff --git a/host/frontend/gcastv2/libsource/include/source/StreamingSource.h b/host/frontend/gcastv2/libsource/include/source/StreamingSource.h
deleted file mode 100644
index 27a30a4..0000000
--- a/host/frontend/gcastv2/libsource/include/source/StreamingSource.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2018, 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 <android-base/logging.h>
-
-#include <cinttypes>
-#include <memory>
-#include <vector>
-
-namespace android {
-
-class SBuffer {
-public:
-    SBuffer() = delete;
-    SBuffer(const SBuffer&) = delete;
-    SBuffer(SBuffer&&) = default;
-    explicit SBuffer(std::size_t size)
-        : buffer_(size, 0), time_us_(0) {}
-    
-    SBuffer& operator=(const SBuffer&) = delete;
-    SBuffer& operator=(SBuffer&&) = default;
-
-    std::size_t capacity() const {
-        return buffer_.capacity();
-    }
-
-    std::size_t size() const {
-        return buffer_.size();
-    }
-
-    void resize(std::size_t size) {
-        buffer_.resize(size);
-    }
-
-    uint8_t* data() {
-        return buffer_.data();
-    }
-    
-    const uint8_t* data() const {
-        return buffer_.data();
-    }
-
-    int64_t time_us() const {
-        return time_us_;
-    }
-
-    void time_us(int64_t time_us) {
-        time_us_ = time_us;
-    }
-private:
-    std::vector<uint8_t> buffer_;
-    int64_t time_us_;
-
-};
-
-struct StreamingSource {
-    explicit StreamingSource();
-
-    StreamingSource(const StreamingSource &) = delete;
-    StreamingSource &operator=(const StreamingSource &) = delete;
-
-    virtual ~StreamingSource() = default;
-
-    virtual int32_t initCheck() const = 0;
-
-    void setCallback(std::function<void(const std::shared_ptr<SBuffer> &)> cb);
-
-    virtual int32_t start() = 0;
-    virtual int32_t stop() = 0;
-
-    virtual bool canPause() { return false; }
-    virtual int32_t pause() { return -EINVAL; }
-    virtual int32_t resume() { return -EINVAL; }
-
-    virtual bool paused() const { return false; }
-
-    virtual int32_t requestIDRFrame() = 0;
-    virtual void notifyNewStreamConsumer() = 0;
-    virtual void notifyStreamConsumerDisconnected() = 0;
-
-protected:
-    void onAccessUnit(const std::shared_ptr<SBuffer> &accessUnit);
-
-private:
-    std::function<void(const std::shared_ptr<SBuffer> &)> mCallbackFn;
-};
-
-}  // namespace android
-
diff --git a/host/frontend/gcastv2/libsource/include/source/TouchSink.h b/host/frontend/gcastv2/libsource/include/source/TouchSink.h
deleted file mode 100644
index d4490f0..0000000
--- a/host/frontend/gcastv2/libsource/include/source/TouchSink.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/RunLoop.h>
-
-#include <memory>
-
-#include <source/InputSink.h>
-
-namespace android {
-
-struct TouchSink {
-    explicit TouchSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
-                       bool write_virtio_input);
-    ~TouchSink() = default;
-
-    void start() {sink_->start();}
-
-    void injectTouchEvent(int32_t x, int32_t y, bool down);
-    void injectMultiTouchEvent(int32_t id, int32_t slot, int32_t x, int32_t y,
-                               bool initialDown);
-
-   private:
-    std::shared_ptr<InputSink> sink_;
-};
-
-}  // namespace android
-
-
diff --git a/host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp b/host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp
deleted file mode 100644
index dcb6d50..0000000
--- a/host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/AdbWebSocketHandler.h>
-
-#include "Utils.h"
-
-#include <https/BaseConnection.h>
-#include <https/Support.h>
-
-#include <android-base/logging.h>
-
-#include <unistd.h>
-
-using namespace android;
-
-struct AdbWebSocketHandler::AdbConnection : public BaseConnection {
-    explicit AdbConnection(
-            AdbWebSocketHandler *parent,
-            std::shared_ptr<RunLoop> runLoop,
-            int sock);
-
-    void send(const void *_data, size_t size);
-
-protected:
-    ssize_t processClientRequest(const void *data, size_t size) override;
-    void onDisconnect(int err) override;
-
-private:
-    AdbWebSocketHandler *mParent;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-AdbWebSocketHandler::AdbConnection::AdbConnection(
-        AdbWebSocketHandler *parent,
-        std::shared_ptr<RunLoop> runLoop,
-        int sock)
-    : BaseConnection(runLoop, sock),
-      mParent(parent) {
-}
-
-// Thanks for calling it a crc32, adb documentation!
-static uint32_t computeNotACrc32(const void *_data, size_t size) {
-    auto data = static_cast<const uint8_t *>(_data);
-    uint32_t sum = 0;
-    for (size_t i = 0; i < size; ++i) {
-        sum += data[i];
-    }
-
-    return sum;
-}
-
-static int verifyAdbHeader(
-        const void *_data, size_t size, size_t *_payloadLength) {
-    auto data = static_cast<const uint8_t *>(_data);
-
-    *_payloadLength = 0;
-
-    if (size < 24) {
-        return -EAGAIN;
-    }
-
-    uint32_t command = U32LE_AT(data);
-    uint32_t magic = U32LE_AT(data + 20);
-
-    if (command != (magic ^ 0xffffffff)) {
-        return -EINVAL;
-    }
-
-    uint32_t payloadLength = U32LE_AT(data + 12);
-
-    if (size < 24 + payloadLength) {
-        return -EAGAIN;
-    }
-
-    auto payloadCrc = U32LE_AT(data + 16);
-    auto crc32 = computeNotACrc32(data + 24, payloadLength);
-
-    if (payloadCrc != crc32) {
-        return -EINVAL;
-    }
-
-    *_payloadLength = payloadLength;
-
-    return 0;
-}
-
-ssize_t AdbWebSocketHandler::AdbConnection::processClientRequest(
-        const void *_data, size_t size) {
-    auto data = static_cast<const uint8_t *>(_data);
-
-    LOG(VERBOSE)
-        << "AdbConnection::processClientRequest (size = " << size << ")";
-
-    // hexdump(data, size);
-
-    size_t payloadLength;
-    int err = verifyAdbHeader(data, size, &payloadLength);
-
-    if (err) {
-        return err;
-    }
-
-    mParent->sendMessage(
-            data, payloadLength + 24, WebSocketHandler::SendMode::binary);
-
-    return payloadLength + 24;
-}
-
-void AdbWebSocketHandler::AdbConnection::onDisconnect(int err) {
-    LOG(INFO) << "AdbConnection::onDisconnect(err=" << err << ")";
-
-    mParent->sendMessage(
-            nullptr /* data */,
-            0 /* size */,
-            WebSocketHandler::SendMode::closeConnection);
-}
-
-void AdbWebSocketHandler::AdbConnection::send(const void *_data, size_t size) {
-    BaseConnection::send(_data, size);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-AdbWebSocketHandler::AdbWebSocketHandler(
-        std::shared_ptr<RunLoop> runLoop,
-        const std::string &adb_host_and_port)
-    : mRunLoop(runLoop),
-      mSocket(-1) {
-    LOG(INFO) << "Connecting to " << adb_host_and_port;
-
-    auto err = setupSocket(adb_host_and_port);
-    CHECK(!err);
-
-    mAdbConnection = std::make_shared<AdbConnection>(this, mRunLoop, mSocket);
-}
-
-AdbWebSocketHandler::~AdbWebSocketHandler() {
-    if (mSocket >= 0) {
-        close(mSocket);
-        mSocket = -1;
-    }
-}
-
-void AdbWebSocketHandler::run() {
-    mAdbConnection->run();
-}
-
-int AdbWebSocketHandler::setupSocket(const std::string &adb_host_and_port) {
-    auto colonPos = adb_host_and_port.find(':');
-    if (colonPos == std::string::npos) {
-        return -EINVAL;
-    }
-
-    auto host = adb_host_and_port.substr(0, colonPos);
-
-    const char *portString = adb_host_and_port.c_str() + colonPos + 1;
-    char *end;
-    unsigned long port = strtoul(portString, &end, 10);
-
-    if (end == portString || *end != '\0' || port > 65535) {
-        return -EINVAL;
-    }
-
-    int err;
-
-    int sock = socket(PF_INET, SOCK_STREAM, 0);
-
-    if (sock < 0) {
-        err = -errno;
-        goto bail;
-    }
-
-    makeFdNonblocking(sock);
-
-    sockaddr_in addr;
-    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
-    addr.sin_family = AF_INET;
-    addr.sin_addr.s_addr = inet_addr(host.c_str());
-    addr.sin_port = htons(port);
-
-    if (connect(sock,
-                reinterpret_cast<const sockaddr *>(&addr),
-                sizeof(addr)) < 0
-            && errno != EINPROGRESS) {
-        err = -errno;
-        goto bail2;
-    }
-
-    mSocket = sock;
-
-    return 0;
-
-bail2:
-    close(sock);
-    sock = -1;
-
-bail:
-    return err;
-}
-
-int AdbWebSocketHandler::handleMessage(
-        uint8_t headerByte, const uint8_t *msg, size_t len) {
-    LOG(VERBOSE)
-        << "headerByte = "
-        << StringPrintf("0x%02x", (unsigned)headerByte);
-
-    // hexdump(msg, len);
-
-    if (!(headerByte & 0x80)) {
-        // I only want to receive whole messages here, not fragments.
-        return -EINVAL;
-    }
-
-    auto opcode = headerByte & 0x1f;
-    switch (opcode) {
-        case 0x8:
-        {
-            // closeConnection.
-            break;
-        }
-
-        case 0x2:
-        {
-            // binary
-
-            size_t payloadLength;
-            int err = verifyAdbHeader(msg, len, &payloadLength);
-
-            if (err || len != 24 + payloadLength) {
-                LOG(ERROR) << "websocket message is not a valid adb message.";
-                return -EINVAL;
-            }
-
-            mAdbConnection->send(msg, len);
-            break;
-        }
-
-        default:
-            return -EINVAL;
-    }
-
-    return 0;
-}
-
diff --git a/host/frontend/gcastv2/webrtc/Android.bp b/host/frontend/gcastv2/webrtc/Android.bp
deleted file mode 100644
index c1d99f0..0000000
--- a/host/frontend/gcastv2/webrtc/Android.bp
+++ /dev/null
@@ -1,165 +0,0 @@
-//
-// Copyright (C) 2019 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.
-
-cc_library_static {
-    name: "libwebrtc",
-    srcs: [
-        "AdbWebSocketHandler.cpp",
-        "DTLS.cpp",
-        "G711Packetizer.cpp",
-        "Keyboard.cpp",
-        "MyWebSocketHandler.cpp",
-        "OpusPacketizer.cpp",
-        "Packetizer.cpp",
-        "RTPSender.cpp",
-        "RTPSession.cpp",
-        "RTPSocketHandler.cpp",
-        "SCTPHandler.cpp",
-        "SDP.cpp",
-        "ServerState.cpp",
-        "STUNClient.cpp",
-        "STUNMessage.cpp",
-        "Utils.cpp",
-        "VP8Packetizer.cpp",
-    ],
-    static_libs: [
-        "libhttps",
-        "libsrtp2",
-        "libcuttlefish_host_config",
-        "libcuttlefish_screen_connector",
-        "libcuttlefish_wayland_server",
-        "libgflags",
-        "libjsoncpp",
-        "libsource",
-        "libdrm",
-        "libffi",
-        "libwayland_server",
-        "libwayland_extension_server_protocols",
-    ],
-    shared_libs: [
-        "libssl",
-        "libbase",
-        "libcuttlefish_fs",
-    ],
-    header_libs: [
-        "cuttlefish_common_headers",
-    ],
-    defaults: ["cuttlefish_host_only"],
-    local_include_dirs: ["include"],
-    export_include_dirs: ["include"],
-}
-
-cc_binary_host {
-    name: "webRTC",
-    srcs: [
-        "webRTC.cpp",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcrypto",
-        "libcuttlefish_fs",
-        "libcuttlefish_utils",
-        "libopus",
-        "libssl",
-        "libvpx",
-        "libyuv",
-    ],
-    static_libs: [
-        "libcuttlefish_host_config",
-        "libcuttlefish_screen_connector",
-        "libcuttlefish_wayland_server",
-        "libgflags",
-        "libhttps",
-        "libjsoncpp",
-        "libsource",
-        "libsrtp2",
-        "libwebrtc",
-        "libdrm",
-        "libffi",
-        "libwayland_server",
-        "libwayland_extension_server_protocols",
-    ],
-    cpp_std: "experimental",
-    defaults: ["cuttlefish_host_only"],
-}
-
-// TODO(jemoreira): Ideally these files should be in $HOST_OUT/webrtc but I
-// couldn't find a module type that would produce that, prebuilt_usr_share_host
-// is the next best thing for now.
-prebuilt_usr_share_host {
-    name: "webrtc_index.html",
-    src: "assets/index.html",
-    filename: "index.html",
-    sub_dir: "webrtc/assets",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_style.css",
-    src: "assets/style.css",
-    filename: "style.css",
-    sub_dir: "webrtc/assets",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_logcat.js",
-    src: "assets/js/logcat.js",
-    filename: "logcat.js",
-    sub_dir: "webrtc/assets/js",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_receive.js",
-    src: "assets/js/receive.js",
-    filename: "receive.js",
-    sub_dir: "webrtc/assets/js",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_viewpane.js",
-    src: "assets/js/viewpane.js",
-    filename: "viewpane.js",
-    sub_dir: "webrtc/assets/js",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_server.crt",
-    src: "certs/server.crt",
-    filename: "server.crt",
-    sub_dir: "webrtc/certs",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_server.key",
-    src: "certs/server.key",
-    filename: "server.key",
-    sub_dir: "webrtc/certs",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_server.p12",
-    src: "certs/server.p12",
-    filename: "server.p12",
-    sub_dir: "webrtc/certs",
-}
-
-prebuilt_usr_share_host {
-    name: "webrtc_trusted.pem",
-    src: "certs/trusted.pem",
-    filename: "trusted.pem",
-    sub_dir: "webrtc/certs",
-}
diff --git a/host/frontend/gcastv2/webrtc/DTLS.cpp b/host/frontend/gcastv2/webrtc/DTLS.cpp
deleted file mode 100644
index 6ae6c9c..0000000
--- a/host/frontend/gcastv2/webrtc/DTLS.cpp
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/DTLS.h>
-
-#include <webrtc/RTPSocketHandler.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/SSLSocket.h>
-#include <https/Support.h>
-
-#include <android-base/logging.h>
-
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <sstream>
-
-static int gDTLSInstanceIndex;
-
-// static
-void DTLS::Init() {
-    SSL_library_init();
-    SSL_load_error_strings();
-    OpenSSL_add_ssl_algorithms();
-
-    auto err = srtp_init();
-    CHECK_EQ(err, srtp_err_status_ok);
-
-    gDTLSInstanceIndex = SSL_get_ex_new_index(
-            0, const_cast<char *>("DTLSInstance index"), NULL, NULL, NULL);
-
-}
-
-bool DTLS::useCertificate(std::shared_ptr<X509> cert) {
-    // I'm assuming that ownership of the certificate is transferred, so I'm
-    // adding an extra reference...
-    CHECK_EQ(1, X509_up_ref(cert.get()));
-
-    return cert != nullptr && 1 == SSL_CTX_use_certificate(mCtx, cert.get());
-}
-
-bool DTLS::usePrivateKey(std::shared_ptr<EVP_PKEY> key) {
-    // I'm assuming that ownership of the key in SSL_CTX_use_PrivateKey is
-    // transferred, so I'm adding an extra reference...
-    CHECK_EQ(1, EVP_PKEY_up_ref(key.get()));
-
-    return key != nullptr
-        && 1 == SSL_CTX_use_PrivateKey(mCtx, key.get())
-        && 1 == SSL_CTX_check_private_key(mCtx);
-}
-
-DTLS::DTLS(
-        std::shared_ptr<RTPSocketHandler> handler,
-        DTLS::Mode mode,
-        std::shared_ptr<X509> cert,
-        std::shared_ptr<EVP_PKEY> key,
-        const std::string &remoteFingerprint,
-        bool useSRTP)
-    : mState(State::UNINITIALIZED),
-      mHandler(handler),
-      mMode(mode),
-      mRemoteFingerprint(remoteFingerprint),
-      mUseSRTP(useSRTP),
-      mCtx(nullptr),
-      mSSL(nullptr),
-      mBioR(nullptr),
-      mBioW(nullptr),
-      mSRTPInbound(nullptr),
-      mSRTPOutbound(nullptr) {
-    mCtx = SSL_CTX_new(DTLSv1_2_method());
-    CHECK(mCtx);
-
-    int result = SSL_CTX_set_cipher_list(
-            mCtx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
-
-    CHECK_EQ(result, 1);
-
-    SSL_CTX_set_verify(
-            mCtx,
-            SSL_VERIFY_PEER
-                | SSL_VERIFY_CLIENT_ONCE
-                | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
-            &DTLS::OnVerifyPeerCertificate);
-
-    CHECK(useCertificate(cert));
-    CHECK(usePrivateKey(key));
-
-    if (mUseSRTP) {
-        result = SSL_CTX_set_tlsext_use_srtp(mCtx, "SRTP_AES128_CM_SHA1_80");
-        CHECK_EQ(result, 0);
-    }
-
-    mSSL = SSL_new(mCtx);
-    CHECK(mSSL);
-
-    SSL_set_ex_data(mSSL, gDTLSInstanceIndex, this);
-
-    mBioR = BIO_new(BIO_s_mem());
-    CHECK(mBioR);
-
-    mBioW = BIO_new(BIO_s_mem());
-    CHECK(mBioW);
-
-    SSL_set_bio(mSSL, mBioR, mBioW);
-
-    if (mode == Mode::CONNECT) {
-        SSL_set_connect_state(mSSL);
-    } else {
-        SSL_set_accept_state(mSSL);
-    }
-}
-
-DTLS::~DTLS() {
-    if (mSRTPOutbound) {
-        srtp_dealloc(mSRTPOutbound);
-        mSRTPOutbound = nullptr;
-    }
-
-    if (mSRTPInbound) {
-        srtp_dealloc(mSRTPInbound);
-        mSRTPInbound = nullptr;
-    }
-
-    if (mSSL) {
-        SSL_shutdown(mSSL);
-    }
-
-    SSL_free(mSSL);
-    mSSL = nullptr;
-
-    mBioW = mBioR = nullptr;
-
-    SSL_CTX_free(mCtx);
-    mCtx = nullptr;
-}
-
-// static
-int DTLS::OnVerifyPeerCertificate(int /* ok */, X509_STORE_CTX *ctx) {
-    LOG(VERBOSE) << "OnVerifyPeerCertificate";
-
-    SSL *ssl = static_cast<SSL *>(X509_STORE_CTX_get_ex_data(
-            ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
-
-    DTLS *me = static_cast<DTLS *>(SSL_get_ex_data(ssl, gDTLSInstanceIndex));
-
-    std::unique_ptr<X509, std::function<void(X509 *)>> cert(
-            SSL_get_peer_certificate(ssl), X509_free);
-
-    if (!cert) {
-        LOG(ERROR) << "SSLSocket::isPeerCertificateValid no certificate.";
-
-        return 0;
-    }
-
-    auto spacePos = me->mRemoteFingerprint.find(' ');
-    CHECK(spacePos != std::string::npos);
-    auto digestName = me->mRemoteFingerprint.substr(0, spacePos);
-    CHECK(!strcasecmp(digestName.c_str(), "sha-256"));
-
-    const EVP_MD *digest = EVP_get_digestbyname("sha256");
-
-    unsigned char md[EVP_MAX_MD_SIZE];
-    unsigned int n;
-    int res = X509_digest(cert.get(), digest, md, &n);
-    CHECK_EQ(res, 1);
-
-    std::stringstream ss;
-    for (unsigned int i = 0; i < n; ++i) {
-        if (i > 0) {
-            ss << ":";
-        }
-
-        auto byte = md[i];
-
-        auto nibble = byte >> 4;
-        ss << (char)((nibble < 10) ? ('0' + nibble) : ('A' + nibble - 10));
-
-        nibble = byte & 0x0f;
-        ss << (char)((nibble < 10) ? ('0' + nibble) : ('A' + nibble - 10));
-    }
-
-    LOG(VERBOSE)
-        << "Client offered certificate w/ fingerprint "
-        << ss.str();
-
-    LOG(VERBOSE) << "should be: " << me->mRemoteFingerprint;
-
-    auto remoteFingerprintHash = me->mRemoteFingerprint.substr(spacePos + 1);
-    bool match = !strcasecmp(remoteFingerprintHash.c_str(), ss.str().c_str());
-
-    if (!match) {
-        LOG(ERROR)
-            << "The peer's certificate's fingerprint does not match that "
-            << "published in the SDP!";
-    }
-
-    return match;
-}
-
-void DTLS::connect(const sockaddr_storage &remoteAddr) {
-    CHECK_EQ(static_cast<int>(mState), static_cast<int>(State::UNINITIALIZED));
-
-    mRemoteAddr = remoteAddr;
-    mState = State::CONNECTING;
-
-    tryConnecting();
-}
-
-void DTLS::doTheThing(int res) {
-    LOG(VERBOSE) << "doTheThing(" << res << ")";
-
-    int err = SSL_get_error(mSSL, res);
-
-    switch (err) {
-        case SSL_ERROR_WANT_READ:
-        {
-            LOG(VERBOSE) << "SSL_ERROR_WANT_READ";
-
-            queueOutputDataFromDTLS();
-            break;
-        }
-
-        case SSL_ERROR_WANT_WRITE:
-        {
-            LOG(VERBOSE) << "SSL_ERROR_WANT_WRITE";
-            break;
-        }
-
-        case SSL_ERROR_NONE:
-        {
-            LOG(VERBOSE) << "SSL_ERROR_NONE";
-            break;
-        }
-
-        case SSL_ERROR_SYSCALL:
-        default:
-        {
-            LOG(ERROR)
-                << "DTLS stack returned error "
-                << err
-                << " ("
-                << SSL_state_string_long(mSSL)
-                << ")";
-        }
-    }
-}
-
-void DTLS::queueOutputDataFromDTLS() {
-    auto handler = mHandler.lock();
-
-    if (!handler) {
-        return;
-    }
-
-    int n;
-
-    do {
-        char buf[RTPSocketHandler::kMaxUDPPayloadSize];
-        n = BIO_read(mBioW, buf, sizeof(buf));
-
-        if (n > 0) {
-            LOG(VERBOSE) << "queueing " << n << " bytes of output data from DTLS.";
-
-            handler->queueDatagram(
-                    mRemoteAddr, buf, static_cast<size_t>(n));
-        } else if (BIO_should_retry(mBioW)) {
-            continue;
-        } else {
-            CHECK(!"Should not be here");
-        }
-    } while (n > 0);
-}
-
-void DTLS::tryConnecting() {
-    CHECK_EQ(static_cast<int>(mState), static_cast<int>(State::CONNECTING));
-
-    int res =
-        (mMode == Mode::CONNECT)
-            ? SSL_connect(mSSL) : SSL_accept(mSSL);
-
-    if (res != 1) {
-        doTheThing(res);
-    } else {
-        queueOutputDataFromDTLS();
-
-        LOG(INFO) << "DTLS connection established.";
-        mState = State::CONNECTED;
-
-        auto handler = mHandler.lock();
-        if (handler) {
-            if (mUseSRTP) {
-                getKeyingMaterial();
-            }
-
-            handler->notifyDTLSConnected();
-        }
-    }
-}
-
-void DTLS::inject(const uint8_t *data, size_t size) {
-    LOG(VERBOSE) << "injecting " << size << " bytes into DTLS stack.";
-
-    auto n = BIO_write(mBioR, data, size);
-    CHECK_EQ(n, static_cast<int>(size));
-
-    if (mState == State::CONNECTING) {
-        if (!SSL_is_init_finished(mSSL)) {
-            tryConnecting();
-        }
-    }
-}
-
-void DTLS::getKeyingMaterial() {
-    static constexpr char kLabel[] = "EXTRACTOR-dtls_srtp";
-
-    // These correspond to the chosen option SRTP_AES128_CM_SHA1_80, passed
-    // to SSL_CTX_set_tlsext_use_srtp before. c/f RFC 5764 4.1.2
-
-    uint8_t material[(SRTP_AES_128_KEY_LEN + SRTP_SALT_LEN) * 2];
-
-    auto res = SSL_export_keying_material(
-            mSSL,
-            material,
-            sizeof(material),
-            kLabel,
-            strlen(kLabel),
-            nullptr /* context */,
-            0 /* contextlen */,
-            0 /* use_context */);
-
-    CHECK_EQ(res, 1);
-
-    // LOG(INFO) << "keying material:";
-    // hexdump(material, sizeof(material));
-
-    size_t offset = 0;
-    const uint8_t *clientKey = &material[offset];
-    offset += SRTP_AES_128_KEY_LEN;
-    const uint8_t *serverKey = &material[offset];
-    offset += SRTP_AES_128_KEY_LEN;
-    const uint8_t *clientSalt = &material[offset];
-    offset += SRTP_SALT_LEN;
-    const uint8_t *serverSalt = &material[offset];
-    offset += SRTP_SALT_LEN;
-
-    CHECK_EQ(offset, sizeof(material));
-
-    std::string sendKey(
-            reinterpret_cast<const char *>(clientKey), SRTP_AES_128_KEY_LEN);
-
-    sendKey.append(
-            reinterpret_cast<const char *>(clientSalt), SRTP_SALT_LEN);
-
-    std::string receiveKey(
-            reinterpret_cast<const char *>(serverKey), SRTP_AES_128_KEY_LEN);
-
-    receiveKey.append(
-            reinterpret_cast<const char *>(serverSalt), SRTP_SALT_LEN);
-
-    if (mMode == Mode::CONNECT) {
-        CreateSRTPSession(&mSRTPInbound, receiveKey, ssrc_any_inbound);
-        CreateSRTPSession(&mSRTPOutbound, sendKey, ssrc_any_outbound);
-    } else {
-        CreateSRTPSession(&mSRTPInbound, sendKey, ssrc_any_inbound);
-        CreateSRTPSession(&mSRTPOutbound, receiveKey, ssrc_any_outbound);
-    }
-}
-
-// static
-void DTLS::CreateSRTPSession(
-        srtp_t *session,
-        const std::string &keyAndSalt,
-        srtp_ssrc_type_t direction) {
-    srtp_policy_t policy;
-    memset(&policy, 0, sizeof(policy));
-
-    srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
-    srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
-
-    policy.ssrc.type = direction;
-    policy.ssrc.value = 0;
-
-    policy.key =
-        const_cast<unsigned char *>(
-                reinterpret_cast<const unsigned char *>(keyAndSalt.c_str()));
-
-    policy.allow_repeat_tx = 1;
-    policy.next = nullptr;
-
-    auto ret = srtp_create(session, &policy);
-    CHECK_EQ(ret, srtp_err_status_ok);
-}
-
-size_t DTLS::protect(void *data, size_t size, bool isRTP) {
-    int len = static_cast<int>(size);
-
-    auto ret =
-        isRTP
-            ? srtp_protect(mSRTPOutbound, data, &len)
-            : srtp_protect_rtcp(mSRTPOutbound, data, &len);
-
-    CHECK_EQ(ret, srtp_err_status_ok);
-
-    return static_cast<size_t>(len);
-}
-
-size_t DTLS::unprotect(void *data, size_t size, bool isRTP) {
-    int len = static_cast<int>(size);
-
-    auto ret =
-        isRTP
-            ? srtp_unprotect(mSRTPInbound, data, &len)
-            : srtp_unprotect_rtcp(mSRTPInbound, data, &len);
-
-    if (ret == srtp_err_status_replay_fail) {
-        LOG(WARNING)
-            << "srtp_unprotect"
-            << (isRTP ? "" : "_rtcp")
-            << " returned srtp_err_status_replay_fail, ignoring packet.";
-
-        return 0;
-    }
-
-    CHECK_EQ(ret, srtp_err_status_ok);
-
-    return static_cast<size_t>(len);
-}
-
-ssize_t DTLS::readApplicationData(void *data, size_t size) {
-    auto res = SSL_read(mSSL, data, size);
-
-    if (res < 0) {
-        doTheThing(res);
-        return -1;
-    }
-
-    return res;
-}
-
-ssize_t DTLS::writeApplicationData(const void *data, size_t size) {
-    auto res = SSL_write(mSSL, data, size);
-
-    queueOutputDataFromDTLS();
-
-    // May have to queue the data and "doTheThing" on failure...
-    CHECK_EQ(res, static_cast<int>(size));
-
-    return res;
-}
diff --git a/host/frontend/gcastv2/webrtc/G711Packetizer.cpp b/host/frontend/gcastv2/webrtc/G711Packetizer.cpp
deleted file mode 100644
index a112351..0000000
--- a/host/frontend/gcastv2/webrtc/G711Packetizer.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/G711Packetizer.h>
-
-#include "Utils.h"
-
-#include <webrtc/RTPSocketHandler.h>
-
-#include <https/SafeCallbackable.h>
-
-using namespace android;
-
-G711Packetizer::G711Packetizer(
-        Mode mode,
-        std::shared_ptr<RunLoop> runLoop,
-        std::shared_ptr<StreamingSource> audioSource)
-    : Packetizer(runLoop, audioSource),
-      mMode(mode),
-      mFirstInTalkspurt(true) {
-}
-
-void G711Packetizer::packetize(const std::shared_ptr<SBuffer> &accessUnit, int64_t timeUs) {
-    LOG(VERBOSE) << "Received G711 frame of size " << accessUnit->size();
-
-    const uint8_t PT = (mMode == Mode::ALAW) ? 8 : 0;
-    static constexpr uint32_t SSRC = 0x8badf00d;
-
-    // XXX Retransmission packets add 2 bytes (for the original seqNum), should
-    // probably reserve that amount in the original packets so we don't exceed
-    // the MTU on retransmission.
-    static const size_t kMaxSRTPPayloadSize =
-        RTPSocketHandler::kMaxUDPPayloadSize - SRTP_MAX_TRAILER_LEN;
-
-    const uint8_t *audioData = accessUnit->data();
-    size_t size = accessUnit->size();
-
-    uint32_t rtpTime = ((timeUs - mediaStartTime()) * 8) / 1000;
-
-    CHECK_LE(12 + size, kMaxSRTPPayloadSize);
-
-    std::vector<uint8_t> packet(12 + size);
-    uint8_t *data = packet.data();
-
-    packet[0] = 0x80;
-    packet[1] = PT;
-
-    if (mFirstInTalkspurt) {
-        packet[1] |= 0x80;  // (M)ark
-        mFirstInTalkspurt = false;
-    }
-
-    SET_U16(&data[2], 0);  // seqNum
-    SET_U32(&data[4], rtpTime);
-    SET_U32(&data[8], SSRC);
-
-    memcpy(&data[12], audioData, size);
-
-    queueRTPDatagram(&packet);
-}
-
-uint32_t G711Packetizer::rtpNow() const {
-    return (timeSinceStart() * 8) / 1000;
-}
diff --git a/host/frontend/gcastv2/webrtc/Keyboard.cpp b/host/frontend/gcastv2/webrtc/Keyboard.cpp
deleted file mode 100644
index 052f300..0000000
--- a/host/frontend/gcastv2/webrtc/Keyboard.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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.
- */
-
-#include <webrtc/Keyboard.h>
-
-#include <linux/input.h>
-
-#include <map>
-
-static const std::map<std::string, uint16_t> kDomToLinuxMapping = {
-    {"Backquote", KEY_GRAVE},
-    {"Backslash", KEY_BACKSLASH},
-    {"Backspace", KEY_BACKSPACE},
-    {"BracketLeft", KEY_LEFTBRACE},
-    {"BracketRight", KEY_RIGHTBRACE},
-    {"Comma", KEY_COMMA},
-    {"Digit0", KEY_0},
-    {"Digit1", KEY_1},
-    {"Digit2", KEY_2},
-    {"Digit3", KEY_3},
-    {"Digit4", KEY_4},
-    {"Digit5", KEY_5},
-    {"Digit6", KEY_6},
-    {"Digit7", KEY_7},
-    {"Digit8", KEY_8},
-    {"Digit9", KEY_9},
-    {"Equal", KEY_EQUAL},
-    {"IntlBackslash", KEY_BACKSLASH},
-    {"IntlRo", KEY_RO},
-    {"IntlYen", KEY_BACKSLASH},
-    {"KeyA", KEY_A},
-    {"KeyB", KEY_B},
-    {"KeyC", KEY_C},
-    {"KeyD", KEY_D},
-    {"KeyE", KEY_E},
-    {"KeyF", KEY_F},
-    {"KeyG", KEY_G},
-    {"KeyH", KEY_H},
-    {"KeyI", KEY_I},
-    {"KeyJ", KEY_J},
-    {"KeyK", KEY_K},
-    {"KeyL", KEY_L},
-    {"KeyM", KEY_M},
-    {"KeyN", KEY_N},
-    {"KeyO", KEY_O},
-    {"KeyP", KEY_P},
-    {"KeyQ", KEY_Q},
-    {"KeyR", KEY_R},
-    {"KeyS", KEY_S},
-    {"KeyT", KEY_T},
-    {"KeyU", KEY_U},
-    {"KeyV", KEY_V},
-    {"KeyW", KEY_W},
-    {"KeyX", KEY_X},
-    {"KeyY", KEY_Y},
-    {"KeyZ", KEY_Z},
-    {"Minus", KEY_MINUS},
-    {"Period", KEY_DOT},
-    {"Quote", KEY_APOSTROPHE},
-    {"Semicolon", KEY_SEMICOLON},
-    {"Slash", KEY_SLASH},
-    {"AltLeft", KEY_LEFTALT},
-    {"AltRight", KEY_RIGHTALT},
-    {"CapsLock", KEY_CAPSLOCK},
-    {"ContextMenu", KEY_CONTEXT_MENU},
-    {"ControlLeft", KEY_LEFTCTRL},
-    {"ControlRight", KEY_RIGHTCTRL},
-    {"Enter", KEY_ENTER},
-    {"MetaLeft", KEY_LEFTMETA},
-    {"MetaRight", KEY_RIGHTMETA},
-    {"ShiftLeft", KEY_LEFTSHIFT},
-    {"ShiftRight", KEY_RIGHTSHIFT},
-    {"Space", KEY_SPACE},
-    {"Tab", KEY_TAB},
-    {"Delete", KEY_DELETE},
-    {"End", KEY_END},
-    {"Help", KEY_HELP},
-    {"Home", KEY_HOME},
-    {"Insert", KEY_INSERT},
-    {"PageDown", KEY_PAGEDOWN},
-    {"PageUp", KEY_PAGEUP},
-    {"ArrowDown", KEY_DOWN},
-    {"ArrowLeft", KEY_LEFT},
-    {"ArrowRight", KEY_RIGHT},
-    {"ArrowUp", KEY_UP},
-
-    {"NumLock", KEY_NUMLOCK},
-    {"Numpad0", KEY_KP0},
-    {"Numpad1", KEY_KP1},
-    {"Numpad2", KEY_KP2},
-    {"Numpad3", KEY_KP3},
-    {"Numpad4", KEY_KP4},
-    {"Numpad5", KEY_KP5},
-    {"Numpad6", KEY_KP6},
-    {"Numpad7", KEY_KP7},
-    {"Numpad8", KEY_KP8},
-    {"Numpad9", KEY_KP9},
-    {"NumpadAdd", KEY_KPPLUS},
-    {"NumpadBackspace", KEY_BACKSPACE},
-    {"NumpadClear", KEY_CLEAR},
-    {"NumpadComma", KEY_KPCOMMA},
-    {"NumpadDecimal", KEY_KPDOT},
-    {"NumpadDivide", KEY_KPSLASH},
-    {"NumpadEnter", KEY_KPENTER},
-    {"NumpadEqual", KEY_KPEQUAL},
-    /*
-    {"NumpadClearEntry", },
-    {"NumpadHash", },
-    {"NumpadMemoryAdd", },
-    {"NumpadMemoryClear", },
-    {"NumpadMemoryRecall", },
-    {"NumpadMemoryStore", },
-    {"NumpadMemorySubtract", },
-    */
-    {"NumpadMultiply", KEY_KPASTERISK},
-    {"NumpadParenLeft", KEY_KPLEFTPAREN},
-    {"NumpadParenRight", KEY_KPRIGHTPAREN},
-    {"NumpadStar", KEY_KPASTERISK},
-    {"NumpadSubtract", KEY_KPMINUS},
-
-    {"Escape", KEY_ESC},
-    {"F1", KEY_F1},
-    {"F2", KEY_F2},
-    {"F3", KEY_F3},
-    {"F4", KEY_F4},
-    {"F5", KEY_F5},
-    {"F6", KEY_F6},
-    {"F7", KEY_F7},
-    {"F8", KEY_F8},
-    {"F9", KEY_F9},
-    {"F10", KEY_F10},
-    {"F11", KEY_F11},
-    {"F12", KEY_F12},
-    {"Fn", KEY_FN},
-    /*{"FnLock", },*/
-    {"PrintScreen", KEY_SYSRQ},
-    {"ScrollLock", KEY_SCROLLLOCK},
-    {"Pause", KEY_PAUSE}};
-
-uint16_t DomKeyCodeToLinux(const std::string& dom_KEY_code) {
-  const auto it = kDomToLinuxMapping.find(dom_KEY_code);
-  if (it == kDomToLinuxMapping.end()) {
-    return 0;
-  }
-  return it->second;
-}
diff --git a/host/frontend/gcastv2/webrtc/MyWebSocketHandler.cpp b/host/frontend/gcastv2/webrtc/MyWebSocketHandler.cpp
deleted file mode 100644
index 60fcfb1..0000000
--- a/host/frontend/gcastv2/webrtc/MyWebSocketHandler.cpp
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/MyWebSocketHandler.h>
-
-#include "Utils.h"
-
-#include <json/json.h>
-
-#include <netdb.h>
-#include <openssl/rand.h>
-
-#include <webrtc/Keyboard.h>
-
-namespace {
-
-// helper method to ensure a json object has the required fields convertible
-// to the appropriate types.
-bool validateJsonObject(
-    const Json::Value &obj, const std::string &type,
-    const std::vector<std::pair<std::string, Json::ValueType>> &fields,
-    std::function<void(const std::string&)> onError) {
-    for (const auto &field_spec : fields) {
-        const auto &field_name = field_spec.first;
-        auto field_type = field_spec.second;
-        if (!(obj.isMember(field_name) &&
-            obj[field_name].isConvertibleTo(field_type))) {
-            std::string error_msg = "Expected a field named '";
-            error_msg += field_name + "' of type '";
-            error_msg += std::to_string(field_type);
-            error_msg += "'";
-            if (!type.empty()) {
-                error_msg += " in message of type '" + type + "'";
-            }
-            error_msg += ".";
-            LOG(WARNING) << error_msg;
-            onError(error_msg);
-            return false;
-        }
-    }
-    return true;
-}
-
-} // namespace
-
-MyWebSocketHandler::MyWebSocketHandler(
-        std::shared_ptr<RunLoop> runLoop,
-        std::shared_ptr<ServerState> serverState,
-        size_t handlerId)
-    : mRunLoop(runLoop),
-      mServerState(serverState),
-      mId(handlerId),
-      mOptions(OptionBits::useSingleCertificateForAllTracks),
-      mTouchSink(mServerState->getTouchSink()),
-      mKeyboardSink(mServerState->getKeyboardSink()) {
-}
-
-MyWebSocketHandler::~MyWebSocketHandler() {
-    mServerState->releaseHandlerId(mId);
-}
-
-int MyWebSocketHandler::handleMessage(
-        uint8_t /* headerByte */, const uint8_t *msg, size_t len) {
-    // android::hexdump(msg, len);
-
-    Json::Value obj;
-    Json::Reader json_reader;
-    Json::FastWriter json_writer;
-    auto str = reinterpret_cast<const char *>(msg);
-    if (!json_reader.parse(str, str + len, obj) < 0) {
-        return -EINVAL;
-    }
-
-    LOG(VERBOSE) << obj.toStyledString();
-
-    auto sendMessageOnError =
-        [this](const std::string &error_msg) {
-          auto reply = "{\"error\": \"" + error_msg + "\"}";
-          sendMessage(reply.c_str(), reply.size());
-        };
-
-    if (!validateJsonObject(obj, "", {{"type", Json::ValueType::stringValue}},
-                            sendMessageOnError)) {
-        return -EINVAL;
-    }
-    std::string type = obj["type"].asString();
-
-    if (type == "greeting") {
-        Json::Value reply;
-        reply["type"] = "hello";
-        reply["reply"] = "Right back at ya!";
-
-        auto replyAsString = json_writer.write(reply);
-        sendMessage(replyAsString.c_str(), replyAsString.size());
-
-        if (obj.isMember("path")) {
-            parseOptions(obj["path"].asString());
-        }
-
-        if (mOptions & OptionBits::useSingleCertificateForAllTracks) {
-            mCertificateAndKey = CreateDTLSCertificateAndKey();
-        }
-
-        prepareSessions();
-    } else if (type == "set-remote-desc") {
-        if (!validateJsonObject(obj, type,
-                                {{"sdp", Json::ValueType::stringValue}},
-                                sendMessageOnError)) {
-            return -EINVAL;
-        }
-
-        int err = mOfferedSDP.setTo(obj["sdp"].asString());
-
-        if (err) {
-            LOG(ERROR) << "Offered SDP could not be parsed (" << err << ")";
-        }
-
-        for (size_t i = 0; i < mSessions.size(); ++i) {
-            const auto &session = mSessions[i];
-
-            session->setRemoteParams(
-                    getRemoteUFrag(i),
-                    getRemotePassword(i),
-                    getRemoteFingerprint(i));
-        }
-
-        return err;
-    } else if (type == "request-offer") {
-        std::stringstream ss;
-
-        ss <<
-"v=0\r\n"
-"o=- 7794515898627856655 2 IN IP4 127.0.0.1\r\n"
-"s=-\r\n"
-"t=0 0\r\n"
-"a=msid-semantic: WMS pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw\r\n";
-
-        bool bundled = false;
-
-        if ((mOptions & OptionBits::bundleTracks) && countTracks() > 1) {
-            bundled = true;
-
-            ss << "a=group:BUNDLE 0";
-
-            if (!(mOptions & OptionBits::disableAudio)) {
-                ss << " 1";
-            }
-
-            if (mOptions & OptionBits::enableData) {
-                ss << " 2";
-            }
-
-            ss << "\r\n";
-
-            emitTrackIceOptionsAndFingerprint(ss, 0 /* mlineIndex */);
-        }
-
-        size_t mlineIndex = 0;
-
-        // Video track (mid = 0)
-
-        std::string videoEncodingSpecific = "a=rtpmap:96 VP8/90000\r\n";
-
-        videoEncodingSpecific +=
-"a=rtcp-fb:96 ccm fir\r\n"
-"a=rtcp-fb:96 nack\r\n"
-"a=rtcp-fb:96 nack pli\r\n";
-
-        ss <<
-"m=video 9 "
-<< ((mOptions & OptionBits::useTCP) ? "TCP" : "UDP")
-<< "/TLS/RTP/SAVPF 96 97\r\n"
-"c=IN IP4 0.0.0.0\r\n"
-"a=rtcp:9 IN IP4 0.0.0.0\r\n";
-
-        if (!bundled) {
-            emitTrackIceOptionsAndFingerprint(ss, mlineIndex++);
-        }
-
-        ss <<
-"a=setup:actpass\r\n"
-"a=mid:0\r\n"
-"a=sendonly\r\n"
-"a=rtcp-mux\r\n"
-"a=rtcp-rsize\r\n"
-"a=rtcp-xr:rcvr-rtt=all\r\n";
-
-        ss << videoEncodingSpecific <<
-"a=rtpmap:97 rtx/90000\r\n"
-"a=fmtp:97 apt=96\r\n"
-"a=ssrc-group:FID 3735928559 3405689008\r\n"
-"a=ssrc:3735928559 cname:myWebRTP\r\n"
-"a=ssrc:3735928559 msid:pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw 61843855-edd7-4ca9-be79-4e3ccc6cc035\r\n"
-"a=ssrc:3735928559 mslabel:pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw\r\n"
-"a=ssrc:3735928559 label:61843855-edd7-4ca9-be79-4e3ccc6cc035\r\n"
-"a=ssrc:3405689008 cname:myWebRTP\r\n"
-"a=ssrc:3405689008 msid:pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw 61843855-edd7-4ca9-be79-4e3ccc6cc035\r\n"
-"a=ssrc:3405689008 mslabel:pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw\r\n"
-"a=ssrc:3405689008 label:61843855-edd7-4ca9-be79-4e3ccc6cc035\r\n";
-
-        if (!(mOptions & OptionBits::disableAudio)) {
-            ss <<
-"m=audio 9 "
-<< ((mOptions & OptionBits::useTCP) ? "TCP" : "UDP")
-<< "/TLS/RTP/SAVPF 98\r\n"
-"c=IN IP4 0.0.0.0\r\n"
-"a=rtcp:9 IN IP4 0.0.0.0\r\n";
-
-            if (!bundled) {
-                emitTrackIceOptionsAndFingerprint(ss, mlineIndex++);
-            }
-
-            ss <<
-"a=setup:actpass\r\n"
-"a=mid:1\r\n"
-"a=sendonly\r\n"
-"a=msid:pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw 61843856-edd7-4ca9-be79-4e3ccc6cc035\r\n"
-"a=rtcp-mux\r\n"
-"a=rtcp-rsize\r\n"
-"a=rtpmap:98 opus/48000/2\r\n"
-"a=fmtp:98 minptime=10;useinbandfec=1\r\n"
-"a=ssrc-group:FID 2343432205\r\n"
-"a=ssrc:2343432205 cname:myWebRTP\r\n"
-"a=ssrc:2343432205 msid:pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw 61843856-edd7-4ca9-be79-4e3ccc6cc035\r\n"
-"a=ssrc:2343432205 mslabel:pqWEULZNyLiJHA7lcwlUnbule9FJNk0pY0aw\r\n"
-"a=ssrc:2343432205 label:61843856-edd7-4ca9-be79-4e3ccc6cc035\r\n";
-        }
-
-        if (mOptions & OptionBits::enableData) {
-            ss <<
-"m=application 9 "
-<< ((mOptions & OptionBits::useTCP) ? "TCP" : "UDP")
-<< "/DTLS/SCTP webrtc-datachannel\r\n"
-"c=IN IP4 0.0.0.0\r\n"
-"a=sctp-port:5000\r\n";
-
-            if (!bundled) {
-                emitTrackIceOptionsAndFingerprint(ss, mlineIndex++);
-            }
-
-            ss <<
-"a=setup:actpass\r\n"
-"a=mid:2\r\n"
-"a=sendrecv\r\n"
-"a=fmtp:webrtc-datachannel max-message-size=65536\r\n";
-        }
-
-        Json::Value reply;
-        reply["type"] = "offer";
-        reply["sdp"] = ss.str();
-
-        auto replyAsString = json_writer.write(reply);
-        sendMessage(replyAsString.c_str(), replyAsString.size());
-    } else if (type == "get-ice-candidate") {
-        if (!validateJsonObject(obj, type, {{"mid", Json::ValueType::intValue}},
-                                sendMessageOnError)) {
-            return -EINVAL;
-        }
-        int32_t mid = obj["mid"].asInt();
-
-        bool success = getCandidate(mid);
-
-        if (!success) {
-            Json::Value reply;
-            reply["type"] = "ice-candidate";
-
-            auto replyAsString = json_writer.write(reply);
-            sendMessage(replyAsString.c_str(), replyAsString.size());
-        }
-    } else if (type == "set-mouse-position") {
-        if (!validateJsonObject(obj, type, {{"down", Json::ValueType::intValue},
-                                            {"x", Json::ValueType::intValue},
-                                            {"y", Json::ValueType::intValue}},
-                                sendMessageOnError)) {
-            return -EINVAL;
-        }
-        int32_t down = obj["down"].asInt();
-        int32_t x = obj["x"].asInt();
-        int32_t y = obj["y"].asInt();
-
-        LOG(VERBOSE)
-            << "set-mouse-position(" << down << ", " << x << ", " << y << ")";
-
-        mTouchSink->injectTouchEvent(x, y, down != 0);
-    } else if (type == "inject-multi-touch") {
-        if (!validateJsonObject(obj, type, {{"id", Json::ValueType::intValue},
-                                            {"initialDown", Json::ValueType::intValue},
-                                            {"x", Json::ValueType::intValue},
-                                            {"y", Json::ValueType::intValue},
-                                            {"slot", Json::ValueType::intValue}},
-                                sendMessageOnError)) {
-            return -EINVAL;
-        }
-        int32_t id = obj["id"].asInt();
-        int32_t initialDown = obj["initialDown"].asInt();
-        int32_t x = obj["x"].asInt();
-        int32_t y = obj["y"].asInt();
-        int32_t slot = obj["slot"].asInt();
-
-        LOG(VERBOSE)
-            << "inject-multi-touch id="
-            << id
-            << ", initialDown="
-            << initialDown
-            << ", x="
-            << x
-            << ", y="
-            << y
-            << ", slot="
-            << slot;
-
-        mTouchSink->injectMultiTouchEvent(id, slot, x, y, initialDown);
-    } else if (type == "key-event") {
-        if (!validateJsonObject(obj, type, {{"event_type", Json::ValueType::stringValue},
-                                            {"keycode", Json::ValueType::stringValue}},
-                                sendMessageOnError)) {
-            return -EINVAL;
-        }
-        auto down = obj["event_type"].asString() == std::string("keydown");
-        auto code = DomKeyCodeToLinux(obj["keycode"].asString());
-        mKeyboardSink->injectEvent(down, code);
-    }
-
-    return 0;
-}
-
-size_t MyWebSocketHandler::countTracks() const {
-    size_t n = 1;  // We always have a video track.
-
-    if (!(mOptions & OptionBits::disableAudio)) {
-        ++n;
-    }
-
-    if (mOptions & OptionBits::enableData) {
-        ++n;
-    }
-
-    return n;
-}
-
-ssize_t MyWebSocketHandler::mlineIndexForMid(int32_t mid) const {
-    switch (mid) {
-        case 0:
-            return 0;
-
-        case 1:
-            if (mOptions & OptionBits::disableAudio) {
-                return -1;
-            }
-
-            return 1;
-
-        case 2:
-            if (!(mOptions & OptionBits::enableData)) {
-                return -1;
-            }
-
-            if (mOptions & OptionBits::disableAudio) {
-                return 1;
-            }
-
-            return 2;
-
-        default:
-            return -1;
-    }
-}
-
-bool MyWebSocketHandler::getCandidate(int32_t mid) {
-    auto mlineIndex = mlineIndexForMid(mid);
-
-    if (mlineIndex < 0) {
-        return false;
-    }
-
-    if (!(mOptions & OptionBits::bundleTracks) || mRTPs.empty()) {
-        // Only allocate a local port once if we bundle tracks.
-
-        size_t sessionIndex = mlineIndex;
-
-        uint32_t trackMask = 0;
-        if (mOptions & OptionBits::bundleTracks) {
-            sessionIndex = 0;  // One session for all tracks.
-
-            trackMask = RTPSocketHandler::TRACK_VIDEO;
-
-            if (!(mOptions & OptionBits::disableAudio)) {
-                trackMask |= RTPSocketHandler::TRACK_AUDIO;
-            }
-
-            if (mOptions & OptionBits::enableData) {
-                trackMask |= RTPSocketHandler::TRACK_DATA;
-            }
-        } else if (mid == 0) {
-            trackMask = RTPSocketHandler::TRACK_VIDEO;
-        } else if (mid == 1) {
-            trackMask = RTPSocketHandler::TRACK_AUDIO;
-        } else {
-            trackMask = RTPSocketHandler::TRACK_DATA;
-        }
-
-        const auto &session = mSessions[sessionIndex];
-
-        auto rtp = std::make_shared<RTPSocketHandler>(
-                mRunLoop,
-                mServerState,
-                (mOptions & OptionBits::useTCP)
-                    ? RTPSocketHandler::TransportType::TCP
-                    : RTPSocketHandler::TransportType::UDP,
-                PF_INET,
-                trackMask,
-                session);
-
-        rtp->run();
-
-        mRTPs.push_back(rtp);
-    }
-
-    auto rtp = mRTPs.back();
-
-    Json::Value reply;
-    reply["type"] = "ice-candidate";
-
-    auto localIPString = rtp->getLocalIPString();
-
-    std::stringstream ss;
-    ss << "candidate:0 1 ";
-
-    if (mOptions & OptionBits::useTCP) {
-        ss << "tcp";
-    } else {
-        ss << "UDP";
-    }
-
-    // see rfc8445, 5.1.2.1. for the derivation of "2122121471" below.
-    ss << " 2122121471 " << localIPString << " " << rtp->getLocalPort() << " typ host ";
-
-    if (mOptions & OptionBits::useTCP) {
-        ss << "tcptype passive ";
-    }
-
-    ss << "generation 0 ufrag " << rtp->getLocalUFrag();
-
-    reply["candidate"] = ss.str();
-    reply["mlineIndex"] = static_cast<Json::UInt64>(mlineIndex);
-
-    Json::FastWriter json_writer;
-    auto replyAsString = json_writer.write(reply);
-    sendMessage(replyAsString.c_str(), replyAsString.size());
-
-    return true;
-}
-
-std::optional<std::string> MyWebSocketHandler::getSDPValue(
-        ssize_t targetMediaIndex,
-        std::string_view key,
-        bool fallthroughToGeneralSection) const {
-
-    CHECK_GE(targetMediaIndex, -1);
-
-    if (targetMediaIndex + 1 >= mOfferedSDP.countSections()) {
-        LOG(ERROR)
-            << "getSDPValue: targetMediaIndex "
-            << targetMediaIndex
-            << " out of range (countSections()="
-            << mOfferedSDP.countSections()
-            << ")";
-
-        return std::nullopt;
-    }
-
-    const std::string prefix = "a=" + std::string(key) + ":";
-
-    auto sectionIndex = 1 + targetMediaIndex;
-    auto rangeEnd = mOfferedSDP.section_end(sectionIndex);
-
-    auto it = std::find_if(
-            mOfferedSDP.section_begin(sectionIndex),
-            rangeEnd,
-            [prefix](const auto &line) {
-        return StartsWith(line, prefix);
-    });
-
-    if (it == rangeEnd) {
-        if (fallthroughToGeneralSection) {
-            CHECK_NE(targetMediaIndex, -1);
-
-            // Oh no, scary recursion ahead.
-            return getSDPValue(
-                    -1 /* targetMediaIndex */,
-                    key,
-                    false /* fallthroughToGeneralSection */);
-        }
-
-        LOG(WARNING)
-            << "Unable to find '"
-            << prefix
-            << "' with targetMediaIndex="
-            << targetMediaIndex;
-
-        return std::nullopt;
-    }
-
-    return (*it).substr(prefix.size());
-}
-
-std::string MyWebSocketHandler::getRemotePassword(size_t mlineIndex) const {
-    auto value = getSDPValue(
-            mlineIndex, "ice-pwd", true /* fallthroughToGeneralSection */);
-
-    return value ? *value : std::string();
-}
-
-std::string MyWebSocketHandler::getRemoteUFrag(size_t mlineIndex) const {
-    auto value = getSDPValue(
-            mlineIndex, "ice-ufrag", true /* fallthroughToGeneralSection */);
-
-    return value ? *value : std::string();
-}
-
-std::string MyWebSocketHandler::getRemoteFingerprint(size_t mlineIndex) const {
-    auto value = getSDPValue(
-            mlineIndex, "fingerprint", true /* fallthroughToGeneralSection */);
-
-    return value ? *value : std::string();
-}
-
-// static
-std::pair<std::shared_ptr<X509>, std::shared_ptr<EVP_PKEY>>
-MyWebSocketHandler::CreateDTLSCertificateAndKey() {
-    // Modeled after "https://stackoverflow.com/questions/256405/
-    // programmatically-create-x509-certificate-using-openssl".
-
-    std::shared_ptr<EVP_PKEY> pkey(EVP_PKEY_new(), EVP_PKEY_free);
-
-    std::unique_ptr<RSA, std::function<void(RSA *)>> rsa(
-            RSA_new(), RSA_free);
-
-    BIGNUM exponent;
-    BN_init(&exponent);
-    BN_set_word(&exponent, RSA_F4);
-
-    int res = RSA_generate_key_ex(
-            rsa.get() /* rsa */, 2048, &exponent, nullptr /* callback */);
-
-    CHECK_EQ(res, 1);
-
-    EVP_PKEY_assign_RSA(pkey.get(), rsa.release());
-
-    std::shared_ptr<X509> x509(X509_new(), X509_free);
-
-    ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), 1);
-
-    X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
-    X509_gmtime_adj(X509_get_notAfter(x509.get()), 60 * 60 * 24 * 7); // 7 days.
-
-    X509_set_pubkey(x509.get(), pkey.get());
-
-    X509_NAME *name = X509_get_subject_name(x509.get());
-
-    X509_NAME_add_entry_by_txt(
-            name, "C",  MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
-
-    X509_NAME_add_entry_by_txt(
-            name,
-            "O",
-            MBSTRING_ASC,
-            (unsigned char *)"Beyond Aggravated",
-            -1,
-            -1,
-            0);
-
-    X509_NAME_add_entry_by_txt(
-            name, "CN", MBSTRING_ASC, (unsigned char *)"localhost", -1, -1, 0);
-
-    X509_set_issuer_name(x509.get(), name);
-
-    auto digest = EVP_sha256();
-
-    X509_sign(x509.get(), pkey.get(), digest);
-
-    return std::make_pair(x509, pkey);
-}
-
-void MyWebSocketHandler::parseOptions(const std::string &pathAndQuery) {
-    auto separatorPos = pathAndQuery.find('?');
-
-    if (separatorPos == std::string::npos) {
-        return;
-    }
-
-    auto components = SplitString(pathAndQuery.substr(separatorPos + 1), '&');
-    for (auto name : components) {
-        bool boolValue = true;
-
-        separatorPos = name.find('=');
-        if (separatorPos != std::string::npos) {
-            boolValue = false;
-
-            auto value = name.substr(separatorPos + 1);
-            name.erase(separatorPos);
-
-            boolValue =
-                !strcasecmp("true", value.c_str())
-                    || !strcasecmp("yes", value.c_str())
-                    || value == "1";
-        }
-
-        if (name == "disable_audio") {
-            auto mask = OptionBits::disableAudio;
-            mOptions = (mOptions & ~mask) | (boolValue ? mask : 0);
-        } else if (name == "bundle_tracks" && boolValue) {
-            auto mask = OptionBits::bundleTracks;
-            mOptions = (mOptions & ~mask) | (boolValue ? mask : 0);
-        } else if (name == "enable_data" && boolValue) {
-            auto mask = OptionBits::enableData;
-            mOptions = (mOptions & ~mask) | (boolValue ? mask : 0);
-        } else if (name == "use_tcp" && boolValue) {
-            auto mask = OptionBits::useTCP;
-            mOptions = (mOptions & ~mask) | (boolValue ? mask : 0);
-        }
-    }
-}
-
-// static
-void MyWebSocketHandler::CreateRandomIceCharSequence(char *dst, size_t size) {
-    // Per RFC 5245 an ice-char is alphanumeric, '+' or '/', i.e. 64 distinct
-    // character values (6 bit).
-
-    CHECK_EQ(1, RAND_bytes(reinterpret_cast<unsigned char *>(dst), size));
-
-    for (size_t i = 0; i < size; ++i) {
-        char x = dst[i] & 0x3f;
-        if (x < 26) {
-            x += 'a';
-        } else if (x < 52) {
-            x += 'A' - 26;
-        } else if (x < 62) {
-            x += '0' - 52;
-        } else if (x < 63) {
-            x = '+';
-        } else {
-            x = '/';
-        }
-
-        dst[i] = x;
-    }
-}
-
-std::pair<std::string, std::string>
-MyWebSocketHandler::createUniqueUFragAndPassword() {
-    // RFC 5245, section 15.4 mandates that uFrag is at least 4 and password
-    // at least 22 ice-chars long.
-
-    char uFragChars[4];
-
-    for (;;) {
-        CreateRandomIceCharSequence(uFragChars, sizeof(uFragChars));
-
-        std::string uFrag(uFragChars, sizeof(uFragChars));
-
-        auto it = std::find_if(
-                mSessions.begin(), mSessions.end(),
-                [uFrag](const auto &session) {
-                    return session->localUFrag() == uFrag;
-                });
-
-        if (it == mSessions.end()) {
-            // This uFrag is not in use yet.
-            break;
-        }
-    }
-
-    char passwordChars[22];
-    CreateRandomIceCharSequence(passwordChars, sizeof(passwordChars));
-
-    return std::make_pair(
-            std::string(uFragChars, sizeof(uFragChars)),
-            std::string(passwordChars, sizeof(passwordChars)));
-}
-
-void MyWebSocketHandler::prepareSessions() {
-    size_t numSessions =
-        (mOptions & OptionBits::bundleTracks) ? 1 : countTracks();
-
-    for (size_t i = 0; i < numSessions; ++i) {
-        auto [ufrag, password] = createUniqueUFragAndPassword();
-
-        auto [certificate, key] =
-            (mOptions & OptionBits::useSingleCertificateForAllTracks)
-                ? mCertificateAndKey : CreateDTLSCertificateAndKey();
-
-        mSessions.push_back(
-                std::make_shared<RTPSession>(
-                    ufrag, password, certificate, key));
-    }
-}
-
-void MyWebSocketHandler::emitTrackIceOptionsAndFingerprint(
-        std::stringstream &ss, size_t mlineIndex) const {
-    CHECK_LT(mlineIndex, mSessions.size());
-    const auto &session = mSessions[mlineIndex];
-
-    ss << "a=ice-ufrag:" << session->localUFrag() << "\r\n";
-    ss << "a=ice-pwd:" << session->localPassword() << "\r\n";
-    ss << "a=ice-options:trickle\r\n";
-    ss << "a=fingerprint:" << session->localFingerprint() << "\r\n";
-}
diff --git a/host/frontend/gcastv2/webrtc/OpusPacketizer.cpp b/host/frontend/gcastv2/webrtc/OpusPacketizer.cpp
deleted file mode 100644
index 7d62589..0000000
--- a/host/frontend/gcastv2/webrtc/OpusPacketizer.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/OpusPacketizer.h>
-
-#include "Utils.h"
-
-#include <webrtc/RTPSocketHandler.h>
-
-#include <https/SafeCallbackable.h>
-
-using namespace android;
-
-OpusPacketizer::OpusPacketizer(
-        std::shared_ptr<RunLoop> runLoop,
-        std::shared_ptr<StreamingSource> audioSource)
-    : Packetizer(runLoop, audioSource),
-      mFirstInTalkspurt(true) {
-}
-
-void OpusPacketizer::packetize(const std::shared_ptr<SBuffer> &accessUnit, int64_t timeUs) {
-    LOG(VERBOSE) << "Received Opus frame of size " << accessUnit->size();
-
-    static constexpr uint8_t PT = 98;
-    static constexpr uint32_t SSRC = 0x8badf00d;
-
-    // XXX Retransmission packets add 2 bytes (for the original seqNum), should
-    // probably reserve that amount in the original packets so we don't exceed
-    // the MTU on retransmission.
-    static const size_t kMaxSRTPPayloadSize =
-        RTPSocketHandler::kMaxUDPPayloadSize - SRTP_MAX_TRAILER_LEN;
-
-    const uint8_t *audioData = accessUnit->data();
-    size_t size = accessUnit->size();
-
-    uint32_t rtpTime = ((timeUs - mediaStartTime()) * 48) / 1000;
-
-    CHECK_LE(12 + size, kMaxSRTPPayloadSize);
-
-    std::vector<uint8_t> packet(12 + size);
-    uint8_t *data = packet.data();
-
-    packet[0] = 0x80;
-    packet[1] = PT;
-
-    if (mFirstInTalkspurt) {
-        packet[1] |= 0x80;  // (M)ark
-        mFirstInTalkspurt = false;
-    }
-
-    SET_U16(&data[2], 0);  // seqNum
-    SET_U32(&data[4], rtpTime);
-    SET_U32(&data[8], SSRC);
-
-    memcpy(&data[12], audioData, size);
-
-    queueRTPDatagram(&packet);
-}
-
-uint32_t OpusPacketizer::rtpNow() const {
-    return (timeSinceStart() * 48) / 1000;
-}
diff --git a/host/frontend/gcastv2/webrtc/Packetizer.cpp b/host/frontend/gcastv2/webrtc/Packetizer.cpp
deleted file mode 100644
index bbe6102..0000000
--- a/host/frontend/gcastv2/webrtc/Packetizer.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/Packetizer.h>
-
-#include <https/SafeCallbackable.h>
-#include <webrtc/RTPSender.h>
-
-Packetizer::Packetizer(std::shared_ptr<RunLoop> runLoop,
-                       std::shared_ptr<StreamingSource> source)
-    : mNumSamplesRead(0),
-      mStartTimeMedia(0),
-      mRunLoop(runLoop),
-      mStreamingSource(source) {}
-
-Packetizer::~Packetizer() {
-    if (mStreamingSource) {
-        mStreamingSource->stop();
-    }
-}
-
-void Packetizer::queueRTPDatagram(std::vector<uint8_t> *packet) {
-    auto it = mSenders.begin();
-    while (it != mSenders.end()) {
-        auto sender = it->lock();
-        if (!sender) {
-            it = mSenders.erase(it);
-            mStreamingSource->notifyStreamConsumerDisconnected();
-            continue;
-        }
-
-        sender->queueRTPDatagram(packet);
-        ++it;
-    }
-}
-
-void Packetizer::addSender(std::shared_ptr<RTPSender> sender) {
-    mSenders.push_back(sender);
-    auto weak_source = std::weak_ptr<StreamingSource>(mStreamingSource);
-    mRunLoop->post([weak_source](){
-        auto source = weak_source.lock();
-        if (!source) return;
-        source->notifyNewStreamConsumer();
-    });
-}
-
-int32_t Packetizer::requestIDRFrame() {
-    return mStreamingSource->requestIDRFrame();
-}
-
-void Packetizer::run() {
-    auto weak_this = weak_from_this();
-
-    mStreamingSource->setCallback(
-            [weak_this](const std::shared_ptr<android::SBuffer> &accessUnit) {
-                auto me = weak_this.lock();
-                if (me) {
-                    me->mRunLoop->post(
-                            makeSafeCallback(
-                                me.get(), &Packetizer::onFrame, accessUnit));
-                }
-            });
-
-    mStreamingSource->start();
-}
-
-void Packetizer::onFrame(const std::shared_ptr<android::SBuffer>& accessUnit) {
-    if (!accessUnit) {
-        LOG(WARNING) << "Received invalid buffer in " << __FUNCTION__;
-        return;
-    }
-    int64_t timeUs = accessUnit->time_us();
-    CHECK(timeUs);
-
-    auto now = std::chrono::steady_clock::now();
-
-    if (mNumSamplesRead == 0) {
-        mStartTimeMedia = timeUs;
-        mStartTimeReal = now;
-    }
-
-    ++mNumSamplesRead;
-
-    LOG(VERBOSE)
-        << "got accessUnit of size "
-        << accessUnit->size()
-        << " at time "
-        << timeUs;
-
-    packetize(accessUnit, timeUs);
-}
-
-uint32_t Packetizer::timeSinceStart() const {
-    if (mNumSamplesRead) return 0;
-
-    auto now = std::chrono::steady_clock::now();
-    return std::chrono::duration_cast<std::chrono::microseconds>(now -
-                                                                 mStartTimeReal)
-        .count();
-}
diff --git a/host/frontend/gcastv2/webrtc/RTPSender.cpp b/host/frontend/gcastv2/webrtc/RTPSender.cpp
deleted file mode 100644
index de05556..0000000
--- a/host/frontend/gcastv2/webrtc/RTPSender.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/RTPSender.h>
-
-#include "Utils.h"
-
-#include <webrtc/RTPSocketHandler.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-#include <random>
-#include <unordered_set>
-
-#define SIMULATE_PACKET_LOSS    0
-
-RTPSender::RTPSender(
-        std::shared_ptr<RunLoop> runLoop,
-        RTPSocketHandler *parent,
-        std::shared_ptr<Packetizer> videoPacketizer,
-        std::shared_ptr<Packetizer> audioPacketizer)
-    : mRunLoop(runLoop),
-      mParent(parent),
-      mVideoPacketizer(videoPacketizer),
-      mAudioPacketizer(audioPacketizer) {
-}
-
-void RTPSender::addSource(uint32_t ssrc) {
-    CHECK(mSources.insert(
-                std::make_pair(ssrc, SourceInfo())).second);
-}
-
-void RTPSender::addRetransInfo(
-        uint32_t ssrc, uint8_t PT, uint32_t retransSSRC, uint8_t retransPT) {
-    auto it = mSources.find(ssrc);
-    CHECK(it != mSources.end());
-
-    auto &info = it->second;
-
-    CHECK(info.mRetrans.insert(
-                std::make_pair(
-                    PT, std::make_pair(retransSSRC, retransPT))).second);
-}
-
-int RTPSender::injectRTCP(uint8_t *data, size_t size) {
-    // LOG(INFO) << "RTPSender::injectRTCP";
-    // hexdump(data, size);
-
-    while (size > 0) {
-        if (size < 8) {
-            return -EINVAL;
-        }
-
-        if ((data[0] >> 6) != 2) {
-            // Wrong version.
-            return -EINVAL;
-        }
-
-        size_t lengthInWords = U16_AT(&data[2]) + 1;
-
-        bool hasPadding = (data[0] & 0x20);
-
-        size_t headerSize = 4 * lengthInWords;
-
-        if (size < headerSize) {
-            return -EINVAL;
-        }
-
-        if (hasPadding) {
-            if (size != headerSize) {
-                // Padding should only be added to the last packet in a compound
-                // packet.
-                return -EINVAL;
-            }
-
-            size_t numPadBytes = data[headerSize - 1];
-            if (numPadBytes == 0 || (numPadBytes % 4) != 0) {
-                return -EINVAL;
-            }
-
-            headerSize -= numPadBytes;
-        }
-
-        auto err = processRTCP(data, headerSize);
-
-        if (err) {
-            return err;
-        }
-
-        data += 4 * lengthInWords;
-        size -= 4 * lengthInWords;
-    }
-
-    return 0;
-}
-
-int RTPSender::processRTCP(const uint8_t *data, size_t size) {
-    static constexpr uint8_t RR = 201;     // RFC 3550
-    // static constexpr uint8_t SDES = 202;
-    // static constexpr uint8_t BYE = 203;
-    // static constexpr uint8_t APP = 204;
-    static constexpr uint8_t RTPFB = 205;  // RFC 4585
-    static constexpr uint8_t PSFB = 206;
-    static constexpr uint8_t XR = 207;  // RFC 3611
-
-    unsigned PT = data[1];
-
-    switch (PT) {
-        case RR:
-        {
-            unsigned RC = data[0] & 0x1f;
-            if (size != 8 + RC * 6 * 4) {
-                return -EINVAL;
-            }
-
-            auto senderSSRC = U32_AT(&data[4]);
-
-            size_t offset = 8;
-            for (unsigned i = 0; i < RC; ++i) {
-                auto SSRC = U32_AT(&data[offset]);
-                auto fractionLost = data[offset + 4];
-                auto cumPacketsLost = U32_AT(&data[offset + 4]) & 0xffffff;
-
-                if (fractionLost) {
-                    LOG(INFO)
-                        << "sender SSRC "
-                        << StringPrintf("0x%08x", senderSSRC)
-                        << " reports "
-                        << StringPrintf("%.2f %%", (double)fractionLost * 100.0 / 256.0)
-                        << " lost, cum. total: "
-                        << cumPacketsLost
-                        << " from SSRC "
-                        << StringPrintf("0x%08x", SSRC);
-                }
-
-                offset += 6 * 4;
-            }
-            break;
-        }
-
-        case RTPFB:
-        {
-            static constexpr uint8_t NACK = 1;
-
-            if (size < 12) {
-                return -EINVAL;
-            }
-
-            unsigned fmt = data[0] & 0x1f;
-
-            auto senderSSRC = U32_AT(&data[4]);
-            auto SSRC = U32_AT(&data[8]);
-
-            switch (fmt) {
-                case NACK:
-                {
-                    size_t offset = 12;
-                    size_t n = (size - offset) / 4;
-                    for (size_t i = 0; i < n; ++i) {
-                        auto PID = U16_AT(&data[offset]);
-                        auto BLP = U16_AT(&data[offset + 2]);
-
-                        LOG(INFO)
-                            << "SSRC "
-                            << StringPrintf("0x%08x", senderSSRC)
-                            << " reports NACK w/ PID="
-                            << StringPrintf("0x%04x", PID)
-                            << ", BLP="
-                            << StringPrintf("0x%04x", BLP)
-                            << " from SSRC "
-                            << StringPrintf("0x%08x", SSRC);
-
-                        offset += 4;
-
-                        retransmitPackets(SSRC, PID, BLP);
-                    }
-                    break;
-                }
-
-                default:
-                {
-                    LOG(WARNING) << "RTPSender::processRTCP unhandled RTPFB.";
-                    hexdump(data, size);
-                    break;
-                }
-            }
-
-            break;
-        }
-
-        case PSFB:
-        {
-            static constexpr uint8_t FMT_PLI = 1;
-            static constexpr uint8_t FMT_SLI = 2;
-            static constexpr uint8_t FMT_AFB = 15;
-
-            if (size < 12) {
-                return -EINVAL;
-            }
-
-            unsigned fmt = data[0] & 0x1f;
-
-            auto SSRC = U32_AT(&data[4]);
-
-            switch (fmt) {
-                case FMT_PLI:
-                {
-                    if (size != 12) {
-                        return -EINVAL;
-                    }
-
-                    LOG(INFO)
-                        << "Received PLI from SSRC "
-                        << StringPrintf("0x%08x", SSRC);
-
-                    if (mVideoPacketizer) {
-                        mVideoPacketizer->requestIDRFrame();
-                    }
-                    break;
-                }
-
-                case FMT_SLI:
-                {
-                    LOG(INFO)
-                        << "Received SLI from SSRC "
-                        << StringPrintf("0x%08x", SSRC);
-
-                    break;
-                }
-
-                case FMT_AFB:
-                    break;
-
-                default:
-                {
-                    LOG(WARNING) << "RTPSender::processRTCP unhandled PSFB.";
-                    hexdump(data, size);
-                    break;
-                }
-            }
-            break;
-        }
-
-        case XR:
-        {
-            static constexpr uint8_t FMT_RRTRB = 4;
-
-            if (size < 8) {
-                return -EINVAL;
-            }
-
-            auto senderSSRC = U32_AT(&data[4]);
-
-            size_t offset = 8;
-            while (offset + 3 < size) {
-                auto fmt = data[offset];
-                auto blockLength = 4 * (1 + U16_AT(&data[offset + 2]));
-
-                if (offset + blockLength > size) {
-                    LOG(WARNING) << "Found incomplete XR report block.";
-                    break;
-                }
-
-                switch (fmt) {
-                    case FMT_RRTRB:
-                    {
-                        if (blockLength != 12) {
-                            LOG(WARNING)
-                                << "Found XR-RRTRB block of invalid length.";
-                            break;
-                        }
-
-                        auto ntpHi = U32_AT(&data[offset + 4]);
-                        auto ntpLo = U32_AT(&data[offset + 8]);
-
-                        queueDLRR(
-                                0xdeadbeef /* localSSRC */,
-                                senderSSRC,
-                                ntpHi,
-                                ntpLo);
-                        break;
-                    }
-
-                    default:
-                    {
-                        LOG(WARNING)
-                            << "Ignoring unknown XR block type " << fmt;
-
-                        break;
-                    }
-                }
-
-                offset += blockLength;
-            }
-
-            if (offset != size) {
-                LOG(WARNING) << "Found trailing bytes in XR report.";
-            }
-            break;
-        }
-
-        default:
-        {
-            LOG(WARNING) << "RTPSender::processRTCP unhandled packet type.";
-            hexdump(data, size);
-        }
-    }
-
-    return 0;
-}
-
-void RTPSender::appendSR(std::vector<uint8_t> *buffer, uint32_t localSSRC) {
-    static constexpr uint8_t SR = 200;
-
-    auto it = mSources.find(localSSRC);
-    CHECK(it != mSources.end());
-
-    const auto &info = it->second;
-
-    const size_t kLengthInWords = 7;
-
-    auto offset = buffer->size();
-    buffer->resize(offset + kLengthInWords * sizeof(uint32_t));
-
-    uint8_t *data = buffer->data() + offset;
-
-    data[0] = 0x80;
-    data[1] = SR;
-    SET_U16(&data[2], kLengthInWords - 1);
-    SET_U32(&data[4], localSSRC);
-
-    auto now = std::chrono::system_clock::now();
-
-    auto us_since_epoch =
-        std::chrono::duration_cast<std::chrono::microseconds>(
-            now.time_since_epoch()).count();
-
-    // This assumes that sd::chrono::system_clock's epoch is unix epoch, i.e.
-    // 1/1/1970 midnight UTC.
-    // Microseconds between midnight 1/1/1970 and midnight 1/1/1900.
-    us_since_epoch += 2208988800ULL * 1000ull;
-
-    uint64_t ntpHi = us_since_epoch / 1000000ll;
-    uint64_t ntpLo = ((1LL << 32) * (us_since_epoch % 1000000LL)) / 1000000LL;
-
-    uint32_t rtpNow =
-        (localSSRC == 0xdeadbeef || localSSRC == 0xcafeb0b0)
-            ? mVideoPacketizer->rtpNow()
-            : mAudioPacketizer->rtpNow();
-
-    SET_U32(&data[8], ntpHi);
-    SET_U32(&data[12], ntpLo);
-    SET_U32(&data[16], rtpNow);
-    SET_U32(&data[20], info.mNumPacketsSent);
-    SET_U32(&data[24], info.mNumBytesSent);
-}
-
-void RTPSender::appendSDES(std::vector<uint8_t> *buffer, uint32_t localSSRC) {
-    static constexpr uint8_t SDES = 202;
-
-    static const char *const kCNAME = "myWebRTP";
-    static const size_t kCNAMELength = strlen(kCNAME);
-
-    const size_t kLengthInWords = 2 + (2 + kCNAMELength + 1 + 3) / 4;
-
-    auto offset = buffer->size();
-    buffer->resize(offset + kLengthInWords * sizeof(uint32_t));
-
-    uint8_t *data = buffer->data() + offset;
-
-    data[0] = 0x81;
-    data[1] = SDES;
-    SET_U16(&data[2], kLengthInWords - 1);
-    SET_U32(&data[4], localSSRC);
-
-    data[8] = 1; // CNAME
-    data[9] = kCNAMELength;
-    memcpy(&data[10], kCNAME, kCNAMELength);
-    data[10 + kCNAMELength] = '\0';
-}
-
-void RTPSender::queueDLRR(
-        uint32_t localSSRC,
-        uint32_t remoteSSRC,
-        uint32_t ntpHi,
-        uint32_t ntpLo) {
-    std::vector<uint8_t> buffer;
-    appendDLRR(&buffer, localSSRC, remoteSSRC, ntpHi, ntpLo);
-
-    mParent->queueRTCPDatagram(buffer.data(), buffer.size());
-}
-
-void RTPSender::appendDLRR(
-        std::vector<uint8_t> *buffer,
-        uint32_t localSSRC,
-        uint32_t remoteSSRC,
-        uint32_t ntpHi,
-        uint32_t ntpLo) {
-    static constexpr uint8_t XR = 207;
-
-    static constexpr uint8_t FMT_DLRRRB = 5;
-
-    const size_t kLengthInWords = 2 + 4;
-
-    auto offset = buffer->size();
-    buffer->resize(offset + kLengthInWords * sizeof(uint32_t));
-
-    uint8_t *data = buffer->data() + offset;
-
-    data[0] = 0x80;
-    data[1] = XR;
-    SET_U16(&data[2], kLengthInWords - 1);
-    SET_U32(&data[4], localSSRC);
-
-    data[8] = FMT_DLRRRB;
-    data[9] = 0x00;
-    SET_U16(&data[10], 3 /* block length */);
-    SET_U32(&data[12], remoteSSRC);
-    SET_U32(&data[16], (ntpHi << 16) | (ntpLo >> 16));
-    SET_U32(&data[20], 0 /* delay since last RR */);
-}
-
-void RTPSender::queueSR(uint32_t localSSRC) {
-    std::vector<uint8_t> buffer;
-    appendSR(&buffer, localSSRC);
-    // appendSDES(&buffer, localSSRC);
-
-    // LOG(INFO) << "RTPSender::queueSR";
-    // hexdump(buffer.data(), buffer.size());
-
-    mParent->queueRTCPDatagram(buffer.data(), buffer.size());
-}
-
-void RTPSender::sendSR(uint32_t localSSRC) {
-    // LOG(INFO) << "sending SR.";
-    queueSR(localSSRC);
-
-    mRunLoop->postWithDelay(
-            std::chrono::seconds(1),
-            makeSafeCallback(this, &RTPSender::sendSR, localSSRC));
-}
-
-void RTPSender::run() {
-    for (const auto &entry : mSources) {
-        sendSR(entry.first);
-    }
-}
-
-void RTPSender::queueRTPDatagram(std::vector<uint8_t> *packet) {
-    CHECK_GE(packet->size(), 12u);
-
-    uint32_t SSRC = U32_AT(&packet->data()[8]);
-
-    auto it = mSources.find(SSRC);
-    CHECK(it != mSources.end());
-
-    auto &info = it->second;
-
-    uint16_t seqNum = info.mNumPacketsSent;
-    SET_U16(packet->data() + 2, seqNum);
-
-#if SIMULATE_PACKET_LOSS
-    static std::random_device rd;
-    static std::mt19937 gen(rd());
-    static std::uniform_real_distribution<> dist(0.0, 1.0);
-    if (dist(gen) < 0.99) {
-#endif
-        mParent->queueRTPDatagram(packet->data(), packet->size());
-#if SIMULATE_PACKET_LOSS
-    } else {
-        LOG(WARNING)
-            << "dropping packet "
-            << StringPrintf("0x%04x", seqNum)
-            << " from SSRC "
-            << StringPrintf("0x%08x", SSRC);
-    }
-#endif
-
-    ++info.mNumPacketsSent;
-    info.mNumBytesSent += packet->size() - 12;  // does not include RTP header.
-
-    if (!info.mRetrans.empty()) {
-        static constexpr size_t kMaxHistory = 512;
-        if (info.mRecentPackets.size() == kMaxHistory) {
-            info.mRecentPackets.pop_front();
-        }
-        // info.mRecentPackets.push_back(std::move(*packet));
-        info.mRecentPackets.push_back(*packet);
-    }
-}
-
-void RTPSender::retransmitPackets(
-        uint32_t localSSRC, uint16_t PID, uint16_t BLP) {
-    auto it = mSources.find(localSSRC);
-    CHECK(it != mSources.end());
-
-    const auto &info = it->second;
-
-    if (!info.mRecentPackets.empty()) {
-        LOG(INFO) << "Recent packets cover range ["
-            << StringPrintf(
-                    "0x%04x", U16_AT(info.mRecentPackets.front().data() + 2))
-            << ";"
-            << StringPrintf(
-                    "0x%04x", U16_AT(info.mRecentPackets.back().data() + 2))
-            << "]";
-    } else {
-        LOG(INFO) << "Recent packets are EMPTY!";
-    }
-
-    bool first = true;
-    while (first || BLP) {
-        if (first) {
-            first = false;
-        } else {
-            ++PID;
-            if (!(BLP & 1)) {
-                BLP = BLP >> 1;
-                continue;
-            }
-
-            BLP = BLP >> 1;
-        }
-
-        for (auto it = info.mRecentPackets.begin();
-                it != info.mRecentPackets.end();
-                ++it) {
-            const auto &origPacket = *it;
-            auto seqNum = U16_AT(origPacket.data() + 2);
-
-            if (seqNum != PID) {
-                continue;
-            }
-
-            LOG(INFO) << "Retransmitting PID " << StringPrintf("0x%04x", PID);
-
-            auto PT = origPacket[1] & 0x7f;
-            auto it2 = info.mRetrans.find(PT);
-            CHECK(it2 != info.mRetrans.end());
-
-            auto [rtxSSRC, rtxPT] = it2->second;
-
-            std::vector<uint8_t> packet(origPacket.size() + 2);
-
-            // XXX This is very simplified and assumes that the original packet
-            // started with a standard 12-byte header, no extensions and no padding!
-            memcpy(packet.data(), origPacket.data(), 12);
-
-            packet[1] = (origPacket[1] & 0x80) | (rtxPT & 0x7f);
-            SET_U32(packet.data() + 8, rtxSSRC);
-            SET_U16(packet.data() + 12, seqNum);
-
-            memcpy(packet.data() + 14,
-                   origPacket.data() + 12,
-                   origPacket.size() - 12);
-
-            // queueRTPDatagram will fill in the new seqNum.
-            queueRTPDatagram(&packet);
-        }
-    }
-}
-
-void RTPSender::requestIDRFrame() {
-    if (mVideoPacketizer) {
-        mVideoPacketizer->requestIDRFrame();
-    }
-}
-
diff --git a/host/frontend/gcastv2/webrtc/RTPSession.cpp b/host/frontend/gcastv2/webrtc/RTPSession.cpp
deleted file mode 100644
index 8eeef1f..0000000
--- a/host/frontend/gcastv2/webrtc/RTPSession.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/RTPSession.h>
-
-#include <android-base/logging.h>
-
-#include <sstream>
-
-RTPSession::RTPSession(
-        std::string_view localUFrag,
-        std::string_view localPassword,
-        std::shared_ptr<X509> localCertificate,
-        std::shared_ptr<EVP_PKEY> localKey)
-    : mLocalUFrag(localUFrag),
-      mLocalPassword(localPassword),
-      mLocalCertificate(localCertificate),
-      mLocalKey(localKey),
-      mPingToken(0),
-      mIsActive(false) {
-}
-
-bool RTPSession::isActive() const {
-    return mIsActive;
-}
-
-void RTPSession::setIsActive() {
-    mIsActive = true;
-}
-
-void RTPSession::schedulePing(
-        std::shared_ptr<RunLoop> runLoop,
-        RunLoop::AsyncFunction cb,
-        std::chrono::steady_clock::duration delay) {
-    CHECK_EQ(mPingToken, 0);
-
-    mPingToken = runLoop->postWithDelay(
-            delay,
-            [weak_this = std::weak_ptr<RTPSession>(shared_from_this()),
-             runLoop, cb]() {
-                auto me = weak_this.lock();
-                if (me) {
-                    me->mPingToken = 0;
-                    cb();
-                }
-            });
-}
-
-void RTPSession::setRemoteParams(
-        std::string_view remoteUFrag,
-        std::string_view remotePassword,
-        std::string_view remoteFingerprint) {
-    CHECK(!mRemoteUFrag && !mRemotePassword && !mRemoteFingerprint);
-
-    mRemoteUFrag = remoteUFrag;
-    mRemotePassword = remotePassword;
-    mRemoteFingerprint = remoteFingerprint;
-}
-
-std::string RTPSession::localUFrag() const {
-    return mLocalUFrag;
-}
-
-std::string RTPSession::localPassword() const {
-    return mLocalPassword;
-}
-
-std::shared_ptr<X509> RTPSession::localCertificate() const {
-    return mLocalCertificate;
-}
-
-std::shared_ptr<EVP_PKEY> RTPSession::localKey() const {
-    return mLocalKey;
-}
-
-std::string RTPSession::localFingerprint() const {
-    auto digest = EVP_sha256();
-
-    unsigned char md[EVP_MAX_MD_SIZE];
-    unsigned int n;
-    auto res = X509_digest(mLocalCertificate.get(), digest, md, &n);
-    CHECK_EQ(res, 1);
-
-    std::stringstream ss;
-    ss << "sha-256 ";
-    for (unsigned int i = 0; i < n; ++i) {
-        if (i > 0) {
-            ss << ":";
-        }
-
-        uint8_t byte = md[i];
-        uint8_t nibble = byte >> 4;
-        ss << (char)(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
-        nibble = byte & 0xf;
-        ss << (char)(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
-    }
-
-    return ss.str();
-}
-
-std::string RTPSession::remoteUFrag() const {
-    CHECK(mRemoteUFrag.has_value());
-    return *mRemoteUFrag;
-}
-
-std::string RTPSession::remotePassword() const {
-    CHECK(mRemotePassword.has_value());
-    return *mRemotePassword;
-}
-
-std::string RTPSession::remoteFingerprint() const {
-    CHECK(mRemoteFingerprint.has_value());
-    return *mRemoteFingerprint;
-}
-
-bool RTPSession::hasRemoteAddress() const {
-    return mRemoteAddr.has_value();
-}
-
-sockaddr_storage RTPSession::remoteAddress() const {
-    CHECK(hasRemoteAddress());
-    return *mRemoteAddr;
-}
-
-void RTPSession::setRemoteAddress(const sockaddr_storage &remoteAddr) {
-    CHECK(!hasRemoteAddress());
-    mRemoteAddr = remoteAddr;
-}
-
diff --git a/host/frontend/gcastv2/webrtc/RTPSocketHandler.cpp b/host/frontend/gcastv2/webrtc/RTPSocketHandler.cpp
deleted file mode 100644
index 3885039..0000000
--- a/host/frontend/gcastv2/webrtc/RTPSocketHandler.cpp
+++ /dev/null
@@ -1,739 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/RTPSocketHandler.h>
-
-#include <webrtc/MyWebSocketHandler.h>
-#include <webrtc/STUNMessage.h>
-#include <Utils.h>
-
-#include <https/PlainSocket.h>
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-#include <android-base/logging.h>
-
-#include <netdb.h>
-#include <netinet/in.h>
-
-#include <cstring>
-#include <iostream>
-#include <set>
-
-#include <gflags/gflags.h>
-
-DECLARE_string(public_ip);
-
-// These are the ports we currently open in the firewall (15550..15557)
-static constexpr int kPortRangeBegin = 15550;
-static constexpr int kPortRangeEnd = 15558;
-static constexpr int kPortRangeEndTcp = 15551;
-
-static socklen_t getSockAddrLen(const sockaddr_storage &addr) {
-    switch (addr.ss_family) {
-        case AF_INET:
-            return sizeof(sockaddr_in);
-        case AF_INET6:
-            return sizeof(sockaddr_in6);
-        default:
-            CHECK(!"Should not be here.");
-            return 0;
-    }
-}
-
-static int acquirePort(int sockfd, int domain, bool tcp) {
-    sockaddr_storage addr;
-    uint16_t* port_ptr;
-
-    if (domain == PF_INET) {
-        sockaddr_in addrV4;
-        memset(addrV4.sin_zero, 0, sizeof(addrV4.sin_zero));
-        addrV4.sin_family = AF_INET;
-        addrV4.sin_addr.s_addr = INADDR_ANY;
-        memcpy(&addr, &addrV4, sizeof(addrV4));
-        port_ptr = &(reinterpret_cast<sockaddr_in*>(&addr)->sin_port);
-    } else {
-        CHECK_EQ(domain, PF_INET6);
-        sockaddr_in6 addrV6;
-        addrV6.sin6_family = AF_INET6;
-        addrV6.sin6_addr = in6addr_any;
-        addrV6.sin6_scope_id = 0;
-        memcpy(&addr, &addrV6, sizeof(addrV6));
-        port_ptr = &(reinterpret_cast<sockaddr_in6*>(&addr)->sin6_port);
-    }
-
-    int port = kPortRangeBegin;
-    for (;port < kPortRangeEnd; ++port) {
-        *port_ptr = htons(port);
-        errno = 0;
-        int res = bind(sockfd, reinterpret_cast<const sockaddr *>(&addr),
-                       getSockAddrLen(addr));
-        if (res == 0) {
-            return port;
-        }
-        if (errno != EADDRINUSE) {
-            return -1;
-        }
-        // for now, limit to one client / one tcp port to minimize
-        // complexity for using WebRTC over TCP over ssh tunnels
-        if (tcp && port == kPortRangeEndTcp)
-            break;
-        // else try the next port
-    }
-
-    return -1;
-}
-
-RTPSocketHandler::RTPSocketHandler(
-        std::shared_ptr<RunLoop> runLoop,
-        std::shared_ptr<ServerState> serverState,
-        TransportType transportType,
-        int domain,
-        uint32_t trackMask,
-        std::shared_ptr<RTPSession> session)
-    : mRunLoop(runLoop),
-      mServerState(serverState),
-      mTransportType(transportType),
-      mTrackMask(trackMask),
-      mSession(session),
-      mSendPending(false),
-      mDTLSConnected(false),
-      mInBufferLength(0) {
-    bool tcp = mTransportType == TransportType::TCP;
-
-    int sock = socket(domain, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
-
-    if (tcp) {
-        static constexpr int yes = 1;
-        auto res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
-        CHECK(!res);
-    }
-
-    makeFdNonblocking(sock);
-
-    mLocalPort = acquirePort(sock, domain, tcp);
-
-    CHECK(mLocalPort > 0);
-
-    if (tcp) {
-        auto res = listen(sock, 4);
-        CHECK(!res);
-    }
-
-    auto tmp = std::make_shared<PlainSocket>(mRunLoop, sock);
-    if (tcp) {
-        mServerSocket = tmp;
-    } else {
-        mSocket = tmp;
-    }
-
-    auto videoPacketizer =
-        (trackMask & TRACK_VIDEO)
-            ? mServerState->getVideoPacketizer() : nullptr;
-
-    auto audioPacketizer =
-        (trackMask & TRACK_AUDIO)
-            ? mServerState->getAudioPacketizer() : nullptr;
-
-    mRTPSender = std::make_shared<RTPSender>(
-            mRunLoop,
-            this,
-            videoPacketizer,
-            audioPacketizer);
-
-    if (trackMask & TRACK_VIDEO) {
-        mRTPSender->addSource(0xdeadbeef);
-        mRTPSender->addSource(0xcafeb0b0);
-
-        mRTPSender->addRetransInfo(0xdeadbeef, 96, 0xcafeb0b0, 97);
-    }
-
-    if (trackMask & TRACK_AUDIO) {
-        mRTPSender->addSource(0x8badf00d);
-    }
-}
-
-uint16_t RTPSocketHandler::getLocalPort() const {
-    return mLocalPort;
-}
-
-std::string RTPSocketHandler::getLocalUFrag() const {
-    return mSession->localUFrag();
-}
-
-std::string RTPSocketHandler::getLocalIPString() const {
-    return FLAGS_public_ip;
-}
-
-void RTPSocketHandler::run() {
-    if (mTransportType == TransportType::TCP) {
-        mServerSocket->postRecv(
-                makeSafeCallback(this, &RTPSocketHandler::onTCPConnect));
-    } else {
-        mSocket->postRecv(makeSafeCallback(this, &RTPSocketHandler::onReceive));
-    }
-}
-
-void RTPSocketHandler::onTCPConnect() {
-    int sock = accept(mServerSocket->fd(), nullptr, 0);
-
-    if (sock < 0) {
-        LOG(ERROR) << "RTPSocketHandler: Failed to accept client";
-        mSocket->postRecv(makeSafeCallback(this, &RTPSocketHandler::onTCPConnect));
-        return;
-    }
-
-    LOG(INFO) << "RTPSocketHandler: Accepted client";
-
-    makeFdNonblocking(sock);
-
-    mClientAddrLen = sizeof(mClientAddr);
-
-    int res = getpeername(
-            sock, reinterpret_cast<sockaddr *>(&mClientAddr), &mClientAddrLen);
-
-    CHECK(!res);
-
-    mSocket = std::make_shared<PlainSocket>(mRunLoop, sock);
-
-    mSocket->postRecv(makeSafeCallback(this, &RTPSocketHandler::onTCPReceive));
-}
-
-void RTPSocketHandler::onTCPReceive() {
-    mInBuffer.resize(mInBuffer.size() + 8192);
-
-    auto n = mSocket->recv(
-            mInBuffer.data() + mInBufferLength, mInBuffer.size() - mInBufferLength);
-
-    if (n == 0) {
-        LOG(INFO) << "Client disconnected.";
-        return;
-    }
-
-    mInBufferLength += n;
-
-    size_t offset = 0;
-    while (offset + 1 < mInBufferLength) {
-        auto packetLength = U16_AT(mInBuffer.data() + offset);
-        offset += 2;
-
-        if (offset + packetLength > mInBufferLength) {
-            break;
-        }
-
-        onPacketReceived(
-                mClientAddr,
-                mClientAddrLen,
-                mInBuffer.data() + offset,
-                packetLength);
-
-        offset += packetLength;
-    }
-
-    if (offset > 0) {
-        mInBuffer.erase(mInBuffer.begin(), mInBuffer.begin() + offset);
-        mInBufferLength -= offset;
-    }
-
-    mSocket->postRecv(makeSafeCallback(this, &RTPSocketHandler::onTCPReceive));
-}
-
-void RTPSocketHandler::onReceive() {
-    std::vector<uint8_t> buffer(kMaxUDPPayloadSize);
-
-    uint8_t *data = buffer.data();
-
-    sockaddr_storage addr;
-    socklen_t addrLen = sizeof(addr);
-
-    auto n = mSocket->recvfrom(
-            data, buffer.size(), reinterpret_cast<sockaddr *>(&addr), &addrLen);
-
-    onPacketReceived(addr, addrLen, data, n);
-
-    mSocket->postRecv(makeSafeCallback(this, &RTPSocketHandler::onReceive));
-}
-
-void RTPSocketHandler::onPacketReceived(
-        const sockaddr_storage &addr,
-        socklen_t addrLen,
-        uint8_t *data,
-        size_t n) {
-#if 0
-    std::cout << "========================================" << std::endl;
-
-    hexdump(data, n);
-#endif
-
-    STUNMessage msg(data, n);
-    if (!msg.isValid()) {
-        if (mDTLSConnected) {
-            int err = -EINVAL;
-            if (mRTPSender) {
-                err = onSRTPReceive(data, static_cast<size_t>(n));
-            }
-
-            if (err == -EINVAL) {
-                LOG(VERBOSE) << "Sending to DTLS instead:";
-                // hexdump(data, n);
-
-                onDTLSReceive(data, static_cast<size_t>(n));
-
-                if (mTrackMask & TRACK_DATA) {
-                    ssize_t n;
-
-                    do {
-                        uint8_t buf[kMaxUDPPayloadSize];
-                        n = mDTLS->readApplicationData(buf, sizeof(buf));
-
-                        if (n > 0) {
-                            auto err = mSCTPHandler->inject(
-                                    buf, static_cast<size_t>(n));
-
-                            if (err) {
-                                LOG(WARNING)
-                                    << "SCTPHandler::inject returned error "
-                                    << err;
-                            }
-                        }
-                    } while (n > 0);
-                }
-            }
-        } else {
-            onDTLSReceive(data, static_cast<size_t>(n));
-        }
-
-        return;
-    }
-
-    if (msg.type() == 0x0001 /* Binding Request */) {
-        STUNMessage response(0x0101 /* Binding Response */, msg.data() + 8);
-
-        if (!matchesSession(msg)) {
-            LOG(WARNING) << "Unknown session or no USERNAME.";
-            return;
-        }
-
-        const auto &answerPassword = mSession->localPassword();
-
-        // msg.dump(answerPassword);
-
-        if (addr.ss_family == AF_INET) {
-            uint8_t attr[8];
-            attr[0] = 0x00;
-
-            sockaddr_in addrV4;
-            CHECK_EQ(addrLen, sizeof(addrV4));
-
-            memcpy(&addrV4, &addr, addrLen);
-
-            attr[1] = 0x01;  // IPv4
-
-            static constexpr uint32_t kMagicCookie = 0x2112a442;
-
-            uint16_t portHost = ntohs(addrV4.sin_port);
-            portHost ^= (kMagicCookie >> 16);
-
-            uint32_t ipHost = ntohl(addrV4.sin_addr.s_addr);
-            ipHost ^= kMagicCookie;
-
-            attr[2] = portHost >> 8;
-            attr[3] = portHost & 0xff;
-            attr[4] = ipHost >> 24;
-            attr[5] = (ipHost >> 16) & 0xff;
-            attr[6] = (ipHost >> 8) & 0xff;
-            attr[7] = ipHost & 0xff;
-
-            response.addAttribute(
-                    0x0020 /* XOR-MAPPED-ADDRESS */, attr, sizeof(attr));
-        } else {
-            uint8_t attr[20];
-            attr[0] = 0x00;
-
-            CHECK_EQ(addr.ss_family, AF_INET6);
-
-            sockaddr_in6 addrV6;
-            CHECK_EQ(addrLen, sizeof(addrV6));
-
-            memcpy(&addrV6, &addr, addrLen);
-
-            attr[1] = 0x02;  // IPv6
-
-            static constexpr uint32_t kMagicCookie = 0x2112a442;
-
-            uint16_t portHost = ntohs(addrV6.sin6_port);
-            portHost ^= (kMagicCookie >> 16);
-
-            attr[2] = portHost >> 8;
-            attr[3] = portHost & 0xff;
-
-            uint8_t ipHost[16];
-
-            std::string out;
-
-            for (size_t i = 0; i < 16; ++i) {
-                ipHost[i] = addrV6.sin6_addr.s6_addr[15 - i];
-
-                if (!out.empty()) {
-                    out += ":";
-                }
-                out += StringPrintf("%02x", ipHost[i]);
-
-                ipHost[i] ^= response.data()[4 + i];
-            }
-
-            // LOG(INFO) << "IP6 = " << out;
-
-            for (size_t i = 0; i < 16; ++i) {
-                attr[4 + i] = ipHost[15 - i];
-            }
-
-            response.addAttribute(
-                    0x0020 /* XOR-MAPPED-ADDRESS */, attr, sizeof(attr));
-        }
-
-        response.addMessageIntegrityAttribute(answerPassword);
-        response.addFingerprint();
-
-        // response.dump(answerPassword);
-
-        queueDatagram(addr, response.data(), response.size());
-
-        if (!mSession->isActive()) {
-            mSession->setRemoteAddress(addr);
-
-            mSession->setIsActive();
-
-            mSession->schedulePing(
-                    mRunLoop,
-                    makeSafeCallback(
-                        this, &RTPSocketHandler::pingRemote, mSession),
-                    std::chrono::seconds(0));
-        }
-
-    } else {
-        // msg.dump();
-
-        if (msg.type() == 0x0101 && !mDTLS) {
-            mDTLS = std::make_shared<DTLS>(
-                    shared_from_this(),
-                    DTLS::Mode::ACCEPT,
-                    mSession->localCertificate(),
-                    mSession->localKey(),
-                    mSession->remoteFingerprint(),
-                    (mTrackMask != TRACK_DATA) /* useSRTP */);
-
-            mDTLS->connect(mSession->remoteAddress());
-        }
-    }
-}
-
-bool RTPSocketHandler::matchesSession(const STUNMessage &msg) const {
-    const void *attrData;
-    size_t attrSize;
-    if (!msg.findAttribute(0x0006 /* USERNAME */, &attrData, &attrSize)) {
-        return false;
-    }
-
-    std::string uFragPair(static_cast<const char *>(attrData), attrSize);
-    auto colonPos = uFragPair.find(':');
-
-    if (colonPos == std::string::npos) {
-        return false;
-    }
-
-    std::string localUFrag(uFragPair, 0, colonPos);
-    std::string remoteUFrag(uFragPair, colonPos + 1);
-
-    if (mSession->localUFrag() != localUFrag
-            || mSession->remoteUFrag() != remoteUFrag) {
-
-        LOG(WARNING)
-            << "Unable to find session localUFrag='"
-            << localUFrag
-            << "', remoteUFrag='"
-            << remoteUFrag
-            << "'";
-
-        return false;
-    }
-
-    return true;
-}
-
-void RTPSocketHandler::pingRemote(std::shared_ptr<RTPSession> session) {
-    std::vector<uint8_t> transactionID { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
-
-    STUNMessage msg(
-            0x0001 /* Binding Request */,
-            transactionID.data());
-
-    std::string uFragPair =
-            session->remoteUFrag() + ":" + session->localUFrag();
-
-    msg.addAttribute(
-            0x0006 /* USERNAME */,
-            uFragPair.c_str(),
-            uFragPair.size());
-
-    uint64_t tieBreaker = 0xdeadbeefcafeb0b0;  // XXX
-    msg.addAttribute(
-            0x802a /* ICE-CONTROLLING */,
-            &tieBreaker,
-            sizeof(tieBreaker));
-
-    uint32_t priority = 0xdeadbeef;
-    msg.addAttribute(
-            0x0024 /* PRIORITY */, &priority, sizeof(priority));
-
-    // We're the controlling agent and including the "USE-CANDIDATE" attribute
-    // below nominates this candidate.
-    msg.addAttribute(0x0025 /* USE_CANDIDATE */);
-
-    msg.addMessageIntegrityAttribute(session->remotePassword());
-    msg.addFingerprint();
-
-    queueDatagram(session->remoteAddress(), msg.data(), msg.size());
-
-    session->schedulePing(
-            mRunLoop,
-            makeSafeCallback(this, &RTPSocketHandler::pingRemote, session),
-            std::chrono::seconds(1));
-}
-
-RTPSocketHandler::Datagram::Datagram(
-        const sockaddr_storage &addr, const void *data, size_t size)
-    : mData(size),
-      mAddr(addr) {
-    memcpy(mData.data(), data, size);
-}
-
-const void *RTPSocketHandler::Datagram::data() const {
-    return mData.data();
-}
-
-size_t RTPSocketHandler::Datagram::size() const {
-    return mData.size();
-}
-
-const sockaddr_storage &RTPSocketHandler::Datagram::remoteAddress() const {
-    return mAddr;
-}
-
-void RTPSocketHandler::queueDatagram(
-        const sockaddr_storage &addr, const void *data, size_t size) {
-    if (mTransportType == TransportType::TCP) {
-        std::vector copy(
-                static_cast<const uint8_t *>(data),
-                static_cast<const uint8_t *>(data) + size);
-
-        mRunLoop->post(
-                makeSafeCallback<RTPSocketHandler>(
-                    this,
-                    [copy](RTPSocketHandler *me) {
-                        // addr is ignored and assumed to be the connected endpoint's.
-                        me->queueTCPOutputPacket(copy.data(), copy.size());
-                    }));
-
-        return;
-    }
-
-    auto datagram = std::make_shared<Datagram>(addr, data, size);
-
-    CHECK_LE(size, RTPSocketHandler::kMaxUDPPayloadSize);
-
-    mRunLoop->post(
-            makeSafeCallback<RTPSocketHandler>(
-                this,
-                [datagram](RTPSocketHandler *me) {
-                    me->mOutQueue.push_back(datagram);
-
-                    if (!me->mSendPending) {
-                        me->scheduleDrainOutQueue();
-                    }
-                }));
-}
-
-void RTPSocketHandler::queueTCPOutputPacket(const uint8_t *data, size_t size) {
-    uint8_t framing[2];
-    framing[0] = size >> 8;
-    framing[1] = size & 0xff;
-
-    std::copy(framing, framing + sizeof(framing), std::back_inserter(mOutBuffer));
-    std::copy(data, data + size, std::back_inserter(mOutBuffer));
-
-    if (!mSendPending) {
-        mSendPending = true;
-
-        mSocket->postSend(
-                makeSafeCallback(this, &RTPSocketHandler::sendTCPOutputData));
-    }
-}
-
-void RTPSocketHandler::sendTCPOutputData() {
-    mSendPending = false;
-
-    const size_t size = mOutBuffer.size();
-    size_t offset = 0;
-
-    bool disconnected = false;
-
-    while (offset < size) {
-        auto n = mSocket->send(mOutBuffer.data() + offset, size - offset);
-
-        if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
-
-            LOG(FATAL) << "Should not be here.";
-        } else if (n == 0) {
-            offset = size;
-            disconnected = true;
-            break;
-        }
-
-        offset += static_cast<size_t>(n);
-    }
-
-    mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + offset);
-
-    if (!mOutBuffer.empty() && !disconnected) {
-        mSendPending = true;
-
-        mSocket->postSend(
-                makeSafeCallback(this, &RTPSocketHandler::sendTCPOutputData));
-    }
-}
-
-void RTPSocketHandler::scheduleDrainOutQueue() {
-    CHECK(!mSendPending);
-
-    mSendPending = true;
-    mSocket->postSend(
-            makeSafeCallback(
-                this, &RTPSocketHandler::drainOutQueue));
-}
-
-void RTPSocketHandler::drainOutQueue() {
-    mSendPending = false;
-
-    CHECK(!mOutQueue.empty());
-
-    do {
-        auto datagram = mOutQueue.front();
-
-        ssize_t n;
-        do {
-            const sockaddr_storage &remoteAddr = datagram->remoteAddress();
-
-            n = mSocket->sendto(
-                    datagram->data(),
-                    datagram->size(),
-                    reinterpret_cast<const sockaddr *>(&remoteAddr),
-                    getSockAddrLen(remoteAddr));
-        } while (n < 0 && errno == EINTR);
-
-        if (n < 0) {
-            if (errno == EAGAIN || errno == EWOULDBLOCK) {
-                break;
-            }
-
-            CHECK(!"Should not be here");
-        }
-
-        mOutQueue.pop_front();
-
-    } while (!mOutQueue.empty());
-
-    if (!mOutQueue.empty()) {
-        scheduleDrainOutQueue();
-    }
-}
-
-void RTPSocketHandler::onDTLSReceive(const uint8_t *data, size_t size) {
-    if (mDTLS) {
-        mDTLS->inject(data, size);
-    }
-}
-
-void RTPSocketHandler::notifyDTLSConnected() {
-    LOG(INFO) << "TDLS says that it's now connected.";
-
-    mDTLSConnected = true;
-
-    if (mTrackMask & TRACK_VIDEO) {
-        mServerState->getVideoPacketizer()->addSender(mRTPSender);
-    }
-
-    if (mTrackMask & TRACK_AUDIO) {
-        mServerState->getAudioPacketizer()->addSender(mRTPSender);
-    }
-
-    if (mTrackMask & TRACK_DATA) {
-        mSCTPHandler = std::make_shared<SCTPHandler>(mRunLoop, mDTLS);
-        mSCTPHandler->run();
-    }
-
-    mRTPSender->run();
-}
-
-int RTPSocketHandler::onSRTPReceive(uint8_t *data, size_t size) {
-    if (size < 2) {
-        return -EINVAL;
-    }
-
-    auto version = data[0] >> 6;
-    if (version != 2) {
-        return -EINVAL;
-    }
-
-    auto outSize = mDTLS->unprotect(data, size, false /* isRTP */);
-
-    auto err = mRTPSender->injectRTCP(data, outSize);
-    if (err) {
-        LOG(WARNING) << "RTPSender::injectRTCP returned " << err;
-    }
-
-    return err;
-}
-
-void RTPSocketHandler::queueRTCPDatagram(const void *data, size_t size) {
-    if (!mDTLSConnected) {
-        return;
-    }
-
-    std::vector<uint8_t> copy(size + SRTP_MAX_TRAILER_LEN);
-    memcpy(copy.data(), data, size);
-
-    auto outSize = mDTLS->protect(copy.data(), size, false /* isRTP */);
-    CHECK_LE(outSize, copy.size());
-
-    queueDatagram(mSession->remoteAddress(), copy.data(), outSize);
-}
-
-void RTPSocketHandler::queueRTPDatagram(const void *data, size_t size) {
-    if (!mDTLSConnected) {
-        return;
-    }
-
-    std::vector<uint8_t> copy(size + SRTP_MAX_TRAILER_LEN);
-    memcpy(copy.data(), data, size);
-
-    auto outSize = mDTLS->protect(copy.data(), size, true /* isRTP */);
-    CHECK_LE(outSize, copy.size());
-
-    queueDatagram(mSession->remoteAddress(), copy.data(), outSize);
-}
diff --git a/host/frontend/gcastv2/webrtc/SCTPHandler.cpp b/host/frontend/gcastv2/webrtc/SCTPHandler.cpp
deleted file mode 100644
index c89f925..0000000
--- a/host/frontend/gcastv2/webrtc/SCTPHandler.cpp
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/SCTPHandler.h>
-
-#include "Utils.h"
-
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-#include <android-base/logging.h>
-
-SCTPHandler::SCTPHandler(
-        std::shared_ptr<RunLoop> runLoop,
-        std::shared_ptr<DTLS> dtls)
-    : mRunLoop(runLoop),
-      mDTLS(dtls),
-      mInitiateTag(0),
-      mSendingTSN(0),
-      mSentGreeting(false) {
-}
-
-void SCTPHandler::run() {
-}
-
-int SCTPHandler::inject(uint8_t *data, size_t size) {
-    LOG(INFO)
-        << "Received SCTP datagram of size " << size << ":";
-
-    hexdump(data, size);
-
-    if (size < 12) {
-        // Need at least the common header.
-        return -EINVAL;
-    }
-
-    auto srcPort = U16_AT(&data[0]);
-    auto dstPort = U16_AT(&data[2]);
-
-    if (dstPort != 5000) {
-        return -EINVAL;
-    }
-
-    auto checkSumIn = U32_AT(&data[8]);
-    SET_U32(&data[8], 0x00000000);
-    auto checkSum = crc32c(data, size);
-
-    if (checkSumIn != checkSum) {
-        LOG(WARNING)
-            << "SCTPHandler::inject checksum invalid."
-            << " (in: " << StringPrintf("0x%08x", checkSumIn) << ", "
-            << "computed: " << StringPrintf("0x%08x", checkSum) << ")";
-
-        return -EINVAL;
-    }
-
-    bool firstChunk = true;
-    size_t offset = 12;
-    while (offset < size) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        size_t chunkLength = U16_AT(&data[offset + 2]);
-
-        if (offset + chunkLength > size) {
-            return -EINVAL;
-        }
-
-        size_t paddedChunkLength = chunkLength;
-        size_t pad = chunkLength % 4;
-        if (pad) {
-            pad = 4 - pad;
-            paddedChunkLength += pad;
-        }
-
-        bool lastChunk =
-            (offset + chunkLength == size)
-                || (offset + paddedChunkLength == size);
-
-        auto err = processChunk(
-                srcPort,
-                &data[offset],
-                chunkLength,
-                firstChunk,
-                lastChunk);
-
-        if (err) {
-            return err;
-        }
-
-        firstChunk = false;
-
-        offset += chunkLength;
-
-        if (offset == size) {
-            break;
-        }
-
-        if (offset + pad > size) {
-            return -EINVAL;
-        }
-
-        offset += pad;
-    }
-
-    return 0;
-}
-
-int SCTPHandler::processChunk(
-        uint16_t srcPort,
-        const uint8_t *data,
-        size_t size,
-        bool firstChunk,
-        bool lastChunk) {
-    static constexpr uint8_t DATA = 0;
-    static constexpr uint8_t INIT = 1;
-    static constexpr uint8_t INIT_ACK = 2;
-    static constexpr uint8_t SACK = 3;
-    static constexpr uint8_t HEARTBEAT = 4;
-    static constexpr uint8_t HEARTBEAT_ACK = 5;
-    static constexpr uint8_t COOKIE_ECHO = 10;
-    static constexpr uint8_t COOKIE_ACK = 11;
-    static constexpr uint8_t SHUTDOWN_COMPLETE = 14;
-
-    static constexpr uint64_t kCookie = 0xDABBAD00DEADBAADull;
-
-    auto chunkType = data[0];
-    if ((!firstChunk || !lastChunk)
-            && (chunkType == INIT
-                    || chunkType == INIT_ACK
-                    || chunkType == SHUTDOWN_COMPLETE)) {
-        // These chunks must be by themselves, no other chunks must be part
-        // of the same datagram.
-
-        return -EINVAL;
-    }
-
-    switch (chunkType) {
-        case INIT:
-        {
-            if (size < 20) {
-                return -EINVAL;
-            }
-
-            mInitiateTag = U32_AT(&data[4]);
-
-            uint8_t out[12 + 24 + sizeof(kCookie)];
-            SET_U16(&out[0], 5000);
-            SET_U16(&out[2], srcPort);
-            SET_U32(&out[4], mInitiateTag);
-            SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
-
-            size_t offset = 12;
-            out[offset++] = INIT_ACK;
-            out[offset++] = 0x00;
-
-            SET_U16(&out[offset], sizeof(out) - 12);
-            offset += 2;
-
-            SET_U32(&out[offset], 0xb0b0cafe);  // initiate tag
-            offset += 4;
-
-            SET_U32(&out[offset], 0x00020000);  // a_rwnd
-            offset += 4;
-
-            SET_U16(&out[offset], 1);  // Number of Outbound Streams
-            offset += 2;
-
-            SET_U16(&out[offset], 1);  // Number of Inbound Streams
-            offset += 2;
-
-            mSendingTSN = 0x12345678;
-
-            SET_U32(&out[offset], mSendingTSN);  // Initial TSN
-            offset += 4;
-
-            SET_U16(&out[offset], 0x0007);  // STATE_COOKIE
-            offset += 2;
-
-            static_assert((sizeof(kCookie) % 4) == 0);
-
-            SET_U16(&out[offset], 4 + sizeof(kCookie));
-            offset += 2;
-
-            memcpy(&out[offset], &kCookie, sizeof(kCookie));
-            offset += sizeof(kCookie);
-
-            CHECK_EQ(offset, sizeof(out));
-
-            SET_U32(&out[8], crc32c(out, sizeof(out)));
-
-            LOG(INFO) << "Sending SCTP INIT_ACK:";
-            hexdump(out, sizeof(out));
-
-            mDTLS->writeApplicationData(out, sizeof(out));
-            break;
-        }
-
-        case COOKIE_ECHO:
-        {
-            if (size != (4 + sizeof(kCookie))) {
-                return -EINVAL;
-            }
-
-            if (memcmp(&data[4], &kCookie, sizeof(kCookie))) {
-                return -EINVAL;
-            }
-
-            uint8_t out[12 + 4];
-            SET_U16(&out[0], 5000);
-            SET_U16(&out[2], srcPort);
-            SET_U32(&out[4], mInitiateTag);
-            SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
-
-            size_t offset = 12;
-            out[offset++] = COOKIE_ACK;
-            out[offset++] = 0x00;
-            SET_U16(&out[offset], sizeof(out) - 12);
-            offset += 2;
-
-            CHECK_EQ(offset, sizeof(out));
-
-            SET_U32(&out[8], crc32c(out, sizeof(out)));
-
-            LOG(INFO) << "Sending SCTP COOKIE_ACK:";
-            hexdump(out, sizeof(out));
-
-            mDTLS->writeApplicationData(out, sizeof(out));
-            break;
-        }
-
-        case DATA:
-        {
-            if (size < 17) {
-                // Minimal size (16 bytes header + 1 byte payload), empty
-                // payloads are prohibited.
-                return -EINVAL;
-            }
-
-            auto TSN = U32_AT(&data[4]);
-
-            uint8_t out[12 + 16];
-            SET_U16(&out[0], 5000);
-            SET_U16(&out[2], srcPort);
-            SET_U32(&out[4], mInitiateTag);
-            SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
-
-            size_t offset = 12;
-            out[offset++] = SACK;
-            out[offset++] = 0x00;
-
-            SET_U16(&out[offset], sizeof(out) - 12);
-            offset += 2;
-
-            SET_U32(&out[offset], TSN);
-            offset += 4;
-
-            SET_U32(&out[offset], 0x00020000);  // a_rwnd
-            offset += 4;
-
-            SET_U16(&out[offset], 0);  // Number of Gap Ack Blocks
-            offset += 2;
-
-            SET_U16(&out[offset], 0);  // Number of Duplicate TSNs
-            offset += 2;
-
-            CHECK_EQ(offset, sizeof(out));
-
-            SET_U32(&out[8], crc32c(out, sizeof(out)));
-
-            LOG(INFO) << "Sending SCTP SACK:";
-            hexdump(out, sizeof(out));
-
-            mDTLS->writeApplicationData(out, sizeof(out));
-
-            if (!mSentGreeting) {
-                mRunLoop->postWithDelay(
-                        std::chrono::seconds(1),
-                        makeSafeCallback(
-                            this,
-                            &SCTPHandler::onSendGreeting,
-                            srcPort,
-                            (size_t)0 /* index */));
-
-                mSentGreeting = true;
-            }
-            break;
-        }
-
-        case HEARTBEAT:
-        {
-            if (size < 8) {
-                return -EINVAL;
-            }
-
-            if (U16_AT(&data[4]) != 1 /* Heartbeat Info Type */
-                || size != (U16_AT(&data[6]) + 4)) {
-                return -EINVAL;
-            }
-
-            size_t pad = size % 4;
-            if (pad) {
-                pad = 4 - pad;
-            }
-
-            std::vector<uint8_t> outVec(12 + size + pad);
-
-            uint8_t *out = outVec.data();
-            SET_U16(&out[0], 5000);
-            SET_U16(&out[2], srcPort);
-            SET_U32(&out[4], mInitiateTag);
-            SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
-
-            size_t offset = 12;
-            out[offset++] = HEARTBEAT_ACK;
-            out[offset++] = 0x00;
-
-            SET_U16(&out[offset], outVec.size() - 12 - pad);
-            offset += 2;
-
-            memcpy(&out[offset], &data[4], size - 4);
-            offset += size - 4;
-
-            memset(&out[offset], 0x00, pad);
-            offset += pad;
-
-            CHECK_EQ(offset, outVec.size());
-
-            SET_U32(&out[8], crc32c(out, outVec.size()));
-
-            LOG(INFO) << "Sending SCTP HEARTBEAT_ACK:";
-            hexdump(out, outVec.size());
-
-            mDTLS->writeApplicationData(out, outVec.size());
-            break;
-        }
-
-        default:
-            break;
-    }
-
-    return 0;
-}
-
-void SCTPHandler::onSendGreeting(uint16_t srcPort, size_t index) {
-    static constexpr uint8_t DATA = 0;
-    // static constexpr uint8_t PPID_WEBRTC_CONTROL = 0x32;
-    static constexpr uint8_t PPID_WEBRTC_STRING  = 0x33;
-
-    std::string message;
-    if (index == 0) {
-        message = "Howdy! How's y'all doin?";
-    } else {
-        message = "But wait... There's more!";
-    }
-
-    size_t pad = message.size() % 4;
-    if (pad) {
-        pad = 4 - pad;
-    }
-
-    std::vector<uint8_t> outVec(12 + 16 + message.size() + pad);
-
-    uint8_t *out = outVec.data();
-    SET_U16(&out[0], 5000);
-    SET_U16(&out[2], srcPort);
-    SET_U32(&out[4], mInitiateTag);
-    SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
-
-    size_t offset = 12;
-    out[offset++] = DATA;
-    out[offset++] = 0x03;  // both Beginning and End of user message.
-
-    SET_U16(&out[offset], outVec.size() - 12 - pad);
-    offset += 2;
-
-    SET_U32(&out[offset], mSendingTSN);  // TSN
-    offset += 4;
-
-    ++mSendingTSN;
-
-    SET_U16(&out[offset], 0);  // Stream Identifier
-    offset += 2;
-
-    SET_U16(&out[offset], index);  // Stream Sequence Number
-    offset += 2;
-
-    SET_U32(&out[offset], PPID_WEBRTC_STRING);  // Payload Protocol Identifier
-    offset += 4;
-
-    // https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-08#section-5.1
-    // https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-11#section-6.5
-
-    // DATA(payload protocol=0x32 (50, WebRTC Control), sequence 0)
-    // 03 00 00 00 00 00 00 00  ........
-    // 00 0c 00 00 64 61 74 61  ....data
-    // 2d 63 68 61 6e 6e 65 6c  -channel
-
-    // DATA(payload protocol=0x33 (51, WebRTC String), sequence 1)
-    // "Hello, world!"
-
-    memcpy(&out[offset], message.data(), message.size());
-    offset += message.size();
-
-    memset(&out[offset], 0x00, pad);
-    offset += pad;
-
-    CHECK_EQ(offset, outVec.size());
-
-    SET_U32(&out[8], crc32c(out, outVec.size()));
-
-    LOG(INFO) << "Sending SCTP DATA:";
-    hexdump(out, outVec.size());
-
-    mDTLS->writeApplicationData(out, outVec.size());
-
-    if (index == 0) {
-        mRunLoop->postWithDelay(
-                std::chrono::seconds(3),
-                makeSafeCallback(
-                    this,
-                    &SCTPHandler::onSendGreeting,
-                    srcPort,
-                    (size_t)1 /* index */));
-    }
-}
-
-static const uint32_t crc_c[256] = {
-    0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
-    0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
-    0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
-    0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
-    0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
-    0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
-    0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
-    0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
-    0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
-    0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
-    0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
-    0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
-    0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
-    0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
-    0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
-    0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
-    0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
-    0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
-    0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
-    0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
-    0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
-    0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
-    0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
-    0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
-    0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
-    0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
-    0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
-    0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
-    0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
-    0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
-    0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
-    0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
-    0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
-    0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
-    0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
-    0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
-    0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
-    0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
-    0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
-    0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
-    0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
-    0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
-    0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
-    0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
-    0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
-    0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
-    0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
-    0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
-    0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
-    0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
-    0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
-    0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
-    0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
-    0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
-    0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
-    0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
-    0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
-    0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
-    0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
-    0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
-    0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
-    0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
-    0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
-    0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
-};
-
-#define CRC32C_POLY 0x1EDC6F41
-#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
-
-static uint32_t swap32(uint32_t x) {
-    return (x >> 24)
-        | (((x >> 16) & 0xff) << 8)
-        | (((x >> 8) & 0xff) << 16)
-        | ((x & 0xff) << 24);
-}
-
-// static
-uint32_t SCTPHandler::crc32c(const uint8_t *data, size_t size) {
-    uint32_t crc32 = ~(uint32_t)0;
-
-    for (size_t i = 0; i < size; ++i) {
-        CRC32C(crc32, data[i]);
-    }
-
-    return ~swap32(crc32);
-}
-
diff --git a/host/frontend/gcastv2/webrtc/SDP.cpp b/host/frontend/gcastv2/webrtc/SDP.cpp
deleted file mode 100644
index daedc79..0000000
--- a/host/frontend/gcastv2/webrtc/SDP.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/SDP.h>
-
-#include "Utils.h"
-
-#include <android-base/logging.h>
-
-#include <cerrno>
-#include <iostream>
-
-SDP::SDP()
-    : mInitCheck(-ENODEV),
-      mNewSectionEditorActive(false) {
-}
-
-int SDP::initCheck() const {
-    return mInitCheck;
-}
-
-size_t SDP::countSections() const {
-    CHECK(!mInitCheck);
-    return mLineIndexBySection.size();
-}
-
-void SDP::clear() {
-    mInitCheck = -ENODEV;
-    mLines.clear();
-    mLineIndexBySection.clear();
-}
-
-int SDP::setTo(const std::string &data) {
-    clear();
-
-    mLines = SplitString(data, "\r\n");
-
-    LOG(VERBOSE) << "SDP contained " << mLines.size() << " lines.";
-
-    mLineIndexBySection.push_back(0);
-
-    mInitCheck = 0;
-
-    for (size_t i = 0; i < mLines.size(); ++i) {
-        const auto &line = mLines[i];
-
-        LOG(VERBOSE) << "Line #" << i << ": " << line;
-
-        if (i == 0 && line != "v=0") {
-            mInitCheck = -EINVAL;
-            break;
-        }
-
-        if (line.size() < 2 || line[1] != '=') {
-            mInitCheck = -EINVAL;
-            break;
-        }
-
-        if (line[0] == 'm') {
-            mLineIndexBySection.push_back(i);
-        }
-    }
-
-    return mInitCheck;
-}
-
-void SDP::getSectionRange(
-        size_t section, size_t *lineStartIndex, size_t *lineStopIndex) const {
-    CHECK(!mInitCheck);
-    CHECK_LT(section, mLineIndexBySection.size());
-
-    if (lineStartIndex) {
-        *lineStartIndex = mLineIndexBySection[section];
-    }
-
-    if (lineStopIndex) {
-        if (section + 1 < mLineIndexBySection.size()) {
-            *lineStopIndex = mLineIndexBySection[section + 1];
-        } else {
-            *lineStopIndex = mLines.size();
-        }
-    }
-}
-
-std::vector<std::string>::const_iterator SDP::section_begin(
-        size_t section) const {
-
-    size_t startLineIndex;
-    getSectionRange(section, &startLineIndex, nullptr /* lineStopIndex */);
-
-    return mLines.cbegin() + startLineIndex;
-}
-
-std::vector<std::string>::const_iterator SDP::section_end(
-        size_t section) const {
-
-    size_t stopLineIndex;
-    getSectionRange(section, nullptr /* lineStartIndex */, &stopLineIndex);
-
-    return mLines.cbegin() + stopLineIndex;
-}
-
-SDP::SectionEditor SDP::createSection() {
-    CHECK(!mNewSectionEditorActive);
-    mNewSectionEditorActive = true;
-
-    if (mInitCheck) {
-        clear();
-        mInitCheck = 0;
-    }
-
-    return SectionEditor(this, countSections());
-}
-
-SDP::SectionEditor SDP::appendToSection(size_t section) {
-    CHECK_LT(section, countSections());
-    return SectionEditor(this, section);
-}
-
-void SDP::commitSectionEdit(
-        size_t section, const std::vector<std::string> &lines) {
-
-    CHECK_LE(section, countSections());
-
-    if (section == countSections()) {
-        // This was an edit creating a new section.
-        mLineIndexBySection.push_back(mLines.size());
-
-        mLines.insert(mLines.end(), lines.begin(), lines.end());
-
-        mNewSectionEditorActive = false;
-        return;
-    }
-
-    mLines.insert(section_end(section), lines.begin(), lines.end());
-
-    if (section + 1 < countSections()) {
-        mLineIndexBySection[section + 1] += lines.size();
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-SDP::SectionEditor::SectionEditor(SDP *sdp, size_t section)
-    : mSDP(sdp),
-      mSection(section) {
-}
-
-SDP::SectionEditor::~SectionEditor() {
-    commit();
-}
-
-SDP::SectionEditor &SDP::SectionEditor::operator<<(std::string_view s) {
-    mBuffer.append(s);
-
-    return *this;
-}
-
-void SDP::SectionEditor::commit() {
-    if (mSDP) {
-        auto lines = SplitString(mBuffer, "\r\n");
-
-        mSDP->commitSectionEdit(mSection, lines);
-        mSDP = nullptr;
-    }
-}
diff --git a/host/frontend/gcastv2/webrtc/STUNClient.cpp b/host/frontend/gcastv2/webrtc/STUNClient.cpp
deleted file mode 100644
index d29c715..0000000
--- a/host/frontend/gcastv2/webrtc/STUNClient.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include "Utils.h"
-
-#include <webrtc/STUNClient.h>
-#include <webrtc/STUNMessage.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-#include <android-base/logging.h>
-
-STUNClient::STUNClient(
-        std::shared_ptr<RunLoop> runLoop,
-        const sockaddr_in &addr,
-        Callback cb)
-    : mRunLoop(runLoop),
-      mRemoteAddr(addr),
-      mCallback(cb),
-      mTimeoutToken(0),
-      mNumRetriesLeft(kMaxNumRetries) {
-
-    int sock = socket(PF_INET, SOCK_DGRAM, 0);
-    makeFdNonblocking(sock);
-
-    sockaddr_in addrV4;
-    memset(addrV4.sin_zero, 0, sizeof(addrV4.sin_zero));
-    addrV4.sin_family = AF_INET;
-    addrV4.sin_port = 0;
-    addrV4.sin_addr.s_addr = INADDR_ANY;
-
-    int res = bind(
-            sock,
-            reinterpret_cast<const sockaddr *>(&addrV4),
-            sizeof(addrV4));
-
-    CHECK(!res);
-
-    sockaddr_in tmp;
-    socklen_t tmpLen = sizeof(tmp);
-
-    res = getsockname(sock, reinterpret_cast<sockaddr *>(&tmp), &tmpLen);
-    CHECK(!res);
-
-    LOG(VERBOSE) << "local port: " << ntohs(tmp.sin_port);
-
-    mSocket = std::make_shared<PlainSocket>(mRunLoop, sock);
-}
-
-void STUNClient::run() {
-    LOG(VERBOSE) << "STUNClient::run()";
-
-    scheduleRequest();
-}
-
-void STUNClient::onSendRequest() {
-    LOG(VERBOSE) << "STUNClient::onSendRequest";
-
-    std::vector<uint8_t> transactionID { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
-
-    STUNMessage msg(0x0001 /* Binding Request */, transactionID.data());
-    msg.addFingerprint();
-
-    ssize_t n;
-
-    do {
-        n = sendto(
-            mSocket->fd(),
-            msg.data(),
-            msg.size(),
-            0 /* flags */,
-            reinterpret_cast<const sockaddr *>(&mRemoteAddr),
-            sizeof(mRemoteAddr));
-
-    } while (n < 0 && errno == EINTR);
-
-    CHECK_GT(n, 0);
-
-    LOG(VERBOSE) << "Sent BIND request, awaiting response";
-
-    mSocket->postRecv(
-            makeSafeCallback(this, &STUNClient::onReceiveResponse));
-}
-
-void STUNClient::onReceiveResponse() {
-    LOG(VERBOSE) << "Received STUN response";
-
-    std::vector<uint8_t> buffer(kMaxUDPPayloadSize);
-
-    uint8_t *data = buffer.data();
-
-    sockaddr_storage addr;
-    socklen_t addrLen = sizeof(addr);
-
-    auto n = mSocket->recvfrom(
-            data, buffer.size(), reinterpret_cast<sockaddr *>(&addr), &addrLen);
-
-    CHECK_GT(n, 0);
-
-    STUNMessage msg(data, n);
-    CHECK(msg.isValid());
-
-    // msg.dump();
-
-    if (msg.type() == 0x0101 /* Binding Response */) {
-        const uint8_t *data;
-        size_t size;
-        if (msg.findAttribute(
-                    0x0020 /* XOR-MAPPED-ADDRESS */,
-                    reinterpret_cast<const void **>(&data),
-                    &size)) {
-
-            CHECK_EQ(size, 8u);
-            CHECK_EQ(data[1], 0x01u);  // We only deal with IPv4 for now.
-
-            static constexpr uint32_t kMagicCookie = 0x2112a442;
-
-            uint16_t port = U16_AT(&data[2]) ^ (kMagicCookie >> 16);
-            uint32_t ip = U32_AT(&data[4]) ^ kMagicCookie;
-
-            LOG(VERBOSE) << "translated port: " << port;
-
-            mCallback(
-                    0 /* result */,
-                    StringPrintf(
-                        "%u.%u.%u.%u",
-                        ip >> 24,
-                        (ip >> 16) & 0xff,
-                        (ip >> 8) & 0xff,
-                        ip & 0xff));
-
-            mRunLoop->cancelToken(mTimeoutToken);
-            mTimeoutToken = 0;
-        }
-    }
-}
-
-void STUNClient::scheduleRequest() {
-    CHECK_EQ(mTimeoutToken, 0);
-
-    mSocket->postSend(
-            makeSafeCallback(this, &STUNClient::onSendRequest));
-
-    mTimeoutToken = mRunLoop->postWithDelay(
-            kTimeoutDelay,
-            makeSafeCallback(this, &STUNClient::onTimeout));
-
-}
-
-void STUNClient::onTimeout() {
-    mTimeoutToken = 0;
-
-    if (mNumRetriesLeft == 0) {
-        mCallback(-ETIMEDOUT, "");
-        return;
-    }
-
-    --mNumRetriesLeft;
-    scheduleRequest();
-}
-
diff --git a/host/frontend/gcastv2/webrtc/STUNMessage.cpp b/host/frontend/gcastv2/webrtc/STUNMessage.cpp
deleted file mode 100644
index 92c3b3e..0000000
--- a/host/frontend/gcastv2/webrtc/STUNMessage.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/STUNMessage.h>
-
-#include "Utils.h"
-
-#include <https/Support.h>
-#include <android-base/logging.h>
-
-#include <arpa/inet.h>
-
-#include <cstring>
-#include <iostream>
-#include <unordered_map>
-
-#include <openssl/hmac.h>
-
-static constexpr uint8_t kMagicCookie[4] = { 0x21, 0x12, 0xa4, 0x42 };
-
-STUNMessage::STUNMessage(uint16_t type, const uint8_t transactionID[12])
-    : mIsValid(true),
-      mData(20),
-      mAddedMessageIntegrity(false) {
-    CHECK((type >> 14) == 0);
-
-    mData[0] = (type >> 8) & 0x3f;
-    mData[1] = type & 0xff;
-    mData[2] = 0;
-    mData[3] = 0;
-
-    memcpy(&mData[4], kMagicCookie, sizeof(kMagicCookie));
-
-    memcpy(&mData[8], transactionID, 12);
-}
-
-STUNMessage::STUNMessage(const void *data, size_t size)
-    : mIsValid(false),
-      mData(size) {
-    memcpy(mData.data(), data, size);
-
-    validate();
-}
-
-bool STUNMessage::isValid() const {
-    return mIsValid;
-}
-
-static uint16_t UINT16_AT(const void *_data) {
-    const uint8_t *data = static_cast<const uint8_t *>(_data);
-    return static_cast<uint16_t>(data[0]) << 8 | data[1];
-}
-
-uint16_t STUNMessage::type() const {
-    return UINT16_AT(mData.data());
-}
-
-void STUNMessage::addAttribute(uint16_t type, const void *data, size_t size) {
-    CHECK(!mAddedMessageIntegrity || type == 0x8028);
-
-    size_t alignedSize = (size + 3) & ~3;
-    CHECK_LE(alignedSize, 0xffffu);
-
-    size_t offset = mData.size();
-    mData.resize(mData.size() + 4 + alignedSize);
-
-    uint8_t *ptr = mData.data() + offset;
-    ptr[0] = type >> 8;
-    ptr[1] = type & 0xff;
-    ptr[2] = (size >> 8) & 0xff;
-    ptr[3] = size & 0xff;
-
-    if (size > 0) {
-        memcpy(&ptr[4], data, size);
-    }
-}
-
-void STUNMessage::addMessageIntegrityAttribute(std::string_view password) {
-    size_t offset = mData.size();
-
-    uint16_t truncatedLength = offset + 4;
-    mData[2] = (truncatedLength >> 8);
-    mData[3] = (truncatedLength & 0xff);
-
-    uint8_t digest[20];
-    unsigned int digestLen = sizeof(digest);
-
-    HMAC(EVP_sha1(),
-         password.data(),
-         password.size(),
-         mData.data(),
-         offset,
-         digest,
-         &digestLen);
-
-    CHECK_EQ(digestLen, 20);
-    addAttribute(0x0008 /* MESSAGE-INTEGRITY */, digest, digestLen);
-
-    mAddedMessageIntegrity = true;
-}
-
-const uint8_t *STUNMessage::data() {
-    size_t size = mData.size() - 20;
-    CHECK_LE(size, 0xffffu);
-
-    mData[2] = (size >> 8) & 0xff;
-    mData[3] = size & 0xff;
-
-    return mData.data();
-}
-
-size_t STUNMessage::size() const {
-    return mData.size();
-}
-
-void STUNMessage::validate() {
-    if (mData.size() < 20) {
-        return;
-    }
-
-    const uint8_t *data = mData.data();
-
-    auto messageLength = UINT16_AT(data + 2);
-    if (messageLength != mData.size() - 20) {
-        return;
-    }
-
-    if (memcmp(kMagicCookie, &data[4], sizeof(kMagicCookie))) {
-        return;
-    }
-
-    bool sawMessageIntegrity = false;
-
-    data += 20;
-    size_t offset = 0;
-    while (offset + 4 <= messageLength) {
-        auto attrType = UINT16_AT(&data[offset]);
-
-        if (sawMessageIntegrity && attrType != 0x8028 /* FINGERPRINT */) {
-            return;
-        }
-
-        sawMessageIntegrity = (attrType == 0x0008 /* MESSAGE-INTEGRITY */);
-
-        auto attrLength = UINT16_AT(&data[offset + 2]);
-
-        if (offset + 4 + attrLength > messageLength) {
-            return;
-        }
-
-        offset += 4 + attrLength;
-        if (offset & 3) {
-            offset += 4 - (offset & 3);
-        }
-    }
-
-    if (offset != messageLength) {
-        return;
-    }
-
-    mAddedMessageIntegrity = sawMessageIntegrity;
-    mIsValid = true;
-}
-
-void STUNMessage::dump(std::optional<std::string_view> password) const {
-    CHECK(mIsValid);
-
-    const uint8_t *data = mData.data();
-
-    auto messageType = UINT16_AT(data);
-    auto messageLength = mData.size() - 20;
-
-    if (messageType == 0x0001) {
-        std::cout << "Binding Request";
-    } else if (messageType == 0x0101) {
-        std::cout << "Binding Response";
-    } else {
-        std::cout
-            << "Unknown message type "
-            << StringPrintf("0x%04x", messageType);
-    }
-
-    std::cout << std::endl;
-
-    data += 20;
-    size_t offset = 0;
-    while (offset + 4 <= messageLength) {
-        auto attrType = UINT16_AT(&data[offset]);
-        auto attrLength = UINT16_AT(&data[offset + 2]);
-
-        static const std::unordered_map<uint16_t, std::string> kAttrName {
-            { 0x0001, "MAPPED-ADDRESS" },
-            { 0x0006, "USERNAME" },
-            { 0x0008, "MESSAGE-INTEGRITY" },
-            { 0x0009, "ERROR-CODE" },
-            { 0x000A, "UNKNOWN-ATTRIBUTES" },
-            { 0x0014, "REALM" },
-            { 0x0015, "NONCE" },
-            { 0x0020, "XOR-MAPPED-ADDRESS" },
-            { 0x0024, "PRIORITY" },  // RFC8445
-            { 0x0025, "USE-CANDIDATE" },  // RFC8445
-            { 0x8022, "SOFTWARE" },
-            { 0x8023, "ALTERNATE-SERVER" },
-            { 0x8028, "FINGERPRINT" },
-            { 0x8029, "ICE-CONTROLLED" },  // RFC8445
-            { 0x802a, "ICE-CONTROLLING" },  // RFC8445
-        };
-
-        auto it = kAttrName.find(attrType);
-        if (it == kAttrName.end()) {
-            if (attrType <= 0x7fff) {
-                std::cout
-                    << "Unknown mandatory attribute type "
-                    << StringPrintf("0x%04x", attrType)
-                    << ":"
-                    << std::endl;
-            } else {
-                std::cout
-                    << "Unknown optional attribute type "
-                    << StringPrintf("0x%04x", attrType)
-                    << ":"
-                    << std::endl;
-            }
-        } else {
-            std::cout << "attribute '" << it->second << "':" << std::endl;
-        }
-
-        hexdump(&data[offset + 4], attrLength);
-
-        if (attrType == 8 /* MESSAGE_INTEGRITY */) {
-            if (attrLength != 20) {
-                LOG(WARNING)
-                    << "Message integrity attribute length mismatch."
-                    << " Expected 20, found "
-                    << attrLength;
-            } else if (password) {
-                auto success = verifyMessageIntegrity(offset + 20, *password);
-
-                if (!success) {
-                    LOG(WARNING) << "Message integrity check FAILED!";
-                }
-            }
-        } else if (attrType == 0x8028 /* FINGERPRINT */) {
-            if (attrLength != 4) {
-                LOG(WARNING)
-                    << "Fingerprint attribute length mismatch."
-                    << " Expected 4, found "
-                    << attrLength;
-            } else {
-                auto success = verifyFingerprint(offset + 20);
-
-                if (!success) {
-                    LOG(WARNING) << "Fingerprint check FAILED!";
-                }
-            }
-        }
-
-        offset += 4 + attrLength;
-        if (offset & 3) {
-            offset += 4 - (offset & 3);
-        }
-    }
-}
-
-bool STUNMessage::verifyMessageIntegrity(
-        size_t offset, std::string_view password) const {
-    // Password used as "short-term" credentials (RFC 5389).
-    // Technically the password would have to be SASLprep'ed...
-
-    std::vector<uint8_t> copy(offset);
-    memcpy(copy.data(), mData.data(), offset);
-
-    uint16_t truncatedLength = offset + 4;
-    copy[2] = (truncatedLength >> 8);
-    copy[3] = (truncatedLength & 0xff);
-
-    uint8_t digest[20];
-    unsigned int digestLen = sizeof(digest);
-
-    HMAC(EVP_sha1(),
-         password.data(),
-         password.size(),
-         copy.data(),
-         copy.size(),
-         digest,
-         &digestLen);
-
-    CHECK_EQ(digestLen, 20);
-
-    bool success = !memcmp(
-            digest,
-            &mData[offset + 4],
-            digestLen);
-
-    return success;
-}
-
-void STUNMessage::addFingerprint() {
-    size_t offset = mData.size();
-
-    // Pretend that we've added the FINGERPRINT attribute already.
-    uint16_t truncatedLength = offset + 4 + 4 - 20;
-    mData[2] = (truncatedLength >> 8);
-    mData[3] = (truncatedLength & 0xff);
-
-    uint32_t crc32 = htonl(computeCrc32(mData.data(), offset) ^ 0x5354554e);
-
-    addAttribute(0x8028 /* FINGERPRINT */, &crc32, sizeof(crc32));
-}
-
-bool STUNMessage::verifyFingerprint(size_t offset) const {
-    std::vector<uint8_t> copy(offset);
-    memcpy(copy.data(), mData.data(), offset);
-
-    copy[2] = ((mData.size() - 20) >> 8) & 0xff;
-    copy[3] = (mData.size() - 20) & 0xff;
-
-    uint32_t crc32 = htonl(computeCrc32(copy.data(), offset) ^ 0x5354554e);
-
-    // hexdump(&crc32, 4);
-
-    return !memcmp(&crc32, &mData[offset + 4], 4);
-}
-
-bool STUNMessage::findAttribute(
-        uint16_t type, const void **attrData, size_t *attrSize) const {
-    CHECK(mIsValid);
-
-    const uint8_t *data = mData.data();
-
-    auto messageLength = mData.size() - 20;
-
-    data += 20;
-    size_t offset = 0;
-    while (offset + 4 <= messageLength) {
-        auto attrType = UINT16_AT(&data[offset]);
-        auto attrLength = UINT16_AT(&data[offset + 2]);
-
-        if (attrType == type) {
-            *attrData = &data[offset + 4];
-            *attrSize = attrLength;
-
-            return true;
-        }
-
-        offset += 4 + attrLength;
-
-        if (offset & 3) {
-            offset += 4 - (offset & 3);
-        }
-    }
-
-    *attrData = nullptr;
-    *attrSize = 0;
-
-    return false;
-}
-
diff --git a/host/frontend/gcastv2/webrtc/ServerState.cpp b/host/frontend/gcastv2/webrtc/ServerState.cpp
deleted file mode 100644
index 1e8b1ca..0000000
--- a/host/frontend/gcastv2/webrtc/ServerState.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/ServerState.h>
-
-#include <webrtc/OpusPacketizer.h>
-#include <webrtc/VP8Packetizer.h>
-
-#include <source/AudioSource.h>
-#include <source/TouchSink.h>
-#include <source/FrameBufferSource.h>
-
-#include "host/libs/config/cuttlefish_config.h"
-
-#include <gflags/gflags.h>
-
-DECLARE_int32(keyboard_fd);
-DECLARE_int32(touch_fd);
-DECLARE_int32(frame_server_fd);
-DECLARE_bool(write_virtio_input);
-
-ServerState::ServerState(
-        std::shared_ptr<RunLoop> runLoop, VideoFormat videoFormat)
-    :
-      mRunLoop(runLoop),
-      mVideoFormat(videoFormat) {
-
-    auto config = vsoc::CuttlefishConfig::Get();
-
-    android::FrameBufferSource::Format fbSourceFormat;
-    switch (videoFormat) {
-        case VideoFormat::VP8:
-            fbSourceFormat = android::FrameBufferSource::Format::VP8;
-            break;
-        default:
-            LOG(FATAL) << "Should not be here.";
-    }
-
-    mFrameBufferSource =
-        std::make_shared<android::FrameBufferSource>(fbSourceFormat);
-
-    int32_t screenParams[4];
-    screenParams[0] = config->x_res();
-    screenParams[1] = config->y_res();
-    screenParams[2] = config->dpi();
-    screenParams[3] = config->refresh_rate_hz();
-
-    static_cast<android::FrameBufferSource *>(
-            mFrameBufferSource.get())->setScreenParams(screenParams);
-
-    mScreenConnector = std::shared_ptr<cvd::ScreenConnector>(
-        cvd::ScreenConnector::Get(FLAGS_frame_server_fd));
-    mScreenConnectorMonitor.reset(
-        new std::thread([this]() { MonitorScreenConnector(); }));
-
-    mAudioSource = std::make_shared<android::AudioSource>(
-            android::AudioSource::Format::OPUS);
-
-    CHECK_GE(FLAGS_touch_fd, 0);
-
-    auto touchSink = std::make_shared<android::TouchSink>(
-        mRunLoop, FLAGS_touch_fd, FLAGS_write_virtio_input);
-
-    touchSink->start();
-
-    mTouchSink = touchSink;
-
-    auto keyboardSink = std::make_shared<android::KeyboardSink>(
-        mRunLoop, FLAGS_keyboard_fd, FLAGS_write_virtio_input);
-
-    keyboardSink->start();
-
-    mKeyboardSink = keyboardSink;
-}
-
-void ServerState::MonitorScreenConnector() {
-    std::uint32_t last_frame = 0;
-    while (true) {
-      mScreenConnector->OnFrameAfter(last_frame, [this, &last_frame](
-                                                     std::uint32_t frame_num,
-                                                     std::uint8_t *data) {
-        mRunLoop->postAndAwait([this, data]() {
-          static_cast<android::FrameBufferSource *>(mFrameBufferSource.get())
-              ->injectFrame(data, cvd::ScreenConnector::ScreenSizeInBytes());
-        });
-        last_frame = frame_num;
-      });
-    }
-}
-
-std::shared_ptr<Packetizer> ServerState::getVideoPacketizer() {
-    auto packetizer = mVideoPacketizer.lock();
-    if (!packetizer) {
-        switch (mVideoFormat) {
-            case VideoFormat::VP8:
-            {
-                packetizer = std::make_shared<VP8Packetizer>(
-                        mRunLoop, mFrameBufferSource);
-                break;
-            }
-
-            default:
-                LOG(FATAL) << "Should not be here.";
-        }
-
-        packetizer->run();
-
-        mVideoPacketizer = packetizer;
-    }
-
-    return packetizer;
-}
-
-std::shared_ptr<Packetizer> ServerState::getAudioPacketizer() {
-    auto packetizer = mAudioPacketizer.lock();
-    if (!packetizer) {
-        packetizer = std::make_shared<OpusPacketizer>(mRunLoop, mAudioSource);
-        packetizer->run();
-
-        mAudioPacketizer = packetizer;
-    }
-
-    return packetizer;
-}
-
-size_t ServerState::acquireHandlerId() {
-    size_t id = 0;
-    while (!mAllocatedHandlerIds.insert(id).second) {
-        ++id;
-    }
-
-    return id;
-}
-
-void ServerState::releaseHandlerId(size_t id) {
-    CHECK_EQ(mAllocatedHandlerIds.erase(id), 1);
-}
-
-std::shared_ptr<android::TouchSink> ServerState::getTouchSink() {
-    return mTouchSink;
-}
-
-std::shared_ptr<android::KeyboardSink> ServerState::getKeyboardSink() {
-    return mKeyboardSink;
-}
diff --git a/host/frontend/gcastv2/webrtc/Utils.cpp b/host/frontend/gcastv2/webrtc/Utils.cpp
deleted file mode 100644
index 56c6158..0000000
--- a/host/frontend/gcastv2/webrtc/Utils.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include "Utils.h"
-
-std::vector<std::string> SplitString(const std::string &s, char c) {
-    return SplitString(s, std::string(1 /* count */, c));
-}
-
-std::vector<std::string> SplitString(
-        const std::string &s, const std::string &separator) {
-    std::vector<std::string> pieces;
-
-    size_t startPos = 0;
-    size_t matchPos;
-    while ((matchPos = s.find(separator, startPos)) != std::string::npos) {
-        pieces.push_back(std::string(s, startPos, matchPos - startPos));
-        startPos = matchPos + separator.size();
-    }
-
-    if (startPos < s.size()) {
-        pieces.push_back(std::string(s, startPos));
-    }
-
-    return pieces;
-}
-
-bool StartsWith(const std::string &s, const std::string &prefix) {
-    return s.find(prefix) == 0;
-}
-
-std::string StringPrintf(const char *format, ...) {
-    va_list ap;
-    va_start(ap, format);
-
-    char *buffer;
-    (void)vasprintf(&buffer, format, ap);
-
-    va_end(ap);
-
-    std::string result(buffer);
-
-    free(buffer);
-    buffer = NULL;
-
-    return result;
-}
-
-void SET_U16(void *_dst, uint16_t x) {
-    uint8_t *dst = static_cast<uint8_t *>(_dst);
-    dst[0] = x >> 8;
-    dst[1] = x & 0xff;
-}
-
-void SET_U32(void *_dst, uint32_t x) {
-    uint8_t *dst = static_cast<uint8_t *>(_dst);
-    dst[0] = x >> 24;
-    dst[1] = (x >> 16) & 0xff;
-    dst[2] = (x >> 8) & 0xff;
-    dst[3] = x & 0xff;
-}
-
-static const uint32_t crc32_tab[] = {
-    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
-    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
-    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
-    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
-    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
-    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
-    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
-    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
-    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
-    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
-    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
-    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
-    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
-    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
-    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
-    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
-    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
-    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
-    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
-    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
-    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
-    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
-    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
-    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
-    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
-    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
-    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
-    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
-    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
-    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
-    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
-};
-
-uint32_t computeCrc32(const void *_data, size_t size) {
-    const uint8_t *data = static_cast<const uint8_t *>(_data);
-
-    uint32_t crc = 0xffffffff;
-
-    for (size_t i = 0; i < size; ++i) {
-        uint32_t lkp = crc32_tab[(crc ^ data[i]) & 0xFF];
-        crc =  lkp ^ (crc >> 8);
-    }
-
-    return crc ^ 0xffffffff;
-}
diff --git a/host/frontend/gcastv2/webrtc/VP8Packetizer.cpp b/host/frontend/gcastv2/webrtc/VP8Packetizer.cpp
deleted file mode 100644
index 69039b3..0000000
--- a/host/frontend/gcastv2/webrtc/VP8Packetizer.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include <webrtc/VP8Packetizer.h>
-
-#include "Utils.h"
-
-#include <webrtc/RTPSocketHandler.h>
-
-#include <https/SafeCallbackable.h>
-#include <https/Support.h>
-
-using namespace android;
-
-VP8Packetizer::VP8Packetizer(
-        std::shared_ptr<RunLoop> runLoop,
-        std::shared_ptr<StreamingSource> frameBufferSource)
-    : Packetizer(runLoop, frameBufferSource) {
-}
-
-void VP8Packetizer::packetize(const std::shared_ptr<SBuffer> &accessUnit, int64_t timeUs) {
-    static constexpr uint8_t PT = 96;
-    static constexpr uint32_t SSRC = 0xdeadbeef;
-
-    // XXX Retransmission packets add 2 bytes (for the original seqNum), should
-    // probably reserve that amount in the original packets so we don't exceed
-    // the MTU on retransmission.
-    static const size_t kMaxSRTPPayloadSize =
-        RTPSocketHandler::kMaxUDPPayloadSize - SRTP_MAX_TRAILER_LEN;
-
-    const uint8_t *src = accessUnit->data();
-    size_t srcSize = accessUnit->size();
-
-    uint32_t rtpTime = ((timeUs - mediaStartTime()) * 9) / 100;
-
-    LOG(VERBOSE) << "got accessUnit of size " << srcSize;
-
-    size_t srcOffset = 0;
-    while (srcOffset < srcSize) {
-        size_t packetSize = 12;  // generic RTP header
-
-        packetSize += 1;  // VP8 Payload Descriptor
-
-        auto copy = std::min(srcSize - srcOffset, kMaxSRTPPayloadSize - packetSize);
-
-        packetSize += copy;
-
-        std::vector<uint8_t> packet(packetSize);
-        uint8_t *dst = packet.data();
-
-        dst[0] = 0x80;
-
-        dst[1] = PT;
-        if (srcOffset + copy == srcSize) {
-            dst[1] |= 0x80;  // (M)ark
-        }
-
-        SET_U16(&dst[2], 0);  // seqNum
-        SET_U32(&dst[4], rtpTime);
-        SET_U32(&dst[8], SSRC);
-
-        size_t dstOffset = 12;
-
-        // VP8 Payload Descriptor
-        dst[dstOffset++] = (srcOffset == 0) ? 0x10 : 0x00;  // S
-
-        memcpy(&dst[dstOffset], &src[srcOffset], copy);
-        dstOffset += copy;
-
-        CHECK_EQ(dstOffset, packetSize);
-
-        srcOffset += copy;
-
-        queueRTPDatagram(&packet);
-    }
-}
-
-uint32_t VP8Packetizer::rtpNow() const {
-    return (timeSinceStart() * 90) / 1000;
-}
diff --git a/host/frontend/gcastv2/webrtc/assets/index.html b/host/frontend/gcastv2/webrtc/assets/index.html
deleted file mode 100644
index 5a249f6..0000000
--- a/host/frontend/gcastv2/webrtc/assets/index.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<html>
-    <head>
-        <title>My Virtual Device Playground</title>
-
-        <link rel="stylesheet" type="text/css" href="style.css" >
-    </head>
-
-    <body>
-        <button id="receiveButton">Receive Media</button>
-        <button id="keyboardCaptureBtn">Capture Keyboard</button>
-        <button id="resizeButton">Resize Viewport</button>
-        <hr>
-        <section class="noscroll">
-            <div class="one" >
-                <video id="deviceScreen" autoplay width="540" height="1080" style="touch-action:none" ></video>
-            </div>
-
-            <div class="two" >
-                <textarea id="logcat" rows="55" cols="120" readonly >
-                </textarea>
-            </div>
-        </section>
-
-        <script src="js/receive.js"></script>
-        <script src="js/logcat.js"></script>
-        <script src="js/viewpane.js"></script>
-    </body>
-
-</html>
-
diff --git a/host/frontend/gcastv2/webrtc/assets/js/logcat.js b/host/frontend/gcastv2/webrtc/assets/js/logcat.js
deleted file mode 100644
index aae94bc..0000000
--- a/host/frontend/gcastv2/webrtc/assets/js/logcat.js
+++ /dev/null
@@ -1,163 +0,0 @@
-let adb_ws;
-let logcat = document.getElementById('logcat');
-
-let utf8Encoder = new TextEncoder();
-let utf8Decoder = new TextDecoder();
-
-const A_CNXN = 0x4e584e43;
-const A_OPEN = 0x4e45504f;
-const A_WRTE = 0x45545257;
-const A_OKAY = 0x59414b4f;
-
-const kLocalChannelId = 666;
-
-function setU32LE(array, offset, x) {
-    array[offset] = x & 0xff;
-    array[offset + 1] = (x >> 8) & 0xff;
-    array[offset + 2] = (x >> 16) & 0xff;
-    array[offset + 3] = x >> 24;
-}
-
-function getU32LE(array, offset) {
-    let x = array[offset]
-        | (array[offset + 1] << 8)
-        | (array[offset + 2] << 16)
-        | (array[offset + 3] << 24);
-
-    return x >>> 0;  // convert signed to unsigned if necessary.
-}
-
-function computeChecksum(array) {
-    let sum = 0;
-    let i;
-    for (i = 0; i < array.length; ++i) {
-        sum = ((sum + array[i]) & 0xffffffff) >>> 0;
-    }
-
-    return sum;
-}
-
-function createAdbMessage(command, arg0, arg1, payload) {
-    let arrayBuffer = new ArrayBuffer(24 + payload.length);
-    let array = new Uint8Array(arrayBuffer);
-    setU32LE(array, 0, command);
-    setU32LE(array, 4, arg0);
-    setU32LE(array, 8, arg1);
-    setU32LE(array, 12, payload.length);
-    setU32LE(array, 16, computeChecksum(payload));
-    setU32LE(array, 20, command ^ 0xffffffff);
-    array.set(payload, 24);
-
-    return arrayBuffer;
-}
-
-function adbOpenConnection() {
-    let systemIdentity = utf8Encoder.encode("Cray_II:1234:whatever");
-
-    let arrayBuffer = createAdbMessage(
-        A_CNXN, 0x1000000, 256 * 1024, systemIdentity);
-
-    adb_ws.send(arrayBuffer);
-}
-
-function adbOpenChannel() {
-    let destination = utf8Encoder.encode("shell:logcat");
-
-    let arrayBuffer = createAdbMessage(A_OPEN, kLocalChannelId, 0, destination);
-    adb_ws.send(arrayBuffer);
-}
-
-function adbSendOkay(remoteId) {
-    let payload = new Uint8Array(0);
-
-    let arrayBuffer = createAdbMessage(
-        A_OKAY, kLocalChannelId, remoteId, payload);
-
-    adb_ws.send(arrayBuffer);
-}
-
-function adbOnMessage(ev) {
-    // console.log("adb_ws: onmessage (" + ev.data.byteLength + " bytes)");
-
-    let arrayBuffer = ev.data;
-    let array = new Uint8Array(arrayBuffer);
-
-    if (array.length < 24) {
-        console.log("adb message too short.");
-        return;
-    }
-
-    let command = getU32LE(array, 0);
-    let magic = getU32LE(array, 20);
-
-    if (command != ((magic ^ 0xffffffff) >>> 0)) {
-        console.log("command = " + command + ", magic = " + magic);
-        console.log("adb message command vs magic failed.");
-        return;
-    }
-
-    let payloadLength = getU32LE(array, 12);
-
-    if (array.length != 24 + payloadLength) {
-        console.log("adb message length mismatch.");
-        return;
-    }
-
-    let payloadChecksum = getU32LE(array, 16);
-    let checksum = computeChecksum(array.slice(24));
-
-    if (payloadChecksum != checksum) {
-        console.log("adb message checksum mismatch.");
-        return;
-    }
-
-    switch (command) {
-        case A_CNXN:
-        {
-            console.log("connected.");
-
-            adbOpenChannel();
-            break;
-        }
-
-        case A_OKAY:
-        {
-            let remoteId = getU32LE(array, 4);
-            console.log("channel created w/ remoteId " + remoteId);
-            break;
-        }
-
-        case A_WRTE:
-        {
-            let payloadText = utf8Decoder.decode(array.slice(24));
-
-            logcat.value += payloadText;
-
-            // Scroll to bottom
-            logcat.scrollTop = logcat.scrollHeight;
-
-            let remoteId = getU32LE(array, 4);
-            adbSendOkay(remoteId);
-            break;
-        }
-    }
-}
-
-function init_logcat() {
-    const wsProtocol = (location.protocol == "http:") ? "ws:" : "wss:";
-
-    adb_ws = new WebSocket(
-        wsProtocol + "//" + location.host + "/control_adb");
-
-    adb_ws.binaryType = "arraybuffer";
-
-    adb_ws.onopen = function() {
-        console.log("adb_ws: onopen");
-
-        adbOpenConnection();
-
-        logcat.style.display = "initial";
-    };
-    adb_ws.onmessage = adbOnMessage;
-}
-
diff --git a/host/frontend/gcastv2/webrtc/assets/js/receive.js b/host/frontend/gcastv2/webrtc/assets/js/receive.js
deleted file mode 100644
index d47566c..0000000
--- a/host/frontend/gcastv2/webrtc/assets/js/receive.js
+++ /dev/null
@@ -1,453 +0,0 @@
-'use strict';
-
-const receiveButton = document.getElementById('receiveButton');
-receiveButton.addEventListener('click', onReceive);
-const keyboardCaptureButton = document.getElementById('keyboardCaptureBtn');
-keyboardCaptureButton.addEventListener('click', onKeyboardCaptureClick);
-
-const deviceScreen = document.getElementById('deviceScreen');
-
-deviceScreen.addEventListener("click", onInitialClick);
-
-function onInitialClick(e) {
-    // This stupid thing makes sure that we disable controls after the first click...
-    // Why not just disable controls altogether you ask? Because then audio won't play
-    // because these days user-interaction is required to enable audio playback...
-    console.log("onInitialClick");
-
-    deviceScreen.controls = false;
-    deviceScreen.removeEventListener("click", onInitialClick);
-}
-
-let pc1;
-let pc2;
-
-let dataChannel;
-
-let ws;
-
-let offerResolve;
-let iceCandidateResolve;
-
-let videoStream;
-
-let mouseIsDown = false;
-
-const is_chrome = navigator.userAgent.indexOf("Chrome") !== -1;
-
-function handleDataChannelStatusChange(event) {
-    console.log('handleDataChannelStatusChange state=' + dataChannel.readyState);
-
-    if (dataChannel.readyState == "open") {
-        dataChannel.send("Hello, world!");
-    }
-}
-
-function handleDataChannelMessage(event) {
-    console.log('handleDataChannelMessage data="' + event.data + '"');
-}
-
-function onKeyboardCaptureClick(e) {
-    const selectedClass = 'selected';
-    if (keyboardCaptureButton.classList.contains(selectedClass)) {
-        stopKeyboardTracking();
-        keyboardCaptureButton.classList.remove(selectedClass);
-    } else {
-        startKeyboardTracking();
-        keyboardCaptureButton.classList.add(selectedClass);
-    }
-}
-
-async function onReceive() {
-    console.log('onReceive');
-    receiveButton.disabled = true;
-
-    init_logcat();
-
-    const wsProtocol = (location.protocol == "http:") ? "ws:" : "wss:";
-
-    ws = new WebSocket(wsProtocol + "//" + location.host + "/control");
-    // temporarily disable audio to free ports in the server since it's only
-    // producing silence anyways.
-    var search = location.search + "&disable_audio=1";
-    search = '?' + search.substr(1);
-
-    ws.onopen = function() {
-        console.log("onopen");
-        ws.send('{\r\n'
-            +     '"type": "greeting",\r\n'
-            +     '"message": "Hello, world!",\r\n'
-            +     '"path": "' + location.pathname + search + '"\r\n'
-            +   '}');
-    };
-    ws.onmessage = function(e) {
-        console.log("onmessage " + e.data);
-
-        let data = JSON.parse(e.data);
-        if (data.type == "hello") {
-            kickoff();
-        } else if (data.type == "offer" && offerResolve) {
-            offerResolve(data.sdp);
-            offerResolve = undefined;
-        } else if (data.type == "ice-candidate" && iceCandidateResolve) {
-            iceCandidateResolve(data);
-
-            iceCandidateResolve = undefined;
-        }
-    };
-
-    pc2 = new RTCPeerConnection();
-    console.log('got pc2=' + pc2);
-
-    pc2.addEventListener(
-        'icecandidate', e => onIceCandidate(pc2, e));
-
-    pc2.addEventListener(
-        'iceconnectionstatechange', e => onIceStateChange(pc2, e));
-
-    pc2.addEventListener(
-        'connectionstatechange', e => {
-        console.log("connection state = " + pc2.connectionState);
-    });
-
-    pc2.addEventListener('track', onGotRemoteStream);
-
-    dataChannel = pc2.createDataChannel("data-channel");
-    dataChannel.onopen = handleDataChannelStatusChange;
-    dataChannel.onclose = handleDataChannelStatusChange;
-    dataChannel.onmessage = handleDataChannelMessage;
-}
-
-async function kickoff() {
-    console.log('createOffer start');
-
-    try {
-        var offer = await getWsOffer();
-        await onCreateOfferSuccess(offer);
-    } catch (e) {
-        console.log('createOffer FAILED ');
-    }
-}
-
-async function onCreateOfferSuccess(desc) {
-    console.log(`Offer ${desc.sdp}`);
-
-    try {
-        pc2.setRemoteDescription(desc);
-    } catch (e) {
-        console.log('setRemoteDescription pc2 FAILED');
-        return;
-    }
-
-    console.log('setRemoteDescription pc2 successful.');
-
-    try {
-        setWsLocalDescription(desc);
-    } catch (e) {
-        console.log('setLocalDescription pc1 FAILED');
-        return;
-    }
-
-    console.log('setLocalDescription pc1 successful.');
-
-    try {
-        const answer = await pc2.createAnswer();
-
-        await onCreateAnswerSuccess(answer);
-    } catch (e) {
-        console.log('createAnswer FAILED');
-    }
-}
-
-function setWsRemoteDescription(desc) {
-    ws.send('{\r\n'
-        +     '"type": "set-remote-desc",\r\n'
-        +     '"sdp": "' + desc.sdp + '"\r\n'
-        +   '}');
-}
-
-function setWsLocalDescription(desc) {
-    ws.send('{\r\n'
-        +     '"type": "set-local-desc",\r\n'
-        +     '"sdp": "' + desc.sdp + '"\r\n'
-        +   '}');
-}
-
-async function getWsOffer() {
-    const offerPromise = new Promise(function(resolve, reject) {
-        offerResolve = resolve;
-    });
-
-    ws.send('{\r\n'
-        +     '"type": "request-offer",\r\n'
-        +     (is_chrome ? '"is_chrome": 1\r\n'
-                         : '"is_chrome": 0\r\n')
-        +   '}');
-
-    const sdp = await offerPromise;
-
-    return { type: "offer", sdp: sdp };
-}
-
-async function getWsIceCandidate(mid) {
-    console.log("getWsIceCandidate (mid=" + mid + ")");
-
-    const answerPromise = new Promise(function(resolve, reject) {
-        iceCandidateResolve = resolve;
-    });
-
-    ws.send('{\r\n'
-        +     '"type": "get-ice-candidate",\r\n'
-        +     '"mid": ' + mid + ',\r\n'
-        +   '}');
-
-    const replyInfo = await answerPromise;
-
-    console.log("got replyInfo '" + replyInfo + "'");
-
-    if (replyInfo == undefined || replyInfo.candidate == undefined) {
-        return null;
-    }
-
-    const replyCandidate = replyInfo.candidate;
-    const mlineIndex = replyInfo.mlineIndex;
-
-    let result;
-    try {
-        result = new RTCIceCandidate(
-            {
-                sdpMid: mid,
-                sdpMLineIndex: mlineIndex,
-                candidate: replyCandidate
-            });
-    }
-    catch (e) {
-        console.log("new RTCIceCandidate FAILED. " + e);
-        return undefined;
-    }
-
-    console.log("got result " + result);
-
-    return result;
-}
-
-async function addRemoteIceCandidate(mid) {
-    const candidate = await getWsIceCandidate(mid);
-
-    if (!candidate) {
-        return false;
-    }
-
-    try {
-        await pc2.addIceCandidate(candidate);
-    } catch (e) {
-        console.log("addIceCandidate pc2 FAILED w/ " + e);
-        return false;
-    }
-
-    console.log("addIceCandidate pc2 successful. (mid="
-        + mid + ", mlineIndex=" + candidate.sdpMLineIndex + ")");
-
-    return true;
-}
-
-async function onCreateAnswerSuccess(desc) {
-    console.log(`Answer ${desc.sdp}`);
-
-    try {
-        await pc2.setLocalDescription(desc);
-    } catch (e) {
-        console.log('setLocalDescription pc2 FAILED ' + e);
-        return;
-    }
-
-    console.log('setLocalDescription pc2 successful.');
-
-    try {
-        setWsRemoteDescription(desc);
-    } catch (e) {
-        console.log('setRemoteDescription pc1 FAILED');
-        return;
-    }
-
-    console.log('setRemoteDescription pc1 successful.');
-
-    if (!await addRemoteIceCandidate(0)) {
-        return;
-    }
-    await addRemoteIceCandidate(1);
-    await addRemoteIceCandidate(2);
-}
-
-function getPcName(pc) {
-    return ((pc == pc2) ? "pc2" : "pc1");
-}
-
-async function onIceCandidate(pc, e) {
-    console.log(
-        getPcName(pc)
-        + ' onIceCandidate '
-        + (e.candidate ? ('"' + e.candidate.candidate + '"') : '(null)')
-        + " "
-        + (e.candidate ? ('sdmMid: ' + e.candidate.sdpMid) : '(null)')
-        + " "
-        + (e.candidate ? ('sdpMLineIndex: ' + e.candidate.sdpMLineIndex) : '(null)'));
-
-    if (!e.candidate) {
-        return;
-    }
-
-    let other_pc = (pc == pc2) ? pc1 : pc2;
-
-    if (other_pc) {
-        try {
-            await other_pc.addIceCandidate(e.candidate);
-        } catch (e) {
-            console.log('addIceCandidate FAILED ' + e);
-            return;
-        }
-
-        console.log('addIceCandidate successful.');
-    }
-}
-
-async function onIceStateChange(pc, e) {
-    console.log(
-        'onIceStateChange ' + getPcName(pc) + " '" + pc.iceConnectionState + "'");
-
-    if (pc.iceConnectionState == "connected") {
-        deviceScreen.srcObject = videoStream;
-
-        startMouseTracking()
-    } else if (pc.iceConnectionState == "disconnected") {
-        stopMouseTracking()
-    }
-}
-
-async function onGotRemoteStream(e) {
-    console.log('onGotRemoteStream ' + e);
-
-    const track = e.track;
-
-    console.log('track = ' + track);
-    console.log('track.kind = ' + track.kind);
-    console.log('track.readyState = ' + track.readyState);
-    console.log('track.enabled = ' + track.enabled);
-
-    if (track.kind == "video") {
-        videoStream = e.streams[0];
-    }
-}
-
-function startMouseTracking() {
-    if (window.PointerEvent) {
-        deviceScreen.addEventListener("pointerdown", onStartDrag);
-        deviceScreen.addEventListener("pointermove", onContinueDrag);
-        deviceScreen.addEventListener("pointerup", onEndDrag);
-    } else if (window.TouchEvent) {
-        deviceScreen.addEventListener("touchstart", onStartDrag);
-        deviceScreen.addEventListener("touchmove", onContinueDrag);
-        deviceScreen.addEventListener("touchend", onEndDrag);
-    } else if (window.MouseEvent) {
-        deviceScreen.addEventListener("mousedown", onStartDrag);
-        deviceScreen.addEventListener("mousemove", onContinueDrag);
-        deviceScreen.addEventListener("mouseup", onEndDrag);
-    }
-}
-
-function stopMouseTracking() {
-    if (window.PointerEvent) {
-        deviceScreen.removeEventListener("pointerdown", onStartDrag);
-        deviceScreen.removeEventListener("pointermove", onContinueDrag);
-        deviceScreen.removeEventListener("pointerup", onEndDrag);
-    } else if (window.TouchEvent) {
-        deviceScreen.removeEventListener("touchstart", onStartDrag);
-        deviceScreen.removeEventListener("touchmove", onContinueDrag);
-        deviceScreen.removeEventListener("touchend", onEndDrag);
-    } else if (window.MouseEvent) {
-        deviceScreen.removeEventListener("mousedown", onStartDrag);
-        deviceScreen.removeEventListener("mousemove", onContinueDrag);
-        deviceScreen.removeEventListener("mouseup", onEndDrag);
-    }
-}
-
-function startKeyboardTracking() {
-    document.addEventListener('keydown', onKeyEvent);
-    document.addEventListener('keyup', onKeyEvent);
-}
-
-function stopKeyboardTracking() {
-    document.removeEventListener('keydown', onKeyEvent);
-    document.removeEventListener('keyup', onKeyEvent);
-}
-
-function onStartDrag(e) {
-    e.preventDefault();
-
-    // console.log("mousedown at " + e.pageX + " / " + e.pageY);
-    mouseIsDown = true;
-
-    sendMouseUpdate(true, e);
-}
-
-function onEndDrag(e) {
-    e.preventDefault();
-
-    // console.log("mouseup at " + e.pageX + " / " + e.pageY);
-    mouseIsDown = false;
-
-    sendMouseUpdate(false, e);
-}
-
-function onContinueDrag(e) {
-    e.preventDefault();
-
-    // console.log("mousemove at " + e.pageX + " / " + e.pageY + ", down=" + mouseIsDown);
-    if (mouseIsDown) {
-        sendMouseUpdate(true, e);
-    }
-}
-
-function sendMouseUpdate(down, e) {
-    var x = e.offsetX;
-    var y = e.offsetY;
-
-    const videoWidth = deviceScreen.videoWidth;
-    const videoHeight = deviceScreen.videoHeight;
-    const elementWidth = deviceScreen.width;
-    const elementHeight = deviceScreen.height;
-
-    // vh*ew > eh*vw? then scale h instead of w
-    const scaleHeight = videoHeight * elementWidth > videoWidth * elementHeight;
-    var elementScaling = 0, videoScaling = 0;
-    if (scaleHeight) {
-        elementScaling = elementHeight;
-        videoScaling = videoHeight;
-    } else {
-        elementScaling = elementWidth;
-        videoScaling = videoWidth;
-    }
-
-    // Substract the offset produced by the difference in aspect ratio if any.
-    if (scaleHeight) {
-        x -= (elementWidth - elementScaling * videoWidth / videoScaling) / 2;
-    } else {
-        y -= (elementHeight - elementScaling * videoHeight / videoScaling) / 2;
-    }
-
-    // Convert to coordinates relative to the video
-    x = videoScaling * x / elementScaling;
-    y = videoScaling * y / elementScaling;
-
-    ws.send('{\r\n'
-        +     '"type": "set-mouse-position",\r\n'
-        +     '"down": ' + (down ? "1" : "0") + ',\r\n'
-        +     '"x": ' + Math.trunc(x) + ',\r\n'
-        +     '"y": ' + Math.trunc(y) + '\r\n'
-        +   '}');
-}
-
-function onKeyEvent(e) {
-    e.preventDefault();
-    ws.send('{"type": "key-event","keycode": "'+e.code+'", "event_type": "'+e.type+'"}');
-}
\ No newline at end of file
diff --git a/host/frontend/gcastv2/webrtc/assets/js/viewpane.js b/host/frontend/gcastv2/webrtc/assets/js/viewpane.js
deleted file mode 100644
index 62297a4..0000000
--- a/host/frontend/gcastv2/webrtc/assets/js/viewpane.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Resize button will control the execution of the resizeDeviceScreen function
-const resizeButton = document.getElementById('resizeButton');
-resizeButton.addEventListener('click', resizeDeviceScreen);
-
-// This will be used to set the max size for the video element.
-// Ex. 0.9 means that the video element will be at most 90% of the windowSize
-const maxVideoRatio = 0.9;
-
-function resizeDeviceScreen() {
-    // Capture/derive all the relevant dimensions
-    var viewportHeight = window.innerHeight;
-    var viewportWidth = window.innerWidth;
-    var maxHeight = viewportHeight * maxVideoRatio;
-    var maxWidth = viewportWidth * maxVideoRatio;
-    var videoWidth = deviceScreen.videoWidth;
-    var videoHeight = deviceScreen.videoHeight;
-
-    if (videoHeight <= maxHeight && videoWidth <= maxWidth) {
-        deviceScreen.setAttribute('height', videoHeight);
-        deviceScreen.setAttribute('width', videoWidth);
-    }
-    else {
-        deviceScreen.setAttribute('height', maxHeight);
-        deviceScreen.setAttribute('width', maxWidth);
-    }
-}
-
-// Listen for the 'play' event on the primary video element
-deviceScreen.addEventListener('play', resizeDeviceScreen);
\ No newline at end of file
diff --git a/host/frontend/gcastv2/webrtc/assets/style.css b/host/frontend/gcastv2/webrtc/assets/style.css
deleted file mode 100644
index a782b0a..0000000
--- a/host/frontend/gcastv2/webrtc/assets/style.css
+++ /dev/null
@@ -1,29 +0,0 @@
-body {
-    background-color:black
-},
-html {
-#    position: fixed;
-}
-
-.noscroll {
-    touch-action: none;
-}
-
-.one {
-    float: left;
-}
-
-.two {
-}
-
-#logcat {
-    display: none;
-    font-family: monospace;
-    padding: 10px;
-}
-
-button.selected {
-    background-color: #aaaaaa;
-    border-style: solid;
-    border-color: #aaaaaa;
-}
\ No newline at end of file
diff --git a/host/frontend/gcastv2/webrtc/certs/create_certs.sh b/host/frontend/gcastv2/webrtc/certs/create_certs.sh
deleted file mode 100755
index 9f85e40..0000000
--- a/host/frontend/gcastv2/webrtc/certs/create_certs.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-# As explained in
-#  https://gist.github.com/darrenjs/4645f115d10aa4b5cebf57483ec82eca
-
-openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
-openssl rsa -passin pass:x -in server.pass.key -out server.key
-rm -f server.pass.key
-
-openssl req \
-    -subj "/C=US/ST=California/L=Santa Clara/O=Beyond Aggravated/CN=localhost" \
-    -new -key server.key -out server.csr
-
-openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
-rm -f server.csr
-
-# Now create the list of certificates we trust as a client.
-
-rm trusted.pem
-
-# For now we just trust our own server.
-openssl x509 -in server.crt -text >> trusted.pem
-
-# Also add the system standard CA cert chain.
-# cat /opt/local/etc/openssl/cert.pem >> trusted.pem
-
-# Convert .pem to .der
-# openssl x509 -outform der -in trusted.pem -out trusted.der
-
-# Convert .crt and .key to .p12 for use by Security.framework
-# Enter password "foo"!
-openssl pkcs12 -export -inkey server.key -in server.crt -name localhost -out server.p12
diff --git a/host/frontend/gcastv2/webrtc/certs/server.crt b/host/frontend/gcastv2/webrtc/certs/server.crt
deleted file mode 100644
index 0b9aa36..0000000
--- a/host/frontend/gcastv2/webrtc/certs/server.crt
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDVzCCAj8CFBXBydw0e/7l31d9fzO7vrBxAw4yMA0GCSqGSIb3DQEBCwUAMGgx
-CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50
-YSBDbGFyYTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxv
-Y2FsaG9zdDAeFw0yMDA1MDcyMTMzMDFaFw0yMTA1MDcyMTMzMDFaMGgxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50YSBDbGFy
-YTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxvY2FsaG9z
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPdz0Tom1NSujwxYFhG2
-MnqTTU5F9E5OwnO9svlXchXozJSoYpuFG43ZI/9exVmhQKZ4WwJUX74beYuZh611
-S1v9nAiAX+w3lpaiH/9gNH9PaR6kyOTveS9DtHqHlsHm9Ahuls/6mIlHVLsfGVcS
-DDIu5eYqBU0Xq1RYm3+9EUtEOLPQGfcaSUTnI6AkZ55TcJiKhq0CIoTpv/I+7mlw
-zsqPi2f2G7kI47bz1aiXeh34jelKR321fKl1/DW3F0CLSj0/u4gMgNIgPB/tHIKj
-GiNnvJTE7ZDSV34oUmqKhKkUixwjFHUFpMislpIJTsefzaKE4NLa57g5qgAnaofw
-m1UCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEASZx0QGNR5DT8vUgEBTMD1OKG3rFw
-zXLI1Lsn5nIMSGkL7aIlx7D8lbdvy0OS+Cg8jE256yiM7cZTF07rKwUeI2v/wDrX
-KP9qfMhonICrbQyKlZ6J4hLVV9wCkYQnMqwS+uSH1l1X+qr3ZCcamgTZ2hrhJFy4
-HEeoC4qdL0+uM2NhrjmPBvqMq9hYWe3nAREmRjSAxBMawjThldLqQCooyvtMskkn
-QAzPte/qvP4kWRpI+KQEv9Rc8iI9PNCF9+W4zl6pIyRDRVYWx3C1PSdniaTc/yDQ
-FL5UbuZ5ujUOdvMy1yAlcTiDVo+Ke7ybAK9FhEBxMPELyTFTY0GVKI46QA==
------END CERTIFICATE-----
diff --git a/host/frontend/gcastv2/webrtc/certs/server.key b/host/frontend/gcastv2/webrtc/certs/server.key
deleted file mode 100644
index 616a4ce..0000000
--- a/host/frontend/gcastv2/webrtc/certs/server.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpgIBAAKCAQEA93PROibU1K6PDFgWEbYyepNNTkX0Tk7Cc72y+VdyFejMlKhi
-m4Ubjdkj/17FWaFApnhbAlRfvht5i5mHrXVLW/2cCIBf7DeWlqIf/2A0f09pHqTI
-5O95L0O0eoeWweb0CG6Wz/qYiUdUux8ZVxIMMi7l5ioFTRerVFibf70RS0Q4s9AZ
-9xpJROcjoCRnnlNwmIqGrQIihOm/8j7uaXDOyo+LZ/YbuQjjtvPVqJd6HfiN6UpH
-fbV8qXX8NbcXQItKPT+7iAyA0iA8H+0cgqMaI2e8lMTtkNJXfihSaoqEqRSLHCMU
-dQWkyKyWkglOx5/NooTg0trnuDmqACdqh/CbVQIDAQABAoIBAQCnBGrxvwfjzTYL
-9OBgcAM+LHH/JMQynoIssJs+JEGCfDCpHcYAhiUE5syfLo4xYt9J/O4gcmZ04AJ3
-sNacwxBsNI6+Rjd4LkTbwu2p5ntIeobPAhX+P4wh1KbaFO4yTfnkPxBXrCKMdbLA
-4cqutCW7MWBGq5IMaK9hLLU30Jr9muiEIQ8tnexghJ4SiHnpju471KD9N77dRVZp
-TmUnIlJLqYMNoPj0nLwy6p1isq1KSg56j27OooL8piqOp2cy82GqjNeCfFcW74dJ
-lYmxILLseJiJvM2nlfFdSOvSOtaBkSG5oKsOO1K56u3cXhwSXChu5b8ewNjG5d+Y
-KY5obpV5AoGBAP/nJGxv7ljsg/pAqfWOwR5g6Iz9JxpgweubVt9fvnS+2Pj4akrJ
-1NZZCB/9zFbYf2Of2VMBdrNw7eS2+QDwj2TYPBjIH3WMPSByyyQaNna47b26Sxu2
-kCMhkoEMvwXEEQrLZ7I/sHgzYIEGg/9yLUJmzfdqpACU4bA1zkzKQ6tnAoGBAPeL
-2qn7ch3vlVLK46tm99Jkbw2SxoJajlZ4p2kpe/EexyqInfZJ58IKQNonqYNWMOwg
-aLeoyf+XsWgnuS4njMBPLmGTa/Pibs2b/0jrHP3mp2LVrRaL+wOUDM/gzmt7NeD+
-zZ8fD4Lsj8lXLfys5M5HrosF8c3TT8odFALjLwnjAoGBAKmH3qh8CsIchl6O4knM
-tgHDH6zvtS0TdsT4lzfKfSlomeNu5zP+vCL4vpo7EFlkehhs+JO1/4ZnRSLlWNcX
-h1e+rSmZwsWkD4bkpdGYEAbdAptTxJhqfNjZT+5wnEhcmRG2qU78RJONLdysjVv4
-ryUzaDYGDvpXp6CONMrIoMX3AoGBAJV/bbg4dauklD6i7yoFjmcOZo8A9EenHs0U
-Iq588jAlUUzbouIpsgBapt3ZFCOQOw1vaS55jjyAxRBM5SX9lqBRcYZWPNzWA+rC
-akMEUsb3tGEZAGZcdWSs1av5bVA14c0WtOGDJaAA87k5oDk3xRra6YtmNKkEE+zQ
-8NPple/XAoGBAJMpXdSP+Hgakv//HaQaBcenHk1f8v4b8t48NnXjou3ojfO8Wzgr
-odwlninHk1PaQD0XnFIISMVD9d2aSX8X1YQVHUQ9IQiA4hLy2lxZbP2K+LEaVKDm
-r7cjRKixJTIGm6vZK8pr1l5XD3657fQte4YLei5XA+i/UgFZyIA0KsKo
------END RSA PRIVATE KEY-----
diff --git a/host/frontend/gcastv2/webrtc/certs/server.p12 b/host/frontend/gcastv2/webrtc/certs/server.p12
deleted file mode 100644
index 87a94c5..0000000
--- a/host/frontend/gcastv2/webrtc/certs/server.p12
+++ /dev/null
Binary files differ
diff --git a/host/frontend/gcastv2/webrtc/certs/trusted.pem b/host/frontend/gcastv2/webrtc/certs/trusted.pem
deleted file mode 100644
index 8097b16..0000000
--- a/host/frontend/gcastv2/webrtc/certs/trusted.pem
+++ /dev/null
@@ -1,70 +0,0 @@
-Certificate:
-    Data:
-        Version: 1 (0x0)
-        Serial Number:
-            15:c1:c9:dc:34:7b:fe:e5:df:57:7d:7f:33:bb:be:b0:71:03:0e:32
-        Signature Algorithm: sha256WithRSAEncryption
-        Issuer: C = US, ST = California, L = Santa Clara, O = Beyond Aggravated, CN = localhost
-        Validity
-            Not Before: May  7 21:33:01 2020 GMT
-            Not After : May  7 21:33:01 2021 GMT
-        Subject: C = US, ST = California, L = Santa Clara, O = Beyond Aggravated, CN = localhost
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-                RSA Public-Key: (2048 bit)
-                Modulus:
-                    00:f7:73:d1:3a:26:d4:d4:ae:8f:0c:58:16:11:b6:
-                    32:7a:93:4d:4e:45:f4:4e:4e:c2:73:bd:b2:f9:57:
-                    72:15:e8:cc:94:a8:62:9b:85:1b:8d:d9:23:ff:5e:
-                    c5:59:a1:40:a6:78:5b:02:54:5f:be:1b:79:8b:99:
-                    87:ad:75:4b:5b:fd:9c:08:80:5f:ec:37:96:96:a2:
-                    1f:ff:60:34:7f:4f:69:1e:a4:c8:e4:ef:79:2f:43:
-                    b4:7a:87:96:c1:e6:f4:08:6e:96:cf:fa:98:89:47:
-                    54:bb:1f:19:57:12:0c:32:2e:e5:e6:2a:05:4d:17:
-                    ab:54:58:9b:7f:bd:11:4b:44:38:b3:d0:19:f7:1a:
-                    49:44:e7:23:a0:24:67:9e:53:70:98:8a:86:ad:02:
-                    22:84:e9:bf:f2:3e:ee:69:70:ce:ca:8f:8b:67:f6:
-                    1b:b9:08:e3:b6:f3:d5:a8:97:7a:1d:f8:8d:e9:4a:
-                    47:7d:b5:7c:a9:75:fc:35:b7:17:40:8b:4a:3d:3f:
-                    bb:88:0c:80:d2:20:3c:1f:ed:1c:82:a3:1a:23:67:
-                    bc:94:c4:ed:90:d2:57:7e:28:52:6a:8a:84:a9:14:
-                    8b:1c:23:14:75:05:a4:c8:ac:96:92:09:4e:c7:9f:
-                    cd:a2:84:e0:d2:da:e7:b8:39:aa:00:27:6a:87:f0:
-                    9b:55
-                Exponent: 65537 (0x10001)
-    Signature Algorithm: sha256WithRSAEncryption
-         49:9c:74:40:63:51:e4:34:fc:bd:48:04:05:33:03:d4:e2:86:
-         de:b1:70:cd:72:c8:d4:bb:27:e6:72:0c:48:69:0b:ed:a2:25:
-         c7:b0:fc:95:b7:6f:cb:43:92:f8:28:3c:8c:4d:b9:eb:28:8c:
-         ed:c6:53:17:4e:eb:2b:05:1e:23:6b:ff:c0:3a:d7:28:ff:6a:
-         7c:c8:68:9c:80:ab:6d:0c:8a:95:9e:89:e2:12:d5:57:dc:02:
-         91:84:27:32:ac:12:fa:e4:87:d6:5d:57:fa:aa:f7:64:27:1a:
-         9a:04:d9:da:1a:e1:24:5c:b8:1c:47:a8:0b:8a:9d:2f:4f:ae:
-         33:63:61:ae:39:8f:06:fa:8c:ab:d8:58:59:ed:e7:01:11:26:
-         46:34:80:c4:13:1a:c2:34:e1:95:d2:ea:40:2a:28:ca:fb:4c:
-         b2:49:27:40:0c:cf:b5:ef:ea:bc:fe:24:59:1a:48:f8:a4:04:
-         bf:d4:5c:f2:22:3d:3c:d0:85:f7:e5:b8:ce:5e:a9:23:24:43:
-         45:56:16:c7:70:b5:3d:27:67:89:a4:dc:ff:20:d0:14:be:54:
-         6e:e6:79:ba:35:0e:76:f3:32:d7:20:25:71:38:83:56:8f:8a:
-         7b:bc:9b:00:af:45:84:40:71:30:f1:0b:c9:31:53:63:41:95:
-         28:8e:3a:40
------BEGIN CERTIFICATE-----
-MIIDVzCCAj8CFBXBydw0e/7l31d9fzO7vrBxAw4yMA0GCSqGSIb3DQEBCwUAMGgx
-CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50
-YSBDbGFyYTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxv
-Y2FsaG9zdDAeFw0yMDA1MDcyMTMzMDFaFw0yMTA1MDcyMTMzMDFaMGgxCzAJBgNV
-BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50YSBDbGFy
-YTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxvY2FsaG9z
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPdz0Tom1NSujwxYFhG2
-MnqTTU5F9E5OwnO9svlXchXozJSoYpuFG43ZI/9exVmhQKZ4WwJUX74beYuZh611
-S1v9nAiAX+w3lpaiH/9gNH9PaR6kyOTveS9DtHqHlsHm9Ahuls/6mIlHVLsfGVcS
-DDIu5eYqBU0Xq1RYm3+9EUtEOLPQGfcaSUTnI6AkZ55TcJiKhq0CIoTpv/I+7mlw
-zsqPi2f2G7kI47bz1aiXeh34jelKR321fKl1/DW3F0CLSj0/u4gMgNIgPB/tHIKj
-GiNnvJTE7ZDSV34oUmqKhKkUixwjFHUFpMislpIJTsefzaKE4NLa57g5qgAnaofw
-m1UCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEASZx0QGNR5DT8vUgEBTMD1OKG3rFw
-zXLI1Lsn5nIMSGkL7aIlx7D8lbdvy0OS+Cg8jE256yiM7cZTF07rKwUeI2v/wDrX
-KP9qfMhonICrbQyKlZ6J4hLVV9wCkYQnMqwS+uSH1l1X+qr3ZCcamgTZ2hrhJFy4
-HEeoC4qdL0+uM2NhrjmPBvqMq9hYWe3nAREmRjSAxBMawjThldLqQCooyvtMskkn
-QAzPte/qvP4kWRpI+KQEv9Rc8iI9PNCF9+W4zl6pIyRDRVYWx3C1PSdniaTc/yDQ
-FL5UbuZ5ujUOdvMy1yAlcTiDVo+Ke7ybAK9FhEBxMPELyTFTY0GVKI46QA==
------END CERTIFICATE-----
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/AdbWebSocketHandler.h b/host/frontend/gcastv2/webrtc/include/webrtc/AdbWebSocketHandler.h
deleted file mode 100644
index 0a622b2..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/AdbWebSocketHandler.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/WebSocketHandler.h>
-#include <https/RunLoop.h>
-
-#include <memory>
-
-struct AdbWebSocketHandler
-    : public WebSocketHandler,
-      public std::enable_shared_from_this<AdbWebSocketHandler> {
-
-    explicit AdbWebSocketHandler(
-            std::shared_ptr<RunLoop> runLoop,
-            const std::string &adb_host_and_port);
-
-    ~AdbWebSocketHandler() override;
-
-    void run();
-
-    int handleMessage(
-            uint8_t headerByte, const uint8_t *msg, size_t len) override;
-
-private:
-    struct AdbConnection;
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    std::shared_ptr<AdbConnection> mAdbConnection;
-
-    int mSocket;
-
-    int setupSocket(const std::string &adb_host_and_port);
-};
-
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/DTLS.h b/host/frontend/gcastv2/webrtc/include/webrtc/DTLS.h
deleted file mode 100644
index fc8738f..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/DTLS.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/RunLoop.h>
-
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-
-#include <functional>
-#include <memory>
-#include <netinet/in.h>
-#include <optional>
-#include <vector>
-
-#include <srtp2/srtp.h>
-
-struct RTPSocketHandler;
-
-struct DTLS : public std::enable_shared_from_this<DTLS> {
-    static void Init();
-
-    enum class Mode {
-        ACCEPT,
-        CONNECT
-    };
-
-    explicit DTLS(
-            std::shared_ptr<RTPSocketHandler> handler,
-            Mode mode,
-            std::shared_ptr<X509> certificate,
-            std::shared_ptr<EVP_PKEY> key,
-            const std::string &remoteFingerprint,
-            bool useSRTP);
-
-    ~DTLS();
-
-    void connect(const sockaddr_storage &remoteAddr);
-    void inject(const uint8_t *data, size_t size);
-
-    size_t protect(void *data, size_t size, bool isRTP);
-    size_t unprotect(void *data, size_t size, bool isRTP);
-
-    // Returns -EAGAIN if no data is currently available.
-    ssize_t readApplicationData(void *data, size_t size);
-
-    ssize_t writeApplicationData(const void *data, size_t size);
-
-private:
-    enum class State {
-        UNINITIALIZED,
-        CONNECTING,
-        CONNECTED,
-
-    } mState;
-
-    std::weak_ptr<RTPSocketHandler> mHandler;
-    Mode mMode;
-    std::string mRemoteFingerprint;
-    bool mUseSRTP;
-
-    SSL_CTX *mCtx;
-    SSL *mSSL;
-
-    // These are owned by the SSL object.
-    BIO *mBioR, *mBioW;
-
-    sockaddr_storage mRemoteAddr;
-
-    srtp_t mSRTPInbound, mSRTPOutbound;
-
-    static int OnVerifyPeerCertificate(int ok, X509_STORE_CTX *ctx);
-
-    void doTheThing(int res);
-    void queueOutputDataFromDTLS();
-    void tryConnecting();
-
-    void getKeyingMaterial();
-
-    static void CreateSRTPSession(
-            srtp_t *session,
-            const std::string &keyAndSalt,
-            srtp_ssrc_type_t direction);
-
-    bool useCertificate(std::shared_ptr<X509> certificate);
-    bool usePrivateKey(std::shared_ptr<EVP_PKEY> key);
-};
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/G711Packetizer.h b/host/frontend/gcastv2/webrtc/include/webrtc/G711Packetizer.h
deleted file mode 100644
index 82fcb4c..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/G711Packetizer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 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 "Packetizer.h"
-
-#include <https/RunLoop.h>
-
-#include <memory>
-
-#include <source/StreamingSource.h>
-
-struct G711Packetizer : public Packetizer {
-
-    using StreamingSource = android::StreamingSource;
-
-    enum class Mode {
-        ALAW,
-        ULAW
-    };
-    explicit G711Packetizer(
-            Mode mode,
-            std::shared_ptr<RunLoop> runLoop,
-            std::shared_ptr<StreamingSource> audioSource);
-
-    uint32_t rtpNow() const override;
-
-private:
-    using SBuffer = android::SBuffer;
-
-    Mode mMode;
-    std::shared_ptr<RunLoop> mRunLoop;
-
-    bool mFirstInTalkspurt;
-
-    void packetize(const std::shared_ptr<SBuffer> &accessUnit, int64_t timeUs);
-};
-
-
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/MyWebSocketHandler.h b/host/frontend/gcastv2/webrtc/include/webrtc/MyWebSocketHandler.h
deleted file mode 100644
index f22de55..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/MyWebSocketHandler.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 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 <webrtc/RTPSession.h>
-#include <webrtc/RTPSocketHandler.h>
-#include <webrtc/SDP.h>
-#include <webrtc/ServerState.h>
-
-#include <https/WebSocketHandler.h>
-#include <https/RunLoop.h>
-#include <source/KeyboardSink.h>
-#include <source/TouchSink.h>
-
-#include <memory>
-#include <optional>
-#include <sstream>
-#include <string>
-#include <vector>
-
-struct MyWebSocketHandler
-    : public WebSocketHandler,
-      public std::enable_shared_from_this<MyWebSocketHandler> {
-
-    explicit MyWebSocketHandler(
-            std::shared_ptr<RunLoop> runLoop,
-            std::shared_ptr<ServerState> serverState,
-            size_t handlerId);
-
-    ~MyWebSocketHandler() override;
-
-    int handleMessage(
-            uint8_t headerByte, const uint8_t *msg, size_t len) override;
-
-private:
-    enum OptionBits : uint32_t {
-        disableAudio                        = 1,
-        bundleTracks                        = 2,
-        enableData                          = 4,
-        useSingleCertificateForAllTracks    = 8,
-        useTCP                              = 16,
-    };
-
-    using TouchSink = android::TouchSink;
-    using KeyboardSink = android::KeyboardSink;
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    std::shared_ptr<ServerState> mServerState;
-    size_t mId;
-    uint32_t mOptions;
-
-    // Vector has the same ordering as the media entries in the SDP, i.e.
-    // vector index is "mlineIndex". (unless we are bundling, in which case
-    // there is only a single session).
-    std::vector<std::shared_ptr<RTPSession>> mSessions;
-
-    SDP mOfferedSDP;
-    std::vector<std::shared_ptr<RTPSocketHandler>> mRTPs;
-
-    std::shared_ptr<TouchSink> mTouchSink;
-    std::shared_ptr<KeyboardSink> mKeyboardSink;
-
-    std::pair<std::shared_ptr<X509>, std::shared_ptr<EVP_PKEY>>
-        mCertificateAndKey;
-
-    // Pass -1 for mlineIndex to access the "general" section.
-    std::optional<std::string> getSDPValue(
-            ssize_t mlineIndex,
-            std::string_view key,
-            bool fallthroughToGeneralSection) const;
-
-    std::string getRemotePassword(size_t mlineIndex) const;
-    std::string getRemoteUFrag(size_t mlineIndex) const;
-    std::string getRemoteFingerprint(size_t mlineIndex) const;
-
-    bool getCandidate(int32_t mid);
-
-    static std::pair<std::shared_ptr<X509>, std::shared_ptr<EVP_PKEY>>
-        CreateDTLSCertificateAndKey();
-
-    std::pair<std::string, std::string> createUniqueUFragAndPassword();
-
-    void parseOptions(const std::string &pathAndQuery);
-    size_t countTracks() const;
-
-    void prepareSessions();
-
-    void emitTrackIceOptionsAndFingerprint(
-            std::stringstream &ss, size_t mlineIndex) const;
-
-    // Returns -1 on error.
-    ssize_t mlineIndexForMid(int32_t mid) const;
-
-    static void CreateRandomIceCharSequence(char *dst, size_t size);
-};
-
-
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/OpusPacketizer.h b/host/frontend/gcastv2/webrtc/include/webrtc/OpusPacketizer.h
deleted file mode 100644
index 269cf42..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/OpusPacketizer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2019 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 "Packetizer.h"
-
-#include <https/RunLoop.h>
-
-#include <memory>
-
-#include <source/StreamingSource.h>
-
-struct OpusPacketizer : public Packetizer {
-
-    using StreamingSource = android::StreamingSource;
-
-    explicit OpusPacketizer(
-            std::shared_ptr<RunLoop> runLoop,
-            std::shared_ptr<StreamingSource> audioSource);
-
-    uint32_t rtpNow() const override;
-
-private:
-    using SBuffer = android::SBuffer;
-
-    std::shared_ptr<RunLoop> mRunLoop;
-
-    bool mFirstInTalkspurt;
-
-    void packetize(const std::shared_ptr<SBuffer> &accessUnit, int64_t timeUs);
-};
-
-
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/Packetizer.h b/host/frontend/gcastv2/webrtc/include/webrtc/Packetizer.h
deleted file mode 100644
index e584085..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/Packetizer.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 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 <stdint.h>
-
-#include <chrono>
-#include <memory>
-#include <vector>
-
-#include <https/RunLoop.h>
-#include <source/StreamingSource.h>
-
-struct RTPSender;
-
-struct Packetizer : public std::enable_shared_from_this<Packetizer> {
-
-  using StreamingSource = android::StreamingSource;
-
-  explicit Packetizer(std::shared_ptr<RunLoop> runLoop,
-                      std::shared_ptr<StreamingSource> source);
-  virtual ~Packetizer();
-
-  virtual void run();
-  virtual uint32_t rtpNow() const = 0;
-  int32_t requestIDRFrame();
-
-  virtual void queueRTPDatagram(std::vector<uint8_t> *packet);
-
-  virtual void addSender(std::shared_ptr<RTPSender> sender);
-
-  virtual void onFrame(const std::shared_ptr<android::SBuffer>& accessUnit);
-
- protected:
-  virtual void packetize(const std::shared_ptr<android::SBuffer>& accessUnit,
-                         int64_t timeUs) = 0;
-
-  uint32_t timeSinceStart() const;
-
-  int64_t mediaStartTime() const { return mStartTimeMedia; }
-
- private:
-  size_t mNumSamplesRead;
-  std::chrono::time_point<std::chrono::steady_clock> mStartTimeReal;
-  int64_t mStartTimeMedia;
-
-  std::shared_ptr<RunLoop> mRunLoop;
-
-  std::shared_ptr<StreamingSource> mStreamingSource;
-
-  std::vector<std::weak_ptr<RTPSender>> mSenders;
-};
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/RTPSender.h b/host/frontend/gcastv2/webrtc/include/webrtc/RTPSender.h
deleted file mode 100644
index 3473fe4..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/RTPSender.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2019 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 "Packetizer.h"
-
-#include <https/RunLoop.h>
-
-#include <memory>
-#include <optional>
-#include <unordered_map>
-#include <vector>
-
-struct RTPSocketHandler;
-
-struct RTPSender : public std::enable_shared_from_this<RTPSender> {
-
-    explicit RTPSender(
-            std::shared_ptr<RunLoop> runLoop,
-            RTPSocketHandler *parent,
-            std::shared_ptr<Packetizer> videoPacketizer,
-            std::shared_ptr<Packetizer> audioPacketizer);
-
-    void addSource(uint32_t ssrc);
-
-    void addRetransInfo(
-            uint32_t ssrc, uint8_t PT, uint32_t retransSSRC, uint8_t retransPT);
-
-    int injectRTCP(uint8_t *data, size_t size);
-    void queueRTPDatagram(std::vector<uint8_t> *packet);
-
-    void run();
-
-    void requestIDRFrame();
-
-private:
-    struct SourceInfo {
-        explicit SourceInfo()
-            : mNumPacketsSent(0),
-              mNumBytesSent(0) {
-        }
-
-        size_t mNumPacketsSent;
-        size_t mNumBytesSent;
-
-        // (ssrc, PT) by PT.
-        std::unordered_map<uint8_t, std::pair<uint32_t, uint8_t>> mRetrans;
-
-        std::deque<std::vector<uint8_t>> mRecentPackets;
-    };
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    RTPSocketHandler *mParent;
-
-    // Sources by ssrc.
-    std::unordered_map<uint32_t, SourceInfo> mSources;
-
-    std::shared_ptr<Packetizer> mVideoPacketizer;
-    std::shared_ptr<Packetizer> mAudioPacketizer;
-
-    void appendSR(std::vector<uint8_t> *buffer, uint32_t localSSRC);
-    void appendSDES(std::vector<uint8_t> *buffer, uint32_t localSSRC);
-
-    void queueSR(uint32_t localSSRC);
-    void sendSR(uint32_t localSSRC);
-
-    void queueDLRR(
-            uint32_t localSSRC,
-            uint32_t remoteSSRC,
-            uint32_t ntpHi,
-            uint32_t ntpLo);
-
-    void appendDLRR(
-            std::vector<uint8_t> *buffer,
-            uint32_t localSSRC,
-            uint32_t remoteSSRC,
-            uint32_t ntpHi,
-            uint32_t ntpLo);
-
-    int processRTCP(const uint8_t *data, size_t size);
-
-    void retransmitPackets(uint32_t localSSRC, uint16_t PID, uint16_t BLP);
-};
-
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/RTPSession.h b/host/frontend/gcastv2/webrtc/include/webrtc/RTPSession.h
deleted file mode 100644
index 4faeb42..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/RTPSession.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/RunLoop.h>
-
-#include <memory>
-#include <optional>
-#include <string_view>
-
-#include <netinet/in.h>
-#include <openssl/ssl.h>
-
-struct RTPSession : std::enable_shared_from_this<RTPSession> {
-    explicit RTPSession(
-            std::string_view localUFrag,
-            std::string_view localPassword,
-            std::shared_ptr<X509> localCertificate,
-            std::shared_ptr<EVP_PKEY> localKey);
-
-    bool isActive() const;
-    void setIsActive();
-
-    void setRemoteParams(
-            std::string_view remoteUFrag,
-            std::string_view remotePassword,
-            std::string_view remoteFingerprint);
-
-    std::string localUFrag() const;
-    std::string localPassword() const;
-    std::shared_ptr<X509> localCertificate() const;
-    std::shared_ptr<EVP_PKEY> localKey() const;
-    std::string localFingerprint() const;
-
-    std::string remoteUFrag() const;
-    std::string remotePassword() const;
-    std::string remoteFingerprint() const;
-
-    bool hasRemoteAddress() const;
-    sockaddr_storage remoteAddress() const;
-    void setRemoteAddress(const sockaddr_storage &remoteAddr);
-
-    void schedulePing(
-            std::shared_ptr<RunLoop> runLoop,
-            RunLoop::AsyncFunction cb,
-            std::chrono::steady_clock::duration delay);
-
-private:
-    std::string mLocalUFrag;
-    std::string mLocalPassword;
-    std::shared_ptr<X509> mLocalCertificate;
-    std::shared_ptr<EVP_PKEY> mLocalKey;
-
-    std::optional<std::string> mRemoteUFrag;
-    std::optional<std::string> mRemotePassword;
-    std::optional<std::string> mRemoteFingerprint;
-    std::optional<sockaddr_storage> mRemoteAddr;
-
-    RunLoop::Token mPingToken;
-
-    bool mIsActive;
-};
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/RTPSocketHandler.h b/host/frontend/gcastv2/webrtc/include/webrtc/RTPSocketHandler.h
deleted file mode 100644
index f1dc4a2..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/RTPSocketHandler.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/PlainSocket.h>
-#include <https/RunLoop.h>
-#include <webrtc/DTLS.h>
-#include <webrtc/RTPSender.h>
-#include <webrtc/RTPSession.h>
-#include <webrtc/SCTPHandler.h>
-#include <webrtc/ServerState.h>
-#include <webrtc/STUNMessage.h>
-
-#include <memory>
-#include <string_view>
-#include <vector>
-
-struct MyWebSocketHandler;
-
-struct RTPSocketHandler
-    : public std::enable_shared_from_this<RTPSocketHandler> {
-
-    static constexpr size_t kMaxUDPPayloadSize = 1536;
-
-    static constexpr uint32_t TRACK_VIDEO = 1;
-    static constexpr uint32_t TRACK_AUDIO = 2;
-    static constexpr uint32_t TRACK_DATA  = 4;
-
-    enum class TransportType {
-        UDP,
-        TCP,
-    };
-
-    explicit RTPSocketHandler(
-            std::shared_ptr<RunLoop> runLoop,
-            std::shared_ptr<ServerState> serverState,
-            TransportType type,
-            int domain,
-            uint32_t trackMask,
-            std::shared_ptr<RTPSession> session);
-
-    uint16_t getLocalPort() const;
-    std::string getLocalUFrag() const;
-    std::string getLocalIPString() const;
-
-    void run();
-
-    void queueDatagram(
-            const sockaddr_storage &addr, const void *data, size_t size);
-
-    void queueRTCPDatagram(const void *data, size_t size);
-    void queueRTPDatagram(const void *data, size_t size);
-
-    void notifyDTLSConnected();
-
-private:
-    struct Datagram {
-        explicit Datagram(
-                const sockaddr_storage &addr, const void *data, size_t size);
-
-        const void *data() const;
-        size_t size() const;
-
-        const sockaddr_storage &remoteAddress() const;
-
-    private:
-        std::vector<uint8_t> mData;
-        sockaddr_storage mAddr;
-    };
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    std::shared_ptr<ServerState> mServerState;
-    TransportType mTransportType;
-    uint16_t mLocalPort;
-    uint32_t mTrackMask;
-    std::shared_ptr<RTPSession> mSession;
-
-    std::shared_ptr<BufferedSocket> mSocket;
-    std::shared_ptr<DTLS> mDTLS;
-    std::shared_ptr<SCTPHandler> mSCTPHandler;
-
-    std::deque<std::shared_ptr<Datagram>> mOutQueue;
-    bool mSendPending;
-    bool mDTLSConnected;
-
-    std::shared_ptr<RTPSender> mRTPSender;
-
-    // for TransportType TCP:
-    std::shared_ptr<PlainSocket> mServerSocket;
-    sockaddr_storage mClientAddr;
-    socklen_t mClientAddrLen;
-
-    std::vector<uint8_t> mInBuffer;
-    size_t mInBufferLength;
-
-    std::vector<uint8_t> mOutBuffer;
-
-    void onReceive();
-    void onDTLSReceive(const uint8_t *data, size_t size);
-
-    void pingRemote(std::shared_ptr<RTPSession> session);
-
-    bool matchesSession(const STUNMessage &msg) const;
-
-    void scheduleDrainOutQueue();
-    void drainOutQueue();
-
-    int onSRTPReceive(uint8_t *data, size_t size);
-
-    void onTCPConnect();
-    void onTCPReceive();
-
-    void onPacketReceived(
-            const sockaddr_storage &addr,
-            socklen_t addrLen,
-            uint8_t *data,
-            size_t size);
-
-    void queueTCPOutputPacket(const uint8_t *data, size_t size);
-    void sendTCPOutputData();
-};
-
-
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/SCTPHandler.h b/host/frontend/gcastv2/webrtc/include/webrtc/SCTPHandler.h
deleted file mode 100644
index af1b11c..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/SCTPHandler.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 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 <webrtc/DTLS.h>
-
-#include <https/RunLoop.h>
-
-#include <memory>
-
-struct SCTPHandler : public std::enable_shared_from_this<SCTPHandler> {
-    explicit SCTPHandler(
-            std::shared_ptr<RunLoop> runLoop,
-            std::shared_ptr<DTLS> dtls);
-
-    void run();
-
-    int inject(uint8_t *data, size_t size);
-
-private:
-    std::shared_ptr<RunLoop> mRunLoop;
-    std::shared_ptr<DTLS> mDTLS;
-
-    uint32_t mInitiateTag;
-    uint32_t mSendingTSN;
-    bool mSentGreeting;
-
-    int processChunk(
-            uint16_t srcPort,
-            const uint8_t *data,
-            size_t size,
-            bool firstChunk,
-            bool lastChunk);
-
-    static uint32_t crc32c(const uint8_t *data, size_t size);
-
-    void onSendGreeting(uint16_t srcPort, size_t index);
-};
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/SDP.h b/host/frontend/gcastv2/webrtc/include/webrtc/SDP.h
deleted file mode 100644
index b531d6d..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/SDP.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2019 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>
-#include <vector>
-
-struct SDP {
-    explicit SDP();
-
-    int initCheck() const;
-
-    void clear();
-    int setTo(const std::string &data);
-
-    // Section 0 is reserved for top-level attributes, section indices >= 1
-    // correspond to each media section starting with an "m=" line.
-    size_t countSections() const;
-
-    std::vector<std::string>::const_iterator section_begin(
-            size_t section) const;
-
-    std::vector<std::string>::const_iterator section_end(
-            size_t section) const;
-
-    struct SectionEditor {
-        ~SectionEditor();
-
-        SectionEditor &operator<<(std::string_view s);
-
-        void commit();
-
-    private:
-        friend struct SDP;
-
-        explicit SectionEditor(SDP *sdp, size_t section);
-
-        SDP *mSDP;
-        size_t mSection;
-
-        std::string mBuffer;
-    };
-
-    SectionEditor createSection();
-    SectionEditor appendToSection(size_t section);
-
-    static void Test();
-
-private:
-    int mInitCheck;
-    std::vector<std::string> mLines;
-
-    std::vector<size_t> mLineIndexBySection;
-
-    bool mNewSectionEditorActive;
-
-    void getSectionRange(
-            size_t section,
-            size_t *lineStartIndex,
-            size_t *lineStopIndex) const;
-
-    void commitSectionEdit(
-            size_t section, const std::vector<std::string> &lines);
-};
-
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/STUNClient.h b/host/frontend/gcastv2/webrtc/include/webrtc/STUNClient.h
deleted file mode 100644
index 87bce72..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/STUNClient.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 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 <https/PlainSocket.h>
-#include <https/RunLoop.h>
-#include <memory>
-
-#include <arpa/inet.h>
-
-struct STUNClient : public std::enable_shared_from_this<STUNClient> {
-    using Callback = std::function<void(int, const std::string &)>;
-
-    explicit STUNClient(
-            std::shared_ptr<RunLoop> runLoop,
-            const sockaddr_in &addr,
-            Callback cb);
-
-    void run();
-
-private:
-    static constexpr size_t kMaxUDPPayloadSize = 1536;
-    static constexpr size_t kMaxNumRetries = 5;
-
-    static constexpr std::chrono::duration kTimeoutDelay =
-        std::chrono::seconds(1);
-
-    std::shared_ptr<RunLoop> mRunLoop;
-    sockaddr_in mRemoteAddr;
-    Callback mCallback;
-
-    std::shared_ptr<PlainSocket> mSocket;
-
-    RunLoop::Token mTimeoutToken;
-    size_t mNumRetriesLeft;
-
-    void onSendRequest();
-    void onReceiveResponse();
-
-    void scheduleRequest();
-    void onTimeout();
-};
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/STUNMessage.h b/host/frontend/gcastv2/webrtc/include/webrtc/STUNMessage.h
deleted file mode 100644
index 1498f59..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/STUNMessage.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 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 <cstdint>
-#include <optional>
-#include <string_view>
-#include <vector>
-
-struct STUNMessage {
-    explicit STUNMessage(uint16_t type, const uint8_t transactionID[12]);
-    explicit STUNMessage(const void *data, size_t size);
-
-    bool isValid() const;
-
-    uint16_t type() const;
-
-    void addAttribute(uint16_t type) {
-        addAttribute(type, nullptr, 0);
-    }
-
-    void addAttribute(uint16_t type, const void *data, size_t size);
-    void addMessageIntegrityAttribute(std::string_view password);
-    void addFingerprint();
-
-    bool findAttribute(uint16_t type, const void **data, size_t *size) const;
-
-    const uint8_t *data();
-    size_t size() const;
-
-    void dump(std::optional<std::string_view> password = std::nullopt) const;
-
-private:
-    bool mIsValid;
-    std::vector<uint8_t> mData;
-    bool mAddedMessageIntegrity;
-
-    void validate();
-
-    bool verifyMessageIntegrity(size_t offset, std::string_view password) const;
-    bool verifyFingerprint(size_t offset) const;
-};
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/ServerState.h b/host/frontend/gcastv2/webrtc/include/webrtc/ServerState.h
deleted file mode 100644
index b98a3f4..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/ServerState.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2019 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 "Packetizer.h"
-
-#include <https/RunLoop.h>
-
-#include <source/HostToGuestComms.h>
-
-#include <source/KeyboardSink.h>
-#include <source/TouchSink.h>
-#include <source/StreamingSource.h>
-
-#include <memory>
-#include <mutex>
-#include <set>
-
-#include <host/libs/screen_connector/screen_connector.h>
-
-struct ServerState {
-    using TouchSink = android::TouchSink;
-    using KeyboardSink = android::KeyboardSink;
-
-    enum class VideoFormat {
-        VP8,
-    };
-    explicit ServerState(
-            std::shared_ptr<RunLoop> runLoop,
-            VideoFormat videoFormat);
-
-    std::shared_ptr<Packetizer> getVideoPacketizer();
-    std::shared_ptr<Packetizer> getAudioPacketizer();
-    std::shared_ptr<TouchSink> getTouchSink();
-    std::shared_ptr<KeyboardSink> getKeyboardSink();
-
-    VideoFormat videoFormat() const { return mVideoFormat; }
-
-    size_t acquireHandlerId();
-    void releaseHandlerId(size_t id);
-
-private:
-    using StreamingSource = android::StreamingSource;
-
-    std::shared_ptr<RunLoop> mRunLoop;
-
-    VideoFormat mVideoFormat;
-
-    std::weak_ptr<Packetizer> mVideoPacketizer;
-    std::weak_ptr<Packetizer> mAudioPacketizer;
-
-    std::shared_ptr<StreamingSource> mFrameBufferSource;
-
-    std::shared_ptr<StreamingSource> mAudioSource;
-
-    std::shared_ptr<cvd::ScreenConnector> mScreenConnector;
-    std::shared_ptr<std::thread> mScreenConnectorMonitor;
-
-    std::shared_ptr<TouchSink> mTouchSink;
-    std::shared_ptr<KeyboardSink> mKeyboardSink;
-
-    std::set<size_t> mAllocatedHandlerIds;
-
-    void MonitorScreenConnector();
-};
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/VP8Packetizer.h b/host/frontend/gcastv2/webrtc/include/webrtc/VP8Packetizer.h
deleted file mode 100644
index fa0a9b9..0000000
--- a/host/frontend/gcastv2/webrtc/include/webrtc/VP8Packetizer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 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 "Packetizer.h"
-
-#include <https/RunLoop.h>
-#include <source/StreamingSource.h>
-
-#include <memory>
-
-struct VP8Packetizer : public Packetizer {
-
-    using StreamingSource = android::StreamingSource;
-
-    explicit VP8Packetizer(
-            std::shared_ptr<RunLoop> runLoop,
-            std::shared_ptr<StreamingSource> frameBufferSource);
-
-    uint32_t rtpNow() const override;
-
-private:
-    using SBuffer = android::SBuffer;
-
-    void packetize(const std::shared_ptr<SBuffer> &accessUnit, int64_t timeUs);
-};
diff --git a/host/frontend/gcastv2/webrtc/makefile b/host/frontend/gcastv2/webrtc/makefile
deleted file mode 100644
index e2c5b7d..0000000
--- a/host/frontend/gcastv2/webrtc/makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-LOCAL_PATH := $(PWD)
-
-all: out/webRTC
-
-include ../build/defaults
-
-TARGET := webRTC
-
-C++FLAGS := \
-    -I../https/include                  \
-
-C++FLAGS += -O0 -g -Wall -Wextra -DTARGET_MAC=1
-
-C++FLAGS += -Wno-gnu-anonymous-struct -Wno-nested-anon-types
-C++FLAGS += -fno-rtti
-
-LDFLAGS += \
-    -framework CoreFoundation   \
-    -framework Security         \
-
-C++FLAGS += -I/usr/local/opt/openssl/include
-LDFLAGS += -L/usr/local/opt/openssl/lib -lssl -lcrypto
-
-C++FLAGS += -I/usr/local/opt/srtp/include
-LDFLAGS += -L/usr/local/opt/srtp/lib -lsrtp2
-
-STATIC_LIBS := libhttps.a
-
-SRCS := \
-    DTLS.cpp                            \
-    MyWebSocketHandler.cpp              \
-    RTPReceiver.cpp                     \
-    RTPSender.cpp                       \
-    RTPSession.cpp                      \
-    RTPSocketHandler.cpp                \
-    STUNMessage.cpp                     \
-    webRTC.cpp                          \
-
-include ../build/build_executable
-include ../build/clear
-
-include ../https/local.mak
diff --git a/host/frontend/gcastv2/webrtc/webRTC.cpp b/host/frontend/gcastv2/webrtc/webRTC.cpp
deleted file mode 100644
index c8afbee..0000000
--- a/host/frontend/gcastv2/webrtc/webRTC.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include "Utils.h"
-
-#include <webrtc/AdbWebSocketHandler.h>
-#include <webrtc/DTLS.h>
-#include <webrtc/MyWebSocketHandler.h>
-#include <webrtc/RTPSocketHandler.h>
-#include <webrtc/ServerState.h>
-#include <webrtc/STUNClient.h>
-#include <webrtc/STUNMessage.h>
-
-#include <https/HTTPServer.h>
-#include <https/PlainSocket.h>
-#include <https/RunLoop.h>
-#include <https/SafeCallbackable.h>
-#include <https/SSLSocket.h>
-#include <https/Support.h>
-
-#include <iostream>
-#include <unordered_map>
-
-#include <netdb.h>
-
-#include <gflags/gflags.h>
-
-DEFINE_int32(http_server_port, 8443, "The port for the http server.");
-DEFINE_bool(use_secure_http, true, "Whether to use HTTPS or HTTP.");
-DEFINE_string(
-        public_ip,
-        "0.0.0.0",
-        "Public IPv4 address of your server, a.b.c.d format");
-DEFINE_string(
-        assets_dir,
-        "webrtc",
-        "Directory with location of webpage assets.");
-DEFINE_string(
-        certs_dir,
-        "webrtc/certs",
-        "Directory to certificates.");
-
-DEFINE_int32(touch_fd, -1, "An fd to listen on for touch connections.");
-DEFINE_int32(keyboard_fd, -1, "An fd to listen on for keyboard connections.");
-DEFINE_int32(frame_server_fd, -1, "An fd to listen on for frame updates");
-DEFINE_bool(write_virtio_input, false, "Whether to send input events in virtio format.");
-
-DEFINE_string(adb, "", "Interface:port of local adb service.");
-
-DEFINE_string(
-        stun_server,
-        "stun.l.google.com:19302",
-        "host:port of STUN server to use for public address resolution");
-
-int main(int argc, char **argv) {
-    ::gflags::ParseCommandLineFlags(&argc, &argv, true);
-
-    SSLSocket::Init();
-    DTLS::Init();
-
-    if (FLAGS_public_ip.empty() || FLAGS_public_ip == "0.0.0.0") {
-        // NOTE: We only contact the external STUN server once upon startup
-        // to determine our own public IP.
-        // This only works if NAT does not remap ports, i.e. a local port 15550
-        // is visible to the outside world on port 15550 as well.
-        // If this condition is not met, this code will have to be modified
-        // and a STUN request made for each locally bound socket before
-        // fulfilling a "MyWebSocketHandler::getCandidate" ICE request.
-
-        const addrinfo kHints = {
-            AI_ADDRCONFIG,
-            PF_INET,
-            SOCK_DGRAM,
-            IPPROTO_UDP,
-            0,  // ai_addrlen
-            nullptr,  // ai_addr
-            nullptr,  // ai_canonname
-            nullptr  // ai_next
-        };
-
-        auto pieces = SplitString(FLAGS_stun_server, ':');
-        CHECK_EQ(pieces.size(), 2u);
-
-        addrinfo *infos;
-        CHECK(!getaddrinfo(pieces[0].c_str(), pieces[1].c_str(), &kHints, &infos));
-
-        sockaddr_storage stunAddr;
-        memcpy(&stunAddr, infos->ai_addr, infos->ai_addrlen);
-
-        freeaddrinfo(infos);
-        infos = nullptr;
-
-        CHECK_EQ(stunAddr.ss_family, AF_INET);
-
-        std::mutex lock;
-        std::condition_variable cond;
-        bool done = false;
-
-        auto runLoop = std::make_shared<RunLoop>("STUN");
-
-        auto stunClient = std::make_shared<STUNClient>(
-                runLoop,
-                reinterpret_cast<const sockaddr_in &>(stunAddr),
-                [&lock, &cond, &done](int result, const std::string &myPublicIp) {
-                    CHECK(!result);
-                    LOG(INFO)
-                        << "STUN-discovered public IP: " << myPublicIp;
-
-                    FLAGS_public_ip = myPublicIp;
-
-                    std::lock_guard autoLock(lock);
-                    done = true;
-                    cond.notify_all();
-                });
-
-        stunClient->run();
-
-        std::unique_lock autoLock(lock);
-        while (!done) {
-            cond.wait(autoLock);
-        }
-    }
-
-    auto runLoop = RunLoop::main();
-
-    auto state = std::make_shared<ServerState>(
-            runLoop, ServerState::VideoFormat::VP8);
-
-    auto port = FLAGS_http_server_port;
-
-    auto httpd = std::make_shared<HTTPServer>(
-            runLoop,
-            "0.0.0.0",
-            port,
-            FLAGS_use_secure_http
-                ? ServerSocket::TransportType::TLS
-                : ServerSocket::TransportType::TCP,
-            FLAGS_certs_dir + "/server.crt",
-            FLAGS_certs_dir + "/server.key");
-
-    const std::string index_html = FLAGS_assets_dir + "/index.html";
-    const std::string logcat_js = FLAGS_assets_dir + "/js/logcat.js";
-    const std::string receive_js = FLAGS_assets_dir + "/js/receive.js";
-    const std::string viewpane_js = FLAGS_assets_dir + "/js/viewpane.js";
-    const std::string style_css = FLAGS_assets_dir + "/style.css";
-
-    httpd->addStaticFile("/index.html", index_html.c_str());
-    httpd->addStaticFile("/js/logcat.js", logcat_js.c_str());
-    httpd->addStaticFile("/js/receive.js", receive_js.c_str());
-    httpd->addStaticFile("/js/viewpane.js", viewpane_js.c_str());
-    httpd->addStaticFile("/style.css", style_css.c_str());
-
-    httpd->addWebSocketHandlerFactory(
-            "/control",
-            [runLoop, state]{
-                auto id = state->acquireHandlerId();
-
-                auto handler =
-                    std::make_shared<MyWebSocketHandler>(runLoop, state, id);
-
-                return std::make_pair(0 /* OK */, handler);
-            });
-
-    if (!FLAGS_adb.empty()) {
-        httpd->addWebSocketHandlerFactory(
-                "/control_adb",
-                [runLoop]{
-                    auto handler = std::make_shared<AdbWebSocketHandler>(
-                            runLoop, FLAGS_adb);
-
-                    handler->run();
-
-                    return std::make_pair(0 /* OK */, handler);
-                });
-    }
-
-    httpd->run();
-    runLoop->run();
-
-    return 0;
-}
diff --git a/host/frontend/vnc_server/Android.bp b/host/frontend/vnc_server/Android.bp
index 3df8d5f..bfb5561 100644
--- a/host/frontend/vnc_server/Android.bp
+++ b/host/frontend/vnc_server/Android.bp
@@ -13,7 +13,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary_host {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
     name: "vnc_server",
     srcs: [
         "blackboard.cpp",
@@ -25,26 +29,30 @@
         "vnc_client_connection.cpp",
         "vnc_server.cpp",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libcuttlefish_fs",
         "libcuttlefish_utils",
-        "cuttlefish_tcp_socket",
         "libbase",
+        "libjsoncpp",
         "liblog",
     ],
+    header_libs: [
+        "libcuttlefish_confui_host_headers",
+    ],
     static_libs: [
         "libcuttlefish_host_config",
         "libcuttlefish_screen_connector",
         "libcuttlefish_wayland_server",
+        "libcuttlefish_confui",
+        "libcuttlefish_confui_host",
+        "libft2.nodep",
+        "libteeui",
+        "libteeui_localization",
         "libffi",
-        "libjsoncpp",
         "libjpeg",
         "libgflags",
         "libwayland_server",
         "libwayland_extension_server_protocols",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/frontend/vnc_server/blackboard.cpp b/host/frontend/vnc_server/blackboard.cpp
index b842648..91a8d1e 100644
--- a/host/frontend/vnc_server/blackboard.cpp
+++ b/host/frontend/vnc_server/blackboard.cpp
@@ -20,7 +20,7 @@
 #include <utility>
 
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include "host/frontend/vnc_server/frame_buffer_watcher.h"
 
 DEFINE_bool(debug_blackboard, false,
@@ -29,10 +29,10 @@
 #define DLOG(LEVEL)                                 \
   if (FLAGS_debug_blackboard) LOG(LEVEL)
 
-using cvd::vnc::BlackBoard;
-using cvd::vnc::Stripe;
+using cuttlefish::vnc::BlackBoard;
+using cuttlefish::vnc::Stripe;
 
-cvd::vnc::SeqNumberVec cvd::vnc::MakeSeqNumberVec() {
+cuttlefish::vnc::SeqNumberVec cuttlefish::vnc::MakeSeqNumberVec() {
   return SeqNumberVec(FrameBufferWatcher::StripesPerFrame());
 }
 
@@ -75,7 +75,7 @@
   return true;
 }
 
-cvd::vnc::StripePtrVec BlackBoard::WaitForSenderWork(
+cuttlefish::vnc::StripePtrVec BlackBoard::WaitForSenderWork(
     const VncClientConnection* conn) {
   std::unique_lock<std::mutex> guard(m_);
   auto& state = GetStateForClient(conn);
@@ -139,7 +139,7 @@
 }
 
 void BlackBoard::set_frame_buffer_watcher(
-    cvd::vnc::FrameBufferWatcher* frame_buffer_watcher) {
+    cuttlefish::vnc::FrameBufferWatcher* frame_buffer_watcher) {
   std::lock_guard<std::mutex> guard(m_);
   frame_buffer_watcher_ = frame_buffer_watcher;
 }
diff --git a/host/frontend/vnc_server/blackboard.h b/host/frontend/vnc_server/blackboard.h
index 1119dd3..af4baea 100644
--- a/host/frontend/vnc_server/blackboard.h
+++ b/host/frontend/vnc_server/blackboard.h
@@ -22,10 +22,10 @@
 #include <mutex>
 #include <unordered_map>
 
-#include "common/libs/threads/thread_annotations.h"
+#include "common/libs/concurrency/thread_annotations.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 
 class VncClientConnection;
@@ -110,4 +110,4 @@
 };
 
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/frame_buffer_watcher.cpp b/host/frontend/vnc_server/frame_buffer_watcher.cpp
index 126fb6b..3cc39c0 100644
--- a/host/frontend/vnc_server/frame_buffer_watcher.cpp
+++ b/host/frontend/vnc_server/frame_buffer_watcher.cpp
@@ -25,14 +25,14 @@
 #include <thread>
 #include <utility>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include "host/frontend/vnc_server/vnc_utils.h"
-#include "host/libs/screen_connector/screen_connector.h"
 
-using cvd::vnc::FrameBufferWatcher;
+using cuttlefish::vnc::FrameBufferWatcher;
 
-FrameBufferWatcher::FrameBufferWatcher(BlackBoard* bb)
-    : bb_{bb}, hwcomposer{bb_} {
+FrameBufferWatcher::FrameBufferWatcher(BlackBoard* bb,
+                                       ScreenConnector& screen_connector)
+    : bb_{bb}, hwcomposer{bb_, screen_connector} {
   for (auto& stripes_vec : stripes_) {
     std::generate_n(std::back_inserter(stripes_vec),
                     SimulatedHWComposer::NumberOfStripes(),
@@ -60,7 +60,7 @@
   return closed_;
 }
 
-cvd::vnc::Stripe FrameBufferWatcher::Rotated(Stripe stripe) {
+cuttlefish::vnc::Stripe FrameBufferWatcher::Rotated(Stripe stripe) {
   if (stripe.orientation == ScreenOrientation::Landscape) {
     LOG(FATAL) << "Rotating a landscape stripe, this is a mistake";
   }
@@ -71,17 +71,17 @@
   Message rotated(raw.size(), 0xAA);
   for (std::uint16_t i = 0; i < w; ++i) {
     for (std::uint16_t j = 0; j < h; ++j) {
-      size_t to = (i * h + j) * ScreenConnector::BytesPerPixel();
-      size_t from = (w - (i + 1)) * ScreenConnector::BytesPerPixel() + s * j;
+      size_t to = (i * h + j) * ScreenConnectorInfo::BytesPerPixel();
+      size_t from = (w - (i + 1)) * ScreenConnectorInfo::BytesPerPixel() + s * j;
       CHECK(from < raw.size());
       CHECK(to < rotated.size());
-      std::memcpy(&rotated[to], &raw[from], ScreenConnector::BytesPerPixel());
+      std::memcpy(&rotated[to], &raw[from], ScreenConnectorInfo::BytesPerPixel());
     }
   }
   std::swap(stripe.x, stripe.y);
   std::swap(stripe.width, stripe.height);
   // The new stride after rotating is the height, as it is not aligned again.
-  stripe.stride = stripe.width * ScreenConnector::BytesPerPixel();
+  stripe.stride = stripe.width * ScreenConnectorInfo::BytesPerPixel();
   stripe.raw_data = std::move(rotated);
   stripe.orientation = ScreenOrientation::Landscape;
   return stripe;
@@ -92,7 +92,7 @@
   return Stripes(stripe.orientation)[stripe.index]->raw_data != stripe.raw_data;
 }
 
-cvd::vnc::StripePtrVec FrameBufferWatcher::StripesNewerThan(
+cuttlefish::vnc::StripePtrVec FrameBufferWatcher::StripesNewerThan(
     ScreenOrientation orientation, const SeqNumberVec& seq_numbers) const {
   std::lock_guard<std::mutex> guard(stripes_lock_);
   const auto& stripes = Stripes(orientation);
@@ -106,12 +106,12 @@
   return new_stripes;
 }
 
-cvd::vnc::StripePtrVec& FrameBufferWatcher::Stripes(
+cuttlefish::vnc::StripePtrVec& FrameBufferWatcher::Stripes(
     ScreenOrientation orientation) {
   return stripes_[static_cast<int>(orientation)];
 }
 
-const cvd::vnc::StripePtrVec& FrameBufferWatcher::Stripes(
+const cuttlefish::vnc::StripePtrVec& FrameBufferWatcher::Stripes(
     ScreenOrientation orientation) const {
   return stripes_[static_cast<int>(orientation)];
 }
@@ -190,3 +190,11 @@
 int FrameBufferWatcher::StripesPerFrame() {
   return SimulatedHWComposer::NumberOfStripes();
 }
+
+void FrameBufferWatcher::IncClientCount() {
+  hwcomposer.ReportClientsConnected();
+}
+
+void FrameBufferWatcher::DecClientCount() {
+  // Do nothing
+}
diff --git a/host/frontend/vnc_server/frame_buffer_watcher.h b/host/frontend/vnc_server/frame_buffer_watcher.h
index 40ab270..9b559b6 100644
--- a/host/frontend/vnc_server/frame_buffer_watcher.h
+++ b/host/frontend/vnc_server/frame_buffer_watcher.h
@@ -22,22 +22,27 @@
 #include <utility>
 #include <vector>
 
-#include "common/libs/threads/thread_annotations.h"
+#include "common/libs/concurrency/thread_annotations.h"
 #include "host/frontend/vnc_server/blackboard.h"
 #include "host/frontend/vnc_server/jpeg_compressor.h"
 #include "host/frontend/vnc_server/simulated_hw_composer.h"
+#include "host/libs/screen_connector/screen_connector.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 class FrameBufferWatcher {
  public:
-  explicit FrameBufferWatcher(BlackBoard* bb);
+  explicit FrameBufferWatcher(BlackBoard* bb,
+                              ScreenConnector& screen_connector);
   FrameBufferWatcher(const FrameBufferWatcher&) = delete;
   FrameBufferWatcher& operator=(const FrameBufferWatcher&) = delete;
   ~FrameBufferWatcher();
 
   StripePtrVec StripesNewerThan(ScreenOrientation orientation,
                                 const SeqNumberVec& seq_num) const;
+  void IncClientCount();
+  void DecClientCount();
+
   static int StripesPerFrame();
 
  private:
@@ -69,8 +74,8 @@
   mutable std::mutex m_;
   bool closed_ GUARDED_BY(m_){};
   BlackBoard* bb_{};
-  SimulatedHWComposer hwcomposer{bb_};
+  SimulatedHWComposer hwcomposer;
 };
 
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/jpeg_compressor.cpp b/host/frontend/vnc_server/jpeg_compressor.cpp
index 3bd3753..05013eb 100644
--- a/host/frontend/vnc_server/jpeg_compressor.cpp
+++ b/host/frontend/vnc_server/jpeg_compressor.cpp
@@ -17,12 +17,12 @@
 #include <stdio.h>  // stdio.h must appear before jpeglib.h
 #include <jpeglib.h>
 
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include "host/frontend/vnc_server/jpeg_compressor.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
 #include "host/libs/screen_connector/screen_connector.h"
 
-using cvd::vnc::JpegCompressor;
+using cuttlefish::vnc::JpegCompressor;
 
 namespace {
 void InitCinfo(jpeg_compress_struct* cinfo, jpeg_error_mgr* err,
@@ -32,7 +32,7 @@
 
   cinfo->image_width = width;
   cinfo->image_height = height;
-  cinfo->input_components = cvd::ScreenConnector::BytesPerPixel();
+  cinfo->input_components = cuttlefish::ScreenConnectorInfo::BytesPerPixel();
   cinfo->in_color_space = JCS_EXT_RGBX;
 
   jpeg_set_defaults(cinfo);
@@ -40,7 +40,7 @@
 }
 }  // namespace
 
-cvd::Message JpegCompressor::Compress(const Message& frame,
+cuttlefish::Message JpegCompressor::Compress(const Message& frame,
                                       int jpeg_quality, std::uint16_t x,
                                       std::uint16_t y, std::uint16_t width,
                                       std::uint16_t height,
@@ -58,7 +58,7 @@
     auto row = static_cast<JSAMPROW>(const_cast<std::uint8_t*>(
         &frame[(y * stride) +
                (cinfo.next_scanline * stride) +
-               (x * cvd::ScreenConnector::BytesPerPixel())]));
+               (x * cuttlefish::ScreenConnectorInfo::BytesPerPixel())]));
     jpeg_write_scanlines(&cinfo, &row, 1);
   }
   jpeg_finish_compress(&cinfo);
diff --git a/host/frontend/vnc_server/jpeg_compressor.h b/host/frontend/vnc_server/jpeg_compressor.h
index ae3af18..b6ef487 100644
--- a/host/frontend/vnc_server/jpeg_compressor.h
+++ b/host/frontend/vnc_server/jpeg_compressor.h
@@ -22,7 +22,7 @@
 
 #include "host/frontend/vnc_server/vnc_utils.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 
 // libjpeg-turbo with jpeg_mem_dest (using memory as a destination) is funky.
@@ -49,4 +49,4 @@
 };
 
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/keysyms.h b/host/frontend/vnc_server/keysyms.h
index 41ff7c7..ddcc0e4 100644
--- a/host/frontend/vnc_server/keysyms.h
+++ b/host/frontend/vnc_server/keysyms.h
@@ -18,7 +18,7 @@
 
 #include <cstdint>
 
-namespace cvd {
+namespace cuttlefish {
 namespace xk {
 
 constexpr uint32_t BackSpace = 0xff08, Tab = 0xff09, Return = 0xff0d,
@@ -51,4 +51,4 @@
                    VNCMenu = 0xffed;  // VNC seems to translate MENU to this
 
 }  // namespace xk
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/main.cpp b/host/frontend/vnc_server/main.cpp
index eab7011..e036b40 100644
--- a/host/frontend/vnc_server/main.cpp
+++ b/host/frontend/vnc_server/main.cpp
@@ -15,22 +15,40 @@
  */
 
 #include <algorithm>
+#include <memory>
 #include <string>
 
 #include <gflags/gflags.h>
 
-#include "common/libs/glog/logging.h"
+#include "host/frontend/vnc_server/simulated_hw_composer.h"
 #include "host/frontend/vnc_server/vnc_server.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
-#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/logging.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_server.h"
 
 DEFINE_bool(agressive, false, "Whether to use agressive server");
+DEFINE_int32(frame_server_fd, -1, "");
 DEFINE_int32(port, 6444, "Port where to listen for connections");
 
 int main(int argc, char* argv[]) {
-  using ::android::base::ERROR;
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
-  ::gflags::ParseCommandLineFlags(&argc, &argv, true);
-  cvd::vnc::VncServer vnc_server(FLAGS_port, FLAGS_agressive);
+  cuttlefish::DefaultSubprocessLogging(argv);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  auto& host_mode_ctrl = cuttlefish::HostModeCtrl::Get();
+  auto screen_connector_ptr = cuttlefish::vnc::ScreenConnector::Get(
+      FLAGS_frame_server_fd, host_mode_ctrl);
+  auto& screen_connector = *(screen_connector_ptr.get());
+
+  // create confirmation UI service, giving host_mode_ctrl and
+  // screen_connector
+  // keep this singleton object alive until the webRTC process ends
+  static auto& host_confui_server =
+      cuttlefish::confui::HostServer::Get(host_mode_ctrl, screen_connector);
+
+  host_confui_server.Start();
+  // lint does not like the spelling of "agressive", so needs NOTYPO
+  cuttlefish::vnc::VncServer vnc_server(FLAGS_port, FLAGS_agressive,  // NOTYPO
+                                        screen_connector, host_confui_server);
   vnc_server.MainLoop();
 }
diff --git a/host/frontend/vnc_server/simulated_hw_composer.cpp b/host/frontend/vnc_server/simulated_hw_composer.cpp
index 7b478f4..15bcd8b 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.cpp
+++ b/host/frontend/vnc_server/simulated_hw_composer.cpp
@@ -16,24 +16,23 @@
 
 #include "host/frontend/vnc_server/simulated_hw_composer.h"
 
-#include <gflags/gflags.h>
-
 #include "host/frontend/vnc_server/vnc_utils.h"
 #include "host/libs/config/cuttlefish_config.h"
 
-DEFINE_int32(frame_server_fd, -1, "");
+using cuttlefish::vnc::SimulatedHWComposer;
+using ScreenConnector = cuttlefish::vnc::ScreenConnector;
 
-using cvd::vnc::SimulatedHWComposer;
-
-SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb)
+SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb,
+                                         ScreenConnector& screen_connector)
     :
 #ifdef FUZZ_TEST_VNC
       engine_{std::random_device{}()},
 #endif
       bb_{bb},
       stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements),
-      screen_connector_(ScreenConnector::Get(FLAGS_frame_server_fd)) {
+      screen_connector_(screen_connector) {
   stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this);
+  screen_connector_.SetCallback(std::move(GetScreenConnectorCallback()));
 }
 
 SimulatedHWComposer::~SimulatedHWComposer() {
@@ -41,7 +40,7 @@
   stripe_maker_.join();
 }
 
-cvd::vnc::Stripe SimulatedHWComposer::GetNewStripe() {
+cuttlefish::vnc::Stripe SimulatedHWComposer::GetNewStripe() {
   auto s = stripes_.Pop();
 #ifdef FUZZ_TEST_VNC
   if (random_(engine_)) {
@@ -72,57 +71,111 @@
   q->erase(q->begin(), std::next(q->begin(), kMaxQueueElements / 2));
 }
 
-void SimulatedHWComposer::MakeStripes() {
-  std::uint32_t previous_frame_number = 0;
-  auto screen_height = ScreenConnector::ScreenHeight();
-  Message raw_screen;
-  std::uint64_t stripe_seq_num = 1;
+SimulatedHWComposer::GenerateProcessedFrameCallback
+SimulatedHWComposer::GetScreenConnectorCallback() {
+  return [](std::uint32_t display_number, std::uint8_t* frame_pixels,
+            cuttlefish::vnc::VncScProcessedFrame& processed_frame) {
+    processed_frame.display_number_ = display_number;
+    // TODO(171305898): handle multiple displays.
+    if (display_number != 0) {
+      // BUG 186580833: display_number comes from surface_id in crosvm
+      // create_surface from virtio_gpu.rs set_scanout.  We cannot use it as
+      // the display number. Either crosvm virtio-gpu is incorrectly ignoring
+      // scanout id and instead using a monotonically increasing surface id
+      // number as the scanout resource is replaced over time, or frontend code
+      // here is incorrectly assuming  surface id == display id.
+      display_number = 0;
+    }
+    const std::uint32_t display_w =
+        ScreenConnector::ScreenWidth(display_number);
+    const std::uint32_t display_h =
+        ScreenConnector::ScreenHeight(display_number);
+    const std::uint32_t display_stride_bytes =
+        ScreenConnector::ScreenStrideBytes(display_number);
+    const std::uint32_t display_bpp = ScreenConnector::BytesPerPixel();
+    const std::uint32_t display_size_bytes =
+        ScreenConnector::ScreenSizeInBytes(display_number);
 
-  const FrameCallback frame_callback = [&](uint32_t frame_number,
-                                           uint8_t* frame_pixels) {
-    raw_screen.assign(frame_pixels,
-                      frame_pixels + ScreenConnector::ScreenSizeInBytes());
+    auto& raw_screen = processed_frame.raw_screen_;
+    raw_screen.assign(frame_pixels, frame_pixels + display_size_bytes);
 
-    for (int i = 0; i < kNumStripes; ++i) {
-      ++stripe_seq_num;
-      std::uint16_t y = (screen_height / kNumStripes) * i;
+    static std::uint32_t next_frame_number = 0;
+
+    const auto num_stripes = SimulatedHWComposer::kNumStripes;
+    for (int i = 0; i < num_stripes; ++i) {
+      std::uint16_t y = (display_h / num_stripes) * i;
 
       // Last frames on the right and/or bottom handle extra pixels
       // when a screen dimension is not evenly divisible by Frame::kNumSlots.
       std::uint16_t height =
-          screen_height / kNumStripes +
-          (i + 1 == kNumStripes ? screen_height % kNumStripes : 0);
-      const auto* raw_start = &raw_screen[y * ScreenConnector::ScreenWidth() *
-                                          ScreenConnector::BytesPerPixel()];
-      const auto* raw_end =
-          raw_start + (height * ScreenConnector::ScreenWidth() *
-                       ScreenConnector::BytesPerPixel());
+          display_h / num_stripes +
+          (i + 1 == num_stripes ? display_h % num_stripes : 0);
+      const auto* raw_start = &raw_screen[y * display_w * display_bpp];
+      const auto* raw_end = raw_start + (height * display_w * display_bpp);
       // creating a named object and setting individual data members in order
       // to make klp happy
       // TODO (haining) construct this inside the call when not compiling
       // on klp
       Stripe s{};
       s.index = i;
-      s.frame_id = frame_number;
       s.x = 0;
       s.y = y;
-      s.width = ScreenConnector::ScreenWidth();
-      s.stride = ScreenConnector::ScreenStride();
+      s.width = display_w;
+      s.stride = display_stride_bytes;
       s.height = height;
+      s.frame_id = next_frame_number++;
       s.raw_data.assign(raw_start, raw_end);
-      s.seq_number = StripeSeqNumber{stripe_seq_num};
       s.orientation = ScreenOrientation::Portrait;
-      stripes_.Push(std::move(s));
+      processed_frame.stripes_.push_back(std::move(s));
     }
 
-    previous_frame_number = frame_number;
+    processed_frame.display_number_ = display_number;
+    processed_frame.is_success_ = true;
   };
+}
 
+void SimulatedHWComposer::MakeStripes() {
+  std::uint64_t stripe_seq_num = 1;
+  /*
+   * callback should be set before the first WaitForAtLeastOneClientConnection()
+   * (b/178504150) and the first OnFrameAfter().
+   */
+  if (!screen_connector_.IsCallbackSet()) {
+    LOG(FATAL) << "ScreenConnector callback hasn't been set before MakeStripes";
+  }
   while (!closed()) {
     bb_->WaitForAtLeastOneClientConnection();
-
-    screen_connector_->OnFrameAfter(previous_frame_number, frame_callback);
+    auto sim_hw_processed_frame = screen_connector_.OnNextFrame();
+    // sim_hw_processed_frame has display number from the guest
+    if (!sim_hw_processed_frame.is_success_) {
+      continue;
+    }
+    while (!sim_hw_processed_frame.stripes_.empty()) {
+      /*
+       * ScreenConnector that supplies the frames into the queue
+       * cannot be aware of stripe_seq_num. The callback was set at the
+       * ScreenConnector creation time. ScreenConnector calls the callback
+       * function autonomously to make the processed frames to supply the
+       * queue with.
+       *
+       * Besides, ScreenConnector is not VNC specific. Thus, stripe_seq_num,
+       * a VNC specific information, is maintained here.
+       *
+       * OnFrameAfter returns a sim_hw_processed_frame, that contains N consecutive stripes.
+       * each stripe s has an invalid seq_number, default-initialzed
+       * We set the field properly, and push to the stripes_
+       */
+      auto& s = sim_hw_processed_frame.stripes_.front();
+      stripe_seq_num++;
+      s.seq_number = StripeSeqNumber{stripe_seq_num};
+      stripes_.Push(std::move(s));
+      sim_hw_processed_frame.stripes_.pop_front();
+    }
   }
 }
 
 int SimulatedHWComposer::NumberOfStripes() { return kNumStripes; }
+
+void SimulatedHWComposer::ReportClientsConnected() {
+  screen_connector_.ReportClientsConnected(true);
+}
diff --git a/host/frontend/vnc_server/simulated_hw_composer.h b/host/frontend/vnc_server/simulated_hw_composer.h
index 4a51f78..9d62e3e 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.h
+++ b/host/frontend/vnc_server/simulated_hw_composer.h
@@ -22,23 +22,30 @@
 #include <random>
 #endif
 #include <thread>
+#include <deque>
 
-#include "common/libs/thread_safe_queue/thread_safe_queue.h"
-#include "common/libs/threads/thread_annotations.h"
+#include "common/libs/concurrency/thread_annotations.h"
+#include "common/libs/concurrency/thread_safe_queue.h"
 #include "host/frontend/vnc_server/blackboard.h"
+#include "host/frontend/vnc_server/vnc_utils.h"
+#include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/screen_connector/screen_connector.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 class SimulatedHWComposer {
  public:
-  SimulatedHWComposer(BlackBoard* bb);
+  using GenerateProcessedFrameCallback = ScreenConnector::GenerateProcessedFrameCallback;
+
+  SimulatedHWComposer(BlackBoard* bb, ScreenConnector& screen_connector);
   SimulatedHWComposer(const SimulatedHWComposer&) = delete;
   SimulatedHWComposer& operator=(const SimulatedHWComposer&) = delete;
   ~SimulatedHWComposer();
 
   Stripe GetNewStripe();
 
+  void ReportClientsConnected();
+
   // NOTE not constexpr on purpose
   static int NumberOfStripes();
 
@@ -47,6 +54,7 @@
   void close();
   static void EraseHalfOfElements(ThreadSafeQueue<Stripe>::QueueImpl* q);
   void MakeStripes();
+  GenerateProcessedFrameCallback GetScreenConnectorCallback();
 
 #ifdef FUZZ_TEST_VNC
   std::default_random_engine engine_;
@@ -60,7 +68,7 @@
   BlackBoard* bb_{};
   ThreadSafeQueue<Stripe> stripes_;
   std::thread stripe_maker_;
-  std::shared_ptr<ScreenConnector> screen_connector_;
+  ScreenConnector& screen_connector_;
 };
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/virtual_inputs.cpp b/host/frontend/vnc_server/virtual_inputs.cpp
index fb91409..35fda80 100644
--- a/host/frontend/vnc_server/virtual_inputs.cpp
+++ b/host/frontend/vnc_server/virtual_inputs.cpp
@@ -15,8 +15,9 @@
  */
 
 #include "host/frontend/vnc_server/virtual_inputs.h"
+
 #include <gflags/gflags.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include <linux/input.h>
 #include <linux/uinput.h>
 
@@ -25,10 +26,12 @@
 #include <thread>
 #include "keysyms.h"
 
-#include <common/libs/fs/shared_select.h>
-#include <host/libs/config/cuttlefish_config.h>
+#include "common/libs/confui/confui.h"
+#include "common/libs/fs/shared_select.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/logging.h"
 
-using cvd::vnc::VirtualInputs;
+using cuttlefish::vnc::VirtualInputs;
 
 DEFINE_int32(touch_fd, -1,
              "A fd for a socket where to accept touch connections");
@@ -49,24 +52,24 @@
 };
 
 void AddKeyMappings(std::map<uint32_t, uint16_t>* key_mapping) {
-  (*key_mapping)[cvd::xk::AltLeft] = KEY_LEFTALT;
-  (*key_mapping)[cvd::xk::ControlLeft] = KEY_LEFTCTRL;
-  (*key_mapping)[cvd::xk::ShiftLeft] = KEY_LEFTSHIFT;
-  (*key_mapping)[cvd::xk::AltRight] = KEY_RIGHTALT;
-  (*key_mapping)[cvd::xk::ControlRight] = KEY_RIGHTCTRL;
-  (*key_mapping)[cvd::xk::ShiftRight] = KEY_RIGHTSHIFT;
-  (*key_mapping)[cvd::xk::MetaLeft] = KEY_LEFTMETA;
-  (*key_mapping)[cvd::xk::MetaRight] = KEY_RIGHTMETA;
-  (*key_mapping)[cvd::xk::MultiKey] = KEY_COMPOSE;
+  (*key_mapping)[cuttlefish::xk::AltLeft] = KEY_LEFTALT;
+  (*key_mapping)[cuttlefish::xk::ControlLeft] = KEY_LEFTCTRL;
+  (*key_mapping)[cuttlefish::xk::ShiftLeft] = KEY_LEFTSHIFT;
+  (*key_mapping)[cuttlefish::xk::AltRight] = KEY_RIGHTALT;
+  (*key_mapping)[cuttlefish::xk::ControlRight] = KEY_RIGHTCTRL;
+  (*key_mapping)[cuttlefish::xk::ShiftRight] = KEY_RIGHTSHIFT;
+  (*key_mapping)[cuttlefish::xk::MetaLeft] = KEY_LEFTMETA;
+  (*key_mapping)[cuttlefish::xk::MetaRight] = KEY_RIGHTMETA;
+  (*key_mapping)[cuttlefish::xk::MultiKey] = KEY_COMPOSE;
 
-  (*key_mapping)[cvd::xk::CapsLock] = KEY_CAPSLOCK;
-  (*key_mapping)[cvd::xk::NumLock] = KEY_NUMLOCK;
-  (*key_mapping)[cvd::xk::ScrollLock] = KEY_SCROLLLOCK;
+  (*key_mapping)[cuttlefish::xk::CapsLock] = KEY_CAPSLOCK;
+  (*key_mapping)[cuttlefish::xk::NumLock] = KEY_NUMLOCK;
+  (*key_mapping)[cuttlefish::xk::ScrollLock] = KEY_SCROLLLOCK;
 
-  (*key_mapping)[cvd::xk::BackSpace] = KEY_BACKSPACE;
-  (*key_mapping)[cvd::xk::Tab] = KEY_TAB;
-  (*key_mapping)[cvd::xk::Return] = KEY_ENTER;
-  (*key_mapping)[cvd::xk::Escape] = KEY_ESC;
+  (*key_mapping)[cuttlefish::xk::BackSpace] = KEY_BACKSPACE;
+  (*key_mapping)[cuttlefish::xk::Tab] = KEY_TAB;
+  (*key_mapping)[cuttlefish::xk::Return] = KEY_ENTER;
+  (*key_mapping)[cuttlefish::xk::Escape] = KEY_ESC;
 
   (*key_mapping)[' '] = KEY_SPACE;
   (*key_mapping)['!'] = KEY_1;
@@ -166,75 +169,75 @@
   (*key_mapping)['}'] = KEY_RIGHTBRACE;
   (*key_mapping)['~'] = KEY_GRAVE;
 
-  (*key_mapping)[cvd::xk::F1] = KEY_F1;
-  (*key_mapping)[cvd::xk::F2] = KEY_F2;
-  (*key_mapping)[cvd::xk::F3] = KEY_F3;
-  (*key_mapping)[cvd::xk::F4] = KEY_F4;
-  (*key_mapping)[cvd::xk::F5] = KEY_F5;
-  (*key_mapping)[cvd::xk::F6] = KEY_F6;
-  (*key_mapping)[cvd::xk::F7] = KEY_F7;
-  (*key_mapping)[cvd::xk::F8] = KEY_F8;
-  (*key_mapping)[cvd::xk::F9] = KEY_F9;
-  (*key_mapping)[cvd::xk::F10] = KEY_F10;
-  (*key_mapping)[cvd::xk::F11] = KEY_F11;
-  (*key_mapping)[cvd::xk::F12] = KEY_F12;
-  (*key_mapping)[cvd::xk::F13] = KEY_F13;
-  (*key_mapping)[cvd::xk::F14] = KEY_F14;
-  (*key_mapping)[cvd::xk::F15] = KEY_F15;
-  (*key_mapping)[cvd::xk::F16] = KEY_F16;
-  (*key_mapping)[cvd::xk::F17] = KEY_F17;
-  (*key_mapping)[cvd::xk::F18] = KEY_F18;
-  (*key_mapping)[cvd::xk::F19] = KEY_F19;
-  (*key_mapping)[cvd::xk::F20] = KEY_F20;
-  (*key_mapping)[cvd::xk::F21] = KEY_F21;
-  (*key_mapping)[cvd::xk::F22] = KEY_F22;
-  (*key_mapping)[cvd::xk::F23] = KEY_F23;
-  (*key_mapping)[cvd::xk::F24] = KEY_F24;
+  (*key_mapping)[cuttlefish::xk::F1] = KEY_F1;
+  (*key_mapping)[cuttlefish::xk::F2] = KEY_F2;
+  (*key_mapping)[cuttlefish::xk::F3] = KEY_F3;
+  (*key_mapping)[cuttlefish::xk::F4] = KEY_F4;
+  (*key_mapping)[cuttlefish::xk::F5] = KEY_F5;
+  (*key_mapping)[cuttlefish::xk::F6] = KEY_F6;
+  (*key_mapping)[cuttlefish::xk::F7] = KEY_F7;
+  (*key_mapping)[cuttlefish::xk::F8] = KEY_F8;
+  (*key_mapping)[cuttlefish::xk::F9] = KEY_F9;
+  (*key_mapping)[cuttlefish::xk::F10] = KEY_F10;
+  (*key_mapping)[cuttlefish::xk::F11] = KEY_F11;
+  (*key_mapping)[cuttlefish::xk::F12] = KEY_F12;
+  (*key_mapping)[cuttlefish::xk::F13] = KEY_F13;
+  (*key_mapping)[cuttlefish::xk::F14] = KEY_F14;
+  (*key_mapping)[cuttlefish::xk::F15] = KEY_F15;
+  (*key_mapping)[cuttlefish::xk::F16] = KEY_F16;
+  (*key_mapping)[cuttlefish::xk::F17] = KEY_F17;
+  (*key_mapping)[cuttlefish::xk::F18] = KEY_F18;
+  (*key_mapping)[cuttlefish::xk::F19] = KEY_F19;
+  (*key_mapping)[cuttlefish::xk::F20] = KEY_F20;
+  (*key_mapping)[cuttlefish::xk::F21] = KEY_F21;
+  (*key_mapping)[cuttlefish::xk::F22] = KEY_F22;
+  (*key_mapping)[cuttlefish::xk::F23] = KEY_F23;
+  (*key_mapping)[cuttlefish::xk::F24] = KEY_F24;
 
-  (*key_mapping)[cvd::xk::Keypad0] = KEY_KP0;
-  (*key_mapping)[cvd::xk::Keypad1] = KEY_KP1;
-  (*key_mapping)[cvd::xk::Keypad2] = KEY_KP2;
-  (*key_mapping)[cvd::xk::Keypad3] = KEY_KP3;
-  (*key_mapping)[cvd::xk::Keypad4] = KEY_KP4;
-  (*key_mapping)[cvd::xk::Keypad5] = KEY_KP5;
-  (*key_mapping)[cvd::xk::Keypad6] = KEY_KP6;
-  (*key_mapping)[cvd::xk::Keypad7] = KEY_KP7;
-  (*key_mapping)[cvd::xk::Keypad8] = KEY_KP8;
-  (*key_mapping)[cvd::xk::Keypad9] = KEY_KP9;
-  (*key_mapping)[cvd::xk::KeypadMultiply] = KEY_KPASTERISK;
-  (*key_mapping)[cvd::xk::KeypadSubtract] = KEY_KPMINUS;
-  (*key_mapping)[cvd::xk::KeypadAdd] = KEY_KPPLUS;
-  (*key_mapping)[cvd::xk::KeypadDecimal] = KEY_KPDOT;
-  (*key_mapping)[cvd::xk::KeypadEnter] = KEY_KPENTER;
-  (*key_mapping)[cvd::xk::KeypadDivide] = KEY_KPSLASH;
-  (*key_mapping)[cvd::xk::KeypadEqual] = KEY_KPEQUAL;
-  (*key_mapping)[cvd::xk::PlusMinus] = KEY_KPPLUSMINUS;
+  (*key_mapping)[cuttlefish::xk::Keypad0] = KEY_KP0;
+  (*key_mapping)[cuttlefish::xk::Keypad1] = KEY_KP1;
+  (*key_mapping)[cuttlefish::xk::Keypad2] = KEY_KP2;
+  (*key_mapping)[cuttlefish::xk::Keypad3] = KEY_KP3;
+  (*key_mapping)[cuttlefish::xk::Keypad4] = KEY_KP4;
+  (*key_mapping)[cuttlefish::xk::Keypad5] = KEY_KP5;
+  (*key_mapping)[cuttlefish::xk::Keypad6] = KEY_KP6;
+  (*key_mapping)[cuttlefish::xk::Keypad7] = KEY_KP7;
+  (*key_mapping)[cuttlefish::xk::Keypad8] = KEY_KP8;
+  (*key_mapping)[cuttlefish::xk::Keypad9] = KEY_KP9;
+  (*key_mapping)[cuttlefish::xk::KeypadMultiply] = KEY_KPASTERISK;
+  (*key_mapping)[cuttlefish::xk::KeypadSubtract] = KEY_KPMINUS;
+  (*key_mapping)[cuttlefish::xk::KeypadAdd] = KEY_KPPLUS;
+  (*key_mapping)[cuttlefish::xk::KeypadDecimal] = KEY_KPDOT;
+  (*key_mapping)[cuttlefish::xk::KeypadEnter] = KEY_KPENTER;
+  (*key_mapping)[cuttlefish::xk::KeypadDivide] = KEY_KPSLASH;
+  (*key_mapping)[cuttlefish::xk::KeypadEqual] = KEY_KPEQUAL;
+  (*key_mapping)[cuttlefish::xk::PlusMinus] = KEY_KPPLUSMINUS;
 
-  (*key_mapping)[cvd::xk::SysReq] = KEY_SYSRQ;
-  (*key_mapping)[cvd::xk::LineFeed] = KEY_LINEFEED;
-  (*key_mapping)[cvd::xk::Home] = KEY_HOME;
-  (*key_mapping)[cvd::xk::Up] = KEY_UP;
-  (*key_mapping)[cvd::xk::PageUp] = KEY_PAGEUP;
-  (*key_mapping)[cvd::xk::Left] = KEY_LEFT;
-  (*key_mapping)[cvd::xk::Right] = KEY_RIGHT;
-  (*key_mapping)[cvd::xk::End] = KEY_END;
-  (*key_mapping)[cvd::xk::Down] = KEY_DOWN;
-  (*key_mapping)[cvd::xk::PageDown] = KEY_PAGEDOWN;
-  (*key_mapping)[cvd::xk::Insert] = KEY_INSERT;
-  (*key_mapping)[cvd::xk::Delete] = KEY_DELETE;
-  (*key_mapping)[cvd::xk::Pause] = KEY_PAUSE;
-  (*key_mapping)[cvd::xk::KeypadSeparator] = KEY_KPCOMMA;
-  (*key_mapping)[cvd::xk::Yen] = KEY_YEN;
-  (*key_mapping)[cvd::xk::Cancel] = KEY_STOP;
-  (*key_mapping)[cvd::xk::Redo] = KEY_AGAIN;
-  (*key_mapping)[cvd::xk::Undo] = KEY_UNDO;
-  (*key_mapping)[cvd::xk::Find] = KEY_FIND;
-  (*key_mapping)[cvd::xk::Print] = KEY_PRINT;
-  (*key_mapping)[cvd::xk::VolumeDown] = KEY_VOLUMEDOWN;
-  (*key_mapping)[cvd::xk::Mute] = KEY_MUTE;
-  (*key_mapping)[cvd::xk::VolumeUp] = KEY_VOLUMEUP;
-  (*key_mapping)[cvd::xk::Menu] = KEY_MENU;
-  (*key_mapping)[cvd::xk::VNCMenu] = KEY_MENU;
+  (*key_mapping)[cuttlefish::xk::SysReq] = KEY_SYSRQ;
+  (*key_mapping)[cuttlefish::xk::LineFeed] = KEY_LINEFEED;
+  (*key_mapping)[cuttlefish::xk::Home] = KEY_HOME;
+  (*key_mapping)[cuttlefish::xk::Up] = KEY_UP;
+  (*key_mapping)[cuttlefish::xk::PageUp] = KEY_PAGEUP;
+  (*key_mapping)[cuttlefish::xk::Left] = KEY_LEFT;
+  (*key_mapping)[cuttlefish::xk::Right] = KEY_RIGHT;
+  (*key_mapping)[cuttlefish::xk::End] = KEY_END;
+  (*key_mapping)[cuttlefish::xk::Down] = KEY_DOWN;
+  (*key_mapping)[cuttlefish::xk::PageDown] = KEY_PAGEDOWN;
+  (*key_mapping)[cuttlefish::xk::Insert] = KEY_INSERT;
+  (*key_mapping)[cuttlefish::xk::Delete] = KEY_DELETE;
+  (*key_mapping)[cuttlefish::xk::Pause] = KEY_PAUSE;
+  (*key_mapping)[cuttlefish::xk::KeypadSeparator] = KEY_KPCOMMA;
+  (*key_mapping)[cuttlefish::xk::Yen] = KEY_YEN;
+  (*key_mapping)[cuttlefish::xk::Cancel] = KEY_STOP;
+  (*key_mapping)[cuttlefish::xk::Redo] = KEY_AGAIN;
+  (*key_mapping)[cuttlefish::xk::Undo] = KEY_UNDO;
+  (*key_mapping)[cuttlefish::xk::Find] = KEY_FIND;
+  (*key_mapping)[cuttlefish::xk::Print] = KEY_PRINT;
+  (*key_mapping)[cuttlefish::xk::VolumeDown] = KEY_VOLUMEDOWN;
+  (*key_mapping)[cuttlefish::xk::Mute] = KEY_MUTE;
+  (*key_mapping)[cuttlefish::xk::VolumeUp] = KEY_VOLUMEUP;
+  (*key_mapping)[cuttlefish::xk::Menu] = KEY_MENU;
+  (*key_mapping)[cuttlefish::xk::VNCMenu] = KEY_MENU;
 }
 
 void InitInputEvent(struct input_event* evt, uint16_t type, uint16_t code,
@@ -280,7 +283,7 @@
 
  private:
   template<size_t num_events>
-  void SendEvents(cvd::SharedFD socket, struct input_event (&event_buffer)[num_events]) {
+  void SendEvents(cuttlefish::SharedFD socket, struct input_event (&event_buffer)[num_events]) {
     std::lock_guard<std::mutex> lock(socket_mutex_);
     if (!socket->IsOpen()) {
       // This is unlikely as it would only happen between the start of the vnc
@@ -312,41 +315,96 @@
   }
 
   void ClientConnectorLoop() {
-    auto touch_server = cvd::SharedFD::Dup(FLAGS_touch_fd);
+    auto touch_server = cuttlefish::SharedFD::Dup(FLAGS_touch_fd);
     close(FLAGS_touch_fd);
     FLAGS_touch_fd = -1;
 
-    auto keyboard_server = cvd::SharedFD::Dup(FLAGS_keyboard_fd);
+    auto keyboard_server = cuttlefish::SharedFD::Dup(FLAGS_keyboard_fd);
     close(FLAGS_keyboard_fd);
     FLAGS_keyboard_fd = -1;
-    LOG(INFO) << "Input socket host accepting connections...";
+    LOG(DEBUG) << "Input socket host accepting connections...";
 
     while (1) {
-      cvd::SharedFDSet read_set;
+      cuttlefish::SharedFDSet read_set;
       read_set.Set(touch_server);
       read_set.Set(keyboard_server);
-      cvd::Select(&read_set, nullptr, nullptr, nullptr);
+      cuttlefish::Select(&read_set, nullptr, nullptr, nullptr);
       {
         std::lock_guard<std::mutex> lock(socket_mutex_);
         if (read_set.IsSet(touch_server)) {
-          touch_socket_ = cvd::SharedFD::Accept(*touch_server);
-          LOG(INFO) << "connected to touch";
+          touch_socket_ = cuttlefish::SharedFD::Accept(*touch_server);
+          LOG(DEBUG) << "connected to touch";
         }
         if (read_set.IsSet(keyboard_server)) {
-          keyboard_socket_ = cvd::SharedFD::Accept(*keyboard_server);
-          LOG(INFO) << "connected to keyboard";
+          keyboard_socket_ = cuttlefish::SharedFD::Accept(*keyboard_server);
+          LOG(DEBUG) << "connected to keyboard";
         }
       }
     }
   }
-  cvd::SharedFD touch_socket_;
-  cvd::SharedFD keyboard_socket_;
+  cuttlefish::SharedFD touch_socket_;
+  cuttlefish::SharedFD keyboard_socket_;
   std::thread client_connector_;
   std::mutex socket_mutex_;
 };
 
 VirtualInputs::VirtualInputs() { AddKeyMappings(&keymapping_); }
 
-VirtualInputs* VirtualInputs::Get() {
-  return new SocketVirtualInputs();
+/**
+ * Depending on the host mode (e.g. android, confirmation ui(tee), etc)
+ * deliver the inputs to the right input implementation
+ * e.g. ConfUI's input or regular socket based input
+ */
+class VirtualInputDemux : public VirtualInputs {
+ public:
+  VirtualInputDemux(cuttlefish::confui::HostVirtualInput& confui_input)
+      : confui_input_{confui_input} {}
+  virtual ~VirtualInputDemux() = default;
+
+  virtual void GenerateKeyPressEvent(int code, bool down) override;
+  virtual void PressPowerButton(bool down) override;
+  virtual void HandlePointerEvent(bool touch_down, int x, int y) override;
+
+ private:
+  SocketVirtualInputs socket_virtual_input_;
+  cuttlefish::confui::HostVirtualInput& confui_input_;
+};
+
+void VirtualInputDemux::GenerateKeyPressEvent(int code, bool down) {
+  // confui input is active only in the confirmation UI
+  // also, socket virtual input should be inactive in the confirmation
+  // UI session
+  if (confui_input_.IsConfUiActive()) {
+    if (code == cuttlefish::xk::Menu) {
+      // release menu button in confirmation UI means for now cancel
+      confui_input_.PressCancelButton(down);
+    }
+    ConfUiLog(DEBUG) << "the key" << code << "ignored."
+                     << "currently confirmation UI handles"
+                     << "menu and power only.";
+    return;
+  }
+  socket_virtual_input_.GenerateKeyPressEvent(code, down);
+}
+
+void VirtualInputDemux::PressPowerButton(bool down) {
+  if (confui_input_.IsConfUiActive()) {
+    confui_input_.PressConfirmButton(down);
+    return;
+  }
+  socket_virtual_input_.PressPowerButton(down);
+}
+
+void VirtualInputDemux::HandlePointerEvent(bool touch_down, int x, int y) {
+  if (confui_input_.IsConfUiActive()) {
+    ConfUiLog(DEBUG) << "currently confirmation UI ignores pointer events at ("
+                     << x << ", " << y << ")";
+    return;
+  }
+  socket_virtual_input_.HandlePointerEvent(touch_down, x, y);
+}
+
+std::shared_ptr<VirtualInputs> VirtualInputs::Get(
+    cuttlefish::confui::HostVirtualInput& confui_input) {
+  return std::make_shared<VirtualInputDemux>(confui_input);
 }
diff --git a/host/frontend/vnc_server/virtual_inputs.h b/host/frontend/vnc_server/virtual_inputs.h
index 7aca3eb..f30202e 100644
--- a/host/frontend/vnc_server/virtual_inputs.h
+++ b/host/frontend/vnc_server/virtual_inputs.h
@@ -16,17 +16,20 @@
  * limitations under the License.
  */
 
-#include "vnc_utils.h"
-
 #include <map>
+#include <memory>
 #include <mutex>
 
-namespace cvd {
+#include "host/libs/confui/host_virtual_input.h"
+#include "vnc_utils.h"
+
+namespace cuttlefish {
 namespace vnc {
 
 class VirtualInputs {
  public:
-  static VirtualInputs* Get();
+  static std::shared_ptr<VirtualInputs> Get(
+      cuttlefish::confui::HostVirtualInput& confui_input);
 
   virtual ~VirtualInputs() = default;
 
@@ -41,4 +44,4 @@
 };
 
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/vnc_client_connection.cpp b/host/frontend/vnc_server/vnc_client_connection.cpp
index c15d46c..ce16ec8 100644
--- a/host/frontend/vnc_server/vnc_client_connection.cpp
+++ b/host/frontend/vnc_server/vnc_client_connection.cpp
@@ -31,18 +31,18 @@
 #include <vector>
 
 #include <gflags/gflags.h>
-#include <glog/logging.h>
-#include "common/libs/tcp_socket/tcp_socket.h"
+#include <android-base/logging.h>
+#include "common/libs/utils/tcp_socket.h"
 #include "host/frontend/vnc_server/keysyms.h"
 #include "host/frontend/vnc_server/mocks.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/screen_connector/screen_connector.h"
 
-using cvd::Message;
-using cvd::vnc::Stripe;
-using cvd::vnc::StripePtrVec;
-using cvd::vnc::VncClientConnection;
+using cuttlefish::Message;
+using cuttlefish::vnc::Stripe;
+using cuttlefish::vnc::StripePtrVec;
+using cuttlefish::vnc::VncClientConnection;
 
 struct ScreenRegionView {
   using Pixel = uint32_t;
@@ -88,7 +88,7 @@
 constexpr size_t kClientCutTextLength = 7;  // more bytes follow
 
 std::string HostName() {
-  auto config = vsoc::CuttlefishConfig::Get();
+  auto config = cuttlefish::CuttlefishConfig::Get();
   auto instance = config->ForDefaultInstance();
   return !config || instance.device_title().empty() ? std::string{"localhost"}
                                                     : instance.device_title();
@@ -130,7 +130,7 @@
          ((0x1 << ScreenRegionView::kGreenBits) - 1);
 }
 }  // namespace
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 bool operator==(const VncClientConnection::FrameBufferUpdateRequest& lhs,
                 const VncClientConnection::FrameBufferUpdateRequest& rhs) {
@@ -143,7 +143,7 @@
   return !(lhs == rhs);
 }
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
 
 VncClientConnection::VncClientConnection(
     ClientSocket client, std::shared_ptr<VirtualInputs> virtual_inputs,
@@ -258,7 +258,7 @@
 void VncClientConnection::SendServerInit() {
   const std::string server_name = HostName();
   std::lock_guard<std::mutex> guard(m_);
-  auto server_init = cvd::CreateMessage(
+  auto server_init = cuttlefish::CreateMessage(
       static_cast<std::uint16_t>(ScreenWidth()),
       static_cast<std::uint16_t>(ScreenHeight()), pixel_format_.bits_per_pixel,
       pixel_format_.depth, pixel_format_.big_endian, pixel_format_.true_color,
@@ -272,7 +272,7 @@
 
 Message VncClientConnection::MakeFrameBufferUpdateHeader(
     std::uint16_t num_stripes) {
-  return cvd::CreateMessage(std::uint8_t{0},  // message-type
+  return cuttlefish::CreateMessage(std::uint8_t{0},  // message-type
                             std::uint8_t{},   // padding
                             std::uint16_t{num_stripes});
 }
@@ -280,7 +280,7 @@
 void VncClientConnection::AppendRawStripeHeader(Message* frame_buffer_update,
                                                 const Stripe& stripe) {
   static constexpr int32_t kRawEncoding = 0;
-  cvd::AppendToMessage(frame_buffer_update, std::uint16_t{stripe.x},
+  cuttlefish::AppendToMessage(frame_buffer_update, std::uint16_t{stripe.x},
                        std::uint16_t{stripe.y}, std::uint16_t{stripe.width},
                        std::uint16_t{stripe.height}, kRawEncoding);
 }
@@ -292,11 +292,11 @@
   constexpr size_t kJpegSizeThreeByteMax = 4194303;
 
   if (jpeg_size <= kJpegSizeOneByteMax) {
-    cvd::AppendToMessage(frame_buffer_update,
+    cuttlefish::AppendToMessage(frame_buffer_update,
                          static_cast<std::uint8_t>(jpeg_size));
   } else if (jpeg_size <= kJpegSizeTwoByteMax) {
     auto sz = static_cast<std::uint32_t>(jpeg_size);
-    cvd::AppendToMessage(frame_buffer_update,
+    cuttlefish::AppendToMessage(frame_buffer_update,
                          static_cast<std::uint8_t>((sz & 0x7F) | 0x80),
                          static_cast<std::uint8_t>((sz >> 7) & 0xFF));
   } else {
@@ -305,7 +305,7 @@
                  << kJpegSizeThreeByteMax;
     }
     const auto sz = static_cast<std::uint32_t>(jpeg_size);
-    cvd::AppendToMessage(frame_buffer_update,
+    cuttlefish::AppendToMessage(frame_buffer_update,
                          static_cast<std::uint8_t>((sz & 0x7F) | 0x80),
                          static_cast<std::uint8_t>(((sz >> 7) & 0x7F) | 0x80),
                          static_cast<std::uint8_t>((sz >> 14) & 0xFF));
@@ -353,7 +353,7 @@
 void VncClientConnection::AppendJpegStripeHeader(Message* frame_buffer_update,
                                                  const Stripe& stripe) {
   static constexpr std::uint8_t kJpegEncoding = 0x90;
-  cvd::AppendToMessage(frame_buffer_update, stripe.x, stripe.y, stripe.width,
+  cuttlefish::AppendToMessage(frame_buffer_update, stripe.x, stripe.y, stripe.width,
                        stripe.height, kTightEncoding, kJpegEncoding);
   AppendJpegSize(frame_buffer_update, stripe.jpeg_data.size());
 }
@@ -411,7 +411,7 @@
 
 void VncClientConnection::SendDesktopSizeUpdate() {
   static constexpr int32_t kDesktopSizeEncoding = -223;
-  client_.SendNoSignal(cvd::CreateMessage(
+  client_.SendNoSignal(cuttlefish::CreateMessage(
       std::uint8_t{0},   // message-type,
       std::uint8_t{},    // padding
       std::uint16_t{1},  // one pseudo rectangle
@@ -504,7 +504,7 @@
     std::lock_guard<std::mutex> guard(m_);
     if (current_orientation_ == ScreenOrientation::Landscape) {
       std::tie(x_pos, y_pos) =
-          std::make_pair(ScreenConnector::ScreenWidth() - y_pos, x_pos);
+          std::make_pair(ScreenConnectorInfo::ScreenWidth(0) - y_pos, x_pos);
     }
   }
   virtual_inputs_->HandlePointerEvent(button_mask, x_pos, y_pos);
@@ -534,14 +534,14 @@
 
 int VncClientConnection::ScreenWidth() const {
   return current_orientation_ == ScreenOrientation::Portrait
-             ? ScreenConnector::ScreenWidth()
-             : ScreenConnector::ScreenHeight();
+             ? ScreenConnectorInfo::ScreenWidth(0)
+             : ScreenConnectorInfo::ScreenHeight(0);
 }
 
 int VncClientConnection::ScreenHeight() const {
   return current_orientation_ == ScreenOrientation::Portrait
-             ? ScreenConnector::ScreenHeight()
-             : ScreenConnector::ScreenWidth();
+             ? ScreenConnectorInfo::ScreenHeight(0)
+             : ScreenConnectorInfo::ScreenWidth(0);
 }
 
 void VncClientConnection::SetScreenOrientation(ScreenOrientation orientation) {
@@ -574,13 +574,13 @@
     return false;
   }
   switch (key) {
-    case cvd::xk::Right:
-    case cvd::xk::F12:
+    case cuttlefish::xk::Right:
+    case cuttlefish::xk::F12:
       DLOG(INFO) << "switching to portrait";
       SetScreenOrientation(ScreenOrientation::Portrait);
       break;
-    case cvd::xk::Left:
-    case cvd::xk::F11:
+    case cuttlefish::xk::Left:
+    case cuttlefish::xk::F11:
       DLOG(INFO) << "switching to landscape";
       SetScreenOrientation(ScreenOrientation::Landscape);
       break;
@@ -599,18 +599,18 @@
   auto key = uint32_tAt(&msg[3]);
   bool key_down = msg[0];
   switch (key) {
-    case cvd::xk::ControlLeft:
-    case cvd::xk::ControlRight:
+    case cuttlefish::xk::ControlLeft:
+    case cuttlefish::xk::ControlRight:
       control_key_down_ = key_down;
       break;
-    case cvd::xk::MetaLeft:
-    case cvd::xk::MetaRight:
+    case cuttlefish::xk::MetaLeft:
+    case cuttlefish::xk::MetaRight:
       meta_key_down_ = key_down;
       break;
-    case cvd::xk::F5:
-      key = cvd::xk::Menu;
+    case cuttlefish::xk::F5:
+      key = cuttlefish::xk::Menu;
       break;
-    case cvd::xk::F7:
+    case cuttlefish::xk::F7:
       virtual_inputs_->PressPowerButton(key_down);
       return;
     default:
diff --git a/host/frontend/vnc_server/vnc_client_connection.h b/host/frontend/vnc_server/vnc_client_connection.h
index 9f4fb96..b26cf86 100644
--- a/host/frontend/vnc_server/vnc_client_connection.h
+++ b/host/frontend/vnc_server/vnc_client_connection.h
@@ -16,8 +16,8 @@
  * limitations under the License.
  */
 
+#include "common/libs/concurrency/thread_annotations.h"
 #include "common/libs/fs/shared_fd.h"
-#include "common/libs/threads/thread_annotations.h"
 
 #include <cstdint>
 #include <memory>
@@ -25,12 +25,12 @@
 #include <thread>
 #include <vector>
 
-#include "common/libs/tcp_socket/tcp_socket.h"
+#include "common/libs/utils/tcp_socket.h"
 #include "host/frontend/vnc_server/blackboard.h"
 #include "host/frontend/vnc_server/virtual_inputs.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 
 class VncClientConnection {
@@ -170,4 +170,4 @@
 };
 
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/vnc_server.cpp b/host/frontend/vnc_server/vnc_server.cpp
index 3aba467..eff0d57 100644
--- a/host/frontend/vnc_server/vnc_server.cpp
+++ b/host/frontend/vnc_server/vnc_server.cpp
@@ -16,8 +16,10 @@
 
 #include "host/frontend/vnc_server/vnc_server.h"
 
-#include <glog/logging.h>
-#include "common/libs/tcp_socket/tcp_socket.h"
+#include <memory>
+
+#include <android-base/logging.h>
+#include "common/libs/utils/tcp_socket.h"
 #include "host/frontend/vnc_server/blackboard.h"
 #include "host/frontend/vnc_server/frame_buffer_watcher.h"
 #include "host/frontend/vnc_server/jpeg_compressor.h"
@@ -25,19 +27,21 @@
 #include "host/frontend/vnc_server/vnc_client_connection.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
 
-using cvd::vnc::VncServer;
+using cuttlefish::vnc::VncServer;
 
-VncServer::VncServer(int port, bool aggressive)
+VncServer::VncServer(int port, bool aggressive,
+                     cuttlefish::vnc::ScreenConnector& screen_connector,
+                     cuttlefish::confui::HostVirtualInput& confui_input)
     : server_(port),
-    virtual_inputs_(VirtualInputs::Get()),
-    frame_buffer_watcher_{&bb_},
-    aggressive_{aggressive} {}
+      virtual_inputs_(VirtualInputs::Get(confui_input)),
+      frame_buffer_watcher_{&bb_, screen_connector},
+      aggressive_{aggressive} {}
 
 void VncServer::MainLoop() {
   while (true) {
-    LOG(INFO) << "Awaiting connections";
+    LOG(DEBUG) << "Awaiting connections";
     auto connection = server_.Accept();
-    LOG(INFO) << "Accepted a client connection";
+    LOG(DEBUG) << "Accepted a client connection";
     StartClient(std::move(connection));
   }
 }
@@ -53,7 +57,9 @@
   // data members. In the current setup, if the VncServer is destroyed with
   // clients still running, the clients will all be left with dangling
   // pointers.
+  frame_buffer_watcher_.IncClientCount();
   VncClientConnection client(std::move(sock), virtual_inputs_, &bb_,
                              aggressive_);
   client.StartSession();
+  frame_buffer_watcher_.DecClientCount();
 }
diff --git a/host/frontend/vnc_server/vnc_server.h b/host/frontend/vnc_server/vnc_server.h
index 66e17e0..2751fd1 100644
--- a/host/frontend/vnc_server/vnc_server.h
+++ b/host/frontend/vnc_server/vnc_server.h
@@ -21,20 +21,25 @@
 #include <thread>
 #include <utility>
 
-#include "common/libs/tcp_socket/tcp_socket.h"
+#include "common/libs/utils/tcp_socket.h"
 #include "host/frontend/vnc_server/blackboard.h"
 #include "host/frontend/vnc_server/frame_buffer_watcher.h"
 #include "host/frontend/vnc_server/jpeg_compressor.h"
 #include "host/frontend/vnc_server/virtual_inputs.h"
 #include "host/frontend/vnc_server/vnc_client_connection.h"
 #include "host/frontend/vnc_server/vnc_utils.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_virtual_input.h"
+#include "host/libs/screen_connector/screen_connector.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 
 class VncServer {
  public:
-  explicit VncServer(int port, bool aggressive);
+  explicit VncServer(int port, bool aggressive,
+                     ScreenConnector& screen_connector,
+                     cuttlefish::confui::HostVirtualInput& confui_input);
 
   VncServer(const VncServer&) = delete;
   VncServer& operator=(const VncServer&) = delete;
@@ -47,11 +52,13 @@
   void StartClientThread(ClientSocket sock);
 
   ServerSocket server_;
+
   std::shared_ptr<VirtualInputs> virtual_inputs_;
   BlackBoard bb_;
+
   FrameBufferWatcher frame_buffer_watcher_;
   bool aggressive_{};
 };
 
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/vnc_server/vnc_utils.h b/host/frontend/vnc_server/vnc_utils.h
index 7a80518..7ec19f7 100644
--- a/host/frontend/vnc_server/vnc_utils.h
+++ b/host/frontend/vnc_server/vnc_utils.h
@@ -18,14 +18,16 @@
 
 #include <array>
 #include <cstdint>
+#include <memory>
 #include <utility>
 #include <vector>
 
 #include "common/libs/utils/size_utils.h"
-#include "common/libs/tcp_socket/tcp_socket.h"
+#include "common/libs/utils/tcp_socket.h"
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/screen_connector/screen_connector.h"
 
-namespace cvd {
+namespace cuttlefish {
 namespace vnc {
 
 // TODO(haining) when the hwcomposer gives a sequence number type, use that
@@ -63,5 +65,26 @@
   ScreenOrientation orientation{};
 };
 
+/**
+ * ScreenConnectorImpl will generate this, and enqueue
+ *
+ * It's basically a (processed) frame, so it:
+ *   must be efficiently std::move-able
+ * Also, for the sake of algorithm simplicity:
+ *   must be default-constructable & assignable
+ *
+ */
+struct VncScProcessedFrame : public ScreenConnectorFrameInfo {
+  Message raw_screen_;
+  std::deque<Stripe> stripes_;
+  std::unique_ptr<VncScProcessedFrame> Clone() {
+    VncScProcessedFrame* cloned_frame = new VncScProcessedFrame();
+    cloned_frame->raw_screen_ = raw_screen_;
+    cloned_frame->stripes_ = stripes_;
+    return std::unique_ptr<VncScProcessedFrame>(cloned_frame);
+  }
+};
+using ScreenConnector = cuttlefish::ScreenConnector<VncScProcessedFrame>;
+
 }  // namespace vnc
-}  // namespace cvd
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/Android.bp b/host/frontend/webrtc/Android.bp
new file mode 100644
index 0000000..f03a589
--- /dev/null
+++ b/host/frontend/webrtc/Android.bp
@@ -0,0 +1,140 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+    name: "libcuttlefish_webrtc",
+    srcs: [
+        "lib/audio_device.cpp",
+        "lib/audio_track_source_impl.cpp",
+        "lib/client_handler.cpp",
+        "lib/keyboard.cpp",
+        "lib/local_recorder.cpp",
+        "lib/port_range_socket_factory.cpp",
+        "lib/streamer.cpp",
+        "lib/utils.cpp",
+        "lib/video_track_source_impl.cpp",
+        "lib/vp8only_encoder_factory.cpp",
+        "lib/ws_connection.cpp",
+    ],
+    cflags: [
+        // libwebrtc headers need this
+        "-Wno-unused-parameter",
+        "-DWEBRTC_POSIX",
+        "-DWEBRTC_LINUX",
+    ],
+    header_libs: [
+        "webrtc_signaling_headers",
+        "libwebrtc_absl_headers",
+    ],
+    static_libs: [
+        "libsrtp2",
+        "libcuttlefish_host_config",
+        "libcuttlefish_screen_connector",
+        "libcuttlefish_wayland_server",
+        "libgflags",
+        "libdrm",
+        "libffi",
+        "libwayland_server",
+        "libwayland_extension_server_protocols",
+        "libwebsockets",
+        "libcap",
+        "libcuttlefish_utils",
+        "libwebrtc",
+        "libwebrtc_absl_base",
+        "libwebrtc_absl_types",
+    ],
+    shared_libs: [
+        "libssl",
+        "libbase",
+        "libcuttlefish_fs",
+        "libjsoncpp",
+        "libwebm_mkvmuxer",
+    ],
+    defaults: ["cuttlefish_buildhost_only"],
+}
+
+cc_binary_host {
+    name: "webRTC",
+    srcs: [
+        "adb_handler.cpp",
+        "audio_handler.cpp",
+        "bluetooth_handler.cpp",
+        "connection_observer.cpp",
+        "cvd_video_frame_buffer.cpp",
+        "display_handler.cpp",
+        "kernel_log_events_handler.cpp",
+        "main.cpp",
+    ],
+    header_libs: [
+        "webrtc_signaling_headers",
+        "libwebrtc_absl_headers",
+        "libcuttlefish_confui_host_headers",
+    ],
+    static_libs: [
+        "libwebrtc_absl_base",
+        "libwebrtc_absl_container",
+        "libwebrtc_absl_debugging",
+        "libwebrtc_absl_flags",
+        "libwebrtc_absl_hash",
+        "libwebrtc_absl_numeric",
+        "libwebrtc_absl_status",
+        "libwebrtc_absl_strings",
+        "libwebrtc_absl_synchronization",
+        "libwebrtc_absl_time",
+        "libwebrtc_absl_types",
+        "libaom",
+        "libcap",
+        "libcuttlefish_audio_connector",
+        "libcuttlefish_host_config",
+        "libcuttlefish_screen_connector",
+        "libcuttlefish_utils",
+        "libcuttlefish_wayland_server",
+        "libcuttlefish_confui",
+        "libcuttlefish_confui_host",
+        "libft2.nodep",
+        "libteeui",
+        "libteeui_localization",
+        "libdrm",
+        "libevent",
+        "libffi",
+        "libgflags",
+        "libopus",
+        "libsrtp2",
+        "libvpx",
+        "libwayland_extension_server_protocols",
+        "libwayland_server",
+        "libwebrtc",
+        "libcuttlefish_webrtc",
+        "libwebsockets",
+        "libyuv",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libcuttlefish_fs",
+        "libcuttlefish_kernel_log_monitor_utils",
+        "libjsoncpp",
+        "libopus",
+        "libssl",
+        "libvpx",
+        "libyuv",
+        "libwebm_mkvmuxer",
+    ],
+    defaults: ["cuttlefish_buildhost_only"],
+}
diff --git a/host/frontend/webrtc/adb_handler.cpp b/host/frontend/webrtc/adb_handler.cpp
new file mode 100644
index 0000000..c580f65
--- /dev/null
+++ b/host/frontend/webrtc/adb_handler.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "host/frontend/webrtc/adb_handler.h"
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+
+using namespace android;
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+namespace {
+
+SharedFD SetupAdbSocket(const std::string &adb_host_and_port) {
+  auto colonPos = adb_host_and_port.find(':');
+  if (colonPos == std::string::npos) {
+    return SharedFD();
+  }
+
+  auto host = adb_host_and_port.substr(0, colonPos);
+
+  const char *portString = adb_host_and_port.c_str() + colonPos + 1;
+  char *end;
+  unsigned long port = strtoul(portString, &end, 10);
+
+  if (end == portString || *end != '\0' || port > 65535) {
+    return SharedFD();
+  }
+
+  auto local_client = SharedFD::SocketLocalClient(port, SOCK_STREAM);
+  CHECK(local_client->IsOpen()) << "Failed to connect to adb socket: " << local_client->StrError();
+  return local_client;
+}
+
+}  // namespace
+
+AdbHandler::AdbHandler(
+    const std::string &adb_host_and_port,
+    std::function<void(const uint8_t *, size_t)> send_to_client)
+    : send_to_client_(send_to_client),
+      adb_socket_(SetupAdbSocket(adb_host_and_port)),
+      shutdown_(SharedFD::Event(0,0))
+{
+    std::thread loop([this]() { ReadLoop(); });
+    read_thread_.swap(loop);
+}
+
+
+AdbHandler::~AdbHandler() {
+    // Send a message to the looper to shut down.
+    uint64_t v = 1;
+    shutdown_->Write(&v, sizeof(v));
+    // Shut down the socket as well.  Not srictly necessary.
+    adb_socket_->Shutdown(SHUT_RDWR);
+    read_thread_.join();
+}
+
+void AdbHandler::ReadLoop() {
+  while (1) {
+    uint8_t buffer[4096];
+
+    read_set_.Set(shutdown_);
+    read_set_.Set(adb_socket_);
+    Select(&read_set_, nullptr, nullptr, nullptr);
+
+    if (read_set_.IsSet(adb_socket_)) {
+        auto read = adb_socket_->Read(buffer, sizeof(buffer));
+        if (read < 0) {
+            LOG(ERROR) << "Error on reading from ADB socket: " << strerror(adb_socket_->GetErrno());
+            break;
+        }
+        if (read) {
+            send_to_client_(buffer, read);
+        }
+    }
+
+    if (read_set_.IsSet(shutdown_)) {
+        LOG(INFO) << "AdbHandler is shutting down.";
+        break;
+    }
+  }
+}
+
+void AdbHandler::handleMessage(const uint8_t *msg, size_t len) {
+  size_t sent = 0;
+  while (sent < len) {
+    auto this_sent = adb_socket_->Write(&msg[sent], len - sent);
+    if (this_sent < 0) {
+      LOG(FATAL) << "Error writing to adb socket: " << adb_socket_->StrError();
+      return;
+    }
+    sent += this_sent;
+  }
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/adb_handler.h b/host/frontend/webrtc/adb_handler.h
new file mode 100644
index 0000000..24a06d6
--- /dev/null
+++ b/host/frontend/webrtc/adb_handler.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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 <memory>
+#include <thread>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/fs/shared_select.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+struct AdbHandler {
+  explicit AdbHandler(const std::string
+          &adb_host_and_port,
+      std::function<void(const uint8_t *, size_t)> send_to_client);
+
+  ~AdbHandler();
+
+  void handleMessage(const uint8_t *msg, size_t len);
+
+ private:
+
+  std::function<void(const uint8_t *, size_t)> send_to_client_;
+
+  void ReadLoop();
+
+  SharedFD adb_socket_;
+  SharedFD shutdown_;
+  SharedFDSet read_set_;
+  std::thread read_thread_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/audio_handler.cpp b/host/frontend/webrtc/audio_handler.cpp
new file mode 100644
index 0000000..4046995
--- /dev/null
+++ b/host/frontend/webrtc/audio_handler.cpp
@@ -0,0 +1,481 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/audio_handler.h"
+
+#include <algorithm>
+#include <chrono>
+
+#include <android-base/logging.h>
+#include <rtc_base/time_utils.h>
+
+namespace cuttlefish {
+namespace {
+
+const virtio_snd_pcm_info STREAMS[] = {{
+    .hdr =
+        {
+            .hda_fn_nid = Le32(0),
+        },
+    .features = Le32(0),
+    // webrtc's api is quite primitive and doesn't allow for many different
+    // formats: It only takes the bits_per_sample as a parameter and assumes
+    // the underlying format to be one of the following:
+    .formats = Le64(
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U8) |
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U16) |
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24) |
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U32)),
+    .rates = Le64(
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_5512) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_8000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_11025) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_16000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_22050) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_32000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_44100) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_48000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_64000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_88200) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_96000) |
+        (((uint64_t)1) << (uint8_t)
+             AudioStreamRate::VIRTIO_SND_PCM_RATE_176400) |
+        (((uint64_t)1) << (uint8_t)
+             AudioStreamRate::VIRTIO_SND_PCM_RATE_192000) |
+        (((uint64_t)1) << (uint8_t)
+             AudioStreamRate::VIRTIO_SND_PCM_RATE_384000)),
+    .direction = (uint8_t)AudioStreamDirection::VIRTIO_SND_D_OUTPUT,
+    .channels_min = 1,
+    .channels_max = 2,
+}, {
+    .hdr =
+        {
+            .hda_fn_nid = Le32(0),
+        },
+    .features = Le32(0),
+    // webrtc's api is quite primitive and doesn't allow for many different
+    // formats: It only takes the bits_per_sample as a parameter and assumes
+    // the underlying format to be one of the following:
+    .formats = Le64(
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U8) |
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U16) |
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24) |
+        (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U32)),
+    .rates = Le64(
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_5512) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_8000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_11025) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_16000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_22050) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_32000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_44100) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_48000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_64000) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_88200) |
+        (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_96000) |
+        (((uint64_t)1) << (uint8_t)
+             AudioStreamRate::VIRTIO_SND_PCM_RATE_176400) |
+        (((uint64_t)1) << (uint8_t)
+             AudioStreamRate::VIRTIO_SND_PCM_RATE_192000) |
+        (((uint64_t)1) << (uint8_t)
+             AudioStreamRate::VIRTIO_SND_PCM_RATE_384000)),
+    .direction = (uint8_t)AudioStreamDirection::VIRTIO_SND_D_INPUT,
+    .channels_min = 1,
+    .channels_max = 2,
+}};
+constexpr uint32_t NUM_STREAMS = sizeof(STREAMS) / sizeof(STREAMS[0]);
+
+bool IsCapture(uint32_t stream_id) {
+  CHECK(stream_id < NUM_STREAMS) << "Invalid stream id: " << stream_id;
+  return STREAMS[stream_id].direction ==
+         (uint8_t)AudioStreamDirection::VIRTIO_SND_D_INPUT;
+}
+
+class CvdAudioFrameBuffer : public webrtc_streaming::AudioFrameBuffer {
+ public:
+  CvdAudioFrameBuffer(const uint8_t* buffer, int bits_per_sample,
+                      int sample_rate, int channels, int frames)
+      : buffer_(buffer),
+        bits_per_sample_(bits_per_sample),
+        sample_rate_(sample_rate),
+        channels_(channels),
+        frames_(frames) {}
+
+  int bits_per_sample() const override { return bits_per_sample_; }
+
+  int sample_rate() const override { return sample_rate_; }
+
+  int channels() const override { return channels_; }
+
+  int frames() const override { return frames_; }
+
+  const uint8_t* data() const override { return buffer_; }
+
+ private:
+  const uint8_t* buffer_;
+  int bits_per_sample_;
+  int sample_rate_;
+  int channels_;
+  int frames_;
+};
+
+int BitsPerSample(uint8_t virtio_format) {
+  switch (virtio_format) {
+    /* analog formats (width / physical width) */
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_IMA_ADPCM:
+      /*  4 /  4 bits */
+      return 4;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_MU_LAW:
+      /*  8 /  8 bits */
+      return 8;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_A_LAW:
+      /*  8 /  8 bits */
+      return 8;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S8:
+      /*  8 /  8 bits */
+      return 8;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U8:
+      /*  8 /  8 bits */
+      return 8;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S16:
+      /* 16 / 16 bits */
+      return 16;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U16:
+      /* 16 / 16 bits */
+      return 16;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S18_3:
+      /* 18 / 24 bits */
+      return 24;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U18_3:
+      /* 18 / 24 bits */
+      return 24;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S20_3:
+      /* 20 / 24 bits */
+      return 24;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U20_3:
+      /* 20 / 24 bits */
+      return 24;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S24_3:
+      /* 24 / 24 bits */
+      return 24;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24_3:
+      /* 24 / 24 bits */
+      return 24;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S20:
+      /* 20 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U20:
+      /* 20 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S24:
+      /* 24 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24:
+      /* 24 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S32:
+      /* 32 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U32:
+      /* 32 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_FLOAT:
+      /* 32 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_FLOAT64:
+      /* 64 / 64 bits */
+      return 64;
+    /* digital formats (width / physical width) */
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_DSD_U8:
+      /*  8 /  8 bits */
+      return 8;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_DSD_U16:
+      /* 16 / 16 bits */
+      return 16;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_DSD_U32:
+      /* 32 / 32 bits */
+      return 32;
+    case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME:
+      /* 32 / 32 bits */
+      return 32;
+    default:
+      LOG(ERROR) << "Unknown virtio-snd audio format: " << virtio_format;
+      return -1;
+  }
+}
+
+int SampleRate(uint8_t virtio_rate) {
+  switch (virtio_rate) {
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_5512:
+      return 5512;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_8000:
+      return 8000;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_11025:
+      return 11025;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_16000:
+      return 16000;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_22050:
+      return 22050;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_32000:
+      return 32000;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_44100:
+      return 44100;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_48000:
+      return 48000;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_64000:
+      return 64000;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_88200:
+      return 88200;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_96000:
+      return 96000;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_176400:
+      return 176400;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_192000:
+      return 192000;
+    case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_384000:
+      return 384000;
+    default:
+      LOG(ERROR) << "Unknown virtio-snd sample rate: " << virtio_rate;
+      return -1;
+  }
+}
+
+}  // namespace
+
+AudioHandler::AudioHandler(
+    std::unique_ptr<AudioServer> audio_server,
+    std::shared_ptr<webrtc_streaming::AudioSink> audio_sink,
+    std::shared_ptr<webrtc_streaming::AudioSource> audio_source)
+    : audio_sink_(audio_sink),
+      audio_server_(std::move(audio_server)),
+      stream_descs_(NUM_STREAMS),
+      audio_source_(audio_source) {}
+
+void AudioHandler::Start() {
+  server_thread_ = std::thread([this]() { Loop(); });
+}
+
+[[noreturn]] void AudioHandler::Loop() {
+  for (;;) {
+    auto audio_client = audio_server_->AcceptClient(
+        NUM_STREAMS, 0 /* num_jacks, */, 0 /* num_chmaps, */,
+        262144 /* tx_shm_len */, 262144 /* rx_shm_len */);
+    CHECK(audio_client) << "Failed to create audio client connection instance";
+
+    std::thread playback_thread([this, &audio_client]() {
+      while (audio_client->ReceivePlayback(*this)) {
+      }
+    });
+    std::thread capture_thread([this, &audio_client]() {
+      while (audio_client->ReceiveCapture(*this)) {
+      }
+    });
+    // Wait for the client to do something
+    while (audio_client->ReceiveCommands(*this)) {
+    }
+    playback_thread.join();
+    capture_thread.join();
+  }
+}
+
+void AudioHandler::StreamsInfo(StreamInfoCommand& cmd) {
+  if (cmd.start_id() >= NUM_STREAMS ||
+      cmd.start_id() + cmd.count() > NUM_STREAMS) {
+    cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG, {});
+    return;
+  }
+  std::vector<virtio_snd_pcm_info> stream_info(
+      &STREAMS[cmd.start_id()], &STREAMS[0] + cmd.start_id() + cmd.count());
+  cmd.Reply(AudioStatus::VIRTIO_SND_S_OK, stream_info);
+}
+
+void AudioHandler::SetStreamParameters(StreamSetParamsCommand& cmd) {
+  if (cmd.stream_id() >= NUM_STREAMS) {
+    cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
+    return;
+  }
+  const auto& stream_info = STREAMS[cmd.stream_id()];
+  auto bits_per_sample = BitsPerSample(cmd.format());
+  auto sample_rate = SampleRate(cmd.rate());
+  auto channels = cmd.channels();
+  if (bits_per_sample < 0 || sample_rate < 0 ||
+      channels < stream_info.channels_min ||
+      channels > stream_info.channels_max) {
+    cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
+    return;
+  }
+  {
+    std::lock_guard<std::mutex> lock(stream_descs_[cmd.stream_id()].mtx);
+    stream_descs_[cmd.stream_id()].bits_per_sample = bits_per_sample;
+    stream_descs_[cmd.stream_id()].sample_rate = sample_rate;
+    stream_descs_[cmd.stream_id()].channels = channels;
+    auto len10ms = (channels * (sample_rate / 100) * bits_per_sample) / 8;
+    stream_descs_[cmd.stream_id()].buffer.Reset(len10ms);
+  }
+  cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
+}
+
+void AudioHandler::PrepareStream(StreamControlCommand& cmd) {
+  if (cmd.stream_id() >= NUM_STREAMS) {
+    cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
+    return;
+  }
+  cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
+}
+
+void AudioHandler::ReleaseStream(StreamControlCommand& cmd) {
+  if (cmd.stream_id() >= NUM_STREAMS) {
+    cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
+    return;
+  }
+  cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
+}
+
+void AudioHandler::StartStream(StreamControlCommand& cmd) {
+  if (cmd.stream_id() >= NUM_STREAMS) {
+    cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
+    return;
+  }
+  stream_descs_[cmd.stream_id()].active = true;
+  cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
+}
+
+void AudioHandler::StopStream(StreamControlCommand& cmd) {
+  if (cmd.stream_id() >= NUM_STREAMS) {
+    cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
+    return;
+  }
+  stream_descs_[cmd.stream_id()].active = false;
+  cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
+}
+
+void AudioHandler::OnPlaybackBuffer(TxBuffer buffer) {
+  auto stream_id = buffer.stream_id();
+  auto& stream_desc = stream_descs_[stream_id];
+  {
+    std::lock_guard<std::mutex> lock(stream_desc.mtx);
+    auto& holding_buffer = stream_descs_[stream_id].buffer;
+    // Invalid or capture streams shouldn't send tx buffers
+    if (stream_id >= NUM_STREAMS || IsCapture(stream_id)) {
+      buffer.SendStatus(AudioStatus::VIRTIO_SND_S_BAD_MSG, 0, 0);
+      return;
+    }
+    // A buffer may be received for an inactive stream if we were slow to
+    // process it and the other side stopped the stream. Quitely ignore it in
+    // that case
+    if (!stream_desc.active) {
+      buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
+      return;
+    }
+    // Webrtc will silently ignore any buffer with a length different than 10ms,
+    // so we must split any buffer bigger than that and temporarily store any
+    // remaining frames that are less than that size.
+    auto current_time = rtc::TimeMillis();
+    // The timestamp of the first 10ms chunk to be sent so that the last one
+    // will have the current time
+    auto base_time =
+        current_time - ((buffer.len() - 1) / holding_buffer.buffer.size()) * 10;
+    // number of frames in a 10 ms buffer
+    const int frames = stream_desc.sample_rate / 100;
+    size_t pos = 0;
+    while (pos < buffer.len()) {
+      if (holding_buffer.empty() &&
+          buffer.len() - pos >= holding_buffer.buffer.size()) {
+        // Avoid the extra copy into holding buffer
+        // This casts away volatility of the pointer, necessary because the
+        // webrtc api doesn't expect volatile memory. This should be safe though
+        // because webrtc will use the contents of the buffer before returning
+        // and only then we release it.
+        auto audio_frame_buffer = std::make_shared<CvdAudioFrameBuffer>(
+            const_cast<const uint8_t*>(&buffer.get()[pos]),
+            stream_desc.bits_per_sample, stream_desc.sample_rate,
+            stream_desc.channels, frames);
+        audio_sink_->OnFrame(audio_frame_buffer, base_time);
+        pos += holding_buffer.buffer.size();
+      } else {
+        pos += holding_buffer.Add(buffer.get() + pos, buffer.len() - pos);
+        if (holding_buffer.full()) {
+          auto buffer_ptr = const_cast<const uint8_t*>(holding_buffer.data());
+          auto audio_frame_buffer = std::make_shared<CvdAudioFrameBuffer>(
+              buffer_ptr, stream_desc.bits_per_sample,
+              stream_desc.sample_rate, stream_desc.channels, frames);
+          audio_sink_->OnFrame(audio_frame_buffer, base_time);
+          holding_buffer.count = 0;
+        }
+      }
+      base_time += 10;
+    }
+  }
+  buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
+}
+
+void AudioHandler::OnCaptureBuffer(RxBuffer buffer) {
+  auto stream_id = buffer.stream_id();
+  auto& stream_desc = stream_descs_[stream_id];
+  {
+    std::lock_guard<std::mutex> lock(stream_desc.mtx);
+    // Invalid or playback streams shouldn't send rx buffers
+    if (stream_id >= NUM_STREAMS || !IsCapture(stream_id)) {
+      LOG(ERROR) << "Received capture buffers on playback stream " << stream_id;
+      buffer.SendStatus(AudioStatus::VIRTIO_SND_S_BAD_MSG, 0, 0);
+      return;
+    }
+    // A buffer may be received for an inactive stream if we were slow to
+    // process it and the other side stopped the stream. Quitely ignore it in
+    // that case
+    if (!stream_desc.active) {
+      buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
+      return;
+    }
+    auto bytes_per_sample = stream_desc.bits_per_sample / 8;
+    auto samples_per_channel =
+        buffer.len() / stream_desc.channels / bytes_per_sample;
+    bool muted = false;
+    auto res = audio_source_->GetMoreAudioData(
+        const_cast<uint8_t*>(buffer.get()), bytes_per_sample,
+        samples_per_channel, stream_desc.channels, stream_desc.sample_rate,
+        muted);
+    if (res < 0) {
+      // This is likely a recoverable error, log the error but don't let the VMM
+      // know about it so that it doesn't crash.
+      LOG(ERROR) << "Failed to receive audio data from client";
+    }
+  }
+  buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
+}
+
+void AudioHandler::HoldingBuffer::Reset(size_t size) {
+  buffer.resize(size);
+  count = 0;
+}
+
+size_t AudioHandler::HoldingBuffer::Add(const volatile uint8_t* data,
+                                        size_t max_len) {
+  auto added_len = std::min(max_len, buffer.size() - count);
+  std::copy(data, data + added_len, &buffer[count]);
+  count += added_len;
+  return added_len;
+}
+
+bool AudioHandler::HoldingBuffer::empty() const { return count == 0; }
+
+bool AudioHandler::HoldingBuffer::full() const {
+  return count == buffer.size();
+}
+
+uint8_t* AudioHandler::HoldingBuffer::data() { return buffer.data(); }
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/audio_handler.h b/host/frontend/webrtc/audio_handler.h
new file mode 100644
index 0000000..3802052
--- /dev/null
+++ b/host/frontend/webrtc/audio_handler.h
@@ -0,0 +1,79 @@
+/*
+ * 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 <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "host/frontend/webrtc/lib/audio_sink.h"
+#include "host/frontend/webrtc/lib/audio_source.h"
+#include "host/libs/audio_connector/server.h"
+
+namespace cuttlefish {
+class AudioHandler : public AudioServerExecutor {
+  // TODO(jemoreira): This can probably be avoided if playback goes through the
+  // audio device instead.
+  struct HoldingBuffer {
+    std::vector<uint8_t> buffer;
+    size_t count;
+
+    void Reset(size_t size);
+    size_t Add(const volatile uint8_t* data, size_t max_len);
+    bool empty() const;
+    bool full() const;
+    uint8_t* data();
+  };
+  struct StreamDesc {
+    std::mutex mtx;
+    int bits_per_sample = -1;
+    int sample_rate = -1;
+    int channels = -1;
+    bool active = false;
+    HoldingBuffer buffer;
+  };
+
+ public:
+  AudioHandler(std::unique_ptr<AudioServer> audio_server,
+               std::shared_ptr<webrtc_streaming::AudioSink> audio_sink,
+               std::shared_ptr<webrtc_streaming::AudioSource> audio_source);
+  ~AudioHandler() override = default;
+
+  void Start();
+
+  // AudioServerExecutor implementation
+  void StreamsInfo(StreamInfoCommand& cmd) override;
+  void SetStreamParameters(StreamSetParamsCommand& cmd) override;
+  void PrepareStream(StreamControlCommand& cmd) override;
+  void ReleaseStream(StreamControlCommand& cmd) override;
+  void StartStream(StreamControlCommand& cmd) override;
+  void StopStream(StreamControlCommand& cmd) override;
+
+  void OnPlaybackBuffer(TxBuffer buffer) override;
+  void OnCaptureBuffer(RxBuffer buffer) override;
+
+ private:
+  [[noreturn]] void Loop();
+
+  std::shared_ptr<webrtc_streaming::AudioSink> audio_sink_;
+  std::unique_ptr<AudioServer> audio_server_;
+  std::thread server_thread_;
+  std::vector<StreamDesc> stream_descs_ = {};
+  std::shared_ptr<webrtc_streaming::AudioSource> audio_source_;
+};
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/bluetooth_handler.cpp b/host/frontend/webrtc/bluetooth_handler.cpp
new file mode 100644
index 0000000..219c36e
--- /dev/null
+++ b/host/frontend/webrtc/bluetooth_handler.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/frontend/webrtc/bluetooth_handler.h"
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+
+using namespace android;
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+BluetoothHandler::BluetoothHandler(
+    const int rootCanalTestPort,
+    std::function<void(const uint8_t *, size_t)> send_to_client)
+    : send_to_client_(send_to_client),
+      rootcanal_socket_(
+          SharedFD::SocketLocalClient(rootCanalTestPort, SOCK_STREAM)),
+      shutdown_(SharedFD::Event(0, 0)) {
+  std::thread loop([this]() { ReadLoop(); });
+  read_thread_.swap(loop);
+}
+
+BluetoothHandler::~BluetoothHandler() {
+  // Send a message to the looper to shut down.
+  uint64_t v = 1;
+  shutdown_->Write(&v, sizeof(v));
+  // Shut down the socket as well.  Not strictly necessary.
+  rootcanal_socket_->Shutdown(SHUT_RDWR);
+  read_thread_.join();
+}
+
+void BluetoothHandler::ReadLoop() {
+  while (1) {
+    uint8_t buffer[4096];
+
+    read_set_.Set(shutdown_);
+    read_set_.Set(rootcanal_socket_);
+    Select(&read_set_, nullptr, nullptr, nullptr);
+
+    if (read_set_.IsSet(rootcanal_socket_)) {
+      auto read = rootcanal_socket_->Read(buffer, sizeof(buffer));
+      if (read < 0) {
+        PLOG(ERROR) << "Error on reading from RootCanal socket.";
+        break;
+      }
+      if (read) {
+        send_to_client_(buffer, read);
+      }
+    }
+
+    if (read_set_.IsSet(shutdown_)) {
+      LOG(INFO) << "BluetoothHandler is shutting down.";
+      break;
+    }
+  }
+}
+
+void BluetoothHandler::handleMessage(const uint8_t *msg, size_t len) {
+  size_t sent = 0;
+  while (sent < len) {
+    auto this_sent = rootcanal_socket_->Write(&msg[sent], len - sent);
+    if (this_sent < 0) {
+      PLOG(FATAL) << "Error writing to rootcanal socket.";
+      return;
+    }
+    sent += this_sent;
+  }
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/bluetooth_handler.h b/host/frontend/webrtc/bluetooth_handler.h
new file mode 100644
index 0000000..72248cf
--- /dev/null
+++ b/host/frontend/webrtc/bluetooth_handler.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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 <memory>
+#include <thread>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/fs/shared_select.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+struct BluetoothHandler {
+  explicit BluetoothHandler(
+      const int rootCanalTestPort,
+      std::function<void(const uint8_t *, size_t)> send_to_client);
+
+  ~BluetoothHandler();
+
+  void handleMessage(const uint8_t *msg, size_t len);
+
+ private:
+  std::function<void(const uint8_t *, size_t)> send_to_client_;
+
+  void ReadLoop();
+
+  SharedFD rootcanal_socket_;
+  SharedFD shutdown_;
+  SharedFDSet read_set_;
+  std::thread read_thread_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/connection_observer.cpp b/host/frontend/webrtc/connection_observer.cpp
new file mode 100644
index 0000000..9f11544
--- /dev/null
+++ b/host/frontend/webrtc/connection_observer.cpp
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ConnectionObserver"
+
+#include "host/frontend/webrtc/connection_observer.h"
+
+#include <linux/input.h>
+
+#include <chrono>
+#include <map>
+#include <set>
+#include <thread>
+#include <vector>
+
+#include <json/json.h>
+
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
+
+#include "common/libs/confui/confui.h"
+#include "common/libs/fs/shared_buf.h"
+#include "host/frontend/webrtc/adb_handler.h"
+#include "host/frontend/webrtc/bluetooth_handler.h"
+#include "host/frontend/webrtc/lib/utils.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+DECLARE_bool(write_virtio_input);
+
+namespace cuttlefish {
+
+// TODO (b/147511234): de-dup this from vnc server and here
+struct virtio_input_event {
+  uint16_t type;
+  uint16_t code;
+  int32_t value;
+};
+
+struct multitouch_slot {
+  int32_t id;
+  int32_t slot;
+  int32_t x;
+  int32_t y;
+};
+
+struct InputEventBuffer {
+  virtual ~InputEventBuffer() = default;
+  virtual void AddEvent(uint16_t type, uint16_t code, int32_t value) = 0;
+  virtual size_t size() const = 0;
+  virtual const void *data() const = 0;
+};
+
+template <typename T>
+struct InputEventBufferImpl : public InputEventBuffer {
+  InputEventBufferImpl() {
+    buffer_.reserve(6);  // 6 is usually enough
+  }
+  void AddEvent(uint16_t type, uint16_t code, int32_t value) override {
+    buffer_.push_back({.type = type, .code = code, .value = value});
+  }
+  T *data() { return buffer_.data(); }
+  const void *data() const override { return buffer_.data(); }
+  std::size_t size() const override { return buffer_.size() * sizeof(T); }
+
+ private:
+  std::vector<T> buffer_;
+};
+
+// TODO: we could add an arg here to specify whether we want the multitouch buffer?
+std::unique_ptr<InputEventBuffer> GetEventBuffer() {
+  if (FLAGS_write_virtio_input) {
+    return std::unique_ptr<InputEventBuffer>(
+        new InputEventBufferImpl<virtio_input_event>());
+  } else {
+    return std::unique_ptr<InputEventBuffer>(
+        new InputEventBufferImpl<input_event>());
+  }
+}
+
+/**
+ * connection observer implementation for regular android mode.
+ * i.e. when it is not in the confirmation UI mode (or TEE),
+ * the control flow will fall back to this ConnectionObserverForAndroid
+ */
+class ConnectionObserverForAndroid
+    : public cuttlefish::webrtc_streaming::ConnectionObserver {
+ public:
+  ConnectionObserverForAndroid(
+      cuttlefish::InputSockets &input_sockets,
+      cuttlefish::KernelLogEventsHandler *kernel_log_events_handler,
+      std::map<std::string, cuttlefish::SharedFD>
+          commands_to_custom_action_servers,
+      std::weak_ptr<DisplayHandler> display_handler)
+      : input_sockets_(input_sockets),
+        kernel_log_events_handler_(kernel_log_events_handler),
+        commands_to_custom_action_servers_(commands_to_custom_action_servers),
+        weak_display_handler_(display_handler) {}
+  virtual ~ConnectionObserverForAndroid() {
+    auto display_handler = weak_display_handler_.lock();
+    if (display_handler) {
+      display_handler->DecClientCount();
+    }
+    if (kernel_log_subscription_id_ != -1) {
+      kernel_log_events_handler_->Unsubscribe(kernel_log_subscription_id_);
+    }
+  }
+
+  void OnConnected(std::function<void(const uint8_t *, size_t, bool)>
+                   /*ctrl_msg_sender*/) override {
+    auto display_handler = weak_display_handler_.lock();
+    if (display_handler) {
+      display_handler->IncClientCount();
+      std::thread th([this]() {
+        // The encoder in libwebrtc won't drop 5 consecutive frames due to frame
+        // size, so we make sure at least 5 frames are sent every time a client
+        // connects to ensure they receive at least one.
+        constexpr int kNumFrames = 5;
+        constexpr int kMillisPerFrame = 16;
+        for (int i = 0; i < kNumFrames; ++i) {
+          auto display_handler = weak_display_handler_.lock();
+          display_handler->SendLastFrame();
+          if (i < kNumFrames - 1) {
+            std::this_thread::sleep_for(std::chrono::milliseconds(kMillisPerFrame));
+          }
+        }
+      });
+      th.detach();
+    }
+    }
+
+  void OnTouchEvent(const std::string & /*display_label*/, int x, int y,
+                    bool down) override {
+
+    auto buffer = GetEventBuffer();
+    if (!buffer) {
+      LOG(ERROR) << "Failed to allocate event buffer";
+      return;
+    }
+    buffer->AddEvent(EV_ABS, ABS_X, x);
+    buffer->AddEvent(EV_ABS, ABS_Y, y);
+    buffer->AddEvent(EV_KEY, BTN_TOUCH, down);
+    buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
+    cuttlefish::WriteAll(input_sockets_.touch_client,
+                         reinterpret_cast<const char *>(buffer->data()),
+                         buffer->size());
+  }
+
+  void OnMultiTouchEvent(const std::string & /*display_label*/, Json::Value id,
+                         Json::Value slot, Json::Value x, Json::Value y,
+                         bool down, int size) override {
+
+    auto buffer = GetEventBuffer();
+    if (!buffer) {
+      LOG(ERROR) << "Failed to allocate event buffer";
+      return;
+    }
+
+    for (int i=0; i<size; i++) {
+      auto this_slot = slot[i].asInt();
+      auto this_id = id[i].asInt();
+      auto this_x = x[i].asInt();
+      auto this_y = y[i].asInt();
+      buffer->AddEvent(EV_ABS, ABS_MT_SLOT, this_slot);
+      if (down) {
+        bool is_new = active_touch_slots_.insert(this_slot).second;
+        if (is_new) {
+          buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, this_id);
+          if (active_touch_slots_.size() == 1) {
+            buffer->AddEvent(EV_KEY, BTN_TOUCH, 1);
+          }
+        }
+        buffer->AddEvent(EV_ABS, ABS_MT_POSITION_X, this_x);
+        buffer->AddEvent(EV_ABS, ABS_MT_POSITION_Y, this_y);
+        // send ABS_X and ABS_Y for single-touch compatibility
+        buffer->AddEvent(EV_ABS, ABS_X, this_x);
+        buffer->AddEvent(EV_ABS, ABS_Y, this_y);
+      } else {
+        // released touch
+        buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, this_id);
+        active_touch_slots_.erase(this_slot);
+        if (active_touch_slots_.empty()) {
+          buffer->AddEvent(EV_KEY, BTN_TOUCH, 0);
+        }
+      }
+    }
+
+    buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
+    cuttlefish::WriteAll(input_sockets_.touch_client,
+                         reinterpret_cast<const char *>(buffer->data()),
+                         buffer->size());
+  }
+
+  void OnKeyboardEvent(uint16_t code, bool down) override {
+    auto buffer = GetEventBuffer();
+    if (!buffer) {
+      LOG(ERROR) << "Failed to allocate event buffer";
+      return;
+    }
+    buffer->AddEvent(EV_KEY, code, down);
+    buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
+    cuttlefish::WriteAll(input_sockets_.keyboard_client,
+                         reinterpret_cast<const char *>(buffer->data()),
+                         buffer->size());
+  }
+
+  void OnSwitchEvent(uint16_t code, bool state) override {
+    auto buffer = GetEventBuffer();
+    if (!buffer) {
+      LOG(ERROR) << "Failed to allocate event buffer";
+      return;
+    }
+    buffer->AddEvent(EV_SW, code, state);
+    buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
+    cuttlefish::WriteAll(input_sockets_.switches_client,
+                         reinterpret_cast<const char *>(buffer->data()),
+                         buffer->size());
+  }
+
+  void OnAdbChannelOpen(std::function<bool(const uint8_t *, size_t)>
+                            adb_message_sender) override {
+    LOG(VERBOSE) << "Adb Channel open";
+    adb_handler_.reset(new cuttlefish::webrtc_streaming::AdbHandler(
+        cuttlefish::CuttlefishConfig::Get()
+            ->ForDefaultInstance()
+            .adb_ip_and_port(),
+        adb_message_sender));
+  }
+  void OnAdbMessage(const uint8_t *msg, size_t size) override {
+    adb_handler_->handleMessage(msg, size);
+  }
+  void OnControlChannelOpen(std::function<bool(const Json::Value)>
+                            control_message_sender) override {
+    LOG(VERBOSE) << "Control Channel open";
+    kernel_log_subscription_id_ =
+        kernel_log_events_handler_->AddSubscriber(control_message_sender);
+  }
+  void OnControlMessage(const uint8_t* msg, size_t size) override {
+    Json::Value evt;
+    const char* msg_str = reinterpret_cast<const char*>(msg);
+    Json::CharReaderBuilder builder;
+    std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
+    std::string errorMessage;
+    if (!json_reader->parse(msg_str, msg_str + size, &evt, &errorMessage)) {
+      LOG(ERROR) << "Received invalid JSON object over control channel: " << errorMessage;
+      return;
+    }
+
+    auto result = webrtc_streaming::ValidationResult::ValidateJsonObject(
+        evt, "command",
+        /*required_fields=*/{{"command", Json::ValueType::stringValue}},
+        /*optional_fields=*/
+        {
+            {"button_state", Json::ValueType::stringValue},
+            {"lid_switch_open", Json::ValueType::booleanValue},
+            {"hinge_angle_value", Json::ValueType::intValue},
+        });
+    if (!result.ok()) {
+      LOG(ERROR) << result.error();
+      return;
+    }
+    auto command = evt["command"].asString();
+
+    if (command == "device_state") {
+      if (evt.isMember("lid_switch_open")) {
+        // InputManagerService treats a value of 0 as open and 1 as closed, so
+        // invert the lid_switch_open value that is sent to the input device.
+        OnSwitchEvent(SW_LID, !evt["lid_switch_open"].asBool());
+      }
+      if (evt.isMember("hinge_angle_value")) {
+        // TODO(b/181157794) Propagate hinge angle sensor data using a custom
+        // Sensor HAL.
+      }
+      return;
+    }
+
+    auto button_state = evt["button_state"].asString();
+    LOG(VERBOSE) << "Control command: " << command << " (" << button_state
+                 << ")";
+    if (command == "power") {
+      OnKeyboardEvent(KEY_POWER, button_state == "down");
+    } else if (command == "home") {
+      OnKeyboardEvent(KEY_HOMEPAGE, button_state == "down");
+    } else if (command == "menu") {
+      OnKeyboardEvent(KEY_MENU, button_state == "down");
+    } else if (command == "volumemute") {
+      OnKeyboardEvent(KEY_MUTE, button_state == "down");
+    } else if (command == "volumedown") {
+      OnKeyboardEvent(KEY_VOLUMEDOWN, button_state == "down");
+    } else if (command == "volumeup") {
+      OnKeyboardEvent(KEY_VOLUMEUP, button_state == "down");
+    } else if (commands_to_custom_action_servers_.find(command) !=
+               commands_to_custom_action_servers_.end()) {
+      // Simple protocol for commands forwarded to action servers:
+      //   - Always 128 bytes
+      //   - Format:   command:button_state
+      //   - Example:  my_button:down
+      std::string action_server_message = command + ":" + button_state;
+      cuttlefish::WriteAll(commands_to_custom_action_servers_[command],
+                           action_server_message.c_str(), 128);
+    } else {
+      LOG(WARNING) << "Unsupported control command: " << command << " ("
+                   << button_state << ")";
+    }
+  }
+
+  void OnBluetoothChannelOpen(std::function<bool(const uint8_t *, size_t)>
+                                  bluetooth_message_sender) override {
+    LOG(VERBOSE) << "Bluetooth channel open";
+    bluetooth_handler_.reset(new cuttlefish::webrtc_streaming::BluetoothHandler(
+        cuttlefish::CuttlefishConfig::Get()
+            ->ForDefaultInstance()
+            .rootcanal_test_port(),
+        bluetooth_message_sender));
+  }
+
+  void OnBluetoothMessage(const uint8_t *msg, size_t size) override {
+    bluetooth_handler_->handleMessage(msg, size);
+  }
+
+ private:
+  cuttlefish::InputSockets& input_sockets_;
+  cuttlefish::KernelLogEventsHandler* kernel_log_events_handler_;
+  int kernel_log_subscription_id_ = -1;
+  std::shared_ptr<cuttlefish::webrtc_streaming::AdbHandler> adb_handler_;
+  std::shared_ptr<cuttlefish::webrtc_streaming::BluetoothHandler>
+      bluetooth_handler_;
+  std::map<std::string, cuttlefish::SharedFD> commands_to_custom_action_servers_;
+  std::weak_ptr<DisplayHandler> weak_display_handler_;
+  std::set<int32_t> active_touch_slots_;
+};
+
+class ConnectionObserverDemuxer
+    : public cuttlefish::webrtc_streaming::ConnectionObserver {
+ public:
+  ConnectionObserverDemuxer(
+      /* params for the base class */
+      cuttlefish::InputSockets &input_sockets,
+      cuttlefish::KernelLogEventsHandler *kernel_log_events_handler,
+      std::map<std::string, cuttlefish::SharedFD>
+          commands_to_custom_action_servers,
+      std::weak_ptr<DisplayHandler> display_handler,
+      /* params for this class */
+      cuttlefish::confui::HostVirtualInput &confui_input)
+      : android_input_(input_sockets, kernel_log_events_handler,
+                       commands_to_custom_action_servers, display_handler),
+        confui_input_{confui_input} {}
+  virtual ~ConnectionObserverDemuxer() = default;
+
+  void OnConnected(std::function<void(const uint8_t *, size_t, bool)>
+                       ctrl_msg_sender) override {
+    android_input_.OnConnected(ctrl_msg_sender);
+  }
+
+  void OnTouchEvent(const std::string &label, int x, int y,
+                    bool down) override {
+    if (confui_input_.IsConfUiActive()) {
+      ConfUiLog(DEBUG) << "touch event ignored in confirmation UI mode";
+      return;
+    }
+    android_input_.OnTouchEvent(label, x, y, down);
+  }
+
+  void OnMultiTouchEvent(const std::string &label, Json::Value id,
+                         Json::Value slot, Json::Value x, Json::Value y,
+                         bool down, int size) override {
+    if (confui_input_.IsConfUiActive()) {
+      ConfUiLog(DEBUG) << "multi-touch event ignored in confirmation UI mode";
+      return;
+    }
+    android_input_.OnMultiTouchEvent(label, id, slot, x, y, down, size);
+  }
+
+  void OnKeyboardEvent(uint16_t code, bool down) override {
+    if (confui_input_.IsConfUiActive()) {
+      switch (code) {
+        case KEY_POWER:
+          confui_input_.PressConfirmButton(down);
+          break;
+        case KEY_MENU:
+          confui_input_.PressCancelButton(down);
+          break;
+        default:
+          ConfUiLog(DEBUG) << "key" << code
+                           << "is ignored in confirmation UI mode";
+          break;
+      }
+      return;
+    }
+    android_input_.OnKeyboardEvent(code, down);
+  }
+
+  void OnSwitchEvent(uint16_t code, bool state) override {
+    android_input_.OnSwitchEvent(code, state);
+  }
+
+  void OnAdbChannelOpen(std::function<bool(const uint8_t *, size_t)>
+                            adb_message_sender) override {
+    android_input_.OnAdbChannelOpen(adb_message_sender);
+  }
+
+  void OnAdbMessage(const uint8_t *msg, size_t size) override {
+    android_input_.OnAdbMessage(msg, size);
+  }
+
+  void OnControlChannelOpen(
+      std::function<bool(const Json::Value)> control_message_sender) override {
+    android_input_.OnControlChannelOpen(control_message_sender);
+  }
+
+  void OnControlMessage(const uint8_t *msg, size_t size) override {
+    android_input_.OnControlMessage(msg, size);
+  }
+
+  void OnBluetoothChannelOpen(std::function<bool(const uint8_t *, size_t)>
+                                  bluetooth_message_sender) override {
+    android_input_.OnBluetoothChannelOpen(bluetooth_message_sender);
+  }
+
+  void OnBluetoothMessage(const uint8_t *msg, size_t size) override {
+    android_input_.OnBluetoothMessage(msg, size);
+  }
+
+ private:
+  ConnectionObserverForAndroid android_input_;
+  cuttlefish::confui::HostVirtualInput &confui_input_;
+};
+
+CfConnectionObserverFactory::CfConnectionObserverFactory(
+    cuttlefish::InputSockets &input_sockets,
+    cuttlefish::KernelLogEventsHandler* kernel_log_events_handler,
+    cuttlefish::confui::HostVirtualInput &confui_input)
+    : input_sockets_(input_sockets),
+      kernel_log_events_handler_(kernel_log_events_handler),
+      confui_input_{confui_input} {}
+
+std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>
+CfConnectionObserverFactory::CreateObserver() {
+  return std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>(
+      new ConnectionObserverDemuxer(input_sockets_, kernel_log_events_handler_,
+                                    commands_to_custom_action_servers_,
+                                    weak_display_handler_, confui_input_));
+}
+
+void CfConnectionObserverFactory::AddCustomActionServer(
+    cuttlefish::SharedFD custom_action_server_fd,
+    const std::vector<std::string>& commands) {
+  for (const std::string& command : commands) {
+    LOG(DEBUG) << "Action server is listening to command: " << command;
+    commands_to_custom_action_servers_[command] = custom_action_server_fd;
+  }
+}
+
+void CfConnectionObserverFactory::SetDisplayHandler(
+    std::weak_ptr<DisplayHandler> display_handler) {
+  weak_display_handler_ = display_handler;
+}
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/connection_observer.h b/host/frontend/webrtc/connection_observer.h
new file mode 100644
index 0000000..abf1884
--- /dev/null
+++ b/host/frontend/webrtc/connection_observer.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <map>
+#include <memory>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/frontend/webrtc/display_handler.h"
+#include "host/frontend/webrtc/kernel_log_events_handler.h"
+#include "host/frontend/webrtc/lib/connection_observer.h"
+#include "host/libs/confui/host_virtual_input.h"
+
+namespace cuttlefish {
+
+struct InputSockets {
+  SharedFD touch_server;
+  SharedFD touch_client;
+  SharedFD keyboard_server;
+  SharedFD keyboard_client;
+  SharedFD switches_server;
+  SharedFD switches_client;
+};
+
+class CfConnectionObserverFactory
+    : public webrtc_streaming::ConnectionObserverFactory {
+ public:
+  CfConnectionObserverFactory(
+      cuttlefish::InputSockets& input_sockets,
+      KernelLogEventsHandler* kernel_log_events_handler,
+      cuttlefish::confui::HostVirtualInput& confui_input);
+  ~CfConnectionObserverFactory() override = default;
+
+  std::shared_ptr<webrtc_streaming::ConnectionObserver> CreateObserver()
+      override;
+
+  void AddCustomActionServer(SharedFD custom_action_server_fd,
+                             const std::vector<std::string>& commands);
+
+  void SetDisplayHandler(std::weak_ptr<DisplayHandler> display_handler);
+
+ private:
+  InputSockets& input_sockets_;
+  KernelLogEventsHandler* kernel_log_events_handler_;
+  std::map<std::string, SharedFD>
+      commands_to_custom_action_servers_;
+  std::weak_ptr<DisplayHandler> weak_display_handler_;
+  cuttlefish::confui::HostVirtualInput& confui_input_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/cvd_video_frame_buffer.cpp b/host/frontend/webrtc/cvd_video_frame_buffer.cpp
new file mode 100644
index 0000000..8d0aeea
--- /dev/null
+++ b/host/frontend/webrtc/cvd_video_frame_buffer.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/cvd_video_frame_buffer.h"
+
+#include <map>
+#include <mutex>
+#include <vector>
+#include "common/libs/utils/size_utils.h"
+
+namespace cuttlefish {
+
+namespace {
+constexpr int kPlanePadding = 1024;
+constexpr int kLogAlignment = 6;  // multiple of 2^6
+
+inline int AlignStride(int width) {
+  return AlignToPowerOf2(width, kLogAlignment);
+}
+
+std::multimap<int, std::vector<uint8_t>> pool;
+std::mutex pool_mutex;
+std::vector<uint8_t> FromPool(int size) {
+  {
+    std::lock_guard<std::mutex> lock(pool_mutex);
+    auto it = pool.find(size);
+    if (it != pool.end()) {
+      auto ret = std::move(it->second);
+      pool.erase(it);
+      return ret;
+    }
+  }
+  return std::vector<uint8_t>(size);
+}
+
+void BackToPool(std::vector<uint8_t> item) {
+  std::lock_guard<std::mutex> lock(pool_mutex);
+  pool.insert({item.size(), std::move(item)});
+}
+
+}  // namespace
+
+CvdVideoFrameBuffer::CvdVideoFrameBuffer(int width, int height)
+    : width_(width),
+      height_(height),
+      y_(FromPool(AlignStride(width) * height + kPlanePadding)),
+      u_(FromPool(AlignStride((width + 1) / 2) * ((height + 1) / 2) +
+                  kPlanePadding)),
+      v_(FromPool(AlignStride((width + 1) / 2) * ((height + 1) / 2) +
+                  kPlanePadding)) {}
+
+CvdVideoFrameBuffer::~CvdVideoFrameBuffer() {
+  BackToPool(std::move(y_));
+  BackToPool(std::move(u_));
+  BackToPool(std::move(v_));
+}
+
+int CvdVideoFrameBuffer::width() const { return width_; }
+int CvdVideoFrameBuffer::height() const { return height_; }
+
+int CvdVideoFrameBuffer::StrideY() const { return AlignStride(width_); }
+int CvdVideoFrameBuffer::StrideU() const {
+  return AlignStride((width_ + 1) / 2);
+}
+int CvdVideoFrameBuffer::StrideV() const {
+  return AlignStride((width_ + 1) / 2);
+}
+
+const uint8_t *CvdVideoFrameBuffer::DataY() const { return y_.data(); }
+const uint8_t *CvdVideoFrameBuffer::DataU() const { return u_.data(); }
+const uint8_t *CvdVideoFrameBuffer::DataV() const { return v_.data(); }
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/cvd_video_frame_buffer.h b/host/frontend/webrtc/cvd_video_frame_buffer.h
new file mode 100644
index 0000000..84b4946
--- /dev/null
+++ b/host/frontend/webrtc/cvd_video_frame_buffer.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <vector>
+
+#include "host/frontend/webrtc/lib/video_frame_buffer.h"
+
+namespace cuttlefish {
+
+class CvdVideoFrameBuffer : public webrtc_streaming::VideoFrameBuffer {
+ public:
+  CvdVideoFrameBuffer(int width, int height);
+  CvdVideoFrameBuffer(CvdVideoFrameBuffer&& cvd_frame_buf) = default;
+  CvdVideoFrameBuffer(const CvdVideoFrameBuffer& cvd_frame_buf) = default;
+  CvdVideoFrameBuffer& operator=(CvdVideoFrameBuffer&& cvd_frame_buf) = default;
+  CvdVideoFrameBuffer& operator=(const CvdVideoFrameBuffer& cvd_frame_buf) = default;
+  CvdVideoFrameBuffer() = delete;
+
+  ~CvdVideoFrameBuffer() override;
+
+  int width() const override;
+  int height() const override;
+
+  int StrideY() const override;
+  int StrideU() const override;
+  int StrideV() const override;
+
+  const uint8_t *DataY() const override;
+  const uint8_t *DataU() const override;
+  const uint8_t *DataV() const override;
+
+  uint8_t *DataY() { return y_.data(); }
+  uint8_t *DataU() { return u_.data(); }
+  uint8_t *DataV() { return v_.data(); }
+
+ private:
+  const int width_;
+  const int height_;
+  std::vector<std::uint8_t> y_;
+  std::vector<std::uint8_t> u_;
+  std::vector<std::uint8_t> v_;
+};
+
+}
diff --git a/host/frontend/webrtc/display_handler.cpp b/host/frontend/webrtc/display_handler.cpp
new file mode 100644
index 0000000..1b3bfd8
--- /dev/null
+++ b/host/frontend/webrtc/display_handler.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/display_handler.h"
+
+#include <chrono>
+#include <functional>
+#include <memory>
+
+#include <libyuv.h>
+
+namespace cuttlefish {
+DisplayHandler::DisplayHandler(
+    std::shared_ptr<webrtc_streaming::VideoSink> display_sink,
+    ScreenConnector& screen_connector)
+    : display_sink_(display_sink), screen_connector_(screen_connector) {
+  screen_connector_.SetCallback(std::move(GetScreenConnectorCallback()));
+}
+
+DisplayHandler::GenerateProcessedFrameCallback DisplayHandler::GetScreenConnectorCallback() {
+    // only to tell the producer how to create a ProcessedFrame to cache into the queue
+    DisplayHandler::GenerateProcessedFrameCallback callback =
+        [](std::uint32_t display_number, std::uint8_t* frame_pixels,
+           WebRtcScProcessedFrame& processed_frame) {
+          processed_frame.display_number_ = display_number;
+          // TODO(171305898): handle multiple displays.
+          if (display_number != 0) {
+            // BUG 186580833: display_number comes from surface_id in crosvm
+            // create_surface from virtio_gpu.rs set_scanout.  We cannot use it as
+            // the display number. Either crosvm virtio-gpu is incorrectly ignoring
+            // scanout id and instead using a monotonically increasing surface id
+            // number as the scanout resource is replaced over time, or frontend code
+            // here is incorrectly assuming  surface id == display id.
+            display_number = 0;
+          }
+          const int display_w =
+              ScreenConnectorInfo::ScreenWidth(display_number);
+          const int display_h =
+              ScreenConnectorInfo::ScreenHeight(display_number);
+          const int display_stride_bytes =
+              ScreenConnectorInfo::ScreenStrideBytes(display_number);
+          processed_frame.display_number_ = display_number;
+          processed_frame.buf_ =
+              std::make_unique<CvdVideoFrameBuffer>(display_w, display_h);
+          libyuv::ABGRToI420(
+              frame_pixels, display_stride_bytes, processed_frame.buf_->DataY(),
+              processed_frame.buf_->StrideY(), processed_frame.buf_->DataU(),
+              processed_frame.buf_->StrideU(), processed_frame.buf_->DataV(),
+              processed_frame.buf_->StrideV(), display_w, display_h);
+          processed_frame.is_success_ = true;
+        };
+    return callback;
+}
+
+[[noreturn]] void DisplayHandler::Loop() {
+  for (;;) {
+    auto processed_frame = screen_connector_.OnNextFrame();
+    // processed_frame has display number from the guest
+    {
+      std::lock_guard<std::mutex> lock(last_buffer_mutex_);
+      std::shared_ptr<CvdVideoFrameBuffer> buffer = std::move(processed_frame.buf_);
+      last_buffer_ =
+          std::static_pointer_cast<webrtc_streaming::VideoFrameBuffer>(buffer);
+    }
+    if (processed_frame.is_success_) {
+      SendLastFrame();
+    }
+  }
+}
+
+void DisplayHandler::SendLastFrame() {
+  std::shared_ptr<webrtc_streaming::VideoFrameBuffer> buffer;
+  {
+    std::lock_guard<std::mutex> lock(last_buffer_mutex_);
+    buffer = last_buffer_;
+  }
+  if (!buffer) {
+    // If a connection request arrives before the first frame is available don't
+    // send any frame.
+    return;
+  }
+  {
+    // SendLastFrame can be called from multiple threads simultaneously, locking
+    // here avoids injecting frames with the timestamps in the wrong order.
+    std::lock_guard<std::mutex> lock(next_frame_mutex_);
+    int64_t time_stamp =
+        std::chrono::duration_cast<std::chrono::microseconds>(
+            std::chrono::system_clock::now().time_since_epoch())
+            .count();
+    display_sink_->OnFrame(buffer, time_stamp);
+  }
+}
+
+void DisplayHandler::IncClientCount() {
+  client_count_++;
+  if (client_count_ == 1) {
+    screen_connector_.ReportClientsConnected(true);
+  }
+}
+
+void DisplayHandler::DecClientCount() {
+  client_count_--;
+  if (client_count_ == 0) {
+    screen_connector_.ReportClientsConnected(false);
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/display_handler.h b/host/frontend/webrtc/display_handler.h
new file mode 100644
index 0000000..aed38a1
--- /dev/null
+++ b/host/frontend/webrtc/display_handler.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <mutex>
+#include <memory>
+
+#include "host/frontend/webrtc/cvd_video_frame_buffer.h"
+#include "host/frontend/webrtc/lib/video_sink.h"
+#include "host/libs/screen_connector/screen_connector.h"
+
+namespace cuttlefish {
+/**
+ * ScreenConnectorImpl will generate this, and enqueue
+ *
+ * It's basically a (processed) frame, so it:
+ *   must be efficiently std::move-able
+ * Also, for the sake of algorithm simplicity:
+ *   must be default-constructable & assignable
+ *
+ */
+struct WebRtcScProcessedFrame : public ScreenConnectorFrameInfo {
+  // must support move semantic
+  std::unique_ptr<CvdVideoFrameBuffer> buf_;
+  std::unique_ptr<WebRtcScProcessedFrame> Clone() {
+    // copy internal buffer, not move
+    CvdVideoFrameBuffer* new_buffer = new CvdVideoFrameBuffer(*(buf_.get()));
+    auto cloned_frame = std::make_unique<WebRtcScProcessedFrame>();
+    cloned_frame->buf_ =
+        std::move(std::unique_ptr<CvdVideoFrameBuffer>(new_buffer));
+    return std::move(cloned_frame);
+  }
+};
+
+class DisplayHandler {
+ public:
+  using ScreenConnector = cuttlefish::ScreenConnector<WebRtcScProcessedFrame>;
+  using GenerateProcessedFrameCallback = ScreenConnector::GenerateProcessedFrameCallback;
+
+  DisplayHandler(std::shared_ptr<webrtc_streaming::VideoSink> display_sink,
+                 ScreenConnector& screen_connector);
+  ~DisplayHandler() = default;
+
+  [[noreturn]] void Loop();
+  void SendLastFrame();
+
+  void IncClientCount();
+  void DecClientCount();
+
+ private:
+  GenerateProcessedFrameCallback GetScreenConnectorCallback();
+  std::shared_ptr<webrtc_streaming::VideoSink> display_sink_;
+  ScreenConnector& screen_connector_;
+  std::shared_ptr<webrtc_streaming::VideoFrameBuffer> last_buffer_;
+  std::mutex last_buffer_mutex_;
+  std::mutex next_frame_mutex_;
+  int client_count_ = 0;
+};
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/kernel_log_events_handler.cpp b/host/frontend/webrtc/kernel_log_events_handler.cpp
new file mode 100644
index 0000000..ca14e6f
--- /dev/null
+++ b/host/frontend/webrtc/kernel_log_events_handler.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/kernel_log_events_handler.h"
+
+#include <android-base/logging.h>
+
+#include <common/libs/fs/shared_select.h>
+#include <host/commands/kernel_log_monitor/kernel_log_server.h>
+#include <host/commands/kernel_log_monitor/utils.h>
+#include <host/libs/config/cuttlefish_config.h>
+
+using namespace android;
+
+namespace cuttlefish {
+
+KernelLogEventsHandler::KernelLogEventsHandler(
+    SharedFD kernel_log_fd)
+    : kernel_log_fd_(kernel_log_fd),
+      eventfd_(SharedFD::Event()),
+      running_(true),
+      read_thread_([this]() { ReadLoop(); }) {}
+
+KernelLogEventsHandler::~KernelLogEventsHandler() {
+  running_ = false;
+  eventfd_->EventfdWrite(1);
+  read_thread_.join();
+}
+
+void KernelLogEventsHandler::ReadLoop() {
+  CHECK(eventfd_->IsOpen()) << "Failed to create event fd: "
+                           << eventfd_->StrError();
+  while (running_) {
+    SharedFDSet read_set;
+    read_set.Set(eventfd_);
+    read_set.Set(kernel_log_fd_);
+    auto select_ret = Select(&read_set, nullptr, nullptr, nullptr);
+    if (select_ret < 0) {
+      LOG(ERROR) << "Error on select call";
+      break;
+    }
+    if (read_set.IsSet(eventfd_)) {
+      eventfd_t evt;
+      (void)eventfd_->EventfdRead(&evt);
+      if (!running_) {
+        // There won't be anyone listening for kernel log events if the thread
+        // was asked to stop, so break out of the loop without reading.
+        break;
+      }
+    }
+    if (read_set.IsSet(kernel_log_fd_)) {
+      std::optional<monitor::ReadEventResult> read_result =
+          monitor::ReadEvent(kernel_log_fd_);
+      if (!read_result) {
+        LOG(ERROR) << "Failed to read kernel log event: "
+                   << kernel_log_fd_->StrError();
+        break;
+      }
+
+      if (read_result->event == monitor::Event::BootStarted) {
+        Json::Value message;
+        message["event"] = kBootStartedMessage;
+        DeliverEvent(message);
+      }
+      if (read_result->event == monitor::Event::BootCompleted) {
+        Json::Value message;
+        message["event"] = kBootCompletedMessage;
+        DeliverEvent(message);
+      }
+      if (read_result->event == monitor::Event::ScreenChanged) {
+        Json::Value message;
+        message["event"] = kScreenChangedMessage;
+        message["metadata"] = read_result->metadata;
+        DeliverEvent(message);
+      }
+    }
+  }
+}
+
+int KernelLogEventsHandler::AddSubscriber(
+    std::function<void(const Json::Value&)> subscriber) {
+  std::lock_guard<std::mutex> lock(subscribers_mtx_);
+  subscribers_[++last_subscriber_id_] = subscriber;
+  return last_subscriber_id_;
+}
+
+void KernelLogEventsHandler::Unsubscribe(int subscriber_id) {
+  std::lock_guard<std::mutex> lock(subscribers_mtx_);
+  subscribers_.erase(subscriber_id);
+}
+
+void KernelLogEventsHandler::DeliverEvent(const Json::Value& event) {
+  std::lock_guard<std::mutex> lock(subscribers_mtx_);
+  for (const auto& entry : subscribers_) {
+    entry.second(event);
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/kernel_log_events_handler.h b/host/frontend/webrtc/kernel_log_events_handler.h
new file mode 100644
index 0000000..5ce99aa
--- /dev/null
+++ b/host/frontend/webrtc/kernel_log_events_handler.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 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 <atomic>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <map>
+
+#include <json/json.h>
+
+#include "common/libs/fs/shared_fd.h"
+
+namespace cuttlefish {
+
+// Listen to kernel log events and report them to clients.
+struct KernelLogEventsHandler {
+  explicit KernelLogEventsHandler(SharedFD kernel_log_fd);
+
+  ~KernelLogEventsHandler();
+
+  int AddSubscriber(std::function<void(const Json::Value&)> subscriber);
+  void Unsubscribe(int subscriber_id);
+ private:
+  void ReadLoop();
+  void DeliverEvent(const Json::Value& event);
+
+  SharedFD kernel_log_fd_;
+  SharedFD eventfd_;
+  std::atomic<bool> running_;
+  std::thread read_thread_;
+  std::map<int, std::function<void(const Json::Value&)>> subscribers_;
+  int last_subscriber_id_ = 0;
+  std::mutex subscribers_mtx_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/audio_device.cpp b/host/frontend/webrtc/lib/audio_device.cpp
new file mode 100644
index 0000000..2d96f72
--- /dev/null
+++ b/host/frontend/webrtc/lib/audio_device.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/frontend/webrtc/lib/audio_device.h"
+
+#include <string.h>
+
+#include <android-base/logging.h>
+
+#include <chrono>
+#include <thread>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+CfAudioDeviceModule::CfAudioDeviceModule() {}
+
+int CfAudioDeviceModule::GetMoreAudioData(void* data, int bytes_per_sample,
+                                          int samples_per_channel,
+                                          int num_channels, int sample_rate,
+                                          bool& muted) {
+  muted = !playing_ || !audio_callback_;
+  if (muted) {
+    return 0;
+  }
+
+  size_t read_samples;
+  int64_t elapsed_time;
+  int64_t ntp_time_ms;
+  auto res = audio_callback_->NeedMorePlayData(
+      samples_per_channel, bytes_per_sample, num_channels, sample_rate, data,
+      read_samples, &elapsed_time, &ntp_time_ms);
+  if (res != 0) {
+    return res;
+  }
+  return read_samples / num_channels;
+}
+
+// Retrieve the currently utilized audio layer
+int32_t CfAudioDeviceModule::ActiveAudioLayer(AudioLayer* audioLayer) const {
+  return -1;
+}
+
+// Full-duplex transportation of PCM audio
+int32_t CfAudioDeviceModule::RegisterAudioCallback(
+    webrtc::AudioTransport* audio_callback) {
+  audio_callback_ = audio_callback;
+  return 0;
+}
+
+// Main initialization and termination
+int32_t CfAudioDeviceModule::Init() { return 0; }
+int32_t CfAudioDeviceModule::Terminate() { return 0; }
+bool CfAudioDeviceModule::Initialized() const { return true; }
+
+// Device enumeration
+int16_t CfAudioDeviceModule::PlayoutDevices() { return 1; }
+int16_t CfAudioDeviceModule::RecordingDevices() { return 1; }
+int32_t CfAudioDeviceModule::PlayoutDeviceName(
+    uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize],
+    char guid[webrtc::kAdmMaxGuidSize]) {
+  if (index != 0) {
+    return -1;
+  }
+  constexpr auto device_name = "Cuttlefish Webrtc Audio";
+  constexpr auto device_guid = "Cuttlefish Webrtc Audio Device Id";
+  strncpy(name, device_name, webrtc::kAdmMaxDeviceNameSize);
+  name[webrtc::kAdmMaxDeviceNameSize - 1] = '\0';
+  strncpy(guid, device_guid, webrtc::kAdmMaxGuidSize);
+  guid[webrtc::kAdmMaxGuidSize - 1] = '\0';
+  return 0;
+}
+int32_t CfAudioDeviceModule::RecordingDeviceName(
+    uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize],
+    char guid[webrtc::kAdmMaxGuidSize]) {
+  if (index != 0) {
+    return -1;
+  }
+  constexpr auto device_name = "Cuttlefish Webrtc Audio";
+  constexpr auto device_guid = "Cuttlefish Webrtc Audio Device Id";
+  strncpy(name, device_name, webrtc::kAdmMaxDeviceNameSize);
+  name[webrtc::kAdmMaxDeviceNameSize - 1] = '\0';
+  strncpy(guid, device_guid, webrtc::kAdmMaxGuidSize);
+  guid[webrtc::kAdmMaxGuidSize - 1] = '\0';
+  return 0;
+}
+
+// Device selection
+int32_t CfAudioDeviceModule::SetPlayoutDevice(uint16_t index) { return 0; }
+int32_t CfAudioDeviceModule::SetPlayoutDevice(WindowsDeviceType device) {
+  return -1;
+}
+int32_t CfAudioDeviceModule::SetRecordingDevice(uint16_t index) { return 0; }
+int32_t CfAudioDeviceModule::SetRecordingDevice(WindowsDeviceType device) {
+  return -1;
+}
+
+// Audio transport initialization
+int32_t CfAudioDeviceModule::PlayoutIsAvailable(bool* available) {
+  *available = true;
+  return 0;
+}
+int32_t CfAudioDeviceModule::InitPlayout() { return 0; }
+bool CfAudioDeviceModule::PlayoutIsInitialized() const { return true; }
+int32_t CfAudioDeviceModule::RecordingIsAvailable(bool* available) {
+  *available = 0;
+  return 0;
+}
+int32_t CfAudioDeviceModule::InitRecording() { return 0; }
+bool CfAudioDeviceModule::RecordingIsInitialized() const { return true; }
+
+// Audio transport control
+int32_t CfAudioDeviceModule::StartPlayout() {
+  playing_ = true;
+  return 0;
+}
+int32_t CfAudioDeviceModule::StopPlayout() {
+  playing_ = false;
+  return 0;
+}
+bool CfAudioDeviceModule::Playing() const { return playing_; }
+int32_t CfAudioDeviceModule::StartRecording() {
+  recording_ = true;
+  return 0;
+}
+int32_t CfAudioDeviceModule::StopRecording() {
+  recording_ = false;
+  return 0;
+}
+bool CfAudioDeviceModule::Recording() const { return recording_; }
+
+// Audio mixer initialization
+int32_t CfAudioDeviceModule::InitSpeaker() { return -1; }
+bool CfAudioDeviceModule::SpeakerIsInitialized() const { return false; }
+int32_t CfAudioDeviceModule::InitMicrophone() { return 0; }
+bool CfAudioDeviceModule::MicrophoneIsInitialized() const { return true; }
+
+// Speaker volume controls
+int32_t CfAudioDeviceModule::SpeakerVolumeIsAvailable(bool* available) {
+  *available = false;
+  return 0;
+}
+int32_t CfAudioDeviceModule::SetSpeakerVolume(uint32_t volume) { return -1; }
+int32_t CfAudioDeviceModule::SpeakerVolume(uint32_t* volume) const {
+  return -1;
+}
+int32_t CfAudioDeviceModule::MaxSpeakerVolume(uint32_t* maxVolume) const {
+  return -1;
+}
+int32_t CfAudioDeviceModule::MinSpeakerVolume(uint32_t* minVolume) const {
+  return -1;
+}
+
+// Microphone volume controls
+int32_t CfAudioDeviceModule::MicrophoneVolumeIsAvailable(bool* available) {
+  *available = false;
+  return 0;
+}
+int32_t CfAudioDeviceModule::SetMicrophoneVolume(uint32_t volume) { return -1; }
+int32_t CfAudioDeviceModule::MicrophoneVolume(uint32_t* volume) const {
+  return -1;
+}
+int32_t CfAudioDeviceModule::MaxMicrophoneVolume(uint32_t* maxVolume) const {
+  return -1;
+}
+int32_t CfAudioDeviceModule::MinMicrophoneVolume(uint32_t* minVolume) const {
+  return -1;
+}
+
+// Speaker mute control
+int32_t CfAudioDeviceModule::SpeakerMuteIsAvailable(bool* available) {
+  *available = false;
+  return 0;
+}
+int32_t CfAudioDeviceModule::SetSpeakerMute(bool enable) { return -1; }
+int32_t CfAudioDeviceModule::SpeakerMute(bool* enabled) const { return -1; }
+
+// Microphone mute control
+int32_t CfAudioDeviceModule::MicrophoneMuteIsAvailable(bool* available) {
+  *available = false;
+  return 0;
+}
+int32_t CfAudioDeviceModule::SetMicrophoneMute(bool enable) { return -1; }
+int32_t CfAudioDeviceModule::MicrophoneMute(bool* enabled) const { return -1; }
+
+// Stereo support
+int32_t CfAudioDeviceModule::StereoPlayoutIsAvailable(bool* available) const {
+  *available = true;
+  return 0;
+}
+int32_t CfAudioDeviceModule::SetStereoPlayout(bool enable) {
+  stereo_playout_enabled_ = enable;
+  return 0;
+}
+int32_t CfAudioDeviceModule::StereoPlayout(bool* enabled) const {
+  *enabled = stereo_playout_enabled_;
+  return 0;
+}
+int32_t CfAudioDeviceModule::StereoRecordingIsAvailable(bool* available) const {
+  *available = true;
+  return 0;
+}
+int32_t CfAudioDeviceModule::SetStereoRecording(bool enable) {
+  stereo_recording_enabled_ = enable;
+  return 0;
+}
+int32_t CfAudioDeviceModule::StereoRecording(bool* enabled) const {
+  *enabled = stereo_recording_enabled_;
+  return 0;
+}
+
+// Playout delay
+int32_t CfAudioDeviceModule::PlayoutDelay(uint16_t* delayMS) const {
+  // There is currently no way to estimate the real delay for thiese streams.
+  // Given that 10ms buffers are used almost everywhere in the pipeline we know
+  // the delay is at least 10ms, so that's the best guess here.
+  *delayMS = 10;
+  return 0;
+}
+
+// Only supported on Android.
+bool CfAudioDeviceModule::BuiltInAECIsAvailable() const { return false; }
+bool CfAudioDeviceModule::BuiltInAGCIsAvailable() const { return false; }
+bool CfAudioDeviceModule::BuiltInNSIsAvailable() const { return false; }
+
+// Enables the built-in audio effects. Only supported on Android.
+int32_t CfAudioDeviceModule::EnableBuiltInAEC(bool enable) { return -1; }
+int32_t CfAudioDeviceModule::EnableBuiltInAGC(bool enable) { return -1; }
+int32_t CfAudioDeviceModule::EnableBuiltInNS(bool enable) { return -1; }
+
+int32_t CfAudioDeviceModule::GetPlayoutUnderrunCount() const { return -1; }
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/audio_device.h b/host/frontend/webrtc/lib/audio_device.h
new file mode 100644
index 0000000..9b675ee
--- /dev/null
+++ b/host/frontend/webrtc/lib/audio_device.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2021 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 <modules/audio_device/include/audio_device.h>
+
+#include <atomic>
+
+#include "host/frontend/webrtc/lib/audio_source.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class CfAudioDeviceModule : public webrtc::AudioDeviceModule,
+                            public AudioSource {
+ public:
+  CfAudioDeviceModule();
+  ~CfAudioDeviceModule() override = default;
+
+  // Returns number of frames if there is data available, 0 if the stream is not
+  // playing (no clients or the streams are muted), -1 on error.
+  int GetMoreAudioData(void* data, int bytes_per_samples, int samples_per_channel,
+                       int num_channels, int sample_rate, bool& muted) override;
+
+  // Retrieve the currently utilized audio layer
+  int32_t ActiveAudioLayer(AudioLayer* audioLayer) const override;
+
+  // Full-duplex transportation of PCM audio
+  int32_t RegisterAudioCallback(webrtc::AudioTransport* audioCallback) override;
+
+  // Main initialization and termination
+  int32_t Init() override;
+  int32_t Terminate() override;
+  bool Initialized() const override;
+
+  // Device enumeration
+  int16_t PlayoutDevices() override;
+  int16_t RecordingDevices() override;
+  int32_t PlayoutDeviceName(uint16_t index,
+                            char name[webrtc::kAdmMaxDeviceNameSize],
+                            char guid[webrtc::kAdmMaxGuidSize]) override;
+  int32_t RecordingDeviceName(uint16_t index,
+                              char name[webrtc::kAdmMaxDeviceNameSize],
+                              char guid[webrtc::kAdmMaxGuidSize]) override;
+
+  // Device selection
+  int32_t SetPlayoutDevice(uint16_t index) override;
+  int32_t SetPlayoutDevice(WindowsDeviceType device) override;
+  int32_t SetRecordingDevice(uint16_t index) override;
+  int32_t SetRecordingDevice(WindowsDeviceType device) override;
+
+  // Audio transport initialization
+  int32_t PlayoutIsAvailable(bool* available) override;
+  int32_t InitPlayout() override;
+  bool PlayoutIsInitialized() const override;
+  int32_t RecordingIsAvailable(bool* available) override;
+  int32_t InitRecording() override;
+  bool RecordingIsInitialized() const override;
+
+  // Audio transport control
+  int32_t StartPlayout() override;
+  int32_t StopPlayout() override;
+  bool Playing() const override;
+  int32_t StartRecording() override;
+  int32_t StopRecording() override;
+  bool Recording() const override;
+
+  // Audio mixer initialization
+  int32_t InitSpeaker() override;
+  bool SpeakerIsInitialized() const override;
+  int32_t InitMicrophone() override;
+  bool MicrophoneIsInitialized() const override;
+
+  // Speaker volume controls
+  int32_t SpeakerVolumeIsAvailable(bool* available) override;
+  int32_t SetSpeakerVolume(uint32_t volume) override;
+  int32_t SpeakerVolume(uint32_t* volume) const override;
+  int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override;
+  int32_t MinSpeakerVolume(uint32_t* minVolume) const override;
+
+  // Microphone volume controls
+  int32_t MicrophoneVolumeIsAvailable(bool* available) override;
+  int32_t SetMicrophoneVolume(uint32_t volume) override;
+  int32_t MicrophoneVolume(uint32_t* volume) const override;
+  int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override;
+  int32_t MinMicrophoneVolume(uint32_t* minVolume) const override;
+
+  // Speaker mute control
+  int32_t SpeakerMuteIsAvailable(bool* available) override;
+  int32_t SetSpeakerMute(bool enable) override;
+  int32_t SpeakerMute(bool* enabled) const override;
+
+  // Microphone mute control
+  int32_t MicrophoneMuteIsAvailable(bool* available) override;
+  int32_t SetMicrophoneMute(bool enable) override;
+  int32_t MicrophoneMute(bool* enabled) const override;
+
+  // Stereo support
+  int32_t StereoPlayoutIsAvailable(bool* available) const override;
+  int32_t SetStereoPlayout(bool enable) override;
+  int32_t StereoPlayout(bool* enabled) const override;
+  int32_t StereoRecordingIsAvailable(bool* available) const override;
+  int32_t SetStereoRecording(bool enable) override;
+  int32_t StereoRecording(bool* enabled) const override;
+
+  // Playout delay
+  int32_t PlayoutDelay(uint16_t* delayMS) const override;
+
+  // Only supported on Android.
+  bool BuiltInAECIsAvailable() const override;
+  bool BuiltInAGCIsAvailable() const override;
+  bool BuiltInNSIsAvailable() const override;
+
+  // Enables the built-in audio effects. Only supported on Android.
+  int32_t EnableBuiltInAEC(bool enable) override;
+  int32_t EnableBuiltInAGC(bool enable) override;
+  int32_t EnableBuiltInNS(bool enable) override;
+
+  // Play underrun count. Only supported on Android (guest).
+  int32_t GetPlayoutUnderrunCount() const override;
+
+ private:
+  webrtc::AudioTransport* audio_callback_ = nullptr;
+  bool stereo_playout_enabled_ = true;
+  bool stereo_recording_enabled_ = true;
+  std::atomic<bool> playing_ = false;
+  std::atomic<bool> recording_ = false;
+};
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/audio_frame_buffer.h b/host/frontend/webrtc/lib/audio_frame_buffer.h
new file mode 100644
index 0000000..4c656b5
--- /dev/null
+++ b/host/frontend/webrtc/lib/audio_frame_buffer.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <cinttypes>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class AudioFrameBuffer {
+ public:
+  virtual ~AudioFrameBuffer() = default;
+
+  virtual int bits_per_sample() const = 0;
+  virtual int sample_rate() const = 0;
+  virtual int channels() const = 0;
+  virtual int frames() const = 0;
+  virtual const uint8_t* data() const = 0;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/audio_sink.h b/host/frontend/webrtc/lib/audio_sink.h
new file mode 100644
index 0000000..e54170b
--- /dev/null
+++ b/host/frontend/webrtc/lib/audio_sink.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <memory>
+
+#include "host/frontend/webrtc/lib/audio_frame_buffer.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class AudioSink {
+ public:
+  virtual ~AudioSink() = default;
+  virtual void OnFrame(std::shared_ptr<AudioFrameBuffer> frame,
+                       int64_t timestamp_us) = 0;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/audio_source.h b/host/frontend/webrtc/lib/audio_source.h
new file mode 100644
index 0000000..09de020
--- /dev/null
+++ b/host/frontend/webrtc/lib/audio_source.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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 <stddef.h>
+
+namespace cuttlefish {
+
+namespace webrtc_streaming {
+
+// Interface to provide access to a stream originated on the client.
+class AudioSource {
+ public:
+  // Returns the number of bytes read or a negative number in case of errors. If
+  // muted is set to true, the contents of data should be considered to be all
+  // 0s.
+  virtual int GetMoreAudioData(void* data, int bytes_per_sample,
+                               int samples_per_channel, int num_channels,
+                               int sample_rate, bool& muted) = 0;
+
+ protected:
+  virtual ~AudioSource() = default;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/audio_track_source_impl.cpp b/host/frontend/webrtc/lib/audio_track_source_impl.cpp
new file mode 100644
index 0000000..334cbb5
--- /dev/null
+++ b/host/frontend/webrtc/lib/audio_track_source_impl.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/audio_track_source_impl.h"
+
+#include <android-base/logging.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+void AudioTrackSourceImpl::SetVolume(double volume) {
+  std::lock_guard<std::mutex> lock(observers_mutex_);
+  for (auto observer : audio_observers_) {
+    observer->OnSetVolume(volume);
+  }
+}
+
+void AudioTrackSourceImpl::RegisterAudioObserver(AudioObserver* observer) {
+  std::lock_guard<std::mutex> lock(observers_mutex_);
+  audio_observers_.insert(observer);
+}
+void AudioTrackSourceImpl::UnregisterAudioObserver(AudioObserver* observer) {
+  std::lock_guard<std::mutex> lock(observers_mutex_);
+  audio_observers_.erase(observer);
+}
+
+void AudioTrackSourceImpl::AddSink(webrtc::AudioTrackSinkInterface* sink) {
+  std::lock_guard<std::mutex> lock(sinks_mutex_);
+  sinks_.insert(sink);
+}
+
+void AudioTrackSourceImpl::RemoveSink(webrtc::AudioTrackSinkInterface* sink) {
+  std::lock_guard<std::mutex> lock(sinks_mutex_);
+  sinks_.erase(sink);
+}
+
+const cricket::AudioOptions AudioTrackSourceImpl::options() const {
+  return cricket::AudioOptions();
+}
+
+void AudioTrackSourceImpl::OnFrame(std::shared_ptr<AudioFrameBuffer> frame,
+                                   int64_t timestamp_ms) {
+    std::lock_guard<std::mutex> lock(sinks_mutex_);
+    for (auto sink : sinks_) {
+      sink->OnData(frame->data(), frame->bits_per_sample(),
+                   frame->sample_rate(), frame->channels(), frame->frames(),
+                   timestamp_ms);
+    }
+}
+
+AudioTrackSourceImpl::SourceState AudioTrackSourceImpl::state() const {
+  return SourceState::kLive;
+}
+
+bool AudioTrackSourceImpl::remote() const { return false; }
+
+void AudioTrackSourceImpl::RegisterObserver(
+    webrtc::ObserverInterface* /*observer*/) {}
+
+void AudioTrackSourceImpl::UnregisterObserver(
+    webrtc::ObserverInterface* /*observer*/) {}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/audio_track_source_impl.h b/host/frontend/webrtc/lib/audio_track_source_impl.h
new file mode 100644
index 0000000..0a72fe4
--- /dev/null
+++ b/host/frontend/webrtc/lib/audio_track_source_impl.h
@@ -0,0 +1,87 @@
+/*
+ * 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 <mutex>
+#include <set>
+
+#include <api/media_stream_interface.h>
+
+#include "host/frontend/webrtc/lib/audio_sink.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class AudioTrackSourceImpl : public webrtc::AudioSourceInterface {
+ public:
+  AudioTrackSourceImpl() = default;
+
+  // Sets the volume of the source. |volume| is in  the range of [0, 10].
+  void SetVolume(double volume) override;
+
+  void RegisterAudioObserver(AudioObserver* observer) override;
+  void UnregisterAudioObserver(AudioObserver* observer) override;
+
+  void AddSink(webrtc::AudioTrackSinkInterface* sink) override;
+  void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override;
+
+  // Returns options for the AudioSource.
+  // (for some of the settings this approach is broken, e.g. setting
+  // audio network adaptation on the source is the wrong layer of abstraction).
+  virtual const cricket::AudioOptions options() const;
+
+  void OnFrame(std::shared_ptr<AudioFrameBuffer> frame, int64_t timestamp_ms);
+
+  // MediaSourceInterface implementation
+  SourceState state() const override;
+  bool remote() const override;
+
+  // NotifierInterface implementation
+  void RegisterObserver(webrtc::ObserverInterface* observer) override;
+  void UnregisterObserver(webrtc::ObserverInterface* observer) override;
+
+ private:
+  std::set<AudioObserver*> audio_observers_;
+  std::mutex observers_mutex_;
+  std::set<webrtc::AudioTrackSinkInterface*> sinks_;
+  std::mutex sinks_mutex_;
+};
+
+// Wraps an AudioTrackSourceImpl as an implementation of the AudioSink
+// interface. This is needed as the AudioTrackSourceImpl is a reference counted
+// object that should only be referenced by rtc::scoped_refptr pointers, but the
+// AudioSink interface is not a reference counted object and therefore not
+// compatible with that kind of pointers. This class can be referenced by a
+// shared pointer and it in turn holds a scoped_refptr to the wrapped object.
+class AudioTrackSourceImplSinkWrapper : public AudioSink {
+ public:
+  virtual ~AudioTrackSourceImplSinkWrapper() = default;
+
+  AudioTrackSourceImplSinkWrapper(rtc::scoped_refptr<AudioTrackSourceImpl> obj)
+      : track_source_impl_(obj) {}
+
+  void OnFrame(std::shared_ptr<AudioFrameBuffer> frame,
+               int64_t timestamp_ms) override {
+    track_source_impl_->OnFrame(frame, timestamp_ms);
+  }
+
+ private:
+  rtc::scoped_refptr<AudioTrackSourceImpl> track_source_impl_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/client_handler.cpp b/host/frontend/webrtc/lib/client_handler.cpp
new file mode 100644
index 0000000..31fd50b
--- /dev/null
+++ b/host/frontend/webrtc/lib/client_handler.cpp
@@ -0,0 +1,767 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ClientHandler"
+
+#include "host/frontend/webrtc/lib/client_handler.h"
+
+#include <vector>
+
+#include <json/json.h>
+#include <json/writer.h>
+#include <netdb.h>
+#include <openssl/rand.h>
+
+#include <android-base/logging.h>
+
+#include "host/frontend/webrtc/lib/keyboard.h"
+#include "host/frontend/webrtc/lib/utils.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+namespace {
+
+static constexpr auto kInputChannelLabel = "input-channel";
+static constexpr auto kAdbChannelLabel = "adb-channel";
+static constexpr auto kBluetoothChannelLabel = "bluetooth-channel";
+
+class CvdCreateSessionDescriptionObserver
+    : public webrtc::CreateSessionDescriptionObserver {
+ public:
+  CvdCreateSessionDescriptionObserver(
+      std::weak_ptr<ClientHandler> client_handler)
+      : client_handler_(client_handler) {}
+
+  void OnSuccess(webrtc::SessionDescriptionInterface *desc) override {
+    auto client_handler = client_handler_.lock();
+    if (client_handler) {
+      client_handler->OnCreateSDPSuccess(desc);
+    }
+  }
+  void OnFailure(webrtc::RTCError error) override {
+    auto client_handler = client_handler_.lock();
+    if (client_handler) {
+      client_handler->OnCreateSDPFailure(error);
+    }
+  }
+
+ private:
+  std::weak_ptr<ClientHandler> client_handler_;
+};
+
+class CvdSetSessionDescriptionObserver
+    : public webrtc::SetSessionDescriptionObserver {
+ public:
+  CvdSetSessionDescriptionObserver(std::weak_ptr<ClientHandler> client_handler)
+      : client_handler_(client_handler) {}
+
+  void OnSuccess() override {
+    // local description set, nothing else to do
+  }
+  void OnFailure(webrtc::RTCError error) override {
+    auto client_handler = client_handler_.lock();
+    if (client_handler) {
+      client_handler->OnSetSDPFailure(error);
+    }
+  }
+
+ private:
+  std::weak_ptr<ClientHandler> client_handler_;
+};
+
+class CvdOnSetRemoteDescription
+    : public webrtc::SetRemoteDescriptionObserverInterface {
+ public:
+  CvdOnSetRemoteDescription(
+      std::function<void(webrtc::RTCError error)> on_error)
+      : on_error_(on_error) {}
+
+  void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override {
+    on_error_(error);
+  }
+
+ private:
+  std::function<void(webrtc::RTCError error)> on_error_;
+};
+
+}  // namespace
+
+class InputChannelHandler : public webrtc::DataChannelObserver {
+ public:
+  InputChannelHandler(
+      rtc::scoped_refptr<webrtc::DataChannelInterface> input_channel,
+      std::shared_ptr<ConnectionObserver> observer);
+  ~InputChannelHandler() override;
+
+  void OnStateChange() override;
+  void OnMessage(const webrtc::DataBuffer &msg) override;
+
+ private:
+  rtc::scoped_refptr<webrtc::DataChannelInterface> input_channel_;
+  std::shared_ptr<ConnectionObserver> observer_;
+};
+
+class AdbChannelHandler : public webrtc::DataChannelObserver {
+ public:
+  AdbChannelHandler(
+      rtc::scoped_refptr<webrtc::DataChannelInterface> adb_channel,
+      std::shared_ptr<ConnectionObserver> observer);
+  ~AdbChannelHandler() override;
+
+  void OnStateChange() override;
+  void OnMessage(const webrtc::DataBuffer &msg) override;
+
+ private:
+  rtc::scoped_refptr<webrtc::DataChannelInterface> adb_channel_;
+  std::shared_ptr<ConnectionObserver> observer_;
+  bool channel_open_reported_ = false;
+};
+
+class ControlChannelHandler : public webrtc::DataChannelObserver {
+ public:
+  ControlChannelHandler(
+      rtc::scoped_refptr<webrtc::DataChannelInterface> control_channel,
+      std::shared_ptr<ConnectionObserver> observer);
+  ~ControlChannelHandler() override;
+
+  void OnStateChange() override;
+  void OnMessage(const webrtc::DataBuffer &msg) override;
+
+  void Send(const Json::Value &message);
+  void Send(const uint8_t *msg, size_t size, bool binary);
+
+ private:
+  rtc::scoped_refptr<webrtc::DataChannelInterface> control_channel_;
+  std::shared_ptr<ConnectionObserver> observer_;
+};
+
+class BluetoothChannelHandler : public webrtc::DataChannelObserver {
+ public:
+  BluetoothChannelHandler(
+      rtc::scoped_refptr<webrtc::DataChannelInterface> bluetooth_channel,
+      std::shared_ptr<ConnectionObserver> observer);
+  ~BluetoothChannelHandler() override;
+
+  void OnStateChange() override;
+  void OnMessage(const webrtc::DataBuffer &msg) override;
+
+ private:
+  rtc::scoped_refptr<webrtc::DataChannelInterface> bluetooth_channel_;
+  std::shared_ptr<ConnectionObserver> observer_;
+  bool channel_open_reported_ = false;
+};
+
+InputChannelHandler::InputChannelHandler(
+    rtc::scoped_refptr<webrtc::DataChannelInterface> input_channel,
+    std::shared_ptr<ConnectionObserver> observer)
+    : input_channel_(input_channel), observer_(observer) {
+  input_channel->RegisterObserver(this);
+}
+
+InputChannelHandler::~InputChannelHandler() {
+  input_channel_->UnregisterObserver();
+}
+
+void InputChannelHandler::OnStateChange() {
+  LOG(VERBOSE) << "Input channel state changed to "
+               << webrtc::DataChannelInterface::DataStateString(
+                      input_channel_->state());
+}
+
+void InputChannelHandler::OnMessage(const webrtc::DataBuffer &msg) {
+  if (msg.binary) {
+    // TODO (jemoreira) consider binary protocol to avoid JSON parsing overhead
+    LOG(ERROR) << "Received invalid (binary) data on input channel";
+    return;
+  }
+  auto size = msg.size();
+
+  Json::Value evt;
+  Json::CharReaderBuilder builder;
+  std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
+  std::string errorMessage;
+  auto str = msg.data.cdata<char>();
+  if (!json_reader->parse(str, str + size, &evt, &errorMessage) < 0) {
+    LOG(ERROR) << "Received invalid JSON object over input channel: "
+               << errorMessage;
+    return;
+  }
+  if (!evt.isMember("type") || !evt["type"].isString()) {
+    LOG(ERROR) << "Input event doesn't have a valid 'type' field: "
+               << evt.toStyledString();
+    return;
+  }
+  auto event_type = evt["type"].asString();
+  if (event_type == "mouse") {
+    auto result =
+        ValidationResult::ValidateJsonObject(evt, "mouse",
+                           {{"down", Json::ValueType::intValue},
+                            {"x", Json::ValueType::intValue},
+                            {"y", Json::ValueType::intValue},
+                            {"display_label", Json::ValueType::stringValue}});
+    if (!result.ok()) {
+      LOG(ERROR) << result.error();
+      return;
+    }
+    auto label = evt["display_label"].asString();
+    int32_t down = evt["down"].asInt();
+    int32_t x = evt["x"].asInt();
+    int32_t y = evt["y"].asInt();
+
+    observer_->OnTouchEvent(label, x, y, down);
+  } else if (event_type == "multi-touch") {
+    auto result =
+        ValidationResult::ValidateJsonObject(evt, "multi-touch",
+                           {{"id", Json::ValueType::arrayValue},
+                            {"down", Json::ValueType::intValue},
+                            {"x", Json::ValueType::arrayValue},
+                            {"y", Json::ValueType::arrayValue},
+                            {"slot", Json::ValueType::arrayValue},
+                            {"display_label", Json::ValueType::stringValue}});
+    if (!result.ok()) {
+      LOG(ERROR) << result.error();
+      return;
+    }
+
+    auto label = evt["display_label"].asString();
+    auto idArr = evt["id"];
+    int32_t down = evt["down"].asInt();
+    auto xArr = evt["x"];
+    auto yArr = evt["y"];
+    auto slotArr = evt["slot"];
+    int size = evt["id"].size();
+
+    observer_->OnMultiTouchEvent(label, idArr, slotArr, xArr, yArr, down, size);
+  } else if (event_type == "keyboard") {
+    auto result =
+        ValidationResult::ValidateJsonObject(evt, "keyboard",
+                           {{"event_type", Json::ValueType::stringValue},
+                            {"keycode", Json::ValueType::stringValue}});
+    if (!result.ok()) {
+      LOG(ERROR) << result.error();
+      return;
+    }
+    auto down = evt["event_type"].asString() == std::string("keydown");
+    auto code = DomKeyCodeToLinux(evt["keycode"].asString());
+    observer_->OnKeyboardEvent(code, down);
+  } else {
+    LOG(ERROR) << "Unrecognized event type: " << event_type;
+    return;
+  }
+}
+
+AdbChannelHandler::AdbChannelHandler(
+    rtc::scoped_refptr<webrtc::DataChannelInterface> adb_channel,
+    std::shared_ptr<ConnectionObserver> observer)
+    : adb_channel_(adb_channel), observer_(observer) {
+  adb_channel->RegisterObserver(this);
+}
+
+AdbChannelHandler::~AdbChannelHandler() { adb_channel_->UnregisterObserver(); }
+
+void AdbChannelHandler::OnStateChange() {
+  LOG(VERBOSE) << "Adb channel state changed to "
+               << webrtc::DataChannelInterface::DataStateString(
+                      adb_channel_->state());
+}
+
+void AdbChannelHandler::OnMessage(const webrtc::DataBuffer &msg) {
+  // Report the adb channel as open on the first message received instead of at
+  // channel open, this avoids unnecessarily connecting to the adb daemon for
+  // clients that don't use ADB.
+  if (!channel_open_reported_) {
+    observer_->OnAdbChannelOpen([this](const uint8_t *msg, size_t size) {
+      webrtc::DataBuffer buffer(rtc::CopyOnWriteBuffer(msg, size),
+                                true /*binary*/);
+      // TODO (b/185832105): When the SCTP channel is congested data channel
+      // messages are buffered up to 16MB, when the buffer is full the channel
+      // is abruptly closed. Keep track of the buffered data to avoid losing the
+      // adb data channel.
+      adb_channel_->Send(buffer);
+      return true;
+    });
+    channel_open_reported_ = true;
+  }
+  observer_->OnAdbMessage(msg.data.cdata(), msg.size());
+}
+
+ControlChannelHandler::ControlChannelHandler(
+    rtc::scoped_refptr<webrtc::DataChannelInterface> control_channel,
+    std::shared_ptr<ConnectionObserver> observer)
+    : control_channel_(control_channel), observer_(observer) {
+  control_channel->RegisterObserver(this);
+  observer_->OnControlChannelOpen([this](const Json::Value& message) {
+    this->Send(message);
+    return true;
+  });
+}
+
+ControlChannelHandler::~ControlChannelHandler() {
+  control_channel_->UnregisterObserver();
+}
+
+void ControlChannelHandler::OnStateChange() {
+  LOG(VERBOSE) << "Control channel state changed to "
+               << webrtc::DataChannelInterface::DataStateString(
+                      control_channel_->state());
+}
+
+void ControlChannelHandler::OnMessage(const webrtc::DataBuffer &msg) {
+  observer_->OnControlMessage(msg.data.cdata(), msg.size());
+}
+
+void ControlChannelHandler::Send(const Json::Value& message) {
+  Json::StreamWriterBuilder factory;
+  std::string message_string = Json::writeString(factory, message);
+  Send(reinterpret_cast<const uint8_t*>(message_string.c_str()),
+       message_string.size(), /*binary=*/false);
+}
+
+void ControlChannelHandler::Send(const uint8_t *msg, size_t size, bool binary) {
+  webrtc::DataBuffer buffer(rtc::CopyOnWriteBuffer(msg, size), binary);
+  control_channel_->Send(buffer);
+}
+
+BluetoothChannelHandler::BluetoothChannelHandler(
+    rtc::scoped_refptr<webrtc::DataChannelInterface> bluetooth_channel,
+    std::shared_ptr<ConnectionObserver> observer)
+    : bluetooth_channel_(bluetooth_channel), observer_(observer) {
+  bluetooth_channel_->RegisterObserver(this);
+}
+
+BluetoothChannelHandler::~BluetoothChannelHandler() {
+  bluetooth_channel_->UnregisterObserver();
+}
+
+void BluetoothChannelHandler::OnStateChange() {
+  LOG(VERBOSE) << "Bluetooth channel state changed to "
+               << webrtc::DataChannelInterface::DataStateString(
+                      bluetooth_channel_->state());
+}
+
+void BluetoothChannelHandler::OnMessage(const webrtc::DataBuffer &msg) {
+  // Notify bluetooth channel opening when actually using the channel,
+  // it has the same reason with AdbChannelHandler::OnMessage,
+  // to avoid unnecessarily connection for Rootcanal.
+  if (channel_open_reported_ == false) {
+    channel_open_reported_ = true;
+    observer_->OnBluetoothChannelOpen([this](const uint8_t *msg, size_t size) {
+      webrtc::DataBuffer buffer(rtc::CopyOnWriteBuffer(msg, size),
+                                true /*binary*/);
+      // TODO (b/185832105): When the SCTP channel is congested data channel
+      // messages are buffered up to 16MB, when the buffer is full the channel
+      // is abruptly closed. Keep track of the buffered data to avoid losing the
+      // adb data channel.
+      bluetooth_channel_->Send(buffer);
+      return true;
+    });
+  }
+
+  observer_->OnBluetoothMessage(msg.data.cdata(), msg.size());
+}
+
+std::shared_ptr<ClientHandler> ClientHandler::Create(
+    int client_id, std::shared_ptr<ConnectionObserver> observer,
+    std::function<void(const Json::Value &)> send_to_client_cb,
+    std::function<void()> on_connection_closed_cb) {
+  return std::shared_ptr<ClientHandler>(new ClientHandler(
+      client_id, observer, send_to_client_cb, on_connection_closed_cb));
+}
+
+ClientHandler::ClientHandler(
+    int client_id, std::shared_ptr<ConnectionObserver> observer,
+    std::function<void(const Json::Value &)> send_to_client_cb,
+    std::function<void()> on_connection_closed_cb)
+    : client_id_(client_id),
+      observer_(observer),
+      send_to_client_(send_to_client_cb),
+      on_connection_closed_cb_(on_connection_closed_cb) {}
+
+ClientHandler::~ClientHandler() {
+  for (auto &data_channel : data_channels_) {
+    data_channel->UnregisterObserver();
+  }
+}
+
+bool ClientHandler::SetPeerConnection(
+    rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection) {
+  peer_connection_ = peer_connection;
+
+  // libwebrtc configures the video encoder with a start bitrate of just 300kbs
+  // which causes it to drop the first 4 frames it receives. Any value over 2Mbs
+  // will be capped at 2Mbs when passed to the encoder by the peer_connection
+  // object, so we pass the maximum possible value here.
+  webrtc::BitrateSettings bitrate_settings;
+  bitrate_settings.start_bitrate_bps = 2000000; // 2Mbs
+  peer_connection_->SetBitrate(bitrate_settings);
+  // At least one data channel needs to be created on the side that makes the
+  // SDP offer (the device) for data channels to be enabled at all.
+  // This channel is meant to carry control commands from the client.
+  auto control_channel = peer_connection_->CreateDataChannel(
+      "device-control", nullptr /* config */);
+  if (!control_channel) {
+    LOG(ERROR) << "Failed to create control data channel";
+    return false;
+  }
+  control_handler_.reset(new ControlChannelHandler(control_channel, observer_));
+  return true;
+}
+
+bool ClientHandler::AddDisplay(
+    rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track,
+    const std::string &label) {
+  // Send each track as part of a different stream with the label as id
+  auto err_or_sender =
+      peer_connection_->AddTrack(video_track, {label} /* stream_id */);
+  if (!err_or_sender.ok()) {
+    LOG(ERROR) << "Failed to add video track to the peer connection";
+    return false;
+  }
+  // TODO (b/154138394): use the returned sender (err_or_sender.value()) to
+  // remove the display from the connection.
+  return true;
+}
+
+bool ClientHandler::AddAudio(
+    rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track,
+    const std::string &label) {
+  // Send each track as part of a different stream with the label as id
+  auto err_or_sender =
+      peer_connection_->AddTrack(audio_track, {label} /* stream_id */);
+  if (!err_or_sender.ok()) {
+    LOG(ERROR) << "Failed to add video track to the peer connection";
+    return false;
+  }
+  return true;
+}
+
+void ClientHandler::LogAndReplyError(const std::string &error_msg) const {
+  LOG(ERROR) << error_msg;
+  Json::Value reply;
+  reply["type"] = "error";
+  reply["error"] = error_msg;
+  send_to_client_(reply);
+}
+
+void ClientHandler::OnCreateSDPSuccess(
+    webrtc::SessionDescriptionInterface *desc) {
+  std::string offer_str;
+  desc->ToString(&offer_str);
+  peer_connection_->SetLocalDescription(
+      // The peer connection wraps this raw pointer with a scoped_refptr, so
+      // it's guaranteed to be deleted at some point
+      new rtc::RefCountedObject<CvdSetSessionDescriptionObserver>(
+          weak_from_this()),
+      desc);
+  // The peer connection takes ownership of the description so it should not be
+  // used after this
+  desc = nullptr;
+
+  Json::Value reply;
+  reply["type"] = "offer";
+  reply["sdp"] = offer_str;
+
+  state_ = State::kAwaitingAnswer;
+  send_to_client_(reply);
+}
+
+void ClientHandler::OnCreateSDPFailure(webrtc::RTCError error) {
+  state_ = State::kFailed;
+  LogAndReplyError(error.message());
+  Close();
+}
+
+void ClientHandler::OnSetSDPFailure(webrtc::RTCError error) {
+  state_ = State::kFailed;
+  LogAndReplyError(error.message());
+  LOG(ERROR) << "Error setting local description: Either there is a bug in "
+                "libwebrtc or the local description was (incorrectly) modified "
+                "after creating it";
+  Close();
+}
+
+void ClientHandler::HandleMessage(const Json::Value &message) {
+  {
+    auto result = ValidationResult::ValidateJsonObject(message, "",
+                                     {{"type", Json::ValueType::stringValue}});
+    if (!result.ok()) {
+      LogAndReplyError(result.error());
+      return;
+    }
+  }
+  auto type = message["type"].asString();
+  if (type == "request-offer") {
+    // Can't check for state being different that kNew because renegotiation can
+    // start in any state after the answer is returned.
+    if (state_ == State::kCreatingOffer) {
+      // An offer has been requested already
+      LogAndReplyError("Multiple requests for offer received from single client");
+      return;
+    }
+    state_ = State::kCreatingOffer;
+    peer_connection_->CreateOffer(
+        // No memory leak here because this is a ref counted objects and the
+        // peer connection immediately wraps it with a scoped_refptr
+        new rtc::RefCountedObject<CvdCreateSessionDescriptionObserver>(
+            weak_from_this()),
+        webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
+    // The created offer wil be sent to the client on
+    // OnSuccess(webrtc::SessionDescriptionInterface* desc)
+  } else if (type == "answer") {
+    if (state_ != State::kAwaitingAnswer) {
+      LogAndReplyError("Received unexpected SDP answer");
+      return;
+    }
+    auto result = ValidationResult::ValidateJsonObject(message, type,
+                                     {{"sdp", Json::ValueType::stringValue}});
+    if (!result.ok()) {
+      LogAndReplyError(result.error());
+      return;
+    }
+    auto remote_desc_str = message["sdp"].asString();
+    auto remote_desc = webrtc::CreateSessionDescription(
+        webrtc::SdpType::kAnswer, remote_desc_str, nullptr /*error*/);
+    if (!remote_desc) {
+      LogAndReplyError("Failed to parse answer.");
+      return;
+    }
+    rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface> observer(
+        new rtc::RefCountedObject<CvdOnSetRemoteDescription>(
+            [this](webrtc::RTCError error) {
+              if (!error.ok()) {
+                LogAndReplyError(error.message());
+                // The remote description was rejected, this client can't be
+                // trusted anymore.
+                Close();
+              }
+            }));
+    peer_connection_->SetRemoteDescription(std::move(remote_desc), observer);
+    state_ = State::kConnecting;
+
+  } else if (type == "ice-candidate") {
+    {
+      auto result = ValidationResult::ValidateJsonObject(
+          message, type, {{"candidate", Json::ValueType::objectValue}});
+      if (!result.ok()) {
+        LogAndReplyError(result.error());
+        return;
+      }
+    }
+    auto candidate_json = message["candidate"];
+    {
+      auto result =
+          ValidationResult::ValidateJsonObject(candidate_json,
+                                               "ice-candidate/candidate",
+                             {
+                                 {"sdpMid", Json::ValueType::stringValue},
+                                 {"candidate", Json::ValueType::stringValue},
+                                 {"sdpMLineIndex", Json::ValueType::intValue},
+                             });
+      if (!result.ok()) {
+        LogAndReplyError(result.error());
+        return;
+      }
+    }
+    auto mid = candidate_json["sdpMid"].asString();
+    auto candidate_sdp = candidate_json["candidate"].asString();
+    auto line_index = candidate_json["sdpMLineIndex"].asInt();
+
+    std::unique_ptr<webrtc::IceCandidateInterface> candidate(
+        webrtc::CreateIceCandidate(mid, line_index, candidate_sdp,
+                                   nullptr /*error*/));
+    if (!candidate) {
+      LogAndReplyError("Failed to parse ICE candidate");
+      return;
+    }
+    peer_connection_->AddIceCandidate(std::move(candidate),
+                                      [this](webrtc::RTCError error) {
+                                        if (!error.ok()) {
+                                          LogAndReplyError(error.message());
+                                        }
+                                      });
+  } else {
+    LogAndReplyError("Unknown client message type: " + type);
+    return;
+  }
+}
+
+void ClientHandler::Close() {
+  // We can't simply call peer_connection_->Close() here because this method
+  // could be called from one of the PeerConnectionObserver callbacks and that
+  // would lead to a deadlock (Close eventually tries to destroy an object that
+  // will then wait for the callback to return -> deadlock). Destroying the
+  // peer_connection_ has the same effect. The only alternative is to postpone
+  // that operation until after the callback returns.
+  on_connection_closed_cb_();
+}
+
+void ClientHandler::OnConnectionChange(
+    webrtc::PeerConnectionInterface::PeerConnectionState new_state) {
+  switch (new_state) {
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kNew:
+      break;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting:
+      break;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected:
+      LOG(VERBOSE) << "Client " << client_id_ << ": WebRTC connected";
+      state_ = State::kConnected;
+      observer_->OnConnected(
+          [this](const uint8_t *msg, size_t size, bool binary) {
+            control_handler_->Send(msg, size, binary);
+            return true;
+          });
+      break;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected:
+      LOG(VERBOSE) << "Client " << client_id_ << ": Connection disconnected";
+      Close();
+      break;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed:
+      LOG(ERROR) << "Client " << client_id_ << ": Connection failed";
+      Close();
+      break;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed:
+      LOG(VERBOSE) << "Client " << client_id_ << ": Connection closed";
+      Close();
+      break;
+  }
+}
+
+void ClientHandler::OnIceCandidate(
+    const webrtc::IceCandidateInterface *candidate) {
+  std::string candidate_sdp;
+  candidate->ToString(&candidate_sdp);
+  auto sdp_mid = candidate->sdp_mid();
+  auto line_index = candidate->sdp_mline_index();
+
+  Json::Value reply;
+  reply["type"] = "ice-candidate";
+  reply["mid"] = sdp_mid;
+  reply["mLineIndex"] = static_cast<Json::UInt64>(line_index);
+  reply["candidate"] = candidate_sdp;
+
+  send_to_client_(reply);
+}
+
+void ClientHandler::OnDataChannel(
+    rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
+  auto label = data_channel->label();
+  if (label == kInputChannelLabel) {
+    input_handler_.reset(new InputChannelHandler(data_channel, observer_));
+  } else if (label == kAdbChannelLabel) {
+    adb_handler_.reset(new AdbChannelHandler(data_channel, observer_));
+  } else if (label == kBluetoothChannelLabel) {
+    bluetooth_handler_.reset(
+        new BluetoothChannelHandler(data_channel, observer_));
+  } else {
+    LOG(VERBOSE) << "Data channel connected: " << label;
+    data_channels_.push_back(data_channel);
+  }
+}
+
+void ClientHandler::OnRenegotiationNeeded() {
+  state_ = State::kNew;
+  LOG(VERBOSE) << "Client " << client_id_ << " needs renegotiation";
+}
+
+void ClientHandler::OnIceGatheringChange(
+    webrtc::PeerConnectionInterface::IceGatheringState new_state) {
+  std::string state_str;
+  switch (new_state) {
+    case webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringNew:
+      state_str = "NEW";
+      break;
+    case webrtc::PeerConnectionInterface::IceGatheringState::
+        kIceGatheringGathering:
+      state_str = "GATHERING";
+      break;
+    case webrtc::PeerConnectionInterface::IceGatheringState::
+        kIceGatheringComplete:
+      state_str = "COMPLETE";
+      break;
+    default:
+      state_str = "UNKNOWN";
+  }
+  LOG(VERBOSE) << "Client " << client_id_
+               << ": ICE Gathering state set to: " << state_str;
+}
+
+void ClientHandler::OnIceCandidateError(const std::string &host_candidate,
+                                        const std::string &url, int error_code,
+                                        const std::string &error_text) {
+  LOG(VERBOSE) << "Gathering of an ICE candidate (host candidate: "
+               << host_candidate << ", url: " << url
+               << ") failed: " << error_text;
+}
+
+void ClientHandler::OnIceCandidateError(const std::string &address, int port,
+                                        const std::string &url, int error_code,
+                                        const std::string &error_text) {
+  LOG(VERBOSE) << "Gathering of an ICE candidate (address: " << address
+               << ", port: " << port << ", url: " << url
+               << ") failed: " << error_text;
+}
+
+void ClientHandler::OnSignalingChange(
+    webrtc::PeerConnectionInterface::SignalingState new_state) {
+  // ignore
+}
+void ClientHandler::OnStandardizedIceConnectionChange(
+    webrtc::PeerConnectionInterface::IceConnectionState new_state) {
+  switch (new_state) {
+    case webrtc::PeerConnectionInterface::kIceConnectionNew:
+      LOG(DEBUG) << "ICE connection state: New";
+      break;
+    case webrtc::PeerConnectionInterface::kIceConnectionChecking:
+      LOG(DEBUG) << "ICE connection state: Checking";
+      break;
+    case webrtc::PeerConnectionInterface::kIceConnectionConnected:
+      LOG(DEBUG) << "ICE connection state: Connected";
+      break;
+    case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
+      LOG(DEBUG) << "ICE connection state: Completed";
+      break;
+    case webrtc::PeerConnectionInterface::kIceConnectionFailed:
+      state_ = State::kFailed;
+      LOG(DEBUG) << "ICE connection state: Failed";
+      break;
+    case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
+      LOG(DEBUG) << "ICE connection state: Disconnected";
+      break;
+    case webrtc::PeerConnectionInterface::kIceConnectionClosed:
+      LOG(DEBUG) << "ICE connection state: Closed";
+      break;
+    case webrtc::PeerConnectionInterface::kIceConnectionMax:
+      LOG(DEBUG) << "ICE connection state: Max";
+      break;
+  }
+}
+void ClientHandler::OnIceCandidatesRemoved(
+    const std::vector<cricket::Candidate> &candidates) {
+  // ignore
+}
+void ClientHandler::OnTrack(
+    rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) {
+  // ignore
+}
+void ClientHandler::OnRemoveTrack(
+    rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) {
+  // ignore
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/client_handler.h b/host/frontend/webrtc/lib/client_handler.h
new file mode 100644
index 0000000..c85f169
--- /dev/null
+++ b/host/frontend/webrtc/lib/client_handler.h
@@ -0,0 +1,131 @@
+/*
+ * 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 <functional>
+#include <memory>
+#include <optional>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <json/json.h>
+
+#include <api/peer_connection_interface.h>
+#include <pc/video_track_source.h>
+
+#include "host/frontend/webrtc/lib/connection_observer.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class InputChannelHandler;
+class AdbChannelHandler;
+class ControlChannelHandler;
+class BluetoothChannelHandler;
+
+class ClientHandler : public webrtc::PeerConnectionObserver,
+                      public std::enable_shared_from_this<ClientHandler> {
+ public:
+  static std::shared_ptr<ClientHandler> Create(
+      int client_id, std::shared_ptr<ConnectionObserver> observer,
+      std::function<void(const Json::Value&)> send_client_cb,
+      std::function<void()> on_connection_closed_cb);
+  ~ClientHandler() override;
+
+  bool SetPeerConnection(
+      rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection);
+
+  bool AddDisplay(rtc::scoped_refptr<webrtc::VideoTrackInterface> track,
+                  const std::string& label);
+
+  bool AddAudio(rtc::scoped_refptr<webrtc::AudioTrackInterface> track,
+                  const std::string& label);
+
+  void HandleMessage(const Json::Value& client_message);
+
+  // CreateSessionDescriptionObserver implementation
+  void OnCreateSDPSuccess(webrtc::SessionDescriptionInterface* desc);
+  void OnCreateSDPFailure(webrtc::RTCError error);
+
+  // SetSessionDescriptionObserver implementation
+  void OnSetSDPFailure(webrtc::RTCError error);
+
+  // PeerConnectionObserver implementation
+  void OnSignalingChange(
+      webrtc::PeerConnectionInterface::SignalingState new_state) override;
+  void OnDataChannel(
+      rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override;
+  void OnRenegotiationNeeded() override;
+  void OnStandardizedIceConnectionChange(
+      webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
+  void OnConnectionChange(
+      webrtc::PeerConnectionInterface::PeerConnectionState new_state) override;
+  void OnIceGatheringChange(
+      webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
+  void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override;
+  // Gathering of an ICE candidate failed.
+  // See https://w3c.github.io/webrtc-pc/#event-icecandidateerror
+  // |host_candidate| is a stringified socket address.
+  void OnIceCandidateError(const std::string& host_candidate,
+                           const std::string& url, int error_code,
+                           const std::string& error_text) override;
+  // Gathering of an ICE candidate failed.
+  // See https://w3c.github.io/webrtc-pc/#event-icecandidateerror
+  void OnIceCandidateError(const std::string& address, int port,
+                           const std::string& url, int error_code,
+                           const std::string& error_text) override;
+  void OnIceCandidatesRemoved(
+      const std::vector<cricket::Candidate>& candidates) override;
+  void OnTrack(
+      rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) override;
+  void OnRemoveTrack(
+      rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override;
+
+ private:
+  enum class State {
+      kNew,
+      kCreatingOffer,
+      kAwaitingAnswer,
+      kConnecting,
+      kConnected,
+      kFailed,
+  };
+  ClientHandler(int client_id, std::shared_ptr<ConnectionObserver> observer,
+                std::function<void(const Json::Value&)> send_client_cb,
+                std::function<void()> on_connection_closed_cb);
+
+  // Intentionally private, disconnect the client by destroying the object.
+  void Close();
+
+  void LogAndReplyError(const std::string& error_msg) const;
+
+  int client_id_;
+  State state_ = State::kNew;
+  std::shared_ptr<ConnectionObserver> observer_;
+  std::function<void(const Json::Value&)> send_to_client_;
+  std::function<void()> on_connection_closed_cb_;
+  rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
+  std::vector<rtc::scoped_refptr<webrtc::DataChannelInterface>> data_channels_;
+  std::unique_ptr<InputChannelHandler> input_handler_;
+  std::unique_ptr<AdbChannelHandler> adb_handler_;
+  std::unique_ptr<ControlChannelHandler> control_handler_;
+  std::unique_ptr<BluetoothChannelHandler> bluetooth_handler_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/connection_observer.h b/host/frontend/webrtc/lib/connection_observer.h
new file mode 100644
index 0000000..be6fc13
--- /dev/null
+++ b/host/frontend/webrtc/lib/connection_observer.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <functional>
+
+#include <json/json.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class ConnectionObserver {
+ public:
+  ConnectionObserver() = default;
+  virtual ~ConnectionObserver() = default;
+
+  virtual void OnConnected(
+      std::function<void(const uint8_t*, size_t, bool)> ctrl_msg_sender) = 0;
+  virtual void OnTouchEvent(const std::string& display_label, int x, int y,
+                            bool down) = 0;
+  virtual void OnMultiTouchEvent(const std::string& label, Json::Value id, Json::Value slot,
+                                 Json::Value x, Json::Value y, bool down, int size) = 0;
+  virtual void OnKeyboardEvent(uint16_t keycode, bool down) = 0;
+  virtual void OnSwitchEvent(uint16_t code, bool state) = 0;
+  virtual void OnAdbChannelOpen(
+      std::function<bool(const uint8_t*, size_t)> adb_message_sender) = 0;
+  virtual void OnAdbMessage(const uint8_t* msg, size_t size) = 0;
+  virtual void OnControlChannelOpen(
+      std::function<bool(const Json::Value)> control_message_sender) = 0;
+  virtual void OnControlMessage(const uint8_t* msg, size_t size) = 0;
+  virtual void OnBluetoothChannelOpen(
+      std::function<bool(const uint8_t*, size_t)> bluetooth_message_sender) = 0;
+  virtual void OnBluetoothMessage(const uint8_t* msg, size_t size) = 0;
+};
+
+class ConnectionObserverFactory {
+ public:
+  virtual ~ConnectionObserverFactory() = default;
+  // Called when a new connection is requested
+  virtual std::shared_ptr<ConnectionObserver> CreateObserver() = 0;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/keyboard.cpp b/host/frontend/webrtc/lib/keyboard.cpp
new file mode 100644
index 0000000..ee6b2a7
--- /dev/null
+++ b/host/frontend/webrtc/lib/keyboard.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/keyboard.h"
+
+#include <linux/input.h>
+
+#include <map>
+
+static const std::map<std::string, uint16_t> kDomToLinuxMapping = {
+    {"Backquote", KEY_GRAVE},
+    {"Backslash", KEY_BACKSLASH},
+    {"Backspace", KEY_BACKSPACE},
+    {"BracketLeft", KEY_LEFTBRACE},
+    {"BracketRight", KEY_RIGHTBRACE},
+    {"Comma", KEY_COMMA},
+    {"Digit0", KEY_0},
+    {"Digit1", KEY_1},
+    {"Digit2", KEY_2},
+    {"Digit3", KEY_3},
+    {"Digit4", KEY_4},
+    {"Digit5", KEY_5},
+    {"Digit6", KEY_6},
+    {"Digit7", KEY_7},
+    {"Digit8", KEY_8},
+    {"Digit9", KEY_9},
+    {"Equal", KEY_EQUAL},
+    {"IntlBackslash", KEY_BACKSLASH},
+    {"IntlRo", KEY_RO},
+    {"IntlYen", KEY_BACKSLASH},
+    {"KeyA", KEY_A},
+    {"KeyB", KEY_B},
+    {"KeyC", KEY_C},
+    {"KeyD", KEY_D},
+    {"KeyE", KEY_E},
+    {"KeyF", KEY_F},
+    {"KeyG", KEY_G},
+    {"KeyH", KEY_H},
+    {"KeyI", KEY_I},
+    {"KeyJ", KEY_J},
+    {"KeyK", KEY_K},
+    {"KeyL", KEY_L},
+    {"KeyM", KEY_M},
+    {"KeyN", KEY_N},
+    {"KeyO", KEY_O},
+    {"KeyP", KEY_P},
+    {"KeyQ", KEY_Q},
+    {"KeyR", KEY_R},
+    {"KeyS", KEY_S},
+    {"KeyT", KEY_T},
+    {"KeyU", KEY_U},
+    {"KeyV", KEY_V},
+    {"KeyW", KEY_W},
+    {"KeyX", KEY_X},
+    {"KeyY", KEY_Y},
+    {"KeyZ", KEY_Z},
+    {"Minus", KEY_MINUS},
+    {"Period", KEY_DOT},
+    {"Quote", KEY_APOSTROPHE},
+    {"Semicolon", KEY_SEMICOLON},
+    {"Slash", KEY_SLASH},
+    {"AltLeft", KEY_LEFTALT},
+    {"AltRight", KEY_RIGHTALT},
+    {"CapsLock", KEY_CAPSLOCK},
+    {"ContextMenu", KEY_CONTEXT_MENU},
+    {"ControlLeft", KEY_LEFTCTRL},
+    {"ControlRight", KEY_RIGHTCTRL},
+    {"Enter", KEY_ENTER},
+    {"MetaLeft", KEY_LEFTMETA},
+    {"MetaRight", KEY_RIGHTMETA},
+    {"ShiftLeft", KEY_LEFTSHIFT},
+    {"ShiftRight", KEY_RIGHTSHIFT},
+    {"Space", KEY_SPACE},
+    {"Tab", KEY_TAB},
+    {"Delete", KEY_DELETE},
+    {"End", KEY_END},
+    {"Help", KEY_HELP},
+    {"Home", KEY_HOME},
+    {"Insert", KEY_INSERT},
+    {"PageDown", KEY_PAGEDOWN},
+    {"PageUp", KEY_PAGEUP},
+    {"ArrowDown", KEY_DOWN},
+    {"ArrowLeft", KEY_LEFT},
+    {"ArrowRight", KEY_RIGHT},
+    {"ArrowUp", KEY_UP},
+
+    {"NumLock", KEY_NUMLOCK},
+    {"Numpad0", KEY_KP0},
+    {"Numpad1", KEY_KP1},
+    {"Numpad2", KEY_KP2},
+    {"Numpad3", KEY_KP3},
+    {"Numpad4", KEY_KP4},
+    {"Numpad5", KEY_KP5},
+    {"Numpad6", KEY_KP6},
+    {"Numpad7", KEY_KP7},
+    {"Numpad8", KEY_KP8},
+    {"Numpad9", KEY_KP9},
+    {"NumpadAdd", KEY_KPPLUS},
+    {"NumpadBackspace", KEY_BACKSPACE},
+    {"NumpadClear", KEY_CLEAR},
+    {"NumpadComma", KEY_KPCOMMA},
+    {"NumpadDecimal", KEY_KPDOT},
+    {"NumpadDivide", KEY_KPSLASH},
+    {"NumpadEnter", KEY_KPENTER},
+    {"NumpadEqual", KEY_KPEQUAL},
+    /*
+    {"NumpadClearEntry", },
+    {"NumpadHash", },
+    {"NumpadMemoryAdd", },
+    {"NumpadMemoryClear", },
+    {"NumpadMemoryRecall", },
+    {"NumpadMemoryStore", },
+    {"NumpadMemorySubtract", },
+    */
+    {"NumpadMultiply", KEY_KPASTERISK},
+    {"NumpadParenLeft", KEY_KPLEFTPAREN},
+    {"NumpadParenRight", KEY_KPRIGHTPAREN},
+    {"NumpadStar", KEY_KPASTERISK},
+    {"NumpadSubtract", KEY_KPMINUS},
+
+    {"Escape", KEY_ESC},
+    {"F1", KEY_F1},
+    {"F2", KEY_F2},
+    {"F3", KEY_F3},
+    {"F4", KEY_F4},
+    {"F5", KEY_F5},
+    {"F6", KEY_F6},
+    {"F7", KEY_F7},
+    {"F8", KEY_F8},
+    {"F9", KEY_F9},
+    {"F10", KEY_F10},
+    {"F11", KEY_F11},
+    {"F12", KEY_F12},
+    {"Fn", KEY_FN},
+    /*{"FnLock", },*/
+    {"PrintScreen", KEY_SYSRQ},
+    {"ScrollLock", KEY_SCROLLLOCK},
+    {"Pause", KEY_PAUSE}};
+
+uint16_t DomKeyCodeToLinux(const std::string& dom_KEY_code) {
+  const auto it = kDomToLinuxMapping.find(dom_KEY_code);
+  if (it == kDomToLinuxMapping.end()) {
+    return 0;
+  }
+  return it->second;
+}
diff --git a/host/frontend/gcastv2/webrtc/include/webrtc/Keyboard.h b/host/frontend/webrtc/lib/keyboard.h
similarity index 100%
rename from host/frontend/gcastv2/webrtc/include/webrtc/Keyboard.h
rename to host/frontend/webrtc/lib/keyboard.h
diff --git a/host/frontend/webrtc/lib/local_recorder.cpp b/host/frontend/webrtc/lib/local_recorder.cpp
new file mode 100644
index 0000000..28f71b0
--- /dev/null
+++ b/host/frontend/webrtc/lib/local_recorder.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/local_recorder.h"
+
+#include <atomic>
+#include <chrono>
+#include <list>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <api/media_stream_interface.h>
+#include <api/rtp_parameters.h>
+#include <api/task_queue/default_task_queue_factory.h>
+#include <api/video/builtin_video_bitrate_allocator_factory.h>
+#include <api/video/video_stream_encoder_create.h>
+#include <api/video/video_stream_encoder_interface.h>
+#include <api/video_codecs/builtin_video_encoder_factory.h>
+#include <mkvmuxer/mkvmuxer.h>
+#include <mkvmuxer/mkvwriter.h>
+#include <system_wrappers/include/clock.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+constexpr double kRtpTicksPerSecond = 90000.;
+constexpr double kRtpTicksPerMs = kRtpTicksPerSecond / 1000.;
+constexpr double kRtpTicksPerUs = kRtpTicksPerMs / 1000.;
+constexpr double kRtpTicksPerNs = kRtpTicksPerUs / 1000.;
+
+class LocalRecorder::Display
+    : public webrtc::EncodedImageCallback
+    , public rtc::VideoSinkInterface<webrtc::VideoFrame> {
+public:
+  Display(LocalRecorder::Impl& impl);
+
+  void EncoderLoop();
+  void Stop();
+
+  // VideoSinkInterface
+  virtual void OnFrame(const webrtc::VideoFrame& frame) override;
+
+  // EncodedImageCallback
+  virtual webrtc::EncodedImageCallback::Result OnEncodedImage(
+      const webrtc::EncodedImage& encoded_image,
+      const webrtc::CodecSpecificInfo* codec_specific_info,
+      const webrtc::RTPFragmentationHeader* fragmentation) override;
+
+  LocalRecorder::Impl& impl_;
+  std::shared_ptr<webrtc::VideoTrackSourceInterface> source_;
+  std::unique_ptr<webrtc::VideoEncoder> video_encoder_;
+  uint64_t video_track_number_;
+
+  // TODO(schuffelen): Use a WebRTC task queue?
+  std::thread encoder_thread_;
+  std::condition_variable encoder_queue_signal_;
+  std::mutex encode_queue_mutex_;
+  std::list<webrtc::VideoFrame> encode_queue_;
+  std::atomic_bool encoder_running_ = true;
+};
+
+class LocalRecorder::Impl {
+public:
+  mkvmuxer::MkvWriter file_writer_;
+  mkvmuxer::Segment segment_;
+  std::unique_ptr<webrtc::VideoEncoderFactory> encoder_factory_;
+  std::mutex mkv_mutex_;
+  std::vector<std::unique_ptr<Display>> displays_;
+};
+
+/* static */
+std::unique_ptr<LocalRecorder> LocalRecorder::Create(
+    const std::string& filename) {
+  std::unique_ptr<Impl> impl(new Impl());
+
+  if (!impl->file_writer_.Open(filename.c_str())) {
+    LOG(ERROR) << "Failed to open \"" << filename << "\" to write a webm";
+    return {};
+  }
+
+  if (!impl->segment_.Init(&impl->file_writer_)) {
+    LOG(ERROR) << "Failed to initialize the mkvkmuxer segment";
+    return {};
+  }
+
+  impl->segment_.AccurateClusterDuration(true);
+  impl->segment_.set_estimate_file_duration(true);
+
+  impl->encoder_factory_ = webrtc::CreateBuiltinVideoEncoderFactory();
+  if (!impl->encoder_factory_) {
+    LOG(ERROR) << "Failed to create webRTC built-in video encoder factory";
+    return {};
+  }
+
+  return std::unique_ptr<LocalRecorder>(new LocalRecorder(std::move(impl)));
+}
+
+LocalRecorder::LocalRecorder(std::unique_ptr<LocalRecorder::Impl> impl)
+    : impl_(std::move(impl)) {
+}
+
+LocalRecorder::~LocalRecorder() = default;
+
+void LocalRecorder::AddDisplay(
+    size_t width,
+    size_t height,
+    std::shared_ptr<webrtc::VideoTrackSourceInterface> source) {
+  std::unique_ptr<Display> display(new Display(*impl_));
+  display->source_ = source;
+
+  display->video_encoder_ =
+      impl_->encoder_factory_->CreateVideoEncoder(webrtc::SdpVideoFormat("VP8"));
+  if (!display->video_encoder_) {
+    LOG(ERROR) << "Could not create vp8 video encoder";
+    return;
+  }
+  auto rc =
+      display->video_encoder_->RegisterEncodeCompleteCallback(display.get());
+  if (rc != 0) {
+    LOG(ERROR) << "Could not register encode complete callback";
+    return;
+  }
+  source->AddOrUpdateSink(display.get(), rtc::VideoSinkWants{});
+
+  webrtc::VideoCodec codec {};
+  memset(&codec, 0, sizeof(codec));
+  codec.codecType = webrtc::kVideoCodecVP8;
+  codec.width = width;
+  codec.height = height;
+  codec.startBitrate = 1000; // kilobits/sec
+  codec.maxBitrate = 2000;
+  codec.minBitrate = 0;
+  codec.maxFramerate = 60;
+  codec.active = true;
+  codec.qpMax = 56; // kDefaultMaxQp from simulcast_encoder_adapter.cc
+  codec.mode = webrtc::VideoCodecMode::kScreensharing;
+  codec.expect_encode_from_texture = false;
+  *codec.VP8() = webrtc::VideoEncoder::GetDefaultVp8Settings();
+
+  webrtc::VideoEncoder::Capabilities capabilities(false);
+  webrtc::VideoEncoder::Settings settings(capabilities, 1, 1 << 20);
+
+  rc = display->video_encoder_->InitEncode(&codec, settings);
+  if (rc != 0) {
+    LOG(ERROR) << "Failed to InitEncode";
+    return;
+  }
+
+  display->encoder_running_ = true;
+  display->encoder_thread_ = std::thread([](Display* display) {
+    display->EncoderLoop();
+  }, display.get());
+
+  std::lock_guard lock(impl_->mkv_mutex_);
+  display->video_track_number_ =
+      impl_->segment_.AddVideoTrack(width, height, 0);
+  if (display->video_track_number_ == 0) {
+    LOG(ERROR) << "Failed to add video track to webm muxer";
+    return;
+  }
+
+  impl_->displays_.emplace_back(std::move(display));
+}
+
+void LocalRecorder::Stop() {
+  for (auto& display : impl_->displays_) {
+    display->Stop();
+  }
+  impl_->displays_.clear();
+
+  std::lock_guard lock(impl_->mkv_mutex_);
+  impl_->segment_.Finalize();
+}
+
+LocalRecorder::Display::Display(LocalRecorder::Impl& impl) : impl_(impl) {
+}
+
+void LocalRecorder::Display::OnFrame(const webrtc::VideoFrame& frame) {
+  std::lock_guard queue_lock(encode_queue_mutex_);
+  static int kMaxQueuedFrames = 10;
+  if (encode_queue_.size() >= kMaxQueuedFrames) {
+    LOG(VERBOSE) << "Dropped frame, encoder queue too long";
+    return;
+  }
+  encode_queue_.push_back(frame);
+  encoder_queue_signal_.notify_one();
+}
+
+void LocalRecorder::Display::EncoderLoop() {
+  int frames_since_keyframe = 0;
+  std::chrono::time_point<std::chrono::steady_clock> start_timestamp;
+  auto last_keyframe_time = std::chrono::steady_clock::now();
+  while (encoder_running_) {
+    std::unique_ptr<webrtc::VideoFrame> frame;
+    {
+      std::unique_lock queue_lock(encode_queue_mutex_);
+      while (encode_queue_.size() == 0 && encoder_running_) {
+        encoder_queue_signal_.wait(queue_lock);
+      }
+      if (!encoder_running_) {
+        break;
+      }
+      frame = std::make_unique<webrtc::VideoFrame>(
+          std::move(encode_queue_.front()));
+      encode_queue_.pop_front();
+    }
+
+    auto now = std::chrono::steady_clock::now();
+    if (start_timestamp.time_since_epoch().count() == 0) {
+      start_timestamp = now;
+    }
+    auto timestamp_diff =
+        std::chrono::duration_cast<std::chrono::microseconds>(
+              now - start_timestamp);
+    frame->set_timestamp_us(timestamp_diff.count());
+    frame->set_timestamp(timestamp_diff.count() * kRtpTicksPerUs);
+
+    std::vector<webrtc::VideoFrameType> types;
+    auto time_since_keyframe = now - last_keyframe_time;
+    const auto min_keyframe_time = std::chrono::seconds(10);
+    if (frames_since_keyframe > 60 || time_since_keyframe > min_keyframe_time) {
+      last_keyframe_time = now;
+      frames_since_keyframe = 0;
+      types.push_back(webrtc::VideoFrameType::kVideoFrameKey);
+    } else {
+      types.push_back(webrtc::VideoFrameType::kVideoFrameDelta);
+    }
+    auto rc = video_encoder_->Encode(*frame, &types);
+    if (rc != 0) {
+      LOG(ERROR) << "Failed to encode frame";
+    }
+  }
+}
+
+void LocalRecorder::Display::Stop() {
+  encoder_running_ = false;
+  encoder_queue_signal_.notify_all();
+  if (encoder_thread_.joinable()) {
+    encoder_thread_.join();
+  }
+}
+
+webrtc::EncodedImageCallback::Result LocalRecorder::Display::OnEncodedImage(
+    const webrtc::EncodedImage& encoded_image,
+    const webrtc::CodecSpecificInfo* codec_specific_info,
+    const webrtc::RTPFragmentationHeader* fragmentation) {
+  uint64_t timestamp = encoded_image.Timestamp() / kRtpTicksPerNs;
+
+  std::lock_guard(impl_.mkv_mutex_);
+
+  bool is_key =
+      encoded_image._frameType == webrtc::VideoFrameType::kVideoFrameKey;
+  bool success = impl_.segment_.AddFrame(
+      encoded_image.data(),
+      encoded_image.size(),
+      video_track_number_,
+      timestamp,
+      is_key);
+
+  webrtc::EncodedImageCallback::Result result(
+      success
+          ? webrtc::EncodedImageCallback::Result::Error::OK
+          : webrtc::EncodedImageCallback::Result::Error::ERROR_SEND_FAILED);
+
+  if (success) {
+    result.frame_id = encoded_image.Timestamp();
+  }
+  return result;
+}
+
+} // namespace webrtc_streaming
+} // namespace cuttlefish
+
diff --git a/host/frontend/webrtc/lib/local_recorder.h b/host/frontend/webrtc/lib/local_recorder.h
new file mode 100644
index 0000000..a18c978
--- /dev/null
+++ b/host/frontend/webrtc/lib/local_recorder.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <memory>
+#include <string>
+
+namespace webrtc {
+class VideoTrackSourceInterface;
+}
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class VideoTrackSourceImpl;
+
+class LocalRecorder {
+public:
+  ~LocalRecorder();
+
+  static std::unique_ptr<LocalRecorder> Create(const std::string& filename);
+
+  void AddDisplay(
+      size_t width,
+      size_t height,
+      std::shared_ptr<webrtc::VideoTrackSourceInterface> video);
+
+  void Stop();
+private:
+  class Display;
+  class Impl;
+
+  LocalRecorder(std::unique_ptr<Impl>);
+
+  std::unique_ptr<Impl> impl_;
+};
+
+} // namespace webrtc_streaming
+} // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/port_range_socket_factory.cpp b/host/frontend/webrtc/lib/port_range_socket_factory.cpp
new file mode 100644
index 0000000..c997cbc
--- /dev/null
+++ b/host/frontend/webrtc/lib/port_range_socket_factory.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/port_range_socket_factory.h"
+
+#include <android-base/logging.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+namespace {
+
+std::pair<uint16_t, uint16_t> IntersectPortRanges(
+    std::pair<uint16_t, uint16_t> own_range, uint16_t min_port,
+    uint16_t max_port) {
+  if (own_range.first == own_range.second && own_range.first == 0) {
+    // No range configured
+    return {min_port, max_port};
+  }
+  if (min_port == max_port && max_port == 0) {
+    // No range requested, use configured
+    return own_range;
+  }
+  uint16_t own_min_port = own_range.first;
+  uint16_t own_max_port = own_range.second;
+
+  if (min_port > own_max_port || max_port < own_min_port) {
+    // Ranges don't intersect
+    LOG(WARNING) << "Port ranges don't intersect: requested=[" << min_port
+                 << "," << max_port << "], configured=[" << own_min_port << ","
+                 << own_max_port << "]";
+  }
+  return {std::max(min_port, own_min_port), std::min(max_port, own_max_port)};
+}
+
+}  // namespace
+
+PortRangeSocketFactory::PortRangeSocketFactory(
+    rtc::Thread* thread, std::pair<uint16_t, uint16_t> udp_port_range,
+    std::pair<uint16_t, uint16_t> tcp_port_range)
+    : rtc::BasicPacketSocketFactory(thread),
+      udp_port_range_(udp_port_range),
+      tcp_port_range_(tcp_port_range) {}
+
+rtc::AsyncPacketSocket* PortRangeSocketFactory::CreateUdpSocket(
+    const rtc::SocketAddress& local_address, uint16_t min_port,
+    uint16_t max_port) {
+  auto port_range = IntersectPortRanges(udp_port_range_, min_port, max_port);
+  if (port_range.second < port_range.first) {
+    // Own range doesn't intersect with requested range
+    return nullptr;
+  }
+  return rtc::BasicPacketSocketFactory::CreateUdpSocket(
+      local_address, port_range.first, port_range.second);
+}
+
+rtc::AsyncPacketSocket* PortRangeSocketFactory::CreateServerTcpSocket(
+    const rtc::SocketAddress& local_address, uint16_t min_port,
+    uint16_t max_port, int opts) {
+  auto port_range = IntersectPortRanges(tcp_port_range_, min_port, max_port);
+  if (port_range.second < port_range.first) {
+    // Own range doesn't intersect with requested range
+    return nullptr;
+  }
+
+  return rtc::BasicPacketSocketFactory::CreateServerTcpSocket(
+      local_address, port_range.first, port_range.second, opts);
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/port_range_socket_factory.h b/host/frontend/webrtc/lib/port_range_socket_factory.h
new file mode 100644
index 0000000..c5a34a1
--- /dev/null
+++ b/host/frontend/webrtc/lib/port_range_socket_factory.h
@@ -0,0 +1,50 @@
+/*
+ * 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 <cinttypes>
+#include <utility>
+
+// This is not part of the webrtc api and therefore subject to change
+#include <p2p/base/basic_packet_socket_factory.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+// rtc::BasicPacketSocketFactory is not part of the webrtc api so only functions
+// from its upper class should be overridden here.
+class PortRangeSocketFactory : public rtc::BasicPacketSocketFactory {
+ public:
+  PortRangeSocketFactory(rtc::Thread* thread,
+                         std::pair<uint16_t, uint16_t> udp_port_range,
+                         std::pair<uint16_t, uint16_t> tcp_port_range);
+
+  rtc::AsyncPacketSocket* CreateUdpSocket(
+      const rtc::SocketAddress& local_address, uint16_t min_port,
+      uint16_t max_port) override;
+
+  rtc::AsyncPacketSocket* CreateServerTcpSocket(
+      const rtc::SocketAddress& local_address, uint16_t min_port,
+      uint16_t max_port, int opts) override;
+
+ private:
+  std::pair<uint16_t, uint16_t> udp_port_range_;
+  std::pair<uint16_t, uint16_t> tcp_port_range_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/streamer.cpp b/host/frontend/webrtc/lib/streamer.cpp
new file mode 100644
index 0000000..7fee1de
--- /dev/null
+++ b/host/frontend/webrtc/lib/streamer.cpp
@@ -0,0 +1,645 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/streamer.h"
+
+#include <android-base/logging.h>
+#include <json/json.h>
+
+#include <api/audio_codecs/audio_decoder_factory.h>
+#include <api/audio_codecs/audio_encoder_factory.h>
+#include <api/audio_codecs/builtin_audio_decoder_factory.h>
+#include <api/audio_codecs/builtin_audio_encoder_factory.h>
+#include <api/create_peerconnection_factory.h>
+#include <api/peer_connection_interface.h>
+#include <api/video_codecs/builtin_video_decoder_factory.h>
+#include <api/video_codecs/builtin_video_encoder_factory.h>
+#include <api/video_codecs/video_decoder_factory.h>
+#include <api/video_codecs/video_encoder_factory.h>
+#include <media/base/video_broadcaster.h>
+#include <pc/video_track_source.h>
+
+#include "host/frontend/webrtc/lib/audio_device.h"
+#include "host/frontend/webrtc/lib/audio_track_source_impl.h"
+#include "host/frontend/webrtc/lib/client_handler.h"
+#include "host/frontend/webrtc/lib/port_range_socket_factory.h"
+#include "host/frontend/webrtc/lib/video_track_source_impl.h"
+#include "host/frontend/webrtc/lib/vp8only_encoder_factory.h"
+#include "host/frontend/webrtc_operator/constants/signaling_constants.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+namespace {
+
+constexpr auto kStreamIdField = "stream_id";
+constexpr auto kXResField = "x_res";
+constexpr auto kYResField = "y_res";
+constexpr auto kDpiField = "dpi";
+constexpr auto kIsTouchField = "is_touch";
+constexpr auto kDisplaysField = "displays";
+constexpr auto kAudioStreamsField = "audio_streams";
+constexpr auto kHardwareField = "hardware";
+constexpr auto kControlPanelButtonCommand = "command";
+constexpr auto kControlPanelButtonTitle = "title";
+constexpr auto kControlPanelButtonIconName = "icon_name";
+constexpr auto kControlPanelButtonShellCommand = "shell_command";
+constexpr auto kControlPanelButtonDeviceStates = "device_states";
+constexpr auto kControlPanelButtonLidSwitchOpen = "lid_switch_open";
+constexpr auto kControlPanelButtonHingeAngleValue = "hinge_angle_value";
+constexpr auto kCustomControlPanelButtonsField = "custom_control_panel_buttons";
+
+void SendJson(WsConnection* ws_conn, const Json::Value& data) {
+  Json::StreamWriterBuilder factory;
+  auto data_str = Json::writeString(factory, data);
+  ws_conn->Send(reinterpret_cast<const uint8_t*>(data_str.c_str()),
+                data_str.size());
+}
+
+bool ParseMessage(const uint8_t* data, size_t length, Json::Value* msg_out) {
+  auto str = reinterpret_cast<const char*>(data);
+  Json::CharReaderBuilder builder;
+  std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
+  std::string errorMessage;
+  return json_reader->parse(str, str + length, msg_out, &errorMessage);
+}
+
+std::unique_ptr<rtc::Thread> CreateAndStartThread(const std::string& name) {
+  auto thread = rtc::Thread::CreateWithSocketServer();
+  if (!thread) {
+    LOG(ERROR) << "Failed to create " << name << " thread";
+    return nullptr;
+  }
+  thread->SetName(name, nullptr);
+  if (!thread->Start()) {
+    LOG(ERROR) << "Failed to start " << name << " thread";
+    return nullptr;
+  }
+  return thread;
+}
+
+struct DisplayDescriptor {
+  int width;
+  int height;
+  int dpi;
+  bool touch_enabled;
+  rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source;
+};
+
+struct ControlPanelButtonDescriptor {
+  std::string command;
+  std::string title;
+  std::string icon_name;
+  std::optional<std::string> shell_command;
+  std::vector<DeviceState> device_states;
+};
+
+// TODO (jemoreira): move to a place in common with the signaling server
+struct OperatorServerConfig {
+  std::vector<webrtc::PeerConnectionInterface::IceServer> servers;
+};
+
+// Wraps a scoped_refptr pointer to an audio device module
+class AudioDeviceModuleWrapper : public AudioSource {
+ public:
+  AudioDeviceModuleWrapper(
+      rtc::scoped_refptr<CfAudioDeviceModule> device_module)
+      : device_module_(device_module) {}
+  int GetMoreAudioData(void* data, int bytes_per_sample,
+                       int samples_per_channel, int num_channels,
+                       int sample_rate, bool& muted) override {
+    return device_module_->GetMoreAudioData(data, bytes_per_sample,
+                                            samples_per_channel, num_channels,
+                                            sample_rate, muted);
+  }
+
+  rtc::scoped_refptr<CfAudioDeviceModule> device_module() {
+    return device_module_;
+  }
+
+ private:
+  rtc::scoped_refptr<CfAudioDeviceModule> device_module_;
+};
+
+}  // namespace
+
+class Streamer::Impl : public WsConnectionObserver {
+ public:
+  std::shared_ptr<ClientHandler> CreateClientHandler(int client_id);
+
+  void SendMessageToClient(int client_id, const Json::Value& msg);
+  void DestroyClientHandler(int client_id);
+
+  // WsObserver
+  void OnOpen() override;
+  void OnClose() override;
+  void OnError(const std::string& error) override;
+  void OnReceive(const uint8_t* msg, size_t length, bool is_binary) override;
+
+  void HandleConfigMessage(const Json::Value& msg);
+  void HandleClientMessage(const Json::Value& server_message);
+
+  // All accesses to these variables happen from the signal_thread, so there is
+  // no need for extra synchronization mechanisms (mutex)
+  StreamerConfig config_;
+  OperatorServerConfig operator_config_;
+  std::shared_ptr<WsConnection> server_connection_;
+  std::shared_ptr<ConnectionObserverFactory> connection_observer_factory_;
+  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
+      peer_connection_factory_;
+  std::unique_ptr<rtc::Thread> network_thread_;
+  std::unique_ptr<rtc::Thread> worker_thread_;
+  std::unique_ptr<rtc::Thread> signal_thread_;
+  std::map<std::string, DisplayDescriptor> displays_;
+  std::map<std::string, rtc::scoped_refptr<AudioTrackSourceImpl>>
+      audio_sources_;
+  std::map<int, std::shared_ptr<ClientHandler>> clients_;
+  std::weak_ptr<OperatorObserver> operator_observer_;
+  std::map<std::string, std::string> hardware_;
+  std::vector<ControlPanelButtonDescriptor> custom_control_panel_buttons_;
+  std::shared_ptr<AudioDeviceModuleWrapper> audio_device_module_;
+};
+
+Streamer::Streamer(std::unique_ptr<Streamer::Impl> impl)
+    : impl_(std::move(impl)) {}
+
+/* static */
+std::unique_ptr<Streamer> Streamer::Create(
+    const StreamerConfig& cfg,
+    std::shared_ptr<ConnectionObserverFactory> connection_observer_factory) {
+
+  rtc::LogMessage::LogToDebug(rtc::LS_ERROR);
+
+  std::unique_ptr<Streamer::Impl> impl(new Streamer::Impl());
+  impl->config_ = cfg;
+  impl->connection_observer_factory_ = connection_observer_factory;
+
+  impl->network_thread_ = CreateAndStartThread("network-thread");
+  impl->worker_thread_ = CreateAndStartThread("work-thread");
+  impl->signal_thread_ = CreateAndStartThread("signal-thread");
+  if (!impl->network_thread_ || !impl->worker_thread_ ||
+      !impl->signal_thread_) {
+    return nullptr;
+  }
+
+  impl->audio_device_module_ = std::make_shared<AudioDeviceModuleWrapper>(
+      rtc::scoped_refptr<CfAudioDeviceModule>(
+          new rtc::RefCountedObject<CfAudioDeviceModule>()));
+
+  impl->peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
+      impl->network_thread_.get(), impl->worker_thread_.get(),
+      impl->signal_thread_.get(), impl->audio_device_module_->device_module(),
+      webrtc::CreateBuiltinAudioEncoderFactory(),
+      webrtc::CreateBuiltinAudioDecoderFactory(),
+      std::make_unique<VP8OnlyEncoderFactory>(
+          webrtc::CreateBuiltinVideoEncoderFactory()),
+      webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
+      nullptr /* audio_processing */);
+
+  if (!impl->peer_connection_factory_) {
+    LOG(ERROR) << "Failed to create peer connection factory";
+    return nullptr;
+  }
+
+  webrtc::PeerConnectionFactoryInterface::Options options;
+  // By default the loopback network is ignored, but generating candidates for
+  // it is useful when using TCP port forwarding.
+  options.network_ignore_mask = 0;
+  impl->peer_connection_factory_->SetOptions(options);
+
+  return std::unique_ptr<Streamer>(new Streamer(std::move(impl)));
+}
+
+std::shared_ptr<VideoSink> Streamer::AddDisplay(const std::string& label,
+                                                int width, int height, int dpi,
+                                                bool touch_enabled) {
+  // Usually called from an application thread
+  return impl_->signal_thread_->Invoke<std::shared_ptr<VideoSink>>(
+      RTC_FROM_HERE,
+      [this, &label, width, height, dpi,
+       touch_enabled]() -> std::shared_ptr<VideoSink> {
+        if (impl_->displays_.count(label)) {
+          LOG(ERROR) << "Display with same label already exists: " << label;
+          return nullptr;
+        }
+        rtc::scoped_refptr<VideoTrackSourceImpl> source(
+            new rtc::RefCountedObject<VideoTrackSourceImpl>(width, height));
+        impl_->displays_[label] = {width, height, dpi, touch_enabled, source};
+        return std::shared_ptr<VideoSink>(
+            new VideoTrackSourceImplSinkWrapper(source));
+      });
+}
+
+std::shared_ptr<AudioSink> Streamer::AddAudioStream(const std::string& label) {
+  // Usually called from an application thread
+  return impl_->signal_thread_->Invoke<std::shared_ptr<AudioSink>>(
+      RTC_FROM_HERE, [this, &label]() -> std::shared_ptr<AudioSink> {
+        if (impl_->audio_sources_.count(label)) {
+          LOG(ERROR) << "Audio stream with same label already exists: "
+                     << label;
+          return nullptr;
+        }
+        rtc::scoped_refptr<AudioTrackSourceImpl> source(
+            new rtc::RefCountedObject<AudioTrackSourceImpl>());
+        impl_->audio_sources_[label] = source;
+        return std::shared_ptr<AudioSink>(
+            new AudioTrackSourceImplSinkWrapper(source));
+      });
+}
+
+std::shared_ptr<AudioSource> Streamer::GetAudioSource() {
+  return impl_->audio_device_module_;
+}
+
+void Streamer::SetHardwareSpec(std::string key, std::string value) {
+  impl_->hardware_.emplace(key, value);
+}
+
+void Streamer::AddCustomControlPanelButton(const std::string& command,
+                                           const std::string& title,
+                                           const std::string& icon_name) {
+  ControlPanelButtonDescriptor button = {
+      .command = command, .title = title, .icon_name = icon_name};
+  impl_->custom_control_panel_buttons_.push_back(button);
+}
+
+void Streamer::AddCustomControlPanelButtonWithShellCommand(
+    const std::string& command, const std::string& title,
+    const std::string& icon_name, const std::string& shell_command) {
+  ControlPanelButtonDescriptor button = {
+      .command = command, .title = title, .icon_name = icon_name};
+  button.shell_command = shell_command;
+  impl_->custom_control_panel_buttons_.push_back(button);
+}
+
+void Streamer::AddCustomControlPanelButtonWithDeviceStates(
+    const std::string& command, const std::string& title,
+    const std::string& icon_name,
+    const std::vector<DeviceState>& device_states) {
+  ControlPanelButtonDescriptor button = {
+      .command = command, .title = title, .icon_name = icon_name};
+  button.device_states = device_states;
+  impl_->custom_control_panel_buttons_.push_back(button);
+}
+
+void Streamer::Register(std::weak_ptr<OperatorObserver> observer) {
+  // Usually called from an application thread
+  // No need to block the calling thread on this, the observer will be notified
+  // when the connection is established.
+  impl_->signal_thread_->PostTask(RTC_FROM_HERE, [this, observer]() {
+    impl_->operator_observer_ = observer;
+    // This can be a local variable since the connection object will keep a
+    // reference to it.
+    auto ws_context = WsConnectionContext::Create();
+    CHECK(ws_context) << "Failed to create websocket context";
+    impl_->server_connection_ = ws_context->CreateConnection(
+        impl_->config_.operator_server.port,
+        impl_->config_.operator_server.addr,
+        impl_->config_.operator_server.path,
+        impl_->config_.operator_server.security, impl_,
+        impl_->config_.operator_server.http_headers);
+
+    CHECK(impl_->server_connection_)
+        << "Unable to create websocket connection object";
+
+    impl_->server_connection_->Connect();
+  });
+}
+
+void Streamer::Unregister() {
+  // Usually called from an application thread.
+  impl_->signal_thread_->PostTask(
+      RTC_FROM_HERE, [this]() { impl_->server_connection_.reset(); });
+}
+
+void Streamer::RecordDisplays(LocalRecorder& recorder) {
+  for (auto& [key, display] : impl_->displays_) {
+    rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source =
+        display.source;
+    auto deleter = [](webrtc::VideoTrackSourceInterface* source) {
+      source->Release();
+    };
+    std::shared_ptr<webrtc::VideoTrackSourceInterface> source_shared(
+        source.release(), deleter);
+    recorder.AddDisplay(display.width, display.height, source_shared);
+  }
+}
+
+void Streamer::Impl::OnOpen() {
+  // Called from the websocket thread.
+  // Connected to operator.
+  signal_thread_->PostTask(RTC_FROM_HERE, [this]() {
+    Json::Value register_obj;
+    register_obj[cuttlefish::webrtc_signaling::kTypeField] =
+        cuttlefish::webrtc_signaling::kRegisterType;
+    register_obj[cuttlefish::webrtc_signaling::kDeviceIdField] =
+        config_.device_id;
+
+    Json::Value device_info;
+    Json::Value displays(Json::ValueType::arrayValue);
+    // No need to synchronize with other accesses to display_ because all
+    // happens on signal_thread.
+    for (auto& entry : displays_) {
+      Json::Value display;
+      display[kStreamIdField] = entry.first;
+      display[kXResField] = entry.second.width;
+      display[kYResField] = entry.second.height;
+      display[kDpiField] = entry.second.dpi;
+      display[kIsTouchField] = true;
+      displays.append(display);
+    }
+    device_info[kDisplaysField] = displays;
+    Json::Value audio_streams(Json::ValueType::arrayValue);
+    for (auto& entry : audio_sources_) {
+      Json::Value audio;
+      audio[kStreamIdField] = entry.first;
+      audio_streams.append(audio);
+    }
+    device_info[kAudioStreamsField] = audio_streams;
+    Json::Value hardware;
+    for (const auto& [k, v] : hardware_) {
+      hardware[k] = v;
+    }
+    device_info[kHardwareField] = hardware;
+    Json::Value custom_control_panel_buttons(Json::arrayValue);
+    for (const auto& button : custom_control_panel_buttons_) {
+      Json::Value button_entry;
+      button_entry[kControlPanelButtonCommand] = button.command;
+      button_entry[kControlPanelButtonTitle] = button.title;
+      button_entry[kControlPanelButtonIconName] = button.icon_name;
+      if (button.shell_command) {
+        button_entry[kControlPanelButtonShellCommand] = *(button.shell_command);
+      } else if (!button.device_states.empty()) {
+        Json::Value device_states(Json::arrayValue);
+        for (const DeviceState& device_state : button.device_states) {
+          Json::Value device_state_entry;
+          if (device_state.lid_switch_open) {
+            device_state_entry[kControlPanelButtonLidSwitchOpen] =
+                *device_state.lid_switch_open;
+          }
+          if (device_state.hinge_angle_value) {
+            device_state_entry[kControlPanelButtonHingeAngleValue] =
+                *device_state.hinge_angle_value;
+          }
+          device_states.append(device_state_entry);
+        }
+        button_entry[kControlPanelButtonDeviceStates] = device_states;
+      }
+      custom_control_panel_buttons.append(button_entry);
+    }
+    device_info[kCustomControlPanelButtonsField] = custom_control_panel_buttons;
+    register_obj[cuttlefish::webrtc_signaling::kDeviceInfoField] = device_info;
+    SendJson(server_connection_.get(), register_obj);
+    // Do this last as OnRegistered() is user code and may take some time to
+    // complete (although it shouldn't...)
+    auto observer = operator_observer_.lock();
+    if (observer) {
+      observer->OnRegistered();
+    }
+  });
+}
+
+void Streamer::Impl::OnClose() {
+  // Called from websocket thread
+  // The operator shouldn't close the connection with the client, it's up to the
+  // device to decide when to disconnect.
+  LOG(WARNING) << "Websocket closed unexpectedly";
+  signal_thread_->PostTask(RTC_FROM_HERE, [this]() {
+    auto observer = operator_observer_.lock();
+    if (observer) {
+      observer->OnClose();
+    }
+  });
+}
+
+void Streamer::Impl::OnError(const std::string& error) {
+  // Called from websocket thread.
+  LOG(ERROR) << "Error on connection with the operator: " << error;
+  signal_thread_->PostTask(RTC_FROM_HERE, [this]() {
+    auto observer = operator_observer_.lock();
+    if (observer) {
+      observer->OnError();
+    }
+  });
+}
+
+void Streamer::Impl::HandleConfigMessage(const Json::Value& server_message) {
+  CHECK(signal_thread_->IsCurrent())
+      << __FUNCTION__ << " called from the wrong thread";
+  if (server_message.isMember("ice_servers") &&
+      server_message["ice_servers"].isArray()) {
+    auto servers = server_message["ice_servers"];
+    operator_config_.servers.clear();
+    for (int server_idx = 0; server_idx < servers.size(); server_idx++) {
+      auto server = servers[server_idx];
+      webrtc::PeerConnectionInterface::IceServer ice_server;
+      if (!server.isMember("urls") || !server["urls"].isArray()) {
+        // The urls field is required
+        LOG(WARNING)
+            << "Invalid ICE server specification obtained from server: "
+            << server.toStyledString();
+        continue;
+      }
+      auto urls = server["urls"];
+      for (int url_idx = 0; url_idx < urls.size(); url_idx++) {
+        auto url = urls[url_idx];
+        if (!url.isString()) {
+          LOG(WARNING) << "Non string 'urls' field in ice server: "
+                       << url.toStyledString();
+          continue;
+        }
+        ice_server.urls.push_back(url.asString());
+        if (server.isMember("credential") && server["credential"].isString()) {
+          ice_server.password = server["credential"].asString();
+        }
+        if (server.isMember("username") && server["username"].isString()) {
+          ice_server.username = server["username"].asString();
+        }
+        operator_config_.servers.push_back(ice_server);
+      }
+    }
+  }
+}
+
+void Streamer::Impl::HandleClientMessage(const Json::Value& server_message) {
+  CHECK(signal_thread_->IsCurrent())
+      << __FUNCTION__ << " called from the wrong thread";
+  if (!server_message.isMember(cuttlefish::webrtc_signaling::kClientIdField) ||
+      !server_message[cuttlefish::webrtc_signaling::kClientIdField].isInt()) {
+    LOG(ERROR) << "Client message received without valid client id";
+    return;
+  }
+  auto client_id =
+      server_message[cuttlefish::webrtc_signaling::kClientIdField].asInt();
+  if (!server_message.isMember(cuttlefish::webrtc_signaling::kPayloadField)) {
+    LOG(WARNING) << "Received empty client message";
+    return;
+  }
+  auto client_message =
+      server_message[cuttlefish::webrtc_signaling::kPayloadField];
+  if (clients_.count(client_id) == 0) {
+    auto client_handler = CreateClientHandler(client_id);
+    if (!client_handler) {
+      LOG(ERROR) << "Failed to create a new client handler";
+      return;
+    }
+    clients_.emplace(client_id, client_handler);
+  }
+  auto client_handler = clients_[client_id];
+
+  client_handler->HandleMessage(client_message);
+}
+
+void Streamer::Impl::OnReceive(const uint8_t* msg, size_t length,
+                               bool is_binary) {
+  // Usually called from websocket thread.
+  Json::Value server_message;
+  // Once OnReceive returns the buffer can be destroyed/recycled at any time, so
+  // parse the data into a JSON object while still on the websocket thread.
+  if (is_binary || !ParseMessage(msg, length, &server_message)) {
+    LOG(ERROR) << "Received invalid JSON from server: '"
+               << (is_binary ? std::string("(binary_data)")
+                             : std::string(msg, msg + length))
+               << "'";
+    return;
+  }
+  // Transition to the signal thread before member variables are accessed.
+  signal_thread_->PostTask(RTC_FROM_HERE, [this, server_message]() {
+    if (!server_message.isMember(cuttlefish::webrtc_signaling::kTypeField) ||
+        !server_message[cuttlefish::webrtc_signaling::kTypeField].isString()) {
+      LOG(ERROR) << "No message_type field from server";
+      // Notify the caller
+      OnError(
+          "Invalid message received from operator: no message type field "
+          "present");
+      return;
+    }
+    auto type =
+        server_message[cuttlefish::webrtc_signaling::kTypeField].asString();
+    if (type == cuttlefish::webrtc_signaling::kConfigType) {
+      HandleConfigMessage(server_message);
+    } else if (type == cuttlefish::webrtc_signaling::kClientDisconnectType) {
+      if (!server_message.isMember(
+              cuttlefish::webrtc_signaling::kClientIdField) ||
+          !server_message.isMember(
+              cuttlefish::webrtc_signaling::kClientIdField)) {
+        LOG(ERROR) << "Invalid disconnect message received from server";
+        // Notify the caller
+        OnError("Invalid disconnect message: client_id is required");
+        return;
+      }
+      auto client_id =
+          server_message[cuttlefish::webrtc_signaling::kClientIdField].asInt();
+      LOG(INFO) << "Client " << client_id << " has disconnected.";
+      DestroyClientHandler(client_id);
+    } else if (type == cuttlefish::webrtc_signaling::kClientMessageType) {
+      HandleClientMessage(server_message);
+    } else {
+      LOG(ERROR) << "Unknown message type: " << type;
+      // Notify the caller
+      OnError("Invalid message received from operator: unknown message type");
+      return;
+    }
+  });
+}
+
+std::shared_ptr<ClientHandler> Streamer::Impl::CreateClientHandler(
+    int client_id) {
+  CHECK(signal_thread_->IsCurrent())
+      << __FUNCTION__ << " called from the wrong thread";
+  auto observer = connection_observer_factory_->CreateObserver();
+
+  auto client_handler = ClientHandler::Create(
+      client_id, observer,
+      [this, client_id](const Json::Value& msg) {
+        SendMessageToClient(client_id, msg);
+      },
+      [this, client_id] { DestroyClientHandler(client_id); });
+
+  webrtc::PeerConnectionInterface::RTCConfiguration config;
+  config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
+  config.enable_dtls_srtp = true;
+  config.servers.insert(config.servers.end(), operator_config_.servers.begin(),
+                        operator_config_.servers.end());
+  webrtc::PeerConnectionDependencies dependencies(client_handler.get());
+  // PortRangeSocketFactory's super class' constructor needs to be called on the
+  // network thread or have it as a parameter
+  dependencies.packet_socket_factory.reset(new PortRangeSocketFactory(
+      network_thread_.get(), config_.udp_port_range, config_.tcp_port_range));
+  auto peer_connection = peer_connection_factory_->CreatePeerConnection(
+      config, std::move(dependencies));
+
+  if (!peer_connection) {
+    LOG(ERROR) << "Failed to create peer connection";
+    return nullptr;
+  }
+
+  if (!client_handler->SetPeerConnection(std::move(peer_connection))) {
+    return nullptr;
+  }
+
+  for (auto& entry : displays_) {
+    auto& label = entry.first;
+    auto& video_source = entry.second.source;
+
+    auto video_track =
+        peer_connection_factory_->CreateVideoTrack(label, video_source.get());
+    client_handler->AddDisplay(video_track, label);
+  }
+
+  for (auto& entry : audio_sources_) {
+    auto& label = entry.first;
+    auto& audio_stream = entry.second;
+    auto audio_track =
+        peer_connection_factory_->CreateAudioTrack(label, audio_stream.get());
+    client_handler->AddAudio(audio_track, label);
+  }
+
+  return client_handler;
+}
+
+void Streamer::Impl::SendMessageToClient(int client_id,
+                                         const Json::Value& msg) {
+  LOG(VERBOSE) << "Sending to client: " << msg.toStyledString();
+  CHECK(signal_thread_->IsCurrent())
+      << __FUNCTION__ << " called from the wrong thread";
+  Json::Value wrapper;
+  wrapper[cuttlefish::webrtc_signaling::kPayloadField] = msg;
+  wrapper[cuttlefish::webrtc_signaling::kTypeField] =
+      cuttlefish::webrtc_signaling::kForwardType;
+  wrapper[cuttlefish::webrtc_signaling::kClientIdField] = client_id;
+  // This is safe to call from the webrtc threads because
+  // WsConnection is thread safe
+  SendJson(server_connection_.get(), wrapper);
+}
+
+void Streamer::Impl::DestroyClientHandler(int client_id) {
+  // Usually called from signal thread, could be called from websocket thread or
+  // an application thread.
+  signal_thread_->PostTask(RTC_FROM_HERE, [this, client_id]() {
+    // This needs to be 'posted' to the thread instead of 'invoked'
+    // immediately for two reasons:
+    // * The client handler is destroyed by this code, it's generally a
+    // bad idea (though not necessarily wrong) to return to a member
+    // function of a destroyed object.
+    // * The client handler may call this from within a peer connection
+    // observer callback, destroying the client handler there leads to a
+    // deadlock.
+    clients_.erase(client_id);
+  });
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/streamer.h b/host/frontend/webrtc/lib/streamer.h
new file mode 100644
index 0000000..0628e7d
--- /dev/null
+++ b/host/frontend/webrtc/lib/streamer.h
@@ -0,0 +1,130 @@
+/*
+ * 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 <functional>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "host/libs/config/custom_actions.h"
+
+#include "host/frontend/webrtc/lib/audio_sink.h"
+#include "host/frontend/webrtc/lib/audio_source.h"
+#include "host/frontend/webrtc/lib/connection_observer.h"
+#include "host/frontend/webrtc/lib/local_recorder.h"
+#include "host/frontend/webrtc/lib/video_sink.h"
+#include "host/frontend/webrtc/lib/ws_connection.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class ClientHandler;
+
+struct StreamerConfig {
+  // The id with which to register with the operator server.
+  std::string device_id;
+  struct {
+    // The ip address or domain name of the operator server.
+    std::string addr;
+    int port;
+    // The path component of the operator server's register url.
+    std::string path;
+    // The security level to use when connecting to the operator server.
+    WsConnection::Security security;
+    // A list of key value pairs to include as HTTP handshake headers when
+    // connecting to the operator.
+    std::vector<std::pair<std::string, std::string>> http_headers;
+  } operator_server;
+  // The port ranges webrtc is allowed to use.
+  // [0,0] means all ports
+  std::pair<uint16_t, uint16_t> udp_port_range = {15550, 15558};
+  std::pair<uint16_t, uint16_t> tcp_port_range = {15550, 15558};
+};
+
+class OperatorObserver {
+ public:
+  virtual ~OperatorObserver() = default;
+  // Called when the websocket connection with the operator is established.
+  virtual void OnRegistered() = 0;
+  // Called when the websocket connection with the operator is closed.
+  virtual void OnClose() = 0;
+  // Called when an error is encountered in the connection to the operator.
+  virtual void OnError() = 0;
+};
+
+class Streamer {
+ public:
+  // The observer_factory will be used to create an observer for every new
+  // client connection. Unregister() needs to be called to stop accepting
+  // connections.
+  static std::unique_ptr<Streamer> Create(
+      const StreamerConfig& cfg,
+      std::shared_ptr<ConnectionObserverFactory> factory);
+  ~Streamer() = default;
+
+  std::shared_ptr<VideoSink> AddDisplay(const std::string& label, int width,
+                                        int height, int dpi,
+                                        bool touch_enabled);
+
+  void SetHardwareSpec(std::string key, std::string value);
+
+  template <typename V>
+  void SetHardwareSpec(std::string key, V value) {
+    SetHardwareSpec(key, std::to_string(value));
+  }
+
+  std::shared_ptr<AudioSink> AddAudioStream(const std::string& label);
+  // Grants access to streams originating on the client side. If there are
+  // multiple streams (either because one client sends more than one or there
+  // are several clients) the audio will be mixed and provided as a single
+  // stream here.
+  std::shared_ptr<AudioSource> GetAudioSource();
+
+  // Add a custom button to the control panel.
+  void AddCustomControlPanelButton(const std::string& command,
+                                   const std::string& title,
+                                   const std::string& icon_name);
+  void AddCustomControlPanelButtonWithShellCommand(
+      const std::string& command, const std::string& title,
+      const std::string& icon_name, const std::string& shell_command);
+  void AddCustomControlPanelButtonWithDeviceStates(
+      const std::string& command, const std::string& title,
+      const std::string& icon_name,
+      const std::vector<DeviceState>& device_states);
+
+  // Register with the operator.
+  void Register(std::weak_ptr<OperatorObserver> operator_observer);
+  void Unregister();
+
+  void RecordDisplays(LocalRecorder& recorder);
+ private:
+  /*
+   * Private Implementation idiom.
+   * https://en.cppreference.com/w/cpp/language/pimpl
+   */
+  class Impl;
+
+  Streamer(std::unique_ptr<Impl> impl);
+  std::shared_ptr<Impl> impl_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/utils.cpp b/host/frontend/webrtc/lib/utils.cpp
new file mode 100644
index 0000000..78460c3
--- /dev/null
+++ b/host/frontend/webrtc/lib/utils.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/utils.h"
+
+#include <map>
+
+#include <json/json.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+namespace {
+
+std::string ValidateField(const Json::Value &obj, const std::string &type,
+                          const std::string &field_name,
+                          const Json::ValueType &field_type, bool required) {
+  if (!obj.isMember(field_name) && !required) {
+    return "";
+  }
+  if (!(obj.isMember(field_name) &&
+        obj[field_name].isConvertibleTo(field_type))) {
+    std::string error_msg = "Expected a field named '";
+    error_msg += field_name + "' of type '";
+    error_msg += std::to_string(field_type);
+    error_msg += "'";
+    if (!type.empty()) {
+      error_msg += " in message of type '" + type + "'";
+    }
+    error_msg += ".";
+    return error_msg;
+  }
+  return "";
+}
+
+}  // namespace
+
+ValidationResult ValidationResult::ValidateJsonObject(
+    const Json::Value &obj, const std::string &type,
+    const std::map<std::string, Json::ValueType> &required_fields,
+    const std::map<std::string, Json::ValueType> &optional_fields) {
+  for (const auto &field_spec : required_fields) {
+    auto result =
+        ValidateField(obj, type, field_spec.first, field_spec.second, true);
+    if (!result.empty()) {
+      return {result};
+    }
+  }
+  for (const auto &field_spec : optional_fields) {
+    auto result =
+        ValidateField(obj, type, field_spec.first, field_spec.second, false);
+    if (!result.empty()) {
+      return {result};
+    }
+  }
+  return {};
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/utils.h b/host/frontend/webrtc/lib/utils.h
new file mode 100644
index 0000000..169221c
--- /dev/null
+++ b/host/frontend/webrtc/lib/utils.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <map>
+#include <optional>
+
+#include <json/json.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class ValidationResult {
+ public:
+  ValidationResult() = default;
+  ValidationResult(const std::string &error) : error_(error) {}
+
+  // Helper method to ensure a json object has the required fields convertible
+  // to the appropriate types.
+  static ValidationResult ValidateJsonObject(
+      const Json::Value &obj, const std::string &type,
+      const std::map<std::string, Json::ValueType> &required_fields,
+      const std::map<std::string, Json::ValueType> &optional_fields = {});
+
+  bool ok() const { return !error_.has_value(); }
+  std::string error() const { return error_.value_or(""); }
+
+ private:
+  std::optional<std::string> error_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/video_frame_buffer.h b/host/frontend/webrtc/lib/video_frame_buffer.h
new file mode 100644
index 0000000..b824058
--- /dev/null
+++ b/host/frontend/webrtc/lib/video_frame_buffer.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <cinttypes>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class VideoFrameBuffer {
+ public:
+  virtual ~VideoFrameBuffer() = default;
+
+  virtual int width() const = 0;
+  virtual int height() const = 0;
+  virtual int StrideY() const = 0;
+  virtual int StrideU() const = 0;
+  virtual int StrideV() const = 0;
+  virtual const uint8_t* DataY() const = 0;
+  virtual const uint8_t* DataU() const = 0;
+  virtual const uint8_t* DataV() const = 0;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/video_sink.h b/host/frontend/webrtc/lib/video_sink.h
new file mode 100644
index 0000000..118a7c2
--- /dev/null
+++ b/host/frontend/webrtc/lib/video_sink.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <memory>
+
+#include "host/frontend/webrtc/lib/video_frame_buffer.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class VideoSink {
+ public:
+  virtual ~VideoSink() = default;
+  virtual void OnFrame(std::shared_ptr<VideoFrameBuffer> frame,
+                       int64_t timestamp_us) = 0;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/video_track_source_impl.cpp b/host/frontend/webrtc/lib/video_track_source_impl.cpp
new file mode 100644
index 0000000..6785e15
--- /dev/null
+++ b/host/frontend/webrtc/lib/video_track_source_impl.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/video_track_source_impl.h"
+
+#include <api/video/video_frame_buffer.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+namespace {
+
+class VideoFrameWrapper : public webrtc::I420BufferInterface {
+ public:
+  VideoFrameWrapper(
+      std::shared_ptr<::cuttlefish::webrtc_streaming::VideoFrameBuffer>
+          frame_buffer)
+      : frame_buffer_(frame_buffer) {}
+  ~VideoFrameWrapper() override = default;
+  // From VideoFrameBuffer
+  int width() const override { return frame_buffer_->width(); }
+  int height() const override { return frame_buffer_->height(); }
+
+  // From class PlanarYuvBuffer
+  int StrideY() const override { return frame_buffer_->StrideY(); }
+  int StrideU() const override { return frame_buffer_->StrideU(); }
+  int StrideV() const override { return frame_buffer_->StrideV(); }
+
+  // From class PlanarYuv8Buffer
+  const uint8_t *DataY() const override { return frame_buffer_->DataY(); }
+  const uint8_t *DataU() const override { return frame_buffer_->DataU(); }
+  const uint8_t *DataV() const override { return frame_buffer_->DataV(); }
+
+ private:
+  std::shared_ptr<::cuttlefish::webrtc_streaming::VideoFrameBuffer>
+      frame_buffer_;
+};
+
+}  // namespace
+
+VideoTrackSourceImpl::VideoTrackSourceImpl(int width, int height)
+    : webrtc::VideoTrackSource(false), width_(width), height_(height) {}
+
+void VideoTrackSourceImpl::OnFrame(std::shared_ptr<VideoFrameBuffer> frame,
+                                   int64_t timestamp_us) {
+  auto video_frame =
+      webrtc::VideoFrame::Builder()
+          .set_video_frame_buffer(
+              new rtc::RefCountedObject<VideoFrameWrapper>(frame))
+          .set_timestamp_us(timestamp_us)
+          .build();
+  broadcaster_.OnFrame(video_frame);
+}
+
+bool VideoTrackSourceImpl::GetStats(Stats *stats) {
+  stats->input_height = height_;
+  stats->input_width = width_;
+  return true;
+}
+
+bool VideoTrackSourceImpl::SupportsEncodedOutput() const { return false; }
+rtc::VideoSourceInterface<webrtc::VideoFrame> *VideoTrackSourceImpl::source() {
+  return &broadcaster_;
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/video_track_source_impl.h b/host/frontend/webrtc/lib/video_track_source_impl.h
new file mode 100644
index 0000000..b3861ac
--- /dev/null
+++ b/host/frontend/webrtc/lib/video_track_source_impl.h
@@ -0,0 +1,77 @@
+/*
+ * 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 <media/base/video_broadcaster.h>
+#include <pc/video_track_source.h>
+
+#include "host/frontend/webrtc/lib/video_sink.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class VideoTrackSourceImpl : public webrtc::VideoTrackSource {
+ public:
+  VideoTrackSourceImpl(int width, int height);
+
+  void OnFrame(std::shared_ptr<VideoFrameBuffer> frame, int64_t timestamp_us);
+
+  // Returns false if no stats are available, e.g, for a remote source, or a
+  // source which has not seen its first frame yet.
+  //
+  // Implementation should avoid blocking.
+  bool GetStats(Stats* stats) override;
+
+  bool SupportsEncodedOutput() const override;
+  void GenerateKeyFrame() override {}
+  void AddEncodedSink(
+      rtc::VideoSinkInterface<webrtc::RecordableEncodedFrame>* sink) override {}
+  void RemoveEncodedSink(
+      rtc::VideoSinkInterface<webrtc::RecordableEncodedFrame>* sink) override {}
+
+  rtc::VideoSourceInterface<webrtc::VideoFrame>* source() override;
+
+ private:
+  int width_;
+  int height_;
+  rtc::VideoBroadcaster broadcaster_;
+};
+
+// Wraps a VideoTrackSourceImpl as an implementation of the VideoSink interface.
+// This is needed as the VideoTrackSourceImpl is a reference counted object that
+// should only be referenced by rtc::scoped_refptr pointers, but the
+// VideoSink interface is not a reference counted object and therefore not
+// compatible with that kind of pointers. This class can be referenced by a
+// shared pointer and it in turn holds a scoped_refptr to the wrapped object.
+class VideoTrackSourceImplSinkWrapper : public VideoSink {
+ public:
+  virtual ~VideoTrackSourceImplSinkWrapper() = default;
+
+  VideoTrackSourceImplSinkWrapper(rtc::scoped_refptr<VideoTrackSourceImpl> obj)
+      : track_source_impl_(obj) {}
+
+  void OnFrame(std::shared_ptr<VideoFrameBuffer> frame,
+               int64_t timestamp_us) override {
+    track_source_impl_->OnFrame(frame, timestamp_us);
+  }
+
+ private:
+  rtc::scoped_refptr<VideoTrackSourceImpl> track_source_impl_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/vp8only_encoder_factory.cpp b/host/frontend/webrtc/lib/vp8only_encoder_factory.cpp
new file mode 100644
index 0000000..ef69cfa
--- /dev/null
+++ b/host/frontend/webrtc/lib/vp8only_encoder_factory.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include "host/frontend/webrtc/lib/vp8only_encoder_factory.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+VP8OnlyEncoderFactory::VP8OnlyEncoderFactory(
+    std::unique_ptr<webrtc::VideoEncoderFactory> inner)
+    : inner_(std::move(inner)) {}
+
+std::vector<webrtc::SdpVideoFormat> VP8OnlyEncoderFactory::GetSupportedFormats()
+    const {
+  std::vector<webrtc::SdpVideoFormat> ret;
+  // Allow only VP8
+  for (auto& format : inner_->GetSupportedFormats()) {
+    if (format.name == "VP8") {
+      ret.push_back(format);
+    }
+  }
+  return ret;
+}
+
+webrtc::VideoEncoderFactory::CodecInfo VP8OnlyEncoderFactory::QueryVideoEncoder(
+    const webrtc::SdpVideoFormat& format) const {
+  return inner_->QueryVideoEncoder(format);
+}
+
+std::unique_ptr<webrtc::VideoEncoder> VP8OnlyEncoderFactory::CreateVideoEncoder(
+    const webrtc::SdpVideoFormat& format) {
+  return inner_->CreateVideoEncoder(format);
+}
+
+std::unique_ptr<webrtc::VideoEncoderFactory::EncoderSelectorInterface>
+VP8OnlyEncoderFactory::GetEncoderSelector() const {
+  return inner_->GetEncoderSelector();
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/vp8only_encoder_factory.h b/host/frontend/webrtc/lib/vp8only_encoder_factory.h
new file mode 100644
index 0000000..fcbdaeb
--- /dev/null
+++ b/host/frontend/webrtc/lib/vp8only_encoder_factory.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <api/video_codecs/video_encoder_factory.h>
+#include <api/video_codecs/video_encoder.h>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class VP8OnlyEncoderFactory : public webrtc::VideoEncoderFactory {
+ public:
+  VP8OnlyEncoderFactory(std::unique_ptr<webrtc::VideoEncoderFactory> inner);
+
+  std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
+
+  CodecInfo QueryVideoEncoder(
+      const webrtc::SdpVideoFormat& format) const override;
+
+  std::unique_ptr<webrtc::VideoEncoder> CreateVideoEncoder(
+      const webrtc::SdpVideoFormat& format) override;
+
+  std::unique_ptr<EncoderSelectorInterface> GetEncoderSelector() const override;
+
+ private:
+  std::unique_ptr<webrtc::VideoEncoderFactory> inner_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/lib/ws_connection.cpp b/host/frontend/webrtc/lib/ws_connection.cpp
new file mode 100644
index 0000000..5303c21
--- /dev/null
+++ b/host/frontend/webrtc/lib/ws_connection.cpp
@@ -0,0 +1,446 @@
+//
+// 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
+//
+
+#include "host/frontend/webrtc/lib/ws_connection.h"
+
+#include <android-base/logging.h>
+#include <libwebsockets.h>
+
+class WsConnectionContextImpl;
+
+class WsConnectionImpl : public WsConnection,
+                         public std::enable_shared_from_this<WsConnectionImpl> {
+ public:
+  struct CreateConnectionSul {
+    lws_sorted_usec_list_t sul = {};
+    std::weak_ptr<WsConnectionImpl> weak_this;
+  };
+
+  WsConnectionImpl(
+      int port, const std::string& addr, const std::string& path,
+      Security secure,
+      const std::vector<std::pair<std::string, std::string>>& headers,
+      std::weak_ptr<WsConnectionObserver> observer,
+      std::shared_ptr<WsConnectionContextImpl> context);
+
+  ~WsConnectionImpl() override;
+
+  void Connect() override;
+  void ConnectInner();
+
+  bool Send(const uint8_t* data, size_t len, bool binary = false) override;
+
+  void OnError(const std::string& error);
+  void OnReceive(const uint8_t* data, size_t len, bool is_binary);
+  void OnOpen();
+  void OnClose();
+  void OnWriteable();
+
+  void AddHttpHeaders(unsigned char** p, unsigned char* end) const;
+
+ private:
+  struct WsBuffer {
+    WsBuffer() = default;
+    WsBuffer(const uint8_t* data, size_t len, bool binary)
+        : buffer_(LWS_PRE + len), is_binary_(binary) {
+      memcpy(&buffer_[LWS_PRE], data, len);
+    }
+
+    uint8_t* data() { return &buffer_[LWS_PRE]; }
+    bool is_binary() const { return is_binary_; }
+    size_t size() const { return buffer_.size() - LWS_PRE; }
+
+   private:
+    std::vector<uint8_t> buffer_;
+    bool is_binary_;
+  };
+
+  CreateConnectionSul extended_sul_;
+  struct lws* wsi_;
+  const int port_;
+  const std::string addr_;
+  const std::string path_;
+  const Security security_;
+  const std::vector<std::pair<std::string, std::string>> headers_;
+
+  std::weak_ptr<WsConnectionObserver> observer_;
+
+  // each element contains the data to be sent and whether it's binary or not
+  std::deque<WsBuffer> write_queue_;
+  std::mutex write_queue_mutex_;
+  // The connection object should not outlive the context object. This reference
+  // guarantees it.
+  std::shared_ptr<WsConnectionContextImpl> context_;
+};
+
+class WsConnectionContextImpl
+    : public WsConnectionContext,
+      public std::enable_shared_from_this<WsConnectionContextImpl> {
+ public:
+  WsConnectionContextImpl(struct lws_context* lws_ctx);
+  ~WsConnectionContextImpl() override;
+
+  std::shared_ptr<WsConnection> CreateConnection(
+      int port, const std::string& addr, const std::string& path,
+      WsConnection::Security secure,
+      std::weak_ptr<WsConnectionObserver> observer,
+      const std::vector<std::pair<std::string, std::string>>& headers) override;
+
+  void RememberConnection(void*, std::weak_ptr<WsConnectionImpl>);
+  void ForgetConnection(void*);
+  std::shared_ptr<WsConnectionImpl> GetConnection(void*);
+
+  struct lws_context* lws_context() {
+    return lws_context_;
+  }
+
+ private:
+  void Start();
+
+  std::map<void*, std::weak_ptr<WsConnectionImpl>> weak_by_ptr_;
+  std::mutex map_mutex_;
+  struct lws_context* lws_context_;
+  std::thread message_loop_;
+};
+
+int LwsCallback(struct lws* wsi, enum lws_callback_reasons reason, void* user,
+                void* in, size_t len);
+void CreateConnectionCallback(lws_sorted_usec_list_t* sul);
+
+namespace {
+
+constexpr char kProtocolName[] = "cf-webrtc-device";
+constexpr int kBufferSize = 65536;
+
+const uint32_t backoff_ms[] = {1000, 2000, 3000, 4000, 5000};
+
+const lws_retry_bo_t kRetry = {
+    .retry_ms_table = backoff_ms,
+    .retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms),
+    .conceal_count = LWS_ARRAY_SIZE(backoff_ms),
+
+    .secs_since_valid_ping = 3,    /* force PINGs after secs idle */
+    .secs_since_valid_hangup = 10, /* hangup after secs idle */
+
+    .jitter_percent = 20,
+};
+
+const struct lws_protocols kProtocols[2] = {
+    {kProtocolName, LwsCallback, 0, kBufferSize, 0, NULL, 0},
+    {NULL, NULL, 0, 0, 0, NULL, 0}};
+
+}  // namespace
+
+std::shared_ptr<WsConnectionContext> WsConnectionContext::Create() {
+  struct lws_context_creation_info context_info = {};
+  context_info.port = CONTEXT_PORT_NO_LISTEN;
+  context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+  context_info.protocols = kProtocols;
+  struct lws_context* lws_ctx = lws_create_context(&context_info);
+  if (!lws_ctx) {
+    return nullptr;
+  }
+  return std::shared_ptr<WsConnectionContext>(
+      new WsConnectionContextImpl(lws_ctx));
+}
+
+WsConnectionContextImpl::WsConnectionContextImpl(struct lws_context* lws_ctx)
+    : lws_context_(lws_ctx) {
+  Start();
+}
+
+WsConnectionContextImpl::~WsConnectionContextImpl() {
+  lws_context_destroy(lws_context_);
+  if (message_loop_.joinable()) {
+    message_loop_.join();
+  }
+}
+
+void WsConnectionContextImpl::Start() {
+  message_loop_ = std::thread([this]() {
+    for (;;) {
+      if (lws_service(lws_context_, 0) < 0) {
+        break;
+      }
+    }
+  });
+}
+
+std::shared_ptr<WsConnection> WsConnectionContextImpl::CreateConnection(
+    int port, const std::string& addr, const std::string& path,
+    WsConnection::Security security,
+    std::weak_ptr<WsConnectionObserver> observer,
+    const std::vector<std::pair<std::string, std::string>>& headers) {
+  return std::shared_ptr<WsConnection>(new WsConnectionImpl(
+      port, addr, path, security, headers, observer, shared_from_this()));
+}
+
+std::shared_ptr<WsConnectionImpl> WsConnectionContextImpl::GetConnection(
+    void* raw) {
+  std::shared_ptr<WsConnectionImpl> connection;
+  {
+    std::lock_guard<std::mutex> lock(map_mutex_);
+    if (weak_by_ptr_.count(raw) == 0) {
+      return nullptr;
+    }
+    connection = weak_by_ptr_[raw].lock();
+    if (!connection) {
+      weak_by_ptr_.erase(raw);
+    }
+  }
+  return connection;
+}
+
+void WsConnectionContextImpl::RememberConnection(
+    void* raw, std::weak_ptr<WsConnectionImpl> conn) {
+  std::lock_guard<std::mutex> lock(map_mutex_);
+  weak_by_ptr_.emplace(
+      std::pair<void*, std::weak_ptr<WsConnectionImpl>>(raw, conn));
+}
+
+void WsConnectionContextImpl::ForgetConnection(void* raw) {
+  std::lock_guard<std::mutex> lock(map_mutex_);
+  weak_by_ptr_.erase(raw);
+}
+
+WsConnectionImpl::WsConnectionImpl(
+    int port, const std::string& addr, const std::string& path,
+    Security security,
+    const std::vector<std::pair<std::string, std::string>>& headers,
+    std::weak_ptr<WsConnectionObserver> observer,
+    std::shared_ptr<WsConnectionContextImpl> context)
+    : port_(port),
+      addr_(addr),
+      path_(path),
+      security_(security),
+      headers_(headers),
+      observer_(observer),
+      context_(context) {}
+
+WsConnectionImpl::~WsConnectionImpl() {
+  context_->ForgetConnection(this);
+  // This will cause the callback to be called which will drop the connection
+  // after seeing the context doesn't remember this object
+  lws_callback_on_writable(wsi_);
+}
+
+void WsConnectionImpl::Connect() {
+  memset(&extended_sul_.sul, 0, sizeof(extended_sul_.sul));
+  extended_sul_.weak_this = weak_from_this();
+  lws_sul_schedule(context_->lws_context(), 0, &extended_sul_.sul,
+                   CreateConnectionCallback, 1);
+}
+
+void WsConnectionImpl::AddHttpHeaders(unsigned char** p,
+                                      unsigned char* end) const {
+  for (const auto& header_entry: headers_) {
+    const auto& name = header_entry.first;
+    const auto& value = header_entry.second;
+    auto res = lws_add_http_header_by_name(
+        wsi_, reinterpret_cast<const unsigned char*>(name.c_str()),
+        reinterpret_cast<const unsigned char*>(value.c_str()), value.size(), p,
+        end);
+    if (res != 0) {
+      LOG(ERROR) << "Unable to add header: " << name;
+    }
+  }
+  if (!headers_.empty()) {
+    // Let LWS know we added some headers.
+    lws_client_http_body_pending(wsi_, 1);
+  }
+}
+
+void WsConnectionImpl::OnError(const std::string& error) {
+  auto observer = observer_.lock();
+  if (observer) {
+    observer->OnError(error);
+  }
+}
+void WsConnectionImpl::OnReceive(const uint8_t* data, size_t len,
+                                 bool is_binary) {
+  auto observer = observer_.lock();
+  if (observer) {
+    observer->OnReceive(data, len, is_binary);
+  }
+}
+void WsConnectionImpl::OnOpen() {
+  auto observer = observer_.lock();
+  if (observer) {
+    observer->OnOpen();
+  }
+}
+void WsConnectionImpl::OnClose() {
+  auto observer = observer_.lock();
+  if (observer) {
+    observer->OnClose();
+  }
+}
+
+void WsConnectionImpl::OnWriteable() {
+  WsBuffer buffer;
+  {
+    std::lock_guard<std::mutex> lock(write_queue_mutex_);
+    if (write_queue_.size() == 0) {
+      return;
+    }
+    buffer = std::move(write_queue_.front());
+    write_queue_.pop_front();
+  }
+  auto flags = lws_write_ws_flags(
+      buffer.is_binary() ? LWS_WRITE_BINARY : LWS_WRITE_TEXT, true, true);
+  auto res = lws_write(wsi_, buffer.data(), buffer.size(),
+                       (enum lws_write_protocol)flags);
+  if (res != buffer.size()) {
+    LOG(WARNING) << "Unable to send the entire message!";
+  }
+}
+
+bool WsConnectionImpl::Send(const uint8_t* data, size_t len, bool binary) {
+  if (!wsi_) {
+    LOG(WARNING) << "Send called on an uninitialized connection!!";
+    return false;
+  }
+  WsBuffer buffer(data, len, binary);
+  {
+    std::lock_guard<std::mutex> lock(write_queue_mutex_);
+    write_queue_.emplace_back(std::move(buffer));
+  }
+
+  lws_callback_on_writable(wsi_);
+  return true;
+}
+
+int LwsCallback(struct lws* wsi, enum lws_callback_reasons reason, void* user,
+                void* in, size_t len) {
+  constexpr int DROP = -1;
+  constexpr int OK = 0;
+
+  // For some values of `reason`, `user` doesn't point to the value provided
+  // when the connection was created. This function object should be used with
+  // care.
+  auto with_connection =
+      [wsi, user](std::function<void(std::shared_ptr<WsConnectionImpl>)> cb) {
+        auto context = reinterpret_cast<WsConnectionContextImpl*>(user);
+        auto connection = context->GetConnection(wsi);
+        if (!connection) {
+          return DROP;
+        }
+        cb(connection);
+        return OK;
+      };
+
+  switch (reason) {
+    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+      return with_connection(
+          [in](std::shared_ptr<WsConnectionImpl> connection) {
+            connection->OnError(in ? (char*)in : "(null)");
+          });
+
+    case LWS_CALLBACK_CLIENT_RECEIVE:
+      return with_connection(
+          [in, len, wsi](std::shared_ptr<WsConnectionImpl> connection) {
+            connection->OnReceive((const uint8_t*)in, len,
+                                  lws_frame_is_binary(wsi));
+          });
+
+    case LWS_CALLBACK_CLIENT_ESTABLISHED:
+      return with_connection([](std::shared_ptr<WsConnectionImpl> connection) {
+        connection->OnOpen();
+      });
+
+    case LWS_CALLBACK_CLIENT_CLOSED:
+      return with_connection([](std::shared_ptr<WsConnectionImpl> connection) {
+        connection->OnClose();
+      });
+
+    case LWS_CALLBACK_CLIENT_WRITEABLE:
+      return with_connection([](std::shared_ptr<WsConnectionImpl> connection) {
+        connection->OnWriteable();
+      });
+
+    case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+      return with_connection(
+          [in, len](std::shared_ptr<WsConnectionImpl> connection) {
+            auto p = reinterpret_cast<unsigned char**>(in);
+            auto end = (*p) + len;
+            connection->AddHttpHeaders(p, end);
+          });
+
+    case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
+      // This callback is only called when we add additional HTTP headers, let
+      // LWS know we're done modifying the HTTP request.
+      lws_client_http_body_pending(wsi, 0);
+      return 0;
+
+    default:
+      LOG(VERBOSE) << "Unhandled value: " << reason;
+      return lws_callback_http_dummy(wsi, reason, user, in, len);
+  }
+}
+
+void CreateConnectionCallback(lws_sorted_usec_list_t* sul) {
+  std::shared_ptr<WsConnectionImpl> connection =
+      reinterpret_cast<WsConnectionImpl::CreateConnectionSul*>(sul)
+          ->weak_this.lock();
+  if (!connection) {
+    LOG(WARNING) << "The object was already destroyed by the time of the first "
+                 << "connection attempt. That's unusual.";
+    return;
+  }
+  connection->ConnectInner();
+}
+
+void WsConnectionImpl::ConnectInner() {
+  struct lws_client_connect_info connect_info;
+
+  memset(&connect_info, 0, sizeof(connect_info));
+
+  connect_info.context = context_->lws_context();
+  connect_info.port = port_;
+  connect_info.address = addr_.c_str();
+  connect_info.path = path_.c_str();
+  connect_info.host = connect_info.address;
+  connect_info.origin = connect_info.address;
+  switch (security_) {
+    case Security::kAllowSelfSigned:
+      connect_info.ssl_connection = LCCSCF_ALLOW_SELFSIGNED |
+                                    LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK |
+                                    LCCSCF_USE_SSL;
+      break;
+    case Security::kStrict:
+      connect_info.ssl_connection = LCCSCF_USE_SSL;
+      break;
+    case Security::kInsecure:
+      connect_info.ssl_connection = 0;
+      break;
+  }
+  connect_info.protocol = "webrtc-operator";
+  connect_info.local_protocol_name = kProtocolName;
+  connect_info.pwsi = &wsi_;
+  connect_info.retry_and_idle_policy = &kRetry;
+  // There is no guarantee the connection object still exists when the callback
+  // is called. Put the context instead as the user data which is guaranteed to
+  // still exist and holds a weak ptr to the connection.
+  connect_info.userdata = context_.get();
+
+  if (lws_client_connect_via_info(&connect_info)) {
+    // wsi_ is not initialized until after the call to
+    // lws_client_connect_via_info(). Luckily, this is guaranteed to run before
+    // the protocol callback is called because it runs in the same loop.
+    context_->RememberConnection(wsi_, weak_from_this());
+  } else {
+    LOG(ERROR) << "Connection failed!";
+  }
+}
diff --git a/host/frontend/webrtc/lib/ws_connection.h b/host/frontend/webrtc/lib/ws_connection.h
new file mode 100644
index 0000000..1c03265
--- /dev/null
+++ b/host/frontend/webrtc/lib/ws_connection.h
@@ -0,0 +1,72 @@
+//
+// 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
+//
+
+#pragma once
+
+#include <string.h>
+
+#include <deque>
+#include <functional>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <libwebsockets.h>
+
+class WsConnectionObserver {
+ public:
+  virtual ~WsConnectionObserver() = default;
+  virtual void OnOpen() = 0;
+  virtual void OnClose() = 0;
+  virtual void OnError(const std::string& error) = 0;
+  virtual void OnReceive(const uint8_t* msg, size_t length, bool is_binary) = 0;
+};
+
+class WsConnection {
+ public:
+  enum class Security {
+    kInsecure,
+    kAllowSelfSigned,
+    kStrict,
+  };
+
+  virtual ~WsConnection() = default;
+
+  virtual void Connect() = 0;
+
+  virtual bool Send(const uint8_t* data, size_t len, bool binary = false) = 0;
+
+ protected:
+  WsConnection() = default;
+};
+
+class WsConnectionContext {
+ public:
+  static std::shared_ptr<WsConnectionContext> Create();
+
+  virtual ~WsConnectionContext() = default;
+
+  virtual std::shared_ptr<WsConnection> CreateConnection(
+      int port, const std::string& addr, const std::string& path,
+      WsConnection::Security secure,
+      std::weak_ptr<WsConnectionObserver> observer,
+      const std::vector<std::pair<std::string, std::string>>& headers = {}) = 0;
+
+ protected:
+  WsConnectionContext() = default;
+};
diff --git a/host/frontend/webrtc/main.cpp b/host/frontend/webrtc/main.cpp
new file mode 100644
index 0000000..007c405
--- /dev/null
+++ b/host/frontend/webrtc/main.cpp
@@ -0,0 +1,360 @@
+/*
+ * 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.
+ */
+
+#include <linux/input.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+#include <libyuv.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/files.h"
+#include "host/frontend/webrtc/audio_handler.h"
+#include "host/frontend/webrtc/connection_observer.h"
+#include "host/frontend/webrtc/display_handler.h"
+#include "host/frontend/webrtc/kernel_log_events_handler.h"
+#include "host/frontend/webrtc/lib/local_recorder.h"
+#include "host/frontend/webrtc/lib/streamer.h"
+#include "host/libs/audio_connector/server.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/logging.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_server.h"
+#include "host/libs/screen_connector/screen_connector.h"
+
+DEFINE_int32(touch_fd, -1, "An fd to listen on for touch connections.");
+DEFINE_int32(keyboard_fd, -1, "An fd to listen on for keyboard connections.");
+DEFINE_int32(switches_fd, -1, "An fd to listen on for switch connections.");
+DEFINE_int32(frame_server_fd, -1, "An fd to listen on for frame updates");
+DEFINE_int32(kernel_log_events_fd, -1,
+             "An fd to listen on for kernel log events.");
+DEFINE_int32(command_fd, -1, "An fd to listen to for control messages");
+DEFINE_string(action_servers, "",
+              "A comma-separated list of server_name:fd pairs, "
+              "where each entry corresponds to one custom action server.");
+DEFINE_bool(write_virtio_input, true,
+            "Whether to send input events in virtio format.");
+DEFINE_int32(audio_server_fd, -1, "An fd to listen on for audio frames");
+
+using cuttlefish::AudioHandler;
+using cuttlefish::CfConnectionObserverFactory;
+using cuttlefish::DisplayHandler;
+using cuttlefish::KernelLogEventsHandler;
+using cuttlefish::webrtc_streaming::LocalRecorder;
+using cuttlefish::webrtc_streaming::Streamer;
+using cuttlefish::webrtc_streaming::StreamerConfig;
+
+class CfOperatorObserver
+    : public cuttlefish::webrtc_streaming::OperatorObserver {
+ public:
+  virtual ~CfOperatorObserver() = default;
+  virtual void OnRegistered() override {
+    LOG(VERBOSE) << "Registered with Operator";
+  }
+  virtual void OnClose() override {
+    LOG(ERROR) << "Connection with Operator unexpectedly closed";
+  }
+  virtual void OnError() override {
+    LOG(ERROR) << "Error encountered in connection with Operator";
+  }
+};
+
+static std::vector<std::pair<std::string, std::string>> ParseHttpHeaders(
+    const std::string& path) {
+  auto fd = cuttlefish::SharedFD::Open(path, O_RDONLY);
+  if (!fd->IsOpen()) {
+    LOG(WARNING) << "Unable to open operator (signaling server) headers file, "
+                    "connecting to the operator will probably fail: "
+                 << fd->StrError();
+    return {};
+  }
+  std::string raw_headers;
+  auto res = cuttlefish::ReadAll(fd, &raw_headers);
+  if (res < 0) {
+    LOG(WARNING) << "Unable to open operator (signaling server) headers file, "
+                    "connecting to the operator will probably fail: "
+                 << fd->StrError();
+    return {};
+  }
+  std::vector<std::pair<std::string, std::string>> headers;
+  std::size_t raw_index = 0;
+  while (raw_index < raw_headers.size()) {
+    auto colon_pos = raw_headers.find(':', raw_index);
+    if (colon_pos == std::string::npos) {
+      LOG(ERROR)
+          << "Expected to find ':' in each line of the operator headers file";
+      break;
+    }
+    auto eol_pos = raw_headers.find('\n', colon_pos);
+    if (eol_pos == std::string::npos) {
+      eol_pos = raw_headers.size();
+    }
+    // If the file uses \r\n as line delimiters exclude the \r too.
+    auto eov_pos = raw_headers[eol_pos - 1] == '\r'? eol_pos - 1: eol_pos;
+    headers.emplace_back(
+        raw_headers.substr(raw_index, colon_pos + 1 - raw_index),
+        raw_headers.substr(colon_pos + 1, eov_pos - colon_pos - 1));
+    raw_index = eol_pos + 1;
+  }
+  return headers;
+}
+
+std::unique_ptr<cuttlefish::AudioServer> CreateAudioServer() {
+  cuttlefish::SharedFD audio_server_fd =
+      cuttlefish::SharedFD::Dup(FLAGS_audio_server_fd);
+  close(FLAGS_audio_server_fd);
+  return std::make_unique<cuttlefish::AudioServer>(audio_server_fd);
+}
+
+int main(int argc, char** argv) {
+  cuttlefish::DefaultSubprocessLogging(argv);
+  ::gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+  cuttlefish::InputSockets input_sockets;
+
+  input_sockets.touch_server = cuttlefish::SharedFD::Dup(FLAGS_touch_fd);
+  input_sockets.keyboard_server = cuttlefish::SharedFD::Dup(FLAGS_keyboard_fd);
+  input_sockets.switches_server = cuttlefish::SharedFD::Dup(FLAGS_switches_fd);
+  auto control_socket = cuttlefish::SharedFD::Dup(FLAGS_command_fd);
+  close(FLAGS_touch_fd);
+  close(FLAGS_keyboard_fd);
+  close(FLAGS_switches_fd);
+  close(FLAGS_command_fd);
+  // Accepting on these sockets here means the device won't register with the
+  // operator as soon as it could, but rather wait until crosvm's input display
+  // devices have been initialized. That's OK though, because without those
+  // devices there is no meaningful interaction the user can have with the
+  // device.
+  input_sockets.touch_client =
+      cuttlefish::SharedFD::Accept(*input_sockets.touch_server);
+  input_sockets.keyboard_client =
+      cuttlefish::SharedFD::Accept(*input_sockets.keyboard_server);
+  input_sockets.switches_client =
+      cuttlefish::SharedFD::Accept(*input_sockets.switches_server);
+
+  std::thread touch_accepter([&input_sockets]() {
+    for (;;) {
+      input_sockets.touch_client =
+          cuttlefish::SharedFD::Accept(*input_sockets.touch_server);
+    }
+  });
+  std::thread keyboard_accepter([&input_sockets]() {
+    for (;;) {
+      input_sockets.keyboard_client =
+          cuttlefish::SharedFD::Accept(*input_sockets.keyboard_server);
+    }
+  });
+  std::thread switches_accepter([&input_sockets]() {
+    for (;;) {
+      input_sockets.switches_client =
+          cuttlefish::SharedFD::Accept(*input_sockets.switches_server);
+    }
+  });
+
+  auto kernel_log_events_client =
+      cuttlefish::SharedFD::Dup(FLAGS_kernel_log_events_fd);
+  close(FLAGS_kernel_log_events_fd);
+
+  auto cvd_config = cuttlefish::CuttlefishConfig::Get();
+  auto instance = cvd_config->ForDefaultInstance();
+  auto& host_mode_ctrl = cuttlefish::HostModeCtrl::Get();
+  auto screen_connector_ptr = cuttlefish::DisplayHandler::ScreenConnector::Get(
+      FLAGS_frame_server_fd, host_mode_ctrl);
+  auto& screen_connector = *(screen_connector_ptr.get());
+
+  // create confirmation UI service, giving host_mode_ctrl and
+  // screen_connector
+  // keep this singleton object alive until the webRTC process ends
+  static auto& host_confui_server =
+      cuttlefish::confui::HostServer::Get(host_mode_ctrl, screen_connector);
+
+  StreamerConfig streamer_config;
+
+  streamer_config.device_id = instance.webrtc_device_id();
+  streamer_config.tcp_port_range = cvd_config->webrtc_tcp_port_range();
+  streamer_config.udp_port_range = cvd_config->webrtc_udp_port_range();
+  streamer_config.operator_server.addr = cvd_config->sig_server_address();
+  streamer_config.operator_server.port = cvd_config->sig_server_port();
+  streamer_config.operator_server.path = cvd_config->sig_server_path();
+  streamer_config.operator_server.security =
+      cvd_config->sig_server_strict()
+          ? WsConnection::Security::kStrict
+          : WsConnection::Security::kAllowSelfSigned;
+
+  if (!cvd_config->sig_server_headers_path().empty()) {
+    streamer_config.operator_server.http_headers =
+        ParseHttpHeaders(cvd_config->sig_server_headers_path());
+  }
+
+  KernelLogEventsHandler kernel_logs_event_handler(kernel_log_events_client);
+  auto observer_factory = std::make_shared<CfConnectionObserverFactory>(
+      input_sockets, &kernel_logs_event_handler, host_confui_server);
+
+  auto streamer = Streamer::Create(streamer_config, observer_factory);
+  CHECK(streamer) << "Could not create streamer";
+
+  auto display_0 = streamer->AddDisplay(
+      "display_0", screen_connector.ScreenWidth(0),
+      screen_connector.ScreenHeight(0), cvd_config->dpi(), true);
+  auto display_handler = std::shared_ptr<DisplayHandler>(
+      new DisplayHandler(display_0, screen_connector));
+
+  std::unique_ptr<cuttlefish::webrtc_streaming::LocalRecorder> local_recorder;
+  if (cvd_config->record_screen()) {
+    int recording_num = 0;
+    std::string recording_path;
+    do {
+      recording_path = instance.PerInstancePath("recording/recording_");
+      recording_path += std::to_string(recording_num);
+      recording_path += ".webm";
+      recording_num++;
+    } while (cuttlefish::FileExists(recording_path));
+    local_recorder = LocalRecorder::Create(recording_path);
+    CHECK(local_recorder) << "Could not create local recorder";
+
+    streamer->RecordDisplays(*local_recorder);
+    display_handler->IncClientCount();
+  }
+
+  observer_factory->SetDisplayHandler(display_handler);
+
+  streamer->SetHardwareSpec("CPUs", cvd_config->cpus());
+  streamer->SetHardwareSpec("RAM", std::to_string(cvd_config->memory_mb()) + " mb");
+
+  std::string user_friendly_gpu_mode;
+  if (cvd_config->gpu_mode() == cuttlefish::kGpuModeGuestSwiftshader) {
+    user_friendly_gpu_mode = "SwiftShader (Guest CPU Rendering)";
+  } else if (cvd_config->gpu_mode() == cuttlefish::kGpuModeDrmVirgl) {
+    user_friendly_gpu_mode = "VirglRenderer (Accelerated Host GPU Rendering)";
+  } else if (cvd_config->gpu_mode() == cuttlefish::kGpuModeGfxStream) {
+    user_friendly_gpu_mode = "Gfxstream (Accelerated Host GPU Rendering)";
+  } else {
+    user_friendly_gpu_mode = cvd_config->gpu_mode();
+  }
+  streamer->SetHardwareSpec("GPU Mode", user_friendly_gpu_mode);
+
+  std::shared_ptr<AudioHandler> audio_handler;
+  if (cvd_config->enable_audio()) {
+    auto audio_stream = streamer->AddAudioStream("audio");
+    auto audio_server = CreateAudioServer();
+    auto audio_source = streamer->GetAudioSource();
+    audio_handler = std::make_shared<AudioHandler>(std::move(audio_server),
+                                                   audio_stream, audio_source);
+  }
+
+  // Parse the -action_servers flag, storing a map of action server name -> fd
+  std::map<std::string, int> action_server_fds;
+  for (const std::string& action_server :
+       android::base::Split(FLAGS_action_servers, ",")) {
+    if (action_server.empty()) {
+      continue;
+    }
+    const std::vector<std::string> server_and_fd =
+        android::base::Split(action_server, ":");
+    CHECK(server_and_fd.size() == 2)
+        << "Wrong format for action server flag: " << action_server;
+    std::string server = server_and_fd[0];
+    int fd = std::stoi(server_and_fd[1]);
+    action_server_fds[server] = fd;
+  }
+
+  for (const auto& custom_action : cvd_config->custom_actions()) {
+    if (custom_action.shell_command) {
+      if (custom_action.buttons.size() != 1) {
+        LOG(FATAL) << "Expected exactly one button for custom action command: "
+                   << *(custom_action.shell_command);
+      }
+      const auto button = custom_action.buttons[0];
+      streamer->AddCustomControlPanelButtonWithShellCommand(
+          button.command, button.title, button.icon_name,
+          *(custom_action.shell_command));
+    } else if (custom_action.server) {
+      if (action_server_fds.find(*(custom_action.server)) !=
+          action_server_fds.end()) {
+        LOG(INFO) << "Connecting to custom action server "
+                  << *(custom_action.server);
+
+        int fd = action_server_fds[*(custom_action.server)];
+        cuttlefish::SharedFD custom_action_server = cuttlefish::SharedFD::Dup(fd);
+        close(fd);
+
+        if (custom_action_server->IsOpen()) {
+          std::vector<std::string> commands_for_this_server;
+          for (const auto& button : custom_action.buttons) {
+            streamer->AddCustomControlPanelButton(button.command, button.title,
+                                                  button.icon_name);
+            commands_for_this_server.push_back(button.command);
+          }
+          observer_factory->AddCustomActionServer(custom_action_server,
+                                                  commands_for_this_server);
+        } else {
+          LOG(ERROR) << "Error connecting to custom action server: "
+                     << *(custom_action.server);
+        }
+      } else {
+        LOG(ERROR) << "Custom action server not provided as command line flag: "
+                   << *(custom_action.server);
+      }
+    } else if (!custom_action.device_states.empty()) {
+      if (custom_action.buttons.size() != 1) {
+        LOG(FATAL)
+            << "Expected exactly one button for custom action device states.";
+      }
+      const auto button = custom_action.buttons[0];
+      streamer->AddCustomControlPanelButtonWithDeviceStates(
+          button.command, button.title, button.icon_name,
+          custom_action.device_states);
+    }
+  }
+
+  std::shared_ptr<cuttlefish::webrtc_streaming::OperatorObserver> operator_observer(
+      new CfOperatorObserver());
+  streamer->Register(operator_observer);
+
+  std::thread control_thread([control_socket, &local_recorder]() {
+    if (!local_recorder) {
+      return;
+    }
+    std::string message = "_";
+    int read_ret;
+    while ((read_ret = cuttlefish::ReadExact(control_socket, &message)) > 0) {
+      LOG(VERBOSE) << "received control message: " << message;
+      if (message[0] == 'C') {
+        LOG(DEBUG) << "Finalizing screen recording...";
+        local_recorder->Stop();
+        LOG(INFO) << "Finalized screen recording.";
+        message = "Y";
+        cuttlefish::WriteAll(control_socket, message);
+      }
+    }
+    LOG(DEBUG) << "control socket closed";
+  });
+
+  if (audio_handler) {
+    audio_handler->Start();
+  }
+  host_confui_server.Start();
+  display_handler->Loop();
+
+  return 0;
+}
diff --git a/host/frontend/webrtc_operator/Android.bp b/host/frontend/webrtc_operator/Android.bp
new file mode 100644
index 0000000..54eda44
--- /dev/null
+++ b/host/frontend/webrtc_operator/Android.bp
@@ -0,0 +1,144 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_headers {
+    name: "webrtc_signaling_headers",
+    export_include_dirs: ["./constants"],
+    host_supported: true,
+}
+
+cc_binary_host {
+    name: "webrtc_operator",
+    srcs: [
+        "client_handler.cpp",
+        "device_registry.cpp",
+        "device_handler.cpp",
+        "device_list_handler.cpp",
+        "server_config.cpp",
+        "server.cpp",
+        "signal_handler.cpp",
+    ],
+    header_libs: [
+        "webrtc_signaling_headers",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcrypto",
+        "libjsoncpp",
+        "libssl",
+        "libcuttlefish_fs",
+    ],
+    static_libs: [
+        "libcap",
+        "libgflags",
+        "libcuttlefish_utils",
+        "libcuttlefish_host_config",
+        "libcuttlefish_host_websocket",
+        "libwebsockets",
+    ],
+    defaults: ["cuttlefish_buildhost_only"],
+}
+
+// TODO(jemoreira): Ideally these files should be in $HOST_OUT/webrtc but I
+// couldn't find a module type that would produce that, prebuilt_usr_share_host
+// is the next best thing for now.
+prebuilt_usr_share_host {
+    name: "webrtc_index.html",
+    src: "assets/index.html",
+    filename: "index.html",
+    sub_dir: "webrtc/assets",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_style.css",
+    src: "assets/style.css",
+    filename: "style.css",
+    sub_dir: "webrtc/assets",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_controls.css",
+    src: "assets/controls.css",
+    filename: "controls.css",
+    sub_dir: "webrtc/assets",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_adb.js",
+    src: "assets/js/adb.js",
+    filename: "adb.js",
+    sub_dir: "webrtc/assets/js",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_cf.js",
+    src: "assets/js/cf_webrtc.js",
+    filename: "cf_webrtc.js",
+    sub_dir: "webrtc/assets/js",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_app.js",
+    src: "assets/js/app.js",
+    filename: "app.js",
+    sub_dir: "webrtc/assets/js",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_controls.js",
+    src: "assets/js/controls.js",
+    filename: "controls.js",
+    sub_dir: "webrtc/assets/js",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_rootcanal.js",
+    src: "assets/js/rootcanal.js",
+    filename: "rootcanal.js",
+    sub_dir: "webrtc/assets/js",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_server.crt",
+    src: "certs/server.crt",
+    filename: "server.crt",
+    sub_dir: "webrtc/certs",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_server.key",
+    src: "certs/server.key",
+    filename: "server.key",
+    sub_dir: "webrtc/certs",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_server.p12",
+    src: "certs/server.p12",
+    filename: "server.p12",
+    sub_dir: "webrtc/certs",
+}
+
+prebuilt_usr_share_host {
+    name: "webrtc_trusted.pem",
+    src: "certs/trusted.pem",
+    filename: "trusted.pem",
+    sub_dir: "webrtc/certs",
+}
diff --git a/host/frontend/webrtc_operator/Readme.md b/host/frontend/webrtc_operator/Readme.md
new file mode 100644
index 0000000..df8b037
--- /dev/null
+++ b/host/frontend/webrtc_operator/Readme.md
@@ -0,0 +1,88 @@
+This signaling server defines a very simple protocol to allow the establishing
+of a WebRTC connection between clients and devices. It should only be used for
+development purposes or for very simple applications with no security, privacy
+or scalability requirements.
+
+Serious applications should build their own signaling server, implementing the
+protocol exactly as defined below (any modifications would likely require
+modifications to the client and/or device which will then not be maintained by
+the cuttlefish team).
+
+The signaling server MUST expose two (different) websocket endpoints:
+
+* wss://<addr>/register_device
+* wss://<addr>/connect_client
+
+Additional endpoints are allowed and are up to the specific applications.
+Extending the messages below with additional fields should be done with extreme
+care, prefixing the field names with an applciation specific word is strongly
+recommended. The same holds true for creating new message types.
+
+Devices connect to the *register_device* endpoint and send these types of
+messages:
+
+* {"message_type": "register", "device_id": <String>, "device_info": <Any>}
+
+* {"message_type": "forward", "client_id": <Integer>, "payload": <Any>}
+
+The server sends the device these types of messages:
+
+* {"message_type": "config", "ice_servers": <Array of IceServer dictionaries>,
+...}
+
+* {"message_type": "client_msg", "client_id": <Integer>, "payload": <Any>}
+
+* {"message_type": "client_disconnected", "client_id": <Integer>}
+
+* {"error": <String>}
+
+Clients connect to the *connect_client* endpoint and send these types of
+messages:
+
+* {"message_type": "connect", "device_id": <String>}
+
+* {"message_type": "forward", "payload": <Any>}
+
+The server sends the clients these types of messages:
+
+* {"message_type": "config", "ice_servers": <Array of IceServer dictionaries>,
+...}
+
+* {"message_type": "device_info", "device_info": <Any>}
+
+* {"message_type": "device_msg", "payload": <Any>}
+
+* {"error": <String>}
+
+A typical application flow looks like this:
+
+* **Device** connects to *register_device*
+
+* **Device** sends **register** message
+
+* **Server** sends **config** message to **Device**
+
+* **Client** connects to *connect_client*
+
+* **Client** sends **connect** message
+
+* **Server** sends **config** message to **Client**
+
+* **Server** sends **device_info** message to **Client**
+
+* **Client** sends **forward** message
+
+* **Server** sends **client_msg** message to **Device** (at this point the
+device knows about the client and cand send **forward** messages intended for
+it)
+
+* **Device** sends **forward** message
+
+* **Server** sends **device_msg** message to client
+
+* ...
+
+In an alternative flow, not supported by this implementation but allowed by the
+design, the **Client** connects first and only receives a **config** message
+from the **Server**, only after the **Device** has sent the **register** message
+the **Server** sends the **device_info** messaage to the **Client**.
diff --git a/host/frontend/webrtc_operator/assets/controls.css b/host/frontend/webrtc_operator/assets/controls.css
new file mode 100644
index 0000000..5bb0cce
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/controls.css
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+.toggle-control {
+  padding-left: 2px;
+  padding-right: 7px;
+  border-radius: 10px;
+  background-color: #5f6368; /* Google grey 700 */
+  width: 117px;
+  height: 64px;
+}
+
+.toggle-control .toggle-control-icon {
+  position: relative;
+  display: inline-block;
+  float: left;
+  font-size: 64px;
+  color: #e8eaed;
+}
+
+.toggle-control .toggle-control-switch {
+  position: relative;
+  display: inline-block;
+  float:left;
+  width: 52px;
+  height: 30px;
+  top: 17px;
+}
+
+.toggle-control .toggle-control-switch input {
+  opacity: 0;
+  width: 0;
+  height: 0;
+}
+
+.toggle-control .toggle-control-slider {
+  position: absolute;
+  cursor: pointer;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  -webkit-transition: .4s;
+  transition: .4s;
+  border-radius: 30px;
+  border: solid 5px;
+  border-color: #e8eaed;
+}
+
+.toggle-control .toggle-control-slider:before {
+  position: absolute;
+  content: "";
+  height: 18px;
+  width: 18px;
+  left: 1px;
+  bottom: 1px;
+  background-color: #e8eaed;
+  -webkit-transition: .4s;
+  transition: .4s;
+  border-radius: 50%;
+}
+
+.toggle-control input:checked + .toggle-control-slider {
+  background-color: #1c4587;
+}
+
+.toggle-control input:focus + .toggle-control-slider {
+  box-shadow: 0 0 1px #2196F3;
+}
+
+.toggle-control input:checked + .toggle-control-slider:before {
+  -webkit-transform: translateX(22px);
+  -ms-transform: translateX(22px);
+  transform: translateX(22px);
+}
diff --git a/host/frontend/webrtc_operator/assets/index.html b/host/frontend/webrtc_operator/assets/index.html
new file mode 100644
index 0000000..1eae893
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/index.html
@@ -0,0 +1,85 @@
+<?--
+ Copyright (C) 2019 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.
+ -->
+
+<html>
+    <head>
+        <title>My Virtual Device Playground</title>
+
+        <link rel="stylesheet" type="text/css" href="style.css" >
+        <link rel="stylesheet" type="text/css" href="controls.css" >
+        <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined">
+        <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
+    </head>
+
+    <body>
+      <section id='device-selector'>
+        <h1>Available devices <span id='refresh-list'>&#8635;</span></h1>
+        <ul id="device-list"></ul>
+      </section>
+      <section id='device-connection'>
+        <div id='header'>
+          <div id='app-controls'>
+            <div id="keyboard-capture-control" title="Capture Keyboard"></div>
+            <div id="mic-capture-control" title="Capture Microphone"></div>
+            <audio autoplay controls id="device-audio"></audio>
+          </div>
+          <div id='status-div'>
+            <h3 id='status-message' class='connecting'>Connecting to device</h3>
+          </div>
+        </div>
+        <div id='controls-and-screens'>
+          <div id='control-panel-default-buttons' class='control-panel-column'>
+            <button id='device-details-button' title='Device Details' class='material-icons'>
+              settings
+            </button>
+            <button id='bluetooth-console-button' title='Bluetooth console' class='material-icons'>
+              settings_bluetooth
+            </button>
+          </div>
+          <div id='control-panel-custom-buttons' class='control-panel-column'></div>
+          <div id='screens'>
+            <video id="device-screen" autoplay ></video>
+          </div>
+        </div>
+      </section>
+      <div id='device-details-modal' class='modal'>
+        <div id='device-details-modal-header' class='modal-header'>
+          <h2>Device Details</h2>
+          <button id='device-details-close' title='Close' class='material-icons modal-close'>close</button>
+        </div>
+        <hr>
+        <h3>Hardware Configuration</h3>
+        <span id='device-details-hardware'>unknown</span>
+      </div>
+      <div id='bluetooth-console-modal' class='modal'>
+        <div id='bluetooth-console-modal-header' class='modal-header'>
+          <h2>Bluetooth Console</h2>
+          <button id='bluetooth-console-close' title='Close' class='material-icons modal-close'>close</button>
+        </div>
+        <div>
+          <table>
+            <tr><td colspan='2'><textarea id='bluetooth-console-view' readonly rows='10' cols='60'></textarea></td></tr>
+            <tr><td width='1'><p id='bluetooth-console-cmd-label'>Command:</p></td><td width='100'><input id='bluetooth-console-input' type='text'></input></td></tr>
+          </table>
+        </div>
+      </div>
+       <script src="js/adb.js"></script>
+       <script src="js/rootcanal.js"></script>
+       <script src="js/cf_webrtc.js" type="module"></script>
+       <script src="js/controls.js"></script>
+       <script src="js/app.js"></script>
+    </body>
+</html>
diff --git a/host/frontend/webrtc_operator/assets/js/adb.js b/host/frontend/webrtc_operator/assets/js/adb.js
new file mode 100644
index 0000000..75540ae
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/js/adb.js
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+let adb_ws;
+
+let utf8Encoder = new TextEncoder();
+let utf8Decoder = new TextDecoder();
+
+const A_CNXN = 0x4e584e43;
+const A_OPEN = 0x4e45504f;
+const A_WRTE = 0x45545257;
+const A_OKAY = 0x59414b4f;
+
+const kLocalChannelId = 666;
+
+let array = new Uint8Array();
+
+function setU32LE(array, offset, x) {
+    array[offset] = x & 0xff;
+    array[offset + 1] = (x >> 8) & 0xff;
+    array[offset + 2] = (x >> 16) & 0xff;
+    array[offset + 3] = x >> 24;
+}
+
+function getU32LE(array, offset) {
+    let x = array[offset]
+        | (array[offset + 1] << 8)
+        | (array[offset + 2] << 16)
+        | (array[offset + 3] << 24);
+
+    return x >>> 0;  // convert signed to unsigned if necessary.
+}
+
+function computeChecksum(array) {
+    let sum = 0;
+    let i;
+    for (i = 0; i < array.length; ++i) {
+        sum = ((sum + array[i]) & 0xffffffff) >>> 0;
+    }
+
+    return sum;
+}
+
+function createAdbMessage(command, arg0, arg1, payload) {
+    let arrayBuffer = new ArrayBuffer(24 + payload.length);
+    let array = new Uint8Array(arrayBuffer);
+    setU32LE(array, 0, command);
+    setU32LE(array, 4, arg0);
+    setU32LE(array, 8, arg1);
+    setU32LE(array, 12, payload.length);
+    setU32LE(array, 16, computeChecksum(payload));
+    setU32LE(array, 20, command ^ 0xffffffff);
+    array.set(payload, 24);
+
+    return arrayBuffer;
+}
+
+function adbOpenConnection() {
+    let systemIdentity = utf8Encoder.encode("Cray_II:1234:whatever");
+
+    let arrayBuffer = createAdbMessage(
+        A_CNXN, 0x1000000, 256 * 1024, systemIdentity);
+
+    adb_ws.send(arrayBuffer);
+}
+
+function adbShell(command) {
+    let destination = utf8Encoder.encode("shell:" + command);
+
+    let arrayBuffer = createAdbMessage(A_OPEN, kLocalChannelId, 0, destination);
+    adb_ws.send(arrayBuffer);
+    awaitConnection();
+}
+
+function adbSendOkay(remoteId) {
+    let payload = new Uint8Array(0);
+
+    let arrayBuffer = createAdbMessage(
+        A_OKAY, kLocalChannelId, remoteId, payload);
+
+    adb_ws.send(arrayBuffer);
+}
+
+function JoinArrays(arr1, arr2) {
+  let arr = new Uint8Array(arr1.length + arr2.length);
+  arr.set(arr1, 0);
+  arr.set(arr2, arr1.length);
+  return arr;
+}
+
+// Simple lifecycle management that executes callbacks based on connection state.
+//
+// Any attempt to initiate a command (e.g. creating a connection, sending a message)
+// (re)starts a timer. Any response back from any command stops that timer.
+const timeoutMs = 3000;
+let connectedCb;
+let disconnectedCb;
+let disconnectedTimeout;
+function awaitConnection() {
+  clearTimeout(disconnectedTimeout);
+  if (disconnectedCb) {
+    disconnectedTimeout = setTimeout(disconnectedCb, timeoutMs);
+  }
+}
+function connected() {
+  if (disconnectedTimeout) {
+    clearTimeout(disconnectedTimeout);
+  }
+  if (connectedCb) {
+    connectedCb();
+  }
+}
+
+function adbOnMessage(arrayBuffer) {
+    // console.log("adb_ws: onmessage (" + arrayBuffer.byteLength + " bytes)");
+    array = JoinArrays(array, new Uint8Array(arrayBuffer));
+
+    while (array.length > 0) {
+        if (array.length < 24) {
+            // Incomplete package, must wait for more data.
+            return;
+        }
+
+        let command = getU32LE(array, 0);
+        let magic = getU32LE(array, 20);
+
+        if (command != ((magic ^ 0xffffffff) >>> 0)) {
+            console.log("command = " + command + ", magic = " + magic);
+            console.log("adb message command vs magic failed.");
+            return;
+        }
+
+        let payloadLength = getU32LE(array, 12);
+
+        if (array.length < 24 + payloadLength) {
+            // Incomplete package, must wait for more data.
+            return;
+        }
+
+        let payloadChecksum = getU32LE(array, 16);
+        let checksum = computeChecksum(array.slice(24));
+
+        if (payloadChecksum != checksum) {
+            console.log("adb message checksum mismatch.");
+            // This can happen if a shell command executes while another
+            // channel is receiving data.
+        }
+
+        switch (command) {
+            case A_CNXN:
+            {
+                console.log("WebRTC adb connected.");
+                connected();
+                break;
+            }
+
+            case A_OKAY:
+            {
+                let remoteId = getU32LE(array, 4);
+                console.log("WebRTC adb channel created w/ remoteId " + remoteId);
+                connected();
+                break;
+            }
+
+            case A_WRTE:
+            {
+                let remoteId = getU32LE(array, 4);
+                adbSendOkay(remoteId);
+                break;
+            }
+        }
+        array = array.subarray(24 + payloadLength, array.length);
+    }
+}
+
+function init_adb(devConn, ccb = connectedCb, dcb = disconnectedCb) {
+    if (adb_ws) return;
+
+    adb_ws = {
+      send: function(buffer) {
+        devConn.sendAdbMessage(buffer);
+      }
+    };
+    connectedCb = ccb;
+    disconnectedCb = dcb;
+    awaitConnection();
+
+    devConn.onAdbMessage(msg => adbOnMessage(msg));
+
+    adbOpenConnection();
+}
diff --git a/host/frontend/webrtc_operator/assets/js/app.js b/host/frontend/webrtc_operator/assets/js/app.js
new file mode 100644
index 0000000..441df00
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/js/app.js
@@ -0,0 +1,793 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+'use strict';
+
+function ConnectToDevice(device_id) {
+  console.log('ConnectToDevice ', device_id);
+  const keyboardCaptureCtrl = document.getElementById('keyboard-capture-control');
+  createToggleControl(keyboardCaptureCtrl, "keyboard", onKeyboardCaptureToggle);
+  const micCaptureCtrl = document.getElementById('mic-capture-control');
+  createToggleControl(micCaptureCtrl, "mic", onMicCaptureToggle);
+
+  const deviceScreen = document.getElementById('device-screen');
+  const deviceAudio = document.getElementById('device-audio');
+  const statusMessage = document.getElementById('status-message');
+
+  let connectionAttemptDuration = 0;
+  const intervalMs = 500;
+  let deviceStatusEllipsisCount = 0;
+  let animateDeviceStatusMessage = setInterval(function() {
+    connectionAttemptDuration += intervalMs;
+    if (connectionAttemptDuration > 30000) {
+      statusMessage.className = 'error';
+      statusMessage.textContent = 'Connection should have occurred by now. ' +
+          'Please attempt to restart the guest device.';
+    } else {
+      if (connectionAttemptDuration > 15000) {
+        statusMessage.textContent = 'Connection is taking longer than expected';
+      } else {
+        statusMessage.textContent = 'Connecting to device';
+      }
+      deviceStatusEllipsisCount = (deviceStatusEllipsisCount + 1) % 4;
+      statusMessage.textContent += '.'.repeat(deviceStatusEllipsisCount);
+    }
+  }, intervalMs);
+
+  deviceScreen.addEventListener('loadeddata', (evt) => {
+    clearInterval(animateDeviceStatusMessage);
+    statusMessage.textContent = 'Awaiting adb connection...';
+    resizeDeviceView();
+    deviceScreen.style.visibility = 'visible';
+    // Enable the buttons after the screen is visible.
+    for (const [_, button] of Object.entries(buttons)) {
+      if (!button.adb) {
+        button.button.disabled = false;
+      }
+    }
+    // Start the adb connection if it is not already started.
+    initializeAdb();
+  });
+
+  let videoStream;
+  let display_label;
+  let buttons = {};
+  let mouseIsDown = false;
+  let deviceConnection;
+  let touchIdSlotMap = new Map();
+  let touchSlots = new Array();
+  let deviceStateLidSwitchOpen = null;
+  let deviceStateHingeAngleValue = null;
+
+  function showAdbConnected() {
+    // Screen changed messages are not reported until after boot has completed.
+    // Certain default adb buttons change screen state, so wait for boot
+    // completion before enabling these buttons.
+    statusMessage.className = 'connected';
+    statusMessage.textContent =
+        'adb connection established successfully.';
+    setTimeout(function() {
+      statusMessage.style.visibility = 'hidden';
+    }, 5000);
+    for (const [_, button] of Object.entries(buttons)) {
+      if (button.adb) {
+        button.button.disabled = false;
+      }
+    }
+  }
+
+  function initializeAdb() {
+    init_adb(
+        deviceConnection,
+        showAdbConnected,
+        function() {
+          statusMessage.className = 'error';
+          statusMessage.textContent = 'adb connection failed.';
+          statusMessage.style.visibility = 'visible';
+          for (const [_, button] of Object.entries(buttons)) {
+            if (button.adb) {
+              button.button.disabled = true;
+            }
+          }
+        });
+  }
+
+  let currentRotation = 0;
+  let currentDisplayDetails;
+  function onControlMessage(message) {
+    let message_data = JSON.parse(message.data);
+    console.log(message_data)
+    let metadata = message_data.metadata;
+    if (message_data.event == 'VIRTUAL_DEVICE_BOOT_STARTED') {
+      // Start the adb connection after receiving the BOOT_STARTED message.
+      // (This is after the adbd start message. Attempting to connect
+      // immediately after adbd starts causes issues.)
+      initializeAdb();
+    }
+    if (message_data.event == 'VIRTUAL_DEVICE_SCREEN_CHANGED') {
+      if (metadata.rotation != currentRotation) {
+        // Animate the screen rotation.
+        deviceScreen.style.transition = 'transform 1s';
+      } else {
+        // Don't animate screen resizes, since these appear as odd sliding
+        // animations if the screen is rotated due to the translateY.
+        deviceScreen.style.transition = '';
+      }
+
+      currentRotation = metadata.rotation;
+      updateDeviceDisplayDetails({
+        dpi: metadata.dpi,
+        x_res: metadata.width,
+        y_res: metadata.height
+      });
+
+      resizeDeviceView();
+    }
+  }
+
+  const screensDiv = document.getElementById('screens');
+  function resizeDeviceView() {
+    // Auto-scale the screen based on window size.
+    // Max window width of 70%, allowing space for the control panel.
+    let ww = screensDiv.offsetWidth * 0.7;
+    let wh = screensDiv.offsetHeight;
+    let vw = currentDisplayDetails.x_res;
+    let vh = currentDisplayDetails.y_res;
+    let scaling = vw * wh > vh * ww ? ww / vw : wh / vh;
+    if (currentRotation == 0) {
+      deviceScreen.style.transform = null;
+      deviceScreen.style.width = vw * scaling;
+      deviceScreen.style.height = vh * scaling;
+    } else if (currentRotation == 1) {
+      deviceScreen.style.transform =
+          `rotateZ(-90deg) translateY(-${vh * scaling}px)`;
+      // When rotated, w and h are swapped.
+      deviceScreen.style.width = vh * scaling;
+      deviceScreen.style.height = vw * scaling;
+    }
+  }
+  window.onresize = resizeDeviceView;
+
+  function createControlPanelButton(command, title, icon_name,
+      listener=onControlPanelButton,
+      parent_id='control-panel-default-buttons') {
+    let button = document.createElement('button');
+    document.getElementById(parent_id).appendChild(button);
+    button.title = title;
+    button.dataset.command = command;
+    button.disabled = true;
+    // Capture mousedown/up/out commands instead of click to enable
+    // hold detection. mouseout is used to catch if the user moves the
+    // mouse outside the button while holding down.
+    button.addEventListener('mousedown', listener);
+    button.addEventListener('mouseup', listener);
+    button.addEventListener('mouseout', listener);
+    // Set the button image using Material Design icons.
+    // See http://google.github.io/material-design-icons
+    // and https://material.io/resources/icons
+    button.classList.add('material-icons');
+    button.innerHTML = icon_name;
+    buttons[command] = { 'button': button }
+    return buttons[command];
+  }
+  createControlPanelButton('power', 'Power', 'power_settings_new');
+  createControlPanelButton('home', 'Home', 'home');
+  createControlPanelButton('menu', 'Menu', 'menu');
+  createControlPanelButton('rotate', 'Rotate', 'screen_rotation', onRotateButton);
+  buttons['rotate'].adb = true;
+  createControlPanelButton('volumemute', 'Volume Mute', 'volume_mute');
+  createControlPanelButton('volumedown', 'Volume Down', 'volume_down');
+  createControlPanelButton('volumeup', 'Volume Up', 'volume_up');
+
+  let modalOffsets = {}
+  function createModalButton(button_id, modal_id, close_id) {
+    const modalButton = document.getElementById(button_id);
+    const modalDiv = document.getElementById(modal_id);
+    const modalHeader = modalDiv.querySelector('.modal-header');
+    const modalClose = document.getElementById(close_id);
+
+    // Position the modal to the right of the show modal button.
+    modalDiv.style.top = modalButton.offsetTop;
+    modalDiv.style.left = modalButton.offsetWidth + 30;
+
+    function showHideModal(show) {
+      if (show) {
+        modalButton.classList.add('modal-button-opened')
+        modalDiv.style.display = 'block';
+      } else {
+        modalButton.classList.remove('modal-button-opened')
+        modalDiv.style.display = 'none';
+      }
+    }
+    // Allow the show modal button to toggle the modal,
+    modalButton.addEventListener('click',
+        evt => showHideModal(modalDiv.style.display != 'block'));
+    // but the close button always closes.
+    modalClose.addEventListener('click',
+        evt => showHideModal(false));
+
+    // Allow the modal to be dragged by the header.
+    modalOffsets[modal_id] = {
+      midDrag: false,
+      mouseDownOffsetX: null,
+      mouseDownOffsetY: null,
+    }
+    modalHeader.addEventListener('mousedown',
+        evt => {
+            modalOffsets[modal_id].midDrag = true;
+            // Store the offset of the mouse location from the
+            // modal's current location.
+            modalOffsets[modal_id].mouseDownOffsetX =
+                parseInt(modalDiv.style.left) - evt.clientX;
+            modalOffsets[modal_id].mouseDownOffsetY =
+                parseInt(modalDiv.style.top) - evt.clientY;
+        });
+    modalHeader.addEventListener('mousemove',
+        evt => {
+            let offsets = modalOffsets[modal_id];
+            if (offsets.midDrag) {
+              // Move the modal to the mouse location plus the
+              // offset calculated on the initial mouse-down.
+              modalDiv.style.left =
+                  evt.clientX + offsets.mouseDownOffsetX;
+              modalDiv.style.top =
+                  evt.clientY + offsets.mouseDownOffsetY;
+            }
+        });
+    document.addEventListener('mouseup',
+        evt => {
+          modalOffsets[modal_id].midDrag = false;
+        });
+  }
+
+  createModalButton(
+    'device-details-button', 'device-details-modal', 'device-details-close');
+  createModalButton(
+    'bluetooth-console-button', 'bluetooth-console-modal', 'bluetooth-console-close');
+
+  let options = {
+    wsUrl: ((location.protocol == 'http:') ? 'ws://' : 'wss://') +
+      location.host + '/connect_client',
+  };
+
+  function showWebrtcError() {
+    statusMessage.className = 'error';
+    statusMessage.textContent = 'No connection to the guest device. ' +
+        'Please ensure the WebRTC process on the host machine is active.';
+    statusMessage.style.visibility = 'visible';
+    deviceScreen.style.display = 'none';
+    for (const [_, button] of Object.entries(buttons)) {
+      button.button.disabled = true;
+    }
+  }
+
+  import('./cf_webrtc.js')
+    .then(webrtcModule => webrtcModule.Connect(device_id, options))
+    .then(devConn => {
+      deviceConnection = devConn;
+      // TODO(b/143667633): get multiple display configuration from the
+      // description object
+      console.log(deviceConnection.description);
+      let stream_id = devConn.description.displays[0].stream_id;
+      devConn.getStream(stream_id).then(stream => {
+        videoStream = stream;
+        display_label = stream_id;
+        deviceScreen.srcObject = videoStream;
+      }).catch(e => console.error('Unable to get display stream: ', e));
+      for (const audio_desc of devConn.description.audio_streams) {
+        let stream_id = audio_desc.stream_id;
+        devConn.getStream(stream_id).then(stream => {
+          deviceAudio.srcObject = stream;
+        }).catch(e => console.error('Unable to get audio stream: ', e));
+      }
+      startMouseTracking();  // TODO stopMouseTracking() when disconnected
+      updateDeviceHardwareDetails(deviceConnection.description.hardware);
+      updateDeviceDisplayDetails(deviceConnection.description.displays[0]);
+      if (deviceConnection.description.custom_control_panel_buttons.length > 0) {
+        document.getElementById('control-panel-custom-buttons').style.display = 'flex';
+        for (const button of deviceConnection.description.custom_control_panel_buttons) {
+          if (button.shell_command) {
+            // This button's command is handled by sending an ADB shell command.
+            createControlPanelButton(button.command, button.title, button.icon_name,
+                e => onCustomShellButton(button.shell_command, e),
+                'control-panel-custom-buttons');
+            buttons[button.command].adb = true;
+          } else if (button.device_states) {
+            // This button corresponds to variable hardware device state(s).
+            createControlPanelButton(button.command, button.title, button.icon_name,
+                getCustomDeviceStateButtonCb(button.device_states),
+                'control-panel-custom-buttons');
+            for (const device_state of button.device_states) {
+              // hinge_angle is currently injected via an adb shell command that
+              // triggers a guest binary.
+              if ('hinge_angle_value' in device_state) {
+                buttons[button.command].adb = true;
+              }
+            }
+          } else {
+            // This button's command is handled by custom action server.
+            createControlPanelButton(button.command, button.title, button.icon_name,
+                onControlPanelButton,
+                'control-panel-custom-buttons');
+          }
+        }
+      }
+      deviceConnection.onControlMessage(msg => onControlMessage(msg));
+      // Start the screen as hidden. Only show when data is ready.
+      deviceScreen.style.visibility = 'hidden';
+      // Show the error message and disable buttons when the WebRTC connection fails.
+      deviceConnection.onConnectionStateChange(state => {
+        if (state == 'disconnected' || state == 'failed') {
+          showWebrtcError();
+        }
+      });
+      deviceConnection.onBluetoothMessage(msg => {
+        bluetoothConsole.addLine(decodeRootcanalMessage(msg));
+      });
+  }, rejection => {
+      console.error('Unable to connect: ', rejection);
+      showWebrtcError();
+  });
+
+  let hardwareDetailsText = '';
+  let displayDetailsText = '';
+  let deviceStateDetailsText = '';
+  function updateDeviceDetailsText() {
+    document.getElementById('device-details-hardware').textContent = [
+      hardwareDetailsText,
+      deviceStateDetailsText,
+      displayDetailsText,
+    ].filter(e => e /*remove empty*/).join('\n');
+  }
+  function updateDeviceHardwareDetails(hardware) {
+    let hardwareDetailsTextLines = [];
+    Object.keys(hardware).forEach(function(key) {
+      let value = hardware[key];
+      hardwareDetailsTextLines.push(`${key} - ${value}`);
+    });
+
+    hardwareDetailsText = hardwareDetailsTextLines.join('\n');
+    updateDeviceDetailsText();
+  }
+  function updateDeviceDisplayDetails(display) {
+    currentDisplayDetails = display;
+    let dpi = display.dpi;
+    let x_res = display.x_res;
+    let y_res = display.y_res;
+    let rotated = currentRotation == 1 ? ' (Rotated)' : '';
+    displayDetailsText = `Display - ${x_res}x${y_res} (${dpi}DPI)${rotated}`;
+    updateDeviceDetailsText();
+  }
+  function updateDeviceStateDetails() {
+    let deviceStateDetailsTextLines = [];
+    if (deviceStateLidSwitchOpen != null) {
+      let state = deviceStateLidSwitchOpen ? 'Opened' : 'Closed';
+      deviceStateDetailsTextLines.push(`Lid Switch - ${state}`);
+    }
+    if (deviceStateHingeAngleValue != null) {
+      deviceStateDetailsTextLines.push(`Hinge Angle - ${deviceStateHingeAngleValue}`);
+    }
+    deviceStateDetailsText = deviceStateDetailsTextLines.join('\n');
+    updateDeviceDetailsText();
+  }
+
+  function onKeyboardCaptureToggle(enabled) {
+    if (enabled) {
+      startKeyboardTracking();
+    } else {
+      stopKeyboardTracking();
+    }
+  }
+
+  function onMicCaptureToggle(enabled) {
+    deviceConnection.useMic(enabled);
+  }
+
+  function cmdConsole(consoleViewName, consoleInputName) {
+    let consoleView = document.getElementById(consoleViewName);
+
+    let addString = function(str) {
+      consoleView.value += str;
+      consoleView.scrollTop = consoleView.scrollHeight;
+    }
+
+    let addLine = function(line) {
+      addString(line + "\r\n");
+    }
+
+    let commandCallbacks = [];
+
+    let addCommandListener = function(f) {
+      commandCallbacks.push(f);
+    }
+
+    let onCommand = function(cmd) {
+      cmd = cmd.trim();
+
+      if (cmd.length == 0) return;
+
+      commandCallbacks.forEach(f => {
+        f(cmd);
+      })
+    }
+
+    addCommandListener(cmd => addLine(">> " + cmd));
+
+    let consoleInput = document.getElementById(consoleInputName);
+
+    consoleInput.addEventListener('keydown', e => {
+      if ((e.key && e.key == 'Enter') || e.keyCode == 13) {
+        let command = e.target.value;
+
+        e.target.value = '';
+
+        onCommand(command);
+      }
+    })
+
+    return {
+      consoleView: consoleView,
+      consoleInput: consoleInput,
+      addLine: addLine,
+      addString: addString,
+      addCommandListener: addCommandListener,
+    };
+  }
+
+  var bluetoothConsole = cmdConsole(
+    'bluetooth-console-view', 'bluetooth-console-input');
+
+  bluetoothConsole.addCommandListener(cmd => {
+    let inputArr = cmd.split(' ');
+    let command = inputArr[0];
+    inputArr.shift();
+    let args = inputArr;
+    deviceConnection.sendBluetoothMessage(createRootcanalMessage(command, args));
+  })
+
+  function onControlPanelButton(e) {
+    if (e.type == 'mouseout' && e.which == 0) {
+      // Ignore mouseout events if no mouse button is pressed.
+      return;
+    }
+    deviceConnection.sendControlMessage(JSON.stringify({
+      command: e.target.dataset.command,
+      button_state: e.type == 'mousedown' ? "down" : "up",
+    }));
+  }
+
+  function onRotateButton(e) {
+    // Attempt to init adb again, in case the initial connection failed.
+    // This succeeds immediately if already connected.
+    initializeAdb();
+    if (e.type == 'mousedown') {
+      adbShell(
+          '/vendor/bin/cuttlefish_sensor_injection rotate ' +
+          (currentRotation == 0 ? 'landscape' : 'portrait'))
+    }
+  }
+
+  function onCustomShellButton(shell_command, e) {
+    // Attempt to init adb again, in case the initial connection failed.
+    // This succeeds immediately if already connected.
+    initializeAdb();
+    if (e.type == 'mousedown') {
+      adbShell(shell_command);
+    }
+  }
+
+  function getCustomDeviceStateButtonCb(device_states) {
+    let states = device_states;
+    let index = 0;
+    return e => {
+      if (e.type == 'mousedown') {
+        // Reset any overridden device state.
+        adbShell('cmd device_state state reset');
+        // Send a device_state message for the current state.
+        let message = {
+          command: 'device_state',
+          ...states[index],
+        };
+        deviceConnection.sendControlMessage(JSON.stringify(message));
+        console.log(JSON.stringify(message));
+        if ('lid_switch_open' in states[index]) {
+          deviceStateLidSwitchOpen = states[index].lid_switch_open;
+        }
+        if ('hinge_angle_value' in states[index]) {
+          deviceStateHingeAngleValue = states[index].hinge_angle_value;
+          // TODO(b/181157794): Use a custom Sensor HAL for hinge_angle injection
+          // instead of this guest binary.
+          adbShell(
+              '/vendor/bin/cuttlefish_sensor_injection hinge_angle ' +
+              states[index].hinge_angle_value);
+        }
+        // Update the Device Details view.
+        updateDeviceStateDetails();
+        // Cycle to the next state.
+        index = (index + 1) % states.length;
+      }
+    }
+  }
+
+  function startMouseTracking() {
+    if (window.PointerEvent) {
+      deviceScreen.addEventListener('pointerdown', onStartDrag);
+      deviceScreen.addEventListener('pointermove', onContinueDrag);
+      deviceScreen.addEventListener('pointerup', onEndDrag);
+    } else if (window.TouchEvent) {
+      deviceScreen.addEventListener('touchstart', onStartDrag);
+      deviceScreen.addEventListener('touchmove', onContinueDrag);
+      deviceScreen.addEventListener('touchend', onEndDrag);
+    } else if (window.MouseEvent) {
+      deviceScreen.addEventListener('mousedown', onStartDrag);
+      deviceScreen.addEventListener('mousemove', onContinueDrag);
+      deviceScreen.addEventListener('mouseup', onEndDrag);
+    }
+  }
+
+  function stopMouseTracking() {
+    if (window.PointerEvent) {
+      deviceScreen.removeEventListener('pointerdown', onStartDrag);
+      deviceScreen.removeEventListener('pointermove', onContinueDrag);
+      deviceScreen.removeEventListener('pointerup', onEndDrag);
+    } else if (window.TouchEvent) {
+      deviceScreen.removeEventListener('touchstart', onStartDrag);
+      deviceScreen.removeEventListener('touchmove', onContinueDrag);
+      deviceScreen.removeEventListener('touchend', onEndDrag);
+    } else if (window.MouseEvent) {
+      deviceScreen.removeEventListener('mousedown', onStartDrag);
+      deviceScreen.removeEventListener('mousemove', onContinueDrag);
+      deviceScreen.removeEventListener('mouseup', onEndDrag);
+    }
+  }
+
+  function startKeyboardTracking() {
+    document.addEventListener('keydown', onKeyEvent);
+    document.addEventListener('keyup', onKeyEvent);
+  }
+
+  function stopKeyboardTracking() {
+    document.removeEventListener('keydown', onKeyEvent);
+    document.removeEventListener('keyup', onKeyEvent);
+  }
+
+  function onStartDrag(e) {
+    e.preventDefault();
+
+    // console.log("mousedown at " + e.pageX + " / " + e.pageY);
+    mouseIsDown = true;
+
+    sendEventUpdate(true, e);
+  }
+
+  function onEndDrag(e) {
+    e.preventDefault();
+
+    // console.log("mouseup at " + e.pageX + " / " + e.pageY);
+    mouseIsDown = false;
+
+    sendEventUpdate(false, e);
+  }
+
+  function onContinueDrag(e) {
+    e.preventDefault();
+
+    // console.log("mousemove at " + e.pageX + " / " + e.pageY + ", down=" +
+    // mouseIsDown);
+    if (mouseIsDown) {
+      sendEventUpdate(true, e);
+    }
+  }
+
+  function sendEventUpdate(down, e) {
+    console.assert(deviceConnection, 'Can\'t send mouse update without device');
+    var eventType = e.type.substring(0, 5);
+
+    // Before the first video frame arrives there is no way to know width and
+    // height of the device's screen, so turn every click into a click at 0x0.
+    // A click at that position is not more dangerous than anywhere else since
+    // the user is clicking blind anyways.
+    const videoWidth = deviceScreen.videoWidth? deviceScreen.videoWidth: 1;
+    const videoHeight = deviceScreen.videoHeight? deviceScreen.videoHeight: 1;
+    const elementWidth = deviceScreen.offsetWidth? deviceScreen.offsetWidth: 1;
+    const elementHeight = deviceScreen.offsetHeight? deviceScreen.offsetHeight: 1;
+
+    // vh*ew > eh*vw? then scale h instead of w
+    const scaleHeight = videoHeight * elementWidth > videoWidth * elementHeight;
+    var elementScaling = 0, videoScaling = 0;
+    if (scaleHeight) {
+      elementScaling = elementHeight;
+      videoScaling = videoHeight;
+    } else {
+      elementScaling = elementWidth;
+      videoScaling = videoWidth;
+    }
+
+    // The screen uses the 'object-fit: cover' property in order to completely
+    // fill the element while maintaining the screen content's aspect ratio.
+    // Therefore:
+    // - If vh*ew > eh*vw, w is scaled so that content width == element width
+    // - Otherwise,        h is scaled so that content height == element height
+    const scaleWidth = videoHeight * elementWidth > videoWidth * elementHeight;
+
+    // Convert to coordinates relative to the video by scaling.
+    // (This matches the scaling used by 'object-fit: cover'.)
+    //
+    // This scaling is needed to translate from the in-browser x/y to the
+    // on-device x/y.
+    //   - When the device screen has not been resized, this is simple: scale
+    //     the coordinates based on the ratio between the input video size and
+    //     the in-browser size.
+    //   - When the device screen has been resized, this scaling is still needed
+    //     even though the in-browser size and device size are identical. This
+    //     is due to the way WindowManager handles a resized screen, resized via
+    //     `adb shell wm size`:
+    //       - The ABS_X and ABS_Y max values of the screen retain their
+    //         original values equal to the value set when launching the device
+    //         (which equals the video size here).
+    //       - The sent ABS_X and ABS_Y values need to be scaled based on the
+    //         ratio between the max size (video size) and in-browser size.
+    const scaling = scaleWidth ? videoWidth / elementWidth : videoHeight / elementHeight;
+
+    var xArr = [];
+    var yArr = [];
+    var idArr = [];
+    var slotArr = [];
+
+    if (eventType == "mouse" || eventType == "point") {
+      xArr.push(e.offsetX);
+      yArr.push(e.offsetY);
+
+      let thisId = -1;
+      if (eventType == "point") {
+        thisId = e.pointerId;
+      }
+
+      slotArr.push(0);
+      idArr.push(thisId);
+    } else if (eventType == "touch") {
+      // touchstart: list of touch points that became active
+      // touchmove: list of touch points that changed
+      // touchend: list of touch points that were removed
+      let changes = e.changedTouches;
+      let rect = e.target.getBoundingClientRect();
+      for (var i=0; i < changes.length; i++) {
+        xArr.push(changes[i].pageX - rect.left);
+        yArr.push(changes[i].pageY - rect.top);
+        if (touchIdSlotMap.has(changes[i].identifier)) {
+          let slot = touchIdSlotMap.get(changes[i].identifier);
+
+          slotArr.push(slot);
+          if (e.type == 'touchstart') {
+            // error
+            console.error('touchstart when already have slot');
+            return;
+          } else if (e.type == 'touchmove') {
+            idArr.push(changes[i].identifier);
+          } else if (e.type == 'touchend') {
+            touchSlots[slot] = false;
+            touchIdSlotMap.delete(changes[i].identifier);
+            idArr.push(-1);
+          }
+        } else {
+          if (e.type == 'touchstart') {
+            let slot = -1;
+            for (var j=0; j < touchSlots.length; j++) {
+              if (!touchSlots[j]) {
+                slot = j;
+                break;
+              }
+            }
+            if (slot == -1) {
+              slot = touchSlots.length;
+              touchSlots.push(true);
+            }
+            slotArr.push(slot);
+            touchSlots[slot] = true;
+            touchIdSlotMap.set(changes[i].identifier, slot);
+            idArr.push(changes[i].identifier);
+          } else if (e.type == 'touchmove') {
+            // error
+            console.error('touchmove when no slot');
+            return;
+          } else if (e.type == 'touchend') {
+            // error
+            console.error('touchend when no slot');
+            return;
+          }
+        }
+      }
+    }
+
+    for (var i=0; i < xArr.length; i++) {
+      xArr[i] = xArr[i] * scaling;
+      yArr[i] = yArr[i] * scaling;
+
+      // Substract the offset produced by the difference in aspect ratio, if any.
+      if (scaleWidth) {
+        // Width was scaled, leaving excess content height, so subtract from y.
+        yArr[i] -= (elementHeight * scaling - videoHeight) / 2;
+      } else {
+        // Height was scaled, leaving excess content width, so subtract from x.
+        xArr[i] -= (elementWidth * scaling - videoWidth) / 2;
+      }
+
+      xArr[i] = Math.trunc(xArr[i]);
+      yArr[i] = Math.trunc(yArr[i]);
+    }
+
+    // NOTE: Rotation is handled automatically because the CSS rotation through
+    // transforms also rotates the coordinates of events on the object.
+
+    deviceConnection.sendMultiTouch(
+    {idArr, xArr, yArr, down, slotArr, display_label});
+  }
+
+  function onKeyEvent(e) {
+    e.preventDefault();
+    console.assert(deviceConnection, 'Can\'t send key event without device');
+    deviceConnection.sendKeyEvent(e.code, e.type);
+  }
+}
+
+/******************************************************************************/
+
+function ConnectDeviceCb(dev_id) {
+  console.log('Connect: ' + dev_id);
+  // Hide the device selection screen
+  document.getElementById('device-selector').style.display = 'none';
+  // Show the device control screen
+  document.getElementById('device-connection').style.visibility = 'visible';
+  ConnectToDevice(dev_id);
+}
+
+function ShowNewDeviceList(device_ids) {
+  let ul = document.getElementById('device-list');
+  ul.innerHTML = "";
+  let count = 1;
+  let device_to_button_map = {};
+  for (const dev_id of device_ids) {
+    const button_id = 'connect_' + count++;
+    ul.innerHTML += ('<li class="device_entry" title="Connect to ' + dev_id
+                     + '">' + dev_id + '<button id="' + button_id
+                     + '" >Connect</button></li>');
+    device_to_button_map[dev_id] = button_id;
+  }
+
+  for (const [dev_id, button_id] of Object.entries(device_to_button_map)) {
+    document.getElementById(button_id).addEventListener(
+        'click', evt => ConnectDeviceCb(dev_id));
+  }
+}
+
+function UpdateDeviceList() {
+  let url = ((location.protocol == 'http:') ? 'ws:' : 'wss:') + location.host +
+    '/list_devices';
+  let ws = new WebSocket(url);
+  ws.onopen = () => {
+    ws.send("give me those device ids");
+  };
+  ws.onmessage = msg => {
+   let device_ids = JSON.parse(msg.data);
+    ShowNewDeviceList(device_ids);
+  };
+}
+
+// Get any devices that are already connected
+UpdateDeviceList();
+// Update the list at the user's request
+document.getElementById('refresh-list')
+    .addEventListener('click', evt => UpdateDeviceList());
diff --git a/host/frontend/webrtc_operator/assets/js/cf_webrtc.js b/host/frontend/webrtc_operator/assets/js/cf_webrtc.js
new file mode 100644
index 0000000..c9d8213
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/js/cf_webrtc.js
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+function createDataChannel(pc, label, onMessage) {
+  console.log('creating data channel: ' + label);
+  let dataChannel = pc.createDataChannel(label);
+  // Return an object with a send function like that of the dataChannel, but
+  // that only actually sends over the data channel once it has connected.
+  return {
+    channelPromise: new Promise((resolve, reject) => {
+      dataChannel.onopen = (event) => {
+        resolve(dataChannel);
+      };
+      dataChannel.onclose = () => {
+        console.log(
+            'Data channel=' + label + ' state=' + dataChannel.readyState);
+      };
+      dataChannel.onmessage = onMessage ? onMessage : (msg) => {
+        console.log('Data channel=' + label + ' data="' + msg.data + '"');
+      };
+      dataChannel.onerror = err => {
+        reject(err);
+      };
+    }),
+    send: function(msg) {
+      this.channelPromise = this.channelPromise.then(channel => {
+        channel.send(msg);
+        return channel;
+      })
+    },
+  };
+}
+
+function awaitDataChannel(pc, label, onMessage) {
+  console.log('expecting data channel: ' + label);
+  // Return an object with a send function like that of the dataChannel, but
+  // that only actually sends over the data channel once it has connected.
+  return {
+    channelPromise: new Promise((resolve, reject) => {
+      let prev_ondatachannel = pc.ondatachannel;
+      pc.ondatachannel = ev => {
+        let dataChannel = ev.channel;
+        if (dataChannel.label == label) {
+          dataChannel.onopen = (event) => {
+            resolve(dataChannel);
+          };
+          dataChannel.onclose = () => {
+            console.log(
+                'Data channel=' + label + ' state=' + dataChannel.readyState);
+          };
+          dataChannel.onmessage = onMessage ? onMessage : (msg) => {
+            console.log('Data channel=' + label + ' data="' + msg.data + '"');
+          };
+          dataChannel.onerror = err => {
+            reject(err);
+          };
+        } else if (prev_ondatachannel) {
+          prev_ondatachannel(ev);
+        }
+      };
+    }),
+    send: function(msg) {
+      this.channelPromise = this.channelPromise.then(channel => {
+        channel.send(msg);
+        return channel;
+      })
+    },
+  };
+}
+
+class DeviceConnection {
+  constructor(pc, control, audio_stream) {
+    this._pc = pc;
+    this._control = control;
+    this._audio_stream = audio_stream;
+    // Disable the microphone by default
+    this.useMic(false);
+    this._inputChannel = createDataChannel(pc, 'input-channel');
+    this._adbChannel = createDataChannel(pc, 'adb-channel', (msg) => {
+      if (this._onAdbMessage) {
+        this._onAdbMessage(msg.data);
+      } else {
+        console.error('Received unexpected ADB message');
+      }
+    });
+    this._controlChannel = awaitDataChannel(pc, 'device-control', (msg) => {
+      if (this._onControlMessage) {
+        this._onControlMessage(msg);
+      } else {
+        console.error('Received unexpected Control message');
+      }
+    });
+    this._bluetoothChannel = createDataChannel(pc, 'bluetooth-channel', (msg) => {
+      if (this._onBluetoothMessage) {
+        this._onBluetoothMessage(msg.data);
+      } else {
+        console.error('Received unexpected Bluetooth message');
+      }
+    });
+    this._streams = {};
+    this._streamPromiseResolvers = {};
+
+    pc.addEventListener('track', e => {
+      console.log('Got remote stream: ', e);
+      for (const stream of e.streams) {
+        this._streams[stream.id] = stream;
+        if (this._streamPromiseResolvers[stream.id]) {
+          for (let resolver of this._streamPromiseResolvers[stream.id]) {
+            resolver();
+          }
+          delete this._streamPromiseResolvers[stream.id];
+        }
+      }
+    });
+  }
+
+  set description(desc) {
+    this._description = desc;
+  }
+
+  get description() {
+    return this._description;
+  }
+
+  getStream(stream_id) {
+    return new Promise((resolve, reject) => {
+      if (this._streams[stream_id]) {
+        resolve(this._streams[stream_id]);
+      } else {
+        if (!this._streamPromiseResolvers[stream_id]) {
+          this._streamPromiseResolvers[stream_id] = [];
+        }
+        this._streamPromiseResolvers[stream_id].push(resolve);
+      }
+    });
+  }
+
+  _sendJsonInput(evt) {
+    this._inputChannel.send(JSON.stringify(evt));
+  }
+
+  sendMousePosition({x, y, down, display_label}) {
+    this._sendJsonInput({
+      type: 'mouse',
+      down: down ? 1 : 0,
+      x,
+      y,
+      display_label,
+    });
+  }
+
+  // TODO (b/124121375): This should probably be an array of pointer events and
+  // have different properties.
+  sendMultiTouch({idArr, xArr, yArr, down, slotArr, display_label}) {
+    this._sendJsonInput({
+      type: 'multi-touch',
+      id: idArr,
+      x: xArr,
+      y: yArr,
+      down: down ? 1 : 0,
+      slot: slotArr,
+      display_label: display_label,
+    });
+  }
+
+  sendKeyEvent(code, type) {
+    this._sendJsonInput({type: 'keyboard', keycode: code, event_type: type});
+  }
+
+  disconnect() {
+    this._pc.close();
+  }
+
+  // Sends binary data directly to the in-device adb daemon (skipping the host)
+  sendAdbMessage(msg) {
+    this._adbChannel.send(msg);
+  }
+
+  // Provide a callback to receive data from the in-device adb daemon
+  onAdbMessage(cb) {
+    this._onAdbMessage = cb;
+  }
+
+  // Send control commands to the device
+  sendControlMessage(msg) {
+    this._controlChannel.send(msg);
+  }
+
+  useMic(in_use) {
+    if (this._audio_stream) {
+      this._audio_stream.getTracks().forEach(track => track.enabled = in_use);
+    }
+  }
+
+  // Provide a callback to receive control-related comms from the device
+  onControlMessage(cb) {
+    this._onControlMessage = cb;
+  }
+
+  sendBluetoothMessage(msg) {
+    this._bluetoothChannel.send(msg);
+  }
+
+  onBluetoothMessage(cb) {
+    this._onBluetoothMessage = cb;
+  }
+
+  // Provide a callback to receive connectionstatechange states.
+  onConnectionStateChange(cb) {
+    this._pc.addEventListener(
+      'connectionstatechange',
+      evt => cb(this._pc.connectionState));
+  }
+}
+
+
+class WebRTCControl {
+  constructor({
+    wsUrl = '',
+  }) {
+    /*
+     * Private attributes:
+     *
+     * _wsPromise: promises the underlying websocket, should resolve when the
+     *             socket passes to OPEN state, will be rejecte/replaced by a
+     *             rejected promise if an error is detected on the socket.
+     *
+     * _onOffer
+     * _onIceCandidate
+     */
+
+    this._promiseResolvers = {};
+
+    this._wsPromise = new Promise((resolve, reject) => {
+      let ws = new WebSocket(wsUrl);
+      ws.onopen = () => {
+        console.info(`Connected to ${wsUrl}`);
+        resolve(ws);
+      };
+      ws.onerror = evt => {
+        console.error('WebSocket error:', evt);
+        reject(evt);
+        // If the promise was already resolved the previous line has no effect
+        this._wsPromise = Promise.reject(new Error(evt));
+      };
+      ws.onmessage = e => {
+        let data = JSON.parse(e.data);
+        this._onWebsocketMessage(data);
+      };
+    });
+  }
+
+  _onWebsocketMessage(message) {
+    const type = message.message_type;
+    if (message.error) {
+      console.error(message.error);
+      this._on_connection_failed(message.error);
+      return;
+    }
+    switch (type) {
+      case 'config':
+        this._infra_config = message;
+        break;
+      case 'device_info':
+        if (this._on_device_available) {
+          this._on_device_available(message.device_info);
+          delete this._on_device_available;
+        } else {
+          console.error('Received unsolicited device info');
+        }
+        break;
+      case 'device_msg':
+        this._onDeviceMessage(message.payload);
+        break;
+      default:
+        console.error('Unrecognized message type from server: ', type);
+        this._on_connection_failed('Unrecognized message type from server: ' + type);
+        console.error(message);
+    }
+  }
+
+  _onDeviceMessage(message) {
+    let type = message.type;
+    switch (type) {
+      case 'offer':
+        if (this._onOffer) {
+          this._onOffer({type: 'offer', sdp: message.sdp});
+        } else {
+          console.error('Receive offer, but nothing is wating for it');
+        }
+        break;
+      case 'ice-candidate':
+        if (this._onIceCandidate) {
+          this._onIceCandidate(new RTCIceCandidate({
+            sdpMid: message.mid,
+            sdpMLineIndex: message.mLineIndex,
+            candidate: message.candidate
+          }));
+        } else {
+          console.error('Received ice candidate but nothing is waiting for it');
+        }
+        break;
+      default:
+        console.error('Unrecognized message type from device: ', type);
+    }
+  }
+
+  async _wsSendJson(obj) {
+    let ws = await this._wsPromise;
+    return ws.send(JSON.stringify(obj));
+  }
+  async _sendToDevice(payload) {
+    this._wsSendJson({message_type: 'forward', payload});
+  }
+
+  onOffer(cb) {
+    this._onOffer = cb;
+  }
+
+  onIceCandidate(cb) {
+    this._onIceCandidate = cb;
+  }
+
+  async requestDevice(device_id) {
+    return new Promise((resolve, reject) => {
+      this._on_device_available = (deviceInfo) => resolve({
+        deviceInfo,
+        infraConfig: this._infra_config,
+      });
+      this._on_connection_failed = (error) => reject(error);
+      this._wsSendJson({
+        message_type: 'connect',
+        device_id,
+      });
+    });
+  }
+
+  ConnectDevice() {
+    console.log('ConnectDevice');
+    this._sendToDevice({type: 'request-offer'});
+  }
+
+  /**
+   * Sends a remote description to the device.
+   */
+  async sendClientDescription(desc) {
+    console.log('sendClientDescription');
+    this._sendToDevice({type: 'answer', sdp: desc.sdp});
+  }
+
+  /**
+   * Sends an ICE candidate to the device
+   */
+  async sendIceCandidate(candidate) {
+    this._sendToDevice({type: 'ice-candidate', candidate});
+  }
+}
+
+function createPeerConnection(infra_config) {
+  let pc_config = {iceServers: []};
+  for (const stun of infra_config.ice_servers) {
+    pc_config.iceServers.push({urls: 'stun:' + stun});
+  }
+  let pc = new RTCPeerConnection(pc_config);
+
+  pc.addEventListener('icecandidate', evt => {
+    console.log('Local ICE Candidate: ', evt.candidate);
+  });
+  pc.addEventListener('iceconnectionstatechange', evt => {
+    console.log(`ICE State Change: ${pc.iceConnectionState}`);
+  });
+  pc.addEventListener(
+      'connectionstatechange',
+      evt =>
+          console.log(`WebRTC Connection State Change: ${pc.connectionState}`));
+  return pc;
+}
+
+export async function Connect(deviceId, options) {
+  let control = new WebRTCControl(options);
+  let requestRet = await control.requestDevice(deviceId);
+  let deviceInfo = requestRet.deviceInfo;
+  let infraConfig = requestRet.infraConfig;
+  console.log('Device available:');
+  console.log(deviceInfo);
+  let pc_config = {iceServers: []};
+  if (infraConfig.ice_servers && infraConfig.ice_servers.length > 0) {
+    for (const server of infraConfig.ice_servers) {
+      pc_config.iceServers.push(server);
+    }
+  }
+  let pc = createPeerConnection(infraConfig, control);
+
+  let audioStream;
+  try {
+    audioStream =
+        await navigator.mediaDevices.getUserMedia({video: false, audio: true});
+    const audioTracks = audioStream.getAudioTracks();
+    if (audioTracks.length > 0) {
+      console.log(`Using Audio device: ${audioTracks[0].label}, with ${
+        audioTracks.length} tracks`);
+      audioTracks.forEach(track => pc.addTrack(track, audioStream));
+    }
+  } catch (e) {
+    console.error("Failed to open audio device: ", e);
+  }
+
+  let deviceConnection = new DeviceConnection(pc, control, audioStream);
+  deviceConnection.description = deviceInfo;
+  async function acceptOfferAndReplyAnswer(offer) {
+    try {
+      await pc.setRemoteDescription(offer);
+      let answer = await pc.createAnswer();
+      console.log('Answer: ', answer);
+      await pc.setLocalDescription(answer);
+      await control.sendClientDescription(answer);
+    } catch (e) {
+      console.error('Error establishing WebRTC connection: ', e)
+      throw e;
+    }
+  }
+  control.onOffer(desc => {
+    console.log('Offer: ', desc);
+    acceptOfferAndReplyAnswer(desc);
+  });
+  control.onIceCandidate(iceCandidate => {
+    console.log(`Remote ICE Candidate: `, iceCandidate);
+    pc.addIceCandidate(iceCandidate);
+  });
+
+  pc.addEventListener('icecandidate', evt => {
+    if (evt.candidate) control.sendIceCandidate(evt.candidate);
+  });
+  let connected_promise = new Promise((resolve, reject) => {
+    pc.addEventListener('connectionstatechange', evt => {
+      let state = pc.connectionState;
+      if (state == 'connected') {
+        resolve(deviceConnection);
+      } else if (state == 'failed') {
+        reject(evt);
+      }
+    });
+  });
+  control.ConnectDevice();
+
+  return connected_promise;
+}
diff --git a/host/frontend/webrtc_operator/assets/js/controls.js b/host/frontend/webrtc_operator/assets/js/controls.js
new file mode 100644
index 0000000..31db046
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/js/controls.js
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+function createToggleControl(elm, iconName, onChangeCb) {
+  let icon = document.createElement("span");
+  icon.classList.add("toggle-control-icon");
+  icon.classList.add("material-icons-outlined");
+  if (iconName) {
+    icon.appendChild(document.createTextNode(iconName));
+  }
+  elm.appendChild(icon);
+  let toggle = document.createElement("label");
+  toggle.classList.add("toggle-control-switch");
+  let input = document.createElement("input");
+  input.type = "checkbox";
+  toggle.appendChild(input);
+  let slider = document.createElement("span");
+  slider.classList.add("toggle-control-slider");
+  toggle.appendChild(slider);
+  elm.classList.add("toggle-control");
+  elm.appendChild(toggle);
+  if (onChangeCb) {
+    input.onchange = e => onChangeCb(e.target.checked);
+  }
+}
diff --git a/host/frontend/webrtc_operator/assets/js/rootcanal.js b/host/frontend/webrtc_operator/assets/js/rootcanal.js
new file mode 100644
index 0000000..4443bcd
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/js/rootcanal.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+'use strict';
+
+function rootCanalCalculateMessageSize(name, args) {
+  let result = 0;
+
+  result += 1 + name.length; // length of name + it's data
+  result += 1; // count of args
+
+  for(let i = 0; i < args.length; i++) {
+    result += 1; // length of args[i]
+    result += args[i].length; // data of args[i]
+  }
+
+  return result;
+}
+
+function rootCanalAddU8(array, pos, val) {
+  array[pos] = val & 0xff;
+
+  return pos + 1;
+}
+
+function rootCanalAddPayload(array, pos, payload) {
+  array.set(payload, pos);
+
+  return pos + payload.length;
+}
+
+function rootCanalAddString(array, pos, val) {
+  let curPos = pos;
+
+  curPos = rootCanalAddU8(array, curPos, val.length);
+
+  return rootCanalAddPayload(array, curPos, utf8Encoder.encode(val));
+}
+
+function createRootcanalMessage(command, args) {
+  let messageSize = rootCanalCalculateMessageSize(command, args);
+  let arrayBuffer = new ArrayBuffer(messageSize);
+  let array = new Uint8Array(arrayBuffer);
+  let pos = 0;
+
+  pos = rootCanalAddString(array, pos, command);
+  pos = rootCanalAddU8(array, pos, args.length);
+
+  for(let i = 0; i < args.length; i++) {
+    pos = rootCanalAddString(array, pos, args[i]);
+  }
+
+  return array;
+}
+
+function decodeRootcanalMessage(array) {
+  let size = array[0];
+  let message = array.slice(1);
+
+  return utf8Decoder.decode(message);
+}
\ No newline at end of file
diff --git a/host/frontend/webrtc_operator/assets/style.css b/host/frontend/webrtc_operator/assets/style.css
new file mode 100644
index 0000000..b8e8365
--- /dev/null
+++ b/host/frontend/webrtc_operator/assets/style.css
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+body {
+  background-color:black;
+  margin: 0;
+}
+
+#device-selector {
+  color: whitesmoke;
+}
+#device-selector li.device-entry {
+  cursor: pointer;
+}
+
+#refresh-list {
+  cursor: pointer;
+}
+
+#device-list .device-entry button {
+  margin-left: 10px;
+}
+
+#device-connection {
+  visibility: hidden;
+  max-height: 100vh;
+}
+
+
+/* Top header row. */
+
+#header {
+  height: 64px;
+  margin-top: 10px;
+  margin-bottom: 10px;
+  /* Items inside this use a row Flexbox.*/
+  display: flex;
+  align-items: center;
+}
+
+#app-controls {
+  margin-left: 10px;
+}
+#app-controls > div {
+  display: inline-block;
+  position: relative;
+  margin-right: 6px;
+}
+#device-audio {
+  margin-bottom: 5px;
+}
+
+#status-div {
+  flex-grow: 1;
+}
+#status-message {
+  color: white;
+  font-family: 'Open Sans', sans-serif;
+  padding: 10px;
+  margin: 10px;
+}
+#status-message.connecting {
+  /* dark yellow */
+  background-color: #927836;
+}
+#status-message.error {
+  /* dark red */
+  background-color: #900000;
+}
+#status-message.connected {
+  /* dark green */
+  background-color: #007000;
+}
+
+/* Control panel buttons and device screen(s). */
+
+#controls-and-screens {
+  height: calc(100% - 84px);
+
+  /* Items inside this use a row Flexbox.*/
+  display: flex;
+}
+#controls-and-screens div {
+  margin-left: 10px;
+  margin-right: 10px;
+}
+
+.modal {
+  /* Start out hidden, and use absolute positioning. */
+  display: none;
+  position: absolute;
+
+  border-radius: 16px;
+  padding: 20px;
+  padding-top: 1px;
+
+  background-color: #5f6368ea; /* Semi-transparent Google grey 500 */
+  color: white;
+  font-family: 'Open Sans', sans-serif;
+}
+.modal-header {
+  cursor: move;
+  /* Items inside this use a row Flexbox.*/
+  display: flex;
+  justify-content: space-between;
+}
+.modal-close {
+  color: white;
+  border: none;
+  outline: none;
+  background-color: transparent;
+}
+#device-details-modal span {
+  white-space: pre;
+}
+#bluetooth-console-input {
+  width: 100%;
+}
+#bluetooth-console-cmd-label {
+  color: white;
+}
+
+.control-panel-column {
+  width: 80px;
+  /* Items inside this use a column Flexbox.*/
+  display: flex;
+  flex-direction: column;
+}
+#control-panel-custom-buttons {
+  display: none;
+  /* Give the custom buttons column a blue background. */
+  background-color: #1c4587ff;
+  height: fit-content;
+  border-radius: 16px;
+}
+
+.control-panel-column button {
+  margin: 0px 0px 5px 0px;
+  height: 80px;
+  font-size: 48px;
+
+  color: #e8eaed; /* Google grey 200 */
+  border: none;
+  outline: none;
+  background-color: transparent;
+}
+.control-panel-column button:disabled {
+  color: #9aa0a6; /* Google grey 500 */
+}
+.control-panel-column button.modal-button-opened {
+  border-radius: 16px;
+  background-color: #5f6368; /* Google grey 700 */
+}
+
+#screens {
+  /* Take up the remaining width of the window.*/
+  flex-grow: 1;
+  /* Don't grow taller than the window.*/
+  max-height: 100vh;
+}
+
+#device-screen {
+  touch-action: none;
+  transform-origin: top right;
+  object-fit: cover;
+}
diff --git a/host/frontend/webrtc_operator/certs/create_certs.sh b/host/frontend/webrtc_operator/certs/create_certs.sh
new file mode 100755
index 0000000..fefc275
--- /dev/null
+++ b/host/frontend/webrtc_operator/certs/create_certs.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# As explained in
+#  https://gist.github.com/darrenjs/4645f115d10aa4b5cebf57483ec82eca
+
+openssl genrsa -des3 -passout pass:xxxx -out server.pass.key 2048
+openssl rsa -passin pass:xxxx -in server.pass.key -out server.key
+rm -f server.pass.key
+
+openssl req \
+    -subj "/C=US/ST=California/L=Santa Clara/O=Beyond Aggravated/CN=localhost" \
+    -new -key server.key -out server.csr
+
+openssl x509 -req -sha256 -days 99999 -in server.csr -signkey server.key -out server.crt
+rm -f server.csr
+
+# Now create the list of certificates we trust as a client.
+
+rm trusted.pem
+
+# For now we just trust our own server.
+openssl x509 -in server.crt -text >> trusted.pem
+
+# Also add the system standard CA cert chain.
+# cat /opt/local/etc/openssl/cert.pem >> trusted.pem
+
+# Convert .pem to .der
+# openssl x509 -outform der -in trusted.pem -out trusted.der
+
+# Convert .crt and .key to .p12 for use by Security.framework
+# Enter password "foo"!
+openssl pkcs12 -export -inkey server.key -in server.crt -name localhost -out server.p12
diff --git a/host/frontend/webrtc_operator/certs/server.crt b/host/frontend/webrtc_operator/certs/server.crt
new file mode 100644
index 0000000..f871fcb
--- /dev/null
+++ b/host/frontend/webrtc_operator/certs/server.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkECFFsSgyQAZHRltRAdi9SrK2ZHRa1/MA0GCSqGSIb3DQEBCwUAMGgx
+CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50
+YSBDbGFyYTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxv
+Y2FsaG9zdDAgFw0yMTA1MDgwNjUwMDBaGA8yMjk1MDIyMDA2NTAwMFowaDELMAkG
+A1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFDASBgNVBAcMC1NhbnRhIENs
+YXJhMRowGAYDVQQKDBFCZXlvbmQgQWdncmF2YXRlZDESMBAGA1UEAwwJbG9jYWxo
+b3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxijHKeNl7nlYwn3f
+6CG8MP3XDVI3bc4v+XIJElH2mrNz8AUd0I9FoJVEdCDnRIO1Vb7sN/Wn9fxMQQv2
+ReHE56kR36Ca19G5VFo789gt7268ibpV7QQ117aoeEdw7kpOukKUG87Q7bZWlsZ3
+FX/nxSv1Hnv5BABxo0uyM8tv5KGXWwR8bsmFCCEr8i2AtglOnyVSV3Ey18Vb/mgt
++E4YE6WobTAiP8UdEKTPdnBms9IcHNknTB+ux910xDH4z9fWv8+4Bp4mH43xvbrt
+GJEzDl1xQ+Mrzc7Hk0FJqUlT6WHuyM9Tk7jspmhXxggtecy0CGB/hSo//urrUu2L
+EUABgQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBKNKU5S6HmO6atYLFmBfBk2ms/
+ZkDNHtDxnKLmsX3CFthRI3mGz1oEaMzYb2G2ufDxzh4/x2DM4iffRgj2knHSGlun
+3NYClZLM18/KTpXF26bycnixVGVw26jG0WHQTSdCS5VLz8CSg1O/487aEC5sKtoe
+LSk4KMpDFzD0+Esbkf/1aw0VyxsxjHRnxIMheK4cUt3y5I5qIKS2qK0W9ZuWr1Er
+dkYKCVumZKxVuMhHVOck6zLC5lZjefkFtTtyLe2nKIvXNWcHyuKqmLfafhEVSlKP
+Idg90Qo9+TY4bwQ8sMRVcVlnnChGvDtmeBXz4xwyFg8Pzhvwa86PlwMISi/m
+-----END CERTIFICATE-----
diff --git a/host/frontend/webrtc_operator/certs/server.key b/host/frontend/webrtc_operator/certs/server.key
new file mode 100644
index 0000000..a6b8f9f
--- /dev/null
+++ b/host/frontend/webrtc_operator/certs/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAxijHKeNl7nlYwn3f6CG8MP3XDVI3bc4v+XIJElH2mrNz8AUd
+0I9FoJVEdCDnRIO1Vb7sN/Wn9fxMQQv2ReHE56kR36Ca19G5VFo789gt7268ibpV
+7QQ117aoeEdw7kpOukKUG87Q7bZWlsZ3FX/nxSv1Hnv5BABxo0uyM8tv5KGXWwR8
+bsmFCCEr8i2AtglOnyVSV3Ey18Vb/mgt+E4YE6WobTAiP8UdEKTPdnBms9IcHNkn
+TB+ux910xDH4z9fWv8+4Bp4mH43xvbrtGJEzDl1xQ+Mrzc7Hk0FJqUlT6WHuyM9T
+k7jspmhXxggtecy0CGB/hSo//urrUu2LEUABgQIDAQABAoIBAQCt5QsiT1QcOpER
+3LSpWTF1LM2T+xp5Wf/vv4sGcLcge2q6r0LCy3gmu9ceseFB1vNDFBDn6sRCse2Z
+B45PNRk+0rfEr4Qy8PDafXUvP/7PpzX9B3BwVsmJS9n783W/J6Z+/f5LiOsAMIs8
+NV47l8sk1LZ+0fxs7pbK3pq7qUPANiEgKQ2F6PBkJkORuHmfhccC/a+qhAdsqwVB
+DjjwY0e5A/4fWqLiIUJGBopv0+df1TWsqfTq4lwaSDPY6dyI9E3MYVxKiYpbqgQ/
+N7QtjDjut6Zuw10bCgYyuEgy3Ab5Pmx6Hs6VGuYI6Hge4JeZ6TzZJ/cNnONZvGTF
+3356FYABAoGBAPgA+JYHDgXl4W6n9uMYQ4ZXL1UrYVxe8B1wWgt7DKD98/fD+Jj1
+KuRRUB2wLv/Jis+48QlAwLHQIL35WGpGm9C9j9dS3NO199BLrDY4fteSr67NrG9P
+Q0H+3F/7Dx7Scg5LNRYe6ZNvdfUD+9zoiaNHa9MMriK0ffc4O08RkA3BAoGBAMyM
+Y6c83Wek6GzPu5GCSMxEGBdqbx8T3iyEo4J23N3WAcfdIgSWZcjB2wNdNqa/RuHW
+QH6Gns5DLO3pYLU7R9DgLK5VE/Nq4nF0o7D57DnRkT+sZ3gYPdC7LiG3d5c+J7k1
+3pKL8yh7t2AgMpopfaY70wV4gL1K2qOLYfxbVGPBAoGBAK/Y2GpghDPwZOD2Xdt2
+R+LIjPpB8R3y/ySQlnhPfovkpYlHvkyOgiQz96+lTh32ROO2ycn6zOcHoT+yvltU
+x4TB9G0EBypie12JWolzk5S9IK68jQi71f/Ee3Pe60C6jT7PWsvdjVcKEERz17Ey
+fO12ZeDWu95Fxo91orAUzuTBAoGAC2xbtF9Fzh/7ivge9YVdI2s6HTSoeAfYBIxz
+xTl2JD1rZAoJeFAd5xRMcuelwbI09y/L8kT6YXKG89JwwC5LWHLsi9/ceV+ivctR
+yPRsKN53SiMKtD5GVX3ematxVlT2SvWjNHP0ZHJkT039BXcDuWDl7AxKxEeF5lRG
+aJ2BHQECgYEA0y67wxrbrgLGnur1J3nMN/sXmaTp6aDg/fTJyaaYhAzt+EUIn3MC
+nqVrWC35lpD5TO1fo8kfyaQH94zQxkywVb018caXHotjHC+EN6VnrG8cXmEvXU8E
+rUmEzHAxy548ZAgV6I/2kIrDEzijElvq7Geq2MzBkOUnFpD2y030iQ0=
+-----END RSA PRIVATE KEY-----
diff --git a/host/frontend/webrtc_operator/certs/server.p12 b/host/frontend/webrtc_operator/certs/server.p12
new file mode 100644
index 0000000..80920ba
--- /dev/null
+++ b/host/frontend/webrtc_operator/certs/server.p12
Binary files differ
diff --git a/host/frontend/webrtc_operator/certs/trusted.pem b/host/frontend/webrtc_operator/certs/trusted.pem
new file mode 100644
index 0000000..0c50578
--- /dev/null
+++ b/host/frontend/webrtc_operator/certs/trusted.pem
@@ -0,0 +1,70 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number:
+            5b:12:83:24:00:64:74:65:b5:10:1d:8b:d4:ab:2b:66:47:45:ad:7f
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, ST = California, L = Santa Clara, O = Beyond Aggravated, CN = localhost
+        Validity
+            Not Before: May  8 06:50:00 2021 GMT
+            Not After : Feb 20 06:50:00 2295 GMT
+        Subject: C = US, ST = California, L = Santa Clara, O = Beyond Aggravated, CN = localhost
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (2048 bit)
+                Modulus:
+                    00:c6:28:c7:29:e3:65:ee:79:58:c2:7d:df:e8:21:
+                    bc:30:fd:d7:0d:52:37:6d:ce:2f:f9:72:09:12:51:
+                    f6:9a:b3:73:f0:05:1d:d0:8f:45:a0:95:44:74:20:
+                    e7:44:83:b5:55:be:ec:37:f5:a7:f5:fc:4c:41:0b:
+                    f6:45:e1:c4:e7:a9:11:df:a0:9a:d7:d1:b9:54:5a:
+                    3b:f3:d8:2d:ef:6e:bc:89:ba:55:ed:04:35:d7:b6:
+                    a8:78:47:70:ee:4a:4e:ba:42:94:1b:ce:d0:ed:b6:
+                    56:96:c6:77:15:7f:e7:c5:2b:f5:1e:7b:f9:04:00:
+                    71:a3:4b:b2:33:cb:6f:e4:a1:97:5b:04:7c:6e:c9:
+                    85:08:21:2b:f2:2d:80:b6:09:4e:9f:25:52:57:71:
+                    32:d7:c5:5b:fe:68:2d:f8:4e:18:13:a5:a8:6d:30:
+                    22:3f:c5:1d:10:a4:cf:76:70:66:b3:d2:1c:1c:d9:
+                    27:4c:1f:ae:c7:dd:74:c4:31:f8:cf:d7:d6:bf:cf:
+                    b8:06:9e:26:1f:8d:f1:bd:ba:ed:18:91:33:0e:5d:
+                    71:43:e3:2b:cd:ce:c7:93:41:49:a9:49:53:e9:61:
+                    ee:c8:cf:53:93:b8:ec:a6:68:57:c6:08:2d:79:cc:
+                    b4:08:60:7f:85:2a:3f:fe:ea:eb:52:ed:8b:11:40:
+                    01:81
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: sha256WithRSAEncryption
+         4a:34:a5:39:4b:a1:e6:3b:a6:ad:60:b1:66:05:f0:64:da:6b:
+         3f:66:40:cd:1e:d0:f1:9c:a2:e6:b1:7d:c2:16:d8:51:23:79:
+         86:cf:5a:04:68:cc:d8:6f:61:b6:b9:f0:f1:ce:1e:3f:c7:60:
+         cc:e2:27:df:46:08:f6:92:71:d2:1a:5b:a7:dc:d6:02:95:92:
+         cc:d7:cf:ca:4e:95:c5:db:a6:f2:72:78:b1:54:65:70:db:a8:
+         c6:d1:61:d0:4d:27:42:4b:95:4b:cf:c0:92:83:53:bf:e3:ce:
+         da:10:2e:6c:2a:da:1e:2d:29:38:28:ca:43:17:30:f4:f8:4b:
+         1b:91:ff:f5:6b:0d:15:cb:1b:31:8c:74:67:c4:83:21:78:ae:
+         1c:52:dd:f2:e4:8e:6a:20:a4:b6:a8:ad:16:f5:9b:96:af:51:
+         2b:76:46:0a:09:5b:a6:64:ac:55:b8:c8:47:54:e7:24:eb:32:
+         c2:e6:56:63:79:f9:05:b5:3b:72:2d:ed:a7:28:8b:d7:35:67:
+         07:ca:e2:aa:98:b7:da:7e:11:15:4a:52:8f:21:d8:3d:d1:0a:
+         3d:f9:36:38:6f:04:3c:b0:c4:55:71:59:67:9c:28:46:bc:3b:
+         66:78:15:f3:e3:1c:32:16:0f:0f:ce:1b:f0:6b:ce:8f:97:03:
+         08:4a:2f:e6
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkECFFsSgyQAZHRltRAdi9SrK2ZHRa1/MA0GCSqGSIb3DQEBCwUAMGgx
+CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtTYW50
+YSBDbGFyYTEaMBgGA1UECgwRQmV5b25kIEFnZ3JhdmF0ZWQxEjAQBgNVBAMMCWxv
+Y2FsaG9zdDAgFw0yMTA1MDgwNjUwMDBaGA8yMjk1MDIyMDA2NTAwMFowaDELMAkG
+A1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFDASBgNVBAcMC1NhbnRhIENs
+YXJhMRowGAYDVQQKDBFCZXlvbmQgQWdncmF2YXRlZDESMBAGA1UEAwwJbG9jYWxo
+b3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxijHKeNl7nlYwn3f
+6CG8MP3XDVI3bc4v+XIJElH2mrNz8AUd0I9FoJVEdCDnRIO1Vb7sN/Wn9fxMQQv2
+ReHE56kR36Ca19G5VFo789gt7268ibpV7QQ117aoeEdw7kpOukKUG87Q7bZWlsZ3
+FX/nxSv1Hnv5BABxo0uyM8tv5KGXWwR8bsmFCCEr8i2AtglOnyVSV3Ey18Vb/mgt
++E4YE6WobTAiP8UdEKTPdnBms9IcHNknTB+ux910xDH4z9fWv8+4Bp4mH43xvbrt
+GJEzDl1xQ+Mrzc7Hk0FJqUlT6WHuyM9Tk7jspmhXxggtecy0CGB/hSo//urrUu2L
+EUABgQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBKNKU5S6HmO6atYLFmBfBk2ms/
+ZkDNHtDxnKLmsX3CFthRI3mGz1oEaMzYb2G2ufDxzh4/x2DM4iffRgj2knHSGlun
+3NYClZLM18/KTpXF26bycnixVGVw26jG0WHQTSdCS5VLz8CSg1O/487aEC5sKtoe
+LSk4KMpDFzD0+Esbkf/1aw0VyxsxjHRnxIMheK4cUt3y5I5qIKS2qK0W9ZuWr1Er
+dkYKCVumZKxVuMhHVOck6zLC5lZjefkFtTtyLe2nKIvXNWcHyuKqmLfafhEVSlKP
+Idg90Qo9+TY4bwQ8sMRVcVlnnChGvDtmeBXz4xwyFg8Pzhvwa86PlwMISi/m
+-----END CERTIFICATE-----
diff --git a/host/frontend/webrtc_operator/client_handler.cpp b/host/frontend/webrtc_operator/client_handler.cpp
new file mode 100644
index 0000000..7b631a6
--- /dev/null
+++ b/host/frontend/webrtc_operator/client_handler.cpp
@@ -0,0 +1,125 @@
+//
+// 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.
+
+#include "host/frontend/webrtc_operator/client_handler.h"
+
+#include <android-base/logging.h>
+
+#include "host/frontend/webrtc_operator/constants/signaling_constants.h"
+#include "host/frontend/webrtc_operator/device_handler.h"
+
+namespace cuttlefish {
+
+ClientHandler::ClientHandler(struct lws* wsi, DeviceRegistry* registry,
+                             const ServerConfig& server_config)
+    : SignalHandler(wsi, registry, server_config),
+      device_handler_(),
+      client_id_(0) {}
+
+void ClientHandler::OnClosed() {
+  auto device_handler = device_handler_.lock();
+  if (device_handler) {
+    device_handler->SendClientDisconnectMessage(client_id_);
+  }
+}
+
+void ClientHandler::SendDeviceMessage(const Json::Value& device_message) {
+  Json::Value message;
+  message[webrtc_signaling::kTypeField] = webrtc_signaling::kDeviceMessageType;
+  message[webrtc_signaling::kPayloadField] = device_message;
+  Reply(message);
+}
+
+void ClientHandler::handleMessage(const std::string& type,
+                                  const Json::Value& message) {
+  if (type == webrtc_signaling::kConnectType) {
+    handleConnectionRequest(message);
+  } else if (type == webrtc_signaling::kForwardType) {
+    handleForward(message);
+  } else {
+    LogAndReplyError("Unknown message type: " + type);
+  }
+}
+
+void ClientHandler::handleConnectionRequest(const Json::Value& message) {
+  if (client_id_ > 0) {
+    LogAndReplyError(
+        "Attempt to connect to multiple devices over same websocket");
+    Close();
+    return;
+  }
+  if (!message.isMember(webrtc_signaling::kDeviceIdField) ||
+      !message[webrtc_signaling::kDeviceIdField].isString()) {
+    LogAndReplyError("Invalid connection request: Missing device id");
+    Close();
+    return;
+  }
+  auto device_id = message[webrtc_signaling::kDeviceIdField].asString();
+  // Always send the server config back, even if the requested device is not
+  // registered. Applications may put clients on hold until the device is ready
+  // to connect.
+  SendServerConfig();
+
+  auto device_handler = registry_->GetDevice(device_id);
+  if (!device_handler) {
+    LogAndReplyError("Connection failed: Device not found: '" + device_id +
+                     "'");
+    Close();
+    return;
+  }
+
+  client_id_ = device_handler->RegisterClient(shared_from_this());
+  device_handler_ = device_handler;
+  Json::Value device_info_reply;
+  device_info_reply[webrtc_signaling::kTypeField] =
+      webrtc_signaling::kDeviceInfoType;
+  device_info_reply[webrtc_signaling::kDeviceInfoField] =
+      device_handler->device_info();
+  Reply(device_info_reply);
+}
+
+void ClientHandler::handleForward(const Json::Value& message) {
+  if (client_id_ == 0) {
+    LogAndReplyError("Forward failed: No device asociated to client");
+    Close();
+    return;
+  }
+  if (!message.isMember(webrtc_signaling::kPayloadField)) {
+    LogAndReplyError("Forward failed: No payload present in message");
+    Close();
+    return;
+  }
+  auto device_handler = device_handler_.lock();
+  if (!device_handler) {
+    LogAndReplyError("Forward failed: Device disconnected");
+    // Disconnect this client since the device is gone
+    Close();
+    return;
+  }
+  device_handler->SendClientMessage(client_id_,
+                                    message[webrtc_signaling::kPayloadField]);
+}
+
+ClientHandlerFactory::ClientHandlerFactory(DeviceRegistry* registry,
+                                           const ServerConfig& server_config)
+  : registry_(registry),
+    server_config_(server_config) {}
+
+std::shared_ptr<WebSocketHandler> ClientHandlerFactory::Build(struct lws* wsi) {
+  return std::shared_ptr<WebSocketHandler>(
+      new ClientHandler(wsi, registry_, server_config_));
+}
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/client_handler.h b/host/frontend/webrtc_operator/client_handler.h
new file mode 100644
index 0000000..b10f3e8
--- /dev/null
+++ b/host/frontend/webrtc_operator/client_handler.h
@@ -0,0 +1,63 @@
+//
+// 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 <memory>
+#include <string>
+
+#include <json/json.h>
+
+#include "host/frontend/webrtc_operator/device_registry.h"
+#include "host/frontend/webrtc_operator/server_config.h"
+#include "host/frontend/webrtc_operator/signal_handler.h"
+#include "host/libs/websocket/websocket_handler.h"
+
+namespace cuttlefish {
+class DeviceHandler;
+class ClientHandler : public SignalHandler,
+                      public std::enable_shared_from_this<ClientHandler> {
+ public:
+  ClientHandler(struct lws* wsi, DeviceRegistry* registry,
+                const ServerConfig& server_config);
+  void SendDeviceMessage(const Json::Value& message);
+
+  void OnClosed() override;
+
+ protected:
+  void handleMessage(const std::string& type,
+                    const Json::Value& message) override;
+
+ private:
+  void handleConnectionRequest(const Json::Value& message);
+  void handleForward(const Json::Value& message);
+
+  std::weak_ptr<DeviceHandler> device_handler_;
+  // The device handler assigns this to each client to be able to differentiate
+  // them.
+  size_t client_id_;
+};
+
+class ClientHandlerFactory : public WebSocketHandlerFactory {
+ public:
+  ClientHandlerFactory(DeviceRegistry* registry,
+                       const ServerConfig& server_config);
+  std::shared_ptr<WebSocketHandler> Build(struct lws* wsi) override;
+
+ private:
+  DeviceRegistry* registry_;
+  const ServerConfig& server_config_;
+};
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/constants/signaling_constants.h b/host/frontend/webrtc_operator/constants/signaling_constants.h
new file mode 100644
index 0000000..ecd3a3d
--- /dev/null
+++ b/host/frontend/webrtc_operator/constants/signaling_constants.h
@@ -0,0 +1,43 @@
+//
+// 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
+
+namespace cuttlefish {
+namespace webrtc_signaling {
+
+constexpr auto kTypeField = "message_type";
+constexpr auto kDeviceInfoField = "device_info";
+constexpr auto kDeviceIdField = "device_id";
+constexpr auto kClientIdField = "client_id";
+constexpr auto kPayloadField = "payload";
+constexpr auto kServersField = "ice_servers";
+// These are defined in the IceServer dictionary
+constexpr auto kUrlsField = "urls";
+constexpr auto kUsernameField = "username";
+constexpr auto kCredentialField = "credential";
+constexpr auto kCredentialTypeField = "credentialType";
+
+constexpr auto kRegisterType = "register";
+constexpr auto kForwardType = "forward";
+constexpr auto kConfigType = "config";
+constexpr auto kConnectType = "connect";
+constexpr auto kDeviceInfoType = "device_info";
+constexpr auto kClientMessageType = "client_msg";
+constexpr auto kClientDisconnectType = "client_disconnected";
+constexpr auto kDeviceMessageType = "device_msg";
+
+}  // namespace webrtc_signaling
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/device_handler.cpp b/host/frontend/webrtc_operator/device_handler.cpp
new file mode 100644
index 0000000..af503d4
--- /dev/null
+++ b/host/frontend/webrtc_operator/device_handler.cpp
@@ -0,0 +1,131 @@
+//
+// 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.
+
+#include "host/frontend/webrtc_operator/device_handler.h"
+
+#include <android-base/logging.h>
+
+#include "host/frontend/webrtc_operator/client_handler.h"
+#include "host/frontend/webrtc_operator/constants/signaling_constants.h"
+
+namespace cuttlefish {
+
+DeviceHandler::DeviceHandler(struct lws* wsi, DeviceRegistry* registry,
+                             const ServerConfig& server_config)
+    : SignalHandler(wsi, registry, server_config), device_info_(), clients_() {}
+
+void DeviceHandler::OnClosed() {
+  if (!device_id_.empty() && registry_) {
+    registry_->UnRegisterDevice(device_id_);
+  }
+}
+
+size_t DeviceHandler::RegisterClient(
+    std::shared_ptr<ClientHandler> client_handler) {
+  clients_.emplace_back(client_handler);
+  return clients_.size();
+}
+
+void DeviceHandler::handleMessage(const std::string& type,
+                                  const Json::Value& message) {
+  if (type == webrtc_signaling::kRegisterType) {
+    HandleRegistrationRequest(message);
+  } else if (type == webrtc_signaling::kForwardType) {
+    HandleForward(message);
+  } else {
+    LogAndReplyError("Unknown message type: " + type);
+  }
+}
+
+void DeviceHandler::HandleRegistrationRequest(const Json::Value& message) {
+  if (!device_id_.empty()) {
+    LogAndReplyError("Device already registered: " + device_id_);
+    Close();
+    return;
+  }
+  if (!message.isMember(webrtc_signaling::kDeviceIdField) ||
+      !message[webrtc_signaling::kDeviceIdField].isString() ||
+      message[webrtc_signaling::kDeviceIdField].asString().empty()) {
+    LogAndReplyError("Missing device id in registration request");
+    Close();
+    return;
+  }
+  device_id_ = message[webrtc_signaling::kDeviceIdField].asString();
+  if (message.isMember(webrtc_signaling::kDeviceInfoField)) {
+    device_info_ = message[webrtc_signaling::kDeviceInfoField];
+  }
+  if (!registry_->RegisterDevice(device_id_, weak_from_this())) {
+    LOG(ERROR) << "Device registration failed";
+    Close();
+    return;
+  }
+
+  SendServerConfig();
+}
+
+void DeviceHandler::HandleForward(const Json::Value& message) {
+  if (!message.isMember(webrtc_signaling::kClientIdField) ||
+      !message[webrtc_signaling::kClientIdField].isInt()) {
+    LogAndReplyError("Forward failed: Missing or invalid client id");
+    Close();
+    return;
+  }
+  size_t client_id = message[webrtc_signaling::kClientIdField].asInt();
+  if (!message.isMember(webrtc_signaling::kPayloadField)) {
+    LogAndReplyError("Forward failed: Missing payload");
+    Close();
+    return;
+  }
+  if (client_id <= 0 || client_id > clients_.size()) {
+    LogAndReplyError("Forward failed: Unknown client " +
+                     std::to_string(client_id));
+    return;
+  }
+  auto client_index = client_id - 1;
+  auto client_handler = clients_[client_index].lock();
+  if (!client_handler) {
+    SendClientDisconnectMessage(client_id);
+    return;
+  }
+  client_handler->SendDeviceMessage(message[webrtc_signaling::kPayloadField]);
+  return;
+}
+
+void DeviceHandler::SendClientMessage(size_t client_id,
+                                      const Json::Value& client_message) {
+  Json::Value msg;
+  msg[webrtc_signaling::kTypeField] = webrtc_signaling::kClientMessageType;
+  msg[webrtc_signaling::kClientIdField] = static_cast<Json::UInt>(client_id);
+  msg[webrtc_signaling::kPayloadField] = client_message;
+  Reply(msg);
+}
+
+void DeviceHandler::SendClientDisconnectMessage(size_t client_id) {
+  Json::Value msg;
+  msg[webrtc_signaling::kTypeField] = webrtc_signaling::kClientDisconnectType;
+  msg[webrtc_signaling::kClientIdField] = static_cast<Json::UInt>(client_id);
+  Reply(msg);
+}
+
+DeviceHandlerFactory::DeviceHandlerFactory(DeviceRegistry* registry,
+                                           const ServerConfig& server_config)
+  : registry_(registry),
+    server_config_(server_config) {}
+
+std::shared_ptr<WebSocketHandler> DeviceHandlerFactory::Build(struct lws* wsi) {
+  return std::shared_ptr<WebSocketHandler>(
+      new DeviceHandler(wsi, registry_, server_config_));
+}
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/device_handler.h b/host/frontend/webrtc_operator/device_handler.h
new file mode 100644
index 0000000..1e17994
--- /dev/null
+++ b/host/frontend/webrtc_operator/device_handler.h
@@ -0,0 +1,70 @@
+//
+// 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 <memory>
+#include <string>
+#include <vector>
+
+#include <json/json.h>
+
+#include "host/frontend/webrtc_operator/device_registry.h"
+#include "host/frontend/webrtc_operator/server_config.h"
+#include "host/frontend/webrtc_operator/signal_handler.h"
+#include "host/libs/websocket/websocket_handler.h"
+
+namespace cuttlefish {
+
+class ClientHandler;
+
+class DeviceHandler : public SignalHandler,
+                      public std::enable_shared_from_this<DeviceHandler> {
+ public:
+  DeviceHandler(struct lws* wsi, DeviceRegistry* registry,
+                const ServerConfig& server_config);
+
+  Json::Value device_info() const { return device_info_; }
+
+  size_t RegisterClient(std::shared_ptr<ClientHandler> client_handler);
+  void SendClientMessage(size_t client_id, const Json::Value& message);
+  void SendClientDisconnectMessage(size_t client_id);
+
+  void OnClosed() override;
+
+ protected:
+  void handleMessage(const std::string& type,
+                    const Json::Value& message) override;
+
+ private:
+  void HandleRegistrationRequest(const Json::Value& message);
+  void HandleForward(const Json::Value& message);
+
+  std::string device_id_;
+  Json::Value device_info_;
+  std::vector<std::weak_ptr<ClientHandler>> clients_;
+};
+
+class DeviceHandlerFactory : public WebSocketHandlerFactory {
+ public:
+  DeviceHandlerFactory(DeviceRegistry* registry,
+                       const ServerConfig& server_config);
+  std::shared_ptr<WebSocketHandler> Build(struct lws* wsi) override;
+
+ private:
+  DeviceRegistry* registry_;
+  const ServerConfig& server_config_;
+};
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/device_list_handler.cpp b/host/frontend/webrtc_operator/device_list_handler.cpp
new file mode 100644
index 0000000..314feea
--- /dev/null
+++ b/host/frontend/webrtc_operator/device_list_handler.cpp
@@ -0,0 +1,48 @@
+//
+// 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.
+
+#include "host/frontend/webrtc_operator/device_list_handler.h"
+
+namespace cuttlefish {
+
+DeviceListHandler::DeviceListHandler(struct lws* wsi,
+                                     const DeviceRegistry& registry)
+    : WebSocketHandler(wsi), registry_(registry) {}
+
+void DeviceListHandler::OnReceive(const uint8_t* /*msg*/, size_t /*len*/,
+                                  bool /*binary*/) {
+  // Ignore the message, just send the reply
+  Json::Value reply(Json::ValueType::arrayValue);
+
+  for (const auto& id : registry_.ListDeviceIds()) {
+    reply.append(id);
+  }
+  Json::StreamWriterBuilder json_factory;
+  auto replyAsString = Json::writeString(json_factory, reply);
+  EnqueueMessage(replyAsString.c_str(), replyAsString.size());
+  Close();
+}
+
+void DeviceListHandler::OnConnected() {}
+
+void DeviceListHandler::OnClosed() {}
+
+DeviceListHandlerFactory::DeviceListHandlerFactory(const DeviceRegistry& registry)
+  : registry_(registry) {}
+
+std::shared_ptr<WebSocketHandler> DeviceListHandlerFactory::Build(struct lws* wsi) {
+  return std::shared_ptr<WebSocketHandler>(new DeviceListHandler(wsi, registry_));
+}
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/device_list_handler.h b/host/frontend/webrtc_operator/device_list_handler.h
new file mode 100644
index 0000000..99d1f9c
--- /dev/null
+++ b/host/frontend/webrtc_operator/device_list_handler.h
@@ -0,0 +1,48 @@
+//
+// 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 <memory>
+#include <string>
+
+#include <json/json.h>
+
+#include "host/libs/websocket/websocket_handler.h"
+#include "host/frontend/webrtc_operator/device_registry.h"
+
+namespace cuttlefish {
+
+class DeviceListHandler : public WebSocketHandler {
+ public:
+  DeviceListHandler(struct lws* wsi, const DeviceRegistry& registry);
+
+  void OnReceive(const uint8_t* msg, size_t len, bool binary) override;
+  void OnConnected() override;
+  void OnClosed() override;
+
+ private:
+  const DeviceRegistry& registry_;
+};
+
+class DeviceListHandlerFactory : public WebSocketHandlerFactory {
+ public:
+  DeviceListHandlerFactory(const DeviceRegistry& registry);
+  std::shared_ptr<WebSocketHandler> Build(struct lws* wsi) override;
+
+ private:
+  const DeviceRegistry& registry_;
+};
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/device_registry.cpp b/host/frontend/webrtc_operator/device_registry.cpp
new file mode 100644
index 0000000..9ca938e
--- /dev/null
+++ b/host/frontend/webrtc_operator/device_registry.cpp
@@ -0,0 +1,71 @@
+//
+// 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.
+
+#include "host/frontend/webrtc_operator/device_registry.h"
+
+#include <android-base/logging.h>
+
+#include "host/frontend/webrtc_operator/device_handler.h"
+
+namespace cuttlefish {
+
+bool DeviceRegistry::RegisterDevice(
+    const std::string& device_id,
+    std::weak_ptr<DeviceHandler> device_handler) {
+  if (devices_.count(device_id) > 0) {
+    LOG(ERROR) << "Device '" << device_id << "' is already registered";
+    return false;
+  }
+
+  devices_.try_emplace(device_id, device_handler);
+  LOG(INFO) << "Registered device: '" << device_id << "'";
+  return true;
+}
+
+void DeviceRegistry::UnRegisterDevice(const std::string& device_id) {
+  auto record = devices_.find(device_id);
+  if (record == devices_.end()) {
+    LOG(WARNING) << "Requested to unregister an unkwnown device: '" << device_id
+                 << "'";
+    return;
+  }
+  devices_.erase(record);
+  LOG(INFO) << "Unregistered device: '" << device_id << "'";
+}
+
+std::shared_ptr<DeviceHandler> DeviceRegistry::GetDevice(
+    const std::string& device_id) {
+  if (devices_.count(device_id) == 0) {
+    LOG(INFO) << "Requested device (" << device_id << ") is not registered";
+    return nullptr;
+  }
+  auto device_handler = devices_[device_id].lock();
+  if (!device_handler) {
+    LOG(WARNING) << "Destroyed device handler detected for device '"
+                 << device_id << "'";
+    UnRegisterDevice(device_id);
+  }
+  return device_handler;
+}
+
+std::vector<std::string> DeviceRegistry::ListDeviceIds() const {
+  std::vector<std::string> ret;
+  for (const auto& entry: devices_) {
+    ret.push_back(entry.first);
+  }
+  return ret;
+}
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/device_registry.h b/host/frontend/webrtc_operator/device_registry.h
new file mode 100644
index 0000000..8cccb90
--- /dev/null
+++ b/host/frontend/webrtc_operator/device_registry.h
@@ -0,0 +1,45 @@
+//
+// 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 <cinttypes>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <json/json.h>
+
+namespace cuttlefish {
+
+class DeviceHandler;
+
+class DeviceRegistry {
+ public:
+  bool RegisterDevice(const std::string& device_id,
+                      std::weak_ptr<DeviceHandler> device_handler);
+  void UnRegisterDevice(const std::string& device_id);
+
+  std::shared_ptr<DeviceHandler> GetDevice(const std::string& device_id);
+
+  std::vector<std::string> ListDeviceIds() const;
+
+ private:
+  std::map<std::string, std::weak_ptr<DeviceHandler>> devices_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/server.cpp b/host/frontend/webrtc_operator/server.cpp
new file mode 100644
index 0000000..565676a
--- /dev/null
+++ b/host/frontend/webrtc_operator/server.cpp
@@ -0,0 +1,71 @@
+//
+// 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.
+
+#include <map>
+#include <string>
+
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
+
+#include "host/frontend/webrtc_operator/client_handler.h"
+#include "host/frontend/webrtc_operator/device_handler.h"
+#include "host/frontend/webrtc_operator/device_list_handler.h"
+#include "host/libs/websocket/websocket_handler.h"
+#include "host/libs/websocket/websocket_server.h"
+
+#include "host/libs/config/logging.h"
+
+DEFINE_int32(http_server_port, 8443, "The port for the http server.");
+DEFINE_bool(use_secure_http, true, "Whether to use HTTPS or HTTP.");
+DEFINE_string(assets_dir, "webrtc",
+              "Directory with location of webpage assets.");
+DEFINE_string(certs_dir, "webrtc/certs", "Directory to certificates.");
+DEFINE_string(stun_server, "stun.l.google.com:19302",
+              "host:port of STUN server to use for public address resolution");
+
+namespace {
+
+constexpr auto kRegisterDeviceUriPath = "/register_device";
+constexpr auto kConnectClientUriPath = "/connect_client";
+constexpr auto kListDevicesUriPath = "/list_devices";
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  cuttlefish::DefaultSubprocessLogging(argv);
+  ::gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+  cuttlefish::DeviceRegistry device_registry;
+  cuttlefish::ServerConfig server_config({FLAGS_stun_server});
+
+  cuttlefish::WebSocketServer wss(
+        "webrtc-operator", FLAGS_certs_dir, FLAGS_assets_dir, FLAGS_http_server_port);
+
+  auto device_handler_factory_p =
+      std::unique_ptr<cuttlefish::WebSocketHandlerFactory>(
+          new cuttlefish::DeviceHandlerFactory(&device_registry, server_config));
+  wss.RegisterHandlerFactory(kRegisterDeviceUriPath, std::move(device_handler_factory_p));
+  auto client_handler_factory_p =
+      std::unique_ptr<cuttlefish::WebSocketHandlerFactory>(
+          new cuttlefish::ClientHandlerFactory(&device_registry, server_config));
+  wss.RegisterHandlerFactory(kConnectClientUriPath, std::move(client_handler_factory_p));
+  auto device_list_handler_factory_p =
+      std::unique_ptr<cuttlefish::WebSocketHandlerFactory>(
+          new cuttlefish::DeviceListHandlerFactory(device_registry));
+  wss.RegisterHandlerFactory(kListDevicesUriPath, std::move(device_list_handler_factory_p));
+
+  wss.Serve();
+  return 0;
+}
diff --git a/host/frontend/webrtc_operator/server_config.cpp b/host/frontend/webrtc_operator/server_config.cpp
new file mode 100644
index 0000000..b49509c
--- /dev/null
+++ b/host/frontend/webrtc_operator/server_config.cpp
@@ -0,0 +1,45 @@
+//
+// 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.
+
+#include "host/frontend/webrtc_operator/server_config.h"
+
+#include <android-base/strings.h>
+
+using android::base::StartsWith;
+
+namespace cuttlefish {
+
+namespace {
+  constexpr auto kStunPrefix = "stun:";
+}
+
+ServerConfig::ServerConfig(const std::vector<std::string>& stuns)
+    : stun_servers_(stuns) {}
+
+Json::Value ServerConfig::ToJson() const {
+  Json::Value ice_servers(Json::ValueType::arrayValue);
+  for (const auto& str : stun_servers_) {
+    Json::Value server;
+    Json::Value urls(Json::ValueType::arrayValue);
+    urls.append(StartsWith(str, kStunPrefix)? str: kStunPrefix + str);
+    server["urls"] = urls;
+    ice_servers.append(server);
+  }
+  Json::Value server_config;
+  server_config["ice_servers"] = ice_servers;
+  return server_config;
+}
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/server_config.h b/host/frontend/webrtc_operator/server_config.h
new file mode 100644
index 0000000..1983128
--- /dev/null
+++ b/host/frontend/webrtc_operator/server_config.h
@@ -0,0 +1,33 @@
+//
+// 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>
+#include <vector>
+
+#include <json/json.h>
+
+namespace cuttlefish {
+class ServerConfig {
+ public:
+  ServerConfig(const std::vector<std::string>& stuns);
+
+  Json::Value ToJson() const;
+
+ private:
+  std::vector<std::string> stun_servers_;
+};
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/signal_handler.cpp b/host/frontend/webrtc_operator/signal_handler.cpp
new file mode 100644
index 0000000..92ceb26
--- /dev/null
+++ b/host/frontend/webrtc_operator/signal_handler.cpp
@@ -0,0 +1,100 @@
+//
+// 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.
+
+#include "host/frontend/webrtc_operator/signal_handler.h"
+
+#include <android-base/logging.h>
+#include <json/json.h>
+
+#include "host/frontend/webrtc_operator/constants/signaling_constants.h"
+
+namespace cuttlefish {
+
+SignalHandler::SignalHandler(struct lws* wsi, DeviceRegistry* registry,
+                             const ServerConfig& server_config)
+    : WebSocketHandler(wsi),
+      registry_(registry),
+      server_config_(server_config) {}
+
+void SignalHandler::OnConnected() {}
+
+void SignalHandler::OnReceive(const uint8_t* msg, size_t len, bool binary) {
+  if (binary) {
+    LogAndReplyError("Received a binary message");
+    Close();
+    return;
+  }
+  Json::Value json_message;
+  Json::CharReaderBuilder builder;
+  std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
+  std::string errorMessage;
+  auto str = reinterpret_cast<const char*>(msg);
+  if (!json_reader->parse(str, str + len, &json_message, &errorMessage)) {
+    LogAndReplyError("Received Invalid JSON");
+    // Rate limiting would be a good idea here
+    Close();
+    return;
+  }
+  if (!json_message.isMember(webrtc_signaling::kTypeField) ||
+      !json_message[webrtc_signaling::kTypeField].isString()) {
+    LogAndReplyError("Invalid message format: '" + std::string(msg, msg + len) +
+                     "'");
+    // Rate limiting would be a good idea here
+    Close();
+    return;
+  }
+
+  auto type = json_message[webrtc_signaling::kTypeField].asString();
+  handleMessage(type, json_message);
+}
+
+void SignalHandler::OnReceive(const uint8_t* msg, size_t len, bool binary,
+                              bool is_final) {
+  if (is_final) {
+    if (receive_buffer_.empty()) {
+      // no previous data - receive as-is
+      OnReceive(msg, len, binary);
+    } else {
+      // concatenate to previous data and receive
+      receive_buffer_.insert(receive_buffer_.end(), msg, msg + len);
+      OnReceive(receive_buffer_.data(), receive_buffer_.size(), binary);
+      receive_buffer_.clear();
+    }
+  } else {
+    // buffer up incomplete messages
+    receive_buffer_.insert(receive_buffer_.end(), msg, msg + len);
+  }
+}
+
+void SignalHandler::SendServerConfig() {
+  // Call every time to allow config changes?
+  auto reply = server_config_.ToJson();
+  reply[webrtc_signaling::kTypeField] = webrtc_signaling::kConfigType;
+  Reply(reply);
+}
+
+void SignalHandler::LogAndReplyError(const std::string& error_message) {
+  LOG(ERROR) << error_message;
+  auto reply_str = "{\"error\":\"" + error_message + "\"}";
+  EnqueueMessage(reply_str.c_str(), reply_str.size());
+}
+
+void SignalHandler::Reply(const Json::Value& json) {
+  Json::StreamWriterBuilder factory;
+  auto replyAsString = Json::writeString(factory, json);
+  EnqueueMessage(replyAsString.c_str(), replyAsString.size());
+}
+
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/signal_handler.h b/host/frontend/webrtc_operator/signal_handler.h
new file mode 100644
index 0000000..a0e813c
--- /dev/null
+++ b/host/frontend/webrtc_operator/signal_handler.h
@@ -0,0 +1,50 @@
+//
+// 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 <memory>
+#include <string>
+
+#include <json/json.h>
+
+#include "host/frontend/webrtc_operator/device_registry.h"
+#include "host/frontend/webrtc_operator/server_config.h"
+#include "host/libs/websocket/websocket_handler.h"
+
+namespace cuttlefish {
+
+class SignalHandler : public WebSocketHandler {
+ public:
+  void OnReceive(const uint8_t* msg, size_t len, bool binary) override;
+  void OnReceive(const uint8_t* msg, size_t len, bool binary,
+                 bool is_final) override;
+  void OnConnected() override;
+ protected:
+  SignalHandler(struct lws* wsi, DeviceRegistry* registry,
+                const ServerConfig& server_config);
+
+  virtual void handleMessage(const std::string& message_type,
+                             const Json::Value& message) = 0;
+  void SendServerConfig();
+
+  void LogAndReplyError(const std::string& message);
+  void Reply(const Json::Value& json);
+
+  DeviceRegistry* registry_;
+  const ServerConfig& server_config_;
+  std::vector<uint8_t> receive_buffer_;
+};
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc_operator/utils.cpp b/host/frontend/webrtc_operator/utils.cpp
new file mode 100644
index 0000000..b4e23e3
--- /dev/null
+++ b/host/frontend/webrtc_operator/utils.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "host/frontend/webrtc_operator/utils.h"
+
+std::vector<std::string> SplitString(const std::string &s, char c) {
+    return SplitString(s, std::string(1 /* count */, c));
+}
+
+std::vector<std::string> SplitString(
+        const std::string &s, const std::string &separator) {
+    std::vector<std::string> pieces;
+
+    size_t startPos = 0;
+    size_t matchPos;
+    while ((matchPos = s.find(separator, startPos)) != std::string::npos) {
+        pieces.push_back(std::string(s, startPos, matchPos - startPos));
+        startPos = matchPos + separator.size();
+    }
+
+    if (startPos < s.size()) {
+        pieces.push_back(std::string(s, startPos));
+    }
+
+    return pieces;
+}
+
+bool StartsWith(const std::string &s, const std::string &prefix) {
+    return s.find(prefix) == 0;
+}
+
+std::string StringPrintf(const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+
+    char *buffer;
+    (void)vasprintf(&buffer, format, ap);
+
+    va_end(ap);
+
+    std::string result(buffer);
+
+    free(buffer);
+    buffer = NULL;
+
+    return result;
+}
+
+void SET_U16(void *_dst, uint16_t x) {
+    uint8_t *dst = static_cast<uint8_t *>(_dst);
+    dst[0] = x >> 8;
+    dst[1] = x & 0xff;
+}
+
+void SET_U32(void *_dst, uint32_t x) {
+    uint8_t *dst = static_cast<uint8_t *>(_dst);
+    dst[0] = x >> 24;
+    dst[1] = (x >> 16) & 0xff;
+    dst[2] = (x >> 8) & 0xff;
+    dst[3] = x & 0xff;
+}
+
+static const uint32_t crc32_tab[] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+uint32_t computeCrc32(const void *_data, size_t size) {
+    const uint8_t *data = static_cast<const uint8_t *>(_data);
+
+    uint32_t crc = 0xffffffff;
+
+    for (size_t i = 0; i < size; ++i) {
+        uint32_t lkp = crc32_tab[(crc ^ data[i]) & 0xFF];
+        crc =  lkp ^ (crc >> 8);
+    }
+
+    return crc ^ 0xffffffff;
+}
diff --git a/host/frontend/gcastv2/webrtc/Utils.h b/host/frontend/webrtc_operator/utils.h
similarity index 100%
rename from host/frontend/gcastv2/webrtc/Utils.h
rename to host/frontend/webrtc_operator/utils.h
diff --git a/host/libs/Android.bp b/host/libs/Android.bp
deleted file mode 100644
index 169507c..0000000
--- a/host/libs/Android.bp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Copyright (C) 2017 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.
-
-subdirs = [
-    "adb_connection_maintainer",
-    "config",
-    "wayland",
-    "vm_manager",
-]
diff --git a/host/libs/allocd/Android.bp b/host/libs/allocd/Android.bp
new file mode 100644
index 0000000..3c52507
--- /dev/null
+++ b/host/libs/allocd/Android.bp
@@ -0,0 +1,75 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+    name: "libcuttlefish_allocd_utils",
+    srcs: [
+        "utils.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_utils",
+        "libcuttlefish_fs",
+        "libjsoncpp",
+        "liblog",
+    ],
+    defaults: ["cuttlefish_host"],
+}
+
+cc_binary {
+    name: "allocd",
+    srcs: [
+        "allocd.cpp",
+        "alloc_utils.cpp",
+        "resource_manager.cpp",
+        "resource.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libcuttlefish_allocd_utils",
+        "libjsoncpp",
+        "liblog",
+    ],
+    static_libs: [
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host"],
+}
+
+cc_binary {
+    name: "allocd_client",
+    srcs: [
+        "test/client.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcuttlefish_allocd_utils",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "liblog",
+        "libjsoncpp",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/libs/allocd/alloc_utils.cpp b/host/libs/allocd/alloc_utils.cpp
new file mode 100644
index 0000000..8c91686
--- /dev/null
+++ b/host/libs/allocd/alloc_utils.cpp
@@ -0,0 +1,482 @@
+#include "host/libs/allocd/alloc_utils.h"
+
+#include <cstdint>
+#include <fstream>
+
+#include "android-base/logging.h"
+
+namespace cuttlefish {
+
+int RunExternalCommand(const std::string& command) {
+  FILE* fp;
+  LOG(INFO) << "Running external command: " << command;
+  fp = popen(command.c_str(), "r");
+
+  if (fp == nullptr) {
+    LOG(WARNING) << "Error running external command";
+    return -1;
+  }
+
+  int status = pclose(fp);
+  int ret = -1;
+  if (status == -1) {
+    LOG(WARNING) << "pclose error";
+  } else {
+    if (WIFEXITED(status)) {
+      LOG(INFO) << "child process exited normally";
+      ret = WEXITSTATUS(status);
+    } else if (WIFSIGNALED(status)) {
+      LOG(WARNING) << "child process was terminated by a signal";
+    } else {
+      LOG(WARNING) << "child process did not terminate normally";
+    }
+  }
+  return ret;
+}
+
+bool AddTapIface(const std::string& name) {
+  std::stringstream ss;
+  ss << "ip tuntap add dev " << name << " mode tap group cvdnetwork vnet_hdr";
+  auto add_command = ss.str();
+  LOG(INFO) << "Create tap interface: " << add_command;
+  int status = RunExternalCommand(add_command);
+  return status == 0;
+}
+
+bool ShutdownIface(const std::string& name) {
+  std::stringstream ss;
+  ss << "ip link set dev " << name << " down";
+  auto link_command = ss.str();
+  LOG(INFO) << "Shutdown tap interface: " << link_command;
+  int status = RunExternalCommand(link_command);
+
+  return status == 0;
+}
+
+bool BringUpIface(const std::string& name) {
+  std::stringstream ss;
+  ss << "ip link set dev " << name << " up";
+  auto link_command = ss.str();
+  LOG(INFO) << "Bring up tap interface: " << link_command;
+  int status = RunExternalCommand(link_command);
+
+  return status == 0;
+}
+
+bool CreateEthernetIface(const std::string& name, const std::string& bridge_name,
+                         bool has_ipv4_bridge, bool has_ipv6_bridge,
+                         bool use_ebtables_legacy) {
+  // assume bridge exists
+
+  EthernetNetworkConfig config{false, false, false};
+
+  if (!CreateTap(name)) {
+    return false;
+  }
+
+  config.has_tap = true;
+
+  if (!LinkTapToBridge(name, bridge_name)) {
+    CleanupEthernetIface(name, config);
+    return false;
+  }
+
+  if (!has_ipv4_bridge) {
+    if (!CreateEbtables(name, true, use_ebtables_legacy)) {
+      CleanupEthernetIface(name, config);
+      return false;
+    }
+    config.has_broute_ipv4 = true;
+  }
+
+  if (!has_ipv6_bridge) {
+    if (CreateEbtables(name, false, use_ebtables_legacy)) {
+      CleanupEthernetIface(name, config);
+      return false;
+    }
+    config.has_broute_ipv6 = true;
+  }
+
+  return true;
+}
+
+std::string MobileGatewayName(const std::string& ipaddr, uint16_t id) {
+  std::stringstream ss;
+  ss << ipaddr << "." << (4 * id + 1);
+  return ss.str();
+}
+
+std::string MobileNetworkName(const std::string& ipaddr,
+                              const std::string& netmask, uint16_t id) {
+  std::stringstream ss;
+  ss << ipaddr << "." << (4 * id) << netmask;
+  return ss.str();
+}
+
+bool CreateMobileIface(const std::string& name, uint16_t id,
+                       const std::string& ipaddr) {
+  if (id > kMaxIfaceNameId) {
+    LOG(ERROR) << "ID exceeds maximum value to assign a netmask: " << id;
+    return false;
+  }
+
+  auto netmask = "/30";
+  auto gateway = MobileGatewayName(ipaddr, id);
+  auto network = MobileNetworkName(ipaddr, netmask, id);
+
+  if (!CreateTap(name)) {
+    return false;
+  }
+
+  if (!AddGateway(name, gateway, netmask)) {
+    DestroyIface(name);
+  }
+
+  if (!IptableConfig(network, true)) {
+    DestroyGateway(name, gateway, netmask);
+    DestroyIface(name);
+    return false;
+  };
+
+  return true;
+}
+
+bool DestroyMobileIface(const std::string& name, uint16_t id,
+                        const std::string& ipaddr) {
+  if (id > 63) {
+    LOG(ERROR) << "ID exceeds maximum value to assign a netmask: " << id;
+    return false;
+  }
+
+  auto netmask = "/30";
+  auto gateway = MobileGatewayName(ipaddr, id);
+  auto network = MobileNetworkName(ipaddr, netmask, id);
+
+  IptableConfig(network, false);
+  DestroyGateway(name, gateway, netmask);
+  return DestroyIface(name);
+}
+
+bool AddGateway(const std::string& name, const std::string& gateway,
+                const std::string& netmask) {
+  std::stringstream ss;
+  ss << "ip addr add " << gateway << netmask << " broadcast + dev " << name;
+  auto command = ss.str();
+  LOG(INFO) << "setup gateway: " << command;
+  int status = RunExternalCommand(command);
+
+  return status == 0;
+}
+
+bool DestroyGateway(const std::string& name, const std::string& gateway,
+                    const std::string& netmask) {
+  std::stringstream ss;
+  ss << "ip addr del " << gateway << netmask << " broadcast + dev " << name;
+  auto command = ss.str();
+  LOG(INFO) << "removing gateway: " << command;
+  int status = RunExternalCommand(command);
+
+  return status == 0;
+}
+
+bool DestroyEthernetIface(const std::string& name, bool has_ipv4_bridge,
+                          bool has_ipv6_bridge, bool use_ebtables_legacy) {
+  if (!has_ipv6_bridge) {
+    DestroyEbtables(name, false, use_ebtables_legacy);
+  }
+
+  if (!has_ipv4_bridge) {
+    DestroyEbtables(name, true, use_ebtables_legacy);
+  }
+
+  return DestroyIface(name);
+}
+
+void CleanupEthernetIface(const std::string& name,
+                          const EthernetNetworkConfig& config) {
+  if (config.has_broute_ipv6) {
+    DestroyEbtables(name, false, config.use_ebtables_legacy);
+  }
+
+  if (config.has_broute_ipv4) {
+    DestroyEbtables(name, true, config.use_ebtables_legacy);
+  }
+
+  if (config.has_tap) {
+    DestroyIface(name);
+  }
+}
+
+bool CreateEbtables(const std::string& name, bool use_ipv4,
+                    bool use_ebtables_legacy) {
+  return EbtablesBroute(name, use_ipv4, true, use_ebtables_legacy) &&
+         EbtablesFilter(name, use_ipv4, true, use_ebtables_legacy);
+}
+
+bool DestroyEbtables(const std::string& name, bool use_ipv4,
+                     bool use_ebtables_legacy) {
+  return EbtablesBroute(name, use_ipv4, false, use_ebtables_legacy) &&
+         EbtablesFilter(name, use_ipv4, false, use_ebtables_legacy);
+}
+
+bool EbtablesBroute(const std::string& name, bool use_ipv4, bool add,
+                    bool use_ebtables_legacy) {
+  std::stringstream ss;
+  // we don't know the name of the ebtables program, but since we're going to
+  // exec this program name, make sure they can only choose between the two
+  // options we currently support, and not something they can overwrite
+  if (use_ebtables_legacy) {
+    ss << kEbtablesLegacyName;
+  } else {
+    ss << kEbtablesName;
+  }
+
+  ss << " -t broute " << (add ? "-A" : "-D") << " BROUTING -p "
+     << (use_ipv4 ? "ipv4" : "ipv6") << " --in-if " << name << " -j DROP";
+  auto command = ss.str();
+  int status = RunExternalCommand(command);
+
+  return status == 0;
+}
+
+bool EbtablesFilter(const std::string& name, bool use_ipv4, bool add,
+                    bool use_ebtables_legacy) {
+  std::stringstream ss;
+  if (use_ebtables_legacy) {
+    ss << kEbtablesLegacyName;
+  } else {
+    ss << kEbtablesName;
+  }
+
+  ss << " -t filter " << (add ? "-A" : "-D") << " FORWARD -p "
+     << (use_ipv4 ? "ipv4" : "ipv6") << " --out-if " << name << " -j DROP";
+  auto command = ss.str();
+  int status = RunExternalCommand(command);
+
+  return status == 0;
+}
+
+bool LinkTapToBridge(const std::string& tap_name,
+                     const std::string& bridge_name) {
+  std::stringstream ss;
+  ss << "ip link set dev " << tap_name << " master " << bridge_name;
+  auto command = ss.str();
+  int status = RunExternalCommand(command);
+
+  return status == 0;
+}
+
+bool CreateTap(const std::string& name) {
+  LOG(INFO) << "Attempt to create tap interface: " << name;
+  if (!AddTapIface(name)) {
+    LOG(WARNING) << "Failed to create tap interface: " << name;
+    return false;
+  }
+
+  if (!BringUpIface(name)) {
+    LOG(WARNING) << "Failed to bring up tap interface: " << name;
+    DeleteIface(name);
+    return false;
+  }
+
+  return true;
+}
+
+bool DeleteIface(const std::string& name) {
+  std::stringstream ss;
+  ss << "ip link delete " << name;
+  auto link_command = ss.str();
+  LOG(INFO) << "Delete tap interface: " << link_command;
+  int status = RunExternalCommand(link_command);
+
+  return status == 0;
+}
+
+bool DestroyIface(const std::string& name) {
+  if (!ShutdownIface(name)) {
+    LOG(WARNING) << "Failed to shutdown tap interface: " << name;
+    // the interface might have already shutdown ... so ignore and try to remove
+    // the interface. In the future we could read from the pipe and handle this
+    // case more elegantly
+  }
+
+  if (!DeleteIface(name)) {
+    LOG(WARNING) << "Failed to delete tap interface: " << name;
+    return false;
+  }
+
+  return true;
+}
+
+std::optional<std::string> GetUserName(uid_t uid) {
+  passwd* pw = getpwuid(uid);
+  if (pw) {
+    std::string ret(pw->pw_name);
+    return ret;
+  }
+  return std::nullopt;
+}
+
+bool CreateBridge(const std::string& name) {
+  std::stringstream ss;
+  ss << "ip link add name " << name
+     << " type bridge forward_delay 0 stp_state 0";
+
+  auto command = ss.str();
+  LOG(INFO) << "create bridge: " << command;
+  int status = RunExternalCommand(command);
+
+  if (status != 0) {
+    return false;
+  }
+
+  return BringUpIface(name);
+}
+
+bool DestroyBridge(const std::string& name) { return DeleteIface(name); }
+
+bool SetupBridgeGateway(const std::string& bridge_name,
+                        const std::string& ipaddr) {
+  GatewayConfig config{false, false, false};
+  auto gateway = ipaddr + ".1";
+  auto netmask = "/24";
+  auto network = ipaddr + ".0" + netmask;
+  auto dhcp_range = ipaddr + ".2," + ipaddr + ".255";
+
+  if (!AddGateway(bridge_name, gateway, netmask)) {
+    return false;
+  }
+
+  config.has_gateway = true;
+
+  if (StartDnsmasq(bridge_name, gateway, dhcp_range)) {
+    CleanupBridgeGateway(bridge_name, ipaddr, config);
+    return false;
+  }
+
+  config.has_dnsmasq = true;
+
+  auto ret = IptableConfig(network, true);
+  if (!ret) {
+    CleanupBridgeGateway(bridge_name, ipaddr, config);
+    LOG(WARNING) << "Failed to setup ip tables";
+  }
+
+  return ret;
+}
+
+void CleanupBridgeGateway(const std::string& name, const std::string& ipaddr,
+                          const GatewayConfig& config) {
+  auto gateway = ipaddr + ".1";
+  auto netmask = "/24";
+  auto network = ipaddr + ".0" + netmask;
+  auto dhcp_range = ipaddr + ".2," + ipaddr + ".255";
+
+  if (config.has_iptable) {
+    IptableConfig(network, false);
+  }
+
+  if (config.has_dnsmasq) {
+    StopDnsmasq(name);
+  }
+
+  if (config.has_gateway) {
+    DestroyGateway(name, gateway, netmask);
+  }
+}
+
+bool StartDnsmasq(const std::string& bridge_name, const std::string& gateway,
+                  const std::string& dhcp_range) {
+  auto dns_servers = "8.8.8.8,8.8.4.4";
+  auto dns6_servers = "2001:4860:4860::8888,2001:4860:4860::8844";
+  std::stringstream ss;
+
+  // clang-format off
+  ss << 
+  "dnsmasq"
+    " --port=0"
+    " --strict-order"
+    " --except-interface=lo"
+    " --interface=" << bridge_name << 
+    " --listen-address=" << gateway << 
+    " --bind-interfaces"
+    " --dhcp-range=" << dhcp_range << 
+    " --dhcp-option=\"option:dns-server," << dns_servers << "\""
+    " --dhcp-option=\"option6:dns-server," << dns6_servers << "\""
+    " --conf-file=\"\""
+    " --pid-file=/var/run/cuttlefish-dnsmasq-" << bridge_name << ".pid"
+    " --dhcp-leasefile=/var/run/cuttlefish-dnsmasq-" << bridge_name << ".leases"
+    " --dhcp-no-override ";
+  // clang-format on
+
+  auto command = ss.str();
+  LOG(INFO) << "start_dnsmasq: " << command;
+  int status = RunExternalCommand(command);
+
+  return status == 0;
+}
+
+bool StopDnsmasq(const std::string& name) {
+  std::ifstream file;
+  std::string filename = "/var/run/cuttlefish-dnsmasq-" + name + ".pid";
+  LOG(INFO) << "stopping dsnmasq for interface: " << name;
+  file.open(filename);
+  if (file.is_open()) {
+    LOG(INFO) << "dnsmasq file:" << filename
+              << " could not be opened, assume dnsmaq has already stopped";
+    return true;
+  }
+
+  std::string pid;
+  file >> pid;
+  file.close();
+  std::string command = "kill " + pid;
+  int status = RunExternalCommand(command);
+  auto ret = (status == 0);
+
+  if (ret) {
+    LOG(INFO) << "dsnmasq for:" << name << "successfully stopped";
+  } else {
+    LOG(WARNING) << "Failed to stop dsnmasq for:" << name;
+  }
+  return ret;
+}
+
+bool IptableConfig(const std::string& network, bool add) {
+  std::stringstream ss;
+  ss << "iptables -t nat " << (add ? "-A" : "-D") << " POSTROUTING -s "
+     << network << " -j MASQUERADE";
+
+  auto command = ss.str();
+  LOG(INFO) << "iptable_config: " << command;
+  int status = RunExternalCommand(command);
+
+  return status == 0;
+}
+
+bool CreateEthernetBridgeIface(const std::string& name,
+                               const std::string& ipaddr) {
+  if (!CreateBridge(name)) {
+    return false;
+  }
+
+  if (!SetupBridgeGateway(name, ipaddr)) {
+    DestroyBridge(name);
+    return false;
+  }
+
+  return true;
+}
+
+bool DestroyEthernetBridgeIface(const std::string& name,
+                                const std::string& ipaddr) {
+  GatewayConfig config{true, true, true};
+
+  // Don't need to check if removing some part of the config failed, we need to
+  // remove the entire interface, so just ignore any error until the end
+  CleanupBridgeGateway(name, ipaddr, config);
+
+  return DestroyBridge(name);
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/alloc_utils.h b/host/libs/allocd/alloc_utils.h
new file mode 100644
index 0000000..63f6d26
--- /dev/null
+++ b/host/libs/allocd/alloc_utils.h
@@ -0,0 +1,126 @@
+/*
+ * 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 <pwd.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <optional>
+#include <sstream>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/request.h"
+
+namespace cuttlefish {
+
+constexpr char kEbtablesName[] = "ebtables";
+constexpr char kEbtablesLegacyName[] = "ebtables-legacy";
+
+// Wireless network prefix
+constexpr char kWirelessIp[] = "192.168.96";
+// Mobile network prefix
+constexpr char kMobileIp[] = "192.168.97";
+// Ethernet network prefix
+constexpr char kEthernetIp[] = "192.168.98";
+// permission bits for socket
+constexpr int kSocketMode = 0666;
+
+// Max ID an interface can have
+// Note: Interface names only have 2 digits in addition to the username prefix
+// Additionally limited by available netmask values in MobileNetworkName
+// Exceeding 63 would result in an overflow when calculating the netmask
+constexpr uint32_t kMaxIfaceNameId = 63;
+
+// struct for managing configuration state
+struct EthernetNetworkConfig {
+  bool has_broute_ipv4 = false;
+  bool has_broute_ipv6 = false;
+  bool has_tap = false;
+  bool use_ebtables_legacy = false;
+};
+
+// struct for managing configuration state
+struct GatewayConfig {
+  bool has_gateway = false;
+  bool has_dnsmasq = false;
+  bool has_iptable = false;
+};
+
+int RunExternalCommand(const std::string& command);
+std::optional<std::string> GetUserName(uid_t uid);
+
+bool AddTapIface(const std::string& name);
+bool CreateTap(const std::string& name);
+
+bool BringUpIface(const std::string& name);
+bool ShutdownIface(const std::string& name);
+
+bool DestroyIface(const std::string& name);
+bool DeleteIface(const std::string& name);
+
+bool CreateBridge(const std::string& name);
+bool DestroyBridge(const std::string& name);
+
+bool CreateEbtables(const std::string& name, bool use_ipv,
+                    bool use_ebtables_legacy);
+bool DestroyEbtables(const std::string& name, bool use_ipv4,
+                     bool use_ebtables_legacy);
+bool EbtablesBroute(const std::string& name, bool use_ipv4, bool add,
+                    bool use_ebtables_legacy);
+bool EbtablesFilter(const std::string& name, bool use_ipv4, bool add,
+                    bool use_ebtables_legacy);
+
+bool CreateMobileIface(const std::string& name, uint16_t id,
+                       const std::string& ipaddr);
+bool DestroyMobileIface(const std::string& name, uint16_t id,
+                        const std::string& ipaddr);
+
+bool CreateEthernetIface(const std::string& name, const std::string& bridge_name,
+                         bool has_ipv4_bridge, bool has_ipv6_bridge,
+                         bool use_ebtables_legacy);
+bool DestroyEthernetIface(const std::string& name,
+                          bool has_ipv4_bridge, bool use_ipv6,
+                          bool use_ebtables_legacy);
+void CleanupEthernetIface(const std::string& name,
+                          const EthernetNetworkConfig& config);
+
+bool IptableConfig(const std::string& network, bool add);
+
+bool LinkTapToBridge(const std::string& tap_name,
+                     const std::string& bridge_name);
+
+bool SetupBridgeGateway(const std::string& name, const std::string& ipaddr);
+void CleanupBridgeGateway(const std::string& name, const std::string& ipaddr,
+                          const GatewayConfig& config);
+
+bool CreateEthernetBridgeIface(const std::string& name,
+                               const std::string &ipaddr);
+bool DestroyEthernetBridgeIface(const std::string& name,
+                                const std::string &ipaddr);
+
+bool AddGateway(const std::string& name, const std::string& gateway,
+                const std::string& netmask);
+bool DestroyGateway(const std::string& name, const std::string& gateway,
+                    const std::string& netmask);
+
+bool StartDnsmasq(const std::string& bridge_name, const std::string& gateway,
+                  const std::string& dhcp_range);
+bool StopDnsmasq(const std::string& name);
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/allocd.cpp b/host/libs/allocd/allocd.cpp
new file mode 100644
index 0000000..6025dab
--- /dev/null
+++ b/host/libs/allocd/allocd.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <asm-generic/socket.h>
+#include <gflags/gflags.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <cstdint>
+#include <cstdlib>
+#include <iomanip>
+#include <iostream>
+#include <optional>
+#include <set>
+#include <sstream>
+#include <thread>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/alloc_utils.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/allocd/resource_manager.h"
+#include "host/libs/config/logging.h"
+
+DEFINE_string(socket_path, cuttlefish::kDefaultLocation, "Socket path");
+DEFINE_bool(ebtables_legacy, false, "use ebtables-legacy instead of ebtables");
+
+int main(int argc, char* argv[]) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  cuttlefish::SharedFD FinalFD;
+  {
+    cuttlefish::ResourceManager m;
+    m.SetSocketLocation(FLAGS_socket_path);
+    m.SetUseEbtablesLegacy(FLAGS_ebtables_legacy);
+    m.JsonServer();
+  }
+
+  return 0;  // EXIT_SUCCESS? or status
+}
diff --git a/host/libs/allocd/request.h b/host/libs/allocd/request.h
new file mode 100644
index 0000000..bb088d5
--- /dev/null
+++ b/host/libs/allocd/request.h
@@ -0,0 +1,90 @@
+/*
+ * 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 <android-base/logging.h>
+#include <json/json.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+
+namespace cuttlefish {
+
+/// Defines operations supported by allocd
+enum class RequestType : uint16_t {
+  Invalid = 0,       // Invalid Request
+  ID,                // Allocate and return a new Session ID
+  CreateInterface,   // Request to create new network interface
+  DestroyInterface,  // Request to destroy a managed network interface
+  StopSession,       // Request all resources within a session be released
+  Shutdown,          // request allocd to shutdown and clean up all resources
+};
+
+/// Defines interface types supported by allocd
+enum class IfaceType : uint16_t {
+  Invalid = 0,  // an invalid interface
+  mtap,         // mobile tap
+  wtap,         // wireless tap
+  etap,         // ethernet tap
+  wbr,          // wireless bridge
+  ebr           // ethernet bridge
+};
+
+enum class RequestStatus : uint16_t {
+  Invalid = 0,  // Invalid status
+  Pending,      // Request which has not been attempted
+  Success,      // Request was satisfied
+  Failure       // Request failed
+};
+
+/// Defines the format for allocd Request messages
+struct RequestHeader {
+  uint16_t version;  /// used to differentiate between allocd feature sets
+  uint16_t len;      /// length in bytes of the message payload
+};
+
+/// Provides a wrapper around libjson's Reader to additionally log errors
+class JsonRequestReader {
+ public:
+  JsonRequestReader() = default;
+
+  ~JsonRequestReader() = default;
+
+  std::optional<Json::Value> parse(std::string msg) {
+    Json::Value ret;
+    std::unique_ptr<Json::CharReader> reader(reader_builder.newCharReader());
+    std::string errorMessage;
+    if (!reader->parse(&*msg.begin(), &*msg.end(), &ret, &errorMessage)) {
+      LOG(WARNING) << "Received invalid JSON object in input channel: "
+                   << errorMessage;
+      LOG(INFO) << "Invalid JSON: " << msg;
+      return std::nullopt;
+    }
+    return ret;
+  }
+
+ private:
+  Json::CharReaderBuilder reader_builder;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/resource.cpp b/host/libs/allocd/resource.cpp
new file mode 100644
index 0000000..881dd85
--- /dev/null
+++ b/host/libs/allocd/resource.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#include "host/libs/allocd/resource.h"
+
+#include <android-base/logging.h>
+
+#include "host/libs/allocd/alloc_utils.h"
+
+namespace cuttlefish {
+
+bool MobileIface::AcquireResource() {
+  return CreateMobileIface(GetName(), iface_id_, ipaddr_);
+}
+
+bool MobileIface::ReleaseResource() {
+  return DestroyMobileIface(GetName(), iface_id_, ipaddr_);
+}
+
+bool EthernetIface::AcquireResource() {
+  return CreateEthernetIface(GetName(), GetBridgeName(), has_ipv4_, has_ipv6_,
+                             use_ebtables_legacy_);
+}
+
+bool EthernetIface::ReleaseResource() {
+  return DestroyEthernetIface(GetName(), has_ipv4_, has_ipv6_,
+                              use_ebtables_legacy_);
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/resource.h b/host/libs/allocd/resource.h
new file mode 100644
index 0000000..c30e9cc
--- /dev/null
+++ b/host/libs/allocd/resource.h
@@ -0,0 +1,119 @@
+/*
+ * 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 <sys/types.h>
+
+#include <cstdint>
+#include <string>
+
+namespace cuttlefish {
+
+enum class ResourceType {
+  Invalid = 0,
+  MobileIface,
+  EthernetIface,
+  EthernetBridge,
+};
+
+class StaticResource {
+ public:
+  StaticResource() = default;
+  StaticResource(const std::string& name, uid_t uid, ResourceType ty,
+                 uint32_t global_id)
+      : name_(name), uid_(uid), global_id_(global_id), ty_(ty){};
+  virtual ~StaticResource() = default;
+  virtual bool ReleaseResource() = 0;
+  virtual bool AcquireResource() = 0;
+
+  std::string GetName() { return name_; }
+  uid_t GetUid() { return uid_; }
+  ResourceType GetResourceType() { return ty_; }
+  uint32_t GetGlobalID() { return global_id_; }
+
+ private:
+  std::string name_{};
+  uid_t uid_{};
+  uint32_t global_id_{};
+  ResourceType ty_ = ResourceType::Invalid;
+};
+
+class MobileIface : public StaticResource {
+ public:
+  MobileIface() = default;
+  ~MobileIface() = default;
+  MobileIface(const std::string& name, uid_t uid, uint16_t iface_id,
+              uint32_t global_id, std::string ipaddr)
+      : StaticResource(name, uid, ResourceType::MobileIface, global_id),
+        iface_id_(iface_id),
+        ipaddr_(ipaddr) {}
+
+  bool ReleaseResource() override;
+  bool AcquireResource() override;
+
+  uint16_t GetIfaceId() { return iface_id_; }
+  std::string GetIpAddr() { return ipaddr_; }
+
+  static constexpr char kNetmask[] = "/30";
+
+ private:
+  uint16_t iface_id_;
+  std::string ipaddr_;
+};
+
+class EthernetIface : public StaticResource {
+ public:
+  EthernetIface() = default;
+  ~EthernetIface() = default;
+
+  EthernetIface(const std::string& name, uid_t uid, uint16_t iface_id,
+                uint32_t global_id, std::string bridge_name,
+                std::string ipaddr)
+      : StaticResource(name, uid, ResourceType::MobileIface, global_id),
+        iface_id_(iface_id),
+        bridge_name_(bridge_name),
+        ipaddr_(ipaddr) {}
+
+  bool ReleaseResource() override;
+  bool AcquireResource() override;
+
+  uint16_t GetIfaceId() { return iface_id_; }
+
+  std::string GetBridgeName() { return bridge_name_; }
+  std::string GetIpAddr() { return ipaddr_; }
+
+  void SetHasIpv4(bool ipv4) { has_ipv4_ = ipv4; }
+  void SetHasIpv6(bool ipv6) { has_ipv6_ = ipv6; }
+  void SetUseEbtablesLegacy(bool use_legacy) {
+    use_ebtables_legacy_ = use_legacy;
+  }
+
+  bool GetHasIpv4() { return has_ipv4_; }
+  bool GetHasIpv6() { return has_ipv6_; }
+  bool GetUseEbtablesLegacy() { return use_ebtables_legacy_; }
+
+ private:
+  static constexpr char kNetmask[] = "/24";
+  uint16_t iface_id_;
+  std::string bridge_name_;
+  std::string ipaddr_;
+  bool has_ipv4_ = true;
+  bool has_ipv6_ = true;
+  bool use_ebtables_legacy_ = false;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/resource_manager.cpp b/host/libs/allocd/resource_manager.cpp
new file mode 100644
index 0000000..aaa8fe0
--- /dev/null
+++ b/host/libs/allocd/resource_manager.cpp
@@ -0,0 +1,619 @@
+/*
+ * 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.
+ */
+
+#include "host/libs/allocd/resource_manager.h"
+
+#include <android-base/logging.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <cstdint>
+#include <cstdlib>
+#include <iomanip>
+#include <memory>
+#include <optional>
+#include <sstream>
+#include <string>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/alloc_utils.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/allocd/utils.h"
+#include "json/forwards.h"
+#include "json/value.h"
+#include "json/writer.h"
+
+namespace cuttlefish {
+
+uid_t GetUserIDFromSock(SharedFD client_socket);
+
+ResourceManager::~ResourceManager() {
+  bool success = true;
+  for (auto& res : managed_sessions_) {
+    success &= res.second->ReleaseAllResources();
+  }
+
+  Json::Value resp;
+  resp["request_type"] = "shutdown";
+  auto status = success ? RequestStatus::Success : RequestStatus::Failure;
+  resp["request_status"] = StatusToStr(status);
+  SendJsonMsg(shutdown_socket_, resp);
+  LOG(INFO) << "Daemon Shutdown complete";
+  unlink(location.c_str());
+}
+
+void ResourceManager::SetSocketLocation(const std::string& sock_name) {
+  location = sock_name;
+}
+
+void ResourceManager::SetUseEbtablesLegacy(bool use_legacy) {
+  use_ebtables_legacy_ = use_legacy;
+}
+
+uint32_t ResourceManager::AllocateResourceID() {
+  return global_resource_id_.fetch_add(1, std::memory_order_relaxed);
+}
+
+uint32_t ResourceManager::AllocateSessionID() {
+  return session_id_.fetch_add(1, std::memory_order_relaxed);
+}
+
+bool ResourceManager::AddInterface(const std::string& iface, IfaceType ty,
+                                   uint32_t resource_id, uid_t uid) {
+  bool allocatedIface = false;
+  std::shared_ptr<StaticResource> res = nullptr;
+
+  bool didInsert = active_interfaces_.insert(iface).second;
+  if (didInsert) {
+    const char* idp = iface.c_str() + (iface.size() - 3);
+    int small_id = atoi(idp);
+    switch (ty) {
+      case IfaceType::mtap:
+        res = std::make_shared<MobileIface>(iface, uid, small_id, resource_id,
+                                            kMobileIp);
+        allocatedIface = res->AcquireResource();
+        pending_add_.insert({resource_id, res});
+        break;
+      case IfaceType::wtap: {
+        // TODO (paulkirth): change this to cvd-wbr, to test w/ today's
+        // debian package, this is required since the number of wireless
+        // bridges provided by the debian package has gone from 10 down to
+        // 1, but our debian packages in cloudtop are not up to date
+        auto w = std::make_shared<EthernetIface>(iface, uid, small_id,
+                                                 resource_id, "cvd-wbr-01",
+                                                 kWirelessIp);
+        w->SetUseEbtablesLegacy(use_ebtables_legacy_);
+        w->SetHasIpv4(use_ipv4_bridge_);
+        w->SetHasIpv6(use_ipv6_bridge_);
+        res = w;
+        allocatedIface = res->AcquireResource();
+        pending_add_.insert({resource_id, res});
+        break;
+      }
+      case IfaceType::etap: {
+        auto w = std::make_shared<EthernetIface>(iface, uid, small_id,
+                                                 resource_id, "cvd-ebr",
+                                                 kEthernetIp);
+        w->SetUseEbtablesLegacy(use_ebtables_legacy_);
+        w->SetHasIpv4(use_ipv4_bridge_);
+        w->SetHasIpv6(use_ipv6_bridge_);
+        res = w;
+        allocatedIface = res->AcquireResource();
+        pending_add_.insert({resource_id, res});
+        break;
+      }
+      case IfaceType::wbr:
+      case IfaceType::ebr:
+        allocatedIface = CreateBridge(iface);
+        break;
+      case IfaceType::Invalid:
+        break;
+    }
+  } else {
+    LOG(WARNING) << "Interface already in use: " << iface;
+  }
+
+  if (didInsert && !allocatedIface) {
+    LOG(WARNING) << "Failed to allocate interface: " << iface;
+    active_interfaces_.erase(iface);
+    auto it = pending_add_.find(resource_id);
+    it->second->ReleaseResource();
+    pending_add_.erase(it);
+  }
+
+  LOG(INFO) << "Finish CreateInterface Request";
+
+  return allocatedIface;
+}
+
+bool ResourceManager::RemoveInterface(const std::string& iface, IfaceType ty) {
+  bool isManagedIface = active_interfaces_.erase(iface) > 0;
+  bool removedIface = false;
+  if (isManagedIface) {
+    switch (ty) {
+      case IfaceType::mtap: {
+        const char* idp = iface.c_str() + (iface.size() - 3);
+        int id = atoi(idp);
+        removedIface = DestroyMobileIface(iface, id, kMobileIp);
+        break;
+      }
+      case IfaceType::wtap:
+      case IfaceType::etap:
+        removedIface = DestroyEthernetIface(
+            iface, use_ipv4_bridge_, use_ipv6_bridge_, use_ebtables_legacy_);
+        break;
+      case IfaceType::wbr:
+      case IfaceType::ebr:
+        removedIface = DestroyBridge(iface);
+        break;
+      case IfaceType::Invalid:
+        break;
+    }
+
+  } else {
+    LOG(WARNING) << "Interface not managed: " << iface;
+  }
+
+  if (isManagedIface) {
+    LOG(INFO) << "Removed interface: " << iface;
+  } else {
+    LOG(WARNING) << "Could not remove interface: " << iface;
+  }
+
+  return isManagedIface;
+}
+
+bool ResourceManager::ValidateRequestList(const Json::Value& config) {
+  if (!config.isMember("request_list") || !config["request_list"].isArray()) {
+    LOG(WARNING) << "Request has invalid 'request_list' field";
+    return false;
+  }
+
+  auto request_list = config["request_list"];
+
+  Json::ArrayIndex size = request_list.size();
+  if (size == 0) {
+    LOG(WARNING) << "Request has empty 'request_list' field";
+    return false;
+  }
+
+  for (Json::ArrayIndex i = 0; i < size; ++i) {
+    if (!ValidateRequest(request_list[i])) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool ResourceManager::ValidateConfigRequest(const Json::Value& config) {
+  if (!config.isMember("config_request") ||
+      !config["config_request"].isObject()) {
+    LOG(WARNING) << "Request has invalid 'config_request' field";
+    return false;
+  }
+
+  Json::Value config_request = config["config_request"];
+
+  return ValidateRequestList(config_request);
+}
+
+bool ResourceManager::ValidateRequest(const Json::Value& request) {
+  if (!request.isMember("request_type") ||
+      !request["request_type"].isString() ||
+      StrToReqTy(request["request_type"].asString()) == RequestType::Invalid) {
+    LOG(WARNING) << "Request has invalid 'request_type' field";
+    return false;
+  }
+  return true;
+}
+
+void ResourceManager::JsonServer() {
+  LOG(INFO) << "Starting server on " << kDefaultLocation;
+  auto server = SharedFD::SocketLocalServer(kDefaultLocation, false,
+                                            SOCK_STREAM, kSocketMode);
+  CHECK(server->IsOpen()) << "Could not start server at " << kDefaultLocation;
+  LOG(INFO) << "Accepting client connections";
+
+  while (true) {
+    auto client_socket = SharedFD::Accept(*server);
+    CHECK(client_socket->IsOpen()) << "Error creating client socket";
+
+    struct timeval timeout;
+    timeout.tv_sec = 10;
+    timeout.tv_usec = 0;
+
+    int err = client_socket->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO, &timeout,
+                                        sizeof(timeout));
+    if (err < 0) {
+      LOG(WARNING) << "Could not set socket timeout";
+      continue;
+    }
+
+    auto req_opt = RecvJsonMsg(client_socket);
+
+    if (!req_opt) {
+      LOG(WARNING) << "Invalid JSON Request, closing connection";
+      continue;
+    }
+
+    Json::Value req = req_opt.value();
+
+    if (!ValidateConfigRequest(req)) {
+      continue;
+    }
+
+    Json::Value req_list = req["config_request"]["request_list"];
+
+    Json::Value config_response;
+    Json::Value response_list;
+    Json::ArrayIndex req_list_size = req_list.size();
+
+    // sentinel value, so we can populate the list of responses correctly
+    // without trying to satisfy requests that will be aborted
+    bool transaction_failed = false;
+
+    for (Json::ArrayIndex i = 0; i < req_list_size; ++i) {
+      LOG(INFO) << "Processing Request: " << i;
+      auto req = req_list[i];
+      auto req_ty_str = req["request_type"].asString();
+      auto req_ty = StrToReqTy(req_ty_str);
+
+      Json::Value response;
+      if (transaction_failed) {
+        response["request_type"] = req_ty_str;
+        response["request_status"] = "pending";
+        response["error"] = "";
+        response_list.append(response);
+        continue;
+      }
+
+      switch (req_ty) {
+        case RequestType::ID: {
+          response = JsonHandleIdRequest();
+          break;
+        }
+        case RequestType::Shutdown: {
+          if (i != 0 || req_list_size != 1) {
+            response["request_type"] = req_ty_str;
+            response["request_status"] = "failed";
+            response["error"] =
+                "Shutdown requests cannot be processed with other "
+                "configuration requests";
+            response_list.append(response);
+            break;
+          } else {
+            response = JsonHandleShutdownRequest(client_socket);
+            response_list.append(response);
+            return;
+          }
+        }
+        case RequestType::CreateInterface: {
+          response = JsonHandleCreateInterfaceRequest(client_socket, req);
+          break;
+        }
+        case RequestType::DestroyInterface: {
+          response = JsonHandleDestroyInterfaceRequest(req);
+          break;
+        }
+        case RequestType::StopSession: {
+          response = JsonHandleStopSessionRequest(
+              req, GetUserIDFromSock(client_socket));
+          break;
+        }
+        case RequestType::Invalid: {
+          LOG(WARNING) << "Invalid Request Type: " << req["request_type"];
+          break;
+        }
+      }
+
+      response_list.append(response);
+      if (!(response["request_status"].asString() ==
+            StatusToStr(RequestStatus::Success))) {
+        LOG(INFO) << "Request failed:" << req;
+        transaction_failed = true;
+        continue;
+      }
+    }
+
+    config_response["response_list"] = response_list;
+
+    auto status =
+        transaction_failed ? RequestStatus::Failure : RequestStatus::Success;
+    config_response["config_status"] = StatusToStr(status);
+
+    if (!transaction_failed) {
+      auto session_id = AllocateSessionID();
+      config_response["session_id"] = session_id;
+      auto s = std::make_shared<Session>(session_id,
+                                         GetUserIDFromSock(client_socket));
+
+      // commit the resources
+      s->Insert(pending_add_);
+      pending_add_.clear();
+      managed_sessions_.insert({session_id, s});
+    } else {
+      // be sure to release anything we've acquired if the transaction failed
+      for (auto& droped_resource : pending_add_) {
+        droped_resource.second->ReleaseResource();
+      }
+    }
+
+    SendJsonMsg(client_socket, config_response);
+    LOG(INFO) << "Closing connection to client";
+    client_socket->Close();
+  }
+  server->Close();
+}
+
+uid_t GetUserIDFromSock(SharedFD client_socket) {
+  struct ucred ucred {};
+  socklen_t len = sizeof(struct ucred);
+
+  if (-1 == client_socket->GetSockOpt(SOL_SOCKET, SO_PEERCRED, &ucred, &len)) {
+    LOG(WARNING) << "Failed to get Socket Credentials";
+    return -1;
+  }
+
+  return ucred.uid;
+}
+
+bool ResourceManager::CheckCredentials(SharedFD client_socket, uid_t uid) {
+  uid_t sock_uid = GetUserIDFromSock(client_socket);
+
+  if (sock_uid == -1) {
+    LOG(WARNING) << "Invalid Socket UID: " << uid;
+    return false;
+  }
+
+  if (uid != sock_uid) {
+    LOG(WARNING) << "Message UID: " << uid
+                 << " does not match socket's EUID: " << sock_uid;
+    return false;
+  }
+
+  return true;
+}
+
+Json::Value ResourceManager::JsonHandleIdRequest() {
+  Json::Value resp;
+  resp["request_type"] = "allocate_id";
+  resp["request_status"] = StatusToStr(RequestStatus::Success);
+  resp["id"] = AllocateSessionID();
+  return resp;
+}
+
+Json::Value ResourceManager::JsonHandleShutdownRequest(SharedFD client_socket) {
+  LOG(INFO) << "Received Shutdown Request";
+  shutdown_socket_ = client_socket;
+
+  Json::Value resp;
+  resp["request_type"] = "shutdown";
+  resp["request_status"] = "pending";
+  resp["error"] = "";
+
+  return resp;
+}
+
+Json::Value ResourceManager::JsonHandleCreateInterfaceRequest(
+    SharedFD client_socket, const Json::Value& request) {
+  LOG(INFO) << "Received CreateInterface Request";
+
+  Json::Value resp;
+  resp["request_type"] = "create_interface";
+  resp["iface_name"] = "";
+  resp["request_status"] = StatusToStr(RequestStatus::Failure);
+  resp["error"] = "unknown";
+
+  if (!request.isMember("uid") || !request["uid"].isUInt()) {
+    auto err_msg = "Input event doesn't have a valid 'uid' field";
+    LOG(WARNING) << err_msg;
+    resp["error"] = err_msg;
+    return resp;
+  }
+
+  if (!request.isMember("iface_type") || !request["iface_type"].isString()) {
+    auto err_msg = "Input event doesn't have a valid 'iface_type' field";
+    LOG(WARNING) << err_msg;
+    resp["error"] = err_msg;
+    return resp;
+  }
+
+  auto uid = request["uid"].asUInt();
+
+  if (!CheckCredentials(client_socket, uid)) {
+    auto err_msg = "Credential check failed";
+    LOG(WARNING) << err_msg;
+    resp["error"] = err_msg;
+    return resp;
+  }
+
+  auto user_opt = GetUserName(uid);
+
+  bool addedIface = false;
+  std::stringstream ss;
+  if (!user_opt) {
+    auto err_msg = "UserName could not be matched to UID";
+    LOG(WARNING) << err_msg;
+    resp["error"] = err_msg;
+    return resp;
+  } else {
+    auto iface_ty_name = request["iface_type"].asString();
+    resp["iface_type"] = iface_ty_name;
+    auto iface_type = StrToIfaceTy(iface_ty_name);
+    auto attempts = kMaxIfaceNameId;
+    do {
+      auto id = AllocateResourceID();
+      resp["resource_id"] = id;
+      ss << "cvd-" << iface_ty_name << "-" << user_opt.value().substr(0, 4)
+         << std::setfill('0') << std::setw(2) << (id % kMaxIfaceNameId);
+      addedIface = AddInterface(ss.str(), iface_type, id, uid);
+      --attempts;
+    } while (!addedIface && (attempts > 0));
+  }
+
+  if (addedIface) {
+    resp["request_status"] = StatusToStr(RequestStatus::Success);
+    resp["iface_name"] = ss.str();
+    resp["error"] = "";
+  }
+
+  return resp;
+}
+
+Json::Value ResourceManager::JsonHandleDestroyInterfaceRequest(
+    const Json::Value& request) {
+  Json::Value resp;
+  resp["request_type"] = "destroy_interface";
+  resp["request_status"] = StatusToStr(RequestStatus::Failure);
+  if (!request.isMember("iface_name") || !request["iface_name"].isString()) {
+    auto err_msg = "Input event doesn't have a valid 'iface_name' field";
+    LOG(WARNING) << err_msg;
+    resp["error"] = err_msg;
+    return resp;
+  }
+
+  auto iface_name = request["iface_name"].asString();
+
+  bool isManagedIface = active_interfaces_.erase(iface_name) > 0;
+
+  if (!isManagedIface) {
+    auto msg = "Interface not managed: " + iface_name;
+    LOG(WARNING) << msg;
+    resp["error"] = msg;
+    return resp;
+  }
+
+  if (!request.isMember("session_id") || !request["session_id"].isUInt()) {
+    auto err_msg = "Input event doesn't have a valid 'session_id' field";
+    LOG(WARNING) << err_msg;
+    resp["error"] = err_msg;
+    return resp;
+  }
+
+  auto session_id = request["session_id"].asUInt();
+
+  auto resource_id = request["resource_id"].asUInt();
+
+  LOG(INFO) << "Received DestroyInterface Request for " << iface_name
+            << " in session: " << session_id
+            << ", resource_id: " << resource_id;
+
+  auto sess_opt = FindSession(session_id);
+  if (!sess_opt) {
+    auto msg = "Interface " + iface_name +
+               " was not managed in session: " + std::to_string(session_id) +
+               " with resource_id: " + std::to_string(resource_id);
+    LOG(WARNING) << msg;
+    resp["error"] = msg;
+    return resp;
+  }
+
+  auto s = sess_opt.value();
+
+  // while we could wait to see if any acquisitions fail and delay releasing
+  // resources until they are all finished, this operation is inherently
+  // destructive, so should a release operation fail, there is no satisfactory
+  // method for aborting the transaction. Instead, we try to release the
+  // resource and then can signal to the rest of the transaction the failure
+  // state, which can then just stop the transaction, and revert any newly
+  // acquired resources, but any successful drop requests will persist
+  auto did_drop_resource = s->ReleaseResource(resource_id);
+
+  if (did_drop_resource) {
+    resp["request_status"] = StatusToStr(RequestStatus::Success);
+  } else {
+    auto msg = "Interface " + iface_name +
+               " was not managed in session: " + std::to_string(session_id) +
+               " with resource_id: " + std::to_string(resource_id);
+    LOG(WARNING) << msg;
+    resp["error"] = msg;
+  }
+
+  return resp;
+}
+
+Json::Value ResourceManager::JsonHandleStopSessionRequest(
+    const Json::Value& request, uid_t uid) {
+  Json::Value resp;
+  resp["request_type"] = ReqTyToStr(RequestType::StopSession);
+  resp["request_status"] = StatusToStr(RequestStatus::Failure);
+  if (!request.isMember("session_id") || !request["session_id"].isUInt()) {
+    auto err_msg = "Input event doesn't have a valid 'session_id' field";
+    LOG(WARNING) << err_msg;
+    resp["error"] = err_msg;
+    return resp;
+  }
+
+  auto session_id = request["session_id"].asUInt();
+  LOG(INFO) << "Received StopSession Request for Session ID: " << session_id;
+
+  auto it = managed_sessions_.find(session_id);
+  if (it == managed_sessions_.end()) {
+    auto msg = "Session not managed: " + std::to_string(session_id);
+    LOG(WARNING) << msg;
+    resp["error"] = msg;
+    return resp;
+  }
+
+  if (it->second->GetUID() != uid) {
+    auto msg = "Effective user ID does not match session owner. socket uid: " +
+               std::to_string(uid);
+    LOG(WARNING) << msg;
+    resp["error"] = msg;
+    return resp;
+  }
+
+  // while we could wait to see if any acquisitions fail and delay releasing
+  // resources until they are all finished, this operation is inherently
+  // destructive, so should a release operation fail, there is no satisfactory
+  // method for aborting the transaction. Instead, we try to release the
+  // resource and then can signal to the rest of the transaction the failure
+  // state
+  auto success = it->second->ReleaseAllResources();
+
+  // release the names from the global list for reuse in future requests
+  for (auto& iface : it->second->GetActiveInterfaces()) {
+    active_interfaces_.erase(iface);
+  }
+
+  if (success) {
+    managed_sessions_.erase(it);
+    resp["request_status"] = StatusToStr(RequestStatus::Success);
+  } else {
+    resp["error"] =
+        "unknown, allocd experienced an error ending the session id: " +
+        std::to_string(session_id);
+  }
+
+  return resp;
+}
+
+std::optional<std::shared_ptr<Session>> ResourceManager::FindSession(
+    uint32_t id) {
+  auto it = managed_sessions_.find(id);
+  if (it == managed_sessions_.end()) {
+    return std::nullopt;
+  } else {
+    return it->second;
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/resource_manager.h b/host/libs/allocd/resource_manager.h
new file mode 100644
index 0000000..32f06cf
--- /dev/null
+++ b/host/libs/allocd/resource_manager.h
@@ -0,0 +1,155 @@
+/*
+ * 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 <sys/types.h>
+
+#include <atomic>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/alloc_utils.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/allocd/resource.h"
+#include "host/libs/allocd/utils.h"
+
+namespace cuttlefish {
+
+class Session {
+ public:
+  explicit Session(uint32_t session_id, uid_t uid)
+      : session_id_(session_id), uid_(uid) {}
+  ~Session() { ReleaseAllResources(); }
+
+  uint32_t GetSessionID() { return session_id_; }
+  uid_t GetUID() { return uid_; }
+
+  const std::set<std::string>& GetActiveInterfaces() {
+    return active_interfaces_;
+  }
+
+  void Insert(
+      const std::map<uint32_t, std::shared_ptr<StaticResource>>& resources) {
+    managed_resources_.insert(resources.begin(), resources.end());
+  }
+
+  bool ReleaseAllResources() {
+    bool success = true;
+    for (auto& res : managed_resources_) {
+      success &= res.second->ReleaseResource();
+    }
+    managed_resources_.clear();
+
+    return success;
+  }
+
+  bool ReleaseResource(uint32_t resource_id) {
+    auto it = managed_resources_.find(resource_id);
+    if (it == managed_resources_.end()) {
+      return false;
+    }
+
+    auto success = it->second->ReleaseResource();
+    if (success) {
+      managed_resources_.erase(it);
+    }
+
+    return success;
+  }
+
+ private:
+  uint32_t session_id_{};
+  uid_t uid_{};
+  std::set<std::string> active_interfaces_;
+  std::map<uint32_t, std::shared_ptr<StaticResource>> managed_resources_;
+};
+
+/* Manages static resources while the daemon is running.
+ * When resources, such as network interfaces are requested the ResourceManager
+ * allocates the resources and takes ownership of them. It will keep maintain
+ * the resource, until requested to release it(i.e. destroy it and/or tear down
+ * related config). When the daemon is stopped, it will walk its list of owned
+ * resources, and deallocate them from the system.
+ *
+ * Clients can request new resources by connecting to a socket, and sending a
+ * JSON request, detailing the type of resource required.
+ */
+struct ResourceManager {
+ public:
+  ResourceManager() = default;
+
+  ~ResourceManager();
+
+  void SetSocketLocation(const std::string& sock_name);
+
+  void SetUseEbtablesLegacy(bool use_legacy);
+
+  void JsonServer();
+
+ private:
+  uint32_t AllocateResourceID();
+  uint32_t AllocateSessionID();
+
+  bool AddInterface(const std::string& iface, IfaceType ty, uint32_t id,
+                    uid_t uid);
+
+  bool RemoveInterface(const std::string& iface, IfaceType ty);
+
+  bool ValidateRequest(const Json::Value& request);
+
+  bool ValidateRequestList(const Json::Value& config);
+
+  bool ValidateConfigRequest(const Json::Value& config);
+
+  Json::Value JsonHandleIdRequest();
+
+  Json::Value JsonHandleShutdownRequest(SharedFD client_socket);
+
+  Json::Value JsonHandleCreateInterfaceRequest(SharedFD client_socket,
+                                               const Json::Value& request);
+
+  Json::Value JsonHandleDestroyInterfaceRequest(const Json::Value& request);
+
+  Json::Value JsonHandleStopSessionRequest(const Json::Value& request,
+                                           uid_t uid);
+
+  bool CheckCredentials(SharedFD client_socket, uid_t uid);
+
+  void SetUseIpv4Bridge(bool ipv4) { use_ipv4_bridge_ = ipv4; }
+
+  void SetUseIpv6Bridge(bool ipv6) { use_ipv6_bridge_ = ipv6; }
+
+  std::optional<std::shared_ptr<Session>> FindSession(uint32_t id);
+
+ private:
+  std::atomic_uint32_t global_resource_id_ = 0;
+  std::atomic_uint32_t session_id_ = 0;
+  std::set<std::string> active_interfaces_;
+  std::map<uint32_t, std::shared_ptr<Session>> managed_sessions_;
+  std::map<uint32_t, std::shared_ptr<StaticResource>> pending_add_;
+  std::string location = kDefaultLocation;
+  bool use_ipv4_bridge_ = true;
+  bool use_ipv6_bridge_ = true;
+  bool use_ebtables_legacy_ = false;
+  cuttlefish::SharedFD shutdown_socket_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/test/client.cpp b/host/libs/allocd/test/client.cpp
new file mode 100644
index 0000000..235f521
--- /dev/null
+++ b/host/libs/allocd/test/client.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
+#include <json/json.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/allocd/utils.h"
+#include "host/libs/config/logging.h"
+
+using namespace cuttlefish;
+
+DEFINE_string(socket_path, kDefaultLocation, "Socket path");
+DEFINE_bool(id, false, "Request new UUID");
+DEFINE_bool(ifcreate, false, "Request a new Interface");
+DEFINE_bool(shutdown, false, "Shutdown Resource Allocation Server");
+DEFINE_bool(stop_session, false, "Remove all resources from session");
+DEFINE_string(ifdestroy, "", "Request an interface be destroyed");
+DEFINE_uint32(ifid, -1, "Global Resource ID");
+DEFINE_uint32(session, -1, "Session ID");
+
+int main(int argc, char* argv[]) {
+  cuttlefish::DefaultSubprocessLogging(argv);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  SharedFD monitor_socket = cuttlefish::SharedFD::SocketLocalClient(
+      FLAGS_socket_path, false, SOCK_STREAM);
+  if (!monitor_socket->IsOpen()) {
+    LOG(ERROR) << "Unable to connect to launcher monitor on "
+               << FLAGS_socket_path << ": " << monitor_socket->StrError();
+    return 1;
+  }
+
+  if (FLAGS_id) {
+    Json::Value req;
+    req["request_type"] = "allocate_id";
+    SendJsonMsg(monitor_socket, req);
+
+    auto resp_opt = RecvJsonMsg(monitor_socket);
+    if (!resp_opt.has_value()) {
+      std::cout << "Bad Response from server\n";
+      return -1;
+    }
+
+    auto resp = resp_opt.value();
+    std::cout << resp << "\n";
+    std::cout << "New ID operation: " << resp["request_status"] << std::endl;
+    std::cout << "New ID: " << resp["id"] << std::endl;
+  }
+
+  Json::Value config;
+  Json::Value request_list;
+
+  if (FLAGS_ifcreate) {
+    Json::Value req;
+    req["request_type"] = "create_interface";
+    req["uid"] = geteuid();
+    req["iface_type"] = "mtap";
+    request_list.append(req);
+    req["iface_type"] = "wtap";
+
+    request_list.append(req);
+    config["config_request"]["request_list"] = request_list;
+
+    std::cout << config << "\n";
+    SendJsonMsg(monitor_socket, config);
+
+    auto resp_opt = RecvJsonMsg(monitor_socket);
+    if (!resp_opt.has_value()) {
+      std::cout << "Bad Response from server\n";
+      return -1;
+    }
+
+    auto resp = resp_opt.value();
+
+    std::cout << resp << "\n";
+    std::cout << "Create Interface operation: " << resp["request_status"]
+              << std::endl;
+    std::cout << resp["iface_name"] << std::endl;
+  }
+
+  if (!FLAGS_ifdestroy.empty() && (FLAGS_ifid != -1) && (FLAGS_session != -1)) {
+    Json::Value req;
+    req["request_type"] = "destroy_interface";
+    req["iface_name"] = FLAGS_ifdestroy;
+    req["resource_id"] = FLAGS_ifid;
+    req["session_id"] = FLAGS_session;
+    request_list.append(req);
+    config["config_request"]["request_list"] = request_list;
+    SendJsonMsg(monitor_socket, config);
+
+    LOG(INFO) << "Request Interface : '" << FLAGS_ifdestroy << "' be removed";
+
+    auto resp_opt = RecvJsonMsg(monitor_socket);
+    if (!resp_opt.has_value()) {
+      std::cout << "Bad Response from server\n";
+      return -1;
+    }
+
+    auto resp = resp_opt.value();
+
+    std::cout << resp << "\n";
+
+    std::cout << "Destroy Interface operation: " << resp["request_status"]
+              << std::endl;
+    std::cout << resp["iface_name"] << std::endl;
+  }
+
+  if (FLAGS_stop_session && (FLAGS_session != -1)) {
+    Json::Value req;
+    req["request_type"] = "stop_session";
+    req["session_id"] = FLAGS_session;
+    request_list.append(req);
+    config["config_request"]["request_list"] = request_list;
+    SendJsonMsg(monitor_socket, config);
+
+    LOG(INFO) << "Request Session : '" << FLAGS_session << "' be stopped";
+
+    auto resp_opt = RecvJsonMsg(monitor_socket);
+    if (!resp_opt.has_value()) {
+      std::cout << "Bad Response from server\n";
+      return -1;
+    }
+
+    auto resp = resp_opt.value();
+
+    std::cout << resp << "\n";
+    std::cout << "Stop Session operation: " << resp["config_status"];
+  }
+
+  if (FLAGS_shutdown) {
+    Json::Value req;
+    req["request_type"] = "shutdown";
+
+    request_list.append(req);
+    config["config_request"]["request_list"] = request_list;
+    cuttlefish::SendJsonMsg(monitor_socket, config);
+
+    auto resp_opt = cuttlefish::RecvJsonMsg(monitor_socket);
+    if (!resp_opt.has_value()) {
+      std::cout << "Bad Response from server\n";
+      return -1;
+    }
+
+    auto resp = resp_opt.value();
+
+    std::cout << resp << "\n";
+    std::cout << "Shutdown operation: " << resp["request_status"] << std::endl;
+  }
+
+  return 0;
+}
diff --git a/host/libs/allocd/utils.cpp b/host/libs/allocd/utils.cpp
new file mode 100644
index 0000000..64eb127
--- /dev/null
+++ b/host/libs/allocd/utils.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#include "host/libs/allocd/utils.h"
+
+#include <cstdint>
+#include <optional>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/request.h"
+
+namespace cuttlefish {
+
+// While the JSON schema and payload structure are designed to be extensible,
+// and avoid version incompatibility. However, should project requirements
+// change, it is necessary that we have a mechanism to handle incompatibilities
+// that arise over time. If an incompatibility should come about, the
+// kMinHeaderVersion constant should be increased to match the new minimal set
+// of features that are supported.
+
+/// Current supported Header version number
+constexpr uint16_t kCurHeaderVersion = 1;
+
+/// Oldest compatible header version number
+constexpr uint16_t kMinHeaderVersion = 1;
+
+const std::map<RequestType, const char*> RequestTyToStrMap = {
+    {RequestType::ID, "alloc_id"},
+    {RequestType::CreateInterface, "create_interface"},
+    {RequestType::DestroyInterface, "destroy_interface"},
+    {RequestType::StopSession, "stop_session"},
+    {RequestType::Shutdown, "shutdown"},
+    {RequestType::Invalid, "invalid"}};
+
+const std::map<std::string, RequestType> StrToRequestTyMap = {
+    {"alloc_id", RequestType::ID},
+    {"create_interface", RequestType::CreateInterface},
+    {"destroy_interface", RequestType::DestroyInterface},
+    {"stop_session", RequestType::StopSession},
+    {"shutdown", RequestType::Shutdown},
+    {"invalid", RequestType::Invalid}};
+
+const std::map<std::string, IfaceType> StrToIfaceTyMap = {
+    {"invalid", IfaceType::Invalid},
+    {"mtap", IfaceType::mtap},
+    {"wtap", IfaceType::wtap},
+    {"etap", IfaceType::etap},
+    {"wbr", IfaceType::wbr},
+    {"ebr", IfaceType::ebr}};
+
+const std::map<IfaceType, std::string> IfaceTyToStrMap = {
+    {IfaceType::Invalid, "invalid"},
+    {IfaceType::mtap, "mtap"},
+    {IfaceType::wtap, "wtap"},
+    {IfaceType::etap, "etap"},
+    {IfaceType::wbr, "wbr"},
+    {IfaceType::ebr, "ebr"}};
+
+const std::map<RequestStatus, std::string> ReqStatusToStrMap = {
+    {RequestStatus::Invalid, "invalid"},
+    {RequestStatus::Pending, "pending"},
+    {RequestStatus::Failure, "failure"},
+    {RequestStatus::Success, "success"}};
+
+const std::map<std::string, RequestStatus> StrToReqStatusMap = {
+    {"invalid", RequestStatus::Invalid},
+    {"pending", RequestStatus::Pending},
+    {"failure", RequestStatus::Failure},
+    {"success", RequestStatus::Success}};
+
+bool SendJsonMsg(SharedFD client_socket, const Json::Value& resp) {
+  LOG(INFO) << "Sending JSON message";
+  Json::StreamWriterBuilder factory;
+  auto resp_str = Json::writeString(factory, resp);
+
+  std::string header_buff(sizeof(RequestHeader), 0);
+
+  // fill in header
+  RequestHeader* header = reinterpret_cast<RequestHeader*>(header_buff.data());
+  header->len = resp_str.size();
+  header->version = kCurHeaderVersion;
+
+  auto payload = header_buff + resp_str;
+
+  return SendAll(client_socket, payload);
+}
+
+std::optional<Json::Value> RecvJsonMsg(SharedFD client_socket) {
+  LOG(INFO) << "Receiving JSON message";
+  RequestHeader header;
+  client_socket->Recv(&header, sizeof(header), kRecvFlags);
+
+  if (header.version < kMinHeaderVersion) {
+    LOG(WARNING) << "bad request header version: " << header.version;
+    return std::nullopt;
+  }
+
+  std::string payload = RecvAll(client_socket, header.len);
+
+  JsonRequestReader reader;
+  return reader.parse(payload);
+}
+
+std::string ReqTyToStr(RequestType req_ty) {
+  switch (req_ty) {
+    case RequestType::Invalid:
+      return "invalid";
+    case RequestType::Shutdown:
+      return "shutdown";
+    case RequestType::StopSession:
+      return "stop_session";
+    case RequestType::DestroyInterface:
+      return "destroy_interface";
+    case RequestType::CreateInterface:
+      return "create_interface";
+    case RequestType::ID:
+      return "id";
+  }
+}
+
+RequestType StrToReqTy(const std::string& req) {
+  auto it = StrToRequestTyMap.find(req);
+  if (it == StrToRequestTyMap.end()) {
+    return RequestType::Invalid;
+  } else {
+    return it->second;
+  }
+}
+
+RequestStatus StrToStatus(const std::string& st) {
+  auto it = StrToReqStatusMap.find(st);
+  if (it == StrToReqStatusMap.end()) {
+    return RequestStatus::Invalid;
+  } else {
+    return it->second;
+  }
+}
+
+std::string StatusToStr(RequestStatus st) {
+  switch (st) {
+    case RequestStatus::Invalid:
+      return "invalid";
+    case RequestStatus::Pending:
+      return "pending";
+    case RequestStatus::Success:
+      return "success";
+    case RequestStatus::Failure:
+      return "failure";
+  }
+}
+
+std::string IfaceTyToStr(IfaceType iface) {
+  switch (iface) {
+    case IfaceType::Invalid:
+      return "invalid";
+    case IfaceType::mtap:
+      return "mtap";
+    case IfaceType::wtap:
+      return "wtap";
+    case IfaceType::etap:
+      return "etap";
+    case IfaceType::wbr:
+      return "wbr";
+    case IfaceType::ebr:
+      return "ebr";
+  }
+}
+
+IfaceType StrToIfaceTy(const std::string& iface) {
+  auto it = StrToIfaceTyMap.find(iface);
+  if (it == StrToIfaceTyMap.end()) {
+    return IfaceType::Invalid;
+  } else {
+    return it->second;
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/allocd/utils.h b/host/libs/allocd/utils.h
new file mode 100644
index 0000000..f173935
--- /dev/null
+++ b/host/libs/allocd/utils.h
@@ -0,0 +1,64 @@
+/*
+ * 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 <android-base/logging.h>
+#include <json/json.h>
+
+#include <optional>
+#include <string>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/allocd/request.h"
+#include "host/libs/config/logging.h"
+
+namespace cuttlefish {
+
+constexpr char kDefaultLocation[] =
+    "/var/run/cuttlefish/cuttlefish_allocd.sock";
+
+// Default flags for send and receive.
+static constexpr int kSendFlags = 0;
+static constexpr int kRecvFlags = 0;
+
+/// Sends a Json value over client_socket
+///
+/// returns true if successfully sent the whole JSON object
+/// returns false otherwise
+bool SendJsonMsg(cuttlefish::SharedFD client_socket, const Json::Value& resp);
+
+/// Receives a single Json value over client_socket
+///
+/// The returned option will contain the JSON object when successful,
+/// or an std::nullopt if an error is reported
+std::optional<Json::Value> RecvJsonMsg(cuttlefish::SharedFD client_socket);
+
+// Helper functions mapping between Enum types and std::string
+
+RequestType StrToReqTy(const std::string& req);
+
+std::string ReqTyToStr(RequestType req_ty);
+
+IfaceType StrToIfaceTy(const std::string& iface);
+
+std::string IfaceTyToStr(IfaceType iface);
+
+RequestStatus StrToStatus(const std::string& st);
+
+std::string StatusToStr(RequestStatus st);
+
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/Android.bp b/host/libs/audio_connector/Android.bp
new file mode 100644
index 0000000..c26fecb
--- /dev/null
+++ b/host/libs/audio_connector/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+    name: "libcuttlefish_audio_connector",
+    srcs: [
+        "buffers.cpp",
+        "commands.cpp",
+        "server.cpp",
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libbase",
+        "libjsoncpp",
+        "liblog",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libcuttlefish_utils",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/libs/audio_connector/buffers.cpp b/host/libs/audio_connector/buffers.cpp
new file mode 100644
index 0000000..29804ca
--- /dev/null
+++ b/host/libs/audio_connector/buffers.cpp
@@ -0,0 +1,43 @@
+//
+// 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.
+
+#include "host/libs/audio_connector/buffers.h"
+
+#include <android-base/logging.h>
+
+namespace cuttlefish {
+
+ShmBuffer::ShmBuffer(ShmBuffer&& other)
+    : header_(std::move(other.header_)),
+      len_(std::move(other.len_)),
+      on_consumed_(std::move(other.on_consumed_)),
+      status_sent_(other.status_sent_) {
+  // It's now this buffer's responsibility to send the status.
+  other.status_sent_ = true;
+}
+
+ShmBuffer::~ShmBuffer() {
+  CHECK(status_sent_) << "Disposing of ShmBuffer before setting status";
+}
+
+uint32_t ShmBuffer::stream_id() const { return header_.stream_id.as_uint32_t(); }
+
+void ShmBuffer::SendStatus(AudioStatus status, uint32_t latency_bytes,
+                          uint32_t consumed_len) {
+  on_consumed_(status, latency_bytes, consumed_len);
+  status_sent_ = true;
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/buffers.h b/host/libs/audio_connector/buffers.h
new file mode 100644
index 0000000..a92fd83
--- /dev/null
+++ b/host/libs/audio_connector/buffers.h
@@ -0,0 +1,92 @@
+//
+// 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 <cinttypes>
+#include <functional>
+
+#include "host/libs/audio_connector/shm_layout.h"
+
+namespace cuttlefish {
+
+enum class Status : uint32_t {
+  Ok = 0x8000,
+  BadMessage,
+  NotSupported,
+  IOError,
+};
+
+using OnConsumedCb = std::function<void(AudioStatus, uint32_t /*latency*/,
+                                        uint32_t /*consumed length*/)>;
+
+// Wraps and provides access to audio buffers sent by the client.
+// Objects of this class can only be moved, not copied. Destroying a buffer
+// without sending the status to the client is a bug so the program aborts in
+// those cases.
+class ShmBuffer {
+ public:
+  ShmBuffer(const virtio_snd_pcm_xfer& header, uint32_t len,
+            OnConsumedCb on_consumed)
+      : header_(header), len_(len), on_consumed_(on_consumed) {}
+  ShmBuffer(const ShmBuffer& other) = delete;
+  ShmBuffer(ShmBuffer&& other);
+  ShmBuffer& operator=(const ShmBuffer& other) = delete;
+
+  ~ShmBuffer();
+
+  uint32_t stream_id() const;
+  uint32_t len() const { return len_; }
+
+  void SendStatus(AudioStatus status, uint32_t latency_bytes,
+                  uint32_t consumed_len);
+
+ private:
+  const virtio_snd_pcm_xfer header_;
+  const uint32_t len_;
+  OnConsumedCb on_consumed_;
+  bool status_sent_ = false;
+};
+
+class TxBuffer : public ShmBuffer {
+ public:
+  TxBuffer(const virtio_snd_pcm_xfer& header, const volatile uint8_t* buffer,
+           uint32_t len, OnConsumedCb on_consumed)
+      : ShmBuffer(header, len, on_consumed), buffer_(buffer) {}
+  TxBuffer(const TxBuffer& other) = delete;
+  TxBuffer(TxBuffer&& other) = default;
+  TxBuffer& operator=(const TxBuffer& other) = delete;
+
+  const volatile uint8_t* get() const { return buffer_; }
+
+ private:
+  const volatile uint8_t* const buffer_;
+};
+
+class RxBuffer : public ShmBuffer {
+ public:
+  RxBuffer(const virtio_snd_pcm_xfer& header, volatile uint8_t* buffer,
+           uint32_t len, OnConsumedCb on_consumed)
+      : ShmBuffer(header, len, on_consumed), buffer_(buffer) {}
+  RxBuffer(const RxBuffer& other) = delete;
+  RxBuffer(RxBuffer&& other) = default;
+  RxBuffer& operator=(const RxBuffer& other) = delete;
+
+  volatile uint8_t* get() const { return buffer_; }
+
+ private:
+  volatile uint8_t* const buffer_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/commands.cpp b/host/libs/audio_connector/commands.cpp
new file mode 100644
index 0000000..42536d5
--- /dev/null
+++ b/host/libs/audio_connector/commands.cpp
@@ -0,0 +1,79 @@
+//
+// 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.
+
+#include "host/libs/audio_connector/commands.h"
+
+#include <android-base/logging.h>
+
+#include "host/libs/audio_connector/shm_layout.h"
+
+namespace cuttlefish {
+
+AudioCommand::~AudioCommand() {
+  CHECK(status_ != AudioStatus::NOT_SET)
+      << "A command of type " << static_cast<uint32_t>(type())
+      << " went out of scope without reply";
+}
+
+StreamInfoCommand::StreamInfoCommand(uint32_t start_id, size_t count,
+                                     virtio_snd_pcm_info* pcm_info)
+    : InfoCommand(AudioCommandType::VIRTIO_SND_R_PCM_INFO, start_id, count,
+                  pcm_info) {}
+
+void StreamInfoCommand::Reply(AudioStatus status,
+                              const std::vector<virtio_snd_pcm_info>& reply) {
+  MarkReplied(status);
+  if (status != AudioStatus::VIRTIO_SND_S_OK) {
+    return;
+  }
+  CHECK(reply.size() == count())
+      << "Returned unmatching info count: " << reply.size() << " vs "
+      << count();
+  for (int i = 0; i < reply.size(); ++i) {
+    info_reply()[i].hdr.hda_fn_nid = Le32(reply[i].hdr.hda_fn_nid);
+    info_reply()[i].features = Le32(reply[i].features);
+    info_reply()[i].formats = Le64(reply[i].formats);
+    info_reply()[i].rates = Le64(reply[i].rates);
+    info_reply()[i].direction = reply[i].direction;
+    info_reply()[i].channels_min = reply[i].channels_min;
+    info_reply()[i].channels_max = reply[i].channels_max;
+    // pcm_info[i].padding is supposed to be all zeros in virtio-snd but here we
+    // can just ignore it.
+  }
+}
+
+StreamControlCommand::StreamControlCommand(AudioCommandType type,
+                                           uint32_t stream_id)
+    : AudioCommand(type), stream_id_(stream_id) {}
+
+void StreamControlCommand::Reply(AudioStatus status) {
+  // These commands don't expect a reply, this method just forces
+  // acknowledgement of the command.
+  MarkReplied(status);
+}
+
+StreamSetParamsCommand::StreamSetParamsCommand(
+    uint32_t stream_id, uint32_t buffer_bytes, uint32_t period_bytes,
+    uint32_t features, uint8_t channels, uint8_t format, uint8_t rate)
+    : StreamControlCommand(AudioCommandType::VIRTIO_SND_R_PCM_SET_PARAMS,
+                           stream_id),
+      buffer_bytes_(buffer_bytes),
+      period_bytes_(period_bytes),
+      features_(features),
+      channels_(channels),
+      format_(format),
+      rate_(rate) {}
+
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/commands.h b/host/libs/audio_connector/commands.h
new file mode 100644
index 0000000..849dc12
--- /dev/null
+++ b/host/libs/audio_connector/commands.h
@@ -0,0 +1,107 @@
+//
+// 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 <stdint.h>
+
+#include <vector>
+
+#include "host/libs/audio_connector/shm_layout.h"
+
+namespace cuttlefish {
+
+class AudioCommand {
+ public:
+  virtual ~AudioCommand();
+
+  AudioCommandType type() const { return type_; }
+  AudioStatus status() const { return status_; }
+
+ protected:
+  AudioCommand(AudioCommandType type) : type_(type) {}
+
+  void MarkReplied(AudioStatus status) { status_ = status; }
+
+ private:
+  AudioStatus status_ = AudioStatus::NOT_SET;
+  const AudioCommandType type_;
+};
+
+template <typename R>
+class InfoCommand : public AudioCommand {
+ public:
+  InfoCommand(AudioCommandType type, uint32_t start_id, size_t count, R* reply)
+      : AudioCommand(type),
+        start_id_(start_id),
+        count_(count),
+        info_reply_(reply) {}
+
+  uint32_t start_id() const { return start_id_; }
+  uint32_t count() const { return count_; }
+
+ protected:
+  R* info_reply() { return info_reply_; }
+
+ private:
+  const uint32_t start_id_;
+  const size_t count_;
+  R* info_reply_;
+};
+
+class StreamInfoCommand : public InfoCommand<virtio_snd_pcm_info> {
+ public:
+  StreamInfoCommand(uint32_t start_id, size_t count,
+                    virtio_snd_pcm_info* pcm_info);
+
+  void Reply(AudioStatus status, const std::vector<virtio_snd_pcm_info>& reply);
+};
+
+// Serves the START, STOP, PREPARE and RELEASE commands. It's also the
+// superclass of the class handling SET_PARAMS
+struct StreamControlCommand : public AudioCommand {
+ public:
+  StreamControlCommand(AudioCommandType type, uint32_t stream_id);
+
+  uint32_t stream_id() const { return stream_id_; }
+
+  void Reply(AudioStatus status);
+
+ private:
+  const uint32_t stream_id_;
+};
+
+struct StreamSetParamsCommand : public StreamControlCommand {
+ public:
+  StreamSetParamsCommand(uint32_t stream_id, uint32_t buffer_bytes,
+                         uint32_t period_bytes, uint32_t features,
+                         uint8_t channels, uint8_t format, uint8_t rate);
+
+  uint32_t buffer_bytes() const { return buffer_bytes_; }
+  uint32_t period_bytes() const { return period_bytes_; }
+  uint32_t features() const { return features_; }
+  uint8_t channels() const { return channels_; }
+  uint8_t format() const { return format_; }
+  uint8_t rate() const { return rate_; }
+
+ private:
+  const uint32_t buffer_bytes_;
+  const uint32_t period_bytes_;
+  const uint32_t features_;
+  const uint8_t channels_;
+  const uint8_t format_;
+  const uint8_t rate_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/server.cpp b/host/libs/audio_connector/server.cpp
new file mode 100644
index 0000000..b925cdd
--- /dev/null
+++ b/host/libs/audio_connector/server.cpp
@@ -0,0 +1,357 @@
+//
+// 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.
+
+#include "host/libs/audio_connector/server.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <utility>
+
+#include <android-base/logging.h>
+
+#include "common/libs/fs/shared_select.h"
+
+namespace cuttlefish {
+
+namespace {
+
+ScopedMMap AllocateShm(size_t size, const std::string& name, SharedFD* shm_fd) {
+  *shm_fd = SharedFD::MemfdCreate(name, 0);
+  if (!(*shm_fd)->IsOpen()) {
+    LOG(FATAL) << "Unable to allocate create file for " << name << ": "
+               << (*shm_fd)->StrError();
+    return ScopedMMap();
+  }
+
+  auto truncate_ret = (*shm_fd)->Truncate(size);
+  if (truncate_ret != 0) {
+    LOG(FATAL) << "Unable to resize " << name << " to " << size
+               << " bytes: " << (*shm_fd)->StrError();
+    return ScopedMMap();
+  }
+
+  auto mmap_res = (*shm_fd)->MMap(NULL /* addr */, size, PROT_READ | PROT_WRITE,
+                                  MAP_SHARED, 0 /*offset*/);
+  if (!mmap_res) {
+    LOG(FATAL) << "Unable to memory map " << name << ": "
+               << (*shm_fd)->StrError();
+  }
+  return mmap_res;
+}
+
+bool CreateSocketPair(SharedFD* local, SharedFD* remote) {
+  auto ret = SharedFD::SocketPair(AF_UNIX, SOCK_SEQPACKET, 0, local, remote);
+  if (!ret) {
+    LOG(ERROR) << "Unable to create socket pair for audio IO signaling: "
+               << (*local)->StrError();
+  }
+  return ret;
+}
+
+std::function<void(AudioStatus, uint32_t, uint32_t)> SendStatusCallback(
+    uint32_t buffer_offset, SharedFD socket) {
+  // Consumption of an audio buffer is an asynchronous event, which could
+  // trigger after the client disconnected. A WeakFD ensures that the response
+  // will only be sent if there is still a client available.
+  auto weak_socket = WeakFD(socket);
+  return
+      [buffer_offset, weak_socket](AudioStatus status, uint32_t latency_bytes,
+                                   uint32_t consumed_length) {
+        auto socket = weak_socket.lock();
+        if (!socket->IsOpen()) {
+          return;
+        }
+        IoStatusMsg reply;
+        reply.status.status = Le32(static_cast<uint32_t>(status));
+        reply.status.latency_bytes = Le32(latency_bytes);
+        reply.buffer_offset = buffer_offset;
+        reply.consumed_length = consumed_length;
+        // Send the acknowledgment non-blockingly to avoid a slow client from
+        // blocking the server.
+        auto sent = socket->Send(&reply, sizeof(reply), MSG_DONTWAIT);
+        if (sent < sizeof(reply)) {
+          LOG(ERROR) << "Failed to send entire reply: " << socket->StrError();
+        }
+      };
+}
+
+}  // namespace
+
+std::unique_ptr<AudioClientConnection> AudioServer::AcceptClient(
+    uint32_t num_streams, uint32_t num_jacks, uint32_t num_chmaps,
+    size_t tx_shm_len, size_t rx_shm_len) {
+  auto conn_fd = SharedFD::Accept(*server_socket_, nullptr, 0);
+  if (!conn_fd->IsOpen()) {
+    LOG(ERROR) << "Connection failed on audio server: " << conn_fd->StrError();
+    return nullptr;
+  }
+  return AudioClientConnection::Create(conn_fd, num_streams, num_jacks,
+                                       num_chmaps, tx_shm_len, rx_shm_len);
+}
+
+/* static */
+std::unique_ptr<AudioClientConnection> AudioClientConnection::Create(
+    SharedFD client_socket, uint32_t num_streams, uint32_t num_jacks,
+    uint32_t num_chmaps, size_t tx_shm_len, size_t rx_shm_len) {
+  SharedFD event_socket, event_pair;
+  SharedFD tx_socket, tx_pair;
+  SharedFD rx_socket, rx_pair;
+
+  bool pairs_created = true;
+  pairs_created &= CreateSocketPair(&event_socket, &event_pair);
+  pairs_created &= CreateSocketPair(&tx_socket, &tx_pair);
+  pairs_created &= CreateSocketPair(&rx_socket, &rx_pair);
+  if (!pairs_created) {
+    return nullptr;
+  }
+
+  SharedFD tx_shm_fd, rx_shm_fd;
+  auto tx_shm =
+      AllocateShm(tx_shm_len, "vios_audio_server_tx_queue", &tx_shm_fd);
+  if (!tx_shm) {
+    return nullptr;
+  }
+  auto rx_shm =
+      AllocateShm(rx_shm_len, "vios_audio_server_rx_queue", &rx_shm_fd);
+  if (!rx_shm) {
+    return nullptr;
+  }
+
+  VioSConfig welcome_msg = {
+      .version = VIOS_VERSION,
+      .jacks = num_jacks,
+      .streams = num_streams,
+      .chmaps = num_chmaps,
+  };
+
+  auto sent = client_socket->SendFileDescriptors(
+      &welcome_msg, sizeof(welcome_msg), event_pair, tx_pair, rx_pair,
+      tx_shm_fd, rx_shm_fd);
+  if (sent < 0) {
+    LOG(ERROR) << "Failed to send file descriptors to client: "
+               << client_socket->StrError();
+    return nullptr;
+  }
+
+  return std::unique_ptr<AudioClientConnection>(new AudioClientConnection(
+      std::move(tx_shm), std::move(rx_shm), client_socket,
+      event_socket, tx_socket, rx_socket));
+}
+
+bool AudioClientConnection::ReceiveCommands(AudioServerExecutor& executor) {
+  // The largest msg the client will send is 24 bytes long, using uint64_t
+  // guarantees it's aligned to 64 bits.
+  uint64_t recv_buffer[3];
+  auto recv_size =
+      ReceiveMsg(control_socket_, &recv_buffer, sizeof(recv_buffer));
+  if (recv_size <= 0) {
+    return false;
+  }
+  const auto cmd_hdr = reinterpret_cast<const virtio_snd_hdr*>(&recv_buffer[0]);
+  if (recv_size < sizeof(virtio_snd_hdr)) {
+    LOG(ERROR) << "Received control message is too small: " << recv_size;
+    return false;
+  }
+  switch (static_cast<AudioCommandType>(cmd_hdr->code.as_uint32_t())) {
+    case AudioCommandType::VIRTIO_SND_R_PCM_INFO: {
+      if (recv_size < sizeof(virtio_snd_query_info)) {
+        LOG(ERROR) << "Received QUERY_INFO message is too small: " << recv_size;
+        return false;
+      }
+      auto query_info = reinterpret_cast<const virtio_snd_query_info*>(cmd_hdr);
+      auto info_count = query_info->count.as_uint32_t();
+      auto start_id = query_info->start_id.as_uint32_t();
+      std::unique_ptr<virtio_snd_pcm_info[]> reply(
+          new virtio_snd_pcm_info[info_count]);
+      StreamInfoCommand cmd(start_id, info_count, reply.get());
+
+      executor.StreamsInfo(cmd);
+      return CmdReply(cmd.status(), reply.get(),
+                      info_count * sizeof(reply[0]));
+    }
+    case AudioCommandType::VIRTIO_SND_R_PCM_SET_PARAMS: {
+      if (recv_size < sizeof(virtio_snd_pcm_set_params)) {
+        LOG(ERROR) << "Received SET_PARAMS message is too small: " << recv_size;
+        return false;
+      }
+      auto set_param_msg =
+          reinterpret_cast<const virtio_snd_pcm_set_params*>(cmd_hdr);
+      StreamSetParamsCommand cmd(set_param_msg->hdr.stream_id.as_uint32_t(),
+                                 set_param_msg->buffer_bytes.as_uint32_t(),
+                                 set_param_msg->period_bytes.as_uint32_t(),
+                                 set_param_msg->features.as_uint32_t(),
+                                 set_param_msg->channels, set_param_msg->format,
+                                 set_param_msg->rate);
+      executor.SetStreamParameters(cmd);
+      return CmdReply(cmd.status());
+    }
+    case AudioCommandType::VIRTIO_SND_R_PCM_PREPARE: {
+      if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
+        LOG(ERROR) << "Received PREPARE message is too small: " << recv_size;
+        return false;
+      }
+      auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
+      StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_PREPARE,
+                               pcm_op_msg->stream_id.as_uint32_t());
+      executor.PrepareStream(cmd);
+      return CmdReply(cmd.status());
+    }
+    case AudioCommandType::VIRTIO_SND_R_PCM_RELEASE: {
+      if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
+        LOG(ERROR) << "Received RELEASE message is too small: " << recv_size;
+        return false;
+      }
+      auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
+      StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_RELEASE,
+                               pcm_op_msg->stream_id.as_uint32_t());
+      executor.ReleaseStream(cmd);
+      return CmdReply(cmd.status());
+    }
+    case AudioCommandType::VIRTIO_SND_R_PCM_START: {
+      if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
+        LOG(ERROR) << "Received START message is too small: " << recv_size;
+        return false;
+      }
+      auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
+      StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_START,
+                               pcm_op_msg->stream_id.as_uint32_t());
+      executor.StartStream(cmd);
+      return CmdReply(cmd.status());
+    }
+    case AudioCommandType::VIRTIO_SND_R_PCM_STOP: {
+      if (recv_size < sizeof(virtio_snd_pcm_hdr)) {
+        LOG(ERROR) << "Received STOP message is too small: " << recv_size;
+        return false;
+      }
+      auto pcm_op_msg = reinterpret_cast<const virtio_snd_pcm_hdr*>(cmd_hdr);
+      StreamControlCommand cmd(AudioCommandType::VIRTIO_SND_R_PCM_STOP,
+                               pcm_op_msg->stream_id.as_uint32_t());
+      executor.StopStream(cmd);
+      return CmdReply(cmd.status());
+    }
+    case AudioCommandType::VIRTIO_SND_R_CHMAP_INFO:
+    case AudioCommandType::VIRTIO_SND_R_JACK_INFO:
+    case AudioCommandType::VIRTIO_SND_R_JACK_REMAP:
+      LOG(ERROR) << "Unsupported command type: " << cmd_hdr->code.as_uint32_t();
+      return CmdReply(AudioStatus::VIRTIO_SND_S_NOT_SUPP);
+    default:
+      LOG(ERROR) << "Unknown command type: " << cmd_hdr->code.as_uint32_t();
+      return CmdReply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
+  }
+  return true;
+}
+
+bool AudioClientConnection::ReceivePlayback(AudioServerExecutor& executor) {
+  // The largest msg the client will send is 12 bytes long, using uint32_t
+  // guarantees it's aligned to 32 bits.
+  uint32_t recv_buffer[3];
+  auto recv_size = ReceiveMsg(tx_socket_, &recv_buffer, sizeof(recv_buffer));
+  if (recv_size <= 0) {
+    return false;
+  }
+  const auto msg_hdr = reinterpret_cast<const IoTransferMsg*>(&recv_buffer[0]);
+
+  if (recv_size < sizeof(IoTransferMsg)) {
+    LOG(ERROR) << "Received PCM_XFER message is too small: " << recv_size;
+    return false;
+  }
+  TxBuffer buffer(msg_hdr->io_xfer,
+                  TxBufferAt(msg_hdr->buffer_offset, msg_hdr->buffer_len),
+                  msg_hdr->buffer_len,
+                  SendStatusCallback(msg_hdr->buffer_offset, tx_socket_));
+  executor.OnPlaybackBuffer(std::move(buffer));
+  return true;
+}
+
+bool AudioClientConnection::ReceiveCapture(AudioServerExecutor& executor) {
+  uint32_t recv_buffer[3];
+  auto recv_size = ReceiveMsg(rx_socket_, &recv_buffer, sizeof(recv_buffer));
+  if (recv_size <= 0) {
+    return false;
+  }
+  const auto msg_hdr = reinterpret_cast<const IoTransferMsg*>(&recv_buffer[0]);
+  if (recv_size < sizeof(IoTransferMsg)) {
+    LOG(ERROR) << "Received PCM_XFER message is too small: " << recv_size;
+    return false;
+  }
+  RxBuffer buffer(msg_hdr->io_xfer,
+                  RxBufferAt(msg_hdr->buffer_offset, msg_hdr->buffer_len),
+                  msg_hdr->buffer_len,
+                  SendStatusCallback(msg_hdr->buffer_offset, rx_socket_));
+  executor.OnCaptureBuffer(std::move(buffer));
+  return true;
+}
+
+bool AudioClientConnection::CmdReply(AudioStatus status, const void* data,
+                                     size_t size) {
+  virtio_snd_hdr vio_status = {
+      .code = Le32(static_cast<uint32_t>(status)),
+  };
+  auto status_sent = control_socket_->Send(&vio_status, sizeof(vio_status), 0);
+  if (status_sent < sizeof(vio_status)) {
+    LOG(ERROR) << "Failed to send entire command status: "
+               << control_socket_->StrError();
+    return false;
+  }
+  if (status != AudioStatus::VIRTIO_SND_S_OK || size == 0) {
+    return true;
+  }
+  auto payload_sent = control_socket_->Send(data, size, 0);
+  if (payload_sent < size) {
+    LOG(ERROR) << "Failed to send entire command response payload: "
+               << control_socket_->StrError();
+    return false;
+  }
+  return true;
+}
+
+const volatile uint8_t* AudioClientConnection::TxBufferAt(size_t offset,
+                                                          size_t len) const {
+  CHECK(offset < tx_shm_.len() && tx_shm_.len() - offset > len)
+      << "Tx buffer bounds outside the buffer area: " << offset << " " << len;
+  const void* ptr = tx_shm_.get();
+  return &reinterpret_cast<const volatile uint8_t*>(ptr)[offset];
+}
+
+volatile uint8_t* AudioClientConnection::RxBufferAt(size_t offset,
+                                                    size_t len) {
+  CHECK(offset < rx_shm_.len() && rx_shm_.len() - offset > len)
+      << "Rx buffer bounds outside the buffer area: " << offset << " " << len;
+  void* ptr = rx_shm_.get();
+  return &reinterpret_cast<volatile uint8_t*>(ptr)[offset];
+}
+
+bool AudioClientConnection::SendEvent(/*TODO*/) { return false; }
+
+ssize_t AudioClientConnection::ReceiveMsg(SharedFD socket, void* buffer,
+                                          size_t size) {
+  auto read = socket->Recv(buffer, size, MSG_TRUNC);
+  CHECK(read < 0 || read <= size)
+      << "Received a msg bigger than the buffer, msg was truncated: " << read
+      << " vs " << size;
+  if (read == 0) {
+    LOG(ERROR) << "Client closed the connection";
+  }
+  if (read < 0) {
+    LOG(ERROR) << "Error receiving messages from client: "
+               << socket->StrError();
+  }
+  return read;
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/server.h b/host/libs/audio_connector/server.h
new file mode 100644
index 0000000..4ba2e7c
--- /dev/null
+++ b/host/libs/audio_connector/server.h
@@ -0,0 +1,113 @@
+//
+// 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 <cinttypes>
+
+#include <functional>
+#include <memory>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/audio_connector/buffers.h"
+#include "host/libs/audio_connector/commands.h"
+#include "host/libs/audio_connector/shm_layout.h"
+
+namespace cuttlefish {
+
+// Callbacks into objects implementing this interface will be made from the same
+// thread that handles the connection fd. Implementations should make every
+// effort to return immediately to avoid blocking the server's main loop.
+class AudioServerExecutor {
+ public:
+  virtual ~AudioServerExecutor() = default;
+
+  // Implementations must ensure each command is replied to before returning
+  // from these functions. Failure to do so causes the program to abort.
+  virtual void StreamsInfo(StreamInfoCommand& cmd) = 0;
+  virtual void SetStreamParameters(StreamSetParamsCommand& cmd) = 0;
+  virtual void PrepareStream(StreamControlCommand& cmd) = 0;
+  virtual void ReleaseStream(StreamControlCommand& cmd) = 0;
+  virtual void StartStream(StreamControlCommand& cmd) = 0;
+  virtual void StopStream(StreamControlCommand& cmd) = 0;
+
+  // Implementations must call buffer.SendStatus() before destroying the buffer
+  // to notify the other side of the release of the buffer. Failure to do so
+  // will cause the program to abort.
+  virtual void OnPlaybackBuffer(TxBuffer buffer) = 0;
+  virtual void OnCaptureBuffer(RxBuffer buffer) = 0;
+};
+
+class AudioClientConnection {
+ public:
+  static std::unique_ptr<AudioClientConnection> Create(
+      SharedFD client_socket, uint32_t num_streams, uint32_t num_jacks,
+      uint32_t num_chmaps, size_t tx_shm_len, size_t rx_shm_len);
+
+  AudioClientConnection() = delete;
+  AudioClientConnection(const AudioClientConnection&) = delete;
+
+  AudioClientConnection& operator=(const AudioClientConnection&) = delete;
+
+  // Allows the caller to react to commands sent by the client.
+  bool ReceiveCommands(AudioServerExecutor& executor);
+  // Allows the caller to react to IO buffers sent by the client.
+  bool ReceivePlayback(AudioServerExecutor& executor);
+  bool ReceiveCapture(AudioServerExecutor& executor);
+
+  bool SendEvent(/*TODO*/);
+
+ private:
+  AudioClientConnection(ScopedMMap tx_shm, ScopedMMap rx_shm,
+                        SharedFD control_socket, SharedFD event_socket,
+                        SharedFD tx_socket, SharedFD rx_socket)
+      : tx_shm_(std::move(tx_shm)),
+        rx_shm_(std::move(rx_shm)),
+        control_socket_(control_socket),
+        event_socket_(event_socket),
+        tx_socket_(tx_socket),
+        rx_socket_(rx_socket) {}
+
+  bool CmdReply(AudioStatus status, const void* data = nullptr,
+                size_t size = 0);
+  bool WithCommand(const virtio_snd_hdr* msg, size_t msg_len,
+                   AudioServerExecutor& executor);
+
+  ssize_t ReceiveMsg(SharedFD socket, void* buffer, size_t size);
+  const volatile uint8_t* TxBufferAt(size_t offset, size_t len) const;
+  volatile uint8_t* RxBufferAt(size_t offset, size_t len);
+
+  const ScopedMMap tx_shm_;
+  ScopedMMap rx_shm_;
+  SharedFD control_socket_;
+  SharedFD event_socket_;
+  SharedFD tx_socket_;
+  SharedFD rx_socket_;
+};
+
+class AudioServer {
+ public:
+  AudioServer(SharedFD server_socket) : server_socket_(server_socket) {}
+
+  std::unique_ptr<AudioClientConnection> AcceptClient(uint32_t num_streams,
+                                                      uint32_t num_jacks,
+                                                      uint32_t num_chmaps,
+                                                      size_t tx_shm_len,
+                                                      size_t rx_shm_len);
+
+ private:
+  SharedFD server_socket_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/shm_layout.h b/host/libs/audio_connector/shm_layout.h
new file mode 100644
index 0000000..9148cb8
--- /dev/null
+++ b/host/libs/audio_connector/shm_layout.h
@@ -0,0 +1,192 @@
+//
+// 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 <atomic>
+#include <type_traits>
+
+#include "common/libs/utils/cf_endian.h"
+
+namespace cuttlefish {
+// TODO (b/175151042): get these from the kernel headers when available
+
+enum class AudioCommandType : uint32_t {
+  /* jack control request types */
+  VIRTIO_SND_R_JACK_INFO = 1,
+  VIRTIO_SND_R_JACK_REMAP,
+
+  /* PCM control request types */
+  VIRTIO_SND_R_PCM_INFO = 0x0100,
+  VIRTIO_SND_R_PCM_SET_PARAMS,
+  VIRTIO_SND_R_PCM_PREPARE,
+  VIRTIO_SND_R_PCM_RELEASE,
+  VIRTIO_SND_R_PCM_START,
+  VIRTIO_SND_R_PCM_STOP,
+
+  /* channel map control request types */
+  VIRTIO_SND_R_CHMAP_INFO = 0x0200,
+};
+
+enum class AudioStatus : uint32_t {
+  /* common status codes */
+  VIRTIO_SND_S_OK = 0x8000,
+  VIRTIO_SND_S_BAD_MSG,
+  VIRTIO_SND_S_NOT_SUPP,
+  VIRTIO_SND_S_IO_ERR,
+  // Not a virtio constant, but it's only used internally as an invalid value so
+  // it's safe.
+  NOT_SET = static_cast<uint32_t>(-1),
+};
+
+enum class AudioStreamDirection : uint32_t {
+  VIRTIO_SND_D_OUTPUT = 0,
+  VIRTIO_SND_D_INPUT
+};
+
+enum class AudioStreamFormat : uint8_t {
+  /* analog formats (width / physical width) */
+  VIRTIO_SND_PCM_FMT_IMA_ADPCM = 0, /*  4 /  4 bits */
+  VIRTIO_SND_PCM_FMT_MU_LAW,        /*  8 /  8 bits */
+  VIRTIO_SND_PCM_FMT_A_LAW,         /*  8 /  8 bits */
+  VIRTIO_SND_PCM_FMT_S8,            /*  8 /  8 bits */
+  VIRTIO_SND_PCM_FMT_U8,            /*  8 /  8 bits */
+  VIRTIO_SND_PCM_FMT_S16,           /* 16 / 16 bits */
+  VIRTIO_SND_PCM_FMT_U16,           /* 16 / 16 bits */
+  VIRTIO_SND_PCM_FMT_S18_3,         /* 18 / 24 bits */
+  VIRTIO_SND_PCM_FMT_U18_3,         /* 18 / 24 bits */
+  VIRTIO_SND_PCM_FMT_S20_3,         /* 20 / 24 bits */
+  VIRTIO_SND_PCM_FMT_U20_3,         /* 20 / 24 bits */
+  VIRTIO_SND_PCM_FMT_S24_3,         /* 24 / 24 bits */
+  VIRTIO_SND_PCM_FMT_U24_3,         /* 24 / 24 bits */
+  VIRTIO_SND_PCM_FMT_S20,           /* 20 / 32 bits */
+  VIRTIO_SND_PCM_FMT_U20,           /* 20 / 32 bits */
+  VIRTIO_SND_PCM_FMT_S24,           /* 24 / 32 bits */
+  VIRTIO_SND_PCM_FMT_U24,           /* 24 / 32 bits */
+  VIRTIO_SND_PCM_FMT_S32,           /* 32 / 32 bits */
+  VIRTIO_SND_PCM_FMT_U32,           /* 32 / 32 bits */
+  VIRTIO_SND_PCM_FMT_FLOAT,         /* 32 / 32 bits */
+  VIRTIO_SND_PCM_FMT_FLOAT64,       /* 64 / 64 bits */
+  /* digital formats (width / physical width) */
+  VIRTIO_SND_PCM_FMT_DSD_U8,         /*  8 /  8 bits */
+  VIRTIO_SND_PCM_FMT_DSD_U16,        /* 16 / 16 bits */
+  VIRTIO_SND_PCM_FMT_DSD_U32,        /* 32 / 32 bits */
+  VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME /* 32 / 32 bits */
+};
+
+/* supported PCM frame rates */
+enum AudioStreamRate : uint8_t {
+  VIRTIO_SND_PCM_RATE_5512 = 0,
+  VIRTIO_SND_PCM_RATE_8000,
+  VIRTIO_SND_PCM_RATE_11025,
+  VIRTIO_SND_PCM_RATE_16000,
+  VIRTIO_SND_PCM_RATE_22050,
+  VIRTIO_SND_PCM_RATE_32000,
+  VIRTIO_SND_PCM_RATE_44100,
+  VIRTIO_SND_PCM_RATE_48000,
+  VIRTIO_SND_PCM_RATE_64000,
+  VIRTIO_SND_PCM_RATE_88200,
+  VIRTIO_SND_PCM_RATE_96000,
+  VIRTIO_SND_PCM_RATE_176400,
+  VIRTIO_SND_PCM_RATE_192000,
+  VIRTIO_SND_PCM_RATE_384000
+};
+
+struct virtio_snd_hdr {
+  Le32 code;
+};
+
+struct virtio_snd_query_info {
+  struct virtio_snd_hdr hdr;
+  Le32 start_id;
+  Le32 count;
+  Le32 size;  // unused
+};
+
+struct virtio_snd_info {
+  Le32 hda_fn_nid;
+};
+
+struct virtio_snd_pcm_info {
+  struct virtio_snd_info hdr;
+  Le32 features; /* 1 << VIRTIO_SND_PCM_F_XXX */
+  Le64 formats;  /* 1 << VIRTIO_SND_PCM_FMT_XXX */
+  Le64 rates;    /* 1 << VIRTIO_SND_PCM_RATE_XXX */
+  uint8_t direction;
+  uint8_t channels_min;
+  uint8_t channels_max;
+
+  uint8_t padding[5];
+};
+
+struct virtio_snd_pcm_hdr {
+  struct virtio_snd_hdr hdr;
+  Le32 stream_id;
+};
+
+struct virtio_snd_pcm_set_params {
+  struct virtio_snd_pcm_hdr hdr;
+  Le32 buffer_bytes;
+  Le32 period_bytes;
+  Le32 features; /* 1 << VIRTIO_SND_PCM_F_XXX */
+  uint8_t channels;
+  uint8_t format;
+  uint8_t rate;
+  uint8_t padding;
+};
+
+struct virtio_snd_pcm_xfer {
+  Le32 stream_id;
+};
+
+struct virtio_snd_pcm_status {
+  Le32 status;
+  Le32 latency_bytes;
+};
+
+// Update this value when the msg layouts change
+const uint32_t VIOS_VERSION = 1;
+
+struct VioSConfig {
+  uint32_t version;
+  uint32_t jacks;
+  uint32_t streams;
+  uint32_t chmaps;
+};
+
+struct IoTransferMsg {
+  virtio_snd_pcm_xfer io_xfer;
+  uint32_t buffer_offset;
+  uint32_t buffer_len;
+};
+
+struct IoStatusMsg {
+  virtio_snd_pcm_status status;
+  uint32_t buffer_offset;
+  uint32_t consumed_length;
+};
+
+// Ensure all message structs have predictable sizes
+#define ASSERT_VALID_MSG_TYPE(T, size) \
+  static_assert(sizeof(T) == (size), #T " has the wrong size")
+ASSERT_VALID_MSG_TYPE(virtio_snd_query_info, 16);
+ASSERT_VALID_MSG_TYPE(virtio_snd_pcm_info, 32);
+ASSERT_VALID_MSG_TYPE(virtio_snd_pcm_set_params, 24);
+ASSERT_VALID_MSG_TYPE(virtio_snd_pcm_hdr, 8);
+ASSERT_VALID_MSG_TYPE(IoTransferMsg, 12);
+ASSERT_VALID_MSG_TYPE(IoStatusMsg, 16);
+#undef ASSERT_VALID_MSG_TYPE
+
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/host/libs/config/Android.bp b/host/libs/config/Android.bp
index d88b206..3697f4e 100644
--- a/host/libs/config/Android.bp
+++ b/host/libs/config/Android.bp
@@ -13,24 +13,31 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_host_static {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
     name: "libcuttlefish_host_config",
     srcs: [
+        "bootconfig_args.cpp",
+        "custom_actions.cpp",
         "cuttlefish_config.cpp",
+        "cuttlefish_config_instance.cpp",
+        "data_image.cpp",
         "fetcher_config.cpp",
-    ],
-    header_libs: [
-        "cuttlefish_glog",
+        "host_tools_version.cpp",
+        "kernel_args.cpp",
+        "known_paths.cpp",
+        "logging.cpp",
     ],
     shared_libs: [
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "libbase",
         "libgflags",
-    ],
-    static_libs: [
-        "libxml2",
         "libjsoncpp",
+        "libz",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/libs/config/bootconfig_args.cpp b/host/libs/config/bootconfig_args.cpp
new file mode 100644
index 0000000..c2bc1eb
--- /dev/null
+++ b/host/libs/config/bootconfig_args.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/libs/config/bootconfig_args.h"
+
+#include <array>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "common/libs/utils/environment.h"
+#include "common/libs/utils/files.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/vm_manager/crosvm_manager.h"
+#include "host/libs/vm_manager/qemu_manager.h"
+#include "host/libs/vm_manager/vm_manager.h"
+
+namespace cuttlefish {
+
+using vm_manager::CrosvmManager;
+using vm_manager::QemuManager;
+
+namespace {
+
+template <typename T>
+void AppendVector(std::vector<T>* destination, const std::vector<T>& source) {
+  destination->insert(destination->end(), source.begin(), source.end());
+}
+
+template <typename S, typename T>
+std::string concat(const S& s, const T& t) {
+  std::ostringstream os;
+  os << s << t;
+  return os.str();
+}
+
+std::string mac_to_str(const std::array<unsigned char, 6>& mac) {
+  std::ostringstream stream;
+  stream << std::hex << (int)mac[0];
+  for (int i = 1; i < 6; i++) {
+    stream << ":" << std::hex << (int)mac[i];
+  }
+  return stream.str();
+}
+
+// TODO(schuffelen): Move more of this into host/libs/vm_manager, as a
+// substitute for the vm_manager comparisons.
+std::vector<std::string> VmManagerBootconfig(const CuttlefishConfig& config) {
+  std::vector<std::string> vm_manager_cmdline;
+  if (config.console()) {
+    vm_manager_cmdline.push_back("androidboot.console=" + config.console_dev());
+  } else {
+    // Specify an invalid path under /dev, so the init process will disable the
+    // console service due to the console not being found. On physical devices,
+    // it is enough to not specify androidboot.console= *and* not specify the
+    // console= kernel command line parameter, because the console and kernel
+    // dmesg are muxed. However, on cuttlefish, we don't need to mux, and would
+    // prefer to retain the kernel dmesg logging, so we must work around init
+    // falling back to the check for /dev/console (which we'll always have).
+    vm_manager_cmdline.push_back("androidboot.console=invalid");
+  }
+  return vm_manager_cmdline;
+}
+
+}  // namespace
+
+std::vector<std::string> BootconfigArgsFromConfig(
+    const CuttlefishConfig& config,
+    const CuttlefishConfig::InstanceSpecific& instance) {
+  std::vector<std::string> bootconfig_args;
+
+  AppendVector(&bootconfig_args, VmManagerBootconfig(config));
+  auto vmm = vm_manager::GetVmManager(config.vm_manager(), config.target_arch());
+  bootconfig_args.push_back(
+      vmm->ConfigureBootDevices(instance.virtual_disk_paths().size()));
+  AppendVector(&bootconfig_args, vmm->ConfigureGpuMode(config.gpu_mode()));
+
+  bootconfig_args.push_back(
+      concat("androidboot.serialno=", instance.serial_number()));
+  bootconfig_args.push_back(concat("androidboot.lcd_density=", config.dpi()));
+  bootconfig_args.push_back(
+      concat("androidboot.setupwizard_mode=", config.setupwizard_mode()));
+  if (!config.guest_enforce_security()) {
+    bootconfig_args.push_back("androidboot.selinux=permissive");
+  }
+
+  if (instance.tombstone_receiver_port()) {
+    bootconfig_args.push_back(concat("androidboot.vsock_tombstone_port=",
+                                     instance.tombstone_receiver_port()));
+  }
+
+  if (instance.config_server_port()) {
+    bootconfig_args.push_back(
+        concat("androidboot.cuttlefish_config_server_port=",
+               instance.config_server_port()));
+  }
+
+  if (instance.keyboard_server_port()) {
+    bootconfig_args.push_back(concat("androidboot.vsock_keyboard_port=",
+                                     instance.keyboard_server_port()));
+  }
+
+  if (instance.touch_server_port()) {
+    bootconfig_args.push_back(
+        concat("androidboot.vsock_touch_port=", instance.touch_server_port()));
+  }
+
+  if (config.enable_vehicle_hal_grpc_server() &&
+      instance.vehicle_hal_server_port() &&
+      FileExists(config.vehicle_hal_grpc_server_binary())) {
+    constexpr int vehicle_hal_server_cid = 2;
+    bootconfig_args.push_back(concat(
+        "androidboot.vendor.vehiclehal.server.cid=", vehicle_hal_server_cid));
+    bootconfig_args.push_back(
+        concat("androidboot.vendor.vehiclehal.server.port=",
+               instance.vehicle_hal_server_port()));
+  }
+
+  if (instance.audiocontrol_server_port()) {
+    bootconfig_args.push_back(
+        concat("androidboot.vendor.audiocontrol.server.cid=",
+               instance.vsock_guest_cid()));
+    bootconfig_args.push_back(
+        concat("androidboot.vendor.audiocontrol.server.port=",
+               instance.audiocontrol_server_port()));
+  }
+
+  if (instance.frames_server_port()) {
+    bootconfig_args.push_back(concat("androidboot.vsock_frames_port=",
+                                     instance.frames_server_port()));
+  }
+
+  if (config.enable_modem_simulator() &&
+      instance.modem_simulator_ports() != "") {
+    bootconfig_args.push_back(concat("androidboot.modem_simulator_ports=",
+                                     instance.modem_simulator_ports()));
+  }
+
+  // TODO(b/158131610): Set this in crosvm instead
+  bootconfig_args.push_back(concat("androidboot.wifi_mac_address=",
+                                   mac_to_str(instance.wifi_mac_address())));
+
+  bootconfig_args.push_back("androidboot.verifiedbootstate=orange");
+
+  // Non-native architecture implies a significantly slower execution speed, so
+  // set a large timeout multiplier.
+  if (!IsHostCompatible(config.target_arch())) {
+    bootconfig_args.push_back("androidboot.hw_timeout_multiplier=50");
+  }
+
+  // TODO(b/173815685): Create an extra_bootconfig flag and add it to bootconfig
+
+  return bootconfig_args;
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/config/bootconfig_args.h b/host/libs/config/bootconfig_args.h
new file mode 100644
index 0000000..6c43204
--- /dev/null
+++ b/host/libs/config/bootconfig_args.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 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>
+#include <vector>
+
+#include "host/libs/config/cuttlefish_config.h"
+
+namespace cuttlefish {
+
+std::vector<std::string> BootconfigArgsFromConfig(
+    const CuttlefishConfig& config,
+    const CuttlefishConfig::InstanceSpecific& instance);
+
+}  // namespace cuttlefish
diff --git a/host/libs/config/custom_actions.cpp b/host/libs/config/custom_actions.cpp
new file mode 100644
index 0000000..1cc2e06
--- /dev/null
+++ b/host/libs/config/custom_actions.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+#include "host/libs/config/custom_actions.h"
+
+#include <android-base/logging.h>
+#include <json/json.h>
+
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "host/libs/config/cuttlefish_config.h"
+
+namespace cuttlefish {
+namespace {
+
+const char* kCustomActionShellCommand = "shell_command";
+const char* kCustomActionServer = "server";
+const char* kCustomActionDeviceStates = "device_states";
+const char* kCustomActionDeviceStateLidSwitchOpen = "lid_switch_open";
+const char* kCustomActionDeviceStateHingeAngleValue = "hinge_angle_value";
+const char* kCustomActionButton = "button";
+const char* kCustomActionButtons = "buttons";
+const char* kCustomActionButtonCommand = "command";
+const char* kCustomActionButtonTitle = "title";
+const char* kCustomActionButtonIconName = "icon_name";
+
+} //namespace
+
+
+CustomActionConfig::CustomActionConfig(const Json::Value& dictionary) {
+  if (dictionary.isMember(kCustomActionShellCommand) +
+          dictionary.isMember(kCustomActionServer) +
+          dictionary.isMember(kCustomActionDeviceStates) !=
+      1) {
+    LOG(FATAL) << "Custom action must contain exactly one of shell_command, "
+               << "server, or device_states";
+    return;
+  }
+  if (dictionary.isMember(kCustomActionShellCommand)) {
+    // Shell command with one button.
+    Json::Value button_entry = dictionary[kCustomActionButton];
+    buttons = {{button_entry[kCustomActionButtonCommand].asString(),
+                button_entry[kCustomActionButtonTitle].asString(),
+                button_entry[kCustomActionButtonIconName].asString()}};
+    shell_command = dictionary[kCustomActionShellCommand].asString();
+  } else if (dictionary.isMember(kCustomActionServer)) {
+    // Action server with possibly multiple buttons.
+    for (const Json::Value& button_entry : dictionary[kCustomActionButtons]) {
+      ControlPanelButton button = {
+          button_entry[kCustomActionButtonCommand].asString(),
+          button_entry[kCustomActionButtonTitle].asString(),
+          button_entry[kCustomActionButtonIconName].asString()};
+      buttons.push_back(button);
+    }
+    server = dictionary[kCustomActionServer].asString();
+  } else if (dictionary.isMember(kCustomActionDeviceStates)) {
+    // Device state(s) with one button.
+    // Each button press cycles to the next state, then repeats to the first.
+    Json::Value button_entry = dictionary[kCustomActionButton];
+    buttons = {{button_entry[kCustomActionButtonCommand].asString(),
+                button_entry[kCustomActionButtonTitle].asString(),
+                button_entry[kCustomActionButtonIconName].asString()}};
+    for (const Json::Value& device_state_entry :
+         dictionary[kCustomActionDeviceStates]) {
+      DeviceState state;
+      if (device_state_entry.isMember(kCustomActionDeviceStateLidSwitchOpen)) {
+        state.lid_switch_open =
+            device_state_entry[kCustomActionDeviceStateLidSwitchOpen].asBool();
+      }
+      if (device_state_entry.isMember(
+              kCustomActionDeviceStateHingeAngleValue)) {
+        state.hinge_angle_value =
+            device_state_entry[kCustomActionDeviceStateHingeAngleValue].asInt();
+      }
+      device_states.push_back(state);
+    }
+  } else {
+    LOG(FATAL) << "Unknown custom action type.";
+  }
+}
+
+Json::Value CustomActionConfig::ToJson() const {
+  Json::Value custom_action;
+  if (shell_command) {
+    // Shell command with one button.
+    custom_action[kCustomActionShellCommand] = *shell_command;
+    custom_action[kCustomActionButton] = Json::Value();
+    custom_action[kCustomActionButton][kCustomActionButtonCommand] =
+        buttons[0].command;
+    custom_action[kCustomActionButton][kCustomActionButtonTitle] =
+        buttons[0].title;
+    custom_action[kCustomActionButton][kCustomActionButtonIconName] =
+        buttons[0].icon_name;
+  } else if (server) {
+    // Action server with possibly multiple buttons.
+    custom_action[kCustomActionServer] = *server;
+    custom_action[kCustomActionButtons] = Json::Value(Json::arrayValue);
+    for (const auto& button : buttons) {
+      Json::Value button_entry;
+      button_entry[kCustomActionButtonCommand] = button.command;
+      button_entry[kCustomActionButtonTitle] = button.title;
+      button_entry[kCustomActionButtonIconName] = button.icon_name;
+      custom_action[kCustomActionButtons].append(button_entry);
+    }
+  } else if (!device_states.empty()) {
+    // Device state(s) with one button.
+    custom_action[kCustomActionDeviceStates] = Json::Value(Json::arrayValue);
+    for (const auto& device_state : device_states) {
+      Json::Value device_state_entry;
+      if (device_state.lid_switch_open) {
+        device_state_entry[kCustomActionDeviceStateLidSwitchOpen] =
+            *device_state.lid_switch_open;
+      }
+      if (device_state.hinge_angle_value) {
+        device_state_entry[kCustomActionDeviceStateHingeAngleValue] =
+            *device_state.hinge_angle_value;
+      }
+      custom_action[kCustomActionDeviceStates].append(device_state_entry);
+    }
+    custom_action[kCustomActionButton] = Json::Value();
+    custom_action[kCustomActionButton][kCustomActionButtonCommand] =
+        buttons[0].command;
+    custom_action[kCustomActionButton][kCustomActionButtonTitle] =
+        buttons[0].title;
+    custom_action[kCustomActionButton][kCustomActionButtonIconName] =
+        buttons[0].icon_name;
+  } else {
+    LOG(FATAL) << "Unknown custom action type.";
+  }
+  return custom_action;
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/config/custom_actions.h b/host/libs/config/custom_actions.h
new file mode 100644
index 0000000..6279401
--- /dev/null
+++ b/host/libs/config/custom_actions.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <json/json.h>
+
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace cuttlefish {
+
+struct ControlPanelButton {
+  std::string command;
+  std::string title;
+  std::string icon_name;
+};
+
+struct DeviceState {
+  std::optional<bool> lid_switch_open;
+  std::optional<int> hinge_angle_value;
+};
+
+struct CustomActionConfig {
+  CustomActionConfig(const Json::Value&);
+  Json::Value ToJson() const;
+
+  std::vector<ControlPanelButton> buttons;
+  std::optional<std::string> shell_command;
+  std::optional<std::string> server;
+  std::vector<DeviceState> device_states;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index c11ed16..c04faae 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -18,6 +18,7 @@
 
 #include <algorithm>
 #include <climits>
+#include <cstdint>
 #include <cstdlib>
 #include <cstring>
 #include <fstream>
@@ -28,14 +29,15 @@
 #include <time.h>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
 #include <json/json.h>
 
 #include "common/libs/utils/environment.h"
 #include "common/libs/utils/files.h"
+#include "host/libs/vm_manager/crosvm_manager.h"
 #include "host/libs/vm_manager/qemu_manager.h"
 
-
+namespace cuttlefish {
 namespace {
 
 int InstanceFromEnvironment() {
@@ -43,130 +45,38 @@
   static constexpr int kDefaultInstance = 1;
 
   // CUTTLEFISH_INSTANCE environment variable
-  const char* instance_str = std::getenv(kInstanceEnvironmentVariable);
-  if (!instance_str) {
+  std::string instance_str = StringFromEnv(kInstanceEnvironmentVariable, "");
+  if (instance_str.empty()) {
     // Try to get it from the user instead
-    instance_str = std::getenv("USER");
+    instance_str = StringFromEnv("USER", "");
 
-    if (!instance_str || std::strncmp(instance_str, vsoc::kVsocUserPrefix,
-                                      sizeof(vsoc::kVsocUserPrefix) - 1)) {
-      // No user or we don't recognize this user
-      LOG(WARNING) << "No user or non-vsoc user, returning default config";
+    if (instance_str.empty()) {
+      LOG(DEBUG) << "CUTTLEFISH_INSTANCE and USER unset, using instance id "
+                 << kDefaultInstance;
       return kDefaultInstance;
     }
-    instance_str += sizeof(vsoc::kVsocUserPrefix) - 1;
-
-    // Set the environment variable so that child processes see it
-    setenv(kInstanceEnvironmentVariable, instance_str, 0);
+    if (!android::base::StartsWith(instance_str, kVsocUserPrefix)) {
+      // No user or we don't recognize this user
+      LOG(DEBUG) << "Non-vsoc user, using instance id " << kDefaultInstance;
+      return kDefaultInstance;
+    }
+    instance_str = instance_str.substr(std::string(kVsocUserPrefix).size());
   }
-
-  int instance = std::atoi(instance_str);
+  int instance = std::stoi(instance_str);
   if (instance <= 0) {
-    instance = kDefaultInstance;
+    LOG(INFO) << "Failed to interpret \"" << instance_str << "\" as an id, "
+              << "using instance id " << kDefaultInstance;
+    return kDefaultInstance;
   }
-
   return instance;
 }
 
 const char* kInstances = "instances";
-const char* kAssemblyDir = "assembly_dir";
-const char* kSerialNumber = "serial_number";
-const char* kInstanceDir = "instance_dir";
-const char* kVmManager = "vm_manager";
-const char* const kGpuMode = "gpu_mode";
-const char* const kWaylandSocket = "wayland_socket";
-const char* const kXDisplay = "x_display";
-const char* kDeviceTitle = "device_title";
 
-const char* kCpus = "cpus";
-const char* kMemoryMb = "memory_mb";
-const char* kDpi = "dpi";
-const char* kXRes = "x_res";
-const char* kYRes = "y_res";
-const char* kRefreshRateHz = "refresh_rate_hz";
 
-const char* kKernelImagePath = "kernel_image_path";
-const char* kUseUnpackedKernel = "use_unpacked_kernel";
-const char* kDecompressedKernelImagePath = "decompressed_kernel_image_path";
-const char* kDecompressKernel = "decompress_kernel";
-const char* kGdbFlag = "gdb_flag";
-const char* kRamdiskImagePath = "ramdisk_image_path";
-const char* kInitramfsPath = "initramfs_path";
-const char* kFinalRamdiskPath = "final_ramdisk_path";
-const char* kVendorRamdiskImagePath = "vendor_ramdisk_image_path";
-
-const char* kVirtualDiskPaths = "virtual_disk_paths";
-const char* kDeprecatedBootCompleted = "deprecated_boot_completed";
-
-const char* kMobileBridgeName = "mobile_bridge_name";
-const char* kMobileTapName = "mobile_tap_name";
-const char* kWifiTapName = "wifi_tap_name";
-const char* kVsockGuestCid = "vsock_guest_cid";
-
-const char* kUuid = "uuid";
-const char* kCuttlefishEnvPath = "cuttlefish_env_path";
-
-const char* kAdbMode = "adb_mode";
-const char* kHostPort = "host_port";
-const char* kAdbIPAndPort = "adb_ip_and_port";
-const char* kSetupWizardMode = "setupwizard_mode";
-
-const char* kQemuBinary = "qemu_binary";
-const char* kCrosvmBinary = "crosvm_binary";
-const char* kConsoleForwarderBinary = "console_forwarder_binary";
-const char* kKernelLogMonitorBinary = "kernel_log_monitor_binary";
-
-const char* kEnableVncServer = "enable_vnc_server";
-const char* kVncServerBinary = "vnc_server_binary";
-const char* kVncServerPort = "vnc_server_port";
-
-const char* kEnableWebRTC = "enable_webrtc";
-const char* kWebRTCBinary = "webrtc_binary";
-const char* kWebRTCAssetsDir = "webrtc_assets_dir";
-const char* kWebRTCPublicIP = "webrtc_public_ip";
-const char* kWebRTCEnableADBWebSocket = "webrtc_enable_adb_websocket";
-
-const char* kEnableVehicleHalServer = "enable_vehicle_hal_server";
-const char* kVehicleHalServerBinary = "vehicle_hal_server_binary";
-const char* kVehicleHalServerPort = "vehicle_hal_server_port";
-
-const char* kRestartSubprocesses = "restart_subprocesses";
-const char* kRunAdbConnector = "run_adb_connector";
-const char* kAdbConnectorBinary = "adb_connector_binary";
-const char* kSocketVsockProxyBinary = "socket_vsock_proxy_binary";
-
-const char* kRunAsDaemon = "run_as_daemon";
-
-const char* kDataPolicy = "data_policy";
-const char* kBlankDataImageMb = "blank_data_image_mb";
-const char* kBlankDataImageFmt = "blank_data_image_fmt";
-
-const char* kLogcatMode = "logcat_mode";
-const char* kLogcatReceiverBinary = "logcat_receiver_binary";
-const char* kConfigServerBinary = "config_server_binary";
-
-const char* kRunTombstoneReceiver = "enable_tombstone_logger";
-const char* kTombstoneReceiverBinary = "tombstone_receiver_binary";
-
-const char* kWebRTCCertsDir = "webrtc_certs_dir";
-
-const char* kBootloader = "bootloader";
-const char* kUseBootloader = "use_bootloader";
-
-const char* kBootSlot = "boot_slot";
-
-const char* kLoopMaxPart = "loop_max_part";
-const char* kGuestEnforceSecurity = "guest_enforce_security";
-const char* kGuestAuditSecurity = "guest_audit_security";
-const char* kGuestForceNormalBoot = "guest_force_normal_boot";
-const char* kBootImageKernelCmdline = "boot_image_kernel_cmdline";
-const char* kExtraKernelCmdline = "extra_kernel_cmdline";
-
-const char* kWifiMacAddress = "wifi_mac_address";
 }  // namespace
 
-namespace vsoc {
-
+const char* const kGpuModeAuto = "auto";
 const char* const kGpuModeGuestSwiftshader = "guest_swiftshader";
 const char* const kGpuModeDrmVirgl = "drm_virgl";
 const char* const kGpuModeGfxStream = "gfxstream";
@@ -174,17 +84,10 @@
 std::string DefaultEnvironmentPath(const char* environment_key,
                                    const char* default_value,
                                    const char* subpath) {
-  return cvd::StringFromEnv(environment_key, default_value) + "/" + subpath;
+  return StringFromEnv(environment_key, default_value) + "/" + subpath;
 }
 
-Json::Value* CuttlefishConfig::MutableInstanceSpecific::Dictionary() {
-  return &(*config_->dictionary_)[kInstances][id_];
-}
-
-const Json::Value* CuttlefishConfig::InstanceSpecific::Dictionary() const {
-  return &(*config_->dictionary_)[kInstances][id_];
-}
-
+static constexpr char kAssemblyDir[] = "assembly_dir";
 std::string CuttlefishConfig::assembly_dir() const {
   return (*dictionary_)[kAssemblyDir].asString();
 }
@@ -192,18 +95,7 @@
   (*dictionary_)[kAssemblyDir] = assembly_dir;
 }
 
-std::string CuttlefishConfig::InstanceSpecific::instance_dir() const {
-  return (*Dictionary())[kInstanceDir].asString();
-}
-void CuttlefishConfig::MutableInstanceSpecific::set_instance_dir(
-    const std::string& instance_dir) {
-  (*Dictionary())[kInstanceDir] = instance_dir;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::instance_internal_dir() const {
-  return PerInstancePath(kInternalDirName);
-}
-
+static constexpr char kVmManager[] = "vm_manager";
 std::string CuttlefishConfig::vm_manager() const {
   return (*dictionary_)[kVmManager].asString();
 }
@@ -211,6 +103,7 @@
   (*dictionary_)[kVmManager] = name;
 }
 
+static constexpr char kGpuMode[] = "gpu_mode";
 std::string CuttlefishConfig::gpu_mode() const {
   return (*dictionary_)[kGpuMode].asString();
 }
@@ -218,32 +111,11 @@
   (*dictionary_)[kGpuMode] = name;
 }
 
-std::string CuttlefishConfig::wayland_socket() const {
-  // Don't use SetPath here: the path is already fully formed.
-  return (*dictionary_)[kWaylandSocket].asString();
-}
-void CuttlefishConfig::set_wayland_socket(const std::string& path) {
-  (*dictionary_)[kWaylandSocket] = path;
-}
-
-std::string CuttlefishConfig::x_display() const {
-  return (*dictionary_)[kXDisplay].asString();
-}
-void CuttlefishConfig::set_x_display(const std::string& address) {
-  (*dictionary_)[kXDisplay] = address;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::serial_number() const {
-  return (*Dictionary())[kSerialNumber].asString();
-}
-void CuttlefishConfig::MutableInstanceSpecific::set_serial_number(
-    const std::string& serial_number) {
-  (*Dictionary())[kSerialNumber] = serial_number;
-}
-
+static constexpr char kCpus[] = "cpus";
 int CuttlefishConfig::cpus() const { return (*dictionary_)[kCpus].asInt(); }
 void CuttlefishConfig::set_cpus(int cpus) { (*dictionary_)[kCpus] = cpus; }
 
+static constexpr char kMemoryMb[] = "memory_mb";
 int CuttlefishConfig::memory_mb() const {
   return (*dictionary_)[kMemoryMb].asInt();
 }
@@ -251,15 +123,39 @@
   (*dictionary_)[kMemoryMb] = memory_mb;
 }
 
+static constexpr char kDpi[] = "dpi";
 int CuttlefishConfig::dpi() const { return (*dictionary_)[kDpi].asInt(); }
 void CuttlefishConfig::set_dpi(int dpi) { (*dictionary_)[kDpi] = dpi; }
 
-int CuttlefishConfig::x_res() const { return (*dictionary_)[kXRes].asInt(); }
-void CuttlefishConfig::set_x_res(int x_res) { (*dictionary_)[kXRes] = x_res; }
+static constexpr char kDisplayConfigs[] = "display_configs";
+static constexpr char kXRes[] = "x_res";
+static constexpr char kYRes[] = "y_res";
+std::vector<CuttlefishConfig::DisplayConfig>
+CuttlefishConfig::display_configs() const {
+  std::vector<DisplayConfig> display_configs;
+  for (auto& display_config_json : (*dictionary_)[kDisplayConfigs]) {
+    DisplayConfig display_config = {};
+    display_config.width = display_config_json[kXRes].asInt();
+    display_config.height = display_config_json[kYRes].asInt();
+    display_configs.emplace_back(std::move(display_config));
+  }
+  return display_configs;
+}
+void CuttlefishConfig::set_display_configs(
+    const std::vector<DisplayConfig>& display_configs) {
+  Json::Value display_configs_json(Json::arrayValue);
 
-int CuttlefishConfig::y_res() const { return (*dictionary_)[kYRes].asInt(); }
-void CuttlefishConfig::set_y_res(int y_res) { (*dictionary_)[kYRes] = y_res; }
+  for (const DisplayConfig& display_configs : display_configs) {
+    Json::Value display_config_json(Json::objectValue);
+    display_config_json[kXRes] = display_configs.width;
+    display_config_json[kYRes] = display_configs.height;
+    display_configs_json.append(display_config_json);
+  }
 
+  (*dictionary_)[kDisplayConfigs] = display_configs_json;
+}
+
+static constexpr char kRefreshRateHz[] = "refresh_rate_hz";
 int CuttlefishConfig::refresh_rate_hz() const {
   return (*dictionary_)[kRefreshRateHz].asInt();
 }
@@ -267,109 +163,22 @@
   (*dictionary_)[kRefreshRateHz] = refresh_rate_hz;
 }
 
-std::string CuttlefishConfig::kernel_image_path() const {
-  return (*dictionary_)[kKernelImagePath].asString();
-}
-
 void CuttlefishConfig::SetPath(const std::string& key,
                                const std::string& path) {
   if (!path.empty()) {
-    (*dictionary_)[key] = cvd::AbsolutePath(path);
+    (*dictionary_)[key] = AbsolutePath(path);
   }
 }
 
-void CuttlefishConfig::set_kernel_image_path(
-    const std::string& kernel_image_path) {
-  SetPath(kKernelImagePath, kernel_image_path);
+static constexpr char kGdbPort[] = "gdb_port";
+int CuttlefishConfig::gdb_port() const {
+  return (*dictionary_)[kGdbPort].asInt();
+}
+void CuttlefishConfig::set_gdb_port(int port) {
+  (*dictionary_)[kGdbPort] = port;
 }
 
-bool CuttlefishConfig::use_unpacked_kernel() const {
-  return (*dictionary_)[kUseUnpackedKernel].asBool();
-}
-
-void CuttlefishConfig::set_use_unpacked_kernel(bool use_unpacked_kernel) {
-  (*dictionary_)[kUseUnpackedKernel] = use_unpacked_kernel;
-}
-
-bool CuttlefishConfig::decompress_kernel() const {
-  return (*dictionary_)[kDecompressKernel].asBool();
-}
-void CuttlefishConfig::set_decompress_kernel(bool decompress_kernel) {
-  (*dictionary_)[kDecompressKernel] = decompress_kernel;
-}
-
-std::string CuttlefishConfig::decompressed_kernel_image_path() const {
-  return (*dictionary_)[kDecompressedKernelImagePath].asString();
-}
-void CuttlefishConfig::set_decompressed_kernel_image_path(
-    const std::string& path) {
-  SetPath(kDecompressedKernelImagePath, path);
-}
-
-std::string CuttlefishConfig::gdb_flag() const {
-  return (*dictionary_)[kGdbFlag].asString();
-}
-
-void CuttlefishConfig::set_gdb_flag(const std::string& device) {
-  (*dictionary_)[kGdbFlag] = device;
-}
-
-std::string CuttlefishConfig::ramdisk_image_path() const {
-  return (*dictionary_)[kRamdiskImagePath].asString();
-}
-void CuttlefishConfig::set_ramdisk_image_path(
-    const std::string& ramdisk_image_path) {
-  SetPath(kRamdiskImagePath, ramdisk_image_path);
-}
-
-std::string CuttlefishConfig::initramfs_path() const {
-  return (*dictionary_)[kInitramfsPath].asString();
-}
-void CuttlefishConfig::set_initramfs_path(const std::string& initramfs_path) {
-  SetPath(kInitramfsPath, initramfs_path);
-}
-
-std::string CuttlefishConfig::final_ramdisk_path() const {
-  return (*dictionary_)[kFinalRamdiskPath].asString();
-}
-void CuttlefishConfig::set_final_ramdisk_path(
-    const std::string& final_ramdisk_path) {
-  SetPath(kFinalRamdiskPath, final_ramdisk_path);
-}
-
-std::string CuttlefishConfig::vendor_ramdisk_image_path() const {
-  return (*dictionary_)[kVendorRamdiskImagePath].asString();
-}
-void CuttlefishConfig::set_vendor_ramdisk_image_path(
-    const std::string& vendor_ramdisk_image_path) {
-  SetPath(kVendorRamdiskImagePath, vendor_ramdisk_image_path);
-}
-
-std::vector<std::string> CuttlefishConfig::InstanceSpecific::virtual_disk_paths() const {
-  std::vector<std::string> virtual_disks;
-  auto virtual_disks_json_obj = (*Dictionary())[kVirtualDiskPaths];
-  for (const auto& disk : virtual_disks_json_obj) {
-    virtual_disks.push_back(disk.asString());
-  }
-  return virtual_disks;
-}
-void CuttlefishConfig::MutableInstanceSpecific::set_virtual_disk_paths(
-    const std::vector<std::string>& virtual_disk_paths) {
-  Json::Value virtual_disks_json_obj(Json::arrayValue);
-  for (const auto& arg : virtual_disk_paths) {
-    virtual_disks_json_obj.append(arg);
-  }
-  (*Dictionary())[kVirtualDiskPaths] = virtual_disks_json_obj;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::kernel_log_pipe_name() const {
-  return cvd::AbsolutePath(PerInstanceInternalPath("kernel-log-pipe"));
-}
-
-std::string CuttlefishConfig::InstanceSpecific::console_pipe_name() const {
-  return cvd::AbsolutePath(PerInstanceInternalPath("console-pipe"));
-}
-
+static constexpr char kDeprecatedBootCompleted[] = "deprecated_boot_completed";
 bool CuttlefishConfig::deprecated_boot_completed() const {
   return (*dictionary_)[kDeprecatedBootCompleted].asBool();
 }
@@ -378,71 +187,7 @@
   (*dictionary_)[kDeprecatedBootCompleted] = deprecated_boot_completed;
 }
 
-std::string CuttlefishConfig::InstanceSpecific::access_kregistry_path() const {
-  return cvd::AbsolutePath(PerInstancePath("access-kregistry"));
-}
-
-std::string CuttlefishConfig::InstanceSpecific::console_path() const {
-  return cvd::AbsolutePath(PerInstancePath("console"));
-}
-
-std::string CuttlefishConfig::InstanceSpecific::logcat_path() const {
-  return cvd::AbsolutePath(PerInstancePath("logcat"));
-}
-
-std::string CuttlefishConfig::InstanceSpecific::launcher_monitor_socket_path()
-    const {
-  return cvd::AbsolutePath(PerInstancePath("launcher_monitor.sock"));
-}
-
-std::string CuttlefishConfig::InstanceSpecific::launcher_log_path() const {
-  return cvd::AbsolutePath(PerInstancePath("launcher.log"));
-}
-
-std::string CuttlefishConfig::InstanceSpecific::sdcard_path() const {
-  return cvd::AbsolutePath(PerInstancePath("sdcard.img"));
-}
-
-std::string CuttlefishConfig::InstanceSpecific::mobile_bridge_name() const {
-  return (*Dictionary())[kMobileBridgeName].asString();
-}
-void CuttlefishConfig::MutableInstanceSpecific::set_mobile_bridge_name(
-    const std::string& mobile_bridge_name) {
-  (*Dictionary())[kMobileBridgeName] = mobile_bridge_name;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::mobile_tap_name() const {
-  return (*Dictionary())[kMobileTapName].asString();
-}
-void CuttlefishConfig::MutableInstanceSpecific::set_mobile_tap_name(
-    const std::string& mobile_tap_name) {
-  (*Dictionary())[kMobileTapName] = mobile_tap_name;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::wifi_tap_name() const {
-  return (*Dictionary())[kWifiTapName].asString();
-}
-void CuttlefishConfig::MutableInstanceSpecific::set_wifi_tap_name(
-    const std::string& wifi_tap_name) {
-  (*Dictionary())[kWifiTapName] = wifi_tap_name;
-}
-
-int CuttlefishConfig::InstanceSpecific::vsock_guest_cid() const {
-  return (*Dictionary())[kVsockGuestCid].asInt();
-}
-
-void CuttlefishConfig::MutableInstanceSpecific::set_vsock_guest_cid(
-    int vsock_guest_cid) {
-  (*Dictionary())[kVsockGuestCid] = vsock_guest_cid;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::uuid() const {
-  return (*Dictionary())[kUuid].asString();
-}
-void CuttlefishConfig::MutableInstanceSpecific::set_uuid(const std::string& uuid) {
-  (*Dictionary())[kUuid] = uuid;
-}
-
+static constexpr char kCuttlefishEnvPath[] = "cuttlefish_env_path";
 void CuttlefishConfig::set_cuttlefish_env_path(const std::string& path) {
   SetPath(kCuttlefishEnvPath, path);
 }
@@ -463,6 +208,7 @@
   }
 }
 
+static constexpr char kAdbMode[] = "adb_mode";
 std::set<AdbMode> CuttlefishConfig::adb_mode() const {
   std::set<AdbMode> args_set;
   for (auto& mode : (*dictionary_)[kAdbMode]) {
@@ -470,7 +216,6 @@
   }
   return args_set;
 }
-
 void CuttlefishConfig::set_adb_mode(const std::set<std::string>& mode) {
   Json::Value mode_json_obj(Json::arrayValue);
   for (const auto& arg : mode) {
@@ -479,329 +224,350 @@
   (*dictionary_)[kAdbMode] = mode_json_obj;
 }
 
-int CuttlefishConfig::InstanceSpecific::host_port() const {
-  return (*Dictionary())[kHostPort].asInt();
-}
-
-void CuttlefishConfig::MutableInstanceSpecific::set_host_port(int host_port) {
-  (*Dictionary())[kHostPort] = host_port;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::adb_ip_and_port() const {
-  return (*Dictionary())[kAdbIPAndPort].asString();
-}
-
-void CuttlefishConfig::MutableInstanceSpecific::set_adb_ip_and_port(
-    const std::string& ip_port) {
-  (*Dictionary())[kAdbIPAndPort] = ip_port;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::adb_device_name() const {
-  if (adb_ip_and_port() != "") {
-    return adb_ip_and_port();
+static SecureHal StringToSecureHal(std::string mode) {
+  std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
+  if (mode == "keymint") {
+    return SecureHal::Keymint;
+  } else if (mode == "gatekeeper") {
+    return SecureHal::Gatekeeper;
+  } else {
+    return SecureHal::Unknown;
   }
-  LOG(ERROR) << "no adb_mode found, returning bad device name";
-  return "NO_ADB_MODE_SET_NO_VALID_DEVICE_NAME";
 }
 
-std::string CuttlefishConfig::InstanceSpecific::device_title() const {
-  return (*Dictionary())[kDeviceTitle].asString();
+static constexpr char kSecureHals[] = "secure_hals";
+std::set<SecureHal> CuttlefishConfig::secure_hals() const {
+  std::set<SecureHal> args_set;
+  for (auto& hal : (*dictionary_)[kSecureHals]) {
+    args_set.insert(StringToSecureHal(hal.asString()));
+  }
+  return args_set;
+}
+void CuttlefishConfig::set_secure_hals(const std::set<std::string>& hals) {
+  Json::Value hals_json_obj(Json::arrayValue);
+  for (const auto& hal : hals) {
+    hals_json_obj.append(hal);
+  }
+  (*dictionary_)[kSecureHals] = hals_json_obj;
 }
 
-void CuttlefishConfig::MutableInstanceSpecific::set_device_title(
-    const std::string& title) {
-  (*Dictionary())[kDeviceTitle] = title;
-}
-
+static constexpr char kSetupWizardMode[] = "setupwizard_mode";
 std::string CuttlefishConfig::setupwizard_mode() const {
   return (*dictionary_)[kSetupWizardMode].asString();
 }
-
 void CuttlefishConfig::set_setupwizard_mode(const std::string& mode) {
   (*dictionary_)[kSetupWizardMode] = mode;
 }
 
-std::string CuttlefishConfig::qemu_binary() const {
-  return (*dictionary_)[kQemuBinary].asString();
+static constexpr char kQemuBinaryDir[] = "qemu_binary_dir";
+std::string CuttlefishConfig::qemu_binary_dir() const {
+  return (*dictionary_)[kQemuBinaryDir].asString();
+}
+void CuttlefishConfig::set_qemu_binary_dir(const std::string& qemu_binary_dir) {
+  (*dictionary_)[kQemuBinaryDir] = qemu_binary_dir;
 }
 
-void CuttlefishConfig::set_qemu_binary(const std::string& qemu_binary) {
-  (*dictionary_)[kQemuBinary] = qemu_binary;
-}
-
+static constexpr char kCrosvmBinary[] = "crosvm_binary";
 std::string CuttlefishConfig::crosvm_binary() const {
   return (*dictionary_)[kCrosvmBinary].asString();
 }
-
 void CuttlefishConfig::set_crosvm_binary(const std::string& crosvm_binary) {
   (*dictionary_)[kCrosvmBinary] = crosvm_binary;
 }
 
-std::string CuttlefishConfig::console_forwarder_binary() const {
-  return (*dictionary_)[kConsoleForwarderBinary].asString();
+static constexpr char kTpmDevice[] = "tpm_device";
+std::string CuttlefishConfig::tpm_device() const {
+  return (*dictionary_)[kTpmDevice].asString();
+}
+void CuttlefishConfig::set_tpm_device(const std::string& tpm_device) {
+  (*dictionary_)[kTpmDevice] = tpm_device;
 }
 
-void CuttlefishConfig::set_console_forwarder_binary(
-    const std::string& binary) {
-  (*dictionary_)[kConsoleForwarderBinary] = binary;
+static constexpr char kEnableGnssGrpcProxy[] = "enable_gnss_grpc_proxy";
+void CuttlefishConfig::set_enable_gnss_grpc_proxy(const bool enable_gnss_grpc_proxy) {
+  (*dictionary_)[kEnableGnssGrpcProxy] = enable_gnss_grpc_proxy;
+}
+bool CuttlefishConfig::enable_gnss_grpc_proxy() const {
+  return (*dictionary_)[kEnableGnssGrpcProxy].asBool();
 }
 
-std::string CuttlefishConfig::kernel_log_monitor_binary() const {
-  return (*dictionary_)[kKernelLogMonitorBinary].asString();
-}
-
-void CuttlefishConfig::set_kernel_log_monitor_binary(
-    const std::string& kernel_log_monitor_binary) {
-  (*dictionary_)[kKernelLogMonitorBinary] = kernel_log_monitor_binary;
-}
-
+static constexpr char kEnableVncServer[] = "enable_vnc_server";
 bool CuttlefishConfig::enable_vnc_server() const {
   return (*dictionary_)[kEnableVncServer].asBool();
 }
-
 void CuttlefishConfig::set_enable_vnc_server(bool enable_vnc_server) {
   (*dictionary_)[kEnableVncServer] = enable_vnc_server;
 }
 
-std::string CuttlefishConfig::vnc_server_binary() const {
-  return (*dictionary_)[kVncServerBinary].asString();
+static constexpr char kEnableSandbox[] = "enable_sandbox";
+void CuttlefishConfig::set_enable_sandbox(const bool enable_sandbox) {
+  (*dictionary_)[kEnableSandbox] = enable_sandbox;
+}
+bool CuttlefishConfig::enable_sandbox() const {
+  return (*dictionary_)[kEnableSandbox].asBool();
 }
 
-void CuttlefishConfig::set_vnc_server_binary(
-    const std::string& vnc_server_binary) {
-  (*dictionary_)[kVncServerBinary] = vnc_server_binary;
+static constexpr char kSeccompPolicyDir[] = "seccomp_policy_dir";
+void CuttlefishConfig::set_seccomp_policy_dir(const std::string& seccomp_policy_dir) {
+  if (seccomp_policy_dir.empty()) {
+    (*dictionary_)[kSeccompPolicyDir] = seccomp_policy_dir;
+    return;
+  }
+  SetPath(kSeccompPolicyDir, seccomp_policy_dir);
+}
+std::string CuttlefishConfig::seccomp_policy_dir() const {
+  return (*dictionary_)[kSeccompPolicyDir].asString();
 }
 
-int CuttlefishConfig::InstanceSpecific::vnc_server_port() const {
-  return (*Dictionary())[kVncServerPort].asInt();
-}
-
-void CuttlefishConfig::MutableInstanceSpecific::set_vnc_server_port(int vnc_server_port) {
-  (*Dictionary())[kVncServerPort] = vnc_server_port;
-}
-
-int CuttlefishConfig::InstanceSpecific::vehicle_hal_server_port() const {
-  return (*Dictionary())[kVehicleHalServerPort].asInt();
-}
-
-void CuttlefishConfig::MutableInstanceSpecific::set_vehicle_hal_server_port(int vehicle_hal_server_port) {
-  (*Dictionary())[kVehicleHalServerPort] = vehicle_hal_server_port;
-}
-
+static constexpr char kEnableWebRTC[] = "enable_webrtc";
 void CuttlefishConfig::set_enable_webrtc(bool enable_webrtc) {
   (*dictionary_)[kEnableWebRTC] = enable_webrtc;
 }
-
 bool CuttlefishConfig::enable_webrtc() const {
   return (*dictionary_)[kEnableWebRTC].asBool();
 }
 
-void CuttlefishConfig::set_webrtc_binary(const std::string& webrtc_binary) {
-  (*dictionary_)[kWebRTCBinary] = webrtc_binary;
-}
-
-std::string CuttlefishConfig::webrtc_binary() const {
-  return (*dictionary_)[kWebRTCBinary].asString();
-}
-
+static constexpr char kEnableVehicleHalServer[] = "enable_vehicle_hal_server";
 void CuttlefishConfig::set_enable_vehicle_hal_grpc_server(bool enable_vehicle_hal_grpc_server) {
   (*dictionary_)[kEnableVehicleHalServer] = enable_vehicle_hal_grpc_server;
 }
-
 bool CuttlefishConfig::enable_vehicle_hal_grpc_server() const {
   return (*dictionary_)[kEnableVehicleHalServer].asBool();
 }
 
+static constexpr char kVehicleHalServerBinary[] = "vehicle_hal_server_binary";
 void CuttlefishConfig::set_vehicle_hal_grpc_server_binary(const std::string& vehicle_hal_server_binary) {
   (*dictionary_)[kVehicleHalServerBinary] = vehicle_hal_server_binary;
 }
-
 std::string CuttlefishConfig::vehicle_hal_grpc_server_binary() const {
   return (*dictionary_)[kVehicleHalServerBinary].asString();
 }
 
+static constexpr char kCustomActions[] = "custom_actions";
+void CuttlefishConfig::set_custom_actions(const std::vector<CustomActionConfig>& actions) {
+  Json::Value actions_array(Json::arrayValue);
+  for (const auto& action : actions) {
+    actions_array.append(action.ToJson());
+  }
+  (*dictionary_)[kCustomActions] = actions_array;
+}
+std::vector<CustomActionConfig> CuttlefishConfig::custom_actions() const {
+  std::vector<CustomActionConfig> result;
+  for (Json::Value custom_action : (*dictionary_)[kCustomActions]) {
+    result.push_back(CustomActionConfig(custom_action));
+  }
+  return result;
+}
+
+static constexpr char kWebRTCAssetsDir[] = "webrtc_assets_dir";
 void CuttlefishConfig::set_webrtc_assets_dir(const std::string& webrtc_assets_dir) {
   (*dictionary_)[kWebRTCAssetsDir] = webrtc_assets_dir;
 }
-
 std::string CuttlefishConfig::webrtc_assets_dir() const {
   return (*dictionary_)[kWebRTCAssetsDir].asString();
 }
 
-void CuttlefishConfig::set_webrtc_public_ip(
-        const std::string& webrtc_public_ip) {
-  (*dictionary_)[kWebRTCPublicIP] = webrtc_public_ip;
-}
-
-std::string CuttlefishConfig::webrtc_public_ip() const {
-  return (*dictionary_)[kWebRTCPublicIP].asString();
-}
-
+static constexpr char kWebRTCEnableADBWebSocket[] =
+    "webrtc_enable_adb_websocket";
 void CuttlefishConfig::set_webrtc_enable_adb_websocket(bool enable) {
     (*dictionary_)[kWebRTCEnableADBWebSocket] = enable;
 }
-
 bool CuttlefishConfig::webrtc_enable_adb_websocket() const {
     return (*dictionary_)[kWebRTCEnableADBWebSocket].asBool();
 }
 
+static constexpr char kRestartSubprocesses[] = "restart_subprocesses";
 bool CuttlefishConfig::restart_subprocesses() const {
   return (*dictionary_)[kRestartSubprocesses].asBool();
 }
-
 void CuttlefishConfig::set_restart_subprocesses(bool restart_subprocesses) {
   (*dictionary_)[kRestartSubprocesses] = restart_subprocesses;
 }
 
+static constexpr char kRunAdbConnector[] = "run_adb_connector";
 bool CuttlefishConfig::run_adb_connector() const {
   return (*dictionary_)[kRunAdbConnector].asBool();
 }
-
 void CuttlefishConfig::set_run_adb_connector(bool run_adb_connector) {
   (*dictionary_)[kRunAdbConnector] = run_adb_connector;
 }
 
-std::string CuttlefishConfig::adb_connector_binary() const {
-  return (*dictionary_)[kAdbConnectorBinary].asString();
-}
-
-void CuttlefishConfig::set_adb_connector_binary(
-    const std::string& adb_connector_binary) {
-  (*dictionary_)[kAdbConnectorBinary] = adb_connector_binary;
-}
-
-std::string CuttlefishConfig::socket_vsock_proxy_binary() const {
-  return (*dictionary_)[kSocketVsockProxyBinary].asString();
-}
-
-void CuttlefishConfig::set_socket_vsock_proxy_binary(
-    const std::string& socket_vsock_proxy_binary) {
-  (*dictionary_)[kSocketVsockProxyBinary] = socket_vsock_proxy_binary;
-}
-
+static constexpr char kRunAsDaemon[] = "run_as_daemon";
 bool CuttlefishConfig::run_as_daemon() const {
   return (*dictionary_)[kRunAsDaemon].asBool();
 }
-
 void CuttlefishConfig::set_run_as_daemon(bool run_as_daemon) {
   (*dictionary_)[kRunAsDaemon] = run_as_daemon;
 }
+
+static constexpr char kDataPolicy[] = "data_policy";
 std::string CuttlefishConfig::data_policy() const {
   return (*dictionary_)[kDataPolicy].asString();
 }
-
 void CuttlefishConfig::set_data_policy(const std::string& data_policy) {
   (*dictionary_)[kDataPolicy] = data_policy;
 }
 
+static constexpr char kBlankDataImageMb[] = "blank_data_image_mb";
 int CuttlefishConfig::blank_data_image_mb() const {
   return (*dictionary_)[kBlankDataImageMb].asInt();
 }
-
 void CuttlefishConfig::set_blank_data_image_mb(int blank_data_image_mb) {
   (*dictionary_)[kBlankDataImageMb] = blank_data_image_mb;
 }
 
+static constexpr char kBlankDataImageFmt[] = "blank_data_image_fmt";
 std::string CuttlefishConfig::blank_data_image_fmt() const {
   return (*dictionary_)[kBlankDataImageFmt].asString();
 }
-
 void CuttlefishConfig::set_blank_data_image_fmt(const std::string& blank_data_image_fmt) {
   (*dictionary_)[kBlankDataImageFmt] = blank_data_image_fmt;
 }
 
-
-void CuttlefishConfig::set_logcat_mode(const std::string& mode) {
-  (*dictionary_)[kLogcatMode] = mode;
-}
-
-std::string CuttlefishConfig::logcat_mode() const {
-  return (*dictionary_)[kLogcatMode].asString();
-}
-
-void CuttlefishConfig::set_logcat_receiver_binary(const std::string& binary) {
-  SetPath(kLogcatReceiverBinary, binary);
-}
-
-std::string CuttlefishConfig::logcat_receiver_binary() const {
-  return (*dictionary_)[kLogcatReceiverBinary].asString();
-}
-
-void CuttlefishConfig::set_config_server_binary(const std::string& binary) {
-  SetPath(kConfigServerBinary, binary);
-}
-
-std::string CuttlefishConfig::config_server_binary() const {
-  return (*dictionary_)[kConfigServerBinary].asString();
-}
-
-bool CuttlefishConfig::enable_tombstone_receiver() const {
-  return (*dictionary_)[kRunTombstoneReceiver].asBool();
-}
-
-void CuttlefishConfig::set_enable_tombstone_receiver(bool enable_tombstone_receiver) {
-  (*dictionary_)[kRunTombstoneReceiver] = enable_tombstone_receiver;
-}
-
-std::string CuttlefishConfig::tombstone_receiver_binary() const {
-  return (*dictionary_)[kTombstoneReceiverBinary].asString();
-}
-
-void CuttlefishConfig::set_tombstone_receiver_binary(const std::string& e2e_test_binary) {
-  (*dictionary_)[kTombstoneReceiverBinary] = e2e_test_binary;
-}
-
-bool CuttlefishConfig::use_bootloader() const {
-  return (*dictionary_)[kUseBootloader].asBool();
-}
-
-void CuttlefishConfig::set_use_bootloader(bool use_bootloader) {
-  (*dictionary_)[kUseBootloader] = use_bootloader;
-}
-
+static constexpr char kBootloader[] = "bootloader";
 std::string CuttlefishConfig::bootloader() const {
   return (*dictionary_)[kBootloader].asString();
 }
-
 void CuttlefishConfig::set_bootloader(const std::string& bootloader) {
   SetPath(kBootloader, bootloader);
 }
 
+static constexpr char kBootSlot[] = "boot_slot";
 void CuttlefishConfig::set_boot_slot(const std::string& boot_slot) {
   (*dictionary_)[kBootSlot] = boot_slot;
 }
-
 std::string CuttlefishConfig::boot_slot() const {
   return (*dictionary_)[kBootSlot].asString();
 }
 
+static constexpr char kWebRTCCertsDir[] = "webrtc_certs_dir";
 void CuttlefishConfig::set_webrtc_certs_dir(const std::string& certs_dir) {
   (*dictionary_)[kWebRTCCertsDir] = certs_dir;
 }
-
 std::string CuttlefishConfig::webrtc_certs_dir() const {
   return (*dictionary_)[kWebRTCCertsDir].asString();
 }
 
-std::string CuttlefishConfig::InstanceSpecific::touch_socket_path() const {
-  return PerInstanceInternalPath("touch.sock");
+static constexpr char kSigServerPort[] = "webrtc_sig_server_port";
+void CuttlefishConfig::set_sig_server_port(int port) {
+  (*dictionary_)[kSigServerPort] = port;
+}
+int CuttlefishConfig::sig_server_port() const {
+  return (*dictionary_)[kSigServerPort].asInt();
 }
 
-std::string CuttlefishConfig::InstanceSpecific::keyboard_socket_path() const {
-  return PerInstanceInternalPath("keyboard.sock");
+static constexpr char kWebrtcUdpPortRange[] = "webrtc_udp_port_range";
+void CuttlefishConfig::set_webrtc_udp_port_range(
+    std::pair<uint16_t, uint16_t> range) {
+  Json::Value arr(Json::ValueType::arrayValue);
+  arr[0] = range.first;
+  arr[1] = range.second;
+  (*dictionary_)[kWebrtcUdpPortRange] = arr;
+}
+std::pair<uint16_t, uint16_t> CuttlefishConfig::webrtc_udp_port_range() const {
+  std::pair<uint16_t, uint16_t> ret;
+  ret.first = (*dictionary_)[kWebrtcUdpPortRange][0].asInt();
+  ret.second = (*dictionary_)[kWebrtcUdpPortRange][1].asInt();
+  return ret;
 }
 
-std::string CuttlefishConfig::InstanceSpecific::frames_socket_path() const {
-  return PerInstanceInternalPath("frames.sock");
+static constexpr char kWebrtcTcpPortRange[] = "webrtc_tcp_port_range";
+void CuttlefishConfig::set_webrtc_tcp_port_range(
+    std::pair<uint16_t, uint16_t> range) {
+  Json::Value arr(Json::ValueType::arrayValue);
+  arr[0] = range.first;
+  arr[1] = range.second;
+  (*dictionary_)[kWebrtcTcpPortRange] = arr;
+}
+std::pair<uint16_t, uint16_t> CuttlefishConfig::webrtc_tcp_port_range() const {
+  std::pair<uint16_t, uint16_t> ret;
+  ret.first = (*dictionary_)[kWebrtcTcpPortRange][0].asInt();
+  ret.second = (*dictionary_)[kWebrtcTcpPortRange][1].asInt();
+  return ret;
 }
 
-void CuttlefishConfig::set_loop_max_part(int loop_max_part) {
-  (*dictionary_)[kLoopMaxPart] = loop_max_part;
+static constexpr char kSigServerAddress[] = "webrtc_sig_server_addr";
+void CuttlefishConfig::set_sig_server_address(const std::string& addr) {
+  (*dictionary_)[kSigServerAddress] = addr;
 }
-int CuttlefishConfig::loop_max_part() const {
-  return (*dictionary_)[kLoopMaxPart].asInt();
+std::string CuttlefishConfig::sig_server_address() const {
+  return (*dictionary_)[kSigServerAddress].asString();
 }
 
+static constexpr char kSigServerPath[] = "webrtc_sig_server_path";
+void CuttlefishConfig::set_sig_server_path(const std::string& path) {
+  // Don't use SetPath here, it's a URL path not a file system path
+  (*dictionary_)[kSigServerPath] = path;
+}
+std::string CuttlefishConfig::sig_server_path() const {
+  return (*dictionary_)[kSigServerPath].asString();
+}
+
+static constexpr char kSigServerStrict[] = "webrtc_sig_server_strict";
+void CuttlefishConfig::set_sig_server_strict(bool strict) {
+  (*dictionary_)[kSigServerStrict] = strict;
+}
+bool CuttlefishConfig::sig_server_strict() const {
+  return (*dictionary_)[kSigServerStrict].asBool();
+}
+
+static constexpr char kSigServerHeadersPath[] =
+    "webrtc_sig_server_headers_path";
+void CuttlefishConfig::set_sig_server_headers_path(const std::string& path) {
+  SetPath(kSigServerHeadersPath, path);
+}
+std::string CuttlefishConfig::sig_server_headers_path() const {
+  return (*dictionary_)[kSigServerHeadersPath].asString();
+}
+
+static constexpr char kRunModemSimulator[] = "enable_modem_simulator";
+bool CuttlefishConfig::enable_modem_simulator() const {
+  return (*dictionary_)[kRunModemSimulator].asBool();
+}
+void CuttlefishConfig::set_enable_modem_simulator(bool enable_modem_simulator) {
+  (*dictionary_)[kRunModemSimulator] = enable_modem_simulator;
+}
+
+static constexpr char kModemSimulatorInstanceNumber[] =
+    "modem_simulator_instance_number";
+void CuttlefishConfig::set_modem_simulator_instance_number(
+    int instance_number) {
+  (*dictionary_)[kModemSimulatorInstanceNumber] = instance_number;
+}
+int CuttlefishConfig::modem_simulator_instance_number() const {
+  return (*dictionary_)[kModemSimulatorInstanceNumber].asInt();
+}
+
+static constexpr char kModemSimulatorSimType[] = "modem_simulator_sim_type";
+void CuttlefishConfig::set_modem_simulator_sim_type(int sim_type) {
+  (*dictionary_)[kModemSimulatorSimType] = sim_type;
+}
+int CuttlefishConfig::modem_simulator_sim_type() const {
+  return (*dictionary_)[kModemSimulatorSimType].asInt();
+}
+
+static constexpr char kHostToolsVersion[] = "host_tools_version";
+void CuttlefishConfig::set_host_tools_version(
+    const std::map<std::string, uint32_t>& versions) {
+  Json::Value json(Json::objectValue);
+  for (const auto& [key, value] : versions) {
+    json[key] = value;
+  }
+  (*dictionary_)[kHostToolsVersion] = json;
+}
+std::map<std::string, uint32_t> CuttlefishConfig::host_tools_version() const {
+  if (!dictionary_->isMember(kHostToolsVersion)) {
+    return {};
+  }
+  std::map<std::string, uint32_t> versions;
+  const auto& elem = (*dictionary_)[kHostToolsVersion];
+  for (auto it = elem.begin(); it != elem.end(); it++) {
+    versions[it.key().asString()] = it->asUInt();
+  }
+  return versions;
+}
+
+static constexpr char kGuestEnforceSecurity[] = "guest_enforce_security";
 void CuttlefishConfig::set_guest_enforce_security(bool guest_enforce_security) {
   (*dictionary_)[kGuestEnforceSecurity] = guest_enforce_security;
 }
@@ -809,6 +575,7 @@
   return (*dictionary_)[kGuestEnforceSecurity].asBool();
 }
 
+const char* kGuestAuditSecurity = "guest_audit_security";
 void CuttlefishConfig::set_guest_audit_security(bool guest_audit_security) {
   (*dictionary_)[kGuestAuditSecurity] = guest_audit_security;
 }
@@ -816,50 +583,43 @@
   return (*dictionary_)[kGuestAuditSecurity].asBool();
 }
 
-void CuttlefishConfig::set_guest_force_normal_boot(bool guest_force_normal_boot) {
-  (*dictionary_)[kGuestForceNormalBoot] = guest_force_normal_boot;
+static constexpr char kenableHostBluetooth[] = "enable_host_bluetooth";
+void CuttlefishConfig::set_enable_host_bluetooth(bool enable_host_bluetooth) {
+  (*dictionary_)[kenableHostBluetooth] = enable_host_bluetooth;
 }
-bool CuttlefishConfig::guest_force_normal_boot() const {
-  return (*dictionary_)[kGuestForceNormalBoot].asBool();
+bool CuttlefishConfig::enable_host_bluetooth() const {
+  return (*dictionary_)[kenableHostBluetooth].asBool();
 }
 
-void CuttlefishConfig::MutableInstanceSpecific::set_wifi_mac_address(
-    const std::array<unsigned char, 6>& mac_address) {
-  Json::Value mac_address_obj(Json::arrayValue);
-  for (const auto& num : mac_address) {
-    mac_address_obj.append(num);
+static constexpr char kEnableMetrics[] = "enable_metrics";
+void CuttlefishConfig::set_enable_metrics(std::string enable_metrics) {
+  (*dictionary_)[kEnableMetrics] = kUnknown;
+  if (!enable_metrics.empty()) {
+    switch (enable_metrics.at(0)) {
+      case 'y':
+      case 'Y':
+        (*dictionary_)[kEnableMetrics] = kYes;
+        break;
+      case 'n':
+      case 'N':
+        (*dictionary_)[kEnableMetrics] = kNo;
+        break;
+    }
   }
-  (*Dictionary())[kWifiMacAddress] = mac_address_obj;
+}
+CuttlefishConfig::Answer CuttlefishConfig::enable_metrics() const {
+  return (CuttlefishConfig::Answer)(*dictionary_)[kEnableMetrics].asInt();
 }
 
-std::array<unsigned char, 6> CuttlefishConfig::InstanceSpecific::wifi_mac_address() const {
-  std::array<unsigned char, 6> mac_address{0, 0, 0, 0, 0, 0};
-  auto mac_address_obj = (*Dictionary())[kWifiMacAddress];
-  if (mac_address_obj.size() != 6) {
-    LOG(ERROR) << kWifiMacAddress << " entry had wrong size";
-    return {};
-  }
-  for (int i = 0; i < 6; i++) {
-    mac_address[i] = mac_address_obj[i].asInt();
-  }
-  return mac_address;
+static constexpr char kMetricsBinary[] = "metrics_binary";
+void CuttlefishConfig::set_metrics_binary(const std::string& metrics_binary) {
+  (*dictionary_)[kMetricsBinary] = metrics_binary;
+}
+std::string CuttlefishConfig::metrics_binary() const {
+  return (*dictionary_)[kMetricsBinary].asString();
 }
 
-void CuttlefishConfig::set_boot_image_kernel_cmdline(std::string boot_image_kernel_cmdline) {
-  Json::Value args_json_obj(Json::arrayValue);
-  for (const auto& arg : android::base::Split(boot_image_kernel_cmdline, " ")) {
-    args_json_obj.append(arg);
-  }
-  (*dictionary_)[kBootImageKernelCmdline] = args_json_obj;
-}
-std::vector<std::string> CuttlefishConfig::boot_image_kernel_cmdline() const {
-  std::vector<std::string> cmdline;
-  for (const Json::Value& arg : (*dictionary_)[kBootImageKernelCmdline]) {
-    cmdline.push_back(arg.asString());
-  }
-  return cmdline;
-}
-
+static constexpr char kExtraKernelCmdline[] = "extra_kernel_cmdline";
 void CuttlefishConfig::set_extra_kernel_cmdline(std::string extra_cmdline) {
   Json::Value args_json_obj(Json::arrayValue);
   for (const auto& arg : android::base::Split(extra_cmdline, " ")) {
@@ -875,12 +635,128 @@
   return cmdline;
 }
 
+static constexpr char kRilDns[] = "ril_dns";
+void CuttlefishConfig::set_ril_dns(const std::string& ril_dns) {
+  (*dictionary_)[kRilDns] = ril_dns;
+}
+std::string CuttlefishConfig::ril_dns() const {
+  return (*dictionary_)[kRilDns].asString();
+}
+
+static constexpr char kKgdb[] = "kgdb";
+void CuttlefishConfig::set_kgdb(bool kgdb) {
+  (*dictionary_)[kKgdb] = kgdb;
+}
+bool CuttlefishConfig::kgdb() const {
+  return (*dictionary_)[kKgdb].asBool();
+}
+
+static constexpr char kEnableMinimalMode[] = "enable_minimal_mode";
+bool CuttlefishConfig::enable_minimal_mode() const {
+  return (*dictionary_)[kEnableMinimalMode].asBool();
+}
+void CuttlefishConfig::set_enable_minimal_mode(bool enable_minimal_mode) {
+  (*dictionary_)[kEnableMinimalMode] = enable_minimal_mode;
+}
+
+static constexpr char kConsole[] = "console";
+void CuttlefishConfig::set_console(bool console) {
+  (*dictionary_)[kConsole] = console;
+}
+bool CuttlefishConfig::console() const {
+  return (*dictionary_)[kConsole].asBool();
+}
+std::string CuttlefishConfig::console_dev() const {
+  auto can_use_virtio_console = !kgdb() && !use_bootloader();
+  std::string console_dev;
+  if (can_use_virtio_console) {
+    // If kgdb and the bootloader are disabled, the Android serial console
+    // spawns on a virtio-console port. If the bootloader is enabled, virtio
+    // console can't be used since uboot doesn't support it.
+    console_dev = "hvc1";
+  } else {
+    // crosvm ARM does not support ttyAMA. ttyAMA is a part of ARM arch.
+    Arch target = target_arch();
+    if ((target == Arch::Arm64 || target == Arch::Arm) &&
+        vm_manager() != vm_manager::CrosvmManager::name()) {
+      console_dev = "ttyAMA0";
+    } else {
+      console_dev = "ttyS0";
+    }
+  }
+  return console_dev;
+}
+
+static constexpr char kVhostNet[] = "vhost_net";
+void CuttlefishConfig::set_vhost_net(bool vhost_net) {
+  (*dictionary_)[kVhostNet] = vhost_net;
+}
+bool CuttlefishConfig::vhost_net() const {
+  return (*dictionary_)[kVhostNet].asBool();
+}
+
+static constexpr char kEthernet[] = "ethernet";
+void CuttlefishConfig::set_ethernet(bool ethernet) {
+  (*dictionary_)[kEthernet] = ethernet;
+}
+bool CuttlefishConfig::ethernet() const {
+  return (*dictionary_)[kEthernet].asBool();
+}
+
+static constexpr char kRecordScreen[] = "record_screen";
+void CuttlefishConfig::set_record_screen(bool record_screen) {
+  (*dictionary_)[kRecordScreen] = record_screen;
+}
+bool CuttlefishConfig::record_screen() const {
+  return (*dictionary_)[kRecordScreen].asBool();
+}
+
+static constexpr char kSmt[] = "smt";
+void CuttlefishConfig::set_smt(bool smt) {
+  (*dictionary_)[kSmt] = smt;
+}
+bool CuttlefishConfig::smt() const {
+  return (*dictionary_)[kSmt].asBool();
+}
+
+static constexpr char kEnableAudio[] = "enable_audio";
+void CuttlefishConfig::set_enable_audio(bool enable) {
+  (*dictionary_)[kEnableAudio] = enable;
+}
+bool CuttlefishConfig::enable_audio() const {
+  return (*dictionary_)[kEnableAudio].asBool();
+}
+
+static constexpr char kProtectedVm[] = "protected_vm";
+void CuttlefishConfig::set_protected_vm(bool protected_vm) {
+  (*dictionary_)[kProtectedVm] = protected_vm;
+}
+bool CuttlefishConfig::protected_vm() const {
+  return (*dictionary_)[kProtectedVm].asBool();
+}
+
+static constexpr char kTargetArch[] = "target_arch";
+void CuttlefishConfig::set_target_arch(Arch target_arch) {
+  (*dictionary_)[kTargetArch] = static_cast<int>(target_arch);
+}
+Arch CuttlefishConfig::target_arch() const {
+  return static_cast<Arch>((*dictionary_)[kTargetArch].asInt());
+}
+
+static constexpr char kBootconfigSupported[] = "bootconfig_supported";
+bool CuttlefishConfig::bootconfig_supported() const {
+  return (*dictionary_)[kBootconfigSupported].asBool();
+}
+void CuttlefishConfig::set_bootconfig_supported(bool bootconfig_supported) {
+  (*dictionary_)[kBootconfigSupported] = bootconfig_supported;
+}
+
 // Creates the (initially empty) config object and populates it with values from
 // the config file if the CUTTLEFISH_CONFIG_FILE env variable is present.
 // Returns nullptr if there was an error loading from file
 /*static*/ CuttlefishConfig* CuttlefishConfig::BuildConfigImpl() {
-  auto config_file_path = cvd::StringFromEnv(kCuttlefishConfigEnvVarName,
-                                             vsoc::GetGlobalConfigFileLink());
+  auto config_file_path = StringFromEnv(kCuttlefishConfigEnvVarName,
+                                        GetGlobalConfigFileLink());
   auto ret = new CuttlefishConfig();
   if (ret) {
     auto loaded = ret->LoadFromFile(config_file_path.c_str());
@@ -897,6 +773,13 @@
   return config.get();
 }
 
+/*static*/ bool CuttlefishConfig::ConfigExists() {
+  auto config_file_path = StringFromEnv(kCuttlefishConfigEnvVarName,
+                                        GetGlobalConfigFileLink());
+  auto real_file_path = AbsolutePath(config_file_path.c_str());
+  return FileExists(real_file_path);
+}
+
 CuttlefishConfig::CuttlefishConfig() : dictionary_(new Json::Value()) {}
 // Can't use '= default' on the header because the compiler complains of
 // Json::Value being an incomplete type
@@ -906,16 +789,16 @@
 CuttlefishConfig& CuttlefishConfig::operator=(CuttlefishConfig&&) = default;
 
 bool CuttlefishConfig::LoadFromFile(const char* file) {
-  auto real_file_path = cvd::AbsolutePath(file);
+  auto real_file_path = AbsolutePath(file);
   if (real_file_path.empty()) {
     LOG(ERROR) << "Could not get real path for file " << file;
     return false;
   }
-  Json::Reader reader;
+  Json::CharReaderBuilder builder;
   std::ifstream ifs(real_file_path);
-  if (!reader.parse(ifs, *dictionary_)) {
-    LOG(ERROR) << "Could not read config file " << file << ": "
-               << reader.getFormattedErrorMessages();
+  std::string errorMessage;
+  if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
+    LOG(ERROR) << "Could not read config file " << file << ": " << errorMessage;
     return false;
   }
   return true;
@@ -932,30 +815,7 @@
 
 std::string CuttlefishConfig::AssemblyPath(
     const std::string& file_name) const {
-  return cvd::AbsolutePath(assembly_dir() + "/" + file_name);
-}
-
-std::string CuttlefishConfig::composite_disk_path() const {
-  return AssemblyPath("composite.img");
-}
-
-std::string CuttlefishConfig::InstanceSpecific::PerInstancePath(
-    const char* file_name) const {
-  return (instance_dir() + "/") + file_name;
-}
-
-std::string CuttlefishConfig::InstanceSpecific::PerInstanceInternalPath(
-    const char* file_name) const {
-  if (file_name[0] == '\0') {
-    // Don't append a / if file_name is empty.
-    return PerInstancePath(kInternalDirName);
-  }
-  auto relative_path = (std::string(kInternalDirName) + "/") + file_name;
-  return PerInstancePath(relative_path.c_str());
-}
-
-std::string CuttlefishConfig::InstanceSpecific::instance_name() const {
-  return ForCurrentInstance("cvd-");
+  return AbsolutePath(assembly_dir() + "/" + file_name);
 }
 
 CuttlefishConfig::MutableInstanceSpecific CuttlefishConfig::ForInstance(int num) {
@@ -984,8 +844,19 @@
   return instance_id;
 }
 
+int GetDefaultVsockCid() {
+  // we assume that this function is used to configure CuttlefishConfig once
+  static const int default_vsock_cid = 3 + GetInstance() - 1;
+  return default_vsock_cid;
+}
+
+int GetVsockServerPort(const int base,
+                       const int vsock_guest_cid /**< per instance guest cid */) {
+    return base + (vsock_guest_cid - 3);
+}
+
 std::string GetGlobalConfigFileLink() {
-  return cvd::StringFromEnv("HOME", ".") + "/.cuttlefish_config.json";
+  return StringFromEnv("HOME", ".") + "/.cuttlefish_config.json";
 }
 
 std::string ForCurrentInstance(const char* prefix) {
@@ -1005,28 +876,21 @@
   return prefix + str;
 }
 
-std::string GetDefaultPerInstanceDir() {
-  std::ostringstream stream;
-  stream << std::getenv("HOME") << "/cuttlefish_runtime";
-  return stream.str();
-}
-
-int GetDefaultPerInstanceVsockCid() {
-  constexpr int kFirstGuestCid = 3;
-  return vsoc::HostSupportsVsock() ? ForCurrentInstance(kFirstGuestCid) : 0;
-}
-
 std::string DefaultHostArtifactsPath(const std::string& file_name) {
-  return (cvd::StringFromEnv("ANDROID_HOST_OUT",
-                             cvd::StringFromEnv("HOME", ".")) +
-          "/") +
+  return (StringFromEnv("ANDROID_SOONG_HOST_OUT", StringFromEnv("HOME", ".")) + "/") +
          file_name;
 }
 
+std::string HostBinaryPath(const std::string& binary_name) {
+#ifdef __ANDROID__
+  return binary_name;
+#else
+  return DefaultHostArtifactsPath("bin/" + binary_name);
+#endif
+}
+
 std::string DefaultGuestImagePath(const std::string& file_name) {
-  return (cvd::StringFromEnv("ANDROID_PRODUCT_OUT",
-                             cvd::StringFromEnv("HOME", ".")) +
-          "/") +
+  return (StringFromEnv("ANDROID_PRODUCT_OUT", StringFromEnv("HOME", "."))) +
          file_name;
 }
 
@@ -1037,10 +901,4 @@
   return supported;
 }
 
-bool HostSupportsVsock() {
-  static bool supported =
-      std::system(
-          "/usr/lib/cuttlefish-common/bin/capability_query.py vsock") == 0;
-  return supported;
-}
-}  // namespace vsoc
+}  // namespace cuttlefish
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index e6a1e79..2b76c75 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -15,17 +15,29 @@
  */
 #pragma once
 
+#include <sys/types.h>
 #include <array>
+#include <cstdint>
+#include <map>
 #include <memory>
+#include <optional>
 #include <string>
 #include <set>
 #include <vector>
 
+#include "common/libs/utils/environment.h"
+#include "host/libs/config/custom_actions.h"
+
 namespace Json {
 class Value;
 }
 
-namespace vsoc {
+namespace cuttlefish {
+constexpr char kLogcatSerialMode[] = "serial";
+constexpr char kLogcatVsockMode[] = "vsock";
+}
+
+namespace cuttlefish {
 
 constexpr char kDefaultUuidPrefix[] = "699acfc4-c8c4-11e7-882b-5065f31dc1";
 constexpr char kCuttlefishConfigEnvVarName[] = "CUTTLEFISH_CONFIG_FILE";
@@ -37,8 +49,12 @@
     "VIRTUAL_DEVICE_NETWORK_MOBILE_CONNECTED";
 constexpr char kWifiConnectedMessage[] =
     "VIRTUAL_DEVICE_NETWORK_WIFI_CONNECTED";
+constexpr char kEthernetConnectedMessage[] =
+    "VIRTUAL_DEVICE_NETWORK_ETHERNET_CONNECTED";
+constexpr char kScreenChangedMessage[] = "VIRTUAL_DEVICE_SCREEN_CHANGED";
 constexpr char kInternalDirName[] = "internal";
-
+constexpr char kSharedDirName[] = "shared";
+constexpr char kCrosvmVarEmptyDir[] = "/var/empty";
 
 enum class AdbMode {
   VsockTunnel,
@@ -47,10 +63,17 @@
   Unknown,
 };
 
+enum class SecureHal {
+  Unknown,
+  Keymint,
+  Gatekeeper,
+};
+
 // Holds the configuration of the cuttlefish instances.
 class CuttlefishConfig {
  public:
   static const CuttlefishConfig* Get();
+  static bool ConfigExists();
 
   CuttlefishConfig();
   CuttlefishConfig(CuttlefishConfig&&);
@@ -66,23 +89,12 @@
 
   std::string AssemblyPath(const std::string&) const;
 
-  std::string composite_disk_path() const;
-
   std::string vm_manager() const;
   void set_vm_manager(const std::string& name);
 
   std::string gpu_mode() const;
   void set_gpu_mode(const std::string& name);
 
-  std::string serial_number() const;
-  void set_serial_number(const std::string& serial_number);
-
-  std::string wayland_socket() const;
-  void set_wayland_socket(const std::string& path);
-
-  std::string x_display() const;
-  void set_x_display(const std::string& address);
-
   int cpus() const;
   void set_cpus(int cpus);
 
@@ -92,104 +104,59 @@
   int dpi() const;
   void set_dpi(int dpi);
 
-  int x_res() const;
-  void set_x_res(int x_res);
-
-  int y_res() const;
-  void set_y_res(int y_res);
-
   int refresh_rate_hz() const;
   void set_refresh_rate_hz(int refresh_rate_hz);
 
-  // Returns kernel image extracted from the boot image or the user-provided one
-  // if given by command line to the launcher. This function should not be used
-  // to get the kernel image the vmm should boot, GetKernelImageToUse() should
-  // be used instead.
-  std::string kernel_image_path() const;
-  void set_kernel_image_path(const std::string& kernel_image_path);
+  struct DisplayConfig {
+    int width;
+    int height;
+  };
 
-  bool decompress_kernel() const;
-  void set_decompress_kernel(bool decompress_kernel);
+  std::vector<DisplayConfig> display_configs() const;
+  void set_display_configs(const std::vector<DisplayConfig>& display_configs);
 
-  // Returns the path to the kernel image that should be given to the vm manager
-  // to boot, takes into account whether the original image was decompressed or
-  // not.
-  std::string GetKernelImageToUse() const {
-    return decompress_kernel() ? decompressed_kernel_image_path()
-                               : kernel_image_path();
-  }
-
-  std::string decompressed_kernel_image_path() const;
-  void set_decompressed_kernel_image_path(const std::string& path);
-
-  bool use_unpacked_kernel() const;
-  void set_use_unpacked_kernel(bool use_unpacked_kernel);
-
-  std::string gdb_flag() const;
-  void set_gdb_flag(const std::string& gdb);
-
-  std::string ramdisk_image_path() const;
-  void set_ramdisk_image_path(const std::string& ramdisk_image_path);
-
-  std::string initramfs_path() const;
-  void set_initramfs_path(const std::string& initramfs_path);
-
-  std::string final_ramdisk_path() const;
-  void set_final_ramdisk_path(const std::string& final_ramdisk_path);
-
-  std::string vendor_ramdisk_image_path() const;
-  void set_vendor_ramdisk_image_path(const std::string&
-    vendor_ramdisk_image_path);
+  int gdb_port() const;
+  void set_gdb_port(int gdb_port);
 
   bool deprecated_boot_completed() const;
   void set_deprecated_boot_completed(bool deprecated_boot_completed);
 
-  std::string logcat_receiver_binary() const;
-  void set_logcat_receiver_binary(const std::string& binary);
-
-  std::string config_server_binary() const;
-  void set_config_server_binary(const std::string& binary);
-
   void set_cuttlefish_env_path(const std::string& path);
   std::string cuttlefish_env_path() const;
 
   void set_adb_mode(const std::set<std::string>& modes);
   std::set<AdbMode> adb_mode() const;
 
+  void set_secure_hals(const std::set<std::string>& hals);
+  std::set<SecureHal> secure_hals() const;
+
   void set_setupwizard_mode(const std::string& title);
   std::string setupwizard_mode() const;
 
-  void set_qemu_binary(const std::string& qemu_binary);
-  std::string qemu_binary() const;
+  void set_qemu_binary_dir(const std::string& qemu_binary_dir);
+  std::string qemu_binary_dir() const;
 
   void set_crosvm_binary(const std::string& crosvm_binary);
   std::string crosvm_binary() const;
 
-  void set_console_forwarder_binary(const std::string& crosvm_binary);
-  std::string console_forwarder_binary() const;
-
-  void set_kernel_log_monitor_binary(
-      const std::string& kernel_log_monitor_binary);
-  std::string kernel_log_monitor_binary() const;
+  void set_tpm_device(const std::string& tpm_device);
+  std::string tpm_device() const;
 
   void set_enable_vnc_server(bool enable_vnc_server);
   bool enable_vnc_server() const;
 
-  void set_vnc_server_binary(const std::string& vnc_server_binary);
-  std::string vnc_server_binary() const;
+  void set_enable_sandbox(const bool enable_sandbox);
+  bool enable_sandbox() const;
+
+  void set_seccomp_policy_dir(const std::string& seccomp_policy_dir);
+  std::string seccomp_policy_dir() const;
 
   void set_enable_webrtc(bool enable_webrtc);
   bool enable_webrtc() const;
 
-  void set_webrtc_binary(const std::string& webrtc_binary);
-  std::string webrtc_binary() const;
-
-  void set_webrtc_assets_dir(const std::string& webrtc_binary);
+  void set_webrtc_assets_dir(const std::string& webrtc_assets_dir);
   std::string webrtc_assets_dir() const;
 
-  void set_webrtc_public_ip(const std::string& webrtc_public_ip);
-  std::string webrtc_public_ip() const;
-
   void set_webrtc_enable_adb_websocket(bool enable);
   bool webrtc_enable_adb_websocket() const;
 
@@ -199,17 +166,17 @@
   void set_vehicle_hal_grpc_server_binary(const std::string& vhal_server_binary);
   std::string vehicle_hal_grpc_server_binary() const;
 
+  void set_custom_actions(const std::vector<CustomActionConfig>& actions);
+  std::vector<CustomActionConfig> custom_actions() const;
+
   void set_restart_subprocesses(bool restart_subprocesses);
   bool restart_subprocesses() const;
 
   void set_run_adb_connector(bool run_adb_connector);
   bool run_adb_connector() const;
 
-  void set_adb_connector_binary(const std::string& adb_connector_binary);
-  std::string adb_connector_binary() const;
-
-  void set_socket_vsock_proxy_binary(const std::string& binary);
-  std::string socket_vsock_proxy_binary() const;
+  void set_enable_gnss_grpc_proxy(const bool enable_gnss_grpc_proxy);
+  bool enable_gnss_grpc_proxy() const;
 
   void set_run_as_daemon(bool run_as_daemon);
   bool run_as_daemon() const;
@@ -223,47 +190,130 @@
   void set_blank_data_image_fmt(const std::string& blank_data_image_fmt);
   std::string blank_data_image_fmt() const;
 
-  void set_logcat_mode(const std::string& mode);
-  std::string logcat_mode() const;
-
-  void set_enable_tombstone_receiver(bool enable_tombstone_receiver);
-  bool enable_tombstone_receiver() const;
-
-  void set_tombstone_receiver_binary(const std::string& binary);
-  std::string tombstone_receiver_binary() const;
-
-  void set_use_bootloader(bool use_bootloader);
-  bool use_bootloader() const;
-
   void set_bootloader(const std::string& bootloader_path);
   std::string bootloader() const;
 
+  // TODO (b/163575714) add virtio console support to the bootloader so the
+  // virtio console path for the console device can be taken again. When that
+  // happens, this function can be deleted along with all the code paths it
+  // forces.
+  bool use_bootloader() const { return true; };
+
   void set_boot_slot(const std::string& boot_slot);
   std::string boot_slot() const;
 
-  void set_loop_max_part(int loop_max_part);
-  int loop_max_part() const;
-
   void set_guest_enforce_security(bool guest_enforce_security);
   bool guest_enforce_security() const;
 
   void set_guest_audit_security(bool guest_audit_security);
   bool guest_audit_security() const;
 
-  void set_guest_force_normal_boot(bool guest_force_normal_boot);
-  bool guest_force_normal_boot() const;
+  void set_enable_host_bluetooth(bool enable_host_bluetooth);
+  bool enable_host_bluetooth() const;
 
-  void set_boot_image_kernel_cmdline(std::string boot_image_kernel_cmdline);
-  std::vector<std::string> boot_image_kernel_cmdline() const;
+  enum Answer {
+    kUnknown = 0,
+    kYes,
+    kNo,
+  };
+
+  void set_enable_metrics(std::string enable_metrics);
+  CuttlefishConfig::Answer enable_metrics() const;
+
+  void set_metrics_binary(const std::string& metrics_binary);
+  std::string metrics_binary() const;
 
   void set_extra_kernel_cmdline(std::string extra_cmdline);
   std::vector<std::string> extra_kernel_cmdline() const;
 
+  // A directory containing the SSL certificates for the signaling server
   void set_webrtc_certs_dir(const std::string& certs_dir);
   std::string webrtc_certs_dir() const;
 
-  void set_dialog_certs_dir(const std::string& certs_dir);
-  std::string dialog_certs_dir() const;
+  // The port for the webrtc signaling server. It's used by the signaling server
+  // to bind to it and by the webrtc process to connect to and register itself
+  void set_sig_server_port(int port);
+  int sig_server_port() const;
+
+  // The range of UDP ports available for webrtc sessions.
+  void set_webrtc_udp_port_range(std::pair<uint16_t, uint16_t> range);
+  std::pair<uint16_t, uint16_t> webrtc_udp_port_range() const;
+
+  // The range of TCP ports available for webrtc sessions.
+  void set_webrtc_tcp_port_range(std::pair<uint16_t, uint16_t> range);
+  std::pair<uint16_t, uint16_t> webrtc_tcp_port_range() const;
+
+  // The address of the signaling server
+  void set_sig_server_address(const std::string& addr);
+  std::string sig_server_address() const;
+
+  // The path section of the url where the webrtc process registers itself with
+  // the signaling server
+  void set_sig_server_path(const std::string& path);
+  std::string sig_server_path() const;
+
+  // Whether the webrtc process should attempt to verify the authenticity of the
+  // signaling server (reject self signed certificates)
+  void set_sig_server_strict(bool strict);
+  bool sig_server_strict() const;
+
+  // A file containing http headers to include in the connection to the
+  // signaling server
+  void set_sig_server_headers_path(const std::string& path);
+  std::string sig_server_headers_path() const;
+
+  // The dns address of mobile network (RIL)
+  void set_ril_dns(const std::string& ril_dns);
+  std::string ril_dns() const;
+
+  // KGDB configuration for kernel debugging
+  void set_kgdb(bool kgdb);
+  bool kgdb() const;
+
+  // Serial console
+  void set_console(bool console);
+  bool console() const;
+  std::string console_dev() const;
+
+  // Configuration flags for a minimal device
+  bool enable_minimal_mode() const;
+  void set_enable_minimal_mode(bool enable_minimal_mode);
+
+  void set_enable_modem_simulator(bool enable_modem_simulator);
+  bool enable_modem_simulator() const;
+
+  void set_modem_simulator_instance_number(int instance_numbers);
+  int modem_simulator_instance_number() const;
+
+  void set_modem_simulator_sim_type(int sim_type);
+  int modem_simulator_sim_type() const;
+
+  void set_host_tools_version(const std::map<std::string, uint32_t>&);
+  std::map<std::string, uint32_t> host_tools_version() const;
+
+  void set_vhost_net(bool vhost_net);
+  bool vhost_net() const;
+
+  void set_ethernet(bool ethernet);
+  bool ethernet() const;
+
+  void set_record_screen(bool record_screen);
+  bool record_screen() const;
+
+  void set_smt(bool smt);
+  bool smt() const;
+
+  void set_enable_audio(bool enable);
+  bool enable_audio() const;
+
+  void set_protected_vm(bool protected_vm);
+  bool protected_vm() const;
+
+  void set_target_arch(Arch target_arch);
+  Arch target_arch() const;
+
+  void set_bootconfig_supported(bool bootconfig_supported);
+  bool bootconfig_supported() const;
 
   class InstanceSpecific;
   class MutableInstanceSpecific;
@@ -289,22 +339,56 @@
     const Json::Value* Dictionary() const;
   public:
     std::string serial_number() const;
+    // If any of the following port numbers is 0, the relevant service is not
+    // running on the guest.
+
+    // Port number to connect to vnc server on the host
     int vnc_server_port() const;
+    // Port number to connect to the tombstone receiver on the host
+    int tombstone_receiver_port() const;
+    // Port number to connect to the config server on the host
+    int config_server_port() const;
+    // Port number to connect to the keyboard server on the host. (Only
+    // operational if QEMU is the vmm.)
+    int keyboard_server_port() const;
+    // Port number to connect to the touch server on the host. (Only
+    // operational if QEMU is the vmm.)
+    int touch_server_port() const;
+    // Port number to connect to the frame server on the host. (Only
+    // operational if using swiftshader as the GPU.)
+    int frames_server_port() const;
     // Port number to connect to the vehicle HAL server on the host
     int vehicle_hal_server_port() const;
+    // Port number to connect to the audiocontrol server on the guest
+    int audiocontrol_server_port() const;
+    // Port number to connect to the adb server on the host
     int host_port() const;
+    // Port number to connect to the gnss grpc proxy server on the host
+    int gnss_grpc_proxy_server_port() const;
     std::string adb_ip_and_port() const;
+    // Port number to connect to the root-canal on the host
+    int rootcanal_hci_port() const;
+    int rootcanal_link_port() const;
+    int rootcanal_test_port() const;
+    std::string rootcanal_config_file() const;
+    std::string rootcanal_default_commands_file() const;
+
     std::string adb_device_name() const;
     std::string device_title() const;
+    std::string gnss_file_path() const;
     std::string mobile_bridge_name() const;
     std::string mobile_tap_name() const;
     std::string wifi_tap_name() const;
+    std::string ethernet_tap_name() const;
+    uint32_t session_id() const;
+    bool use_allocd() const;
     int vsock_guest_cid() const;
     std::string uuid() const;
     std::string instance_name() const;
     std::vector<std::string> virtual_disk_paths() const;
 
-    // Returns the path to a file with the given name in the instance directory..
+    // Returns the path to a file with the given name in the instance
+    // directory..
     std::string PerInstancePath(const char* file_name) const;
     std::string PerInstanceInternalPath(const char* file_name) const;
 
@@ -314,17 +398,31 @@
 
     std::string touch_socket_path() const;
     std::string keyboard_socket_path() const;
+    std::string switches_socket_path() const;
     std::string frames_socket_path() const;
 
+    // mock hal guest socket that will be vsock/virtio later on
+    std::string confui_hal_guest_socket_path() const;
+
     std::string access_kregistry_path() const;
 
+    std::string pstore_path() const;
+
     std::string console_path() const;
 
     std::string logcat_path() const;
 
     std::string kernel_log_pipe_name() const;
 
-    std::string console_pipe_name() const;
+    std::string console_pipe_prefix() const;
+    std::string console_in_pipe_name() const;
+    std::string console_out_pipe_name() const;
+
+    std::string gnss_pipe_prefix() const;
+    std::string gnss_in_pipe_name() const;
+    std::string gnss_out_pipe_name() const;
+
+    std::string logcat_pipe_name() const;
 
     std::string launcher_log_path() const;
 
@@ -332,8 +430,32 @@
 
     std::string sdcard_path() const;
 
+    std::string os_composite_disk_path() const;
+
+    std::string persistent_composite_disk_path() const;
+
+    std::string uboot_env_image_path() const;
+
+    std::string vendor_boot_image_path() const;
+
+    std::string audio_server_path() const;
+
+    // modem simulator related
+    std::string modem_simulator_ports() const;
+
+    // The device id the webrtc process should use to register with the
+    // signaling server
+    std::string webrtc_device_id() const;
+
+    // Whether this instance should start the webrtc signaling server
+    bool start_webrtc_sig_server() const;
+
     // Wifi MAC address inside the guest
     std::array<unsigned char, 6> wifi_mac_address() const;
+
+    std::string factory_reset_protected_path() const;
+
+    std::string persistent_bootconfig_path() const;
   };
 
   // A view into an existing CuttlefishConfig object for a particular instance.
@@ -349,19 +471,44 @@
   public:
     void set_serial_number(const std::string& serial_number);
     void set_vnc_server_port(int vnc_server_port);
+    void set_tombstone_receiver_port(int tombstone_receiver_port);
+    void set_config_server_port(int config_server_port);
+    void set_frames_server_port(int config_server_port);
+    void set_touch_server_port(int config_server_port);
+    void set_keyboard_server_port(int config_server_port);
+    void set_gatekeeper_vsock_port(int gatekeeper_vsock_port);
+    void set_keymaster_vsock_port(int keymaster_vsock_port);
     void set_vehicle_hal_server_port(int vehicle_server_port);
+    void set_audiocontrol_server_port(int audiocontrol_server_port);
     void set_host_port(int host_port);
     void set_adb_ip_and_port(const std::string& ip_port);
+    void set_rootcanal_hci_port(int rootcanal_hci_port);
+    void set_rootcanal_link_port(int rootcanal_link_port);
+    void set_rootcanal_test_port(int rootcanal_test_port);
+    void set_rootcanal_config_file(const std::string& rootcanal_config_file);
+    void set_rootcanal_default_commands_file(
+        const std::string& rootcanal_default_commands_file);
     void set_device_title(const std::string& title);
     void set_mobile_bridge_name(const std::string& mobile_bridge_name);
     void set_mobile_tap_name(const std::string& mobile_tap_name);
     void set_wifi_tap_name(const std::string& wifi_tap_name);
+    void set_ethernet_tap_name(const std::string& ethernet_tap_name);
+    void set_session_id(uint32_t session_id);
+    void set_use_allocd(bool use_allocd);
     void set_vsock_guest_cid(int vsock_guest_cid);
     void set_uuid(const std::string& uuid);
     void set_instance_dir(const std::string& instance_dir);
+    // modem simulator related
+    void set_modem_simulator_ports(const std::string& modem_simulator_ports);
     void set_virtual_disk_paths(const std::vector<std::string>& disk_paths);
+    void set_webrtc_device_id(const std::string& id);
+    void set_start_webrtc_signaling_server(bool start);
     // Wifi MAC address inside the guest
     void set_wifi_mac_address(const std::array<unsigned char, 6>&);
+    // Gnss grpc proxy server port inside the host
+    void set_gnss_grpc_proxy_server_port(int gnss_grpc_proxy_server_port);
+    // Gnss grpc proxy local file path
+    void set_gnss_file_path(const std::string &gnss_file_path);
   };
 
  private:
@@ -378,6 +525,16 @@
 // Returns the instance number as obtained from the CUTTLEFISH_INSTANCE
 // environment variable or the username.
 int GetInstance();
+
+// Returns default Vsock CID, which is
+// GetInstance() + 2
+int GetDefaultVsockCid();
+
+// Calculates vsock server port number
+// return base + (vsock_guest_cid - 3)
+int GetVsockServerPort(const int base,
+                       const int vsock_guest_cid);
+
 // Returns a path where the launhcer puts a link to the config file which makes
 // it easily discoverable regardless of what vm manager is in use
 std::string GetGlobalConfigFileLink();
@@ -388,14 +545,11 @@
 std::string ForCurrentInstance(const char* prefix);
 int ForCurrentInstance(int base);
 
-// Returns a random serial number appended to a given prefix.
+// Returns a random serial number appeneded to a given prefix.
 std::string RandomSerialNumber(const std::string& prefix);
 
-std::string GetDefaultPerInstanceDir();
-std::string GetDefaultMempath();
-int GetDefaultPerInstanceVsockCid();
-
 std::string DefaultHostArtifactsPath(const std::string& file);
+std::string HostBinaryPath(const std::string& file);
 std::string DefaultGuestImagePath(const std::string& file);
 std::string DefaultEnvironmentPath(const char* environment_key,
                                    const char* default_value,
@@ -403,10 +557,10 @@
 
 // Whether the host supports qemu
 bool HostSupportsQemuCli();
-bool HostSupportsVsock();
 
 // GPU modes
+extern const char* const kGpuModeAuto;
 extern const char* const kGpuModeGuestSwiftshader;
 extern const char* const kGpuModeDrmVirgl;
 extern const char* const kGpuModeGfxStream;
-}  // namespace vsoc
+}  // namespace cuttlefish
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
new file mode 100644
index 0000000..97b3503
--- /dev/null
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "host/libs/config/cuttlefish_config.h"
+
+#include <android-base/logging.h>
+#include <json/json.h>
+
+#include "common/libs/utils/files.h"
+
+namespace cuttlefish {
+namespace {
+
+const char* kInstances = "instances";
+
+}  // namespace
+
+Json::Value* CuttlefishConfig::MutableInstanceSpecific::Dictionary() {
+  return &(*config_->dictionary_)[kInstances][id_];
+}
+
+const Json::Value* CuttlefishConfig::InstanceSpecific::Dictionary() const {
+  return &(*config_->dictionary_)[kInstances][id_];
+}
+
+static constexpr char kInstanceDir[] = "instance_dir";
+std::string CuttlefishConfig::InstanceSpecific::instance_dir() const {
+  return (*Dictionary())[kInstanceDir].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_instance_dir(
+    const std::string& instance_dir) {
+  (*Dictionary())[kInstanceDir] = instance_dir;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::instance_internal_dir() const {
+  return PerInstancePath(kInternalDirName);
+}
+
+static constexpr char kSerialNumber[] = "serial_number";
+std::string CuttlefishConfig::InstanceSpecific::serial_number() const {
+  return (*Dictionary())[kSerialNumber].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_serial_number(
+    const std::string& serial_number) {
+  (*Dictionary())[kSerialNumber] = serial_number;
+}
+
+static constexpr char kVirtualDiskPaths[] = "virtual_disk_paths";
+std::vector<std::string> CuttlefishConfig::InstanceSpecific::virtual_disk_paths() const {
+  std::vector<std::string> virtual_disks;
+  auto virtual_disks_json_obj = (*Dictionary())[kVirtualDiskPaths];
+  for (const auto& disk : virtual_disks_json_obj) {
+    virtual_disks.push_back(disk.asString());
+  }
+  return virtual_disks;
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_virtual_disk_paths(
+    const std::vector<std::string>& virtual_disk_paths) {
+  Json::Value virtual_disks_json_obj(Json::arrayValue);
+  for (const auto& arg : virtual_disk_paths) {
+    virtual_disks_json_obj.append(arg);
+  }
+  (*Dictionary())[kVirtualDiskPaths] = virtual_disks_json_obj;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::kernel_log_pipe_name() const {
+  return AbsolutePath(PerInstanceInternalPath("kernel-log-pipe"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::console_pipe_prefix() const {
+  return AbsolutePath(PerInstanceInternalPath("console"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::console_in_pipe_name() const {
+  return console_pipe_prefix() + ".in";
+}
+
+std::string CuttlefishConfig::InstanceSpecific::console_out_pipe_name() const {
+  return console_pipe_prefix() + ".out";
+}
+
+std::string CuttlefishConfig::InstanceSpecific::gnss_pipe_prefix() const {
+  return AbsolutePath(PerInstanceInternalPath("gnss"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::gnss_in_pipe_name() const {
+  return gnss_pipe_prefix() + ".in";
+}
+
+std::string CuttlefishConfig::InstanceSpecific::gnss_out_pipe_name() const {
+  return gnss_pipe_prefix() + ".out";
+}
+
+static constexpr char kGnssGrpcProxyServerPort[] =
+    "gnss_grpc_proxy_server_port";
+int CuttlefishConfig::InstanceSpecific::gnss_grpc_proxy_server_port() const {
+  return (*Dictionary())[kGnssGrpcProxyServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_gnss_grpc_proxy_server_port(
+    int gnss_grpc_proxy_server_port) {
+  (*Dictionary())[kGnssGrpcProxyServerPort] = gnss_grpc_proxy_server_port;
+}
+
+static constexpr char kGnssFilePath[] = "gnss_file_path";
+std::string CuttlefishConfig::InstanceSpecific::gnss_file_path() const {
+  return (*Dictionary())[kGnssFilePath].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_gnss_file_path(
+  const std::string& gnss_file_path) {
+  (*Dictionary())[kGnssFilePath] = gnss_file_path;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::logcat_pipe_name() const {
+  return AbsolutePath(PerInstanceInternalPath("logcat-pipe"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::access_kregistry_path() const {
+  return AbsolutePath(PerInstancePath("access-kregistry"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::pstore_path() const {
+  return AbsolutePath(PerInstancePath("pstore"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::console_path() const {
+  return AbsolutePath(PerInstancePath("console"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::logcat_path() const {
+  return AbsolutePath(PerInstancePath("logcat"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::launcher_monitor_socket_path()
+    const {
+  return AbsolutePath(PerInstancePath("launcher_monitor.sock"));
+}
+
+static constexpr char kModemSimulatorPorts[] = "modem_simulator_ports";
+std::string CuttlefishConfig::InstanceSpecific::modem_simulator_ports() const {
+  return (*Dictionary())[kModemSimulatorPorts].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_modem_simulator_ports(
+    const std::string& modem_simulator_ports) {
+  (*Dictionary())[kModemSimulatorPorts] = modem_simulator_ports;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::launcher_log_path() const {
+  return AbsolutePath(PerInstancePath("launcher.log"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::sdcard_path() const {
+  return AbsolutePath(PerInstancePath("sdcard.img"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::os_composite_disk_path() const {
+  return AbsolutePath(PerInstancePath("os_composite.img"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::persistent_composite_disk_path()
+    const {
+  return AbsolutePath(PerInstancePath("persistent_composite.img"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::uboot_env_image_path() const {
+  return AbsolutePath(PerInstancePath("uboot_env.img"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::vendor_boot_image_path() const {
+  return AbsolutePath(PerInstancePath("vendor_boot_repacked.img"));
+}
+
+static constexpr char kMobileBridgeName[] = "mobile_bridge_name";
+
+std::string CuttlefishConfig::InstanceSpecific::audio_server_path() const {
+  return AbsolutePath(PerInstanceInternalPath("audio_server.sock"));
+}
+
+std::string CuttlefishConfig::InstanceSpecific::mobile_bridge_name() const {
+  return (*Dictionary())[kMobileBridgeName].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_mobile_bridge_name(
+    const std::string& mobile_bridge_name) {
+  (*Dictionary())[kMobileBridgeName] = mobile_bridge_name;
+}
+
+static constexpr char kMobileTapName[] = "mobile_tap_name";
+std::string CuttlefishConfig::InstanceSpecific::mobile_tap_name() const {
+  return (*Dictionary())[kMobileTapName].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_mobile_tap_name(
+    const std::string& mobile_tap_name) {
+  (*Dictionary())[kMobileTapName] = mobile_tap_name;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::confui_hal_guest_socket_path()
+    const {
+  return PerInstanceInternalPath("confui_mock_hal_guest.sock");
+}
+
+static constexpr char kWifiTapName[] = "wifi_tap_name";
+std::string CuttlefishConfig::InstanceSpecific::wifi_tap_name() const {
+  return (*Dictionary())[kWifiTapName].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_wifi_tap_name(
+    const std::string& wifi_tap_name) {
+  (*Dictionary())[kWifiTapName] = wifi_tap_name;
+}
+
+static constexpr char kEthernetTapName[] = "ethernet_tap_name";
+std::string CuttlefishConfig::InstanceSpecific::ethernet_tap_name() const {
+  return (*Dictionary())[kEthernetTapName].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_ethernet_tap_name(
+    const std::string& ethernet_tap_name) {
+  (*Dictionary())[kEthernetTapName] = ethernet_tap_name;
+}
+
+static constexpr char kUseAllocd[] = "use_allocd";
+bool CuttlefishConfig::InstanceSpecific::use_allocd() const {
+  return (*Dictionary())[kUseAllocd].asBool();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_use_allocd(
+    bool use_allocd) {
+  (*Dictionary())[kUseAllocd] = use_allocd;
+}
+
+static constexpr char kSessionId[] = "session_id";
+uint32_t CuttlefishConfig::InstanceSpecific::session_id() const {
+  return (*Dictionary())[kSessionId].asUInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_session_id(
+    uint32_t session_id) {
+  (*Dictionary())[kSessionId] = session_id;
+}
+
+static constexpr char kVsockGuestCid[] = "vsock_guest_cid";
+int CuttlefishConfig::InstanceSpecific::vsock_guest_cid() const {
+  return (*Dictionary())[kVsockGuestCid].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_vsock_guest_cid(
+    int vsock_guest_cid) {
+  (*Dictionary())[kVsockGuestCid] = vsock_guest_cid;
+}
+
+static constexpr char kUuid[] = "uuid";
+std::string CuttlefishConfig::InstanceSpecific::uuid() const {
+  return (*Dictionary())[kUuid].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_uuid(const std::string& uuid) {
+  (*Dictionary())[kUuid] = uuid;
+}
+
+static constexpr char kHostPort[] = "host_port";
+int CuttlefishConfig::InstanceSpecific::host_port() const {
+  return (*Dictionary())[kHostPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_host_port(int host_port) {
+  (*Dictionary())[kHostPort] = host_port;
+}
+
+static constexpr char kAdbIPAndPort[] = "adb_ip_and_port";
+std::string CuttlefishConfig::InstanceSpecific::adb_ip_and_port() const {
+  return (*Dictionary())[kAdbIPAndPort].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_adb_ip_and_port(
+    const std::string& ip_port) {
+  (*Dictionary())[kAdbIPAndPort] = ip_port;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::adb_device_name() const {
+  if (adb_ip_and_port() != "") {
+    return adb_ip_and_port();
+  }
+  LOG(ERROR) << "no adb_mode found, returning bad device name";
+  return "NO_ADB_MODE_SET_NO_VALID_DEVICE_NAME";
+}
+
+static constexpr char kDeviceTitle[] = "device_title";
+std::string CuttlefishConfig::InstanceSpecific::device_title() const {
+  return (*Dictionary())[kDeviceTitle].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_device_title(
+    const std::string& title) {
+  (*Dictionary())[kDeviceTitle] = title;
+}
+
+static constexpr char kVncServerPort[] = "vnc_server_port";
+int CuttlefishConfig::InstanceSpecific::vnc_server_port() const {
+  return (*Dictionary())[kVncServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_vnc_server_port(int vnc_server_port) {
+  (*Dictionary())[kVncServerPort] = vnc_server_port;
+}
+
+static constexpr char kFramesServerPort[] = "frames_server_port";
+int CuttlefishConfig::InstanceSpecific::frames_server_port() const {
+  return (*Dictionary())[kFramesServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_frames_server_port(int frames_server_port) {
+  (*Dictionary())[kFramesServerPort] = frames_server_port;
+}
+
+static constexpr char kTouchServerPort[] = "touch_server_port";
+int CuttlefishConfig::InstanceSpecific::touch_server_port() const {
+  return (*Dictionary())[kTouchServerPort].asInt();
+}
+
+void CuttlefishConfig::MutableInstanceSpecific::set_touch_server_port(int touch_server_port) {
+  (*Dictionary())[kTouchServerPort] = touch_server_port;
+}
+
+static constexpr char kKeyboardServerPort[] = "keyboard_server_port";
+int CuttlefishConfig::InstanceSpecific::keyboard_server_port() const {
+  return (*Dictionary())[kKeyboardServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_keyboard_server_port(int keyboard_server_port) {
+  (*Dictionary())[kKeyboardServerPort] = keyboard_server_port;
+}
+
+static constexpr char kTombstoneReceiverPort[] = "tombstone_receiver_port";
+int CuttlefishConfig::InstanceSpecific::tombstone_receiver_port() const {
+  return (*Dictionary())[kTombstoneReceiverPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_tombstone_receiver_port(int tombstone_receiver_port) {
+  (*Dictionary())[kTombstoneReceiverPort] = tombstone_receiver_port;
+}
+
+static constexpr char kVehicleHalServerPort[] = "vehicle_hal_server_port";
+int CuttlefishConfig::InstanceSpecific::vehicle_hal_server_port() const {
+  return (*Dictionary())[kVehicleHalServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_vehicle_hal_server_port(int vehicle_hal_server_port) {
+  (*Dictionary())[kVehicleHalServerPort] = vehicle_hal_server_port;
+}
+
+static constexpr char kAudioControlServerPort[] = "audiocontrol_server_port";
+int CuttlefishConfig::InstanceSpecific::audiocontrol_server_port() const {
+  return (*Dictionary())[kAudioControlServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_audiocontrol_server_port(int audiocontrol_server_port) {
+  (*Dictionary())[kAudioControlServerPort] = audiocontrol_server_port;
+}
+
+static constexpr char kConfigServerPort[] = "config_server_port";
+int CuttlefishConfig::InstanceSpecific::config_server_port() const {
+  return (*Dictionary())[kConfigServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_config_server_port(int config_server_port) {
+  (*Dictionary())[kConfigServerPort] = config_server_port;
+}
+
+static constexpr char kRootcanalHciPort[] = "rootcanal_hci_port";
+int CuttlefishConfig::InstanceSpecific::rootcanal_hci_port() const {
+  return (*Dictionary())[kRootcanalHciPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_rootcanal_hci_port(
+    int rootcanal_hci_port) {
+  (*Dictionary())[kRootcanalHciPort] = rootcanal_hci_port;
+}
+
+static constexpr char kRootcanalLinkPort[] = "rootcanal_link_port";
+int CuttlefishConfig::InstanceSpecific::rootcanal_link_port() const {
+  return (*Dictionary())[kRootcanalLinkPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_rootcanal_link_port(
+    int rootcanal_link_port) {
+  (*Dictionary())[kRootcanalLinkPort] = rootcanal_link_port;
+}
+
+static constexpr char kRootcanalTestPort[] = "rootcanal_test_port";
+int CuttlefishConfig::InstanceSpecific::rootcanal_test_port() const {
+  return (*Dictionary())[kRootcanalTestPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_rootcanal_test_port(
+    int rootcanal_test_port) {
+  (*Dictionary())[kRootcanalTestPort] = rootcanal_test_port;
+}
+
+static constexpr char kRootcanalConfigFile[] = "rootcanal_config_file";
+std::string CuttlefishConfig::InstanceSpecific::rootcanal_config_file() const {
+  return (*Dictionary())[kRootcanalConfigFile].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_rootcanal_config_file(
+    const std::string& rootcanal_config_file) {
+  (*Dictionary())[kRootcanalConfigFile] =
+      DefaultHostArtifactsPath(rootcanal_config_file);
+}
+
+static constexpr char kRootcanalDefaultCommandsFile[] =
+    "rootcanal_default_commands_file";
+std::string
+CuttlefishConfig::InstanceSpecific::rootcanal_default_commands_file() const {
+  return (*Dictionary())[kRootcanalDefaultCommandsFile].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::
+    set_rootcanal_default_commands_file(
+        const std::string& rootcanal_default_commands_file) {
+  (*Dictionary())[kRootcanalDefaultCommandsFile] =
+      DefaultHostArtifactsPath(rootcanal_default_commands_file);
+}
+
+static constexpr char kWebrtcDeviceId[] = "webrtc_device_id";
+void CuttlefishConfig::MutableInstanceSpecific::set_webrtc_device_id(
+    const std::string& id) {
+  (*Dictionary())[kWebrtcDeviceId] = id;
+}
+std::string CuttlefishConfig::InstanceSpecific::webrtc_device_id() const {
+  return (*Dictionary())[kWebrtcDeviceId].asString();
+}
+
+static constexpr char kStartSigServer[] = "webrtc_start_sig_server";
+void CuttlefishConfig::MutableInstanceSpecific::set_start_webrtc_signaling_server(bool start) {
+  (*Dictionary())[kStartSigServer] = start;
+}
+bool CuttlefishConfig::InstanceSpecific::start_webrtc_sig_server() const {
+  return (*Dictionary())[kStartSigServer].asBool();
+}
+
+std::string CuttlefishConfig::InstanceSpecific::touch_socket_path() const {
+  return PerInstanceInternalPath("touch.sock");
+}
+
+std::string CuttlefishConfig::InstanceSpecific::keyboard_socket_path() const {
+  return PerInstanceInternalPath("keyboard.sock");
+}
+
+std::string CuttlefishConfig::InstanceSpecific::switches_socket_path() const {
+  return PerInstanceInternalPath("switches.sock");
+}
+
+std::string CuttlefishConfig::InstanceSpecific::frames_socket_path() const {
+  return PerInstanceInternalPath("frames.sock");
+}
+
+static constexpr char kWifiMacAddress[] = "wifi_mac_address";
+void CuttlefishConfig::MutableInstanceSpecific::set_wifi_mac_address(
+    const std::array<unsigned char, 6>& mac_address) {
+  Json::Value mac_address_obj(Json::arrayValue);
+  for (const auto& num : mac_address) {
+    mac_address_obj.append(num);
+  }
+  (*Dictionary())[kWifiMacAddress] = mac_address_obj;
+}
+std::array<unsigned char, 6> CuttlefishConfig::InstanceSpecific::wifi_mac_address() const {
+  std::array<unsigned char, 6> mac_address{0, 0, 0, 0, 0, 0};
+  auto mac_address_obj = (*Dictionary())[kWifiMacAddress];
+  if (mac_address_obj.size() != 6) {
+    LOG(ERROR) << kWifiMacAddress << " entry had wrong size";
+    return {};
+  }
+  for (int i = 0; i < 6; i++) {
+    mac_address[i] = mac_address_obj[i].asInt();
+  }
+  return mac_address;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::factory_reset_protected_path() const {
+  return PerInstanceInternalPath("factory_reset_protected.img");
+}
+
+std::string CuttlefishConfig::InstanceSpecific::persistent_bootconfig_path()
+    const {
+  return PerInstanceInternalPath("bootconfig");
+}
+
+std::string CuttlefishConfig::InstanceSpecific::PerInstancePath(
+    const char* file_name) const {
+  return (instance_dir() + "/") + file_name;
+}
+
+std::string CuttlefishConfig::InstanceSpecific::PerInstanceInternalPath(
+    const char* file_name) const {
+  if (file_name[0] == '\0') {
+    // Don't append a / if file_name is empty.
+    return PerInstancePath(kInternalDirName);
+  }
+  auto relative_path = (std::string(kInternalDirName) + "/") + file_name;
+  return PerInstancePath(relative_path.c_str());
+}
+
+std::string CuttlefishConfig::InstanceSpecific::instance_name() const {
+  return "cvd-" + id_;
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/config/data_image.cpp b/host/libs/config/data_image.cpp
new file mode 100644
index 0000000..044dadb
--- /dev/null
+++ b/host/libs/config/data_image.cpp
@@ -0,0 +1,203 @@
+#include "host/libs/config/data_image.h"
+
+#include <android-base/logging.h>
+
+#include "common/libs/fs/shared_buf.h"
+
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/subprocess.h"
+
+#include "host/libs/config/mbr.h"
+
+namespace cuttlefish {
+
+namespace {
+const std::string kDataPolicyUseExisting = "use_existing";
+const std::string kDataPolicyCreateIfMissing = "create_if_missing";
+const std::string kDataPolicyAlwaysCreate = "always_create";
+const std::string kDataPolicyResizeUpTo= "resize_up_to";
+
+const int FSCK_ERROR_CORRECTED = 1;
+const int FSCK_ERROR_CORRECTED_REQUIRES_REBOOT = 2;
+
+bool ForceFsckImage(const char* data_image) {
+  auto fsck_path = HostBinaryPath("fsck.f2fs");
+  int fsck_status = execute({fsck_path, "-y", "-f", data_image});
+  if (fsck_status & ~(FSCK_ERROR_CORRECTED|FSCK_ERROR_CORRECTED_REQUIRES_REBOOT)) {
+    LOG(ERROR) << "`fsck.f2fs -y -f " << data_image << "` failed with code "
+               << fsck_status;
+    return false;
+  }
+  return true;
+}
+
+bool ResizeImage(const char* data_image, int data_image_mb) {
+  auto file_mb = FileSize(data_image) >> 20;
+  if (file_mb > data_image_mb) {
+    LOG(ERROR) << data_image << " is already " << file_mb << " MB, will not "
+               << "resize down.";
+    return false;
+  } else if (file_mb == data_image_mb) {
+    LOG(INFO) << data_image << " is already the right size";
+    return true;
+  } else {
+    off_t raw_target = static_cast<off_t>(data_image_mb) << 20;
+    auto fd = SharedFD::Open(data_image, O_RDWR);
+    if (fd->Truncate(raw_target) != 0) {
+      LOG(ERROR) << "`truncate --size=" << data_image_mb << "M "
+                  << data_image << "` failed:" << fd->StrError();
+      return false;
+    }
+    bool fsck_success = ForceFsckImage(data_image);
+    if (!fsck_success) {
+      return false;
+    }
+    auto resize_path = HostBinaryPath("resize.f2fs");
+    int resize_status = execute({resize_path, data_image});
+    if (resize_status != 0) {
+      LOG(ERROR) << "`resize.f2fs " << data_image << "` failed with code "
+                 << resize_status;
+      return false;
+    }
+    fsck_success = ForceFsckImage(data_image);
+    if (!fsck_success) {
+      return false;
+    }
+  }
+  return true;
+}
+} // namespace
+
+void CreateBlankImage(
+    const std::string& image, int num_mb, const std::string& image_fmt) {
+  LOG(DEBUG) << "Creating " << image;
+
+  off_t image_size_bytes = static_cast<off_t>(num_mb) << 20;
+  // The newfs_msdos tool with the mandatory -C option will do the same
+  // as below to zero the image file, so we don't need to do it here
+  if (image_fmt != "sdcard") {
+    auto fd = SharedFD::Open(image, O_CREAT | O_TRUNC | O_RDWR, 0666);
+    if (fd->Truncate(image_size_bytes) != 0) {
+      LOG(ERROR) << "`truncate --size=" << num_mb << "M " << image
+                 << "` failed:" << fd->StrError();
+      return;
+    }
+  }
+
+  if (image_fmt == "ext4") {
+    execute({"/sbin/mkfs.ext4", image});
+  } else if (image_fmt == "f2fs") {
+    auto make_f2fs_path = cuttlefish::HostBinaryPath("make_f2fs");
+    execute({make_f2fs_path, "-t", image_fmt, image, "-C", "utf8", "-O",
+             "compression,extra_attr,prjquota", "-g", "android"});
+  } else if (image_fmt == "sdcard") {
+    // Reserve 1MB in the image for the MBR and padding, to simulate what
+    // other OSes do by default when partitioning a drive
+    off_t offset_size_bytes = 1 << 20;
+    image_size_bytes -= offset_size_bytes;
+    off_t image_size_sectors = image_size_bytes / 512;
+    auto newfs_msdos_path = HostBinaryPath("newfs_msdos");
+    execute({newfs_msdos_path, "-F", "32", "-m", "0xf8", "-a", "4088",
+                               "-o", "0",  "-c", "8",    "-h", "255",
+                               "-u", "63", "-S", "512",
+                               "-s", std::to_string(image_size_sectors),
+                               "-C", std::to_string(num_mb) + "M",
+                               "-@", std::to_string(offset_size_bytes),
+                               image});
+    // Write the MBR after the filesystem is formatted, as the formatting tools
+    // don't consistently preserve the image contents
+    MasterBootRecord mbr = {
+      .partitions = {{
+        .partition_type = 0xC,
+        .first_lba = (std::uint32_t) offset_size_bytes / SECTOR_SIZE,
+        .num_sectors = (std::uint32_t) image_size_bytes / SECTOR_SIZE,
+      }},
+      .boot_signature = { 0x55, 0xAA },
+    };
+    auto fd = SharedFD::Open(image, O_RDWR);
+    if (WriteAllBinary(fd, &mbr) != sizeof(MasterBootRecord)) {
+      LOG(ERROR) << "Writing MBR to " << image << " failed:" << fd->StrError();
+      return;
+    }
+  } else if (image_fmt != "none") {
+    LOG(WARNING) << "Unknown image format '" << image_fmt
+                 << "' for " << image << ", treating as 'none'.";
+  }
+}
+
+DataImageResult ApplyDataImagePolicy(const CuttlefishConfig& config,
+                                     const std::string& data_image) {
+  bool data_exists = FileHasContent(data_image.c_str());
+  bool remove{};
+  bool create{};
+  bool resize{};
+
+  if (config.data_policy() == kDataPolicyUseExisting) {
+    if (!data_exists) {
+      LOG(ERROR) << "Specified data image file does not exists: " << data_image;
+      return DataImageResult::Error;
+    }
+    if (config.blank_data_image_mb() > 0) {
+      LOG(ERROR) << "You should NOT use -blank_data_image_mb with -data_policy="
+                 << kDataPolicyUseExisting;
+      return DataImageResult::Error;
+    }
+    create = false;
+    remove = false;
+    resize = false;
+  } else if (config.data_policy() == kDataPolicyAlwaysCreate) {
+    remove = data_exists;
+    create = true;
+    resize = false;
+  } else if (config.data_policy() == kDataPolicyCreateIfMissing) {
+    create = !data_exists;
+    remove = false;
+    resize = false;
+  } else if (config.data_policy() == kDataPolicyResizeUpTo) {
+    create = false;
+    remove = false;
+    resize = true;
+  } else {
+    LOG(ERROR) << "Invalid data_policy: " << config.data_policy();
+    return DataImageResult::Error;
+  }
+
+  if (remove) {
+    RemoveFile(data_image.c_str());
+  }
+
+  if (create) {
+    if (config.blank_data_image_mb() <= 0) {
+      LOG(ERROR) << "-blank_data_image_mb is required to create data image";
+      return DataImageResult::Error;
+    }
+    CreateBlankImage(data_image.c_str(), config.blank_data_image_mb(),
+                     config.blank_data_image_fmt());
+    return DataImageResult::FileUpdated;
+  } else if (resize) {
+    if (!data_exists) {
+      LOG(ERROR) << data_image << " does not exist, but resizing was requested";
+      return DataImageResult::Error;
+    }
+    bool success = ResizeImage(data_image.c_str(), config.blank_data_image_mb());
+    return success ? DataImageResult::FileUpdated : DataImageResult::Error;
+  } else {
+    LOG(DEBUG) << data_image << " exists. Not creating it.";
+    return DataImageResult::NoChange;
+  }
+}
+
+bool InitializeMiscImage(const std::string& misc_image) {
+  bool misc_exists = FileHasContent(misc_image.c_str());
+
+  if (misc_exists) {
+    LOG(DEBUG) << "misc partition image: use existing";
+    return true;
+  }
+
+  LOG(DEBUG) << "misc partition image: creating empty";
+  CreateBlankImage(misc_image, 1 /* mb */, "none");
+  return true;
+}
+
+} // namespace cuttlefish
diff --git a/host/libs/config/data_image.h b/host/libs/config/data_image.h
new file mode 100644
index 0000000..6a6a810
--- /dev/null
+++ b/host/libs/config/data_image.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <string>
+
+#include "host/libs/config/cuttlefish_config.h"
+
+namespace cuttlefish {
+
+enum class DataImageResult {
+  Error,
+  NoChange,
+  FileUpdated,
+};
+
+DataImageResult ApplyDataImagePolicy(const CuttlefishConfig& config,
+                                     const std::string& path);
+bool InitializeMiscImage(const std::string& misc_image);
+void CreateBlankImage(
+    const std::string& image, int num_mb, const std::string& image_fmt);
+
+} // namespace cuttlefish
diff --git a/host/libs/config/fetcher_config.cpp b/host/libs/config/fetcher_config.cpp
index 86e16dc..e58c378 100644
--- a/host/libs/config/fetcher_config.cpp
+++ b/host/libs/config/fetcher_config.cpp
@@ -21,13 +21,14 @@
 #include <string>
 #include <vector>
 
-#include <gflags/gflags.h>
-#include <glog/logging.h>
-#include <json/json.h>
+#include "android-base/logging.h"
+#include "android-base/strings.h"
+#include "gflags/gflags.h"
+#include "json/json.h"
 
 #include "common/libs/utils/files.h"
 
-namespace cvd {
+namespace cuttlefish {
 
 namespace {
 
@@ -110,16 +111,16 @@
 }
 
 bool FetcherConfig::LoadFromFile(const std::string& file) {
-  auto real_file_path = cvd::AbsolutePath(file);
+  auto real_file_path = AbsolutePath(file);
   if (real_file_path.empty()) {
     LOG(ERROR) << "Could not get real path for file " << file;
     return false;
   }
-  Json::Reader reader;
+  Json::CharReaderBuilder builder;
   std::ifstream ifs(real_file_path);
-  if (!reader.parse(ifs, *dictionary_)) {
-    LOG(ERROR) << "Could not read config file " << file << ": "
-               << reader.getFormattedErrorMessages();
+  std::string errorMessage;
+  if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
+    LOG(ERROR) << "Could not read config file " << file << ": " << errorMessage;
     return false;
   }
   return true;
@@ -203,14 +204,13 @@
   }
   const auto& json_files = (*dictionary_)[kCvdFiles];
   for (auto it = json_files.begin(); it != json_files.end(); it++) {
-    auto file = it.key().asString();
-    auto expected_pos = file.size() - suffix.size();
-    if (file.rfind(suffix) == expected_pos) {
+    const auto& file = it.key().asString();
+    if (android::base::EndsWith(file, suffix)) {
       return file;
     }
   }
-  LOG(ERROR) << "Could not find file ending in " << suffix;
+  LOG(DEBUG) << "Could not find file ending in " << suffix;
   return "";
 }
 
-} // namespace cvd
+} // namespace cuttlefish
diff --git a/host/libs/config/fetcher_config.h b/host/libs/config/fetcher_config.h
index 825fbc6..c15134c 100644
--- a/host/libs/config/fetcher_config.h
+++ b/host/libs/config/fetcher_config.h
@@ -23,7 +23,7 @@
 class Value;
 }
 
-namespace cvd {
+namespace cuttlefish {
 
 // Order in enum is not guaranteed to be stable, serialized as a string.
 enum FileSource {
@@ -33,6 +33,7 @@
   KERNEL_BUILD,
   LOCAL_FILE,
   GENERATED,
+  BOOTLOADER_BUILD,
 };
 
 /*
@@ -82,4 +83,4 @@
   std::string FindCvdFileWithSuffix(const std::string& suffix) const;
 };
 
-} // namespace cvd
+} // namespace cuttlefish
diff --git a/host/libs/config/host_tools_version.cpp b/host/libs/config/host_tools_version.cpp
new file mode 100644
index 0000000..58f0657
--- /dev/null
+++ b/host/libs/config/host_tools_version.cpp
@@ -0,0 +1,82 @@
+//
+// 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.
+
+#include "host/libs/config/host_tools_version.h"
+
+#include <algorithm>
+#include <fstream>
+#include <future>
+#include <vector>
+
+#include <zlib.h>
+
+#include "common/libs/utils/files.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+using std::uint32_t;
+
+namespace cuttlefish {
+
+static uint32_t FileCrc(const std::string& path) {
+  uint32_t crc = crc32(0, (unsigned char*) path.c_str(), path.size());
+  std::ifstream file_stream(path, std::ifstream::binary);
+  std::vector<char> data(1024, 0);
+  while (file_stream) {
+    file_stream.read(data.data(), data.size());
+    crc = crc32(crc, (unsigned char*) data.data(), file_stream.gcount());
+  }
+  return crc;
+}
+
+static std::map<std::string, uint32_t> DirectoryCrc(const std::string& path) {
+  auto full_path = DefaultHostArtifactsPath(path);
+  if (!DirectoryExists(full_path)) {
+    return {};
+  }
+  std::vector<std::string> files = DirectoryContents(full_path);
+  for (auto it = files.begin(); it != files.end();) {
+    if (*it == "." || *it == "..") {
+      it = files.erase(it);
+    } else {
+      it++;
+    }
+  }
+  std::vector<std::future<uint32_t>> calculations;
+  for (auto& file : files) {
+    file = path + "/" + file; // mutate in place in files vector
+    calculations.emplace_back(
+        std::async(FileCrc, DefaultHostArtifactsPath(file)));
+  }
+  std::map<std::string, uint32_t> crcs;
+  for (int i = 0; i < files.size(); i++) {
+    crcs[files[i]] = calculations[i].get();
+  }
+  return crcs;
+}
+
+std::map<std::string, uint32_t> HostToolsCrc() {
+  auto bin_future = std::async(DirectoryCrc, "bin");
+  auto lib_future = std::async(DirectoryCrc, "lib64");
+  std::map<std::string, uint32_t> all_crcs;
+  for (auto const& [file, crc] : bin_future.get()) {
+    all_crcs[file] = crc;
+  }
+  for (auto const& [file, crc] : lib_future.get()) {
+    all_crcs[file] = crc;
+  }
+  return all_crcs;
+}
+
+} // namespace cuttlefish
diff --git a/host/libs/config/host_tools_version.h b/host/libs/config/host_tools_version.h
new file mode 100644
index 0000000..06b075e
--- /dev/null
+++ b/host/libs/config/host_tools_version.h
@@ -0,0 +1,26 @@
+//
+// 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 <cstdint>
+#include <map>
+#include <string>
+
+namespace cuttlefish {
+
+std::map<std::string, uint32_t> HostToolsCrc();
+
+} // namespace cuttlefish
diff --git a/host/libs/config/kernel_args.cpp b/host/libs/config/kernel_args.cpp
new file mode 100644
index 0000000..421950a
--- /dev/null
+++ b/host/libs/config/kernel_args.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "host/libs/config/kernel_args.h"
+
+#include <array>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "common/libs/utils/environment.h"
+#include "common/libs/utils/files.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/vm_manager/qemu_manager.h"
+#include "host/libs/vm_manager/vm_manager.h"
+
+namespace cuttlefish {
+
+using vm_manager::QemuManager;
+
+namespace {
+
+template<typename T>
+void AppendVector(std::vector<T>* destination, const std::vector<T>& source) {
+  destination->insert(destination->end(), source.begin(), source.end());
+}
+
+// TODO(schuffelen): Move more of this into host/libs/vm_manager, as a
+// substitute for the vm_manager comparisons.
+std::vector<std::string> VmManagerKernelCmdline(const CuttlefishConfig& config) {
+  std::vector<std::string> vm_manager_cmdline;
+  if (config.vm_manager() == QemuManager::name() || config.use_bootloader()) {
+    // crosvm sets up the console= earlycon= panic= flags for us if booting straight to
+    // the kernel, but QEMU and the bootloader via crosvm does not.
+    AppendVector(&vm_manager_cmdline, {"console=hvc0", "panic=-1"});
+    Arch target_arch = config.target_arch();
+    if (target_arch == Arch::Arm64 || target_arch == Arch::Arm) {
+      if (config.vm_manager() == QemuManager::name()) {
+        // To update the pl011 address:
+        // $ qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine dumpdtb=virt.dtb
+        // $ dtc -O dts -o virt.dts -I dtb virt.dtb
+        // In the virt.dts file, look for a uart node
+        vm_manager_cmdline.push_back(" earlycon=pl011,mmio32,0x9000000");
+      } else {
+        // Crosvm ARM only supports earlycon uart over mmio.
+        vm_manager_cmdline.push_back(" earlycon=uart8250,mmio,0x3f8");
+      }
+    } else {
+      // To update the uart8250 address:
+      // $ qemu-system-x86_64 -kernel bzImage -serial stdio | grep ttyS0
+      // Only 'io' mode works; mmio and mmio32 do not
+      vm_manager_cmdline.push_back("earlycon=uart8250,io,0x3f8");
+
+      if (config.vm_manager() == QemuManager::name()) {
+        // crosvm doesn't support ACPI PNP, but QEMU does. We need to disable
+        // it on QEMU so that the ISA serial ports aren't claimed by ACPI, so
+        // we can use serdev with platform devices instead
+        vm_manager_cmdline.push_back("pnpacpi=off");
+
+        // crosvm sets up the ramoops.xx= flags for us, but QEMU does not.
+        // See external/crosvm/x86_64/src/lib.rs
+        // this feature is not supported on aarch64
+        vm_manager_cmdline.push_back("ramoops.mem_address=0x100000000");
+        vm_manager_cmdline.push_back("ramoops.mem_size=0x200000");
+        vm_manager_cmdline.push_back("ramoops.console_size=0x80000");
+        vm_manager_cmdline.push_back("ramoops.record_size=0x80000");
+        vm_manager_cmdline.push_back("ramoops.dump_oops=1");
+      } else {
+        // crosvm requires these additional parameters on x86_64 in bootloader mode
+        AppendVector(&vm_manager_cmdline, {"pci=noacpi", "reboot=k"});
+      }
+    }
+  }
+
+  if (config.console() && config.kgdb()) {
+    AppendVector(&vm_manager_cmdline, {"kgdboc_earlycon", "kgdbcon",
+                                       "kgdboc=" + config.console_dev()});
+  }
+  return vm_manager_cmdline;
+}
+
+} // namespace
+
+std::vector<std::string> KernelCommandLineFromConfig(
+    const CuttlefishConfig& config) {
+  std::vector<std::string> kernel_cmdline;
+
+  AppendVector(&kernel_cmdline, VmManagerKernelCmdline(config));
+
+  if (config.enable_gnss_grpc_proxy()) {
+    kernel_cmdline.push_back("gnss_cmdline.serdev=serial8250/serial0/serial0-0");
+    kernel_cmdline.push_back("gnss_cmdline.type=0");
+    kernel_cmdline.push_back("serdev_ttyport.pdev_tty_port=ttyS1");
+  }
+
+  if (config.guest_audit_security()) {
+    kernel_cmdline.push_back("audit=1");
+  } else {
+    kernel_cmdline.push_back("audit=0");
+  }
+
+  AppendVector(&kernel_cmdline, config.extra_kernel_cmdline());
+
+  return kernel_cmdline;
+}
+
+} // namespace cuttlefish
diff --git a/host/libs/config/kernel_args.h b/host/libs/config/kernel_args.h
new file mode 100644
index 0000000..59b9e8e
--- /dev/null
+++ b/host/libs/config/kernel_args.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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>
+#include <vector>
+
+#include "host/libs/config/cuttlefish_config.h"
+
+namespace cuttlefish {
+
+std::vector<std::string> KernelCommandLineFromConfig(
+    const CuttlefishConfig& config);
+
+} // namespace cuttlefish
diff --git a/host/libs/config/known_paths.cpp b/host/libs/config/known_paths.cpp
new file mode 100644
index 0000000..1581a06
--- /dev/null
+++ b/host/libs/config/known_paths.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include "host/libs/config/known_paths.h"
+
+#include "host/libs/config/cuttlefish_config.h"
+
+namespace cuttlefish {
+
+std::string AdbConnectorBinary() {
+  return HostBinaryPath("adb_connector");
+}
+
+std::string ConfigServerBinary() {
+  return HostBinaryPath("config_server");
+}
+
+std::string ConsoleForwarderBinary() {
+  return HostBinaryPath("console_forwarder");
+}
+
+std::string GnssGrpcProxyBinary() {
+  return HostBinaryPath("gnss_grpc_proxy");
+}
+
+std::string KernelLogMonitorBinary() {
+  return HostBinaryPath("kernel_log_monitor");
+}
+
+std::string LogcatReceiverBinary() {
+  return HostBinaryPath("logcat_receiver");
+}
+
+std::string MetricsBinary() {
+  return HostBinaryPath("metrics");
+}
+
+std::string ModemSimulatorBinary() {
+  return HostBinaryPath("modem_simulator");
+}
+
+std::string RootCanalBinary() {
+  return DefaultHostArtifactsPath("bin/root-canal");
+}
+
+std::string SocketVsockProxyBinary() {
+  return HostBinaryPath("socket_vsock_proxy");
+}
+
+std::string TombstoneReceiverBinary() {
+  return HostBinaryPath("tombstone_receiver");
+}
+
+std::string WebRtcBinary() {
+  return HostBinaryPath("webRTC");
+}
+
+std::string WebRtcSigServerBinary() {
+  return HostBinaryPath("webrtc_operator");
+}
+
+std::string VncServerBinary() {
+  return HostBinaryPath("vnc_server");
+}
+
+} // namespace cuttlefish
diff --git a/host/libs/config/known_paths.h b/host/libs/config/known_paths.h
new file mode 100644
index 0000000..71b6253
--- /dev/null
+++ b/host/libs/config/known_paths.h
@@ -0,0 +1,37 @@
+/*
+ * 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 cuttlefish {
+
+std::string AdbConnectorBinary();
+std::string ConfigServerBinary();
+std::string ConsoleForwarderBinary();
+std::string GnssGrpcProxyBinary();
+std::string KernelLogMonitorBinary();
+std::string LogcatReceiverBinary();
+std::string MetricsBinary();
+std::string ModemSimulatorBinary();
+std::string RootCanalBinary();
+std::string SocketVsockProxyBinary();
+std::string TombstoneReceiverBinary();
+std::string WebRtcBinary();
+std::string WebRtcSigServerBinary();
+std::string VncServerBinary();
+
+} // namespace cuttlefish
diff --git a/host/libs/config/logging.cpp b/host/libs/config/logging.cpp
new file mode 100644
index 0000000..50a14f8
--- /dev/null
+++ b/host/libs/config/logging.cpp
@@ -0,0 +1,43 @@
+//
+// 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.
+
+#include "logging.h"
+
+#include <android-base/logging.h>
+
+#include "common/libs/utils/tee_logging.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+using android::base::SetLogger;
+
+namespace cuttlefish {
+
+void DefaultSubprocessLogging(char* argv[]) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+
+  auto config = CuttlefishConfig::Get();
+
+  CHECK(config) << "Could not open cuttlefish config";
+
+  auto instance = config->ForDefaultInstance();
+
+  if (config->run_as_daemon()) {
+    SetLogger(LogToFiles({instance.launcher_log_path()}));
+  } else {
+    SetLogger(LogToStderrAndFiles({instance.launcher_log_path()}));
+  }
+}
+
+} // namespace cuttlefish
diff --git a/host/libs/config/logging.h b/host/libs/config/logging.h
new file mode 100644
index 0000000..5d57c6f
--- /dev/null
+++ b/host/libs/config/logging.h
@@ -0,0 +1,22 @@
+//
+// 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
+
+namespace cuttlefish {
+
+void DefaultSubprocessLogging(char* argv[]);
+
+} // namespace cuttlefish
diff --git a/host/libs/config/mbr.h b/host/libs/config/mbr.h
new file mode 100644
index 0000000..3388237
--- /dev/null
+++ b/host/libs/config/mbr.h
@@ -0,0 +1,36 @@
+/*
+ * 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
+
+constexpr int SECTOR_SIZE_SHIFT = 9;
+constexpr int SECTOR_SIZE = 1 << SECTOR_SIZE_SHIFT;
+
+struct __attribute__((packed)) MbrPartitionEntry {
+  std::uint8_t status;
+  std::uint8_t begin_chs[3];
+  std::uint8_t partition_type;
+  std::uint8_t end_chs[3];
+  std::uint32_t first_lba;
+  std::uint32_t num_sectors;
+};
+
+struct __attribute__((packed)) MasterBootRecord {
+  std::uint8_t bootstrap_code[446];
+  MbrPartitionEntry partitions[4];
+  std::uint8_t boot_signature[2];
+};
+
+static_assert(sizeof(MasterBootRecord) == SECTOR_SIZE);
diff --git a/host/libs/confui/Android.bp b/host/libs/confui/Android.bp
new file mode 100644
index 0000000..b74eb24
--- /dev/null
+++ b/host/libs/confui/Android.bp
@@ -0,0 +1,61 @@
+//
+// Copyright (C) 2021 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.
+
+// copied from cuttlefish top level Android.bp, cuttlefish_common_headers
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_headers {
+    name: "libcuttlefish_confui_host_headers",
+    vendor_available: true,
+    product_available: true,
+    host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
+}
+
+cc_library_static {
+    name: "libcuttlefish_confui_host",
+    srcs: [
+        "host_renderer.cc",
+        "host_server.cc",
+        "host_utils.cc",
+        "server_common.cc",
+        "session.cc",
+        "fonts.S",
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libbase",
+        "libjsoncpp",
+        "liblog",
+    ],
+    header_libs: [
+        "libcuttlefish_confui_host_headers",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libcuttlefish_utils",
+        "libcuttlefish_confui",
+        "libcuttlefish_wayland_server",
+        "libft2.nodep",
+        "libteeui",
+        "libteeui_localization",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/libs/confui/Roboto-Medium.ttf b/host/libs/confui/Roboto-Medium.ttf
new file mode 100644
index 0000000..1a7f3b0
--- /dev/null
+++ b/host/libs/confui/Roboto-Medium.ttf
Binary files differ
diff --git a/host/libs/confui/Roboto-Regular.ttf b/host/libs/confui/Roboto-Regular.ttf
new file mode 100644
index 0000000..2c97eea
--- /dev/null
+++ b/host/libs/confui/Roboto-Regular.ttf
Binary files differ
diff --git a/host/libs/confui/Shield.ttf b/host/libs/confui/Shield.ttf
new file mode 100644
index 0000000..a2f5e33
--- /dev/null
+++ b/host/libs/confui/Shield.ttf
Binary files differ
diff --git a/host/libs/confui/fonts.S b/host/libs/confui/fonts.S
new file mode 100644
index 0000000..5a134df
--- /dev/null
+++ b/host/libs/confui/fonts.S
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#include <teeui/incfont.h>
+
+TEEUI_INCFONT(RobotoMedium, "Roboto-Medium.ttf");
+TEEUI_INCFONT(RobotoRegular, "Roboto-Regular.ttf");
+TEEUI_INCFONT(Shield, "Shield.ttf");
diff --git a/host/libs/confui/host_mode_ctrl.h b/host/libs/confui/host_mode_ctrl.h
new file mode 100644
index 0000000..7cf991c
--- /dev/null
+++ b/host/libs/confui/host_mode_ctrl.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 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 <atomic>
+#include <condition_variable>
+#include <cstdint>
+#include <functional>
+#include <mutex>
+
+#include "common/libs/confui/confui.h"
+#include "host/libs/confui/host_utils.h"
+
+namespace cuttlefish {
+/**
+ * mechanism to orchestrate concurrent executions of threads
+ * that work for screen connector
+ *
+ * Within VNC or WebRTC service, it tells when it is now in the Android Mode or
+ * Confirmation UI mode
+ */
+class HostModeCtrl {
+ public:
+  enum class ModeType : std::uint8_t { kAndroidMode = 55, kConfUI_Mode = 77 };
+
+  /**
+   * The thread that enqueues Android frames will call this to wait until
+   * the mode is kAndroidMode
+   *
+   * Logically, using atomic_mode_ alone is not sufficient. Using mutex alone
+   * is logically complete but slow.
+   *
+   * Note that most of the time, the mode is kAndroidMode. Also, note that
+   * this method is called at every single frame.
+   *
+   * As an optimization, we check atomic_mode_ first. If failed, we wait for
+   * kAndroidMode with mutex-based lock
+   *
+   * The actual synchronization is not at the and_mode_cv_.wait line but at
+   * this line:
+   *     if (atomic_mode_ == ModeType::kAndroidMode) {
+   *
+   * This trick reduces the flag checking delays by 70+% on a Gentoo based
+   * amd64 desktop, with Linux 5.10
+   */
+  void WaitAndroidMode() {
+    ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName()
+                     << "checking atomic Android mode";
+    if (atomic_mode_ == ModeType::kAndroidMode) {
+      ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName()
+                       << "returns as it is already Android mode";
+      return;
+    }
+    auto check = [this]() -> bool {
+      return atomic_mode_ == ModeType::kAndroidMode;
+    };
+    std::unique_lock<std::mutex> lock(mode_mtx_);
+    and_mode_cv_.wait(lock, check);
+    ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName()
+                     << "awakes from cond var waiting for Android mode";
+  }
+
+  void SetMode(const ModeType mode) {
+    ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName()
+                     << "tries to acquire the lock in SetMode";
+    std::lock_guard<std::mutex> lock(mode_mtx_);
+    ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName()
+                     << "acquired the lock in SetMode";
+    atomic_mode_ = mode;
+    if (atomic_mode_ == ModeType::kAndroidMode) {
+      ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName()
+                       << "signals kAndroidMode in SetMode";
+      and_mode_cv_.notify_all();
+      return;
+    }
+    ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName()
+                     << "signals kConfUI_Mode in SetMode";
+    confui_mode_cv_.notify_all();
+  }
+
+  auto GetMode() {
+    ModeType ret_val = atomic_mode_;
+    return ret_val;
+  }
+
+  auto IsConfirmatioUiMode() {
+    return (atomic_mode_ == ModeType::kConfUI_Mode);
+  }
+
+  auto IsAndroidMode() { return (atomic_mode_ == ModeType::kAndroidMode); }
+
+  static HostModeCtrl& Get() {
+    static HostModeCtrl host_mode_controller;
+    return host_mode_controller;
+  }
+
+ private:
+  HostModeCtrl() : atomic_mode_(ModeType::kAndroidMode) {}
+  std::mutex mode_mtx_;
+  std::condition_variable and_mode_cv_;
+  std::condition_variable confui_mode_cv_;
+  std::atomic<ModeType> atomic_mode_;
+};
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/host_renderer.cc b/host/libs/confui/host_renderer.cc
new file mode 100644
index 0000000..f3e0c52
--- /dev/null
+++ b/host/libs/confui/host_renderer.cc
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/libs/confui/host_renderer.h"
+
+namespace cuttlefish {
+namespace confui {
+static teeui::Color alfaCombineChannel(std::uint32_t shift, double alfa,
+                                       teeui::Color a, teeui::Color b) {
+  a >>= shift;
+  a &= 0xff;
+  b >>= shift;
+  b &= 0xff;
+  double acc = alfa * a + (1 - alfa) * b;
+  if (acc <= 0) return 0;
+  std::uint32_t result = acc;
+  if (result > 255) return 255 << shift;
+  return result << shift;
+}
+
+ConfUiRenderer::ConfUiRenderer(const std::uint32_t display)
+    : display_num_(display),
+      lang_id_{"en"},
+      prompt_("Am I Yumi Meow?"),
+      current_height_(ScreenConnectorInfo::ScreenHeight(display_num_)),
+      current_width_(ScreenConnectorInfo::ScreenWidth(display_num_)),
+      color_bg_{kColorBackground},
+      color_text_{kColorDisabled},
+      shield_color_{kColorShield},
+      is_inverted_{false},
+      ctx_{GetDeviceContext()} {
+  auto opted_frame = RepaintRawFrame(prompt_, lang_id_);
+  if (opted_frame) {
+    raw_frame_ = std::move(opted_frame.value());
+  }
+}
+
+void ConfUiRenderer::SetConfUiMessage(const std::string& msg) {
+  prompt_ = msg;
+  SetText<LabelConfMsg>(msg);
+}
+
+teeui::Error ConfUiRenderer::SetLangId(const std::string& lang_id) {
+  using teeui::Error;
+  lang_id_ = lang_id;
+  teeui::localization::selectLangId(lang_id_.c_str());
+  if (auto error = UpdateTranslations()) {
+    return error;
+  }
+  return Error::OK;
+}
+
+teeui::Error ConfUiRenderer::UpdateTranslations() {
+  using namespace teeui;
+  if (auto error = UpdateString<LabelOK>()) {
+    return error;
+  }
+  if (auto error = UpdateString<LabelOK>()) {
+    return error;
+  }
+  if (auto error = UpdateString<LabelCancel>()) {
+    return error;
+  }
+  if (auto error = UpdateString<LabelTitle>()) {
+    return error;
+  }
+  if (auto error = UpdateString<LabelHint>()) {
+    return error;
+  }
+  return Error::OK;
+}
+
+teeui::context<teeui::ConUIParameters> ConfUiRenderer::GetDeviceContext() {
+  using namespace teeui;
+  const unsigned long long w = ScreenConnectorInfo::ScreenWidth(display_num_);
+  const unsigned long long h = ScreenConnectorInfo::ScreenHeight(display_num_);
+  const auto screen_width = operator""_px(w);
+  const auto screen_height = operator""_px(h);
+  context<teeui::ConUIParameters> ctx(6.45211, 400.0 / 412.0);
+  ctx.setParam<RightEdgeOfScreen>(screen_width);
+  ctx.setParam<BottomOfScreen>(screen_height);
+  ctx.setParam<PowerButtonTop>(20.26_mm);
+  ctx.setParam<PowerButtonBottom>(30.26_mm);
+  ctx.setParam<VolUpButtonTop>(40.26_mm);
+  ctx.setParam<VolUpButtonBottom>(50.26_mm);
+  ctx.setParam<DefaultFontSize>(14_dp);
+  ctx.setParam<BodyFontSize>(16_dp);
+  return ctx;
+}
+
+bool ConfUiRenderer::InitLayout(const std::string& lang_id) {
+  layout_ = teeui::instantiateLayout(teeui::ConfUILayout(), ctx_);
+  SetLangId(lang_id);
+  if (auto error = UpdateTranslations()) {
+    ConfUiLog(ERROR) << "Update Translation Error";
+    return false;
+  }
+  UpdateColorScheme(&ctx_);
+  return true;
+}
+
+teeui::Error ConfUiRenderer::UpdatePixels(TeeUiFrame& raw_frame,
+                                          std::uint32_t x, std::uint32_t y,
+                                          teeui::Color color) {
+  auto buffer = raw_frame.data();
+  const auto height = ScreenConnectorInfo::ScreenHeight(display_num_);
+  const auto width = ScreenConnectorInfo::ScreenWidth(display_num_);
+  auto pos = width * y + x;
+  if (pos >= (height * width)) {
+    ConfUiLog(ERROR) << "Rendering Out of Bound";
+    return teeui::Error::OutOfBoundsDrawing;
+  }
+  const double alfa = ((color & 0xff000000) >> 24) / 255.0;
+  auto& pixel = *reinterpret_cast<teeui::Color*>(buffer + pos);
+  pixel = alfaCombineChannel(0, alfa, color, pixel) |
+          alfaCombineChannel(8, alfa, color, pixel) |
+          alfaCombineChannel(16, alfa, color, pixel);
+  return teeui::Error::OK;
+}
+
+std::tuple<TeeUiFrame&, bool> ConfUiRenderer::RenderRawFrame(
+    const std::string& confirmation_msg, const std::string& lang_id) {
+  /* we repaint only if one or more of the followng meet:
+   *
+   *  1. raw_frame_ is empty
+   *  2. the current_width_ and current_height_ is out of date
+   *  3. lang_id is different (e.g. new locale)
+   *
+   *  in the future, maybe you wanna inverted, new background, etc?
+   */
+  if (lang_id != lang_id_ || !IsFrameReady() ||
+      current_height_ != ScreenConnectorInfo::ScreenHeight(display_num_) ||
+      current_width_ != ScreenConnectorInfo::ScreenWidth(display_num_)) {
+    auto opted_new_frame = RepaintRawFrame(confirmation_msg, lang_id_);
+    if (opted_new_frame) {
+      // repainting from the scratch successful in a new frame
+      raw_frame_ = std::move(opted_new_frame.value());
+      return {raw_frame_, true};
+    }
+    // repaint failed even if it was necessary, so returns invalid values
+    raw_frame_.clear();
+    return {raw_frame_, false};
+  }
+  // no need to repaint from the scratch. repaint the confirmation message only
+  // the frame is mostly already in raw_frame_
+  auto ret_code = RenderConfirmationMsgOnly(confirmation_msg);
+  return {raw_frame_, (ret_code == teeui::Error::OK)};
+}
+
+std::optional<TeeUiFrame> ConfUiRenderer::RepaintRawFrame(
+    const std::string& confirmation_msg, const std::string& lang_id) {
+  /*
+   * NOTE: DON'T use current_width_/height_ to create this frame
+   * it may fail, and then we must not mess up the current_width_, height_
+   *
+   */
+  if (!InitLayout(lang_id)) {
+    return std::nullopt;
+  }
+  SetConfUiMessage(confirmation_msg);
+  auto color = kColorEnabled;
+  std::get<teeui::LabelOK>(layout_).setTextColor(color);
+  std::get<teeui::LabelCancel>(layout_).setTextColor(color);
+
+  /* in the future, if ever we need to register a handler for the
+     Label{OK,Cancel}. do this: std::get<teeui::LabelOK>(layout_)
+     .setCB(teeui::makeCallback<teeui::Error, teeui::Event>(
+     [](teeui::Event e, void* p) -> teeui::Error {
+     LOG(DEBUG) << "Calling callback for Confirm?";
+     return reinterpret_cast<decltype(owner)*>(p)->TapOk(e); },
+     owner));
+  */
+  // we manually check if click happened, where if yes, and generate the label
+  // event manually. So we won't register the handler here.
+  /**
+   * should be uint32_t for teeui APIs.
+   * It assumes that each raw frame buffer element is 4 bytes
+   */
+  TeeUiFrame new_raw_frame(
+      ScreenConnectorInfo::ScreenSizeInBytes(display_num_) / 4,
+      kColorBackground);
+
+  auto draw_pixel = teeui::makePixelDrawer(
+      [this, &new_raw_frame](std::uint32_t x, std::uint32_t y,
+                             teeui::Color color) -> teeui::Error {
+        return this->UpdatePixels(new_raw_frame, x, y, color);
+      });
+
+  // render all components
+  const auto error = drawElements(layout_, draw_pixel);
+  if (error) {
+    ConfUiLog(ERROR) << "Painting failed: " << error.code();
+    return std::nullopt;
+  }
+
+  // set current frame's dimension as frame generation was successful
+  current_height_ = ScreenConnectorInfo::ScreenHeight(display_num_);
+  current_width_ = ScreenConnectorInfo::ScreenWidth(display_num_);
+
+  return {new_raw_frame};
+}
+
+teeui::Error ConfUiRenderer::RenderConfirmationMsgOnly(
+    const std::string& confirmation_msg) {
+  // repaint labelbody on the raw_frame__ only
+  auto callback_func = [this](std::uint32_t x, std::uint32_t y,
+                              teeui::Color color) -> teeui::Error {
+    return UpdatePixels(raw_frame_, x, y, color);
+  };
+  auto draw_pixel = teeui::makePixelDrawer(callback_func);
+  LabelConfMsg& label = std::get<LabelConfMsg>(layout_);
+  auto b = GetBoundary(label);
+  for (std::uint32_t i = 0; i != b.w; i++) {
+    const auto col_index = i + b.x - 1;
+    for (std::uint32_t j = 0; j != b.y; j++) {
+      const auto row_index = (j + b.y - 1);
+      raw_frame_[current_width_ * row_index + col_index] = color_bg_;
+    }
+  }
+
+  SetConfUiMessage(confirmation_msg);
+  ConfUiLog(DEBUG) << "Repaint Confirmation Msg with :" << prompt_;
+  if (auto error = std::get<LabelConfMsg>(layout_).draw(draw_pixel)) {
+    ConfUiLog(ERROR) << "Repainting Confirmation Message Label failed:"
+                     << error.code();
+    return error;
+  }
+  return teeui::Error::OK;
+}
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/host_renderer.h b/host/libs/confui/host_renderer.h
new file mode 100644
index 0000000..c614109
--- /dev/null
+++ b/host/libs/confui/host_renderer.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 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 <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include <freetype/ftglyph.h>  // $(croot)/external/freetype
+#include <teeui/utils.h>       // $(croot)/system/teeui/libteeui/.../include
+
+#include "common/libs/confui/confui.h"
+#include "host/libs/confui/layouts/layout.h"
+#include "host/libs/confui/server_common.h"
+#include "host/libs/screen_connector/screen_connector.h"
+
+namespace cuttlefish {
+namespace confui {
+
+/**
+ * create a raw frame for confirmation UI dialog
+ */
+class ConfUiRenderer {
+ public:
+  using LabelConfMsg = teeui::LabelBody;
+
+  ConfUiRenderer(const std::uint32_t display);
+
+  /**
+   * this does not repaint from the scratch all the time
+   *
+   * Unless repainting the whole thing is needed, it remove the message
+   * label, and re-draw there. There seems yet no fancy way of doing this.
+   * Thus, it repaint the background color on the top of the label, and
+   * draw the label on the new background
+   *
+   * As HostRenderer is intended to be shared across sessions, HostRender
+   * owns the buffer, and returns reference to the buffer. Note that no
+   * 2 or more sessions are concurrently executed. Only 1 or 0 is active
+   * at the given moment.
+   */
+  std::tuple<TeeUiFrame&, bool> RenderRawFrame(
+      const std::string& confirmation_msg, const std::string& lang_id = "en");
+
+  bool IsFrameReady() const { return !raw_frame_.empty(); }
+
+ private:
+  struct Boundary {            // inclusive but.. LayoutElement's size is float
+    std::uint32_t x, y, w, h;  // (x, y) is the top left
+  };
+
+  template <typename LayoutElement>
+  Boundary GetBoundary(LayoutElement&& e) {
+    auto box = e.bounds_;
+    Boundary b;
+    // (x,y) is left top. so floor() makes sense
+    // w, h are witdh and height in float. perhaps ceiling makes more
+    // sense
+    b.x = static_cast<std::uint32_t>(box.x().floor().count());
+    b.y = static_cast<std::uint32_t>(box.y().floor().count());
+    b.w = static_cast<std::uint32_t>(box.w().ceil().count());
+    b.h = static_cast<std::uint32_t>(box.h().ceil().count());
+    return b;
+  }
+
+  // essentially, to repaint from the scratch, so returns new frame
+  // when successful. Or, nullopt
+  std::optional<TeeUiFrame> RepaintRawFrame(const std::string& confirmation_msg,
+                                            const std::string& lang_id = "en");
+
+  bool InitLayout(const std::string& lang_id);
+  teeui::Error UpdateTranslations();
+  /**
+   * could be confusing. update prompt_, and update the text_ in the Label
+   * object, the GUI components. This does not render immediately. And..
+   * to render it, we must clean up the existing dirty pixels, which
+   * this method does not do.
+   */
+  void SetConfUiMessage(const std::string& s);
+  teeui::Error SetLangId(const std::string& lang_id);
+  teeui::context<teeui::ConUIParameters> GetDeviceContext();
+
+  // effectively, will be send to teeui as a callback function
+  teeui::Error UpdatePixels(TeeUiFrame& buffer, std::uint32_t x,
+                            std::uint32_t y, teeui::Color color);
+
+  // from Trusty
+  // second param is for type deduction
+  template <typename... Elements>
+  static teeui::Error drawElements(std::tuple<Elements...>& layout,
+                                   const teeui::PixelDrawer& drawPixel) {
+    // Error::operator|| is overloaded, so we don't get short circuit
+    // evaluation. But we get the first error that occurs. We will still try and
+    // draw the remaining elements in the order they appear in the layout tuple.
+    return (std::get<Elements>(layout).draw(drawPixel) || ...);
+  }
+
+  // repaint the confirmation UI label only
+  teeui::Error RenderConfirmationMsgOnly(const std::string& confirmation_msg);
+
+  // from Trusty
+  template <typename Context>
+  void UpdateColorScheme(Context* ctx) {
+    using namespace teeui;
+    color_text_ = is_inverted_ ? kColorDisabledInv : kColorDisabled;
+    shield_color_ = is_inverted_ ? kColorShieldInv : kColorShield;
+    color_bg_ = is_inverted_ ? kColorBackgroundInv : kColorBackground;
+
+    ctx->template setParam<ShieldColor>(shield_color_);
+    ctx->template setParam<ColorText>(color_text_);
+    ctx->template setParam<ColorBG>(color_bg_);
+    return;
+  }
+
+  template <typename Label>
+  auto SetText(const std::string& text) {
+    return std::get<Label>(layout_).setText(
+        {text.c_str(), text.c_str() + text.size()});
+  }
+
+  /**
+   * source:
+   * https://android.googlesource.com/trusty/app/confirmationui/+/0429cc7/src/trusty_confirmation_ui.cpp#49
+   */
+  template <typename Label>
+  teeui::Error UpdateString() {
+    using namespace teeui;
+    const char* str;
+    auto& label = std::get<Label>(layout_);
+    str = localization::lookup(TranslationId(label.textId()));
+    if (str == nullptr) {
+      ConfUiLog(ERROR) << "Given translation_id" << label.textId()
+                       << "not found";
+      return Error::Localization;
+    }
+    label.setText({str, str + strlen(str)});
+    return Error::OK;
+  }
+
+  const int display_num_;
+  teeui::layout_t<teeui::ConfUILayout> layout_;
+  std::string lang_id_;
+  std::string prompt_;  // confirmation ui message
+  TeeUiFrame raw_frame_;
+  std::uint32_t current_height_;
+  std::uint32_t current_width_;
+  teeui::Color color_bg_;
+  teeui::Color color_text_;
+  teeui::Color shield_color_;
+  bool is_inverted_;
+  teeui::context<teeui::ConUIParameters> ctx_;
+
+  static constexpr const teeui::Color kColorEnabled = 0xff212121;
+  static constexpr const teeui::Color kColorDisabled = 0xffbdbdbd;
+  static constexpr const teeui::Color kColorEnabledInv = 0xffdedede;
+  static constexpr const teeui::Color kColorDisabledInv = 0xff424242;
+  static constexpr const teeui::Color kColorBackground = 0xffffffff;
+  static constexpr const teeui::Color kColorBackgroundInv = 0xff212121;
+  static constexpr const teeui::Color kColorShieldInv = 0xffc4cb80;
+  static constexpr const teeui::Color kColorShield = 0xff778500;
+};
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/host_server.cc b/host/libs/confui/host_server.cc
new file mode 100644
index 0000000..c14e0ed
--- /dev/null
+++ b/host/libs/confui/host_server.cc
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/libs/confui/host_server.h"
+
+#include <chrono>
+#include <functional>
+#include <optional>
+#include <tuple>
+
+#include "common/libs/confui/confui.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/confui/host_utils.h"
+
+namespace cuttlefish {
+namespace confui {
+static auto CuttlefishConfigDefaultInstance() {
+  auto config = cuttlefish::CuttlefishConfig::Get();
+  CHECK(config) << "Config must not be null";
+  return config->ForDefaultInstance();
+}
+
+static std::string HalGuestSocketPath() {
+  return CuttlefishConfigDefaultInstance().confui_hal_guest_socket_path();
+}
+
+HostServer& HostServer::Get(
+    HostModeCtrl& host_mode_ctrl,
+    cuttlefish::ScreenConnectorFrameRenderer& screen_connector) {
+  static HostServer host_server{host_mode_ctrl, screen_connector};
+  return host_server;
+}
+
+HostServer::HostServer(
+    cuttlefish::HostModeCtrl& host_mode_ctrl,
+    cuttlefish::ScreenConnectorFrameRenderer& screen_connector)
+    : display_num_(0),
+      host_mode_ctrl_(host_mode_ctrl),
+      screen_connector_{screen_connector},
+      renderer_(display_num_),
+      hal_socket_path_(HalGuestSocketPath()),
+      input_multiplexer_{/* max n_elems */ 20, /* n_Qs */ 2} {
+  hal_cmd_q_id_ = input_multiplexer_.GetNewQueueId();         // return 0
+  user_input_evt_q_id_ = input_multiplexer_.GetNewQueueId();  // return 1
+}
+
+void HostServer::Start() {
+  guest_hal_socket_ = cuttlefish::SharedFD::SocketLocalServer(
+      hal_socket_path_, false, SOCK_STREAM, 0666);
+  if (!guest_hal_socket_->IsOpen()) {
+    ConfUiLog(FATAL) << "Confirmation UI host service mandates a server socket"
+                     << "to which the guest HAL to connect.";
+    return;
+  }
+  auto hal_cmd_fetching = [this]() { this->HalCmdFetcherLoop(); };
+  auto main = [this]() { this->MainLoop(); };
+  hal_input_fetcher_thread_ =
+      thread::RunThread("HalInputLoop", hal_cmd_fetching);
+  main_loop_thread_ = thread::RunThread("MainLoop", main);
+  ConfUiLog(DEBUG) << "configured internal socket based input.";
+  return;
+}
+
+void HostServer::HalCmdFetcherLoop() {
+  hal_cli_socket_ = EstablishHalConnection();
+  if (!hal_cli_socket_->IsOpen()) {
+    ConfUiLog(FATAL)
+        << "Confirmation UI host service mandates connection with HAL.";
+    return;
+  }
+  while (true) {
+    auto opted_msg = RecvConfUiMsg(hal_cli_socket_);
+    if (!opted_msg) {
+      ConfUiLog(ERROR) << "Error in RecvConfUiMsg from HAL";
+      continue;
+    }
+    auto input = std::move(opted_msg.value());
+    input_multiplexer_.Push(hal_cmd_q_id_, std::move(input));
+  }
+}
+
+bool HostServer::SendUserSelection(UserResponse::type selection) {
+  if (!curr_session_) {
+    ConfUiLog(FATAL) << "Current session must not be null";
+    return false;
+  }
+  if (curr_session_->GetState() != MainLoopState::kInSession) {
+    // ignore
+    return true;
+  }
+
+  std::lock_guard<std::mutex> lock(input_socket_mtx_);
+  if (selection != UserResponse::kConfirm &&
+      selection != UserResponse::kCancel) {
+    ConfUiLog(FATAL) << selection << " must be either" << UserResponse::kConfirm
+                     << "or" << UserResponse::kCancel;
+    return false;  // not reaching here
+  }
+
+  ConfUiMessage input{GetCurrentSessionId(),
+                      ToString(ConfUiCmd::kUserInputEvent), selection};
+
+  input_multiplexer_.Push(user_input_evt_q_id_, std::move(input));
+  return true;
+}
+
+void HostServer::PressConfirmButton(const bool is_down) {
+  if (!is_down) {
+    return;
+  }
+  // shared by N vnc/webRTC clients
+  SendUserSelection(UserResponse::kConfirm);
+}
+
+void HostServer::PressCancelButton(const bool is_down) {
+  if (!is_down) {
+    return;
+  }
+  // shared by N vnc/webRTC clients
+  SendUserSelection(UserResponse::kCancel);
+}
+
+bool HostServer::IsConfUiActive() {
+  if (!curr_session_) {
+    return false;
+  }
+  return curr_session_->IsConfUiActive();
+}
+
+SharedFD HostServer::EstablishHalConnection() {
+  ConfUiLog(DEBUG) << "Waiting hal accepting";
+  auto new_cli = SharedFD::Accept(*guest_hal_socket_);
+  ConfUiLog(DEBUG) << "hal client accepted";
+  return new_cli;
+}
+
+std::unique_ptr<Session> HostServer::ComputeCurrentSession(
+    const std::string& session_id) {
+  if (curr_session_ && (GetCurrentSessionId() != session_id)) {
+    ConfUiLog(FATAL) << curr_session_->GetId() << " is active and in the"
+                     << GetCurrentState() << "but HAL sends command to"
+                     << session_id;
+  }
+  if (curr_session_) {
+    return std::move(curr_session_);
+  }
+
+  // pick up a new session, or create one
+  auto result = GetSession(session_id);
+  if (result) {
+    return std::move(result);
+  }
+
+  auto raw_ptr = new Session(session_id, display_num_, renderer_,
+                             host_mode_ctrl_, screen_connector_);
+  result = std::unique_ptr<Session>(raw_ptr);
+  // note that the new session is directly going to curr_session_
+  // when it is suspended, it will be moved to session_map_
+  return std::move(result);
+}
+
+// read the comments in the header file
+[[noreturn]] void HostServer::MainLoop() {
+  while (true) {
+    // this gets one input from either queue:
+    // from HAL or from all webrtc/vnc clients
+    // if no input, sleep until there is
+    const auto input = input_multiplexer_.Pop();
+    const auto& [session_id, cmd_str, additional_info] = input;
+
+    // take input for the Finite States Machine below
+    const ConfUiCmd cmd = ToCmd(cmd_str);
+    const bool is_user_input = (cmd == ConfUiCmd::kUserInputEvent);
+    std::string src = is_user_input ? "input" : "hal";
+
+    ConfUiLog(DEBUG) << "In Session" << GetCurrentSessionId() << ","
+                     << "in state" << GetCurrentState() << ","
+                     << "received input from" << src << "cmd =" << cmd_str
+                     << "and additional_info =" << additional_info
+                     << "going to session" << session_id;
+
+    FsmInput fsm_input = ToFsmInput(input);
+
+    if (is_user_input && !curr_session_) {
+      // discard the input, there's no session to take it yet
+      // actually, no confirmation UI screen is available
+      ConfUiLog(DEBUG) << "Took user input but no active session is available.";
+      continue;
+    }
+
+    /**
+     * if the curr_session_ is null, create one
+     * if the curr_session_ is not null but the session id doesn't match,
+     * something is wrong. Confirmation UI doesn't allow preemption by
+     * another confirmation UI session back to back. When it's preempted,
+     * HAL must send "kSuspend"
+     *
+     */
+    curr_session_ = ComputeCurrentSession(session_id);
+    ConfUiLog(DEBUG) << "Host service picked up "
+                     << (curr_session_ ? curr_session_->GetId()
+                                       : "null session");
+    ConfUiLog(DEBUG) << "The state of current session is "
+                     << (curr_session_ ? ToString(curr_session_->GetState())
+                                       : "null session");
+
+    if (is_user_input) {
+      curr_session_->Transition(is_user_input, hal_cli_socket_, fsm_input,
+                                additional_info);
+    } else {
+      ConfUiCmd cmd = ToCmd(cmd_str);
+      switch (cmd) {
+        case ConfUiCmd::kSuspend:
+          curr_session_->Suspend(hal_cli_socket_);
+          break;
+        case ConfUiCmd::kRestore:
+          curr_session_->Restore(hal_cli_socket_);
+          break;
+        case ConfUiCmd::kAbort:
+          curr_session_->Abort(hal_cli_socket_);
+          break;
+        default:
+          curr_session_->Transition(is_user_input, hal_cli_socket_, fsm_input,
+                                    additional_info);
+          break;
+      }
+    }
+
+    // check the session if it is inactive (e.g. init, suspended)
+    // and if it is done (transitioned to init from any other state)
+    if (curr_session_->IsSuspended()) {
+      session_map_[GetCurrentSessionId()] = std::move(curr_session_);
+      curr_session_ = nullptr;
+      continue;
+    }
+
+    if (curr_session_->GetState() == MainLoopState::kAwaitCleanup) {
+      curr_session_->CleanUp();
+      curr_session_ = nullptr;
+    }
+    // otherwise, continue with keeping the curr_session_
+  }  // end of the infinite while loop
+}
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/host_server.h b/host/libs/confui/host_server.h
new file mode 100644
index 0000000..be5caeb
--- /dev/null
+++ b/host/libs/confui/host_server.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2021 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 <atomic>
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <teeui/utils.h>
+
+#include "common/libs/concurrency/multiplexer.h"
+#include "common/libs/concurrency/semaphore.h"
+#include "common/libs/confui/confui.h"
+#include "common/libs/fs/shared_fd.h"
+#include "host/commands/kernel_log_monitor/utils.h"
+#include "host/libs/config/logging.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_renderer.h"
+#include "host/libs/confui/host_virtual_input.h"
+#include "host/libs/confui/server_common.h"
+#include "host/libs/confui/session.h"
+#include "host/libs/screen_connector/screen_connector.h"
+
+namespace cuttlefish {
+namespace confui {
+class HostServer : public HostVirtualInput {
+ public:
+  static HostServer& Get(
+      HostModeCtrl& host_mode_ctrl,
+      cuttlefish::ScreenConnectorFrameRenderer& screen_connector);
+
+  void Start();  // start this server itself
+  virtual ~HostServer() = default;
+
+  // implement input interfaces. called by webRTC & vnc
+  void PressConfirmButton(const bool is_down) override;
+  void PressCancelButton(const bool is_down) override;
+  bool IsConfUiActive() override;
+
+ private:
+  explicit HostServer(
+      cuttlefish::HostModeCtrl& host_mode_ctrl,
+      cuttlefish::ScreenConnectorFrameRenderer& screen_connector);
+  HostServer() = delete;
+
+  /**
+   * basic prompt flow:
+   * (1) Without preemption
+   *  send "kStart" with confirmation message
+   *  wait kCliAck from the host service with the echoed command
+   *  wait the confirmation/cancellation (or perhaps reset?)
+   *  send kStop
+   *  wait kCliAck from the host service with the echoed command
+   *
+   * (2) With preemption (e.g.)
+   *  send "kStart" with confirmation message
+   *  wait kCliAck from the host service with the echoed command
+   *  wait the confirmation/cancellation (or perhaps reset?)
+   *  send kSuspend  // when HAL is preempted
+   *  send kRestore  // when HAL resumes
+   *  send kStop
+   *
+   *  From the host end, it is a close-to-Mealy FSM.
+   *  There are four states S = {init, session, wait_ack, suspended}
+   *
+   *  'session' means in a confirmation session. 'wait_ack' means
+   *  server sends the confirmation and waiting "stop" command from HAL
+   *  'suspended' means the HAL service is preemptied. So, the host
+   *  should render the Android guest frames but keep the confirmation
+   *  UI session and frame
+   *
+   *  The inputs are I = {u, g}. 'u' is the user input from vnc/webRTC
+   *  clients. Note that the host service serialized the concurrent user
+   *  inputs from multiple clients. 'g' is the command from the HAL service
+   *
+   *  The transition rules:
+   *    (S, I) --> (S, O) where O is the output
+   *
+   *   init, g(start) -->  session, set Conf UI mode, render a frame
+   *   session, u(cancel/confirm) --> waitstop, send the result to HAL
+   *   session, g(suspend) --> suspend, create a saved session
+   *   session, g(abort)   --> init, clear saved frame
+   *   waitstop, g(stop) --> init, clear saved frame
+   *   waitstop, g(suspend) --> suspend, no need to save the session
+   *   waitstop, g(abort) --> init, clear saved frame
+   *   suspend, g(restore) --> return to the saved state, restore if there's a
+   *                           saved session
+   *   suspend, g(abort) --> init, clear saved frame
+   *
+   * For now, we did not yet implement suspend or abort.
+   *
+   */
+  [[noreturn]] void MainLoop();
+  void HalCmdFetcherLoop();
+
+  SharedFD EstablishHalConnection();
+
+  // failed to start dialog, etc
+  // basically, will reset the session, so start from the beginning in the same
+  // session
+  void ResetOnCommandFailure();
+
+  // note: the picked session will be removed from session_map_
+  std::unique_ptr<Session> GetSession(const std::string& session_id) {
+    if (session_map_.find(session_id) == session_map_.end()) {
+      return nullptr;
+    }
+    std::unique_ptr<Session> temp = std::move(session_map_[session_id]);
+    session_map_.erase(session_id);
+    return temp;
+  }
+
+  std::string GetCurrentSessionId() {
+    if (curr_session_) {
+      return curr_session_->GetId();
+    }
+    return SESSION_ANY;
+  }
+
+  std::string GetCurrentState() {
+    if (!curr_session_) {
+      return {"kInvalid"};
+    }
+    return ToString(curr_session_->GetState());
+  }
+  std::unique_ptr<Session> ComputeCurrentSession(const std::string& session_id);
+  bool SendUserSelection(UserResponse::type selection);
+
+  const std::uint32_t display_num_;
+  HostModeCtrl& host_mode_ctrl_;
+  ScreenConnectorFrameRenderer& screen_connector_;
+
+  // this member creates a raw frame
+  ConfUiRenderer renderer_;
+
+  std::string input_socket_path_;
+  std::string hal_socket_path_;
+
+  // session id to Session object map, for those that are suspended
+  std::unordered_map<std::string, std::unique_ptr<Session>> session_map_;
+  // curr_session_ doesn't belong to session_map_
+  std::unique_ptr<Session> curr_session_;
+
+  SharedFD guest_hal_socket_;
+  // ACCEPTED fd on guest_hal_socket_
+  SharedFD hal_cli_socket_;
+  std::mutex input_socket_mtx_;
+
+  /*
+   * Multiplexer has N queues. When pop(), it is going to sleep until
+   * there's at least one item in at least one queue. The lower the Q
+   * index is, the higher the priority is.
+   *
+   * For HostServer, we have a queue for the user input events, and
+   * another for hal cmd/msg queues
+   */
+  Multiplexer<ConfUiMessage> input_multiplexer_;
+  int hal_cmd_q_id_;         // Q id in input_multiplexer_
+  int user_input_evt_q_id_;  // Q id in input_multiplexer_
+
+  std::thread main_loop_thread_;
+  std::thread hal_input_fetcher_thread_;
+};
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/host_utils.cc b/host/libs/confui/host_utils.cc
new file mode 100644
index 0000000..6ff67b0
--- /dev/null
+++ b/host/libs/confui/host_utils.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/libs/confui/host_utils.h"
+
+namespace cuttlefish {
+namespace confui {
+namespace thread {
+std::string ThreadTracer::Get(const std::thread::id tid) {
+  std::lock_guard<std::mutex> lock(mtx_);
+  if (id2name_.find(tid) != id2name_.end()) {
+    return id2name_[tid];
+  }
+  std::stringstream ss;
+  ss << "Thread@" << tid;
+  return ss.str();
+}
+
+void ThreadTracer::Set(const std::string& name, const std::thread::id tid) {
+  std::lock_guard<std::mutex> lock(mtx_);
+  if (name2id_.find(name) != name2id_.end()) {
+    // has the name already
+    if (name2id_[name] != tid) {  // used for another thread
+      ConfUiLog(FATAL) << "Thread name is duplicated.";
+    }
+    // name and id are already set correctly
+    return;
+  }
+  if (id2name_.find(tid) != id2name_.end()) {
+    // tid exists but has a different name
+    name2id_.erase(id2name_[tid]);  // delete old_name -> tid map
+  }
+  id2name_[tid] = name;
+  name2id_[name] = tid;
+  return;
+}
+
+std::optional<std::thread::id> ThreadTracer::Get(const std::string& name) {
+  std::lock_guard<std::mutex> lock(mtx_);
+  if (name2id_.find(name) != name2id_.end()) {
+    return {name2id_[name]};
+  }
+  return std::nullopt;  // unknown
+}
+
+ThreadTracer& GetThreadTracer() {
+  static ThreadTracer thread_tracer;
+  return thread_tracer;
+}
+
+std::string GetName(const std::thread::id tid) {
+  return GetThreadTracer().Get(tid);
+}
+
+std::optional<std::thread::id> GetId(const std::string& name) {
+  return GetThreadTracer().Get(name);
+}
+
+void Set(const std::string& name, const std::thread::id tid) {
+  GetThreadTracer().Set(name, tid);
+}
+}  // namespace thread
+}  // namespace confui
+}  // namespace cuttlefish
diff --git a/host/libs/confui/host_utils.h b/host/libs/confui/host_utils.h
new file mode 100644
index 0000000..bd4004b
--- /dev/null
+++ b/host/libs/confui/host_utils.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2021 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 <functional>
+#include <map>
+#include <mutex>
+#include <optional>
+#include <sstream>
+#include <string>
+#include <thread>
+
+#include <android-base/logging.h>
+
+#include "common/libs/confui/confui.h"
+#include "host/commands/kernel_log_monitor/utils.h"
+#include "host/libs/config/logging.h"
+
+namespace cuttlefish {
+namespace confui {
+
+namespace thread {
+/* thread id to name
+ * these three functions internally uses the singleton ThreadTracer object.
+ *
+ * When running a thread, use the global RunThread function
+ */
+std::string GetName(const std::thread::id tid = std::this_thread::get_id());
+std::optional<std::thread::id> GetId(const std::string& name);
+void Set(const std::string& name, const std::thread::id tid);
+
+/*
+ * This is wrapping std::thread. However, we keep the bidirectional map
+ * between the given thread name and the thread id. The main purpose is
+ * to help debugging.
+ *
+ */
+template <typename F, typename... Args>
+std::thread RunThread(const std::string& name, F&& f, Args&&... args);
+
+class ThreadTracer;
+ThreadTracer& GetThreadTracer();
+
+class ThreadTracer {
+  friend ThreadTracer& GetThreadTracer();
+  friend std::string GetName(const std::thread::id tid);
+  friend std::optional<std::thread::id> GetId(const std::string& name);
+  friend void Set(const std::string& name, const std::thread::id tid);
+
+  template <typename F, typename... Args>
+  friend std::thread RunThread(const std::string& name, F&& f, Args&&... args);
+
+ private:
+  template <typename F, typename... Args>
+  std::thread RunThread(const std::string& name, F&& f, Args&&... args) {
+    auto th = std::thread(std::forward<F>(f), std::forward<Args>(args)...);
+    if (name2id_.find(name) != name2id_.end()) {
+      ConfUiLog(FATAL) << "Thread name is duplicated";
+    }
+    name2id_[name] = th.get_id();
+    id2name_[th.get_id()] = name;
+    ConfUiLog(DEBUG) << name << "thread started.";
+    return th;
+  }
+  std::string Get(const std::thread::id id = std::this_thread::get_id());
+  std::optional<std::thread::id> Get(const std::string& name);
+
+  // add later on even though it wasn't started with RunThread
+  // if tid is already added, update the name only
+  void Set(const std::string& name, const std::thread::id tid);
+
+  ThreadTracer() = default;
+  std::map<std::thread::id, std::string> id2name_;
+  std::map<std::string, std::thread::id> name2id_;
+  std::mutex mtx_;
+};
+
+template <typename F, typename... Args>
+std::thread RunThread(const std::string& name, F&& f, Args&&... args) {
+  auto& tracer = GetThreadTracer();
+  return tracer.RunThread(name, std::forward<F>(f),
+                          std::forward<Args>(args)...);
+}
+
+}  // namespace thread
+}  // namespace confui
+}  // namespace cuttlefish
diff --git a/host/libs/confui/host_virtual_input.h b/host/libs/confui/host_virtual_input.h
new file mode 100644
index 0000000..ec800cb
--- /dev/null
+++ b/host/libs/confui/host_virtual_input.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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.0f
+ *
+ * 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 <cstdint>
+
+namespace cuttlefish {
+namespace confui {
+enum class ConfUiKeys : std::uint32_t { Confirm = 7, Cancel = 8 };
+
+/**
+ * vnc, webrtc will deliver the user inputs from their client
+ * to this class object
+ */
+class HostVirtualInput {
+ public:
+  virtual void PressConfirmButton(const bool is_down) = 0;
+  virtual void PressCancelButton(const bool is_down) = 0;
+  virtual ~HostVirtualInput() = default;
+  // guarantees that if this returns true, it is confirmation UI mode
+  virtual bool IsConfUiActive() = 0;
+};
+}  // namespace confui
+}  // namespace cuttlefish
diff --git a/host/libs/confui/layouts/fonts.h b/host/libs/confui/layouts/fonts.h
new file mode 100644
index 0000000..1abfd25
--- /dev/null
+++ b/host/libs/confui/layouts/fonts.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021, 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 <teeui/incfont.h>
+
+/*
+ * Each entry TEEUI_INCFONT(<name>) declares:
+ *    extern unsigned char <name>[];
+ *    extern unsigned int <name>_length;
+ * The first one pointing to a raw ttf font file in the .rodata section, and the
+ * second beeing the size of the buffer.
+ */
+TEEUI_INCFONT(RobotoMedium);
+TEEUI_INCFONT(RobotoRegular);
+TEEUI_INCFONT(Shield);
diff --git a/host/libs/confui/layouts/layout.h b/host/libs/confui/layouts/layout.h
new file mode 100644
index 0000000..bb40b67
--- /dev/null
+++ b/host/libs/confui/layouts/layout.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2021 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 <teeui/button.h>
+#include <teeui/label.h>
+#include <teeui/localization/ConfirmationUITranslations.h>
+#include <teeui/utils.h>
+
+#include "fonts.h"
+
+using teeui::localization::TranslationId;
+
+namespace teeui {
+
+DECLARE_PARAMETER(RightEdgeOfScreen);
+DECLARE_PARAMETER(BottomOfScreen);
+DECLARE_PARAMETER(PowerButtonTop);
+DECLARE_PARAMETER(PowerButtonBottom);
+DECLARE_PARAMETER(VolUpButtonTop);
+DECLARE_PARAMETER(VolUpButtonBottom);
+DECLARE_PARAMETER(DefaultFontSize);  // 14_dp regular and 18_dp magnified
+DECLARE_PARAMETER(BodyFontSize);     // 16_dp regular and 20_dp magnified
+DECLARE_TYPED_PARAMETER(ShieldColor, ::teeui::Color);
+DECLARE_TYPED_PARAMETER(ColorText, ::teeui::Color);
+DECLARE_TYPED_PARAMETER(ColorBG, ::teeui::Color);
+
+NEW_PARAMETER_SET(ConUIParameters, RightEdgeOfScreen, BottomOfScreen,
+                  PowerButtonTop, PowerButtonBottom, VolUpButtonTop,
+                  VolUpButtonBottom, DefaultFontSize, BodyFontSize, ShieldColor,
+                  ColorText, ColorBG);
+
+CONSTANT(BorderWidth, 24_dp);
+CONSTANT(PowerButtonCenter, (PowerButtonTop() + PowerButtonBottom()) / 2_px);
+CONSTANT(VolUpButtonCenter, (VolUpButtonTop() + VolUpButtonBottom()) / 2.0_px);
+CONSTANT(GrayZone, 12_dp);
+CONSTANT(RightLabelEdge, RightEdgeOfScreen() - BorderWidth - GrayZone);
+CONSTANT(LabelWidth, RightLabelEdge - BorderWidth);
+
+CONSTANT(SQRT2, 1.4142135623_dp);
+CONSTANT(SQRT8, 2.828427125_dp);
+
+CONSTANT(ARROW_SHAPE,
+         CONVEX_OBJECTS(
+             CONVEX_OBJECT(Vec2d{.0_dp, .0_dp}, Vec2d{6.0_dp, 6.0_dp},
+                           Vec2d{6.0_dp - SQRT8, 6.0_dp}, Vec2d{-SQRT2, SQRT2}),
+             CONVEX_OBJECT(Vec2d{6.0_dp - SQRT8, 6.0_dp}, Vec2d{6.0_dp, 6.0_dp},
+                           Vec2d{0.0_dp, 12.0_dp},
+                           Vec2d{-SQRT2, 12.0_dp - SQRT2})));
+
+DECLARE_FONT_BUFFER(RobotoMedium, RobotoMedium, RobotoMedium_length);
+DECLARE_FONT_BUFFER(RobotoRegular, RobotoRegular, RobotoRegular_length);
+DECLARE_FONT_BUFFER(Shield, Shield, Shield_length);
+
+CONSTANT(DefaultFont, FONT(RobotoRegular));
+
+BEGIN_ELEMENT(LabelOK, teeui::Label)
+FontSize(DefaultFontSize());
+LineHeight(20_dp);
+NumberOfLines(2);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, PowerButtonCenter - dim_h / 2.0_px);
+DefaultText("Press Power Button Confirm");
+RightJustified;
+VerticallyCentered;
+TextColor(ColorText());
+Font(FONT(RobotoMedium));
+TextID(TEXT_ID(TranslationId::CONFIRM_PWR_BUTTON_DOUBLE_PRESS));
+END_ELEMENT();
+
+BEGIN_ELEMENT(IconPower, teeui::Button, ConvexObjectCount(2))
+Dimension(BorderWidth, PowerButtonBottom() - PowerButtonTop());
+Position(RightEdgeOfScreen() - BorderWidth, PowerButtonTop());
+CornerRadius(3_dp);
+ButtonColor(ColorText());
+RoundTopLeft;
+RoundBottomLeft;
+ConvexObjectColor(ColorBG());
+ConvexObjects(ARROW_SHAPE);
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelCancel, teeui::Label)
+FontSize(DefaultFontSize());
+LineHeight(20_dp);
+NumberOfLines(2);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, VolUpButtonCenter - dim_h / 2.0_px);
+DefaultText("Press Menu Button to Cancel");
+RightJustified;
+VerticallyCentered;
+TextColor(ColorText());
+Font(FONT(RobotoMedium));
+TextID(TEXT_ID(TranslationId::CANCEL));
+END_ELEMENT();
+
+BEGIN_ELEMENT(IconVolUp, teeui::Button, ConvexObjectCount(2))
+Dimension(BorderWidth, VolUpButtonBottom() - VolUpButtonTop());
+Position(RightEdgeOfScreen() - BorderWidth, VolUpButtonTop());
+CornerRadius(5_dp);
+ButtonColor(ColorBG());
+ConvexObjectColor(ColorText());
+ConvexObjects(ARROW_SHAPE);
+END_ELEMENT();
+
+BEGIN_ELEMENT(IconShield, teeui::Label)
+FontSize(24_dp);
+LineHeight(24_dp);
+NumberOfLines(1);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, BOTTOM_EDGE_OF(LabelCancel) + 40_dp);
+DefaultText(
+    "A");  // ShieldTTF has just one glyph at the code point for capital A
+TextColor(ShieldColor());
+Font(FONT(Shield));
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelTitle, teeui::Label)
+FontSize(20_dp);
+LineHeight(20_dp);
+NumberOfLines(1);
+Dimension(RightEdgeOfScreen() - BorderWidth, HeightFromLines);
+Position(BorderWidth, BOTTOM_EDGE_OF(IconShield) + 12_dp);
+DefaultText("Android Protected Confirmation");
+Font(FONT(RobotoMedium));
+VerticallyCentered;
+TextColor(ColorText());
+TextID(TEXT_ID(TranslationId::TITLE));
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelHint, teeui::Label)
+FontSize(DefaultFontSize());
+LineHeight(DefaultFontSize() * 1.5_px);
+NumberOfLines(4);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, BottomOfScreen() - BorderWidth - dim_h);
+DefaultText(
+    "This confirmation provides an extra layer of security for the action "
+    "you're "
+    "about to take.");
+VerticalTextAlignment(Alignment::BOTTOM);
+TextColor(ColorText());
+Font(DefaultFont);
+TextID(TEXT_ID(TranslationId::DESCRIPTION));
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelBody, teeui::Label)
+FontSize(BodyFontSize());
+LineHeight(BodyFontSize() * 1.4_px);
+NumberOfLines(20);
+Position(BorderWidth, BOTTOM_EDGE_OF(LabelTitle) + 18_dp);
+Dimension(LabelWidth, LabelHint::pos_y - pos_y - 24_dp);
+DefaultText(
+    "12345678901234567890123456789012345678901234567890123456789012345678901234"
+    "567890123456"
+    "78901234567890");
+TextColor(ColorText());
+Font(FONT(RobotoRegular));
+END_ELEMENT();
+
+NEW_LAYOUT(ConfUILayout, LabelOK, IconPower, LabelCancel, IconVolUp, IconShield,
+           LabelTitle, LabelHint, LabelBody);
+
+}  // namespace teeui
diff --git a/host/libs/confui/server_common.cc b/host/libs/confui/server_common.cc
new file mode 100644
index 0000000..cf46fe3
--- /dev/null
+++ b/host/libs/confui/server_common.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/libs/confui/server_common.h"
+namespace cuttlefish {
+namespace confui {
+static FsmInput UserEvtToFsmInput(UserResponse::type user_response) {
+  if (user_response == UserResponse::kConfirm) {
+    return FsmInput::kUserUnknown;
+  }
+  if (user_response == UserResponse::kCancel) {
+    return FsmInput::kUserCancel;
+  }
+  return FsmInput::kUserUnknown;
+}
+
+FsmInput ToFsmInput(const ConfUiMessage& confui_msg) {
+  ConfUiCmd cmd = ToCmd(confui_msg.type_);
+  if (cmd == ConfUiCmd::kUserInputEvent) {
+    return UserEvtToFsmInput(confui_msg.msg_);
+  }
+  const auto hal_cmd = cmd;
+  switch (hal_cmd) {
+    case ConfUiCmd::kUnknown:
+      return FsmInput::kHalUnknown;
+    case ConfUiCmd::kStart:
+      return FsmInput::kHalStart;
+    case ConfUiCmd::kStop:
+      return FsmInput::kHalStop;
+    case ConfUiCmd::kSuspend:
+      return FsmInput::kHalSuspend;
+    case ConfUiCmd::kRestore:
+      return FsmInput::kHalRestore;
+    case ConfUiCmd::kAbort:
+      return FsmInput::kHalAbort;
+    case ConfUiCmd::kCliAck:
+    case ConfUiCmd::kCliRespond:
+    default:
+      ConfUiLog(FATAL) << "The" << ToString(hal_cmd)
+                       << "is not handled by Session";
+  }
+  return FsmInput::kHalUnknown;
+}
+
+std::string ToString(FsmInput input) {
+  switch (input) {
+    case FsmInput::kUserConfirm:
+      return {"kUserConfirm"};
+    case FsmInput::kUserCancel:
+      return {"kUserCancel"};
+    case FsmInput::kUserUnknown:
+      return {"kUserUnknown"};
+    case FsmInput::kHalStart:
+      return {"kHalStart"};
+    case FsmInput::kHalStop:
+      return {"kHalStop"};
+    case FsmInput::kHalSuspend:
+      return {"kHalSuspend"};
+    case FsmInput::kHalRestore:
+      return {"kHalRestore"};
+    case FsmInput::kHalAbort:
+      return {"kHalAbort"};
+    case FsmInput::kHalUnknown:
+    default:
+      break;
+  }
+  return {"kHalUnknown"};
+}
+
+std::string ToString(const MainLoopState& state) {
+  switch (state) {
+    case MainLoopState::kInit:
+      return "kInit";
+    case MainLoopState::kInSession:
+      return "kInSession";
+    case MainLoopState::kWaitStop:
+      return "kWaitStop";
+    case MainLoopState::kSuspended:
+      return "kSuspended";
+    case MainLoopState::kAwaitCleanup:
+      return "kAwaitCleanup";
+    default:
+      return "kInvalid";
+  }
+}
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/server_common.h b/host/libs/confui/server_common.h
new file mode 100644
index 0000000..6175d16
--- /dev/null
+++ b/host/libs/confui/server_common.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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 <cstdint>
+#include <vector>
+
+#include "common/libs/confui/confui.h"
+
+namespace cuttlefish {
+namespace confui {
+enum class MainLoopState : std::uint32_t {
+  kInit = 1,
+  kInSession = 2,
+  kWaitStop = 3,  // wait ack after sending confirm/cancel
+  kSuspended = 4,
+  kAwaitCleanup = 5,
+  kInvalid = 9
+};
+
+using TeeUiFrame = std::vector<std::uint32_t>;
+
+// FSM input to Session FSM
+enum class FsmInput : std::uint32_t {
+  kUserConfirm,
+  kUserCancel,
+  kUserUnknown,
+  kHalStart,
+  kHalStop,
+  kHalSuspend,
+  kHalRestore,
+  kHalAbort,
+  kHalUnknown
+};
+
+std::string ToString(FsmInput input);
+std::string ToString(const MainLoopState& state);
+
+FsmInput ToFsmInput(const ConfUiMessage& confui_msg);
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/session.cc b/host/libs/confui/session.cc
new file mode 100644
index 0000000..3d365c6
--- /dev/null
+++ b/host/libs/confui/session.cc
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "host/libs/confui/session.h"
+
+namespace cuttlefish {
+namespace confui {
+
+Session::Session(const std::string& session_id, const std::uint32_t display_num,
+                 ConfUiRenderer& host_renderer, HostModeCtrl& host_mode_ctrl,
+                 ScreenConnectorFrameRenderer& screen_connector,
+                 const std::string& locale)
+    : session_id_{session_id},
+      display_num_{display_num},
+      renderer_{host_renderer},
+      host_mode_ctrl_{host_mode_ctrl},
+      screen_connector_{screen_connector},
+      locale_{locale},
+      state_{MainLoopState::kInit},
+      saved_state_{MainLoopState::kInit} {}
+
+bool Session::IsConfUiActive() const {
+  if (state_ == MainLoopState::kInSession ||
+      state_ == MainLoopState::kWaitStop) {
+    return true;
+  }
+  return false;
+}
+
+bool Session::RenderDialog(const std::string& msg, const std::string& locale) {
+  auto [teeui_frame, is_success] = renderer_.RenderRawFrame(msg, locale);
+  if (!is_success) {
+    return false;
+  }
+  prompt_ = msg;
+  locale_ = locale;
+
+  ConfUiLog(DEBUG) << "actually trying to render the frame"
+                   << thread::GetName();
+  auto raw_frame = reinterpret_cast<std::uint8_t*>(teeui_frame.data());
+  return screen_connector_.RenderConfirmationUi(display_num_, raw_frame);
+}
+
+bool Session::IsSuspended() const {
+  return (state_ == MainLoopState::kSuspended);
+}
+
+MainLoopState Session::Transition(const bool is_user_input, SharedFD& hal_cli,
+                                  const FsmInput fsm_input,
+                                  const std::string& additional_info) {
+  switch (state_) {
+    case MainLoopState::kInit: {
+      HandleInit(is_user_input, hal_cli, fsm_input, additional_info);
+    } break;
+    case MainLoopState::kInSession: {
+      HandleInSession(is_user_input, hal_cli, fsm_input);
+    } break;
+    case MainLoopState::kWaitStop: {
+      if (is_user_input) {
+        ConfUiLog(DEBUG) << "User input ignored" << ToString(fsm_input) << " : "
+                         << additional_info << "at state" << ToString(state_);
+      }
+      HandleWaitStop(is_user_input, hal_cli, fsm_input);
+    } break;
+    default:
+      // host service explicitly calls restore and suspend
+      ConfUiLog(FATAL) << "Must not be in the state of" << ToString(state_);
+      break;
+  }
+  return state_;
+};
+
+bool Session::Suspend(SharedFD hal_cli) {
+  if (state_ == MainLoopState::kInit) {
+    // HAL sent wrong command
+    ConfUiLog(FATAL)
+        << "HAL sent wrong command, suspend, when the session is in kIinit";
+    return false;
+  }
+  if (state_ == MainLoopState::kSuspended) {
+    ConfUiLog(DEBUG) << "Already kSuspended state";
+    return false;
+  }
+  saved_state_ = state_;
+  state_ = MainLoopState::kSuspended;
+  host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kAndroidMode);
+  if (!packet::SendAck(hal_cli, session_id_, /*is success*/ true,
+                       "suspended")) {
+    ConfUiLog(FATAL) << "I/O error";
+    return false;
+  }
+  return true;
+}
+
+bool Session::Restore(SharedFD hal_cli) {
+  if (state_ == MainLoopState::kInit) {
+    // HAL sent wrong command
+    ConfUiLog(FATAL)
+        << "HAL sent wrong command, restore, when the session is in kIinit";
+    return false;
+  }
+
+  if (state_ != MainLoopState::kSuspended) {
+    ConfUiLog(DEBUG) << "Already Restored to state " + ToString(state_);
+    return false;
+  }
+  host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kConfUI_Mode);
+  if (!RenderDialog(prompt_, locale_)) {
+    // the confirmation UI is driven by a user app, not running from the start
+    // automatically so that means webRTC/vnc should have been set up
+    ConfUiLog(ERROR) << "Dialog is not rendered. However, it should."
+                     << "No webRTC can't initiate any confirmation UI.";
+    if (!packet::SendAck(hal_cli, session_id_, false,
+                         "render failed in restore")) {
+      ConfUiLog(FATAL) << "Rendering failed in restore, and ack failed in I/O";
+    }
+    state_ = MainLoopState::kInit;
+    return false;
+  }
+  if (!packet::SendAck(hal_cli, session_id_, true, "restored")) {
+    ConfUiLog(FATAL) << "Ack to restore failed in I/O";
+  }
+  state_ = saved_state_;
+  saved_state_ = MainLoopState::kInit;
+  return true;
+}
+
+bool Session::Kill(SharedFD hal_cli, const std::string& response_msg) {
+  state_ = MainLoopState::kAwaitCleanup;
+  saved_state_ = MainLoopState::kInvalid;
+  if (!packet::SendAck(hal_cli, session_id_, true, response_msg)) {
+    ConfUiLog(FATAL) << "I/O error in ack to Abort";
+    return false;
+  }
+  return true;
+}
+
+void Session::CleanUp() {
+  if (state_ != MainLoopState::kAwaitCleanup) {
+    ConfUiLog(FATAL) << "Clean up a session only when in kAwaitCleanup";
+  }
+  // common action done when the state is back to init state
+  host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kAndroidMode);
+}
+
+void Session::ReportErrorToHal(SharedFD hal_cli, const std::string& msg) {
+  // reset the session -- destroy it & recreate it with the same
+  // session id
+  state_ = MainLoopState::kAwaitCleanup;
+  if (!packet::SendAck(hal_cli, session_id_, false, msg)) {
+    ConfUiLog(FATAL) << "I/O error in sending ack to report rendering failure";
+  }
+  return;
+}
+
+bool Session::Abort(SharedFD hal_cli) { return Kill(hal_cli, "aborted"); }
+
+void Session::HandleInit(const bool is_user_input, SharedFD hal_cli,
+                         const FsmInput fsm_input,
+                         const std::string& additional_info) {
+  using namespace cuttlefish::confui::packet;
+  if (is_user_input) {
+    // ignore user input
+    state_ = MainLoopState::kInit;
+    return;
+  }
+
+  ConfUiLog(DEBUG) << ToString(fsm_input) << "is handled in HandleInit";
+  if (fsm_input != FsmInput::kHalStart) {
+    ConfUiLog(ERROR) << "invalid cmd for Init State:" << ToString(fsm_input);
+    // reset the session -- destroy it & recreate it with the same
+    // session id
+    ReportErrorToHal(hal_cli, "wrong hal command");
+    return;
+  }
+
+  // Start Session
+  ConfUiLog(DEBUG) << "Sending ack to hal_cli: "
+                   << Enum2Base(ConfUiCmd::kCliAck);
+  host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kConfUI_Mode);
+  auto confirmation_msg = additional_info;
+  if (!RenderDialog(confirmation_msg, locale_)) {
+    // the confirmation UI is driven by a user app, not running from the start
+    // automatically so that means webRTC/vnc should have been set up
+    ConfUiLog(ERROR) << "Dialog is not rendered. However, it should."
+                     << "No webRTC can't initiate any confirmation UI.";
+    ReportErrorToHal(hal_cli, "rendering failed");
+    return;
+  }
+  if (!packet::SendAck(hal_cli, session_id_, true, "started")) {
+    ConfUiLog(FATAL) << "Ack to kStart failed in I/O";
+  }
+  state_ = MainLoopState::kInSession;
+  return;
+}
+
+void Session::HandleInSession(const bool is_user_input, SharedFD hal_cli,
+                              const FsmInput fsm_input) {
+  if (!is_user_input) {
+    ConfUiLog(FATAL) << "cmd" << ToString(fsm_input)
+                     << "should not be handled in HandleInSession";
+    ReportErrorToHal(hal_cli, "wrong hal command");
+    return;
+  }
+
+  // send to hal_cli either confirm or cancel
+  if (fsm_input != FsmInput::kUserConfirm &&
+      fsm_input != FsmInput::kUserCancel) {
+    /*
+     * TODO(kwstephenkim@google.com): change here when other user inputs must
+     * be handled
+     *
+     */
+    if (!packet::SendAck(hal_cli, session_id_, true,
+                         "invalid user input error")) {
+      // note that input is what we control in memory
+      ConfUiCheck(false) << "Input must be either confirm or cancel for now.";
+    }
+    return;
+  }
+
+  ConfUiLog(DEBUG) << "In HandlieInSession, session" << session_id_
+                   << "is sending the user input" << ToString(fsm_input);
+  auto selection = UserResponse::kConfirm;
+  if (fsm_input == FsmInput::kUserCancel) {
+    selection = UserResponse::kCancel;
+  }
+  if (!packet::SendResponse(hal_cli, session_id_, selection)) {
+    ConfUiLog(FATAL) << "I/O error in sending user response to HAL";
+  }
+  state_ = MainLoopState::kWaitStop;
+  return;
+}
+
+void Session::HandleWaitStop(const bool is_user_input, SharedFD hal_cli,
+                             const FsmInput fsm_input) {
+  using namespace cuttlefish::confui::packet;
+
+  if (is_user_input) {
+    // ignore user input
+    state_ = MainLoopState::kWaitStop;
+    return;
+  }
+  if (fsm_input == FsmInput::kHalStop) {
+    ConfUiLog(DEBUG) << "Handling Abort in kWaitStop.";
+    Kill(hal_cli, "stopped");
+    return;
+  }
+  ConfUiLog(FATAL) << "In WaitStop, received wrong HAL command "
+                   << ToString(fsm_input);
+  state_ = MainLoopState::kAwaitCleanup;
+  return;
+}
+
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/confui/session.h b/host/libs/confui/session.h
new file mode 100644
index 0000000..87e98c9
--- /dev/null
+++ b/host/libs/confui/session.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 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 <memory>
+
+#include "common/libs/confui/confui.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_renderer.h"
+#include "host/libs/confui/server_common.h"
+#include "host/libs/confui/session.h"
+#include "host/libs/screen_connector/screen_connector.h"
+
+namespace cuttlefish {
+namespace confui {
+
+/**
+ * Confirmation UI Session
+ *
+ * E.g. Two guest apps could drive confirmation UI respectively,
+ * and both are alive at the moment. Each needs one session
+ *
+ */
+class Session {
+ public:
+  Session(const std::string& session_id, const std::uint32_t display_num,
+          ConfUiRenderer& host_renderer, HostModeCtrl& host_mode_ctrl,
+          ScreenConnectorFrameRenderer& screen_connector,
+          const std::string& locale = "en");
+
+  bool IsConfUiActive() const;
+
+  std::string GetId() { return session_id_; }
+
+  MainLoopState GetState() { return state_; }
+
+  MainLoopState Transition(const bool is_user_input, SharedFD& hal_cli,
+                           const FsmInput fsm_input,
+                           const std::string& additional_info);
+
+  /**
+   * this make a transition from kWaitStop or kInSession to kSuspend
+   */
+  bool Suspend(SharedFD hal_cli);
+
+  /**
+   * this make a transition from kRestore to the saved state
+   */
+  bool Restore(SharedFD hal_cli);
+
+  // abort session
+  bool Abort(SharedFD hal_cli);
+
+  bool IsSuspended() const;
+  void CleanUp();
+
+ private:
+  /** create a frame, and render it on the vnc/webRTC client
+   *
+   * note that this does not check host_ctrl_mode_
+   */
+  bool RenderDialog(const std::string& msg, const std::string& locale);
+
+  // transition actions on each state per input
+  // the new state will be save to the state_ at the end of each call
+  void HandleInit(const bool is_user_input, SharedFD hal_cli,
+                  const FsmInput fsm_input, const std::string& additional_info);
+
+  void HandleWaitStop(const bool is_user_input, SharedFD hal_cli,
+                      const FsmInput fsm_input);
+
+  void HandleInSession(const bool is_user_input, SharedFD hal_cli,
+                       const FsmInput fsm_input);
+
+  bool Kill(SharedFD hal_cli, const std::string& response_msg);
+
+  // report with an error ack to HAL, and reset the FSM
+  void ReportErrorToHal(SharedFD hal_cli, const std::string& msg);
+
+  const std::string session_id_;
+  const std::uint32_t display_num_;
+  // host renderer is shared across sessions
+  ConfUiRenderer& renderer_;
+  HostModeCtrl& host_mode_ctrl_;
+  ScreenConnectorFrameRenderer& screen_connector_;
+
+  // only context to save
+  std::string prompt_;
+  std::string locale_;
+
+  // effectively, this variables are shared with vnc, webRTC thread
+  // the input demuxer will check the confirmation UI mode based on this
+  std::atomic<MainLoopState> state_;
+  MainLoopState saved_state_;  // for restore/suspend
+};
+}  // end of namespace confui
+}  // end of namespace cuttlefish
diff --git a/host/libs/graphics_detector/Android.bp b/host/libs/graphics_detector/Android.bp
new file mode 100644
index 0000000..bd6a55e
--- /dev/null
+++ b/host/libs/graphics_detector/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "device_google_cuttlefish_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    default_applicable_licenses: ["device_google_cuttlefish_license"],
+}
+
+cc_library_headers {
+    name: "egl_headers",
+    export_include_dirs: ["include"],
+    defaults: ["cuttlefish_host"],
+}
+
+cc_library_static {
+    name: "libcuttlefish_graphics_detector",
+    srcs: [
+        "graphics_detector.cpp",
+    ],
+    header_libs: [
+        "egl_headers",
+        "vulkan_headers",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/libs/graphics_detector/graphics_detector.cpp b/host/libs/graphics_detector/graphics_detector.cpp
new file mode 100644
index 0000000..367e637
--- /dev/null
+++ b/host/libs/graphics_detector/graphics_detector.cpp
@@ -0,0 +1,604 @@
+/*
+ * 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.
+ */
+
+#include "host/libs/graphics_detector/graphics_detector.h"
+
+#include <sstream>
+#include <vector>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <dlfcn.h>
+#include <sys/wait.h>
+#include <vulkan/vulkan.h>
+
+namespace cuttlefish {
+namespace {
+
+constexpr const char kEglLib[] = "libEGL.so.1";
+constexpr const char kGlLib[] = "libOpenGL.so.0";
+constexpr const char kGles1Lib[] = "libGLESv1_CM.so.1";
+constexpr const char kGles2Lib[] = "libGLESv2.so.2";
+constexpr const char kVulkanLib[] = "libvulkan.so.1";
+
+constexpr const char kSurfacelessContextExt[] = "EGL_KHR_surfaceless_context";
+
+class Closer {
+public:
+  Closer(std::function<void()> on_close) : on_close_(on_close) {}
+  ~Closer() { on_close_(); }
+
+private:
+  std::function<void()> on_close_;
+};
+
+struct LibraryCloser {
+ public:
+  void operator()(void* library) { dlclose(library); }
+};
+
+using ManagedLibrary = std::unique_ptr<void, LibraryCloser>;
+
+void PopulateGlAvailability(GraphicsAvailability* availability) {
+  ManagedLibrary gl_lib(dlopen(kGlLib, RTLD_NOW | RTLD_LOCAL));
+  if (!gl_lib) {
+    LOG(VERBOSE) << "Failed to dlopen " << kGlLib << ".";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded " << kGlLib << ".";
+  availability->has_gl = true;
+}
+
+void PopulateGles1Availability(GraphicsAvailability* availability) {
+  ManagedLibrary gles1_lib(dlopen(kGles1Lib, RTLD_NOW | RTLD_LOCAL));
+  if (!gles1_lib) {
+    LOG(VERBOSE) << "Failed to dlopen " << kGles1Lib << ".";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded " << kGles1Lib << ".";
+  availability->has_gles1 = true;
+}
+
+void PopulateGles2Availability(GraphicsAvailability* availability) {
+  ManagedLibrary gles2_lib(dlopen(kGles2Lib, RTLD_NOW | RTLD_LOCAL));
+  if (!gles2_lib) {
+    LOG(VERBOSE) << "Failed to dlopen " << kGles2Lib << ".";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded " << kGles2Lib << ".";
+  availability->has_gles2 = true;
+}
+
+void PopulateEglAvailability(GraphicsAvailability* availability) {
+  ManagedLibrary egllib(dlopen(kEglLib, RTLD_NOW | RTLD_LOCAL));
+  if (!egllib) {
+    LOG(VERBOSE) << "Failed to dlopen " << kEglLib << ".";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded " << kEglLib << ".";
+  availability->has_egl = true;
+
+  PFNEGLGETPROCADDRESSPROC eglGetProcAddress =
+      reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(
+          dlsym(egllib.get(), "eglGetProcAddress"));
+  if (eglGetProcAddress == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglGetProcAddress.";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglGetProcAddress.";
+
+  // Some implementations have it so that eglGetProcAddress is only for
+  // loading EXT functions.
+  auto EglLoadFunction = [&](const char* name) {
+    void* func = dlsym(egllib.get(), name);
+    if (func == NULL) {
+      func = reinterpret_cast<void*>(eglGetProcAddress(name));
+    }
+    return func;
+  };
+
+  PFNEGLGETERRORPROC eglGetError =
+    reinterpret_cast<PFNEGLGETERRORPROC>(EglLoadFunction("eglGetError"));
+  if (eglGetError == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglGetError.";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglGetError.";
+
+  PFNEGLGETDISPLAYPROC eglGetDisplay =
+    reinterpret_cast<PFNEGLGETDISPLAYPROC>(EglLoadFunction("eglGetDisplay"));
+  if (eglGetDisplay == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglGetDisplay.";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglGetDisplay.";
+
+  EGLDisplay default_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+  if (default_display == EGL_NO_DISPLAY) {
+    LOG(VERBOSE) << "Failed to get default display. " << eglGetError();
+    return;
+  }
+  LOG(VERBOSE) << "Found default display.";
+  availability->has_egl_default_display = true;
+
+  PFNEGLINITIALIZEPROC eglInitialize =
+    reinterpret_cast<PFNEGLINITIALIZEPROC>(EglLoadFunction("eglInitialize"));
+  if (eglInitialize == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglQueryString";
+    return;
+  }
+
+  EGLint client_version_major = 0;
+  EGLint client_version_minor = 0;
+  if (eglInitialize(default_display,
+                    &client_version_major,
+                    &client_version_minor) != EGL_TRUE) {
+    LOG(VERBOSE) << "Failed to initialize default display.";
+    return;
+  }
+  LOG(VERBOSE) << "Initialized default display.";
+
+  PFNEGLQUERYSTRINGPROC eglQueryString =
+    reinterpret_cast<PFNEGLQUERYSTRINGPROC>(EglLoadFunction("eglQueryString"));
+  if (eglQueryString == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglQueryString";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglQueryString.";
+
+  std::string client_extensions;
+  if (client_version_major >= 1 && client_version_minor >= 5) {
+    client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+  }
+  availability->egl_client_extensions = client_extensions;
+
+  EGLDisplay display = EGL_NO_DISPLAY;
+
+  if (client_extensions.find("EGL_EXT_platform_base") != std::string::npos) {
+    LOG(VERBOSE) << "Client extension EGL_EXT_platform_base is supported.";
+
+    PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
+      reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
+        EglLoadFunction("eglGetPlatformDisplayEXT"));
+    if (eglGetPlatformDisplayEXT == nullptr) {
+      LOG(VERBOSE) << "Failed to find function eglGetPlatformDisplayEXT";
+      return;
+    }
+
+    display =
+      eglGetPlatformDisplayEXT(EGL_PLATFORM_SURFACELESS_MESA,
+                               EGL_DEFAULT_DISPLAY,
+                               NULL);
+  } else {
+    LOG(VERBOSE) << "Failed to find client extension EGL_EXT_platform_base.";
+  }
+  if (display == EGL_NO_DISPLAY) {
+    LOG(VERBOSE) << "Failed to get EGL_PLATFORM_SURFACELESS_MESA display..."
+                 << "failing back to EGL_DEFAULT_DISPLAY display.";
+    display = default_display;
+  }
+  if (display == EGL_NO_DISPLAY) {
+    LOG(VERBOSE) << "Failed to find display.";
+    return;
+  }
+
+  if (eglInitialize(display,
+                    &client_version_major,
+                    &client_version_minor) != EGL_TRUE) {
+    LOG(VERBOSE) << "Failed to initialize surfaceless display.";
+    return;
+  }
+  LOG(VERBOSE) << "Initialized surfaceless display.";
+
+  const std::string version_string = eglQueryString(display, EGL_VERSION);
+  if (version_string.empty()) {
+    LOG(VERBOSE) << "Failed to query client version.";
+    return;
+  }
+  LOG(VERBOSE) << "Found version: " << version_string;
+  availability->egl_version = version_string;
+
+  const std::string vendor_string = eglQueryString(display, EGL_VENDOR);
+  if (vendor_string.empty()) {
+    LOG(VERBOSE) << "Failed to query vendor.";
+    return;
+  }
+  LOG(VERBOSE) << "Found vendor: " << vendor_string;
+  availability->egl_vendor = vendor_string;
+
+  const std::string extensions_string = eglQueryString(display, EGL_EXTENSIONS);
+  if (extensions_string.empty()) {
+    LOG(VERBOSE) << "Failed to query extensions.";
+    return;
+  }
+  LOG(VERBOSE) << "Found extensions: " << extensions_string;
+  availability->egl_extensions = extensions_string;
+
+  if (extensions_string.find(kSurfacelessContextExt) == std::string::npos) {
+    LOG(VERBOSE) << "Failed to find extension EGL_KHR_surfaceless_context.";
+    return;
+  }
+
+  const std::string display_apis_string = eglQueryString(display,
+                                                         EGL_CLIENT_APIS);
+  if (display_apis_string.empty()) {
+    LOG(VERBOSE) << "Failed to query display apis.";
+    return;
+  }
+  LOG(VERBOSE) << "Found display apis: " << display_apis_string;
+
+  PFNEGLBINDAPIPROC eglBindAPI =
+    reinterpret_cast<PFNEGLBINDAPIPROC>(EglLoadFunction("eglBindAPI"));
+  if (eglBindAPI == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglBindAPI";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglBindAPI.";
+
+  if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
+    LOG(VERBOSE) << "Failed to bind GLES API.";
+    return;
+  }
+  LOG(VERBOSE) << "Bound GLES API.";
+
+  PFNEGLCHOOSECONFIGPROC eglChooseConfig =
+    reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(
+      EglLoadFunction("eglChooseConfig"));
+  if (eglChooseConfig == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglChooseConfig";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglChooseConfig.";
+
+  const EGLint framebuffer_config_attributes[] = {
+    EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+    EGL_RED_SIZE, 1,
+    EGL_GREEN_SIZE, 1,
+    EGL_BLUE_SIZE, 1,
+    EGL_ALPHA_SIZE, 0,
+    EGL_NONE,
+  };
+
+  EGLConfig framebuffer_config;
+  EGLint num_framebuffer_configs = 0;
+  if (eglChooseConfig(display,
+                      framebuffer_config_attributes,
+                      &framebuffer_config,
+                      1,
+                      &num_framebuffer_configs) != EGL_TRUE) {
+    LOG(VERBOSE) << "Failed to find matching framebuffer config.";
+    return;
+  }
+  LOG(VERBOSE) << "Found matching framebuffer config.";
+
+  PFNEGLCREATECONTEXTPROC eglCreateContext =
+    reinterpret_cast<PFNEGLCREATECONTEXTPROC>(
+      EglLoadFunction("eglCreateContext"));
+  if (eglCreateContext == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglCreateContext";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglCreateContext.";
+
+  PFNEGLDESTROYCONTEXTPROC eglDestroyContext =
+    reinterpret_cast<PFNEGLDESTROYCONTEXTPROC>(
+      EglLoadFunction("eglDestroyContext"));
+  if (eglDestroyContext == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglDestroyContext";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglDestroyContext.";
+
+  const EGLint context_attributes[] = {
+    EGL_CONTEXT_CLIENT_VERSION, 2,
+    EGL_NONE
+  };
+
+  EGLContext context = eglCreateContext(display,
+                                        framebuffer_config,
+                                        EGL_NO_CONTEXT,
+                                        context_attributes);
+  if (context == EGL_NO_CONTEXT) {
+    LOG(VERBOSE) << "Failed to create EGL context.";
+    return;
+  }
+  LOG(VERBOSE) << "Created EGL context.";
+  Closer context_closer([&]() { eglDestroyContext(display, context); });
+
+  PFNEGLMAKECURRENTPROC eglMakeCurrent =
+    reinterpret_cast<PFNEGLMAKECURRENTPROC>(EglLoadFunction("eglMakeCurrent"));
+  if (eglMakeCurrent == nullptr) {
+    LOG(VERBOSE) << "Failed to find function eglMakeCurrent";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded eglMakeCurrent.";
+
+  if (eglMakeCurrent(display,
+                     EGL_NO_SURFACE,
+                     EGL_NO_SURFACE,
+                     context) != EGL_TRUE) {
+    LOG(VERBOSE) << "Failed to make EGL context current.";
+    return;
+  }
+  LOG(VERBOSE) << "Make EGL context current.";
+  availability->has_egl_surfaceless_with_gles = true;
+}
+
+void PopulateVulkanAvailability(GraphicsAvailability* availability) {
+  ManagedLibrary vklib(dlopen(kVulkanLib, RTLD_NOW | RTLD_LOCAL));
+  if (!vklib) {
+    LOG(VERBOSE) << "Failed to dlopen " << kVulkanLib << ".";
+    return;
+  }
+  LOG(VERBOSE) << "Loaded " << kVulkanLib << ".";
+  availability->has_vulkan = true;
+
+  uint32_t instance_version = 0;
+
+  PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
+      reinterpret_cast<PFN_vkGetInstanceProcAddr>(
+          dlsym(vklib.get(), "vkGetInstanceProcAddr"));
+  if (vkGetInstanceProcAddr == nullptr) {
+    LOG(VERBOSE) << "Failed to find symbol vkGetInstanceProcAddr.";
+    return;
+  }
+
+  PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion =
+      reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
+          dlsym(vklib.get(), "vkEnumerateInstanceVersion"));
+  if (vkEnumerateInstanceVersion == nullptr ||
+      vkEnumerateInstanceVersion(&instance_version) != VK_SUCCESS) {
+    instance_version = VK_API_VERSION_1_0;
+  }
+
+  PFN_vkCreateInstance vkCreateInstance =
+    reinterpret_cast<PFN_vkCreateInstance>(
+      vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance"));
+  if (vkCreateInstance == nullptr) {
+    LOG(VERBOSE) << "Failed to get function vkCreateInstance.";
+    return;
+  }
+
+  VkApplicationInfo application_info;
+  application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+  application_info.pNext = nullptr;
+  application_info.pApplicationName = "";
+  application_info.applicationVersion = 1;
+  application_info.pEngineName = "";
+  application_info.engineVersion = 1;
+  application_info.apiVersion = instance_version;
+
+  VkInstanceCreateInfo instance_create_info = {};
+  instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+  instance_create_info.pNext = nullptr;
+  instance_create_info.flags = 0;
+  instance_create_info.pApplicationInfo = &application_info;
+  instance_create_info.enabledLayerCount = 0;
+  instance_create_info.ppEnabledLayerNames = nullptr;
+  instance_create_info.enabledExtensionCount = 0;
+  instance_create_info.ppEnabledExtensionNames = nullptr;
+
+  VkInstance instance = VK_NULL_HANDLE;
+  VkResult result = vkCreateInstance(&instance_create_info, nullptr, &instance);
+  if (result != VK_SUCCESS) {
+    if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
+      LOG(VERBOSE) << "Failed to create Vulkan instance: "
+                   << "VK_ERROR_OUT_OF_HOST_MEMORY.";
+    } else if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
+      LOG(VERBOSE) << "Failed to create Vulkan instance: "
+                   << "VK_ERROR_OUT_OF_DEVICE_MEMORY.";
+    } else if (result == VK_ERROR_INITIALIZATION_FAILED) {
+      LOG(VERBOSE) << "Failed to create Vulkan instance: "
+                   << "VK_ERROR_INITIALIZATION_FAILED.";
+    } else if (result == VK_ERROR_LAYER_NOT_PRESENT) {
+      LOG(VERBOSE) << "Failed to create Vulkan instance: "
+                   << "VK_ERROR_LAYER_NOT_PRESENT.";
+    } else if (result == VK_ERROR_EXTENSION_NOT_PRESENT) {
+      LOG(VERBOSE) << "Failed to create Vulkan instance: "
+                   << "VK_ERROR_EXTENSION_NOT_PRESENT.";
+    } else if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
+      LOG(VERBOSE) << "Failed to create Vulkan instance: "
+                   << "VK_ERROR_INCOMPATIBLE_DRIVER.";
+    } else {
+      LOG(VERBOSE) << "Failed to create Vulkan instance.";
+    }
+    return;
+  }
+
+  PFN_vkDestroyInstance vkDestroyInstance =
+    reinterpret_cast<PFN_vkDestroyInstance>(
+      vkGetInstanceProcAddr(instance, "vkDestroyInstance"));
+  if (vkDestroyInstance == nullptr) {
+    LOG(VERBOSE) << "Failed to get function vkDestroyInstance.";
+    return;
+  }
+
+  Closer instancecloser([&]() {vkDestroyInstance(instance, nullptr); });
+
+  PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices =
+    reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(
+      vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"));
+  if (vkEnumeratePhysicalDevices == nullptr) {
+    LOG(VERBOSE) << "Failed to "
+                 << "vkGetInstanceProcAddr(vkEnumeratePhysicalDevices).";
+    return;
+  }
+
+  PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties =
+    reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
+      vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties"));
+  if (vkGetPhysicalDeviceProperties == nullptr) {
+    LOG(VERBOSE) << "Failed to "
+                 << "vkGetInstanceProcAddr(vkGetPhysicalDeviceProperties).";
+    return;
+  }
+
+  auto vkEnumerateDeviceExtensionProperties =
+    reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
+      vkGetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties"));
+  if (vkEnumerateDeviceExtensionProperties == nullptr) {
+    LOG(VERBOSE) << "Failed to "
+                 << "vkGetInstanceProcAddr("
+                 << "vkEnumerateDeviceExtensionProperties"
+                 << ").";
+    return;
+  }
+
+  uint32_t device_count = 0;
+  result = vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
+  if (result != VK_SUCCESS) {
+    if (result == VK_INCOMPLETE) {
+      LOG(VERBOSE) << "Failed to enumerate physical device count: "
+                   << "VK_INCOMPLETE";
+    } else if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
+      LOG(VERBOSE) << "Failed to enumerate physical device count: "
+                   << "VK_ERROR_OUT_OF_HOST_MEMORY";
+    } else if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
+      LOG(VERBOSE) << "Failed to enumerate physical device count: "
+                   << "VK_ERROR_OUT_OF_DEVICE_MEMORY";
+    } else if (result == VK_ERROR_INITIALIZATION_FAILED) {
+      LOG(VERBOSE) << "Failed to enumerate physical device count: "
+                   << "VK_ERROR_INITIALIZATION_FAILED";
+    } else {
+      LOG(VERBOSE) << "Failed to enumerate physical device count.";
+    }
+    return;
+  }
+
+  if (device_count == 0) {
+    LOG(VERBOSE) << "No physical devices present.";
+    return;
+  }
+
+  std::vector<VkPhysicalDevice> devices(device_count, VK_NULL_HANDLE);
+  result = vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
+  if (result != VK_SUCCESS) {
+    LOG(VERBOSE) << "Failed to enumerate physical devices.";
+    return;
+  }
+
+  for (VkPhysicalDevice device : devices) {
+    VkPhysicalDeviceProperties device_properties = {};
+    vkGetPhysicalDeviceProperties(device, &device_properties);
+
+    uint32_t device_extensions_count = 0;
+    vkEnumerateDeviceExtensionProperties(device,
+                                         nullptr,
+                                         &device_extensions_count,
+                                         nullptr);
+
+    std::vector<VkExtensionProperties> device_extensions;
+    device_extensions.resize(device_extensions_count);
+
+    vkEnumerateDeviceExtensionProperties(device,
+                                         nullptr,
+                                         &device_extensions_count,
+                                         device_extensions.data());
+
+    std::vector<const char*> device_extensions_strings;
+    for (const VkExtensionProperties& device_extension : device_extensions) {
+      device_extensions_strings.push_back(device_extension.extensionName);
+    }
+
+    std::string device_extensions_string =
+      android::base::Join(device_extensions_strings, ' ');
+
+    if (device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
+      availability->has_discrete_gpu = true;
+      availability->discrete_gpu_device_name = device_properties.deviceName;
+      availability->discrete_gpu_device_extensions = device_extensions_string;
+      break;
+    }
+  }
+}
+
+GraphicsAvailability GetGraphicsAvailability() {
+  GraphicsAvailability availability;
+
+  PopulateEglAvailability(&availability);
+  PopulateGlAvailability(&availability);
+  PopulateGles1Availability(&availability);
+  PopulateGles2Availability(&availability);
+  PopulateVulkanAvailability(&availability);
+
+  return availability;
+}
+
+}  // namespace
+
+bool ShouldEnableAcceleratedRendering(
+    const GraphicsAvailability& availability) {
+  return availability.has_egl && availability.has_egl_surfaceless_with_gles &&
+         availability.has_discrete_gpu;
+}
+
+// Runs GetGraphicsAvailability() inside of a subprocess first to ensure that
+// GetGraphicsAvailability() can complete successfully without crashing
+// assemble_cvd. Configurations such as GCE instances without a GPU but with GPU
+// drivers for example have seen crashes.
+GraphicsAvailability GetGraphicsAvailabilityWithSubprocessCheck() {
+  pid_t pid = fork();
+  if (pid == 0) {
+    GetGraphicsAvailability();
+    std::exit(0);
+  }
+  int status;
+  if (waitpid(pid, &status, 0) != pid) {
+    PLOG(ERROR) << "Failed to wait for graphics check subprocess";
+    return GraphicsAvailability{};
+  }
+  if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+    return GetGraphicsAvailability();
+  }
+  LOG(VERBOSE) << "Subprocess for detect_graphics failed with " << status;
+  return GraphicsAvailability{};
+}
+
+std::ostream& operator<<(std::ostream& stream,
+                         const GraphicsAvailability& availability) {
+  std::ios_base::fmtflags flags_backup(stream.flags());
+  stream << std::boolalpha;
+  stream << "Graphics Availability:\n";
+  stream << "OpenGL available: " << availability.has_gl << "\n";
+  stream << "OpenGL ES1 available: " << availability.has_gles1 << "\n";
+  stream << "OpenGL ES2 available: " << availability.has_gles2 << "\n";
+  stream << "EGL available: " << availability.has_egl << "\n";
+  stream << "EGL client extensions: " << availability.egl_client_extensions
+         << "\n";
+  stream << "EGL default display available: "
+         << availability.has_egl_default_display << "\n";
+  stream << "EGL display vendor: " << availability.egl_vendor << "\n";
+  stream << "EGL display version: " << availability.egl_version << "\n";
+  stream << "EGL display extensions: " << availability.egl_extensions << "\n";
+  stream << "EGL surfaceless display with GLES: "
+         << availability.has_egl_surfaceless_with_gles << "\n";
+  stream << "Vulkan available: " << availability.has_vulkan << "\n";
+  stream << "Vulkan discrete GPU detected: " << availability.has_discrete_gpu
+         << "\n";
+  if (availability.has_discrete_gpu) {
+    stream << "Vulkan discrete GPU device name: "
+           << availability.discrete_gpu_device_name << "\n";
+    stream << "Vulkan discrete GPU device extensions: "
+           << availability.discrete_gpu_device_extensions << "\n";
+  }
+  stream.flags(flags_backup);
+  return stream;
+}
+
+} // namespace cuttlefish
diff --git a/host/libs/graphics_detector/graphics_detector.h b/host/libs/graphics_detector/graphics_detector.h
new file mode 100644
index 0000000..83a7068
--- /dev/null
+++ b/host/libs/graphics_detector/graphics_detector.h
@@ -0,0 +1,45 @@
+/*
+ * 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 <ostream>
+#include <string>
+
+namespace cuttlefish {
+
+struct GraphicsAvailability {
+  bool has_gl = false;
+  bool has_gles1 = false;
+  bool has_gles2 = false;
+  bool has_egl = false;
+  bool has_egl_default_display = false;
+  std::string egl_client_extensions;
+  std::string egl_version;
+  std::string egl_vendor;
+  std::string egl_extensions;
+  bool has_egl_surfaceless_with_gles = false;
+  bool has_vulkan = false;
+  bool has_discrete_gpu = false;
+  std::string discrete_gpu_device_name;
+  std::string discrete_gpu_device_extensions;
+};
+
+bool ShouldEnableAcceleratedRendering(const GraphicsAvailability& availability);
+GraphicsAvailability GetGraphicsAvailabilityWithSubprocessCheck();
+
+std::ostream& operator<<(std::ostream& out, const GraphicsAvailability& info);
+
+}  // namespace cuttlefish
diff --git a/host/libs/graphics_detector/include/EGL/egl.h b/host/libs/graphics_detector/include/EGL/egl.h
new file mode 100644
index 0000000..e5dd15b
--- /dev/null
+++ b/host/libs/graphics_detector/include/EGL/egl.h
@@ -0,0 +1,361 @@
+#ifndef __egl_h_
+#define __egl_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2017 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos EGL XML API Registry.
+** The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+**   http://www.khronos.org/registry/egl
+**
+** Khronos $Git commit SHA1: b5409265f3 $ on $Git commit date: 2020-02-20 08:24:34 -0800 $
+*/
+
+#include <EGL/eglplatform.h>
+
+#ifndef EGL_EGL_PROTOTYPES
+#define EGL_EGL_PROTOTYPES 1
+#endif
+
+/* Generated on date 20200220 */
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: .*
+ * Default extensions included: None
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_VERSION_1_0
+#define EGL_VERSION_1_0 1
+typedef unsigned int EGLBoolean;
+typedef void *EGLDisplay;
+#include <KHR/khrplatform.h>
+#include <EGL/eglplatform.h>
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+#define EGL_ALPHA_SIZE                    0x3021
+#define EGL_BAD_ACCESS                    0x3002
+#define EGL_BAD_ALLOC                     0x3003
+#define EGL_BAD_ATTRIBUTE                 0x3004
+#define EGL_BAD_CONFIG                    0x3005
+#define EGL_BAD_CONTEXT                   0x3006
+#define EGL_BAD_CURRENT_SURFACE           0x3007
+#define EGL_BAD_DISPLAY                   0x3008
+#define EGL_BAD_MATCH                     0x3009
+#define EGL_BAD_NATIVE_PIXMAP             0x300A
+#define EGL_BAD_NATIVE_WINDOW             0x300B
+#define EGL_BAD_PARAMETER                 0x300C
+#define EGL_BAD_SURFACE                   0x300D
+#define EGL_BLUE_SIZE                     0x3022
+#define EGL_BUFFER_SIZE                   0x3020
+#define EGL_CONFIG_CAVEAT                 0x3027
+#define EGL_CONFIG_ID                     0x3028
+#define EGL_CORE_NATIVE_ENGINE            0x305B
+#define EGL_DEPTH_SIZE                    0x3025
+#define EGL_DONT_CARE                     EGL_CAST(EGLint,-1)
+#define EGL_DRAW                          0x3059
+#define EGL_EXTENSIONS                    0x3055
+#define EGL_FALSE                         0
+#define EGL_GREEN_SIZE                    0x3023
+#define EGL_HEIGHT                        0x3056
+#define EGL_LARGEST_PBUFFER               0x3058
+#define EGL_LEVEL                         0x3029
+#define EGL_MAX_PBUFFER_HEIGHT            0x302A
+#define EGL_MAX_PBUFFER_PIXELS            0x302B
+#define EGL_MAX_PBUFFER_WIDTH             0x302C
+#define EGL_NATIVE_RENDERABLE             0x302D
+#define EGL_NATIVE_VISUAL_ID              0x302E
+#define EGL_NATIVE_VISUAL_TYPE            0x302F
+#define EGL_NONE                          0x3038
+#define EGL_NON_CONFORMANT_CONFIG         0x3051
+#define EGL_NOT_INITIALIZED               0x3001
+#define EGL_NO_CONTEXT                    EGL_CAST(EGLContext,0)
+#define EGL_NO_DISPLAY                    EGL_CAST(EGLDisplay,0)
+#define EGL_NO_SURFACE                    EGL_CAST(EGLSurface,0)
+#define EGL_PBUFFER_BIT                   0x0001
+#define EGL_PIXMAP_BIT                    0x0002
+#define EGL_READ                          0x305A
+#define EGL_RED_SIZE                      0x3024
+#define EGL_SAMPLES                       0x3031
+#define EGL_SAMPLE_BUFFERS                0x3032
+#define EGL_SLOW_CONFIG                   0x3050
+#define EGL_STENCIL_SIZE                  0x3026
+#define EGL_SUCCESS                       0x3000
+#define EGL_SURFACE_TYPE                  0x3033
+#define EGL_TRANSPARENT_BLUE_VALUE        0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE       0x3036
+#define EGL_TRANSPARENT_RED_VALUE         0x3037
+#define EGL_TRANSPARENT_RGB               0x3052
+#define EGL_TRANSPARENT_TYPE              0x3034
+#define EGL_TRUE                          1
+#define EGL_VENDOR                        0x3053
+#define EGL_VERSION                       0x3054
+#define EGL_WIDTH                         0x3057
+#define EGL_WINDOW_BIT                    0x0004
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCHOOSECONFIGPROC) (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOPYBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+typedef EGLContext (EGLAPIENTRYP PFNEGLCREATECONTEXTPROC) (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERSURFACEPROC) (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGATTRIBPROC) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGSPROC) (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETCURRENTDISPLAYPROC) (void);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLGETCURRENTSURFACEPROC) (EGLint readdraw);
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDISPLAYPROC) (EGLNativeDisplayType display_id);
+typedef EGLint (EGLAPIENTRYP PFNEGLGETERRORPROC) (void);
+typedef __eglMustCastToProperFunctionPointerType (EGLAPIENTRYP PFNEGLGETPROCADDRESSPROC) (const char *procname);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLINITIALIZEPROC) (EGLDisplay dpy, EGLint *major, EGLint *minor);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLMAKECURRENTPROC) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLTERMINATEPROC) (EGLDisplay dpy);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITGLPROC) (void);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITNATIVEPROC) (EGLint engine);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);
+EGLAPI EGLint EGLAPIENTRY eglGetError (void);
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+EGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);
+#endif
+#endif /* EGL_VERSION_1_0 */
+
+#ifndef EGL_VERSION_1_1
+#define EGL_VERSION_1_1 1
+#define EGL_BACK_BUFFER                   0x3084
+#define EGL_BIND_TO_TEXTURE_RGB           0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA          0x303A
+#define EGL_CONTEXT_LOST                  0x300E
+#define EGL_MIN_SWAP_INTERVAL             0x303B
+#define EGL_MAX_SWAP_INTERVAL             0x303C
+#define EGL_MIPMAP_TEXTURE                0x3082
+#define EGL_MIPMAP_LEVEL                  0x3083
+#define EGL_NO_TEXTURE                    0x305C
+#define EGL_TEXTURE_2D                    0x305F
+#define EGL_TEXTURE_FORMAT                0x3080
+#define EGL_TEXTURE_RGB                   0x305D
+#define EGL_TEXTURE_RGBA                  0x305E
+#define EGL_TEXTURE_TARGET                0x3081
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDTEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSURFACEATTRIBPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPINTERVALPROC) (EGLDisplay dpy, EGLint interval);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);
+#endif
+#endif /* EGL_VERSION_1_1 */
+
+#ifndef EGL_VERSION_1_2
+#define EGL_VERSION_1_2 1
+typedef unsigned int EGLenum;
+typedef void *EGLClientBuffer;
+#define EGL_ALPHA_FORMAT                  0x3088
+#define EGL_ALPHA_FORMAT_NONPRE           0x308B
+#define EGL_ALPHA_FORMAT_PRE              0x308C
+#define EGL_ALPHA_MASK_SIZE               0x303E
+#define EGL_BUFFER_PRESERVED              0x3094
+#define EGL_BUFFER_DESTROYED              0x3095
+#define EGL_CLIENT_APIS                   0x308D
+#define EGL_COLORSPACE                    0x3087
+#define EGL_COLORSPACE_sRGB               0x3089
+#define EGL_COLORSPACE_LINEAR             0x308A
+#define EGL_COLOR_BUFFER_TYPE             0x303F
+#define EGL_CONTEXT_CLIENT_TYPE           0x3097
+#define EGL_DISPLAY_SCALING               10000
+#define EGL_HORIZONTAL_RESOLUTION         0x3090
+#define EGL_LUMINANCE_BUFFER              0x308F
+#define EGL_LUMINANCE_SIZE                0x303D
+#define EGL_OPENGL_ES_BIT                 0x0001
+#define EGL_OPENVG_BIT                    0x0002
+#define EGL_OPENGL_ES_API                 0x30A0
+#define EGL_OPENVG_API                    0x30A1
+#define EGL_OPENVG_IMAGE                  0x3096
+#define EGL_PIXEL_ASPECT_RATIO            0x3092
+#define EGL_RENDERABLE_TYPE               0x3040
+#define EGL_RENDER_BUFFER                 0x3086
+#define EGL_RGB_BUFFER                    0x308E
+#define EGL_SINGLE_BUFFER                 0x3085
+#define EGL_SWAP_BEHAVIOR                 0x3093
+#define EGL_UNKNOWN                       EGL_CAST(EGLint,-1)
+#define EGL_VERTICAL_RESOLUTION           0x3091
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDAPIPROC) (EGLenum api);
+typedef EGLenum (EGLAPIENTRYP PFNEGLQUERYAPIPROC) (void);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETHREADPROC) (void);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITCLIENTPROC) (void);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);
+#endif
+#endif /* EGL_VERSION_1_2 */
+
+#ifndef EGL_VERSION_1_3
+#define EGL_VERSION_1_3 1
+#define EGL_CONFORMANT                    0x3042
+#define EGL_CONTEXT_CLIENT_VERSION        0x3098
+#define EGL_MATCH_NATIVE_PIXMAP           0x3041
+#define EGL_OPENGL_ES2_BIT                0x0004
+#define EGL_VG_ALPHA_FORMAT               0x3088
+#define EGL_VG_ALPHA_FORMAT_NONPRE        0x308B
+#define EGL_VG_ALPHA_FORMAT_PRE           0x308C
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT       0x0040
+#define EGL_VG_COLORSPACE                 0x3087
+#define EGL_VG_COLORSPACE_sRGB            0x3089
+#define EGL_VG_COLORSPACE_LINEAR          0x308A
+#define EGL_VG_COLORSPACE_LINEAR_BIT      0x0020
+#endif /* EGL_VERSION_1_3 */
+
+#ifndef EGL_VERSION_1_4
+#define EGL_VERSION_1_4 1
+#define EGL_DEFAULT_DISPLAY               EGL_CAST(EGLNativeDisplayType,0)
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT   0x0200
+#define EGL_MULTISAMPLE_RESOLVE           0x3099
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT   0x309A
+#define EGL_MULTISAMPLE_RESOLVE_BOX       0x309B
+#define EGL_OPENGL_API                    0x30A2
+#define EGL_OPENGL_BIT                    0x0008
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT   0x0400
+typedef EGLContext (EGLAPIENTRYP PFNEGLGETCURRENTCONTEXTPROC) (void);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
+#endif
+#endif /* EGL_VERSION_1_4 */
+
+#ifndef EGL_VERSION_1_5
+#define EGL_VERSION_1_5 1
+typedef void *EGLSync;
+typedef intptr_t EGLAttrib;
+typedef khronos_utime_nanoseconds_t EGLTime;
+typedef void *EGLImage;
+#define EGL_CONTEXT_MAJOR_VERSION         0x3098
+#define EGL_CONTEXT_MINOR_VERSION         0x30FB
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK   0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
+#define EGL_NO_RESET_NOTIFICATION         0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET         0x31BF
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define EGL_CONTEXT_OPENGL_DEBUG          0x31B0
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS  0x31B2
+#define EGL_OPENGL_ES3_BIT                0x00000040
+#define EGL_CL_EVENT_HANDLE               0x309C
+#define EGL_SYNC_CL_EVENT                 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE        0x30FF
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE  0x30F0
+#define EGL_SYNC_TYPE                     0x30F7
+#define EGL_SYNC_STATUS                   0x30F1
+#define EGL_SYNC_CONDITION                0x30F8
+#define EGL_SIGNALED                      0x30F2
+#define EGL_UNSIGNALED                    0x30F3
+#define EGL_SYNC_FLUSH_COMMANDS_BIT       0x0001
+#define EGL_FOREVER                       0xFFFFFFFFFFFFFFFFull
+#define EGL_TIMEOUT_EXPIRED               0x30F5
+#define EGL_CONDITION_SATISFIED           0x30F6
+#define EGL_NO_SYNC                       EGL_CAST(EGLSync,0)
+#define EGL_SYNC_FENCE                    0x30F9
+#define EGL_GL_COLORSPACE                 0x309D
+#define EGL_GL_COLORSPACE_SRGB            0x3089
+#define EGL_GL_COLORSPACE_LINEAR          0x308A
+#define EGL_GL_RENDERBUFFER               0x30B9
+#define EGL_GL_TEXTURE_2D                 0x30B1
+#define EGL_GL_TEXTURE_LEVEL              0x30BC
+#define EGL_GL_TEXTURE_3D                 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET            0x30BD
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
+#define EGL_IMAGE_PRESERVED               0x30D2
+#define EGL_NO_IMAGE                      EGL_CAST(EGLImage,0)
+typedef EGLSync (EGLAPIENTRYP PFNEGLCREATESYNCPROC) (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCPROC) (EGLDisplay dpy, EGLSync sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBPROC) (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
+typedef EGLImage (EGLAPIENTRYP PFNEGLCREATEIMAGEPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEPROC) (EGLDisplay dpy, EGLImage image);
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYPROC) (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);
+#endif
+#endif /* EGL_VERSION_1_5 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/host/libs/graphics_detector/include/EGL/eglext.h b/host/libs/graphics_detector/include/EGL/eglext.h
new file mode 100644
index 0000000..73c1595
--- /dev/null
+++ b/host/libs/graphics_detector/include/EGL/eglext.h
@@ -0,0 +1,1409 @@
+#ifndef __eglext_h_
+#define __eglext_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2017 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos EGL XML API Registry.
+** The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+**   http://www.khronos.org/registry/egl
+**
+** Khronos $Git commit SHA1: b5409265f3 $ on $Git commit date: 2020-02-20 08:24:34 -0800 $
+*/
+
+#include <EGL/eglplatform.h>
+
+#define EGL_EGLEXT_VERSION 20200220
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: _nomatch_^
+ * Default extensions included: egl
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_KHR_cl_event
+#define EGL_KHR_cl_event 1
+#define EGL_CL_EVENT_HANDLE_KHR           0x309C
+#define EGL_SYNC_CL_EVENT_KHR             0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE_KHR    0x30FF
+#endif /* EGL_KHR_cl_event */
+
+#ifndef EGL_KHR_cl_event2
+#define EGL_KHR_cl_event2 1
+typedef void *EGLSyncKHR;
+typedef intptr_t EGLAttribKHR;
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#endif
+#endif /* EGL_KHR_cl_event2 */
+
+#ifndef EGL_KHR_client_get_all_proc_addresses
+#define EGL_KHR_client_get_all_proc_addresses 1
+#endif /* EGL_KHR_client_get_all_proc_addresses */
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR                0x3042
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR  0x0020
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR   0x0040
+#endif /* EGL_KHR_config_attribs */
+
+#ifndef EGL_KHR_context_flush_control
+#define EGL_KHR_context_flush_control 1
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR  0x2097
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
+#endif /* EGL_KHR_context_flush_control */
+
+#ifndef EGL_KHR_create_context
+#define EGL_KHR_create_context 1
+#define EGL_CONTEXT_MAJOR_VERSION_KHR     0x3098
+#define EGL_CONTEXT_MINOR_VERSION_KHR     0x30FB
+#define EGL_CONTEXT_FLAGS_KHR             0x30FC
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
+#define EGL_NO_RESET_NOTIFICATION_KHR     0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_KHR     0x31BF
+#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR  0x00000001
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
+#define EGL_OPENGL_ES3_BIT_KHR            0x00000040
+#endif /* EGL_KHR_create_context */
+
+#ifndef EGL_KHR_create_context_no_error
+#define EGL_KHR_create_context_no_error 1
+#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR   0x31B3
+#endif /* EGL_KHR_create_context_no_error */
+
+#ifndef EGL_KHR_debug
+#define EGL_KHR_debug 1
+typedef void *EGLLabelKHR;
+typedef void *EGLObjectKHR;
+typedef void (EGLAPIENTRY  *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);
+#define EGL_OBJECT_THREAD_KHR             0x33B0
+#define EGL_OBJECT_DISPLAY_KHR            0x33B1
+#define EGL_OBJECT_CONTEXT_KHR            0x33B2
+#define EGL_OBJECT_SURFACE_KHR            0x33B3
+#define EGL_OBJECT_IMAGE_KHR              0x33B4
+#define EGL_OBJECT_SYNC_KHR               0x33B5
+#define EGL_OBJECT_STREAM_KHR             0x33B6
+#define EGL_DEBUG_MSG_CRITICAL_KHR        0x33B9
+#define EGL_DEBUG_MSG_ERROR_KHR           0x33BA
+#define EGL_DEBUG_MSG_WARN_KHR            0x33BB
+#define EGL_DEBUG_MSG_INFO_KHR            0x33BC
+#define EGL_DEBUG_CALLBACK_KHR            0x33B8
+typedef EGLint (EGLAPIENTRYP PFNEGLDEBUGMESSAGECONTROLKHRPROC) (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEBUGKHRPROC) (EGLint attribute, EGLAttrib *value);
+typedef EGLint (EGLAPIENTRYP PFNEGLLABELOBJECTKHRPROC) (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDebugMessageControlKHR (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDebugKHR (EGLint attribute, EGLAttrib *value);
+EGLAPI EGLint EGLAPIENTRY eglLabelObjectKHR (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);
+#endif
+#endif /* EGL_KHR_debug */
+
+#ifndef EGL_KHR_display_reference
+#define EGL_KHR_display_reference 1
+#define EGL_TRACK_REFERENCES_KHR          0x3352
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBKHRPROC) (EGLDisplay dpy, EGLint name, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribKHR (EGLDisplay dpy, EGLint name, EGLAttrib *value);
+#endif
+#endif /* EGL_KHR_display_reference */
+
+#ifndef EGL_KHR_fence_sync
+#define EGL_KHR_fence_sync 1
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
+#define EGL_SYNC_CONDITION_KHR            0x30F8
+#define EGL_SYNC_FENCE_KHR                0x30F9
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR (EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_fence_sync */
+
+#ifndef EGL_KHR_get_all_proc_addresses
+#define EGL_KHR_get_all_proc_addresses 1
+#endif /* EGL_KHR_get_all_proc_addresses */
+
+#ifndef EGL_KHR_gl_colorspace
+#define EGL_KHR_gl_colorspace 1
+#define EGL_GL_COLORSPACE_KHR             0x309D
+#define EGL_GL_COLORSPACE_SRGB_KHR        0x3089
+#define EGL_GL_COLORSPACE_LINEAR_KHR      0x308A
+#endif /* EGL_KHR_gl_colorspace */
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR           0x30B9
+#endif /* EGL_KHR_gl_renderbuffer_image */
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR             0x30B1
+#define EGL_GL_TEXTURE_LEVEL_KHR          0x30BC
+#endif /* EGL_KHR_gl_texture_2D_image */
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR             0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET_KHR        0x30BD
+#endif /* EGL_KHR_gl_texture_3D_image */
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8
+#endif /* EGL_KHR_gl_texture_cubemap_image */
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+typedef void *EGLImageKHR;
+#define EGL_NATIVE_PIXMAP_KHR             0x30B0
+#define EGL_NO_IMAGE_KHR                  EGL_CAST(EGLImageKHR,0)
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif
+#endif /* EGL_KHR_image */
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+#define EGL_IMAGE_PRESERVED_KHR           0x30D2
+#endif /* EGL_KHR_image_base */
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+#endif /* EGL_KHR_image_pixmap */
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR          0x0001
+#define EGL_WRITE_SURFACE_BIT_KHR         0x0002
+#define EGL_LOCK_SURFACE_BIT_KHR          0x0080
+#define EGL_OPTIMAL_FORMAT_BIT_KHR        0x0100
+#define EGL_MATCH_FORMAT_KHR              0x3043
+#define EGL_FORMAT_RGB_565_EXACT_KHR      0x30C0
+#define EGL_FORMAT_RGB_565_KHR            0x30C1
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR    0x30C2
+#define EGL_FORMAT_RGBA_8888_KHR          0x30C3
+#define EGL_MAP_PRESERVE_PIXELS_KHR       0x30C4
+#define EGL_LOCK_USAGE_HINT_KHR           0x30C5
+#define EGL_BITMAP_POINTER_KHR            0x30C6
+#define EGL_BITMAP_PITCH_KHR              0x30C7
+#define EGL_BITMAP_ORIGIN_KHR             0x30C8
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR   0x30C9
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR  0x30CB
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD
+#define EGL_LOWER_LEFT_KHR                0x30CE
+#define EGL_UPPER_LEFT_KHR                0x30CF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay dpy, EGLSurface surface);
+#endif
+#endif /* EGL_KHR_lock_surface */
+
+#ifndef EGL_KHR_lock_surface2
+#define EGL_KHR_lock_surface2 1
+#define EGL_BITMAP_PIXEL_SIZE_KHR         0x3110
+#endif /* EGL_KHR_lock_surface2 */
+
+#ifndef EGL_KHR_lock_surface3
+#define EGL_KHR_lock_surface3 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACE64KHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface64KHR (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#endif
+#endif /* EGL_KHR_lock_surface3 */
+
+#ifndef EGL_KHR_mutable_render_buffer
+#define EGL_KHR_mutable_render_buffer 1
+#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
+#endif /* EGL_KHR_mutable_render_buffer */
+
+#ifndef EGL_KHR_no_config_context
+#define EGL_KHR_no_config_context 1
+#define EGL_NO_CONFIG_KHR                 EGL_CAST(EGLConfig,0)
+#endif /* EGL_KHR_no_config_context */
+
+#ifndef EGL_KHR_partial_update
+#define EGL_KHR_partial_update 1
+#define EGL_BUFFER_AGE_KHR                0x313D
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETDAMAGEREGIONKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_partial_update */
+
+#ifndef EGL_KHR_platform_android
+#define EGL_KHR_platform_android 1
+#define EGL_PLATFORM_ANDROID_KHR          0x3141
+#endif /* EGL_KHR_platform_android */
+
+#ifndef EGL_KHR_platform_gbm
+#define EGL_KHR_platform_gbm 1
+#define EGL_PLATFORM_GBM_KHR              0x31D7
+#endif /* EGL_KHR_platform_gbm */
+
+#ifndef EGL_KHR_platform_wayland
+#define EGL_KHR_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_KHR          0x31D8
+#endif /* EGL_KHR_platform_wayland */
+
+#ifndef EGL_KHR_platform_x11
+#define EGL_KHR_platform_x11 1
+#define EGL_PLATFORM_X11_KHR              0x31D5
+#define EGL_PLATFORM_X11_SCREEN_KHR       0x31D6
+#endif /* EGL_KHR_platform_x11 */
+
+#ifndef EGL_KHR_reusable_sync
+#define EGL_KHR_reusable_sync 1
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_STATUS_KHR               0x30F1
+#define EGL_SIGNALED_KHR                  0x30F2
+#define EGL_UNSIGNALED_KHR                0x30F3
+#define EGL_TIMEOUT_EXPIRED_KHR           0x30F5
+#define EGL_CONDITION_SATISFIED_KHR       0x30F6
+#define EGL_SYNC_TYPE_KHR                 0x30F7
+#define EGL_SYNC_REUSABLE_KHR             0x30FA
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR   0x0001
+#define EGL_FOREVER_KHR                   0xFFFFFFFFFFFFFFFFull
+#define EGL_NO_SYNC_KHR                   EGL_CAST(EGLSyncKHR,0)
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_reusable_sync */
+
+#ifndef EGL_KHR_stream
+#define EGL_KHR_stream 1
+typedef void *EGLStreamKHR;
+typedef khronos_uint64_t EGLuint64KHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_NO_STREAM_KHR                 EGL_CAST(EGLStreamKHR,0)
+#define EGL_CONSUMER_LATENCY_USEC_KHR     0x3210
+#define EGL_PRODUCER_FRAME_KHR            0x3212
+#define EGL_CONSUMER_FRAME_KHR            0x3213
+#define EGL_STREAM_STATE_KHR              0x3214
+#define EGL_STREAM_STATE_CREATED_KHR      0x3215
+#define EGL_STREAM_STATE_CONNECTING_KHR   0x3216
+#define EGL_STREAM_STATE_EMPTY_KHR        0x3217
+#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218
+#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219
+#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A
+#define EGL_BAD_STREAM_KHR                0x321B
+#define EGL_BAD_STATE_KHR                 0x321C
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream */
+
+#ifndef EGL_KHR_stream_attrib
+#define EGL_KHR_stream_attrib 1
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMATTRIBKHRPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribKHR (EGLDisplay dpy, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream_attrib */
+
+#ifndef EGL_KHR_stream_consumer_gltexture
+#define EGL_KHR_stream_consumer_gltexture 1
+#ifdef EGL_KHR_stream
+#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_consumer_gltexture */
+
+#ifndef EGL_KHR_stream_cross_process_fd
+#define EGL_KHR_stream_cross_process_fd 1
+typedef int EGLNativeFileDescriptorKHR;
+#ifdef EGL_KHR_stream
+#define EGL_NO_FILE_DESCRIPTOR_KHR        EGL_CAST(EGLNativeFileDescriptorKHR,-1)
+typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_cross_process_fd */
+
+#ifndef EGL_KHR_stream_fifo
+#define EGL_KHR_stream_fifo 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_FIFO_LENGTH_KHR        0x31FC
+#define EGL_STREAM_TIME_NOW_KHR           0x31FD
+#define EGL_STREAM_TIME_CONSUMER_KHR      0x31FE
+#define EGL_STREAM_TIME_PRODUCER_KHR      0x31FF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_fifo */
+
+#ifndef EGL_KHR_stream_producer_aldatalocator
+#define EGL_KHR_stream_producer_aldatalocator 1
+#ifdef EGL_KHR_stream
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_aldatalocator */
+
+#ifndef EGL_KHR_stream_producer_eglsurface
+#define EGL_KHR_stream_producer_eglsurface 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_BIT_KHR                0x0800
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_eglsurface */
+
+#ifndef EGL_KHR_surfaceless_context
+#define EGL_KHR_surfaceless_context 1
+#endif /* EGL_KHR_surfaceless_context */
+
+#ifndef EGL_KHR_swap_buffers_with_damage
+#define EGL_KHR_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_swap_buffers_with_damage */
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR           0x30BA
+#endif /* EGL_KHR_vg_parent_image */
+
+#ifndef EGL_KHR_wait_sync
+#define EGL_KHR_wait_sync 1
+typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+#endif /* EGL_KHR_wait_sync */
+
+#ifndef EGL_ANDROID_GLES_layers
+#define EGL_ANDROID_GLES_layers 1
+#endif /* EGL_ANDROID_GLES_layers */
+
+#ifndef EGL_ANDROID_blob_cache
+#define EGL_ANDROID_blob_cache 1
+typedef khronos_ssize_t EGLsizeiANDROID;
+typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
+typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#endif
+#endif /* EGL_ANDROID_blob_cache */
+
+#ifndef EGL_ANDROID_create_native_client_buffer
+#define EGL_ANDROID_create_native_client_buffer 1
+#define EGL_NATIVE_BUFFER_USAGE_ANDROID   0x3143
+#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
+#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
+#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC) (const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglCreateNativeClientBufferANDROID (const EGLint *attrib_list);
+#endif
+#endif /* EGL_ANDROID_create_native_client_buffer */
+
+#ifndef EGL_ANDROID_framebuffer_target
+#define EGL_ANDROID_framebuffer_target 1
+#define EGL_FRAMEBUFFER_TARGET_ANDROID    0x3147
+#endif /* EGL_ANDROID_framebuffer_target */
+
+#ifndef EGL_ANDROID_front_buffer_auto_refresh
+#define EGL_ANDROID_front_buffer_auto_refresh 1
+#define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C
+#endif /* EGL_ANDROID_front_buffer_auto_refresh */
+
+#ifndef EGL_ANDROID_get_frame_timestamps
+#define EGL_ANDROID_get_frame_timestamps 1
+typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+#define EGL_TIMESTAMP_PENDING_ANDROID     EGL_CAST(EGLnsecsANDROID,-2)
+#define EGL_TIMESTAMP_INVALID_ANDROID     EGL_CAST(EGLnsecsANDROID,-1)
+#define EGL_TIMESTAMPS_ANDROID            0x3430
+#define EGL_COMPOSITE_DEADLINE_ANDROID    0x3431
+#define EGL_COMPOSITE_INTERVAL_ANDROID    0x3432
+#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433
+#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434
+#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438
+#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID  0x343A
+#define EGL_DEQUEUE_READY_TIME_ANDROID    0x343B
+#define EGL_READS_DONE_TIME_ANDROID       0x343C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps,  const EGLint *names, EGLnsecsANDROID *values);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETNEXTFRAMEIDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps,  const EGLint *timestamps, EGLnsecsANDROID *values);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetCompositorTimingSupportedANDROID (EGLDisplay dpy, EGLSurface surface, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetCompositorTimingANDROID (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps,  const EGLint *names, EGLnsecsANDROID *values);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetNextFrameIdANDROID (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetFrameTimestampSupportedANDROID (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetFrameTimestampsANDROID (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps,  const EGLint *timestamps, EGLnsecsANDROID *values);
+#endif
+#endif /* EGL_ANDROID_get_frame_timestamps */
+
+#ifndef EGL_ANDROID_get_native_client_buffer
+#define EGL_ANDROID_get_native_client_buffer 1
+struct AHardwareBuffer;
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC) (const struct AHardwareBuffer *buffer);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
+#endif
+#endif /* EGL_ANDROID_get_native_client_buffer */
+
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_ANDROID         0x3140
+#endif /* EGL_ANDROID_image_native_buffer */
+
+#ifndef EGL_ANDROID_native_fence_sync
+#define EGL_ANDROID_native_fence_sync 1
+#define EGL_SYNC_NATIVE_FENCE_ANDROID     0x3144
+#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID  0x3145
+#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID    -1
+typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+#endif /* EGL_ANDROID_native_fence_sync */
+
+#ifndef EGL_ANDROID_presentation_time
+#define EGL_ANDROID_presentation_time 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPresentationTimeANDROID (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
+#endif
+#endif /* EGL_ANDROID_presentation_time */
+
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID            0x3142
+#endif /* EGL_ANDROID_recordable */
+
+#ifndef EGL_ANGLE_d3d_share_handle_client_buffer
+#define EGL_ANGLE_d3d_share_handle_client_buffer 1
+#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+#endif /* EGL_ANGLE_d3d_share_handle_client_buffer */
+
+#ifndef EGL_ANGLE_device_d3d
+#define EGL_ANGLE_device_d3d 1
+#define EGL_D3D9_DEVICE_ANGLE             0x33A0
+#define EGL_D3D11_DEVICE_ANGLE            0x33A1
+#endif /* EGL_ANGLE_device_d3d */
+
+#ifndef EGL_ANGLE_query_surface_pointer
+#define EGL_ANGLE_query_surface_pointer 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+#endif /* EGL_ANGLE_query_surface_pointer */
+
+#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
+#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
+
+#ifndef EGL_ANGLE_window_fixed_size
+#define EGL_ANGLE_window_fixed_size 1
+#define EGL_FIXED_SIZE_ANGLE              0x3201
+#endif /* EGL_ANGLE_window_fixed_size */
+
+#ifndef EGL_ARM_image_format
+#define EGL_ARM_image_format 1
+#define EGL_COLOR_COMPONENT_TYPE_UNSIGNED_INTEGER_ARM 0x3287
+#define EGL_COLOR_COMPONENT_TYPE_INTEGER_ARM 0x3288
+#endif /* EGL_ARM_image_format */
+
+#ifndef EGL_ARM_implicit_external_sync
+#define EGL_ARM_implicit_external_sync 1
+#define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A
+#endif /* EGL_ARM_implicit_external_sync */
+
+#ifndef EGL_ARM_pixmap_multisample_discard
+#define EGL_ARM_pixmap_multisample_discard 1
+#define EGL_DISCARD_SAMPLES_ARM           0x3286
+#endif /* EGL_ARM_pixmap_multisample_discard */
+
+#ifndef EGL_EXT_bind_to_front
+#define EGL_EXT_bind_to_front 1
+#define EGL_FRONT_BUFFER_EXT              0x3464
+#endif /* EGL_EXT_bind_to_front */
+
+#ifndef EGL_EXT_buffer_age
+#define EGL_EXT_buffer_age 1
+#define EGL_BUFFER_AGE_EXT                0x313D
+#endif /* EGL_EXT_buffer_age */
+
+#ifndef EGL_EXT_client_extensions
+#define EGL_EXT_client_extensions 1
+#endif /* EGL_EXT_client_extensions */
+
+#ifndef EGL_EXT_client_sync
+#define EGL_EXT_client_sync 1
+#define EGL_SYNC_CLIENT_EXT               0x3364
+#define EGL_SYNC_CLIENT_SIGNAL_EXT        0x3365
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCLIENTSIGNALSYNCEXTPROC) (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglClientSignalSyncEXT (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_EXT_client_sync */
+
+#ifndef EGL_EXT_compositor
+#define EGL_EXT_compositor 1
+#define EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460
+#define EGL_EXTERNAL_REF_ID_EXT           0x3461
+#define EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT 0x3462
+#define EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT 0x3463
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC) (const EGLint *external_ref_ids, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC) (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWLISTEXTPROC) (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC) (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC) (EGLint external_win_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETSIZEEXTPROC) (EGLint external_win_id, EGLint width, EGLint height);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSWAPPOLICYEXTPROC) (EGLint external_win_id, EGLint policy);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextListEXT (const EGLint *external_ref_ids, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextAttributesEXT (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowListEXT (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowAttributesEXT (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorBindTexWindowEXT (EGLint external_win_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetSizeEXT (EGLint external_win_id, EGLint width, EGLint height);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSwapPolicyEXT (EGLint external_win_id, EGLint policy);
+#endif
+#endif /* EGL_EXT_compositor */
+
+#ifndef EGL_EXT_create_context_robustness
+#define EGL_EXT_create_context_robustness 1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+#define EGL_NO_RESET_NOTIFICATION_EXT     0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_EXT     0x31BF
+#endif /* EGL_EXT_create_context_robustness */
+
+#ifndef EGL_EXT_device_base
+#define EGL_EXT_device_base 1
+typedef void *EGLDeviceEXT;
+#define EGL_NO_DEVICE_EXT                 EGL_CAST(EGLDeviceEXT,0)
+#define EGL_BAD_DEVICE_EXT                0x322B
+#define EGL_DEVICE_EXT                    0x322C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryDeviceStringEXT (EGLDeviceEXT device, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDevicesEXT (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#endif
+#endif /* EGL_EXT_device_base */
+
+#ifndef EGL_EXT_device_drm
+#define EGL_EXT_device_drm 1
+#define EGL_DRM_DEVICE_FILE_EXT           0x3233
+#define EGL_DRM_MASTER_FD_EXT             0x333C
+#endif /* EGL_EXT_device_drm */
+
+#ifndef EGL_EXT_device_enumeration
+#define EGL_EXT_device_enumeration 1
+#endif /* EGL_EXT_device_enumeration */
+
+#ifndef EGL_EXT_device_openwf
+#define EGL_EXT_device_openwf 1
+#define EGL_OPENWF_DEVICE_ID_EXT          0x3237
+#endif /* EGL_EXT_device_openwf */
+
+#ifndef EGL_EXT_device_query
+#define EGL_EXT_device_query 1
+#endif /* EGL_EXT_device_query */
+
+#ifndef EGL_EXT_gl_colorspace_bt2020_linear
+#define EGL_EXT_gl_colorspace_bt2020_linear 1
+#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F
+#endif /* EGL_EXT_gl_colorspace_bt2020_linear */
+
+#ifndef EGL_EXT_gl_colorspace_bt2020_pq
+#define EGL_EXT_gl_colorspace_bt2020_pq 1
+#define EGL_GL_COLORSPACE_BT2020_PQ_EXT   0x3340
+#endif /* EGL_EXT_gl_colorspace_bt2020_pq */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3
+#define EGL_EXT_gl_colorspace_display_p3 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT  0x3363
+#endif /* EGL_EXT_gl_colorspace_display_p3 */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3_linear
+#define EGL_EXT_gl_colorspace_display_p3_linear 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362
+#endif /* EGL_EXT_gl_colorspace_display_p3_linear */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3_passthrough
+#define EGL_EXT_gl_colorspace_display_p3_passthrough 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT 0x3490
+#endif /* EGL_EXT_gl_colorspace_display_p3_passthrough */
+
+#ifndef EGL_EXT_gl_colorspace_scrgb
+#define EGL_EXT_gl_colorspace_scrgb 1
+#define EGL_GL_COLORSPACE_SCRGB_EXT       0x3351
+#endif /* EGL_EXT_gl_colorspace_scrgb */
+
+#ifndef EGL_EXT_gl_colorspace_scrgb_linear
+#define EGL_EXT_gl_colorspace_scrgb_linear 1
+#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350
+#endif /* EGL_EXT_gl_colorspace_scrgb_linear */
+
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_EXT_image_dma_buf_import 1
+#define EGL_LINUX_DMA_BUF_EXT             0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT          0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT         0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT     0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT      0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT         0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT     0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT      0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT         0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT     0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT      0x327A
+#define EGL_YUV_COLOR_SPACE_HINT_EXT      0x327B
+#define EGL_SAMPLE_RANGE_HINT_EXT         0x327C
+#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
+#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E
+#define EGL_ITU_REC601_EXT                0x327F
+#define EGL_ITU_REC709_EXT                0x3280
+#define EGL_ITU_REC2020_EXT               0x3281
+#define EGL_YUV_FULL_RANGE_EXT            0x3282
+#define EGL_YUV_NARROW_RANGE_EXT          0x3283
+#define EGL_YUV_CHROMA_SITING_0_EXT       0x3284
+#define EGL_YUV_CHROMA_SITING_0_5_EXT     0x3285
+#endif /* EGL_EXT_image_dma_buf_import */
+
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+#define EGL_EXT_image_dma_buf_import_modifiers 1
+#define EGL_DMA_BUF_PLANE3_FD_EXT         0x3440
+#define EGL_DMA_BUF_PLANE3_OFFSET_EXT     0x3441
+#define EGL_DMA_BUF_PLANE3_PITCH_EXT      0x3442
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
+#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
+#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
+#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
+#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
+#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
+#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufFormatsEXT (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufModifiersEXT (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#endif
+#endif /* EGL_EXT_image_dma_buf_import_modifiers */
+
+#ifndef EGL_EXT_image_gl_colorspace
+#define EGL_EXT_image_gl_colorspace 1
+#define EGL_GL_COLORSPACE_DEFAULT_EXT     0x314D
+#endif /* EGL_EXT_image_gl_colorspace */
+
+#ifndef EGL_EXT_image_implicit_sync_control
+#define EGL_EXT_image_implicit_sync_control 1
+#define EGL_IMPORT_SYNC_TYPE_EXT          0x3470
+#define EGL_IMPORT_IMPLICIT_SYNC_EXT      0x3471
+#define EGL_IMPORT_EXPLICIT_SYNC_EXT      0x3472
+#endif /* EGL_EXT_image_implicit_sync_control */
+
+#ifndef EGL_EXT_multiview_window
+#define EGL_EXT_multiview_window 1
+#define EGL_MULTIVIEW_VIEW_COUNT_EXT      0x3134
+#endif /* EGL_EXT_multiview_window */
+
+#ifndef EGL_EXT_output_base
+#define EGL_EXT_output_base 1
+typedef void *EGLOutputLayerEXT;
+typedef void *EGLOutputPortEXT;
+#define EGL_NO_OUTPUT_LAYER_EXT           EGL_CAST(EGLOutputLayerEXT,0)
+#define EGL_NO_OUTPUT_PORT_EXT            EGL_CAST(EGLOutputPortEXT,0)
+#define EGL_BAD_OUTPUT_LAYER_EXT          0x322D
+#define EGL_BAD_OUTPUT_PORT_EXT           0x322E
+#define EGL_SWAP_INTERVAL_EXT             0x322F
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTLAYERSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTPORTSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputLayersEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputPortsEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputLayerStringEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputPortStringEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#endif
+#endif /* EGL_EXT_output_base */
+
+#ifndef EGL_EXT_output_drm
+#define EGL_EXT_output_drm 1
+#define EGL_DRM_CRTC_EXT                  0x3234
+#define EGL_DRM_PLANE_EXT                 0x3235
+#define EGL_DRM_CONNECTOR_EXT             0x3236
+#endif /* EGL_EXT_output_drm */
+
+#ifndef EGL_EXT_output_openwf
+#define EGL_EXT_output_openwf 1
+#define EGL_OPENWF_PIPELINE_ID_EXT        0x3238
+#define EGL_OPENWF_PORT_ID_EXT            0x3239
+#endif /* EGL_EXT_output_openwf */
+
+#ifndef EGL_EXT_pixel_format_float
+#define EGL_EXT_pixel_format_float 1
+#define EGL_COLOR_COMPONENT_TYPE_EXT      0x3339
+#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
+#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B
+#endif /* EGL_EXT_pixel_format_float */
+
+#ifndef EGL_EXT_platform_base
+#define EGL_EXT_platform_base 1
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#endif
+#endif /* EGL_EXT_platform_base */
+
+#ifndef EGL_EXT_platform_device
+#define EGL_EXT_platform_device 1
+#define EGL_PLATFORM_DEVICE_EXT           0x313F
+#endif /* EGL_EXT_platform_device */
+
+#ifndef EGL_EXT_platform_wayland
+#define EGL_EXT_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_EXT          0x31D8
+#endif /* EGL_EXT_platform_wayland */
+
+#ifndef EGL_EXT_platform_x11
+#define EGL_EXT_platform_x11 1
+#define EGL_PLATFORM_X11_EXT              0x31D5
+#define EGL_PLATFORM_X11_SCREEN_EXT       0x31D6
+#endif /* EGL_EXT_platform_x11 */
+
+#ifndef EGL_EXT_protected_content
+#define EGL_EXT_protected_content 1
+#define EGL_PROTECTED_CONTENT_EXT         0x32C0
+#endif /* EGL_EXT_protected_content */
+
+#ifndef EGL_EXT_protected_surface
+#define EGL_EXT_protected_surface 1
+#endif /* EGL_EXT_protected_surface */
+
+#ifndef EGL_EXT_stream_consumer_egloutput
+#define EGL_EXT_stream_consumer_egloutput 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerOutputEXT (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#endif
+#endif /* EGL_EXT_stream_consumer_egloutput */
+
+#ifndef EGL_EXT_surface_CTA861_3_metadata
+#define EGL_EXT_surface_CTA861_3_metadata 1
+#define EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT 0x3360
+#define EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT 0x3361
+#endif /* EGL_EXT_surface_CTA861_3_metadata */
+
+#ifndef EGL_EXT_surface_SMPTE2086_metadata
+#define EGL_EXT_surface_SMPTE2086_metadata 1
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346
+#define EGL_SMPTE2086_WHITE_POINT_X_EXT   0x3347
+#define EGL_SMPTE2086_WHITE_POINT_Y_EXT   0x3348
+#define EGL_SMPTE2086_MAX_LUMINANCE_EXT   0x3349
+#define EGL_SMPTE2086_MIN_LUMINANCE_EXT   0x334A
+#define EGL_METADATA_SCALING_EXT          50000
+#endif /* EGL_EXT_surface_SMPTE2086_metadata */
+
+#ifndef EGL_EXT_swap_buffers_with_damage
+#define EGL_EXT_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_EXT_swap_buffers_with_damage */
+
+#ifndef EGL_EXT_sync_reuse
+#define EGL_EXT_sync_reuse 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNSIGNALSYNCEXTPROC) (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglUnsignalSyncEXT (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_EXT_sync_reuse */
+
+#ifndef EGL_EXT_yuv_surface
+#define EGL_EXT_yuv_surface 1
+#define EGL_YUV_ORDER_EXT                 0x3301
+#define EGL_YUV_NUMBER_OF_PLANES_EXT      0x3311
+#define EGL_YUV_SUBSAMPLE_EXT             0x3312
+#define EGL_YUV_DEPTH_RANGE_EXT           0x3317
+#define EGL_YUV_CSC_STANDARD_EXT          0x330A
+#define EGL_YUV_PLANE_BPP_EXT             0x331A
+#define EGL_YUV_BUFFER_EXT                0x3300
+#define EGL_YUV_ORDER_YUV_EXT             0x3302
+#define EGL_YUV_ORDER_YVU_EXT             0x3303
+#define EGL_YUV_ORDER_YUYV_EXT            0x3304
+#define EGL_YUV_ORDER_UYVY_EXT            0x3305
+#define EGL_YUV_ORDER_YVYU_EXT            0x3306
+#define EGL_YUV_ORDER_VYUY_EXT            0x3307
+#define EGL_YUV_ORDER_AYUV_EXT            0x3308
+#define EGL_YUV_SUBSAMPLE_4_2_0_EXT       0x3313
+#define EGL_YUV_SUBSAMPLE_4_2_2_EXT       0x3314
+#define EGL_YUV_SUBSAMPLE_4_4_4_EXT       0x3315
+#define EGL_YUV_DEPTH_RANGE_LIMITED_EXT   0x3318
+#define EGL_YUV_DEPTH_RANGE_FULL_EXT      0x3319
+#define EGL_YUV_CSC_STANDARD_601_EXT      0x330B
+#define EGL_YUV_CSC_STANDARD_709_EXT      0x330C
+#define EGL_YUV_CSC_STANDARD_2020_EXT     0x330D
+#define EGL_YUV_PLANE_BPP_0_EXT           0x331B
+#define EGL_YUV_PLANE_BPP_8_EXT           0x331C
+#define EGL_YUV_PLANE_BPP_10_EXT          0x331D
+#endif /* EGL_EXT_yuv_surface */
+
+#ifndef EGL_HI_clientpixmap
+#define EGL_HI_clientpixmap 1
+struct EGLClientPixmapHI {
+    void  *pData;
+    EGLint iWidth;
+    EGLint iHeight;
+    EGLint iStride;
+};
+#define EGL_CLIENT_PIXMAP_POINTER_HI      0x8F74
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#endif
+#endif /* EGL_HI_clientpixmap */
+
+#ifndef EGL_HI_colorformats
+#define EGL_HI_colorformats 1
+#define EGL_COLOR_FORMAT_HI               0x8F70
+#define EGL_COLOR_RGB_HI                  0x8F71
+#define EGL_COLOR_RGBA_HI                 0x8F72
+#define EGL_COLOR_ARGB_HI                 0x8F73
+#endif /* EGL_HI_colorformats */
+
+#ifndef EGL_IMG_context_priority
+#define EGL_IMG_context_priority 1
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG    0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG     0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG   0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG      0x3103
+#endif /* EGL_IMG_context_priority */
+
+#ifndef EGL_IMG_image_plane_attribs
+#define EGL_IMG_image_plane_attribs 1
+#define EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG 0x3105
+#define EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG 0x3106
+#endif /* EGL_IMG_image_plane_attribs */
+
+#ifndef EGL_MESA_drm_image
+#define EGL_MESA_drm_image 1
+#define EGL_DRM_BUFFER_FORMAT_MESA        0x31D0
+#define EGL_DRM_BUFFER_USE_MESA           0x31D1
+#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2
+#define EGL_DRM_BUFFER_MESA               0x31D3
+#define EGL_DRM_BUFFER_STRIDE_MESA        0x31D4
+#define EGL_DRM_BUFFER_USE_SCANOUT_MESA   0x00000001
+#define EGL_DRM_BUFFER_USE_SHARE_MESA     0x00000002
+#define EGL_DRM_BUFFER_USE_CURSOR_MESA    0x00000004
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#endif
+#endif /* EGL_MESA_drm_image */
+
+#ifndef EGL_MESA_image_dma_buf_export
+#define EGL_MESA_image_dma_buf_export 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageQueryMESA (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageMESA (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#endif
+#endif /* EGL_MESA_image_dma_buf_export */
+
+#ifndef EGL_MESA_platform_gbm
+#define EGL_MESA_platform_gbm 1
+#define EGL_PLATFORM_GBM_MESA             0x31D7
+#endif /* EGL_MESA_platform_gbm */
+
+#ifndef EGL_MESA_platform_surfaceless
+#define EGL_MESA_platform_surfaceless 1
+#define EGL_PLATFORM_SURFACELESS_MESA     0x31DD
+#endif /* EGL_MESA_platform_surfaceless */
+
+#ifndef EGL_MESA_query_driver
+#define EGL_MESA_query_driver 1
+typedef char *(EGLAPIENTRYP PFNEGLGETDISPLAYDRIVERCONFIGPROC) (EGLDisplay dpy);
+typedef const char *(EGLAPIENTRYP PFNEGLGETDISPLAYDRIVERNAMEPROC) (EGLDisplay dpy);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI char *EGLAPIENTRY eglGetDisplayDriverConfig (EGLDisplay dpy);
+EGLAPI const char *EGLAPIENTRY eglGetDisplayDriverName (EGLDisplay dpy);
+#endif
+#endif /* EGL_MESA_query_driver */
+
+#ifndef EGL_NOK_swap_region
+#define EGL_NOK_swap_region 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegionNOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region */
+
+#ifndef EGL_NOK_swap_region2
+#define EGL_NOK_swap_region2 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGION2NOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegion2NOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region2 */
+
+#ifndef EGL_NOK_texture_from_pixmap
+#define EGL_NOK_texture_from_pixmap 1
+#define EGL_Y_INVERTED_NOK                0x307F
+#endif /* EGL_NOK_texture_from_pixmap */
+
+#ifndef EGL_NV_3dvision_surface
+#define EGL_NV_3dvision_surface 1
+#define EGL_AUTO_STEREO_NV                0x3136
+#endif /* EGL_NV_3dvision_surface */
+
+#ifndef EGL_NV_context_priority_realtime
+#define EGL_NV_context_priority_realtime 1
+#define EGL_CONTEXT_PRIORITY_REALTIME_NV  0x3357
+#endif /* EGL_NV_context_priority_realtime */
+
+#ifndef EGL_NV_coverage_sample
+#define EGL_NV_coverage_sample 1
+#define EGL_COVERAGE_BUFFERS_NV           0x30E0
+#define EGL_COVERAGE_SAMPLES_NV           0x30E1
+#endif /* EGL_NV_coverage_sample */
+
+#ifndef EGL_NV_coverage_sample_resolve
+#define EGL_NV_coverage_sample_resolve 1
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NV    0x3131
+#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
+#endif /* EGL_NV_coverage_sample_resolve */
+
+#ifndef EGL_NV_cuda_event
+#define EGL_NV_cuda_event 1
+#define EGL_CUDA_EVENT_HANDLE_NV          0x323B
+#define EGL_SYNC_CUDA_EVENT_NV            0x323C
+#define EGL_SYNC_CUDA_EVENT_COMPLETE_NV   0x323D
+#endif /* EGL_NV_cuda_event */
+
+#ifndef EGL_NV_depth_nonlinear
+#define EGL_NV_depth_nonlinear 1
+#define EGL_DEPTH_ENCODING_NV             0x30E2
+#define EGL_DEPTH_ENCODING_NONE_NV        0
+#define EGL_DEPTH_ENCODING_NONLINEAR_NV   0x30E3
+#endif /* EGL_NV_depth_nonlinear */
+
+#ifndef EGL_NV_device_cuda
+#define EGL_NV_device_cuda 1
+#define EGL_CUDA_DEVICE_NV                0x323A
+#endif /* EGL_NV_device_cuda */
+
+#ifndef EGL_NV_native_query
+#define EGL_NV_native_query 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC) (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#endif
+#endif /* EGL_NV_native_query */
+
+#ifndef EGL_NV_post_convert_rounding
+#define EGL_NV_post_convert_rounding 1
+#endif /* EGL_NV_post_convert_rounding */
+
+#ifndef EGL_NV_post_sub_buffer
+#define EGL_NV_post_sub_buffer 1
+#define EGL_POST_SUB_BUFFER_SUPPORTED_NV  0x30BE
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#endif
+#endif /* EGL_NV_post_sub_buffer */
+
+#ifndef EGL_NV_quadruple_buffer
+#define EGL_NV_quadruple_buffer 1
+#define EGL_QUADRUPLE_BUFFER_NV           0x3231
+#endif /* EGL_NV_quadruple_buffer */
+
+#ifndef EGL_NV_robustness_video_memory_purge
+#define EGL_NV_robustness_video_memory_purge 1
+#define EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C
+#endif /* EGL_NV_robustness_video_memory_purge */
+
+#ifndef EGL_NV_stream_consumer_gltexture_yuv
+#define EGL_NV_stream_consumer_gltexture_yuv 1
+#define EGL_YUV_PLANE0_TEXTURE_UNIT_NV    0x332C
+#define EGL_YUV_PLANE1_TEXTURE_UNIT_NV    0x332D
+#define EGL_YUV_PLANE2_TEXTURE_UNIT_NV    0x332E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalAttribsNV (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_NV_stream_consumer_gltexture_yuv */
+
+#ifndef EGL_NV_stream_cross_display
+#define EGL_NV_stream_cross_display 1
+#define EGL_STREAM_CROSS_DISPLAY_NV       0x334E
+#endif /* EGL_NV_stream_cross_display */
+
+#ifndef EGL_NV_stream_cross_object
+#define EGL_NV_stream_cross_object 1
+#define EGL_STREAM_CROSS_OBJECT_NV        0x334D
+#endif /* EGL_NV_stream_cross_object */
+
+#ifndef EGL_NV_stream_cross_partition
+#define EGL_NV_stream_cross_partition 1
+#define EGL_STREAM_CROSS_PARTITION_NV     0x323F
+#endif /* EGL_NV_stream_cross_partition */
+
+#ifndef EGL_NV_stream_cross_process
+#define EGL_NV_stream_cross_process 1
+#define EGL_STREAM_CROSS_PROCESS_NV       0x3245
+#endif /* EGL_NV_stream_cross_process */
+
+#ifndef EGL_NV_stream_cross_system
+#define EGL_NV_stream_cross_system 1
+#define EGL_STREAM_CROSS_SYSTEM_NV        0x334F
+#endif /* EGL_NV_stream_cross_system */
+
+#ifndef EGL_NV_stream_dma
+#define EGL_NV_stream_dma 1
+#define EGL_STREAM_DMA_NV                 0x3371
+#define EGL_STREAM_DMA_SERVER_NV          0x3372
+#endif /* EGL_NV_stream_dma */
+
+#ifndef EGL_NV_stream_fifo_next
+#define EGL_NV_stream_fifo_next 1
+#define EGL_PENDING_FRAME_NV              0x3329
+#define EGL_STREAM_TIME_PENDING_NV        0x332A
+#endif /* EGL_NV_stream_fifo_next */
+
+#ifndef EGL_NV_stream_fifo_synchronous
+#define EGL_NV_stream_fifo_synchronous 1
+#define EGL_STREAM_FIFO_SYNCHRONOUS_NV    0x3336
+#endif /* EGL_NV_stream_fifo_synchronous */
+
+#ifndef EGL_NV_stream_flush
+#define EGL_NV_stream_flush 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMFLUSHNVPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamFlushNV (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_NV_stream_flush */
+
+#ifndef EGL_NV_stream_frame_limits
+#define EGL_NV_stream_frame_limits 1
+#define EGL_PRODUCER_MAX_FRAME_HINT_NV    0x3337
+#define EGL_CONSUMER_MAX_FRAME_HINT_NV    0x3338
+#endif /* EGL_NV_stream_frame_limits */
+
+#ifndef EGL_NV_stream_metadata
+#define EGL_NV_stream_metadata 1
+#define EGL_MAX_STREAM_METADATA_BLOCKS_NV 0x3250
+#define EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV 0x3251
+#define EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV 0x3252
+#define EGL_PRODUCER_METADATA_NV          0x3253
+#define EGL_CONSUMER_METADATA_NV          0x3254
+#define EGL_PENDING_METADATA_NV           0x3328
+#define EGL_METADATA0_SIZE_NV             0x3255
+#define EGL_METADATA1_SIZE_NV             0x3256
+#define EGL_METADATA2_SIZE_NV             0x3257
+#define EGL_METADATA3_SIZE_NV             0x3258
+#define EGL_METADATA0_TYPE_NV             0x3259
+#define EGL_METADATA1_TYPE_NV             0x325A
+#define EGL_METADATA2_TYPE_NV             0x325B
+#define EGL_METADATA3_TYPE_NV             0x325C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBNVPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribNV (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data);
+#endif
+#endif /* EGL_NV_stream_metadata */
+
+#ifndef EGL_NV_stream_origin
+#define EGL_NV_stream_origin 1
+#define EGL_STREAM_FRAME_ORIGIN_X_NV      0x3366
+#define EGL_STREAM_FRAME_ORIGIN_Y_NV      0x3367
+#define EGL_STREAM_FRAME_MAJOR_AXIS_NV    0x3368
+#define EGL_CONSUMER_AUTO_ORIENTATION_NV  0x3369
+#define EGL_PRODUCER_AUTO_ORIENTATION_NV  0x336A
+#define EGL_LEFT_NV                       0x336B
+#define EGL_RIGHT_NV                      0x336C
+#define EGL_TOP_NV                        0x336D
+#define EGL_BOTTOM_NV                     0x336E
+#define EGL_X_AXIS_NV                     0x336F
+#define EGL_Y_AXIS_NV                     0x3370
+#endif /* EGL_NV_stream_origin */
+
+#ifndef EGL_NV_stream_remote
+#define EGL_NV_stream_remote 1
+#define EGL_STREAM_STATE_INITIALIZING_NV  0x3240
+#define EGL_STREAM_TYPE_NV                0x3241
+#define EGL_STREAM_PROTOCOL_NV            0x3242
+#define EGL_STREAM_ENDPOINT_NV            0x3243
+#define EGL_STREAM_LOCAL_NV               0x3244
+#define EGL_STREAM_PRODUCER_NV            0x3247
+#define EGL_STREAM_CONSUMER_NV            0x3248
+#define EGL_STREAM_PROTOCOL_FD_NV         0x3246
+#endif /* EGL_NV_stream_remote */
+
+#ifndef EGL_NV_stream_reset
+#define EGL_NV_stream_reset 1
+#define EGL_SUPPORT_RESET_NV              0x3334
+#define EGL_SUPPORT_REUSE_NV              0x3335
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLRESETSTREAMNVPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglResetStreamNV (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_NV_stream_reset */
+
+#ifndef EGL_NV_stream_socket
+#define EGL_NV_stream_socket 1
+#define EGL_STREAM_PROTOCOL_SOCKET_NV     0x324B
+#define EGL_SOCKET_HANDLE_NV              0x324C
+#define EGL_SOCKET_TYPE_NV                0x324D
+#endif /* EGL_NV_stream_socket */
+
+#ifndef EGL_NV_stream_socket_inet
+#define EGL_NV_stream_socket_inet 1
+#define EGL_SOCKET_TYPE_INET_NV           0x324F
+#endif /* EGL_NV_stream_socket_inet */
+
+#ifndef EGL_NV_stream_socket_unix
+#define EGL_NV_stream_socket_unix 1
+#define EGL_SOCKET_TYPE_UNIX_NV           0x324E
+#endif /* EGL_NV_stream_socket_unix */
+
+#ifndef EGL_NV_stream_sync
+#define EGL_NV_stream_sync 1
+#define EGL_SYNC_NEW_FRAME_NV             0x321F
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESTREAMSYNCNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateStreamSyncNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#endif
+#endif /* EGL_NV_stream_sync */
+
+#ifndef EGL_NV_sync
+#define EGL_NV_sync 1
+typedef void *EGLSyncNV;
+typedef khronos_utime_nanoseconds_t EGLTimeNV;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
+#define EGL_SYNC_STATUS_NV                0x30E7
+#define EGL_SIGNALED_NV                   0x30E8
+#define EGL_UNSIGNALED_NV                 0x30E9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV    0x0001
+#define EGL_FOREVER_NV                    0xFFFFFFFFFFFFFFFFull
+#define EGL_ALREADY_SIGNALED_NV           0x30EA
+#define EGL_TIMEOUT_EXPIRED_NV            0x30EB
+#define EGL_CONDITION_SATISFIED_NV        0x30EC
+#define EGL_SYNC_TYPE_NV                  0x30ED
+#define EGL_SYNC_CONDITION_NV             0x30EE
+#define EGL_SYNC_FENCE_NV                 0x30EF
+#define EGL_NO_SYNC_NV                    EGL_CAST(EGLSyncNV,0)
+typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync);
+EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_sync */
+
+#ifndef EGL_NV_system_time
+#define EGL_NV_system_time 1
+typedef khronos_utime_nanoseconds_t EGLuint64NV;
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV (void);
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV (void);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_system_time */
+
+#ifndef EGL_NV_triple_buffer
+#define EGL_NV_triple_buffer 1
+#define EGL_TRIPLE_BUFFER_NV              0x3230
+#endif /* EGL_NV_triple_buffer */
+
+#ifndef EGL_TIZEN_image_native_buffer
+#define EGL_TIZEN_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_TIZEN           0x32A0
+#endif /* EGL_TIZEN_image_native_buffer */
+
+#ifndef EGL_TIZEN_image_native_surface
+#define EGL_TIZEN_image_native_surface 1
+#define EGL_NATIVE_SURFACE_TIZEN          0x32A1
+#endif /* EGL_TIZEN_image_native_surface */
+
+#ifndef EGL_WL_bind_wayland_display
+#define EGL_WL_bind_wayland_display 1
+#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC
+#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC
+#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC
+struct wl_display;
+struct wl_resource;
+#define EGL_WAYLAND_BUFFER_WL             0x31D5
+#define EGL_WAYLAND_PLANE_WL              0x31D6
+#define EGL_TEXTURE_Y_U_V_WL              0x31D7
+#define EGL_TEXTURE_Y_UV_WL               0x31D8
+#define EGL_TEXTURE_Y_XUXV_WL             0x31D9
+#define EGL_TEXTURE_EXTERNAL_WL           0x31DA
+#define EGL_WAYLAND_Y_INVERTED_WL         0x31DB
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWLPROC) (EGLDisplay dpy, struct wl_display *display);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWLPROC) (EGLDisplay dpy, struct wl_display *display);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWLPROC) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL (EGLDisplay dpy, struct wl_display *display);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL (EGLDisplay dpy, struct wl_display *display);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+#endif
+#endif /* EGL_WL_bind_wayland_display */
+
+#ifndef EGL_WL_create_wayland_buffer_from_image
+#define EGL_WL_create_wayland_buffer_from_image 1
+#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
+struct wl_buffer;
+typedef struct wl_buffer *(EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC) (EGLDisplay dpy, EGLImageKHR image);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI struct wl_buffer *EGLAPIENTRY eglCreateWaylandBufferFromImageWL (EGLDisplay dpy, EGLImageKHR image);
+#endif
+#endif /* EGL_WL_create_wayland_buffer_from_image */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/host/libs/graphics_detector/include/EGL/eglplatform.h b/host/libs/graphics_detector/include/EGL/eglplatform.h
new file mode 100644
index 0000000..a35f91c
--- /dev/null
+++ b/host/libs/graphics_detector/include/EGL/eglplatform.h
@@ -0,0 +1,182 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2016 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+ * $Revision: 30994 $ on $Date: 2015-04-30 13:36:48 -0700 (Thu, 30 Apr 2015) $
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file.  Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "EGL" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY  KHRONOS_APIENTRY
+#endif
+#define EGLAPIENTRYP EGLAPIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ *
+ * Khronos STRONGLY RECOMMENDS that you use the default definitions
+ * provided below, since these changes affect both binary and source
+ * portability of applications using EGL running on different EGL
+ * implementations.
+ */
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC     EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+typedef HWND    EGLNativeWindowType;
+
+#elif defined(__EMSCRIPTEN__)
+
+typedef int EGLNativeDisplayType;
+typedef int EGLNativePixmapType;
+typedef int EGLNativeWindowType;
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */
+
+typedef int   EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(WL_EGL_PLATFORM)
+
+typedef struct wl_display     *EGLNativeDisplayType;
+typedef struct wl_egl_pixmap  *EGLNativePixmapType;
+typedef struct wl_egl_window  *EGLNativeWindowType;
+
+#elif defined(__GBM__)
+
+typedef struct gbm_device  *EGLNativeDisplayType;
+typedef struct gbm_bo      *EGLNativePixmapType;
+typedef void               *EGLNativeWindowType;
+
+#elif defined(__ANDROID__) || defined(ANDROID)
+
+struct ANativeWindow;
+struct egl_native_pixmap_t;
+
+typedef void*                           EGLNativeDisplayType;
+typedef struct egl_native_pixmap_t*     EGLNativePixmapType;
+typedef struct ANativeWindow*           EGLNativeWindowType;
+
+#elif defined(USE_OZONE)
+
+typedef intptr_t EGLNativeDisplayType;
+typedef intptr_t EGLNativePixmapType;
+typedef intptr_t EGLNativeWindowType;
+
+#elif defined(__unix__) && defined(EGL_NO_X11)
+
+typedef void             *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#elif defined(__unix__) || defined(USE_X11)
+
+/* X11 (tentative)  */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap   EGLNativePixmapType;
+typedef Window   EGLNativeWindowType;
+
+#elif defined(__APPLE__)
+
+typedef int   EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(__HAIKU__)
+
+#include <kernel/image.h>
+
+typedef void              *EGLNativeDisplayType;
+typedef khronos_uintptr_t  EGLNativePixmapType;
+typedef khronos_uintptr_t  EGLNativeWindowType;
+
+#elif defined(__Fuchsia__)
+
+typedef void              *EGLNativeDisplayType;
+typedef khronos_uintptr_t  EGLNativePixmapType;
+typedef khronos_uintptr_t  EGLNativeWindowType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType  NativePixmapType;
+typedef EGLNativeWindowType  NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other.  While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+
+/* C++ / C typecast macros for special EGL handle values */
+#if defined(__cplusplus)
+#define EGL_CAST(type, value) (static_cast<type>(value))
+#else
+#define EGL_CAST(type, value) ((type) (value))
+#endif
+
+#endif /* __eglplatform_h */
\ No newline at end of file
diff --git a/host/libs/graphics_detector/include/KHR/khrplatform.h b/host/libs/graphics_detector/include/KHR/khrplatform.h
new file mode 100644
index 0000000..63e74c7
--- /dev/null
+++ b/host/libs/graphics_detector/include/KHR/khrplatform.h
@@ -0,0 +1,290 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * The master copy of khrplatform.h is maintained in the Khronos EGL
+ * Registry repository at https://github.com/KhronosGroup/EGL-Registry
+ * The last semantic modification to khrplatform.h was at commit ID:
+ *      67a3e0864c2d75ea5287b9f3d2eb74a745936692
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by filing pull requests or issues on
+ * the EGL Registry repository linked above.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ *    http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ *        #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ *    khronos_int8_t              signed   8  bit
+ *    khronos_uint8_t             unsigned 8  bit
+ *    khronos_int16_t             signed   16 bit
+ *    khronos_uint16_t            unsigned 16 bit
+ *    khronos_int32_t             signed   32 bit
+ *    khronos_uint32_t            unsigned 32 bit
+ *    khronos_int64_t             signed   64 bit
+ *    khronos_uint64_t            unsigned 64 bit
+ *    khronos_intptr_t            signed   same number of bits as a pointer
+ *    khronos_uintptr_t           unsigned same number of bits as a pointer
+ *    khronos_ssize_t             signed   size
+ *    khronos_usize_t             unsigned size
+ *    khronos_float_t             signed   32 bit floating point
+ *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
+ *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ *                                         nanoseconds
+ *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ *    khronos_boolean_enum_t      enumerated boolean type. This should
+ *      only be used as a base type when a client API's boolean type is
+ *      an enum. Client APIs which use an integer or other type for
+ *      booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ *    KHRONOS_APICALL
+ *    KHRONOS_APIENTRY
+ *    KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ *                                  int arg1,
+ *                                  int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
+#   define KHRONOS_STATIC 1
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(KHRONOS_STATIC)
+    /* If the preprocessor constant KHRONOS_STATIC is defined, make the
+     * header compatible with static linking. */
+#   define KHRONOS_APICALL
+#elif defined(_WIN32)
+#   define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+#   define KHRONOS_APICALL IMPORT_C
+#elif defined(__ANDROID__)
+#   define KHRONOS_APICALL __attribute__((visibility("default")))
+#else
+#   define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function  and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC)
+    /* Win32 but not WinCE */
+#   define KHRONOS_APIENTRY __stdcall
+#else
+#   define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32                 khronos_int32_t;
+typedef unsigned __int32        khronos_uint32_t;
+typedef __int64                 khronos_int64_t;
+typedef unsigned __int64        khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int                khronos_int64_t;
+typedef unsigned long int       khronos_uint64_t;
+#else
+typedef long long int           khronos_int64_t;
+typedef unsigned long long int  khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64   0
+#define KHRONOS_SUPPORT_FLOAT   0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed   char          khronos_int8_t;
+typedef unsigned char          khronos_uint8_t;
+typedef signed   short int     khronos_int16_t;
+typedef unsigned short int     khronos_uint16_t;
+
+/*
+ * Types that differ between LLP64 and LP64 architectures - in LLP64,
+ * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+ * to be the only LLP64 architecture in current use.
+ */
+#ifdef _WIN64
+typedef signed   long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed   long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed   long  int     khronos_intptr_t;
+typedef unsigned long  int     khronos_uintptr_t;
+typedef signed   long  int     khronos_ssize_t;
+typedef unsigned long  int     khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef          float         khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time.  Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted).  The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years.  Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
+typedef khronos_int64_t        khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true.  Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+    KHRONOS_FALSE = 0,
+    KHRONOS_TRUE  = 1,
+    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
\ No newline at end of file
diff --git a/host/libs/image_aggregator/Android.bp b/host/libs/image_aggregator/Android.bp
new file mode 100644
index 0000000..23d4874
--- /dev/null
+++ b/host/libs/image_aggregator/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2021 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+    name: "libcdisk_spec",
+    srcs: [
+        "cdisk_spec.proto",
+    ],
+    proto: {
+        type: "lite",
+        export_proto_headers: true,
+        include_dirs: [
+            "external/protobuf/src",
+        ],
+    },
+    defaults: ["cuttlefish_host"],
+}
+
+cc_library_static {
+    name: "libimage_aggregator",
+    srcs: [
+        "image_aggregator.cc",
+    ],
+    export_include_dirs: ["."],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libbase",
+        "libprotobuf-cpp-lite",
+        "libz",
+    ],
+    static_libs: [
+        "libcdisk_spec",
+        "libext2_uuid",
+        "libsparse",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/commands/assemble_cvd/cdisk_spec.proto b/host/libs/image_aggregator/cdisk_spec.proto
similarity index 100%
rename from host/commands/assemble_cvd/cdisk_spec.proto
rename to host/libs/image_aggregator/cdisk_spec.proto
diff --git a/host/libs/image_aggregator/image_aggregator.cc b/host/libs/image_aggregator/image_aggregator.cc
new file mode 100644
index 0000000..b6b412d
--- /dev/null
+++ b/host/libs/image_aggregator/image_aggregator.cc
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/*
+ * GUID Partition Table and Composite Disk generation code.
+ */
+
+#include "host/libs/image_aggregator/image_aggregator.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <cdisk_spec.pb.h>
+#include <google/protobuf/text_format.h>
+#include <sparse/sparse.h>
+#include <uuid.h>
+#include <zlib.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/size_utils.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/libs/config/mbr.h"
+
+namespace cuttlefish {
+namespace {
+
+constexpr int GPT_NUM_PARTITIONS = 128;
+
+/**
+ * Creates a "Protective" MBR Partition Table header. The GUID
+ * Partition Table Specification recommends putting this on the first sector
+ * of the disk, to protect against old disk formatting tools from misidentifying
+ * the GUID Partition Table later and doing the wrong thing.
+ */
+MasterBootRecord ProtectiveMbr(std::uint64_t size) {
+  MasterBootRecord mbr = {
+    .partitions =  {{
+      .partition_type = 0xEE,
+      .first_lba = 1,
+      .num_sectors = (std::uint32_t) size / SECTOR_SIZE,
+    }},
+    .boot_signature = { 0x55, 0xAA },
+  };
+  return mbr;
+}
+
+struct __attribute__((packed)) GptHeader {
+  std::uint8_t signature[8];
+  std::uint8_t revision[4];
+  std::uint32_t header_size;
+  std::uint32_t header_crc32;
+  std::uint32_t reserved;
+  std::uint64_t current_lba;
+  std::uint64_t backup_lba;
+  std::uint64_t first_usable_lba;
+  std::uint64_t last_usable_lba;
+  std::uint8_t disk_guid[16];
+  std::uint64_t partition_entries_lba;
+  std::uint32_t num_partition_entries;
+  std::uint32_t partition_entry_size;
+  std::uint32_t partition_entries_crc32;
+};
+
+static_assert(sizeof(GptHeader) == 92);
+
+struct __attribute__((packed)) GptPartitionEntry {
+  std::uint8_t partition_type_guid[16];
+  std::uint8_t unique_partition_guid[16];
+  std::uint64_t first_lba;
+  std::uint64_t last_lba;
+  std::uint64_t attributes;
+  std::uint16_t partition_name[36]; // UTF-16LE
+};
+
+static_assert(sizeof(GptPartitionEntry) == 128);
+
+struct __attribute__((packed)) GptBeginning {
+  MasterBootRecord protective_mbr;
+  GptHeader header;
+  std::uint8_t header_padding[420];
+  GptPartitionEntry entries[GPT_NUM_PARTITIONS];
+  std::uint8_t partition_alignment[3072];
+};
+
+static_assert(sizeof(GptBeginning) == SECTOR_SIZE * 40);
+
+struct __attribute__((packed)) GptEnd {
+  GptPartitionEntry entries[GPT_NUM_PARTITIONS];
+  GptHeader footer;
+  std::uint8_t footer_padding[420];
+};
+
+static_assert(sizeof(GptEnd) == SECTOR_SIZE * 33);
+
+struct PartitionInfo {
+  MultipleImagePartition source;
+  std::uint64_t guest_size;
+  std::uint64_t host_size;
+  std::uint64_t offset;
+};
+
+/*
+ * Returns the file size of `file_path`. If `file_path` is an Android-Sparse
+ * file, returns the file size it would have after being converted to a raw
+ * file.
+ *
+ * Android-Sparse is a file format invented by Android that optimizes for
+ * chunks of zeroes or repeated data. The Android build system can produce
+ * sparse files to save on size of disk files after they are extracted from a
+ * disk file, as the imag eflashing process also can handle Android-Sparse
+ * images.
+ */
+std::uint64_t UnsparsedSize(const std::string& file_path) {
+  auto fd = open(file_path.c_str(), O_RDONLY);
+  CHECK(fd >= 0) << "Could not open \"" << file_path << "\""
+                 << strerror(errno);
+  auto sparse = sparse_file_import(fd, /* verbose */ false, /* crc */ false);
+  auto size =
+      sparse ? sparse_file_len(sparse, false, true) : FileSize(file_path);
+  close(fd);
+  return size;
+}
+
+/*
+ * strncpy equivalent for u16 data. GPT disks use UTF16-LE for disk labels.
+ */
+void u16cpy(std::uint16_t* dest, std::uint16_t* src, std::size_t size) {
+  while (size > 0 && *src) {
+    *dest = *src;
+    dest++;
+    src++;
+    size--;
+  }
+  if (size > 0) {
+    *dest = 0;
+  }
+}
+
+MultipleImagePartition ToMultipleImagePartition(ImagePartition source) {
+  return MultipleImagePartition{
+      .label = source.label,
+      .image_file_paths = std::vector{source.image_file_path},
+      .type = source.type,
+      .read_only = source.read_only,
+  };
+}
+
+/**
+ * Incremental builder class for producing partition tables. Add partitions
+ * one-by-one, then produce specification files
+ */
+class CompositeDiskBuilder {
+private:
+  std::vector<PartitionInfo> partitions_;
+  std::uint64_t next_disk_offset_;
+
+  static const char* GetPartitionGUID(MultipleImagePartition source) {
+    // Due to some endianness mismatch in e2fsprogs GUID vs GPT, the GUIDs are
+    // rearranged to make the right GUIDs appear in gdisk
+    switch (source.type) {
+      case kLinuxFilesystem:
+        // Technically 0FC63DAF-8483-4772-8E79-3D69D8477DE4
+        return "AF3DC60F-8384-7247-8E79-3D69D8477DE4";
+      case kEfiSystemPartition:
+        // Technically C12A7328-F81F-11D2-BA4B-00A0C93EC93B
+        return "28732AC1-1FF8-D211-BA4B-00A0C93EC93B";
+      default:
+        LOG(FATAL) << "Unknown partition type: " << (int) source.type;
+    }
+  }
+
+public:
+  CompositeDiskBuilder() : next_disk_offset_(sizeof(GptBeginning)) {}
+
+  void AppendPartition(ImagePartition source) {
+    AppendPartition(ToMultipleImagePartition(source));
+  }
+
+  void AppendPartition(MultipleImagePartition source) {
+    uint64_t host_size = 0;
+    for (const auto& path : source.image_file_paths) {
+      host_size += UnsparsedSize(path);
+    }
+    auto guest_size = AlignToPowerOf2(host_size, PARTITION_SIZE_SHIFT);
+    CHECK(host_size == guest_size || source.read_only)
+        << "read-write partition " << source.label
+        << " is not aligned to the size of " << (1 << PARTITION_SIZE_SHIFT);
+    partitions_.push_back(PartitionInfo{
+        .source = source,
+        .guest_size = guest_size,
+        .host_size = host_size,
+        .offset = next_disk_offset_,
+    });
+    next_disk_offset_ =
+        AlignToPowerOf2(next_disk_offset_ + guest_size, PARTITION_SIZE_SHIFT);
+  }
+
+  std::uint64_t DiskSize() const {
+    std::uint64_t val = next_disk_offset_ + sizeof(GptEnd);
+    return AlignToPowerOf2(val, DISK_SIZE_SHIFT);
+  }
+
+  /**
+   * Generates a composite disk specification file, assuming that `header_file`
+   * and `footer_file` will be populated with the contents of `Beginning()` and
+   * `End()`.
+   */
+  CompositeDisk MakeCompositeDiskSpec(const std::string& header_file,
+                                      const std::string& footer_file) const {
+    CompositeDisk disk;
+    disk.set_version(1);
+    disk.set_length(DiskSize());
+
+    ComponentDisk* header = disk.add_component_disks();
+    header->set_file_path(AbsolutePath(header_file));
+    header->set_offset(0);
+
+    for (auto& partition : partitions_) {
+      uint64_t host_size = 0;
+      for (const auto& path : partition.source.image_file_paths) {
+        ComponentDisk* component = disk.add_component_disks();
+        component->set_file_path(AbsolutePath(path));
+        component->set_offset(partition.offset + host_size);
+        component->set_read_write_capability(
+            partition.source.read_only ? ReadWriteCapability::READ_ONLY
+                                       : ReadWriteCapability::READ_WRITE);
+        host_size += UnsparsedSize(path);
+      }
+      CHECK(partition.host_size == host_size);
+      // When partition's size differs from its size on the host
+      // reading the disk within the guest os would fail due to the gap.
+      // Putting any disk bigger than 4K can fill this gap.
+      // Here we reuse the header which is always > 4K.
+      // We don't fill the "writable" disk's hole and it should be an error
+      // because writes in the guest of can't be reflected to the backing file.
+      if (partition.guest_size != partition.host_size) {
+        ComponentDisk* component = disk.add_component_disks();
+        component->set_file_path(AbsolutePath(header_file));
+        component->set_offset(partition.offset + partition.host_size);
+        component->set_read_write_capability(ReadWriteCapability::READ_ONLY);
+      }
+    }
+
+    ComponentDisk* footer = disk.add_component_disks();
+    footer->set_file_path(AbsolutePath(footer_file));
+    footer->set_offset(next_disk_offset_);
+
+    return disk;
+  }
+
+  /*
+   * Returns a GUID Partition Table header structure for all the disks that have
+   * been added with `AppendDisk`. Includes a protective MBR.
+   *
+   * This method is not deterministic: some data is generated such as the disk
+   * uuids.
+   */
+  GptBeginning Beginning() const {
+    if (partitions_.size() > GPT_NUM_PARTITIONS) {
+      LOG(FATAL) << "Too many partitions: " << partitions_.size();
+      return {};
+    }
+    GptBeginning gpt = {
+      .protective_mbr = ProtectiveMbr(DiskSize()),
+      .header = {
+        .signature = {'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T'},
+        .revision = {0, 0, 1, 0},
+        .header_size = sizeof(GptHeader),
+        .current_lba = 1,
+        .backup_lba = (next_disk_offset_ + sizeof(GptEnd)) / SECTOR_SIZE - 1,
+        .first_usable_lba = sizeof(GptBeginning) / SECTOR_SIZE,
+        .last_usable_lba = (next_disk_offset_ - SECTOR_SIZE) / SECTOR_SIZE,
+        .partition_entries_lba = 2,
+        .num_partition_entries = GPT_NUM_PARTITIONS,
+        .partition_entry_size = sizeof(GptPartitionEntry),
+      },
+    };
+    uuid_generate(gpt.header.disk_guid);
+    for (std::size_t i = 0; i < partitions_.size(); i++) {
+      const auto& partition = partitions_[i];
+      gpt.entries[i] = GptPartitionEntry{
+          .first_lba = partition.offset / SECTOR_SIZE,
+          .last_lba =
+              (partition.offset + partition.guest_size) / SECTOR_SIZE - 1,
+      };
+      uuid_generate(gpt.entries[i].unique_partition_guid);
+      if (uuid_parse(GetPartitionGUID(partition.source),
+                     gpt.entries[i].partition_type_guid)) {
+        LOG(FATAL) << "Could not parse partition guid";
+      }
+      std::u16string wide_name(partitions_[i].source.label.begin(),
+                              partitions_[i].source.label.end());
+      u16cpy((std::uint16_t*) gpt.entries[i].partition_name,
+            (std::uint16_t*) wide_name.c_str(), 36);
+    }
+    // Not sure these are right, but it works for bpttool
+    gpt.header.partition_entries_crc32 =
+        crc32(0, (std::uint8_t*) gpt.entries,
+              GPT_NUM_PARTITIONS * sizeof(GptPartitionEntry));
+    gpt.header.header_crc32 =
+        crc32(0, (std::uint8_t*) &gpt.header, sizeof(GptHeader));
+    return gpt;
+  }
+
+  /**
+   * Generates a GUID Partition Table footer that matches the header in `head`.
+   */
+  GptEnd End(const GptBeginning& head) const {
+    GptEnd gpt;
+    std::memcpy((void*) gpt.entries, (void*) head.entries, 128 * 128);
+    gpt.footer = head.header;
+    gpt.footer.partition_entries_lba = next_disk_offset_ / SECTOR_SIZE;
+    std::swap(gpt.footer.current_lba, gpt.footer.backup_lba);
+    gpt.footer.header_crc32 = 0;
+    gpt.footer.header_crc32 =
+        crc32(0, (std::uint8_t*) &gpt.footer, sizeof(GptHeader));
+    return gpt;
+  }
+};
+
+bool WriteBeginning(SharedFD out, const GptBeginning& beginning) {
+  std::string begin_str((const char*) &beginning, sizeof(GptBeginning));
+  if (WriteAll(out, begin_str) != begin_str.size()) {
+    LOG(ERROR) << "Could not write GPT beginning: " << out->StrError();
+    return false;
+  }
+  return true;
+}
+
+bool WriteEnd(SharedFD out, const GptEnd& end, std::int64_t padding) {
+  std::string end_str((const char*) &end, sizeof(GptEnd));
+  end_str.resize(end_str.size() + padding, '\0');
+  if (WriteAll(out, end_str) != end_str.size()) {
+    LOG(ERROR) << "Could not write GPT end: " << out->StrError();
+    return false;
+  }
+  return true;
+}
+
+/**
+ * Converts any Android-Sparse image files in `partitions` to raw image files.
+ *
+ * Android-Sparse is a file format invented by Android that optimizes for
+ * chunks of zeroes or repeated data. The Android build system can produce
+ * sparse files to save on size of disk files after they are extracted from a
+ * disk file, as the imag eflashing process also can handle Android-Sparse
+ * images.
+ *
+ * crosvm has read-only support for Android-Sparse files, but QEMU does not
+ * support them.
+ */
+void DeAndroidSparse(const std::vector<ImagePartition>& partitions) {
+  for (const auto& partition : partitions) {
+    auto fd = open(partition.image_file_path.c_str(), O_RDONLY);
+    if (fd < 0) {
+      PLOG(FATAL) << "Could not open \"" << partition.image_file_path;
+      break;
+    }
+    auto sparse = sparse_file_import(fd, /* verbose */ false, /* crc */ false);
+    if (!sparse) {
+      close(fd);
+      continue;
+    }
+    LOG(INFO) << "Desparsing " << partition.image_file_path;
+    std::string out_file_name = partition.image_file_path + ".desparse";
+    auto write_fd = open(out_file_name.c_str(), O_RDWR | O_CREAT | O_TRUNC,
+                         S_IRUSR | S_IWUSR | S_IRGRP);
+    if (write_fd < 0) {
+      PLOG(FATAL) << "Could not open " << out_file_name;
+    }
+    int write_status = sparse_file_write(sparse, write_fd, /* gz */ false,
+                                         /* sparse */ false, /* crc */ false);
+    if (write_status < 0) {
+      LOG(FATAL) << "Failed to desparse \"" << partition.image_file_path
+                 << "\": " << write_status;
+    }
+    close(write_fd);
+    if (rename(out_file_name.c_str(), partition.image_file_path.c_str()) < 0) {
+      int error_num = errno;
+      LOG(FATAL) << "Could not move \"" << out_file_name << "\" to \""
+                 << partition.image_file_path << "\": " << strerror(error_num);
+    }
+    sparse_file_destroy(sparse);
+    close(fd);
+  }
+}
+
+} // namespace
+
+uint64_t AlignToPartitionSize(uint64_t size) {
+  return AlignToPowerOf2(size, PARTITION_SIZE_SHIFT);
+}
+
+void AggregateImage(const std::vector<ImagePartition>& partitions,
+                    const std::string& output_path) {
+  DeAndroidSparse(partitions);
+  CompositeDiskBuilder builder;
+  for (auto& partition : partitions) {
+    builder.AppendPartition(partition);
+  }
+  auto output = SharedFD::Creat(output_path, 0600);
+  auto beginning = builder.Beginning();
+  if (!WriteBeginning(output, beginning)) {
+    LOG(FATAL) << "Could not write GPT beginning to \"" << output_path
+               << "\": " << output->StrError();
+  }
+  for (auto& disk : partitions) {
+    auto disk_fd = SharedFD::Open(disk.image_file_path, O_RDONLY);
+    auto file_size = FileSize(disk.image_file_path);
+    if (!output->CopyFrom(*disk_fd, file_size)) {
+      LOG(FATAL) << "Could not copy from \"" << disk.image_file_path
+                 << "\" to \"" << output_path << "\": " << output->StrError();
+    }
+    // Handle disk images that are not aligned to PARTITION_SIZE_SHIFT
+    std::uint64_t padding =
+        AlignToPowerOf2(file_size, PARTITION_SIZE_SHIFT) - file_size;
+    std::string padding_str;
+    padding_str.resize(padding, '\0');
+    if (WriteAll(output, padding_str) != padding_str.size()) {
+      LOG(FATAL) << "Could not write partition padding to \"" << output_path
+                 << "\": " << output->StrError();
+    }
+  }
+  std::uint64_t padding =
+      builder.DiskSize() - ((beginning.header.backup_lba + 1) * SECTOR_SIZE);
+  if (!WriteEnd(output, builder.End(beginning), padding)) {
+    LOG(FATAL) << "Could not write GPT end to \"" << output_path
+               << "\": " << output->StrError();
+  }
+};
+
+void CreateCompositeDisk(std::vector<ImagePartition> partitions,
+                         const std::string& header_file,
+                         const std::string& footer_file,
+                         const std::string& output_composite_path) {
+  std::vector<MultipleImagePartition> multiple_image_partitions;
+  for (const auto& partition : partitions) {
+    multiple_image_partitions.push_back(ToMultipleImagePartition(partition));
+  }
+  return CreateCompositeDisk(std::move(multiple_image_partitions), header_file,
+                             footer_file, output_composite_path);
+}
+
+void CreateCompositeDisk(std::vector<MultipleImagePartition> partitions,
+                         const std::string& header_file,
+                         const std::string& footer_file,
+                         const std::string& output_composite_path) {
+  CompositeDiskBuilder builder;
+  for (auto& partition : partitions) {
+    builder.AppendPartition(partition);
+  }
+  auto header = SharedFD::Creat(header_file, 0600);
+  auto beginning = builder.Beginning();
+  if (!WriteBeginning(header, beginning)) {
+    LOG(FATAL) << "Could not write GPT beginning to \"" << header_file
+               << "\": " << header->StrError();
+  }
+  auto footer = SharedFD::Creat(footer_file, 0600);
+  std::uint64_t padding =
+      builder.DiskSize() - ((beginning.header.backup_lba + 1) * SECTOR_SIZE);
+  if (!WriteEnd(footer, builder.End(beginning), padding)) {
+    LOG(FATAL) << "Could not write GPT end to \"" << footer_file
+               << "\": " << footer->StrError();
+  }
+  auto composite_proto = builder.MakeCompositeDiskSpec(header_file, footer_file);
+  std::ofstream composite(output_composite_path.c_str(),
+                          std::ios::binary | std::ios::trunc);
+  composite << "composite_disk\x1d";
+  composite_proto.SerializeToOstream(&composite);
+  composite.flush();
+}
+
+void CreateQcowOverlay(const std::string& crosvm_path,
+                       const std::string& backing_file,
+                       const std::string& output_overlay_path) {
+  Command crosvm_qcow2_cmd(crosvm_path);
+  crosvm_qcow2_cmd.AddParameter("create_qcow2");
+  crosvm_qcow2_cmd.AddParameter("--backing_file=", backing_file);
+  crosvm_qcow2_cmd.AddParameter(output_overlay_path);
+  int success = crosvm_qcow2_cmd.Start().Wait();
+  if (success != 0) {
+    LOG(FATAL) << "Unable to run crosvm create_qcow2. Exited with status " << success;
+  }
+}
+
+} // namespace cuttlefish
diff --git a/host/libs/image_aggregator/image_aggregator.h b/host/libs/image_aggregator/image_aggregator.h
new file mode 100644
index 0000000..b9a2458
--- /dev/null
+++ b/host/libs/image_aggregator/image_aggregator.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 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
+
+/**
+ * Functions for manipulating disk files given to crosvm or QEMU.
+ */
+
+#include <string>
+#include <vector>
+
+namespace cuttlefish {
+
+enum ImagePartitionType {
+  kLinuxFilesystem = 0,
+  kEfiSystemPartition,
+};
+
+struct ImagePartition {
+  std::string label;
+  std::string image_file_path;
+  ImagePartitionType type;
+  bool read_only;
+};
+
+struct MultipleImagePartition {
+  std::string label;
+  std::vector<std::string> image_file_paths;
+  ImagePartitionType type;
+  bool read_only;
+};
+
+uint64_t AlignToPartitionSize(uint64_t size);
+
+/**
+ * Combine the files in `partition` into a single raw disk file and write it to
+ * `output_path`. The raw disk file will have a GUID Partition Table and copy in
+ * the contents of the files mentioned in `partitions`.
+ */
+void AggregateImage(const std::vector<ImagePartition>& partitions,
+                    const std::string& output_path);
+
+/**
+ * Generate the files necessary for booting with a Composite Disk.
+ *
+ * Composite Disk is a crosvm disk format that is a layer of indirection over
+ * other disk files. The Composite Disk file lists names and offsets in the
+ * virtual disk.
+ *
+ * For a complete single disk inside the VM, there must also be a GUID Partition
+ * Table header and footer. These are saved to `header_file` and `footer_file`,
+ * then the specification file containing the file paths and offsets is saved to
+ * `output_composite_path`.
+ */
+void CreateCompositeDisk(std::vector<ImagePartition> partitions,
+                         const std::string& header_file,
+                         const std::string& footer_file,
+                         const std::string& output_composite_path);
+
+/**
+ * Overloaded function to generate a composite disk with multiple images for a
+ * single partition.
+ */
+void CreateCompositeDisk(std::vector<MultipleImagePartition> partitions,
+                         const std::string& header_file,
+                         const std::string& footer_file,
+                         const std::string& output_composite_path);
+/**
+ * Generate a qcow overlay backed by a given implementation file.
+ *
+ * qcow, or "QEMU Copy-On-Write" is a file format containing a list of disk
+ * offsets and file contents. This can be combined with a backing file, to
+ * represent an original disk file plus disk updates over that file. The qcow
+ * files can be swapped out and replaced without affecting the original. qcow
+ * is supported by QEMU and crosvm.
+ *
+ * The crosvm binary at `crosvm_path` is used to generate an overlay file at
+ * `output_overlay_path` that functions as an overlay on the file at
+ * `backing_file`.
+ */
+void CreateQcowOverlay(const std::string& crosvm_path,
+                       const std::string& backing_file,
+                       const std::string& output_overlay_path);
+
+}
diff --git a/host/libs/msg_queue/Android.bp b/host/libs/msg_queue/Android.bp
new file mode 100644
index 0000000..39d9c96
--- /dev/null
+++ b/host/libs/msg_queue/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_host_static {
+    name: "libcuttlefish_msg_queue",
+    srcs: [
+        "msg_queue.cc",
+    ],
+    shared_libs: [
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "libbase",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libgflags",
+    ],
+    defaults: ["cuttlefish_host"],
+}
diff --git a/host/libs/msg_queue/README.md b/host/libs/msg_queue/README.md
new file mode 100644
index 0000000..3cef411
--- /dev/null
+++ b/host/libs/msg_queue/README.md
@@ -0,0 +1,57 @@
+# msg_queue
+
+This is the Cuttlefish message queue wrapper library, as one of the IPC options available.  Below are the example usages running in two separate processes.
+
+```
+#define MAX_MSG_SIZE 200
+#define NUM_MESSAGES 100
+
+typedef struct msg_buffer {
+	long mesg_type;
+	char mesg_text[MAX_MSG_SIZE];
+} msg_buffer;
+
+int example_send()
+{
+    // create message queue with the key 'a'
+	int queue_id = msg_queue_create('a');
+	struct msg_buffer msg;
+	for (int i=1; i <= NUM_MESSAGES; i++) {
+        // create message types 1-3
+		msg.mesg_type = (i % 3) + 1;
+		sprintf(msg.mesg_text, "test %d", i);
+		int rc = msg_queue_send(queue_id, &msg, strlen(msg.mesg_text)+1, false);
+		if (rc == -1) {
+			perror("main: msgsnd");
+			exit(1);
+		}
+	}
+	printf("generated %d messages, exiting.\n", NUM_MESSAGES);
+	return 0;
+}
+```
+
+```
+#define MAX_MSG_SIZE 200
+
+typedef struct msg_buffer {
+	long mesg_type;
+	char mesg_text[MAX_MSG_SIZE];
+} msg_buffer;
+
+int example_receive()
+{
+    // create message queue with the key 'a'
+	int queue_id = msg_queue_create('a');
+	struct msg_buffer msg;
+	while (1) {
+		int rc = msg_queue_receive(queue_id, &msg, MAX_MSG_SIZE, 1, false);
+		if (rc == -1) {
+			perror("main: msgrcv");
+			exit(1);
+		}
+		printf("Reader '%d' read message: '%s'\n", 1, msg.mesg_text);
+	}
+	return 0;
+}
+```
diff --git a/host/libs/msg_queue/msg_queue.cc b/host/libs/msg_queue/msg_queue.cc
new file mode 100644
index 0000000..8016a23
--- /dev/null
+++ b/host/libs/msg_queue/msg_queue.cc
@@ -0,0 +1,96 @@
+//
+// 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.
+
+#include "host/libs/msg_queue/msg_queue.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+#include <fstream>
+#include <iostream>
+#include <memory>
+
+#include <android-base/logging.h>
+
+namespace cuttlefish {
+
+// class holds `msgid` returned from msg_queue_create, and match the lifetime of
+// the message queue to the lifetime of the object.
+
+SysVMessageQueue::SysVMessageQueue(int id) { msgid = id; }
+
+SysVMessageQueue::~SysVMessageQueue(void) {
+  if (msgctl(msgid, IPC_RMID, NULL) < 0) {
+    int error_num = errno;
+    LOG(ERROR) << "Could not remove message queue: " << strerror(error_num);
+  }
+}
+
+// SysVMessageQueue::Create would return an empty/null std::unique_ptr if
+// initialization failed.
+std::unique_ptr<SysVMessageQueue> SysVMessageQueue::Create(
+    const std::string& path, char proj_id) {
+  // key file must exist before calling ftok
+  std::fstream fs;
+  fs.open(path, std::ios::out);
+  fs.close();
+
+  // only the owning user has access
+  key_t key = ftok(path.c_str(), proj_id);
+  if (key < 0) {
+    int error_num = errno;
+    LOG(ERROR) << "Could not ftok to create IPC key: " << strerror(error_num);
+    return NULL;
+  }
+  int queue_id = msgget(key, 0);
+  if (queue_id < 0) {
+    queue_id = msgget(key, IPC_CREAT | IPC_EXCL | 0600);
+  }
+  auto msg = std::unique_ptr<SysVMessageQueue>(new SysVMessageQueue(queue_id));
+  return msg;
+}
+
+int SysVMessageQueue::Send(void* data, size_t size, bool block) {
+  int msgflg = block ? 0 : IPC_NOWAIT;
+  if (msgsnd(msgid, data, size, msgflg) < 0) {
+    int error_num = errno;
+    if (error_num == EAGAIN) {
+      // returns EAGAIN if queue is full and non-blocking
+      return EAGAIN;
+    }
+    LOG(ERROR) << "Could not send message: " << strerror(error_num);
+    return error_num;
+  }
+  return 0;
+}
+
+// If msgtyp is 0, then the first message in the queue is read.
+// If msgtyp is greater than 0, then the first message in the queue of type
+// msgtyp is read.
+// If msgtyp is less than 0, then the first message in the queue with the lowest
+// type less than or equal to the absolute value of msgtyp will be read.
+ssize_t SysVMessageQueue::Receive(void* data, size_t size, long msgtyp,
+                                  bool block) {
+  // System call fails with errno set to ENOMSG if queue is empty and
+  // non-blocking.
+  int msgflg = block ? 0 : IPC_NOWAIT;
+  return msgrcv(msgid, data, size, msgtyp, msgflg);
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/msg_queue/msg_queue.h b/host/libs/msg_queue/msg_queue.h
new file mode 100644
index 0000000..0d43cd1
--- /dev/null
+++ b/host/libs/msg_queue/msg_queue.h
@@ -0,0 +1,34 @@
+/*
+ * 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 cuttlefish {
+class SysVMessageQueue {
+ public:
+  static std::unique_ptr<SysVMessageQueue> Create(const std::string& path,
+                                                  char proj_id);
+  ~SysVMessageQueue();
+
+  int Send(void* data, size_t size, bool block);
+  ssize_t Receive(void* data, size_t size, long msgtyp, bool block);
+
+ private:
+  SysVMessageQueue(int msgid);
+  int msgid;
+};
+}  // namespace cuttlefish
diff --git a/host/libs/screen_connector/Android.bp b/host/libs/screen_connector/Android.bp
index 69fa002..d4e4002 100644
--- a/host/libs/screen_connector/Android.bp
+++ b/host/libs/screen_connector/Android.bp
@@ -13,26 +13,33 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_host_static {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
     name: "libcuttlefish_screen_connector",
     srcs: [
-        "screen_connector.cpp",
-        "socket_based_screen_connector.cpp",
         "wayland_screen_connector.cpp",
     ],
-    header_libs: [
-        "cuttlefish_glog",
-    ],
     shared_libs: [
         "libcuttlefish_fs",
         "libbase",
+        "libjsoncpp",
         "liblog",
     ],
+    header_libs: [
+        "libcuttlefish_confui_host_headers",
+    ],
     static_libs: [
         "libcuttlefish_host_config",
         "libcuttlefish_utils",
+        "libcuttlefish_confui",
         "libcuttlefish_wayland_server",
-        "libjsoncpp",
+        "libcuttlefish_confui_host",
+        "libft2.nodep",
+        "libteeui",
+        "libteeui_localization",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/libs/screen_connector/screen_connector.cpp b/host/libs/screen_connector/screen_connector.cpp
deleted file mode 100644
index 39c0fa3..0000000
--- a/host/libs/screen_connector/screen_connector.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include "host/libs/screen_connector/screen_connector.h"
-
-#include <glog/logging.h>
-
-#include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/screen_connector/socket_based_screen_connector.h"
-#include "host/libs/screen_connector/wayland_screen_connector.h"
-
-namespace cvd {
-
-ScreenConnector* ScreenConnector::Get(int frames_fd) {
-  auto config = vsoc::CuttlefishConfig::Get();
-  if (config->gpu_mode() == vsoc::kGpuModeDrmVirgl ||
-      config->gpu_mode() == vsoc::kGpuModeGfxStream) {
-    return new WaylandScreenConnector(frames_fd);
-  } else if (config->gpu_mode() == vsoc::kGpuModeGuestSwiftshader) {
-    return new SocketBasedScreenConnector(frames_fd);
-  } else {
-      LOG(ERROR) << "Invalid gpu mode: " << config->gpu_mode();
-      return nullptr;
-  }
-}
-
-}  // namespace cvd
diff --git a/host/libs/screen_connector/screen_connector.h b/host/libs/screen_connector/screen_connector.h
index 3a0e0e2..de55b0e 100644
--- a/host/libs/screen_connector/screen_connector.h
+++ b/host/libs/screen_connector/screen_connector.h
@@ -16,50 +16,242 @@
 
 #pragma once
 
+#include <cassert>
+#include <chrono>
 #include <cstdint>
 #include <functional>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <thread>
+#include <type_traits>
 
+#include <android-base/logging.h>
+#include "common/libs/concurrency/semaphore.h"
+#include "common/libs/confui/confui.h"
+#include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/size_utils.h"
+
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_utils.h"
+#include "host/libs/screen_connector/screen_connector_common.h"
+#include "host/libs/screen_connector/screen_connector_queue.h"
+#include "host/libs/screen_connector/wayland_screen_connector.h"
 
-namespace cvd {
+namespace cuttlefish {
 
-using FrameCallback = std::function<void(std::uint32_t /*frame_number*/,
-                                         std::uint8_t* /*frame_pixels*/)>;
-
-class ScreenConnector {
+template <typename ProcessedFrameType>
+class ScreenConnector : public ScreenConnectorInfo,
+                        public ScreenConnectorFrameRenderer {
  public:
-  static ScreenConnector* Get(int frames_fd);
+  static_assert(cuttlefish::is_movable<ProcessedFrameType>::value,
+                "ProcessedFrameType should be std::move-able.");
+  static_assert(std::is_base_of<ScreenConnectorFrameInfo, ProcessedFrameType>::value,
+                "ProcessedFrameType should inherit ScreenConnectorFrameInfo");
+
+  /**
+   * This is the type of the callback function WebRTC/VNC is supposed to provide
+   * ScreenConnector with.
+   *
+   * The callback function should be defined so that the two parameters are
+   * given by the callback function caller (e.g. ScreenConnectorSource) and used
+   * to fill out the ProcessedFrameType object, msg.
+   *
+   * The ProcessedFrameType object is internally created by ScreenConnector,
+   * filled out by the ScreenConnectorSource, and returned via OnNextFrame()
+   * call.
+   */
+  using GenerateProcessedFrameCallback = std::function<void(
+      std::uint32_t /*display_number*/, std::uint8_t* /*frame_pixels*/,
+      /* ScImpl enqueues this type into the Q */
+      ProcessedFrameType& msg)>;
+
+  static std::unique_ptr<ScreenConnector<ProcessedFrameType>> Get(
+      const int frames_fd, HostModeCtrl& host_mode_ctrl) {
+    auto config = cuttlefish::CuttlefishConfig::Get();
+    ScreenConnector<ProcessedFrameType>* raw_ptr = nullptr;
+    if (config->gpu_mode() == cuttlefish::kGpuModeDrmVirgl ||
+        config->gpu_mode() == cuttlefish::kGpuModeGfxStream ||
+        config->gpu_mode() == cuttlefish::kGpuModeGuestSwiftshader) {
+      raw_ptr = new ScreenConnector<ProcessedFrameType>(
+          std::make_unique<WaylandScreenConnector>(frames_fd), host_mode_ctrl);
+    } else {
+      LOG(FATAL) << "Invalid gpu mode: " << config->gpu_mode();
+    }
+    return std::unique_ptr<ScreenConnector<ProcessedFrameType>>(raw_ptr);
+  }
 
   virtual ~ScreenConnector() = default;
 
-  // Runs the given callback on the next available frame after the given
-  // frame number and returns true if successful.
-  virtual bool OnFrameAfter(std::uint32_t frame_number,
-                            const FrameCallback& frame_callback) = 0;
-
-  static inline constexpr int BytesPerPixel() {
-      return sizeof(int32_t);
+  /**
+   * set the callback function to be eventually used by Wayland/Socket-Based Connectors
+   *
+   * @param[in] To tell how ScreenConnectorSource caches the frame & meta info
+   */
+  void SetCallback(GenerateProcessedFrameCallback&& frame_callback) {
+    std::lock_guard<std::mutex> lock(streamer_callback_mutex_);
+    callback_from_streamer_ = std::move(frame_callback);
+    streamer_callback_set_cv_.notify_all();
+    /*
+     * the first WaitForAtLeastOneClientConnection() call from VNC requires the
+     * Android-frame-processing thread starts beforehands (b/178504150)
+     */
+    if (!sc_android_frame_fetching_thread_.joinable()) {
+      sc_android_frame_fetching_thread_ = cuttlefish::confui::thread::RunThread(
+          "AndroidFetcher", &ScreenConnector::AndroidFrameFetchingLoop, this);
+    }
   }
 
-  static inline int ScreenHeight() {
-      return vsoc::CuttlefishConfig::Get()->y_res();
+  bool IsCallbackSet() const override {
+    if (callback_from_streamer_) {
+      return true;
+    }
+    return false;
   }
 
-  static inline int ScreenWidth() {
-      return vsoc::CuttlefishConfig::Get()->x_res();
+  /* returns the processed frame that also includes meta-info such as success/fail
+   * and display number from the guest
+   *
+   * NOTE THAT THIS IS THE ONLY CONSUMER OF THE TWO QUEUES
+   */
+  ProcessedFrameType OnNextFrame() {
+    on_next_frame_cnt_++;
+    while (true) {
+      ConfUiLog(VERBOSE) << "Streamer waiting Semaphore with host ctrl mode ="
+                         << static_cast<std::uint32_t>(
+                                host_mode_ctrl_.GetMode())
+                         << " and cnd = #" << on_next_frame_cnt_;
+      sc_sem_.SemWait();
+      ConfUiLog(VERBOSE)
+          << "Streamer got Semaphore'ed resources with host ctrl mode ="
+          << static_cast<std::uint32_t>(host_mode_ctrl_.GetMode())
+          << "and cnd = #" << on_next_frame_cnt_;
+      // do something
+      if (!sc_android_queue_.Empty()) {
+        auto mode = host_mode_ctrl_.GetMode();
+        if (mode == HostModeCtrl::ModeType::kAndroidMode) {
+          ConfUiLog(VERBOSE)
+              << "Streamer gets Android frame with host ctrl mode ="
+              << static_cast<std::uint32_t>(mode) << "and cnd = #"
+              << on_next_frame_cnt_;
+          return sc_android_queue_.PopFront();
+        }
+        // AndroidFrameFetchingLoop could have added 1 or 2 frames
+        // before it becomes Conf UI mode.
+        ConfUiLog(VERBOSE)
+            << "Streamer ignores Android frame with host ctrl mode ="
+            << static_cast<std::uint32_t>(mode) << "and cnd = #"
+            << on_next_frame_cnt_;
+        sc_android_queue_.PopFront();
+        continue;
+      }
+      ConfUiLog(VERBOSE) << "Streamer gets Conf UI frame with host ctrl mode = "
+                         << static_cast<std::uint32_t>(
+                                host_mode_ctrl_.GetMode())
+                         << " and cnd = #" << on_next_frame_cnt_;
+      return sc_confui_queue_.PopFront();
+    }
   }
 
-  static inline int ScreenStride() {
-      return AlignToPowerOf2(ScreenWidth() * BytesPerPixel(), 4);
+  [[noreturn]] void AndroidFrameFetchingLoop() {
+    unsigned long long int loop_cnt = 0;
+    cuttlefish::confui::thread::Set("AndroidFrameFetcher",
+                                    std::this_thread::get_id());
+    while (true) {
+      loop_cnt++;
+      ProcessedFrameType processed_frame;
+      decltype(callback_from_streamer_) cp_of_streamer_callback;
+      {
+        std::lock_guard<std::mutex> lock(streamer_callback_mutex_);
+        cp_of_streamer_callback = callback_from_streamer_;
+      }
+      GenerateProcessedFrameCallbackImpl callback_for_sc_impl =
+          std::bind(cp_of_streamer_callback, std::placeholders::_1,
+                    std::placeholders::_2, std::ref(processed_frame));
+      ConfUiLog(VERBOSE) << cuttlefish::confui::thread::GetName(
+                                std::this_thread::get_id())
+                         << " calling Android OnNextFrame. "
+                         << " at loop #" << loop_cnt;
+      bool flag = sc_android_src_->OnNextFrame(callback_for_sc_impl);
+      processed_frame.is_success_ = flag && processed_frame.is_success_;
+      const bool is_confui_mode = host_mode_ctrl_.IsConfirmatioUiMode();
+      if (!is_confui_mode) {
+        ConfUiLog(VERBOSE) << cuttlefish::confui::thread::GetName(
+                                  std::this_thread::get_id())
+                           << "is sending an Android Frame at loop_cnt #"
+                           << loop_cnt;
+        sc_android_queue_.PushBack(std::move(processed_frame));
+        continue;
+      }
+      ConfUiLog(VERBOSE) << cuttlefish::confui::thread::GetName(
+                                std::this_thread::get_id())
+                         << "is skipping an Android Frame at loop_cnt #"
+                         << loop_cnt;
+    }
   }
 
-  static inline int ScreenSizeInBytes() {
-      return ScreenStride() * ScreenHeight();
+  /**
+   * ConfUi calls this when it has frames to render
+   *
+   * This won't be called if not by Confirmation UI. This won't affect rendering
+   * Android guest frames if Confirmation UI HAL is not active.
+   *
+   */
+  bool RenderConfirmationUi(const std::uint32_t display,
+                            std::uint8_t* raw_frame) override {
+    render_confui_cnt_++;
+    // wait callback is not set, the streamer is not ready
+    // return with LOG(ERROR)
+    if (!IsCallbackSet()) {
+      ConfUiLog(ERROR) << "callback function to process frames is not yet set";
+      return false;
+    }
+    ProcessedFrameType processed_frame;
+    auto this_thread_name = cuttlefish::confui::thread::GetName();
+    ConfUiLog(DEBUG) << this_thread_name
+                     << "is sending a #" + std::to_string(render_confui_cnt_)
+                     << "Conf UI frame";
+    callback_from_streamer_(display, raw_frame, processed_frame);
+    // now add processed_frame to the queue
+    sc_confui_queue_.PushBack(std::move(processed_frame));
+    return true;
+  }
+
+  // Let the screen connector know when there are clients connected
+  void ReportClientsConnected(bool have_clients) {
+    // screen connector implementation must implement ReportClientsConnected
+    sc_android_src_->ReportClientsConnected(have_clients);
+    return ;
   }
 
  protected:
-  ScreenConnector() = default;
+  template <typename T,
+            typename = std::enable_if_t<
+                std::is_base_of<ScreenConnectorSource, T>::value, void>>
+  ScreenConnector(std::unique_ptr<T>&& impl, HostModeCtrl& host_mode_ctrl)
+      : sc_android_src_{std::move(impl)},
+        host_mode_ctrl_{host_mode_ctrl},
+        on_next_frame_cnt_{0},
+        render_confui_cnt_{0},
+        sc_android_queue_{sc_sem_},
+        sc_confui_queue_{sc_sem_} {}
+  ScreenConnector() = delete;
+
+ private:
+  // either socket_based or wayland
+  std::unique_ptr<ScreenConnectorSource> sc_android_src_;
+  HostModeCtrl& host_mode_ctrl_;
+  unsigned long long int on_next_frame_cnt_;
+  unsigned long long int render_confui_cnt_;
+  Semaphore sc_sem_;
+  ScreenConnectorQueue<ProcessedFrameType> sc_android_queue_;
+  ScreenConnectorQueue<ProcessedFrameType> sc_confui_queue_;
+  GenerateProcessedFrameCallback callback_from_streamer_;
+  std::thread sc_android_frame_fetching_thread_;
+  std::mutex streamer_callback_mutex_; // mutex to set & read callback_from_streamer_
+  std::condition_variable streamer_callback_set_cv_;
 };
 
-}  // namespace cvd
\ No newline at end of file
+}  // namespace cuttlefish
diff --git a/host/libs/screen_connector/screen_connector_common.h b/host/libs/screen_connector/screen_connector_common.h
new file mode 100644
index 0000000..48c7c76
--- /dev/null
+++ b/host/libs/screen_connector/screen_connector_common.h
@@ -0,0 +1,99 @@
+/*
+ * 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 <cstdint>
+#include <functional>
+#include <type_traits>
+
+#include <android-base/logging.h>
+#include "common/libs/utils/size_utils.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+namespace cuttlefish {
+
+template<typename T>
+struct is_movable {
+  static constexpr const bool value =
+      std::is_move_constructible<T>::value &&
+      std::is_move_assignable<T>::value;
+};
+
+// this callback type is going directly to socket-based or wayland ScreenConnector
+using GenerateProcessedFrameCallbackImpl = std::function<void(std::uint32_t /*display_number*/,
+                                                              std::uint8_t* /*frame_pixels*/)>;
+
+class ScreenConnectorSource {
+ public:
+  virtual ~ScreenConnectorSource() = default;
+  // Runs the given callback on the next available frame after the given
+  // frame number and returns true if successful.
+  virtual bool OnNextFrame(
+      const GenerateProcessedFrameCallbackImpl& frame_callback) = 0;
+  virtual void ReportClientsConnected(bool /*have_clients*/) { /* ignore by default */ }
+  ScreenConnectorSource() = default;
+};
+
+struct ScreenConnectorInfo {
+  // functions are intended to be inlined
+  static constexpr std::uint32_t BytesPerPixel() { return 4; }
+  static std::uint32_t ScreenCount() {
+    auto config = ChkAndGetConfig();
+    auto display_configs = config->display_configs();
+    return static_cast<std::uint32_t>(display_configs.size());
+  }
+  static std::uint32_t ScreenHeight(std::uint32_t display_number) {
+    auto config = ChkAndGetConfig();
+    auto display_configs = config->display_configs();
+    CHECK_GT(display_configs.size(), display_number);
+    return display_configs[display_number].height;
+  }
+  static std::uint32_t ScreenWidth(std::uint32_t display_number) {
+    auto config = ChkAndGetConfig();
+    auto display_configs = config->display_configs();
+    CHECK_GE(display_configs.size(), display_number);
+    return display_configs[display_number].width;
+  }
+  static std::uint32_t ScreenStrideBytes(std::uint32_t display_number) {
+    return AlignToPowerOf2(ScreenWidth(display_number) * BytesPerPixel(), 4);
+  }
+  static std::uint32_t ScreenSizeInBytes(std::uint32_t display_number) {
+    return ScreenStrideBytes(display_number) * ScreenHeight(display_number);
+  }
+ private:
+  static auto ChkAndGetConfig() -> decltype(cuttlefish::CuttlefishConfig::Get()) {
+    auto config = cuttlefish::CuttlefishConfig::Get();
+    CHECK(config) << "Config is Missing";
+    return config;
+  }
+};
+
+struct ScreenConnectorFrameRenderer {
+  virtual bool RenderConfirmationUi(const std::uint32_t display,
+                                    std::uint8_t* raw_frame) = 0;
+  virtual bool IsCallbackSet() const = 0;
+  virtual ~ScreenConnectorFrameRenderer() = default;
+};
+
+// this is inherited by the data type that represents the processed frame
+// being moved around.
+struct ScreenConnectorFrameInfo {
+  std::uint32_t display_number_;
+  bool is_success_;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/screen_connector/screen_connector_ctrl.h b/host/libs/screen_connector/screen_connector_ctrl.h
new file mode 100644
index 0000000..9b90152
--- /dev/null
+++ b/host/libs/screen_connector/screen_connector_ctrl.h
@@ -0,0 +1,104 @@
+/*
+ * 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 <atomic>
+#include <condition_variable>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "common/libs/concurrency/semaphore.h"
+
+namespace cuttlefish {
+/**
+ * mechanism to orchestrate concurrent executions of threads
+ * that work for screen connector
+ *
+ * One thing is when any of wayland/socket-based connector or
+ * confirmation UI has a frame, it should wake up the consumer
+ * The two queues are separate, so the conditional variables,
+ * etc, can't be in the queue
+ */
+class ScreenConnectorCtrl {
+ public:
+  enum class ModeType {
+    kAndroidMode,
+    kConfUI_Mode
+  };
+
+  ScreenConnectorCtrl() : atomic_mode_(ModeType::kAndroidMode) {}
+
+  /**
+   * The thread that enqueues Android frames will call this to wait until
+   * the mode is kAndroidMode
+   *
+   * Logically, using atomic_mode_ alone is not sufficient. Using mutex alone
+   * is logically complete but slow.
+   *
+   * Note that most of the time, the mode is kAndroidMode. Also, note that
+   * this method is called at every single frame.
+   *
+   * As an optimization, we check atomic_mode_ first. If failed, we wait for
+   * kAndroidMode with mutex-based lock
+   *
+   * The actual synchronization is not at the and_mode_cv_.wait line but at
+   * this line:
+   *     if (atomic_mode_ == ModeType::kAndroidMode) {
+   *
+   * This trick reduces the flag checking delays by 70+% on a Gentoo based
+   * amd64 desktop, with Linux 5.10
+   */
+  void WaitAndroidMode() {
+    if (atomic_mode_ == ModeType::kAndroidMode) {
+      return ;
+    }
+    auto check = [this]() -> bool { return atomic_mode_ == ModeType::kAndroidMode; };
+    std::unique_lock<std::mutex> lock(mode_mtx_);
+    and_mode_cv_.wait(lock, check);
+  }
+
+  void SetMode(const ModeType mode) {
+    std::lock_guard<std::mutex> lock(mode_mtx_);
+    atomic_mode_ = mode;
+    if (atomic_mode_ == ModeType::kAndroidMode) {
+      and_mode_cv_.notify_all();
+    }
+  }
+
+  auto GetMode() {
+    std::lock_guard<std::mutex> lock(mode_mtx_);
+    ModeType ret_val = atomic_mode_;
+    return ret_val;
+  }
+
+  void SemWait() { sem_.SemWait(); }
+
+  // Only called by the producers
+  void SemPost() { sem_.SemPost(); }
+
+ private:
+  std::mutex mode_mtx_;
+  std::condition_variable and_mode_cv_;
+  std::atomic<ModeType> atomic_mode_;
+
+  // track the total number of items in all queues
+  Semaphore sem_;
+};
+
+} // namespace cuttlefish
diff --git a/host/libs/screen_connector/screen_connector_queue.h b/host/libs/screen_connector/screen_connector_queue.h
new file mode 100644
index 0000000..2019168
--- /dev/null
+++ b/host/libs/screen_connector/screen_connector_queue.h
@@ -0,0 +1,125 @@
+/*
+ * 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 <deque>
+#include <memory>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+
+#include "common/libs/concurrency/semaphore.h"
+
+namespace cuttlefish {
+// move-based concurrent queue
+template<typename T>
+class ScreenConnectorQueue {
+
+ public:
+  static const int kQSize = 2;
+
+  static_assert( is_movable<T>::value,
+                 "Items in ScreenConnectorQueue should be std::mov-able");
+
+  ScreenConnectorQueue(Semaphore& sc_sem)
+      : q_mutex_(std::make_unique<std::mutex>()), sc_semaphore_(sc_sem) {}
+  ScreenConnectorQueue(ScreenConnectorQueue&& cq) = delete;
+  ScreenConnectorQueue(const ScreenConnectorQueue& cq) = delete;
+  ScreenConnectorQueue& operator=(const ScreenConnectorQueue& cq) = delete;
+  ScreenConnectorQueue& operator=(ScreenConnectorQueue&& cq) = delete;
+
+  bool Empty() const {
+    const std::lock_guard<std::mutex> lock(*q_mutex_);
+    return buffer_.empty();
+  }
+
+  auto Size() const {
+    const std::lock_guard<std::mutex> lock(*q_mutex_);
+    return buffer_.size();
+  }
+
+  void WaitEmpty() {
+    auto is_empty = [this](void) { return buffer_.empty(); };
+    std::unique_lock<std::mutex> lock(*q_mutex_);
+    q_empty_.wait(lock, is_empty);
+  }
+
+  /*
+   * PushBack( std::move(src) );
+   *
+   * Note: this queue is suppoed to be used only by ScreenConnector-
+   * related components such as ScreenConnectorSource
+   *
+   * The traditional assumption was that when webRTC or VNC calls
+   * OnFrameAfter, the call should be block until it could return
+   * one frame.
+   *
+   * Thus, the producers of this queue must not produce frames
+   * much faster than the consumer, VNC or WebRTC consumes.
+   * Therefore, when the small buffer is full -- which means
+   * VNC or WebRTC would not call OnFrameAfter --, the producer
+   * should stop adding itmes to the queue.
+   *
+   */
+  void PushBack(T&& item) {
+    std::unique_lock<std::mutex> lock(*q_mutex_);
+    if (Full()) {
+      auto is_empty =
+          [this](void){ return buffer_.empty(); };
+      q_empty_.wait(lock, is_empty);
+    }
+    buffer_.push_back(std::move(item));
+    /* Whether the total number of items in ALL queus is 0 or not
+     * is tracked via a semaphore shared by all queues
+     *
+     * This is NOT intended to block queue from pushing an item
+     * This IS intended to awake the screen_connector consumer thread
+     * when one or more items are available at least in one queue
+     */
+    sc_semaphore_.SemPost();
+  }
+  void PushBack(T& item) = delete;
+  void PushBack(const T& item) = delete;
+
+  /*
+   * PopFront must be preceded by sc_semaphore_.SemWaitItem()
+   *
+   */
+  T PopFront() {
+    const std::lock_guard<std::mutex> lock(*q_mutex_);
+    auto item = std::move(buffer_.front());
+    buffer_.pop_front();
+    if (buffer_.empty()) {
+      q_empty_.notify_all();
+    }
+    return item;
+  }
+
+ private:
+  bool Full() const {
+    // call this in a critical section
+    // after acquiring q_mutex_
+    return kQSize == buffer_.size();
+  }
+  std::deque<T> buffer_;
+  std::unique_ptr<std::mutex> q_mutex_;
+  std::condition_variable q_empty_;
+  Semaphore& sc_semaphore_;
+};
+
+} // namespace cuttlefish
diff --git a/host/libs/screen_connector/socket_based_screen_connector.cpp b/host/libs/screen_connector/socket_based_screen_connector.cpp
deleted file mode 100644
index 7e6333a..0000000
--- a/host/libs/screen_connector/socket_based_screen_connector.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#include "host/libs/screen_connector/socket_based_screen_connector.h"
-
-#include <glog/logging.h>
-
-#include "common/libs/fs/shared_fd.h"
-
-namespace cvd {
-
-SocketBasedScreenConnector::SocketBasedScreenConnector(int frames_fd) {
-screen_server_thread_ =
-    std::thread([this, frames_fd]() { ServerLoop(frames_fd); });
-}
-
-bool SocketBasedScreenConnector::OnFrameAfter(
-    std::uint32_t frame_number, const FrameCallback& frame_callback) {
-  int buffer_idx = WaitForNewFrameSince(&frame_number);
-  void* buffer = GetBuffer(buffer_idx);
-  frame_callback(frame_number, reinterpret_cast<uint8_t*>(buffer));
-  return true;
-}
-
-int SocketBasedScreenConnector::WaitForNewFrameSince(std::uint32_t* seq_num) {
-  std::unique_lock<std::mutex> lock(new_frame_mtx_);
-  while (seq_num_ == *seq_num) {
-    new_frame_cond_var_.wait(lock);
-  }
-  *seq_num = seq_num_;
-  return newest_buffer_;
-}
-
-void* SocketBasedScreenConnector::GetBuffer(int buffer_idx) {
-  if (buffer_idx < 0) return nullptr;
-  buffer_idx %= NUM_BUFFERS_;
-  return &buffer_[buffer_idx * ScreenSizeInBytes()];
-}
-
-void SocketBasedScreenConnector::ServerLoop(int frames_fd) {
-  if (frames_fd < 0) {
-    LOG(FATAL) << "Invalid file descriptor: " << frames_fd;
-    return;
-  }
-  auto server = SharedFD::Dup(frames_fd);
-  close(frames_fd);
-  if (!server->IsOpen()) {
-    LOG(FATAL) << "Unable to dup screen server: " << server->StrError();
-    return;
-  }
-
-  int current_buffer = 0;
-
-  while (1) {
-    LOG(INFO) << "Screen Connector accepting connections...";
-    auto conn = SharedFD::Accept(*server);
-    if (!conn->IsOpen()) {
-      LOG(ERROR) << "Disconnected fd returned from accept";
-      continue;
-    }
-    while (conn->IsOpen()) {
-      int32_t size = 0;
-      if (conn->Read(&size, sizeof(size)) < 0) {
-        LOG(ERROR) << "Failed to read from hwcomposer: " << conn->StrError();
-        break;
-      }
-      auto buff = reinterpret_cast<uint8_t*>(GetBuffer(current_buffer));
-      while (size > 0) {
-        auto read = conn->Read(buff, size);
-        if (read < 0) {
-          LOG(ERROR) << "Failed to read from hwcomposer: " << conn->StrError();
-          conn->Close();
-          break;
-        }
-        size -= read;
-        buff += read;
-      }
-      BroadcastNewFrame(current_buffer);
-      current_buffer = (current_buffer + 1) % NUM_BUFFERS_;
-    }
-  }
-}
-
-void SocketBasedScreenConnector::BroadcastNewFrame(int buffer_idx) {
-  {
-    std::lock_guard<std::mutex> lock(new_frame_mtx_);
-    seq_num_++;
-    newest_buffer_ = buffer_idx;
-  }
-  new_frame_cond_var_.notify_all();
-}
-} // namespace cvd
diff --git a/host/libs/screen_connector/socket_based_screen_connector.h b/host/libs/screen_connector/socket_based_screen_connector.h
deleted file mode 100644
index 0ed8414..0000000
--- a/host/libs/screen_connector/socket_based_screen_connector.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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 "host/libs/screen_connector/screen_connector.h"
-
-#include <atomic>
-#include <cinttypes>
-#include <condition_variable>
-#include <mutex>
-#include <thread>
-#include <vector>
-
-namespace cvd {
-
-class SocketBasedScreenConnector : public ScreenConnector {
- public:
-  explicit SocketBasedScreenConnector(int frames_fd);
-
-  bool OnFrameAfter(std::uint32_t frame_number,
-                    const FrameCallback& frame_callback) override;
-
- private:
-  static constexpr int NUM_BUFFERS_ = 4;
-
-  int WaitForNewFrameSince(std::uint32_t* seq_num);
-  void* GetBuffer(int buffer_idx);
-  void ServerLoop(int frames_fd);
-  void BroadcastNewFrame(int buffer_idx);
-
-  std::vector<std::uint8_t> buffer_ =
-      std::vector<std::uint8_t>(NUM_BUFFERS_ * ScreenSizeInBytes());
-  std::uint32_t seq_num_{0};
-  int newest_buffer_ = 0;
-  std::condition_variable new_frame_cond_var_;
-  std::mutex new_frame_mtx_;
-  std::thread screen_server_thread_;
-};
-
-} // namespace cvd
\ No newline at end of file
diff --git a/host/libs/screen_connector/wayland_screen_connector.cpp b/host/libs/screen_connector/wayland_screen_connector.cpp
index 8059290..7eb6642 100644
--- a/host/libs/screen_connector/wayland_screen_connector.cpp
+++ b/host/libs/screen_connector/wayland_screen_connector.cpp
@@ -19,13 +19,11 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include <future>
-
-#include <glog/logging.h>
+#include <android-base/logging.h>
 
 #include "host/libs/wayland/wayland_server.h"
 
-namespace cvd {
+namespace cuttlefish {
 
 WaylandScreenConnector::WaylandScreenConnector(int frames_fd) {
   int wayland_fd = fcntl(frames_fd, F_DUPFD_CLOEXEC, 3);
@@ -35,14 +33,10 @@
   server_.reset(new wayland::WaylandServer(wayland_fd));
 }
 
-bool WaylandScreenConnector::OnFrameAfter(
-    std::uint32_t frame_number, const FrameCallback& frame_callback) {
-  std::future<void> frame_callback_completed_future =
-      server_->OnFrameAfter(frame_number, frame_callback);
-
-  frame_callback_completed_future.get();
-
+bool WaylandScreenConnector::OnNextFrame(
+    const GenerateProcessedFrameCallbackImpl& frame_callback) {
+  server_->OnNextFrame(frame_callback);
   return true;
 }
 
-}  // namespace cvd
\ No newline at end of file
+}  // namespace cuttlefish
diff --git a/host/libs/screen_connector/wayland_screen_connector.h b/host/libs/screen_connector/wayland_screen_connector.h
index 537bb31..00e7ca0 100644
--- a/host/libs/screen_connector/wayland_screen_connector.h
+++ b/host/libs/screen_connector/wayland_screen_connector.h
@@ -16,23 +16,23 @@
 
 #pragma once
 
-#include "host/libs/screen_connector/screen_connector.h"
+#include "host/libs/screen_connector/screen_connector_common.h"
 
 #include <memory>
 
 #include "host/libs/wayland/wayland_server.h"
 
-namespace cvd {
+namespace cuttlefish {
 
-class WaylandScreenConnector : public ScreenConnector {
+class WaylandScreenConnector : public ScreenConnectorSource {
  public:
   WaylandScreenConnector(int frames_fd);
 
-  bool OnFrameAfter(std::uint32_t frame_number,
-                    const FrameCallback& frame_callback) override;
+  bool OnNextFrame(
+      const GenerateProcessedFrameCallbackImpl& frame_callback) override;
 
  private:
   std::unique_ptr<wayland::WaylandServer> server_;
 };
 
-}
\ No newline at end of file
+}
diff --git a/host/libs/vm_manager/Android.bp b/host/libs/vm_manager/Android.bp
index 734dfe5..20c9027 100644
--- a/host/libs/vm_manager/Android.bp
+++ b/host/libs/vm_manager/Android.bp
@@ -13,26 +13,29 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_host_static {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
     name: "libcuttlefish_vm_manager",
     srcs: [
         "crosvm_manager.cpp",
+        "host_configuration.cpp",
         "qemu_manager.cpp",
         "vm_manager.cpp",
     ],
     header_libs: [
-        "cuttlefish_glog",
+        "vulkan_headers",
     ],
     shared_libs: [
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "libbase",
-        "libicuuc",
-    ],
-    static_libs: [
-        "libxml2",
-        "libcuttlefish_host_config",
         "libjsoncpp",
     ],
-    defaults: ["cuttlefish_host_only"],
+    static_libs: [
+        "libcuttlefish_host_config",
+    ],
+    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
 }
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index 7fecc34..dbc74f5 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -19,42 +19,69 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <cassert>
 #include <string>
 #include <vector>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
+#include <vulkan/vulkan.h>
 
 #include "common/libs/utils/environment.h"
 #include "common/libs/utils/network.h"
 #include "common/libs/utils/subprocess.h"
+#include "common/libs/utils/files.h"
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/known_paths.h"
 #include "host/libs/vm_manager/qemu_manager.h"
 
+namespace cuttlefish {
 namespace vm_manager {
 
 namespace {
 
-std::string GetControlSocketPath(const vsoc::CuttlefishConfig* config) {
-  return config->ForDefaultInstance()
+std::string GetControlSocketPath(const CuttlefishConfig& config) {
+  return config.ForDefaultInstance()
       .PerInstanceInternalPath("crosvm_control.sock");
 }
 
-void AddTapFdParameter(cvd::Command* crosvm_cmd, const std::string& tap_name) {
-  auto tap_fd = cvd::OpenTapInterface(tap_name);
+SharedFD AddTapFdParameter(Command* crosvm_cmd,
+                                const std::string& tap_name) {
+  auto tap_fd = OpenTapInterface(tap_name);
   if (tap_fd->IsOpen()) {
     crosvm_cmd->AddParameter("--tap-fd=", tap_fd);
   } else {
     LOG(ERROR) << "Unable to connect to " << tap_name << ": "
                << tap_fd->StrError();
   }
+  return tap_fd;
+}
+
+bool ReleaseDhcpLeases(const std::string& lease_path, SharedFD tap_fd) {
+  auto lease_file_fd = SharedFD::Open(lease_path, O_RDONLY);
+  if (!lease_file_fd->IsOpen()) {
+    LOG(ERROR) << "Could not open leases file \"" << lease_path << '"';
+    return false;
+  }
+  bool success = true;
+  auto dhcp_leases = ParseDnsmasqLeases(lease_file_fd);
+  for (auto& lease : dhcp_leases) {
+    std::uint8_t dhcp_server_ip[] = {192, 168, 96, (std::uint8_t) (ForCurrentInstance(1) * 4 - 3)};
+    if (!ReleaseDhcp4(tap_fd, lease.mac_address, lease.ip_address, dhcp_server_ip)) {
+      LOG(ERROR) << "Failed to release " << lease;
+      success = false;
+    } else {
+      LOG(INFO) << "Successfully dropped " << lease;
+    }
+  }
+  return success;
 }
 
 bool Stop() {
-  auto config = vsoc::CuttlefishConfig::Get();
-  cvd::Command command(config->crosvm_binary());
+  auto config = CuttlefishConfig::Get();
+  Command command(config->crosvm_binary());
   command.AddParameter("stop");
-  command.AddParameter(GetControlSocketPath(config));
+  command.AddParameter(GetControlSocketPath(*config));
 
   auto process = command.Start();
 
@@ -63,65 +90,67 @@
 
 }  // namespace
 
-const std::string CrosvmManager::name() { return "crosvm"; }
+bool CrosvmManager::IsSupported() {
+#ifdef __ANDROID__
+  return true;
+#else
+  return HostSupportsQemuCli();
+#endif
+}
 
-std::vector<std::string> CrosvmManager::ConfigureGpu(const std::string& gpu_mode) {
+std::vector<std::string> CrosvmManager::ConfigureGpuMode(
+    const std::string& gpu_mode) {
   // Override the default HAL search paths in all cases. We do this because
   // the HAL search path allows for fallbacks, and fallbacks in conjunction
   // with properities lead to non-deterministic behavior while loading the
   // HALs.
-  if (gpu_mode == vsoc::kGpuModeGuestSwiftshader) {
+  if (gpu_mode == kGpuModeGuestSwiftshader) {
     return {
+        "androidboot.cpuvulkan.version=" + std::to_string(VK_API_VERSION_1_1),
         "androidboot.hardware.gralloc=minigbm",
-        "androidboot.hardware.hwcomposer=cutf_hwc2",
-        "androidboot.hardware.egl=swiftshader",
+        "androidboot.hardware.hwcomposer=ranchu",
+        "androidboot.hardware.egl=angle",
         "androidboot.hardware.vulkan=pastel",
     };
   }
 
-  // Try to load the Nvidia modeset kernel module. Running Crosvm with Nvidia's EGL library on a
-  // fresh machine after a boot will fail because the Nvidia EGL library will fork to run the
-  // nvidia-modprobe command and the main Crosvm process will abort after receiving the exit signal
-  // of the forked child which is interpreted as a failure.
-  cvd::Command modprobe_cmd("/usr/bin/nvidia-modprobe");
-  modprobe_cmd.AddParameter("--modeset");
-  modprobe_cmd.Start().Wait();
-
-  if (gpu_mode == vsoc::kGpuModeDrmVirgl) {
+  if (gpu_mode == kGpuModeDrmVirgl) {
     return {
+      "androidboot.cpuvulkan.version=0",
       "androidboot.hardware.gralloc=minigbm",
       "androidboot.hardware.hwcomposer=drm_minigbm",
       "androidboot.hardware.egl=mesa",
     };
   }
-  if (gpu_mode == vsoc::kGpuModeGfxStream) {
+  if (gpu_mode == kGpuModeGfxStream) {
     return {
+        "androidboot.cpuvulkan.version=0",
         "androidboot.hardware.gralloc=minigbm",
-        "androidboot.hardware.hwcomposer=drm_minigbm",
+        "androidboot.hardware.hwcomposer=ranchu",
         "androidboot.hardware.egl=emulation",
         "androidboot.hardware.vulkan=ranchu",
-        "androidboot.hardware.gltransport=virtio-gpu-pipe",
+        "androidboot.hardware.gltransport=virtio-gpu-asg",
     };
   }
   return {};
 }
 
-std::vector<std::string> CrosvmManager::ConfigureBootDevices() {
-  // PCI domain 0, bus 0, device 1, function 0
+std::string CrosvmManager::ConfigureBootDevices(int num_disks) {
   // TODO There is no way to control this assignment with crosvm (yet)
-  if (cvd::HostArch() == "x86_64") {
-    return { "androidboot.boot_devices=pci0000:00/0000:00:01.0" };
+  if (HostArch() == Arch::X86_64) {
+    // crosvm has an additional PCI device for an ISA bridge
+    return ConfigureMultipleBootDevices("pci0000:00/0000:00:", 1, num_disks);
   } else {
-    return { "androidboot.boot_devices=10000.pci" };
+    // On ARM64 crosvm, block devices are on their own bridge, so we don't
+    // need to calculate it, and the path is always the same
+    return "androidboot.boot_devices=10000.pci";
   }
 }
 
-CrosvmManager::CrosvmManager(const vsoc::CuttlefishConfig* config)
-    : VmManager(config) {}
-
-std::vector<cvd::Command> CrosvmManager::StartCommands() {
-  auto instance = config_->ForDefaultInstance();
-  cvd::Command crosvm_cmd(config_->crosvm_binary(), [](cvd::Subprocess* proc) {
+std::vector<Command> CrosvmManager::StartCommands(
+    const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
+  Command crosvm_cmd(config.crosvm_binary(), [](Subprocess* proc) {
     auto stopped = Stop();
     if (stopped) {
       return true;
@@ -129,101 +158,264 @@
     LOG(WARNING) << "Failed to stop VMM nicely, attempting to KILL";
     return KillSubprocess(proc);
   });
+
+  int hvc_num = 0;
+  int serial_num = 0;
+  auto add_hvc_sink = [&crosvm_cmd, &hvc_num]() {
+    crosvm_cmd.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num,
+                            ",type=sink");
+  };
+  auto add_serial_sink = [&crosvm_cmd, &serial_num]() {
+    crosvm_cmd.AddParameter("--serial=hardware=serial,num=", ++serial_num,
+                            ",type=sink");
+  };
+  auto add_hvc_console = [&crosvm_cmd, &hvc_num](const std::string& output) {
+    crosvm_cmd.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num,
+                            ",type=file,path=", output, ",console=true");
+  };
+  auto add_serial_console_ro = [&crosvm_cmd,
+                                &serial_num](const std::string& output) {
+    crosvm_cmd.AddParameter("--serial=hardware=serial,num=", ++serial_num,
+                            ",type=file,path=", output, ",earlycon=true");
+  };
+  auto add_serial_console = [&crosvm_cmd, &serial_num](
+                                const std::string& output,
+                                const std::string& input) {
+    crosvm_cmd.AddParameter("--serial=hardware=serial,num=", ++serial_num,
+                            ",type=file,path=", output, ",input=", input,
+                            ",earlycon=true");
+  };
+  auto add_hvc_ro = [&crosvm_cmd, &hvc_num](const std::string& output) {
+    crosvm_cmd.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num,
+                            ",type=file,path=", output);
+  };
+  auto add_hvc = [&crosvm_cmd, &hvc_num](const std::string& output,
+                                         const std::string& input) {
+    crosvm_cmd.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num,
+                            ",type=file,path=", output, ",input=", input);
+  };
+  // Deprecated; do not add any more users
+  auto add_serial = [&crosvm_cmd, &serial_num](const std::string& output,
+                                               const std::string& input) {
+    crosvm_cmd.AddParameter("--serial=hardware=serial,num=", ++serial_num,
+                            ",type=file,path=", output, ",input=", input);
+  };
+
   crosvm_cmd.AddParameter("run");
 
-  auto gpu_mode = config_->gpu_mode();
+  if (!config.smt()) {
+    crosvm_cmd.AddParameter("--no-smt");
+  }
 
-  if (gpu_mode == vsoc::kGpuModeGuestSwiftshader) {
+  if (config.vhost_net()) {
+    crosvm_cmd.AddParameter("--vhost-net");
+  }
+
+  if (config.protected_vm()) {
+    crosvm_cmd.AddParameter("--protected-vm");
+  }
+
+  if (config.gdb_port() > 0) {
+    CHECK(config.cpus() == 1) << "CPUs must be 1 for crosvm gdb mode";
+    crosvm_cmd.AddParameter("--gdb=", config.gdb_port());
+  }
+
+  auto display_configs = config.display_configs();
+  CHECK_GE(display_configs.size(), 1);
+  auto display_config = display_configs[0];
+
+  auto gpu_mode = config.gpu_mode();
+
+  if (gpu_mode == kGpuModeGuestSwiftshader) {
     crosvm_cmd.AddParameter("--gpu=2D,",
-                            "width=", config_->x_res(), ",",
-                            "height=", config_->y_res());
-  } else if (gpu_mode == vsoc::kGpuModeDrmVirgl ||
-             gpu_mode == vsoc::kGpuModeGfxStream) {
-    crosvm_cmd.AddParameter(gpu_mode == vsoc::kGpuModeGfxStream ?
+                            "width=", display_config.width, ",",
+                            "height=", display_config.height);
+  } else if (gpu_mode == kGpuModeDrmVirgl || gpu_mode == kGpuModeGfxStream) {
+    crosvm_cmd.AddParameter(gpu_mode == kGpuModeGfxStream ?
                                 "--gpu=gfxstream," : "--gpu=",
-                            "width=", config_->x_res(), ",",
-                            "height=", config_->y_res(), ",",
+                            "width=", display_config.width, ",",
+                            "height=", display_config.height, ",",
                             "egl=true,surfaceless=true,glx=false,gles=true");
-    crosvm_cmd.AddParameter("--wayland-sock=", instance.frames_socket_path());
   }
-  if (!config_->final_ramdisk_path().empty()) {
-    crosvm_cmd.AddParameter("--initrd=", config_->final_ramdisk_path());
-  }
-  crosvm_cmd.AddParameter("--mem=", config_->memory_mb());
-  crosvm_cmd.AddParameter("--cpus=", config_->cpus());
-  crosvm_cmd.AddParameter("--params=", kernel_cmdline_);
-  for (const auto& disk : instance.virtual_disk_paths()) {
-    crosvm_cmd.AddParameter("--rwdisk=", disk);
-  }
-  crosvm_cmd.AddParameter("--socket=", GetControlSocketPath(config_));
+  crosvm_cmd.AddParameter("--wayland-sock=", instance.frames_socket_path());
 
-  if (frontend_enabled_) {
-    crosvm_cmd.AddParameter("--single-touch=", instance.touch_socket_path(),
-                            ":", config_->x_res(), ":", config_->y_res());
+  // crosvm_cmd.AddParameter("--null-audio");
+  crosvm_cmd.AddParameter("--mem=", config.memory_mb());
+  crosvm_cmd.AddParameter("--cpus=", config.cpus());
+
+  auto disk_num = instance.virtual_disk_paths().size();
+  CHECK_GE(VmManager::kMaxDisks, disk_num)
+      << "Provided too many disks (" << disk_num << "), maximum "
+      << VmManager::kMaxDisks << "supported";
+  for (const auto& disk : instance.virtual_disk_paths()) {
+    crosvm_cmd.AddParameter(config.protected_vm() ? "--disk=" :
+                                                    "--rwdisk=", disk);
+  }
+  crosvm_cmd.AddParameter("--socket=", GetControlSocketPath(config));
+
+  if (config.enable_vnc_server() || config.enable_webrtc()) {
+    auto touch_type_parameter =
+        config.enable_webrtc() ? "--multi-touch=" : "--single-touch=";
+    crosvm_cmd.AddParameter(touch_type_parameter, instance.touch_socket_path(),
+                            ":", display_config.width, ":",
+                            display_config.height);
     crosvm_cmd.AddParameter("--keyboard=", instance.keyboard_socket_path());
   }
+  if (config.enable_webrtc()) {
+    crosvm_cmd.AddParameter("--switches=", instance.switches_socket_path());
+  }
 
-  AddTapFdParameter(&crosvm_cmd, instance.wifi_tap_name());
+  auto wifi_tap = AddTapFdParameter(&crosvm_cmd, instance.wifi_tap_name());
   AddTapFdParameter(&crosvm_cmd, instance.mobile_tap_name());
 
-  crosvm_cmd.AddParameter("--rw-pmem-device=", instance.access_kregistry_path());
+  if (FileExists(instance.access_kregistry_path())) {
+    crosvm_cmd.AddParameter("--rw-pmem-device=",
+                            instance.access_kregistry_path());
+  }
 
-  // TODO remove this (use crosvm's seccomp files)
-  crosvm_cmd.AddParameter("--disable-sandbox");
+  if (FileExists(instance.pstore_path())) {
+    crosvm_cmd.AddParameter("--pstore=path=", instance.pstore_path(),
+                            ",size=", FileSize(instance.pstore_path()));
+  }
+
+  if (config.enable_sandbox()) {
+    const bool seccomp_exists = DirectoryExists(config.seccomp_policy_dir());
+    const std::string& var_empty_dir = kCrosvmVarEmptyDir;
+    const bool var_empty_available = DirectoryExists(var_empty_dir);
+    if (!var_empty_available || !seccomp_exists) {
+      LOG(FATAL) << var_empty_dir << " is not an existing, empty directory."
+                 << "seccomp-policy-dir, " << config.seccomp_policy_dir()
+                 << " does not exist " << std::endl;
+      return {};
+    }
+    crosvm_cmd.AddParameter("--seccomp-policy-dir=", config.seccomp_policy_dir());
+  } else {
+    crosvm_cmd.AddParameter("--disable-sandbox");
+  }
 
   if (instance.vsock_guest_cid() >= 2) {
     crosvm_cmd.AddParameter("--cid=", instance.vsock_guest_cid());
   }
 
-  // Redirect the first serial port with the kernel logs to the appropriate file
-  crosvm_cmd.AddParameter("--serial=num=1,type=file,path=",
-                          instance.kernel_log_pipe_name(), ",console=true");
+  // Use a virtio-console instance for the main kernel console. All
+  // messages will switch from earlycon to virtio-console after the driver
+  // is loaded, and crosvm will append to the kernel log automatically
+  add_hvc_console(instance.kernel_log_pipe_name());
 
-  // Redirect standard input to a pipe for the console forwarder host process
-  // to handle.
-  cvd::SharedFD console_in_rd, console_in_wr;
-  if (!cvd::SharedFD::Pipe(&console_in_rd, &console_in_wr)) {
-    LOG(ERROR) << "Failed to create console pipe for crosvm's stdin: "
-               << console_in_rd->StrError();
-    return {};
-  }
-  auto console_pipe_name = instance.console_pipe_name();
-  if (mkfifo(console_pipe_name.c_str(), 0660) != 0) {
-    auto error = errno;
-    LOG(ERROR) << "Failed to create console fifo for crosvm: "
-               << strerror(error);
-    return {};
+  if (config.console()) {
+    // stdin is the only currently supported way to write data to a serial port in
+    // crosvm. A file (named pipe) is used here instead of stdout to ensure only
+    // the serial port output is received by the console forwarder as crosvm may
+    // print other messages to stdout.
+    if (config.kgdb() || config.use_bootloader()) {
+      add_serial_console(instance.console_out_pipe_name(),
+                         instance.console_in_pipe_name());
+      // In kgdb mode, we have the interactive console on ttyS0 (both Android's
+      // console and kdb), so we can disable the virtio-console port usually
+      // allocated to Android's serial console, and redirect it to a sink. This
+      // ensures that that the PCI device assignments (and thus sepolicy) don't
+      // have to change
+      add_hvc_sink();
+    } else {
+      add_serial_sink();
+      add_hvc(instance.console_out_pipe_name(),
+              instance.console_in_pipe_name());
+    }
+  } else {
+    // Use an 8250 UART (ISA or platform device) for earlycon, as the
+    // virtio-console driver may not be available for early messages
+    // In kgdb mode, earlycon is an interactive console, and so early
+    // dmesg will go there instead of the kernel.log
+    if (config.kgdb() || config.use_bootloader()) {
+      add_serial_console_ro(instance.kernel_log_pipe_name());
+    }
+
+    // as above, create a fake virtio-console 'sink' port when the serial
+    // console is disabled, so the PCI device ID assignments don't move
+    // around
+    add_hvc_sink();
   }
 
-  // This fd will only be read from, but it's open with write access as well to
-  // keep the pipe open in case the subprocesses exit.
-  cvd::SharedFD console_out_rd =
-      cvd::SharedFD::Open(console_pipe_name.c_str(), O_RDWR);
-  if (!console_out_rd->IsOpen()) {
-    LOG(ERROR) << "Failed to open console fifo for reads: "
-               << console_out_rd->StrError();
+  if (config.enable_gnss_grpc_proxy()) {
+    add_serial(instance.gnss_out_pipe_name(), instance.gnss_in_pipe_name());
+  }
+
+  SharedFD log_out_rd, log_out_wr;
+  if (!SharedFD::Pipe(&log_out_rd, &log_out_wr)) {
+    LOG(ERROR) << "Failed to create log pipe for crosvm's stdout/stderr: "
+               << log_out_rd->StrError();
     return {};
   }
-  // stdin is the only currently supported way to write data to a serial port in
-  // crosvm. A file (named pipe) is used here instead of stdout to ensure only
-  // the serial port output is received by the console forwarder as crosvm may
-  // print other messages to stdout.
-  crosvm_cmd.AddParameter("--serial=num=2,type=file,path=", console_pipe_name,
-                          ",stdin=true");
+  crosvm_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, log_out_wr);
+  crosvm_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, log_out_wr);
 
-  crosvm_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn,
-                           console_in_rd);
-  cvd::Command console_cmd(config_->console_forwarder_binary());
-  console_cmd.AddParameter("--console_in_fd=", console_in_wr);
-  console_cmd.AddParameter("--console_out_fd=", console_out_rd);
+  Command log_tee_cmd(HostBinaryPath("log_tee"));
+  log_tee_cmd.AddParameter("--process_name=crosvm");
+  log_tee_cmd.AddParameter("--log_fd_in=", log_out_rd);
+
+  // Serial port for logcat, redirected to a pipe
+  add_hvc_ro(instance.logcat_pipe_name());
+
+  add_hvc(instance.PerInstanceInternalPath("keymaster_fifo_vm.out"),
+          instance.PerInstanceInternalPath("keymaster_fifo_vm.in"));
+  add_hvc(instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
+          instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"));
+
+  if (config.enable_host_bluetooth()) {
+    add_hvc(instance.PerInstanceInternalPath("bt_fifo_vm.out"),
+            instance.PerInstanceInternalPath("bt_fifo_vm.in"));
+  } else {
+    add_hvc_sink();
+  }
+  for (auto i = 0; i < VmManager::kMaxDisks - disk_num; i++) {
+    add_hvc_sink();
+  }
+  CHECK(hvc_num + disk_num == VmManager::kMaxDisks + VmManager::kDefaultNumHvcs)
+      << "HVC count (" << hvc_num << ") + disk count (" << disk_num << ") "
+      << "is not the expected total of "
+      << VmManager::kMaxDisks + VmManager::kDefaultNumHvcs << " devices";
+
+  if (config.enable_audio()) {
+    crosvm_cmd.AddParameter("--ac97=backend=vios,server=" +
+                            config.ForDefaultInstance().audio_server_path());
+  }
+
+  // TODO(b/172286896): This is temporarily optional, but should be made
+  // unconditional and moved up to the other network devices area
+  if (config.ethernet()) {
+    AddTapFdParameter(&crosvm_cmd, instance.ethernet_tap_name());
+  }
+
+  // TODO(b/162071003): virtiofs crashes without sandboxing, this should be fixed
+  if (config.enable_sandbox()) {
+    // Set up directory shared with virtiofs
+    crosvm_cmd.AddParameter("--shared-dir=", instance.PerInstancePath(kSharedDirName),
+                            ":shared:type=fs");
+  }
 
   // This needs to be the last parameter
-  crosvm_cmd.AddParameter(config_->GetKernelImageToUse());
+  crosvm_cmd.AddParameter("--bios=", config.bootloader());
 
-  std::vector<cvd::Command> ret;
+  // Only run the leases workaround if we are not using the new network
+  // bridge architecture - in that case, we have a wider DHCP address
+  // space and stale leases should be much less of an issue
+  if (!FileExists("/var/run/cuttlefish-dnsmasq-cvd-wbr.leases")) {
+    // TODO(schuffelen): QEMU also needs this and this is not the best place for
+    // this code. Find a better place to put it.
+    auto lease_file =
+        ForCurrentInstance("/var/run/cuttlefish-dnsmasq-cvd-wbr-") + ".leases";
+    if (!ReleaseDhcpLeases(lease_file, wifi_tap)) {
+      LOG(ERROR) << "Failed to release wifi DHCP leases. Connecting to the wifi "
+                 << "network may not work.";
+    }
+  }
+
+  std::vector<Command> ret;
   ret.push_back(std::move(crosvm_cmd));
-  ret.push_back(std::move(console_cmd));
+  ret.push_back(std::move(log_tee_cmd));
   return ret;
 }
 
-}  // namespace vm_manager
+} // namespace vm_manager
+} // namespace cuttlefish
+
diff --git a/host/libs/vm_manager/crosvm_manager.h b/host/libs/vm_manager/crosvm_manager.h
index 848f2ae..9d41d68 100644
--- a/host/libs/vm_manager/crosvm_manager.h
+++ b/host/libs/vm_manager/crosvm_manager.h
@@ -23,21 +23,25 @@
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/subprocess.h"
 
+namespace cuttlefish {
 namespace vm_manager {
 
 // Starts a guest VM with crosvm. It requires the host package to support the
 // qemu-cli capability (for network only).
 class CrosvmManager : public VmManager {
  public:
-  static const std::string name();
-  static bool EnsureInstanceDirExists(const std::string& instance_dir);
-  static std::vector<std::string> ConfigureGpu(const std::string& gpu_mode);
-  static std::vector<std::string> ConfigureBootDevices();
-
-  CrosvmManager(const vsoc::CuttlefishConfig* config);
+  static std::string name() { return "crosvm"; }
+  CrosvmManager(Arch arch) : VmManager(arch) {}
   virtual ~CrosvmManager() = default;
 
-  std::vector<cvd::Command> StartCommands() override;
+  bool IsSupported() override;
+  std::vector<std::string> ConfigureGpuMode(const std::string&) override;
+  std::string ConfigureBootDevices(int num_disks) override;
+
+  std::vector<cuttlefish::Command> StartCommands(
+      const CuttlefishConfig& config) override;
 };
 
-}  // namespace vm_manager
+} // namespace vm_manager
+} // namespace cuttlefish
+
diff --git a/host/libs/vm_manager/host_configuration.cpp b/host/libs/vm_manager/host_configuration.cpp
new file mode 100644
index 0000000..f49f74d
--- /dev/null
+++ b/host/libs/vm_manager/host_configuration.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "host/libs/vm_manager/host_configuration.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <sys/utsname.h>
+
+#include "common/libs/utils/users.h"
+
+namespace cuttlefish {
+namespace vm_manager {
+namespace {
+
+bool UserInGroup(const std::string& group,
+                 std::vector<std::string>* config_commands) {
+  if (!InGroup(group)) {
+    LOG(ERROR) << "User must be a member of " << group;
+    config_commands->push_back("# Add your user to the " + group + " group:");
+    config_commands->push_back("sudo usermod -aG " + group + " $USER");
+    return false;
+  }
+  return true;
+}
+
+constexpr std::pair<int,int> invalid_linux_version = std::pair<int,int>();
+
+std::pair<int,int> GetLinuxVersion() {
+  struct utsname info;
+  if (!uname(&info)) {
+    char* digit = strtok(info.release, "+.-");
+    int major = atoi(digit);
+    if (digit) {
+      digit = strtok(NULL, "+.-");
+      int minor = atoi(digit);
+      return std::pair<int,int>{major, minor};
+    }
+  }
+  LOG(ERROR) << "Failed to detect Linux kernel version";
+  return invalid_linux_version;
+}
+
+bool LinuxVersionAtLeast(std::vector<std::string>* config_commands,
+                         const std::pair<int,int>& version,
+                         int major, int minor) {
+  if (version.first > major ||
+      (version.first == major && version.second >= minor)) {
+    return true;
+  }
+
+  LOG(ERROR) << "Kernel version must be >=" << major << "." << minor
+             << ", have " << version.first << "." << version.second;
+  config_commands->push_back("# Please upgrade your kernel to >=" +
+                             std::to_string(major) + "." +
+                             std::to_string(minor));
+  return false;
+}
+
+} // namespace
+
+bool ValidateHostConfiguration(std::vector<std::string>* config_commands) {
+  // if we can't detect the kernel version, just fail
+  auto version = GetLinuxVersion();
+  if (version == invalid_linux_version) {
+    return false;
+  }
+
+  // the check for cvdnetwork needs to happen even if the user is not in kvm, so
+  // we can't just say UserInGroup("kvm") && UserInGroup("cvdnetwork")
+  auto in_cvdnetwork = UserInGroup("cvdnetwork", config_commands);
+
+  // if we're in the virtaccess group this is likely to be a CrOS environment.
+  auto is_cros = InGroup("virtaccess");
+  if (is_cros) {
+    // relax the minimum kernel requirement slightly, as chromeos-4.4 has the
+    // needed backports to enable vhost_vsock
+    auto linux_ver_4_4 = LinuxVersionAtLeast(config_commands, version, 4, 4);
+    return in_cvdnetwork && linux_ver_4_4;
+  } else {
+    // this is regular Linux, so use the Debian group name and be more
+    // conservative with the kernel version check.
+    auto in_kvm = UserInGroup("kvm", config_commands);
+    auto linux_ver_4_8 = LinuxVersionAtLeast(config_commands, version, 4, 8);
+    return in_cvdnetwork && in_kvm && linux_ver_4_8;
+  }
+}
+
+} // namespace vm_manager
+} // namespace cuttlefish
+
diff --git a/host/libs/vm_manager/host_configuration.h b/host/libs/vm_manager/host_configuration.h
new file mode 100644
index 0000000..0705522
--- /dev/null
+++ b/host/libs/vm_manager/host_configuration.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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>
+#include <vector>
+
+namespace cuttlefish {
+namespace vm_manager {
+
+bool ValidateHostConfiguration(std::vector<std::string>* config_commands);
+
+} // namespace vm_manager
+} // namespace cuttlefish
+
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index cfc073c..f26818a 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -31,20 +31,22 @@
 #include <vector>
 
 #include <android-base/strings.h>
-#include <glog/logging.h>
+#include <android-base/logging.h>
+#include <vulkan/vulkan.h>
 
 #include "common/libs/fs/shared_select.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/subprocess.h"
 #include "common/libs/utils/users.h"
 #include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/known_paths.h"
 
+namespace cuttlefish {
 namespace vm_manager {
-
 namespace {
 
-std::string GetMonitorPath(const vsoc::CuttlefishConfig* config) {
-  return config->ForDefaultInstance()
+std::string GetMonitorPath(const CuttlefishConfig& config) {
+  return config.ForDefaultInstance()
       .PerInstanceInternalPath("qemu_monitor.sock");
 }
 
@@ -54,9 +56,9 @@
 }
 
 bool Stop() {
-  auto config = vsoc::CuttlefishConfig::Get();
-  auto monitor_path = GetMonitorPath(config);
-  auto monitor_sock = cvd::SharedFD::SocketLocalClient(
+  auto config = CuttlefishConfig::Get();
+  auto monitor_path = GetMonitorPath(*config);
+  auto monitor_sock = SharedFD::SocketLocalClient(
       monitor_path.c_str(), false, SOCK_STREAM);
 
   if (!monitor_sock->IsOpen()) {
@@ -85,37 +87,57 @@
 
 }  // namespace
 
-const std::string QemuManager::name() { return "qemu_cli"; }
+bool QemuManager::IsSupported() {
+  return HostSupportsQemuCli();
+}
 
-std::vector<std::string> QemuManager::ConfigureGpu(const std::string& gpu_mode) {
-  if (gpu_mode != vsoc::kGpuModeGuestSwiftshader) {
-    return {};
+std::vector<std::string> QemuManager::ConfigureGpuMode(
+    const std::string& gpu_mode) {
+  if (gpu_mode == kGpuModeGuestSwiftshader) {
+    // Override the default HAL search paths in all cases. We do this because
+    // the HAL search path allows for fallbacks, and fallbacks in conjunction
+    // with properities lead to non-deterministic behavior while loading the
+    // HALs.
+    return {
+        "androidboot.cpuvulkan.version=" + std::to_string(VK_API_VERSION_1_1),
+        "androidboot.hardware.gralloc=minigbm",
+        "androidboot.hardware.hwcomposer=ranchu",
+        "androidboot.hardware.egl=swiftshader",
+        "androidboot.hardware.vulkan=pastel",
+    };
   }
-  // Override the default HAL search paths in all cases. We do this because
-  // the HAL search path allows for fallbacks, and fallbacks in conjunction
-  // with properities lead to non-deterministic behavior while loading the
-  // HALs.
-  return {
+
+  if (gpu_mode == kGpuModeDrmVirgl) {
+    return {
+      "androidboot.cpuvulkan.version=0",
       "androidboot.hardware.gralloc=minigbm",
-      "androidboot.hardware.hwcomposer=cutf_cvm_ashmem",
-      "androidboot.hardware.egl=swiftshader",
-      "androidboot.hardware.vulkan=pastel",
-  };
+      "androidboot.hardware.hwcomposer=drm_minigbm",
+      "androidboot.hardware.egl=mesa",
+    };
+  }
+
+  return {};
 }
 
-std::vector<std::string> QemuManager::ConfigureBootDevices() {
-  // PCI domain 0, bus 0, device 3, function 0
-  // This is controlled with 'addr=0x3' in cf_qemu.sh
-  return { "androidboot.boot_devices=pci0000:00/0000:00:03.0" };
+std::string QemuManager::ConfigureBootDevices(int num_disks) {
+  switch (arch_) {
+    case Arch::X86:
+    case Arch::X86_64: {
+      // QEMU has additional PCI devices for an ISA bridge and PIIX4
+      return ConfigureMultipleBootDevices("pci0000:00/0000:00:", 2, num_disks);
+    }
+    case Arch::Arm:
+      return "androidboot.boot_devices=3f000000.pcie";
+    case Arch::Arm64:
+      return "androidboot.boot_devices=4010000000.pcie";
+  }
 }
 
-QemuManager::QemuManager(const vsoc::CuttlefishConfig* config)
-  : VmManager(config) {}
+std::vector<Command> QemuManager::StartCommands(
+    const CuttlefishConfig& config) {
+  auto instance = config.ForDefaultInstance();
 
-std::vector<cvd::Command> QemuManager::StartCommands() {
-  auto instance = config_->ForDefaultInstance();
-
-  auto stop = [](cvd::Subprocess* proc) {
+  auto stop = [](Subprocess* proc) {
     auto stopped = Stop();
     if (stopped) {
       return true;
@@ -124,33 +146,140 @@
                   << "attempting to KILL";
     return KillSubprocess(proc);
   };
+  std::string qemu_binary = config.qemu_binary_dir();
+  switch (arch_) {
+    case Arch::Arm:
+      qemu_binary += "/qemu-system-arm";
+      break;
+    case Arch::Arm64:
+      qemu_binary += "/qemu-system-aarch64";
+      break;
+    case Arch::X86:
+      qemu_binary += "/qemu-system-i386";
+      break;
+    case Arch::X86_64:
+      qemu_binary += "/qemu-system-x86_64";
+      break;
+  }
+  Command qemu_cmd(qemu_binary, stop);
 
-  bool is_arm = android::base::EndsWith(config_->qemu_binary(), "system-aarch64");
+  int hvc_num = 0;
+  int serial_num = 0;
+  auto add_hvc_sink = [&qemu_cmd, &hvc_num]() {
+    qemu_cmd.AddParameter("-chardev");
+    qemu_cmd.AddParameter("null,id=hvc", hvc_num);
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter(
+        "virtio-serial-pci-non-transitional,max_ports=1,id=virtio-serial",
+        hvc_num);
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter("virtconsole,bus=virtio-serial", hvc_num,
+                          ".0,chardev=hvc", hvc_num);
+    hvc_num++;
+  };
+  auto add_serial_sink = [&qemu_cmd, &serial_num]() {
+    qemu_cmd.AddParameter("-chardev");
+    qemu_cmd.AddParameter("null,id=serial", serial_num);
+    qemu_cmd.AddParameter("-serial");
+    qemu_cmd.AddParameter("chardev:serial", serial_num);
+    serial_num++;
+  };
+  auto add_serial_console_ro = [&qemu_cmd,
+                                &serial_num](const std::string& output) {
+    qemu_cmd.AddParameter("-chardev");
+    qemu_cmd.AddParameter("file,id=serial", serial_num, ",path=", output,
+                          ",append=on");
+    qemu_cmd.AddParameter("-serial");
+    qemu_cmd.AddParameter("chardev:serial", serial_num);
+    serial_num++;
+  };
+  auto add_serial_console = [&qemu_cmd,
+                             &serial_num](const std::string& prefix) {
+    qemu_cmd.AddParameter("-chardev");
+    qemu_cmd.AddParameter("pipe,id=serial", serial_num, ",path=", prefix);
+    qemu_cmd.AddParameter("-serial");
+    qemu_cmd.AddParameter("chardev:serial", serial_num);
+    serial_num++;
+  };
+  auto add_hvc_ro = [&qemu_cmd, &hvc_num](const std::string& output) {
+    qemu_cmd.AddParameter("-chardev");
+    qemu_cmd.AddParameter("file,id=hvc", hvc_num, ",path=", output,
+                          ",append=on");
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter(
+        "virtio-serial-pci-non-transitional,max_ports=1,id=virtio-serial",
+        hvc_num);
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter("virtconsole,bus=virtio-serial", hvc_num,
+                          ".0,chardev=hvc", hvc_num);
+    hvc_num++;
+  };
+  auto add_hvc = [&qemu_cmd, &hvc_num](const std::string& prefix) {
+    qemu_cmd.AddParameter("-chardev");
+    qemu_cmd.AddParameter("pipe,id=hvc", hvc_num, ",path=", prefix);
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter(
+        "virtio-serial-pci-non-transitional,max_ports=1,id=virtio-serial",
+        hvc_num);
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter("virtconsole,bus=virtio-serial", hvc_num,
+                          ".0,chardev=hvc", hvc_num);
+    hvc_num++;
+  };
 
-  cvd::Command qemu_cmd(config_->qemu_binary(), stop);
+  bool is_arm = arch_ == Arch::Arm || arch_ == Arch::Arm64;
+
+  auto access_kregistry_size_bytes = 0;
+  if (FileExists(instance.access_kregistry_path())) {
+    access_kregistry_size_bytes = FileSize(instance.access_kregistry_path());
+    CHECK((access_kregistry_size_bytes & (1024 * 1024 - 1)) == 0)
+        << instance.access_kregistry_path() <<  " file size ("
+        << access_kregistry_size_bytes << ") not a multiple of 1MB";
+  }
+
+  auto pstore_size_bytes = 0;
+  if (FileExists(instance.pstore_path())) {
+    pstore_size_bytes = FileSize(instance.pstore_path());
+    CHECK((pstore_size_bytes & (1024 * 1024 - 1)) == 0)
+        << instance.pstore_path() <<  " file size ("
+        << pstore_size_bytes << ") not a multiple of 1MB";
+  }
+
   qemu_cmd.AddParameter("-name");
   qemu_cmd.AddParameter("guest=", instance.instance_name(), ",debug-threads=on");
 
   qemu_cmd.AddParameter("-machine");
-  auto machine = is_arm ? "virt,gic_version=2" : "pc-i440fx-2.8,accel=kvm";
+  auto machine = is_arm ? "virt,gic-version=2,mte=on"
+                        : "pc-i440fx-2.8,accel=kvm,nvdimm=on";
   qemu_cmd.AddParameter(machine, ",usb=off,dump-guest-core=off");
 
   qemu_cmd.AddParameter("-m");
-  qemu_cmd.AddParameter(config_->memory_mb());
+  auto maxmem = config.memory_mb() +
+                access_kregistry_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",
+                        ",maxmem=", maxmem, "M", slots);
 
-  qemu_cmd.AddParameter("-realtime");
-  qemu_cmd.AddParameter("mlock=off");
+  qemu_cmd.AddParameter("-overcommit");
+  qemu_cmd.AddParameter("mem-lock=off");
 
+  // Assume SMT is always 2 threads per core, which is how most hardware
+  // today is configured, and the way crosvm does it
   qemu_cmd.AddParameter("-smp");
-  qemu_cmd.AddParameter(config_->cpus(), ",sockets=", config_->cpus(),
-                        ",cores=1,threads=1");
+  if (config.smt()) {
+    CHECK(config.cpus() % 2 == 0)
+        << "CPUs must be a multiple of 2 in SMT mode";
+    qemu_cmd.AddParameter(config.cpus(), ",cores=",
+                          config.cpus() / 2, ",threads=2");
+  } else {
+    qemu_cmd.AddParameter(config.cpus(), ",cores=",
+                          config.cpus(), ",threads=1");
+  }
 
   qemu_cmd.AddParameter("-uuid");
   qemu_cmd.AddParameter(instance.uuid());
 
-  qemu_cmd.AddParameter("-display");
-  qemu_cmd.AddParameter("none");
-
   qemu_cmd.AddParameter("-no-user-config");
   qemu_cmd.AddParameter("-nodefaults");
   qemu_cmd.AddParameter("-no-shutdown");
@@ -161,119 +290,207 @@
   qemu_cmd.AddParameter("-boot");
   qemu_cmd.AddParameter("strict=on");
 
-  qemu_cmd.AddParameter("-kernel");
-  qemu_cmd.AddParameter(config_->GetKernelImageToUse());
-
-  qemu_cmd.AddParameter("-append");
-  qemu_cmd.AddParameter(kernel_cmdline_);
-
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("virtio-serial-pci,id=virtio-serial0");
-
-  for (size_t i = 0; i < instance.virtual_disk_paths().size(); i++) {
-    auto bootindex = i == 0 ? ",bootindex=1" : "";
-    auto disk = instance.virtual_disk_paths()[i];
-    qemu_cmd.AddParameter("-drive");
-    qemu_cmd.AddParameter("file=", disk, ",if=none,id=drive-virtio-disk", i,
-                          ",aio=threads");
-    qemu_cmd.AddParameter("-device");
-    qemu_cmd.AddParameter("virtio-blk-pci,scsi=off,drive=drive-virtio-disk", i,
-                          ",id=virtio-disk", i, bootindex);
-  }
-
-  qemu_cmd.AddParameter("-netdev");
-  qemu_cmd.AddParameter("tap,id=hostnet0,ifname=", instance.wifi_tap_name(),
-                        ",script=no,downscript=no");
-
-  auto romfile = is_arm ? ",romfile" : "";
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("virtio-net-pci,netdev=hostnet0,id=net0", romfile);
-
-  qemu_cmd.AddParameter("-netdev");
-  qemu_cmd.AddParameter("tap,id=hostnet1,ifname=", instance.mobile_tap_name(),
-                        ",script=no,downscript=no");
-
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("virtio-net-pci,netdev=hostnet1,id=net1", romfile);
-
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("virtio-balloon-pci,id=balloon0");
-
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("virtio-gpu-pci,id=gpu0");
-
-  qemu_cmd.AddParameter("-object");
-  qemu_cmd.AddParameter("rng-random,id=objrng0,filename=/dev/urandom");
-
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("virtio-rng-pci,rng=objrng0,id=rng0,",
-                        "max-bytes=1024,period=2000");
-
-  qemu_cmd.AddParameter("-cpu");
-  qemu_cmd.AddParameter(is_arm ? "cortex-a53" : "host");
-
-  qemu_cmd.AddParameter("-msg");
-  qemu_cmd.AddParameter("timestamp=on");
-
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("AC97");
-
-  if (config_->use_bootloader()) {
-    qemu_cmd.AddParameter("-bios");
-    qemu_cmd.AddParameter(config_->bootloader());
-  }
-
   qemu_cmd.AddParameter("-chardev");
-  qemu_cmd.AddParameter("socket,id=charmonitor,path=", GetMonitorPath(config_),
+  qemu_cmd.AddParameter("socket,id=charmonitor,path=", GetMonitorPath(config),
                         ",server,nowait");
 
   qemu_cmd.AddParameter("-mon");
   qemu_cmd.AddParameter("chardev=charmonitor,id=monitor,mode=control");
 
-  qemu_cmd.AddParameter("-chardev");
-  qemu_cmd.AddParameter("file,id=charserial0,path=",
-                        instance.kernel_log_pipe_name(), ",append=on");
+  // In kgdb mode, earlycon is an interactive console, and so early
+  // dmesg will go there instead of the kernel.log. On QEMU, we do this
+  // bit of logic up before the hvc console is set up, so the command line
+  // flags appear in the right order and "append=on" does the right thing
+  if (!(config.console() && (config.kgdb() || config.use_bootloader()))) {
+    add_serial_console_ro(instance.kernel_log_pipe_name());
+  }
 
-  qemu_cmd.AddParameter("-device");
-  // On ARM, the early console can be PCI, and ISA is not supported
-  // On x86, the early console must be ISA, not PCI, so we start to get kernel
-  // messages as soon as possible. ISA devices do not have 'addr' assignments.
-  auto kernel_console_serial = is_arm ? "pci-serial" : "isa-serial";
-  qemu_cmd.AddParameter(kernel_console_serial, ",chardev=charserial0,id=serial0");
+  // Use a virtio-console instance for the main kernel console. All
+  // messages will switch from earlycon to virtio-console after the driver
+  // is loaded, and QEMU will append to the kernel log automatically
+  add_hvc_ro(instance.kernel_log_pipe_name());
 
-  qemu_cmd.AddParameter("-chardev");
-  qemu_cmd.AddParameter("socket,id=charserial1,path=", instance.console_path(),
-                        ",server,nowait");
+  if (config.console()) {
+    if (config.kgdb() || config.use_bootloader()) {
+      add_serial_console(instance.console_pipe_prefix());
 
-  qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter(kernel_console_serial, ",chardev=charserial1,id=serial1");
+      // In kgdb mode, we have the interactive console on ttyS0 (both Android's
+      // console and kdb), so we can disable the virtio-console port usually
+      // allocated to Android's serial console, and redirect it to a sink. This
+      // ensures that that the PCI device assignments (and thus sepolicy) don't
+      // have to change
+      add_hvc_sink();
+    } else {
+      add_serial_sink();
+      add_hvc(instance.console_pipe_prefix());
+    }
+  } else {
+    if (config.kgdb() || config.use_bootloader()) {
+      // The add_serial_console_ro() call above was applied by the time we reach
+      // this code, so we don't need another add_serial_*() call
+    }
 
-  if (config_->logcat_mode() == "serial") {
-    qemu_cmd.AddParameter("-chardev");
-    qemu_cmd.AddParameter("file,id=charchannel0,path=", instance.logcat_path(),
-                          ",append=on");
+    // as above, create a fake virtio-console 'sink' port when the serial
+    // console is disabled, so the PCI device ID assignments don't move
+    // around
+    add_hvc_sink();
+  }
+
+  if (config.enable_gnss_grpc_proxy()) {
+    add_serial_console(instance.gnss_pipe_prefix());
+  }
+
+  // Serial port for logcat, redirected to a pipe
+  add_hvc_ro(instance.logcat_pipe_name());
+
+  add_hvc(instance.PerInstanceInternalPath("keymaster_fifo_vm"));
+  add_hvc(instance.PerInstanceInternalPath("gatekeeper_fifo_vm"));
+  if (config.enable_host_bluetooth()) {
+    add_hvc(instance.PerInstanceInternalPath("bt_fifo_vm"));
+  } else {
+    add_hvc_sink();
+  }
+
+  auto disk_num = instance.virtual_disk_paths().size();
+
+  for (auto i = 0; i < VmManager::kMaxDisks - disk_num; i++) {
+    add_hvc_sink();
+  }
+
+  CHECK(hvc_num + disk_num == VmManager::kMaxDisks + VmManager::kDefaultNumHvcs)
+      << "HVC count (" << hvc_num << ") + disk count (" << disk_num << ") "
+      << "is not the expected total of "
+      << VmManager::kMaxDisks + VmManager::kDefaultNumHvcs << " devices";
+
+  CHECK_GE(VmManager::kMaxDisks, disk_num)
+      << "Provided too many disks (" << disk_num << "), maximum "
+      << VmManager::kMaxDisks << "supported";
+  auto readonly = config.protected_vm() ? ",readonly" : "";
+  for (size_t i = 0; i < disk_num; i++) {
+    auto bootindex = i == 0 ? ",bootindex=1" : "";
+    auto format = i == 0 ? "" : ",format=raw";
+    auto disk = instance.virtual_disk_paths()[i];
+    qemu_cmd.AddParameter("-drive");
+    qemu_cmd.AddParameter("file=", disk, ",if=none,id=drive-virtio-disk", i,
+                          ",aio=threads", format, readonly);
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter("virtio-blk-pci-non-transitional,scsi=off,drive=drive-virtio-disk", i,
+                          ",id=virtio-disk", i, bootindex);
+  }
+
+  if (config.gpu_mode() == kGpuModeDrmVirgl) {
+    qemu_cmd.AddParameter("-display");
+    qemu_cmd.AddParameter("egl-headless");
+
+    qemu_cmd.AddParameter("-vnc");
+    qemu_cmd.AddParameter(":", instance.vnc_server_port() - 5900);
+  } else {
+    qemu_cmd.AddParameter("-display");
+    qemu_cmd.AddParameter("none");
+  }
+
+  if (!is_arm && FileExists(instance.pstore_path())) {
+    // QEMU will assign the NVDIMM (ramoops pstore region) 100000000-1001fffff
+    // As we will pass this to ramoops, define this region first so it is always
+    // located at this address. This is currently x86 only.
+    qemu_cmd.AddParameter("-object");
+    qemu_cmd.AddParameter("memory-backend-file,id=objpmem0,share,mem-path=",
+                          instance.pstore_path(), ",size=", pstore_size_bytes);
 
     qemu_cmd.AddParameter("-device");
-    qemu_cmd.AddParameter("virtserialport,bus=virtio-serial0.0,nr=1,",
-                          "chardev=charchannel0,id=channel0,name=cf-logcat");
+    qemu_cmd.AddParameter("nvdimm,memdev=objpmem0,id=ramoops");
   }
 
-  if (config_->gdb_flag().size() > 0) {
-    qemu_cmd.AddParameter("-gdb");
-    qemu_cmd.AddParameter(config_->gdb_flag());
+  // QEMU does not implement virtio-pmem-pci for ARM64 yet; restore this
+  // when the device has been added
+  if (!is_arm && FileExists(instance.access_kregistry_path())) {
+    qemu_cmd.AddParameter("-object");
+    qemu_cmd.AddParameter("memory-backend-file,id=objpmem1,share,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("-initrd");
-  qemu_cmd.AddParameter(config_->final_ramdisk_path());
+  qemu_cmd.AddParameter("-object");
+  qemu_cmd.AddParameter("rng-random,id=objrng0,filename=/dev/urandom");
 
   qemu_cmd.AddParameter("-device");
-  qemu_cmd.AddParameter("vhost-vsock-pci,guest-cid=", instance.vsock_guest_cid());
+  qemu_cmd.AddParameter("virtio-rng-pci-non-transitional,rng=objrng0,id=rng0,",
+                        "max-bytes=1024,period=2000");
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("virtio-mouse-pci");
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("virtio-keyboard-pci");
+
+  auto vhost_net = config.vhost_net() ? ",vhost=on" : "";
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("virtio-balloon-pci-non-transitional,id=balloon0");
+
+  qemu_cmd.AddParameter("-netdev");
+  qemu_cmd.AddParameter("tap,id=hostnet0,ifname=", instance.wifi_tap_name(),
+                        ",script=no,downscript=no", vhost_net);
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("virtio-net-pci-non-transitional,netdev=hostnet0,id=net0");
+
+  qemu_cmd.AddParameter("-netdev");
+  qemu_cmd.AddParameter("tap,id=hostnet1,ifname=", instance.mobile_tap_name(),
+                        ",script=no,downscript=no", vhost_net);
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("virtio-net-pci-non-transitional,netdev=hostnet1,id=net1");
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("virtio-gpu-pci,id=gpu0");
+
+  qemu_cmd.AddParameter("-cpu");
+  qemu_cmd.AddParameter(IsHostCompatible(arch_) ? "host" : "max");
+
+  qemu_cmd.AddParameter("-msg");
+  qemu_cmd.AddParameter("timestamp=on");
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("vhost-vsock-pci-non-transitional,guest-cid=",
+                        instance.vsock_guest_cid());
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("AC97");
+
+  // TODO(b/172286896): This is temporarily optional, but should be made
+  // unconditional and moved up to the other network devices area
+  if (config.ethernet()) {
+    qemu_cmd.AddParameter("-netdev");
+    qemu_cmd.AddParameter("tap,id=hostnet2,ifname=", instance.ethernet_tap_name(),
+                          ",script=no,downscript=no", vhost_net);
+
+    qemu_cmd.AddParameter("-device");
+    qemu_cmd.AddParameter("virtio-net-pci-non-transitional,netdev=hostnet2,id=net2");
+  }
+
+  qemu_cmd.AddParameter("-device");
+  qemu_cmd.AddParameter("qemu-xhci,id=xhci");
+
+  qemu_cmd.AddParameter("-bios");
+  qemu_cmd.AddParameter(config.bootloader());
+
+  if (config.gdb_port() > 0) {
+    qemu_cmd.AddParameter("-S");
+    qemu_cmd.AddParameter("-gdb");
+    qemu_cmd.AddParameter("tcp::", config.gdb_port());
+  }
 
   LogAndSetEnv("QEMU_AUDIO_DRV", "none");
 
-  std::vector<cvd::Command> ret;
+  std::vector<Command> ret;
   ret.push_back(std::move(qemu_cmd));
   return ret;
 }
 
-}  // namespace vm_manager
+} // namespace vm_manager
+} // namespace cuttlefish
+
diff --git a/host/libs/vm_manager/qemu_manager.h b/host/libs/vm_manager/qemu_manager.h
index 4b04876..934a976 100644
--- a/host/libs/vm_manager/qemu_manager.h
+++ b/host/libs/vm_manager/qemu_manager.h
@@ -22,20 +22,26 @@
 
 #include "common/libs/fs/shared_fd.h"
 
+namespace cuttlefish {
 namespace vm_manager {
 
 // Starts a guest VM using the qemu command directly. It requires the host
 // package to support the qemu-cli capability.
 class QemuManager : public VmManager {
  public:
-  static const std::string name();
-  static std::vector<std::string> ConfigureGpu(const std::string& gpu_mode);
-  static std::vector<std::string> ConfigureBootDevices();
+  static std::string name() { return "qemu_cli"; }
 
-  QemuManager(const vsoc::CuttlefishConfig* config);
+  QemuManager(Arch arch) : VmManager(arch) {}
   virtual ~QemuManager() = default;
 
-  std::vector<cvd::Command> StartCommands() override;
+  bool IsSupported() override;
+  std::vector<std::string> ConfigureGpuMode(const std::string&) override;
+  std::string ConfigureBootDevices(int num_disks) override;
+
+  std::vector<cuttlefish::Command> StartCommands(
+      const CuttlefishConfig& config) override;
 };
 
-}  // namespace vm_manager
+} // namespace vm_manager
+} // namespace cuttlefish
+
diff --git a/host/libs/vm_manager/vm_manager.cpp b/host/libs/vm_manager/vm_manager.cpp
index d2810da..8c2ef57 100644
--- a/host/libs/vm_manager/vm_manager.cpp
+++ b/host/libs/vm_manager/vm_manager.cpp
@@ -16,174 +16,51 @@
 
 #include "host/libs/vm_manager/vm_manager.h"
 
+#include <android-base/logging.h>
+
+#include <iomanip>
 #include <memory>
 
-#include <glog/logging.h>
-#include <sys/utsname.h>
-
-#include "common/libs/utils/users.h"
 #include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/vm_manager/qemu_manager.h"
 #include "host/libs/vm_manager/crosvm_manager.h"
+#include "host/libs/vm_manager/qemu_manager.h"
 
+namespace cuttlefish {
 namespace vm_manager {
 
-VmManager::VmManager(const vsoc::CuttlefishConfig* config)
-    : config_(config) {}
-
-namespace{
-template <typename T>
-VmManager* GetManagerSingleton(const vsoc::CuttlefishConfig* config) {
-  static std::shared_ptr<VmManager> vm_manager(new T(config));
-  return vm_manager.get();
-}
-}
-
-std::map<std::string, VmManager::VmManagerHelper>
-    VmManager::vm_manager_helpers_ = {
-        {
-          QemuManager::name(),
-          {
-            GetManagerSingleton<QemuManager>,
-            vsoc::HostSupportsQemuCli,
-            QemuManager::ConfigureGpu,
-            QemuManager::ConfigureBootDevices,
-          },
-        },
-        {
-          CrosvmManager::name(),
-          {
-            GetManagerSingleton<CrosvmManager>,
-            // Same as Qemu for the time being
-            vsoc::HostSupportsQemuCli,
-            CrosvmManager::ConfigureGpu,
-            CrosvmManager::ConfigureBootDevices,
-          }
-        }
-    };
-
-VmManager* VmManager::Get(const std::string& vm_manager_name,
-                          const vsoc::CuttlefishConfig* config) {
-  if (VmManager::IsValidName(vm_manager_name)) {
-    return vm_manager_helpers_[vm_manager_name].builder(config);
+std::unique_ptr<VmManager> GetVmManager(const std::string& name, Arch arch) {
+  std::unique_ptr<VmManager> vmm;
+  if (name == QemuManager::name()) {
+    vmm.reset(new QemuManager(arch));
+  } else if (name == CrosvmManager::name()) {
+    vmm.reset(new CrosvmManager(arch));
   }
-  LOG(ERROR) << "Requested invalid VmManager: " << vm_manager_name;
-  return nullptr;
-}
-
-bool VmManager::IsValidName(const std::string& name) {
-  return vm_manager_helpers_.count(name) > 0;
-}
-
-bool VmManager::IsVmManagerSupported(const std::string& name) {
-  return VmManager::IsValidName(name) &&
-         vm_manager_helpers_[name].support_checker();
-}
-
-std::vector<std::string> VmManager::ConfigureGpuMode(
-    const std::string& vmm_name, const std::string& gpu_mode) {
-  auto it = vm_manager_helpers_.find(vmm_name);
-  if (it == vm_manager_helpers_.end()) {
+  if (!vmm) {
+    LOG(ERROR) << "Invalid VM manager: " << name;
     return {};
   }
-  return it->second.configure_gpu_mode(gpu_mode);
-}
-
-std::vector<std::string> VmManager::ConfigureBootDevices(
-    const std::string& vmm_name) {
-  auto it = vm_manager_helpers_.find(vmm_name);
-  if (it == vm_manager_helpers_.end()) {
+  if (!vmm->IsSupported()) {
+    LOG(ERROR) << "VM manager " << name << " is not supported on this machine.";
     return {};
   }
-  return it->second.configure_boot_devices();
+  return vmm;
 }
 
-std::vector<std::string> VmManager::GetValidNames() {
-  std::vector<std::string> ret = {};
-  for (const auto& key_val: vm_manager_helpers_) {
-    ret.push_back(key_val.first);
+std::string ConfigureMultipleBootDevices(const std::string& pci_path,
+                                         int pci_offset, int num_disks) {
+  int num_boot_devices =
+      (num_disks < VmManager::kDefaultNumBootDevices) ? num_disks : VmManager::kDefaultNumBootDevices;
+  std::string boot_devices_prop = "androidboot.boot_devices=";
+  for (int i = 0; i < num_boot_devices; i++) {
+    std::stringstream stream;
+    stream << std::setfill('0') << std::setw(2) << std::hex
+           << pci_offset + i + VmManager::kDefaultNumHvcs + VmManager::kMaxDisks - num_disks;
+    boot_devices_prop += pci_path + stream.str() + ".0,";
   }
-  return ret;
+  boot_devices_prop.pop_back();
+  return {boot_devices_prop};
 }
 
-bool VmManager::UserInGroup(const std::string& group,
-                            std::vector<std::string>* config_commands) {
-  if (!cvd::InGroup(group)) {
-    LOG(ERROR) << "User must be a member of " << group;
-    config_commands->push_back("# Add your user to the " + group + " group:");
-    config_commands->push_back("sudo usermod -aG " + group + " $USER");
-    return false;
-  }
-  return true;
-}
+} // namespace vm_manager
+} // namespace cuttlefish
 
-std::pair<int,int> VmManager::GetLinuxVersion() {
-  struct utsname info;
-  if (!uname(&info)) {
-    char* digit = strtok(info.release, "+.-");
-    int major = atoi(digit);
-    if (digit) {
-      digit = strtok(NULL, "+.-");
-      int minor = atoi(digit);
-      return std::pair<int,int>{major, minor};
-    }
-  }
-  LOG(ERROR) << "Failed to detect Linux kernel version";
-  return invalid_linux_version;
-}
-
-bool VmManager::LinuxVersionAtLeast(std::vector<std::string>* config_commands,
-                                    const std::pair<int,int>& version,
-                                    int major, int minor) {
-  if (version.first > major ||
-      (version.first == major && version.second >= minor)) {
-    return true;
-  }
-
-  LOG(ERROR) << "Kernel version must be >=" << major << "." << minor
-             << ", have " << version.first << "." << version.second;
-  config_commands->push_back("# Please upgrade your kernel to >=" +
-                             std::to_string(major) + "." +
-                             std::to_string(minor));
-  return false;
-}
-
-bool VmManager::ValidateHostConfiguration(
-    std::vector<std::string>* config_commands) const {
-  // if we can't detect the kernel version, just fail
-  auto version = VmManager::GetLinuxVersion();
-  if (version == invalid_linux_version) {
-    return false;
-  }
-
-  // the check for cvdnetwork needs to happen even if the user is not in kvm, so
-  // we can't just say UserInGroup("kvm") && UserInGroup("cvdnetwork")
-  auto in_cvdnetwork = VmManager::UserInGroup("cvdnetwork", config_commands);
-
-  // if we're in the virtaccess group this is likely to be a CrOS environment.
-  auto is_cros = cvd::InGroup("virtaccess");
-  if (is_cros) {
-    // relax the minimum kernel requirement slightly, as chromeos-4.4 has the
-    // needed backports to enable vhost_vsock
-    auto linux_ver_4_4 =
-      VmManager::LinuxVersionAtLeast(config_commands, version, 4, 4);
-    return in_cvdnetwork && linux_ver_4_4;
-  } else {
-    // this is regular Linux, so use the Debian group name and be more
-    // conservative with the kernel version check.
-    auto in_kvm = VmManager::UserInGroup("kvm", config_commands);
-    auto linux_ver_4_8 =
-      VmManager::LinuxVersionAtLeast(config_commands, version, 4, 8);
-    return in_cvdnetwork && in_kvm && linux_ver_4_8;
-  }
-}
-
-void VmManager::WithFrontend(bool enabled) {
-  frontend_enabled_ = enabled;
-}
-
-void VmManager::WithKernelCommandLine(const std::string& kernel_cmdline) {
-  kernel_cmdline_ = kernel_cmdline;
-}
-
-}  // namespace vm_manager
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index a86218c..b538e8f 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -15,75 +15,69 @@
  */
 #pragma once
 
-#include <map>
-#include <set>
 #include <string>
-#include <utility>
 #include <vector>
 
 #include <common/libs/utils/subprocess.h>
 #include <host/libs/config/cuttlefish_config.h>
 
+namespace cuttlefish {
 namespace vm_manager {
 
-// Superclass of every guest VM manager. It provides a static getter that
-// returns the requested vm manager as a singleton.
+// Superclass of every guest VM manager.
 class VmManager {
- public:
-  // Returns the most suitable vm manager as a singleton. It may return nullptr
-  // if the requested vm manager is not supported by the current version of the
-  // host packages
-  static VmManager* Get(const std::string& vm_manager_name,
-                        const vsoc::CuttlefishConfig* config);
-  static bool IsValidName(const std::string& name);
-  static std::vector<std::string> ConfigureGpuMode(
-      const std::string& vmm_name, const std::string& gpu_mode);
-  static std::vector<std::string> ConfigureBootDevices(
-      const std::string& vmm_name);
-  static bool IsVmManagerSupported(const std::string& name);
-  static std::vector<std::string> GetValidNames();
+ protected:
+  const Arch arch_;
 
+ public:
+  // This is the number of HVC virtual console ports that should be configured
+  // by the VmManager. Because crosvm currently allocates these ports as the
+  // first PCI devices, and it does not control the allocation of PCI ID
+  // assignments, the number of these ports affects the PCI paths for
+  // subsequent PCI devices, and these paths are hard-coded in SEPolicy.
+  // Fortunately, HVC virtual console ports can be set up to be "sink" devices,
+  // so even if they are disabled and the guest isn't using them, they don't
+  // 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 = 6;
+
+  // This is the number of virtual disks (block devices) that should be
+  // configured by the VmManager. Related to the description above regarding
+  // HVC ports, this problem can also affect block devices (which are
+  // enumerated second) if not all of the block devices are available. Unlike
+  // HVC virtual console ports, block devices cannot be configured to be sinks,
+  // so we once again leverage HVC virtual console ports to "bump up" the last
+  // assigned virtual disk PCI ID (i.e. 2 disks = 7 hvcs, 1 disks = 8 hvcs)
+  static const int kMaxDisks = 3;
+
+  // This is the number of virtual disks that contribute to the named partition
+  // list (/dev/block/by-name/*) under Android. The partitions names from
+  // multiple disks *must not* collide. Normally we have one set of partitions
+  // from the powerwashed disk (operating system disk) and another set from
+  // the persistent disk
+  static const int kDefaultNumBootDevices = 2;
+
+  VmManager(Arch arch) : arch_(arch) {}
   virtual ~VmManager() = default;
 
-  virtual void WithFrontend(bool);
-  virtual void WithKernelCommandLine(const std::string&);
+  virtual bool IsSupported() = 0;
+  virtual std::vector<std::string> ConfigureGpuMode(const std::string&) = 0;
+  virtual std::string ConfigureBootDevices(int num_disks) = 0;
 
   // Starts the VMM. It will usually build a command and pass it to the
   // command_starter function, although it may start more than one. The
   // command_starter function allows to customize the way vmm commands are
   // started/tracked/etc.
-  virtual std::vector<cvd::Command> StartCommands() = 0;
-
-  virtual bool ValidateHostConfiguration(
-      std::vector<std::string>* config_commands) const;
-
- protected:
-  static bool UserInGroup(const std::string& group,
-                          std::vector<std::string>* config_commands);
-  static constexpr std::pair<int,int> invalid_linux_version =
-    std::pair<int,int>();
-  static std::pair<int,int> GetLinuxVersion();
-  static bool LinuxVersionAtLeast(std::vector<std::string>* config_commands,
-                                  const std::pair<int,int>& version,
-                                  int major, int minor);
-
-  const vsoc::CuttlefishConfig* config_;
-  VmManager(const vsoc::CuttlefishConfig* config);
-
-  bool frontend_enabled_;
-  std::string kernel_cmdline_;
-
- private:
-  struct VmManagerHelper {
-    // The singleton implementation
-    std::function<VmManager*(const vsoc::CuttlefishConfig*)> builder;
-    // Whether the host packages support this vm manager
-    std::function<bool()> support_checker;
-    std::function<std::vector<std::string>(const std::string&)> configure_gpu_mode;
-    std::function<std::vector<std::string>()> configure_boot_devices;
-  };
-  // Asociates a vm manager helper to every valid vm manager name
-  static std::map<std::string, VmManagerHelper> vm_manager_helpers_;
+  virtual std::vector<cuttlefish::Command> StartCommands(
+      const CuttlefishConfig& config) = 0;
 };
 
-}  // namespace vm_manager
+std::unique_ptr<VmManager> GetVmManager(const std::string&, Arch arch);
+
+std::string ConfigureMultipleBootDevices(const std::string& pci_path, int pci_offset,
+                                         int num_disks);
+
+} // namespace vm_manager
+} // namespace cuttlefish
+
diff --git a/host/libs/wayland/Android.bp b/host/libs/wayland/Android.bp
index 6123d67..4be6528 100644
--- a/host/libs/wayland/Android.bp
+++ b/host/libs/wayland/Android.bp
@@ -13,7 +13,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_host_static {
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
     name: "libcuttlefish_wayland_server",
     srcs: [
         "wayland_compositor.cpp",
@@ -23,6 +27,7 @@
         "wayland_server.cpp",
         "wayland_subcompositor.cpp",
         "wayland_surface.cpp",
+        "wayland_surfaces.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -35,6 +40,5 @@
         "libwayland_server",
         "libwayland_extension_server_protocols",
     ],
-    defaults: ["cuttlefish_host_only"],
+    defaults: ["cuttlefish_host"],
 }
-
diff --git a/host/libs/wayland/wayland_compositor.cpp b/host/libs/wayland/wayland_compositor.cpp
index 96fdd6d..6179092 100644
--- a/host/libs/wayland/wayland_compositor.cpp
+++ b/host/libs/wayland/wayland_compositor.cpp
@@ -21,6 +21,7 @@
 #include <wayland-server-core.h>
 #include <wayland-server-protocol.h>
 
+#include "host/libs/wayland/wayland_surface.h"
 #include "host/libs/wayland/wayland_utils.h"
 
 namespace wayland {
@@ -190,7 +191,12 @@
                << " compositor=" << compositor
                << " id=" << id;
 
-  Surface* surface = GetUserData<Surface>(compositor);
+  // Wayland seems to use a single global id space for all objects.
+  static std::atomic<std::uint32_t> sNextDisplayId{0};
+  uint32_t display_id = sNextDisplayId++;
+
+  Surfaces* surfaces = GetUserData<Surfaces>(compositor);
+  Surface* surface = surfaces->GetOrCreateSurface(display_id);
 
   wl_resource* surface_resource = wl_resource_create(
       client, &wl_surface_interface, wl_resource_get_version(compositor), id);
@@ -239,9 +245,9 @@
 
 }  // namespace
 
-void BindCompositorInterface(wl_display* display, Surface* surface) {
+void BindCompositorInterface(wl_display* display, Surfaces* surfaces) {
   wl_global_create(display, &wl_compositor_interface, kCompositorVersion,
-                   surface, bind_compositor);
+                   surfaces, bind_compositor);
 }
 
 }  // namespace wayland
diff --git a/host/libs/wayland/wayland_compositor.h b/host/libs/wayland/wayland_compositor.h
index 5054c40..18f0d7e 100644
--- a/host/libs/wayland/wayland_compositor.h
+++ b/host/libs/wayland/wayland_compositor.h
@@ -21,11 +21,11 @@
 
 #include <wayland-server-core.h>
 
-#include "host/libs/wayland/wayland_surface.h"
+#include "host/libs/wayland/wayland_surfaces.h"
 
 namespace wayland {
 
 // Binds the compositor interface to the given wayland server.
-void BindCompositorInterface(wl_display* display, Surface* surface);
+void BindCompositorInterface(wl_display* display, Surfaces* surfaces);
 
 }  // namespace wayland
\ No newline at end of file
diff --git a/host/libs/wayland/wayland_server.cpp b/host/libs/wayland/wayland_server.cpp
index 699fda2..4dc4b88 100644
--- a/host/libs/wayland/wayland_server.cpp
+++ b/host/libs/wayland/wayland_server.cpp
@@ -35,7 +35,7 @@
 struct WaylandServerState {
   struct wl_display* display_ = nullptr;
 
-  Surface surface_;
+  Surfaces surfaces_;
 };
 
 }  // namespace internal
@@ -78,7 +78,7 @@
 
   wl_display_init_shm(server_state_->display_);
 
-  BindCompositorInterface(server_state_->display_, &server_state_->surface_);
+  BindCompositorInterface(server_state_->display_, &server_state_->surfaces_);
   BindDmabufInterface(server_state_->display_);
   BindSubcompositorInterface(server_state_->display_);
   BindSeatInterface(server_state_->display_);
@@ -94,20 +94,8 @@
   wl_display_destroy(server_state_->display_);
 }
 
-std::future<void> WaylandServer::OnFrameAfter(
-    uint32_t frame_number,
-    const FrameCallback& frame_callback) {
-  // Wraps the given callback in a callback that can be waited on using
-  // std::future.
-  Surface::FrameCallbackPackaged packaged([&frame_callback](std::uint32_t frame_number,
-                                                   std::uint8_t* frame_pixels){
-    frame_callback(frame_number, frame_pixels);
-  });
-
-  std::future<void> frame_callback_complete = packaged.get_future();
-
-  server_state_->surface_.OnFrameAfter(frame_number, std::move(packaged));
-  return frame_callback_complete;
+void WaylandServer::OnNextFrame(const Surfaces::FrameCallback& callback) {
+  server_state_->surfaces_.OnNextFrame(callback);
 }
 
-}  // namespace wayland
\ No newline at end of file
+}  // namespace wayland
diff --git a/host/libs/wayland/wayland_server.h b/host/libs/wayland/wayland_server.h
index e73d74a..3149481 100644
--- a/host/libs/wayland/wayland_server.h
+++ b/host/libs/wayland/wayland_server.h
@@ -24,15 +24,14 @@
 #include <string>
 #include <thread>
 
+#include "host/libs/wayland/wayland_surfaces.h"
+
 namespace wayland {
 
 namespace internal {
 struct WaylandServerState;
 }  // namespace internal
 
-using FrameCallback = std::function<void(std::uint32_t /*frame_number*/,
-                                         std::uint8_t* /*frame_pixels*/)>;
-
 // A Wayland compositing server that provides an interface for receiving frame
 // updates from a connected client.
 class WaylandServer {
@@ -49,12 +48,10 @@
     WaylandServer(WaylandServer&& rhs) = delete;
     WaylandServer& operator=(WaylandServer&& rhs) = delete;
 
-    // Registers a callback to run on the next frame available after the given
-    // frame number.
-    std::future<void> OnFrameAfter(std::uint32_t frame_number,
-                                   const FrameCallback& frame_callback);
+    // Blocks until the given callback is run on the next frame available.
+    void OnNextFrame(const Surfaces::FrameCallback& callback);
 
-  private:
+   private:
     void ServerLoop(int wayland_socket_fd);
 
     bool server_ready_ = false;
diff --git a/host/libs/wayland/wayland_surface.cpp b/host/libs/wayland/wayland_surface.cpp
index eb4b401..e9abece 100644
--- a/host/libs/wayland/wayland_surface.cpp
+++ b/host/libs/wayland/wayland_surface.cpp
@@ -19,8 +19,13 @@
 #include <android-base/logging.h>
 #include <wayland-server-protocol.h>
 
+#include "host/libs/wayland/wayland_surfaces.h"
+
 namespace wayland {
 
+Surface::Surface(std::uint32_t display_number, Surfaces& surfaces)
+    : display_number_(display_number), surfaces_(surfaces) {}
+
 void Surface::SetRegion(const Region& region) {
   std::unique_lock<std::mutex> lock(state_mutex_);
   state_.region = region;
@@ -36,30 +41,27 @@
   state_.current_buffer = state_.pending_buffer;
   state_.pending_buffer = nullptr;
 
-  {
-    std::unique_lock<std::mutex> lock(callback_mutex_);
-    if (callback_ && callback_->frame_number < state_.current_frame_number) {
-      struct wl_shm_buffer* shm_buffer =
-          wl_shm_buffer_get(state_.current_buffer);
-      CHECK(shm_buffer != nullptr);
-
-      wl_shm_buffer_begin_access(shm_buffer);
-
-      const int32_t buffer_w = wl_shm_buffer_get_width(shm_buffer);
-      CHECK(buffer_w == state_.region.w);
-      const int32_t buffer_h = wl_shm_buffer_get_height(shm_buffer);
-      CHECK(buffer_h == state_.region.h);
-
-      uint8_t* buffer_pixels =
-          reinterpret_cast<uint8_t*>(wl_shm_buffer_get_data(shm_buffer));
-
-      callback_->frame_callback(state_.current_frame_number, buffer_pixels);
-      callback_.reset();
-
-      wl_shm_buffer_end_access(shm_buffer);
-    }
+  if (state_.current_buffer == nullptr) {
+    return;
   }
 
+  struct wl_shm_buffer* shm_buffer = wl_shm_buffer_get(state_.current_buffer);
+  CHECK(shm_buffer != nullptr);
+
+  wl_shm_buffer_begin_access(shm_buffer);
+
+  const int32_t buffer_w = wl_shm_buffer_get_width(shm_buffer);
+  CHECK(buffer_w == state_.region.w);
+  const int32_t buffer_h = wl_shm_buffer_get_height(shm_buffer);
+  CHECK(buffer_h == state_.region.h);
+
+  uint8_t* buffer_pixels =
+      reinterpret_cast<uint8_t*>(wl_shm_buffer_get_data(shm_buffer));
+
+  surfaces_.HandleSurfaceFrame(display_number_, buffer_pixels);
+
+  wl_shm_buffer_end_access(shm_buffer);
+
   wl_buffer_send_release(state_.current_buffer);
   wl_client_flush(wl_resource_get_client(state_.current_buffer));
 
@@ -67,11 +69,4 @@
   state_.current_frame_number++;
 }
 
-void Surface::OnFrameAfter(uint32_t frame_number,
-                           FrameCallbackPackaged frame_callback) {
-  std::unique_lock<std::mutex> lock(callback_mutex_);
-  callback_.emplace(PendingFrameCallback{frame_number,
-                                         std::move(frame_callback)});
-}
-
 }  // namespace wayland
\ No newline at end of file
diff --git a/host/libs/wayland/wayland_surface.h b/host/libs/wayland/wayland_surface.h
index e0d0a12..fcf2345 100644
--- a/host/libs/wayland/wayland_surface.h
+++ b/host/libs/wayland/wayland_surface.h
@@ -17,19 +17,19 @@
 
 #pragma once
 
-#include <optional>
 #include <stdint.h>
-#include <thread>
-#include <future>
+#include <mutex>
 
 #include <wayland-server-core.h>
 
 namespace wayland {
 
+class Surfaces;
+
 // Tracks the buffer associated with a Wayland surface.
 class Surface {
  public:
-  Surface() = default;
+  Surface(std::uint32_t display_number, Surfaces& surfaces);
   virtual ~Surface() = default;
 
   Surface(const Surface& rhs) = delete;
@@ -53,16 +53,10 @@
   // Commits the pending frame state.
   void Commit();
 
-  using FrameCallbackPackaged =
-    std::packaged_task<void(std::uint32_t /*frame_number*/,
-                            std::uint8_t* /*frame_pixels*/)>;
-
-  // Registers a callback that should be invoked on the first frame after
-  // the given frame number.
-  void OnFrameAfter(uint32_t frame_number,
-                    FrameCallbackPackaged frame_callback);
-
  private:
+  std::uint32_t display_number_;
+  Surfaces& surfaces_;
+
   struct State {
     uint32_t current_frame_number = 0;
 
@@ -78,15 +72,6 @@
 
   std::mutex state_mutex_;
   State state_;
-
-  struct PendingFrameCallback {
-    uint32_t frame_number;
-
-    FrameCallbackPackaged frame_callback;
-  };
-
-  std::mutex callback_mutex_;
-  std::optional<PendingFrameCallback> callback_;
 };
 
-}  // namespace wayland
\ No newline at end of file
+}  // namespace wayland
diff --git a/host/libs/wayland/wayland_surfaces.cpp b/host/libs/wayland/wayland_surfaces.cpp
new file mode 100644
index 0000000..7096574
--- /dev/null
+++ b/host/libs/wayland/wayland_surfaces.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#include "host/libs/wayland/wayland_surfaces.h"
+
+#include <android-base/logging.h>
+#include <wayland-server-protocol.h>
+
+#include "host/libs/wayland/wayland_surface.h"
+
+namespace wayland {
+
+Surface* Surfaces::GetOrCreateSurface(std::uint32_t id) {
+  std::unique_lock<std::mutex> lock(surfaces_mutex_);
+
+  auto [it, inserted] = surfaces_.try_emplace(id, nullptr);
+
+  std::unique_ptr<Surface>& surface_ptr = it->second;
+  if (inserted) {
+    surface_ptr.reset(new Surface(id, *this));
+  }
+  return surface_ptr.get();
+}
+
+void Surfaces::OnNextFrame(const FrameCallback& frame_callback) {
+  // Wraps the given callback in a std::package_task that can be waited upon
+  // for completion.
+  Surfaces::FrameCallbackPackaged frame_callback_packaged(
+      [&frame_callback](std::uint32_t display_number,
+                        std::uint8_t* frame_pixels) {
+        frame_callback(display_number, frame_pixels);
+      });
+
+  {
+    std::unique_lock<std::mutex> lock(callback_mutex_);
+    callback_.emplace(&frame_callback_packaged);
+  }
+
+  // Blocks until the frame_callback_packaged was called.
+  frame_callback_packaged.get_future().get();
+}
+
+void Surfaces::HandleSurfaceFrame(std::uint32_t display_number,
+                                  std::uint8_t* frame_bytes) {
+  std::unique_lock<std::mutex> lock(callback_mutex_);
+  if (callback_) {
+    (*callback_.value())(display_number, frame_bytes);
+    callback_.reset();
+  }
+}
+
+}  // namespace wayland
\ No newline at end of file
diff --git a/host/libs/wayland/wayland_surfaces.h b/host/libs/wayland/wayland_surfaces.h
new file mode 100644
index 0000000..ec67ca4
--- /dev/null
+++ b/host/libs/wayland/wayland_surfaces.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <stdint.h>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <thread>
+#include <unordered_map>
+
+namespace wayland {
+
+class Surface;
+
+class Surfaces {
+ public:
+  Surfaces() = default;
+  virtual ~Surfaces() = default;
+
+  Surfaces(const Surfaces& rhs) = delete;
+  Surfaces& operator=(const Surfaces& rhs) = delete;
+
+  Surfaces(Surfaces&& rhs) = delete;
+  Surfaces& operator=(Surfaces&& rhs) = delete;
+
+  Surface* GetOrCreateSurface(std::uint32_t id);
+
+  using FrameCallback = std::function<void(std::uint32_t /*display_number*/,
+                                           std::uint8_t* /*frame_pixels*/)>;
+
+  // Blocking
+  void OnNextFrame(const FrameCallback& callback);
+
+ private:
+  friend class Surface;
+  void HandleSurfaceFrame(std::uint32_t display_number,
+                          std::uint8_t* frame_bytes);
+
+  std::mutex surfaces_mutex_;
+  std::unordered_map<std::uint32_t, std::unique_ptr<Surface>> surfaces_;
+
+  using FrameCallbackPackaged = std::packaged_task<void(
+      std::uint32_t /*display_number*/, std::uint8_t* /*frame_bytes*/)>;
+
+  std::mutex callback_mutex_;
+  std::optional<FrameCallbackPackaged*> callback_;
+};
+
+}  // namespace wayland
diff --git a/host/libs/websocket/Android.bp b/host/libs/websocket/Android.bp
new file mode 100644
index 0000000..2a4a522
--- /dev/null
+++ b/host/libs/websocket/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_host_static {
+    name: "libcuttlefish_host_websocket",
+    srcs: [
+        "websocket_handler.cpp",
+        "websocket_server.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libssl",
+        "libcrypto",
+    ],
+    static_libs: [
+        "libcap",
+        "libwebsockets",
+    ],
+    defaults: ["cuttlefish_buildhost_only"],
+}
diff --git a/host/libs/websocket/websocket_handler.cpp b/host/libs/websocket/websocket_handler.cpp
new file mode 100644
index 0000000..9d6f636
--- /dev/null
+++ b/host/libs/websocket/websocket_handler.cpp
@@ -0,0 +1,70 @@
+//
+// 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.
+
+#include "host/libs/websocket/websocket_handler.h"
+
+#include <android-base/logging.h>
+#include <libwebsockets.h>
+
+namespace cuttlefish {
+
+WebSocketHandler::WebSocketHandler(struct lws* wsi) : wsi_(wsi) {}
+
+void WebSocketHandler::EnqueueMessage(const uint8_t* data, size_t len,
+                                      bool binary) {
+  std::vector<uint8_t> buffer(LWS_PRE + len, 0);
+  std::copy(data, data + len, buffer.begin() + LWS_PRE);
+  buffer_queue_.emplace_front(std::move(buffer), binary);
+  lws_callback_on_writable(wsi_);
+}
+
+// Attempts to write what's left on a websocket buffer to the websocket,
+// updating the buffer.
+void WebSocketHandler::WriteWsBuffer(WebSocketHandler::WsBuffer& ws_buffer) {
+  auto len = ws_buffer.data.size() - LWS_PRE;
+  auto flags = lws_write_ws_flags(
+      ws_buffer.binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT, true, true);
+  auto res = lws_write(wsi_, &ws_buffer.data[LWS_PRE], len,
+                       static_cast<enum lws_write_protocol>(flags));
+  // lws_write will write all bytes of the provided buffer or enqueue the ones
+  // it couldn't write for later, but it guarantees it will consume the entire
+  // buffer, so we only need to check for error.
+  if (res < 0) {
+    // This shouldn't happen since this function is called in response to a
+    // LWS_CALLBACK_SERVER_WRITEABLE call.
+    LOG(FATAL) << "Failed to write data on the websocket";
+  }
+}
+
+bool WebSocketHandler::OnWritable() {
+  if (buffer_queue_.empty()) {
+    return close_;
+  }
+  WriteWsBuffer(buffer_queue_.back());
+  buffer_queue_.pop_back();
+
+  if (!buffer_queue_.empty()) {
+    lws_callback_on_writable(wsi_);
+  }
+  // Only close if there are no more queued writes
+  return buffer_queue_.empty() && close_;
+}
+
+void WebSocketHandler::Close() {
+  close_ = true;
+  lws_callback_on_writable(wsi_);
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/websocket/websocket_handler.h b/host/libs/websocket/websocket_handler.h
new file mode 100644
index 0000000..45b51fa
--- /dev/null
+++ b/host/libs/websocket/websocket_handler.h
@@ -0,0 +1,66 @@
+//
+// 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 <deque>
+#include <vector>
+
+struct lws;
+
+namespace cuttlefish {
+
+class WebSocketHandler {
+ public:
+  WebSocketHandler(struct lws* wsi);
+  virtual ~WebSocketHandler() = default;
+
+  virtual void OnReceive(const uint8_t* msg, size_t len, bool binary) = 0;
+  virtual void OnReceive(const uint8_t* msg, size_t len, bool binary,
+                         [[maybe_unused]] bool is_final) {
+    OnReceive(msg, len, binary);
+  }
+  virtual void OnConnected() = 0;
+  virtual void OnClosed() = 0;
+
+  void EnqueueMessage(const uint8_t* data, size_t len, bool binary = false);
+  void EnqueueMessage(const char* data, size_t len, bool binary = false) {
+    EnqueueMessage(reinterpret_cast<const uint8_t*>(data), len, binary);
+  }
+  void Close();
+  bool OnWritable();
+
+ private:
+  struct WsBuffer {
+    WsBuffer(std::vector<uint8_t> data, bool binary)
+        : data(std::move(data)), binary(binary) {}
+    std::vector<uint8_t> data;
+    bool binary;
+  };
+
+  void WriteWsBuffer(WsBuffer& ws_buffer);
+
+  struct lws* wsi_;
+  bool close_ = false;
+  std::deque<WsBuffer> buffer_queue_;
+};
+
+class WebSocketHandlerFactory {
+ public:
+  virtual ~WebSocketHandlerFactory() = default;
+  virtual std::shared_ptr<WebSocketHandler> Build(struct lws* wsi) = 0;
+};
+
+}  // namespace cuttlefish
diff --git a/host/libs/websocket/websocket_server.cpp b/host/libs/websocket/websocket_server.cpp
new file mode 100644
index 0000000..cdfcba2
--- /dev/null
+++ b/host/libs/websocket/websocket_server.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+#include <host/libs/websocket/websocket_server.h>
+
+#include <string>
+#include <unordered_map>
+
+#include <android-base/logging.h>
+#include <libwebsockets.h>
+
+#include <host/libs/websocket/websocket_handler.h>
+
+namespace cuttlefish {
+WebSocketServer::WebSocketServer(
+    const char* protocol_name,
+    const std::string &certs_dir,
+    const std::string &assets_dir,
+    int server_port) {
+  std::string cert_file = certs_dir + "/server.crt";
+  std::string key_file = certs_dir + "/server.key";
+
+  retry_ = {
+      .secs_since_valid_ping = 3,
+      .secs_since_valid_hangup = 10,
+  };
+
+  struct lws_protocols protocols[] = {
+      {protocol_name, ServerCallback, 4096, 0, 0, nullptr, 0},
+      {nullptr, nullptr, 0, 0, 0, nullptr, 0}};
+
+  mount_ = {
+      .mount_next = nullptr,
+      .mountpoint = "/",
+      .mountpoint_len = 1,
+      .origin = assets_dir.c_str(),
+      .def = "index.html",
+      .protocol = nullptr,
+      .cgienv = nullptr,
+      .extra_mimetypes = nullptr,
+      .interpret = nullptr,
+      .cgi_timeout = 0,
+      .cache_max_age = 0,
+      .auth_mask = 0,
+      .cache_reusable = 0,
+      .cache_revalidate = 0,
+      .cache_intermediaries = 0,
+      .origin_protocol = LWSMPRO_FILE,  // files in a dir
+      .basic_auth_login_file = nullptr,
+  };
+
+  struct lws_context_creation_info info;
+  headers_ = {NULL, NULL,
+    "content-security-policy:",
+      "default-src 'self'; "
+      "style-src 'self' https://fonts.googleapis.com/; "
+      "font-src  https://fonts.gstatic.com/; "};
+
+  memset(&info, 0, sizeof info);
+  info.port = server_port;
+  info.mounts = &mount_;
+  info.protocols = protocols;
+  info.vhost_name = "localhost";
+  info.ws_ping_pong_interval = 10;
+  info.headers = &headers_;
+  info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+  info.ssl_cert_filepath = cert_file.c_str();
+  info.ssl_private_key_filepath = key_file.c_str();
+  info.retry_and_idle_policy = &retry_;
+
+  context_ = lws_create_context(&info);
+  if (!context_) {
+    LOG(FATAL) << "Failed to create websocket context";
+  }
+}
+
+void WebSocketServer::RegisterHandlerFactory(
+    const std::string &path,
+    std::unique_ptr<WebSocketHandlerFactory> handler_factory_p) {
+  handler_factories_[path] = std::move(handler_factory_p);
+}
+
+void WebSocketServer::Serve() {
+  int n = 0;
+  while (n >= 0) {
+    n = lws_service(context_, 0);
+  }
+  lws_context_destroy(context_);
+}
+
+std::unordered_map<struct lws*, std::shared_ptr<WebSocketHandler>> WebSocketServer::handlers_ = {};
+std::unordered_map<std::string, std::unique_ptr<WebSocketHandlerFactory>>
+    WebSocketServer::handler_factories_ = {};
+
+std::string WebSocketServer::GetPath(struct lws* wsi) {
+  auto len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
+  std::string path(len + 1, '\0');
+  auto ret = lws_hdr_copy(wsi, path.data(), path.size(), WSI_TOKEN_GET_URI);
+  if (ret <= 0) {
+      len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
+      path.resize(len + 1, '\0');
+      ret = lws_hdr_copy(wsi, path.data(), path.size(), WSI_TOKEN_HTTP_COLON_PATH);
+  }
+  if (ret < 0) {
+    LOG(FATAL) << "Something went wrong getting the path";
+  }
+  path.resize(len);
+  return path;
+}
+
+int WebSocketServer::ServerCallback(struct lws* wsi, enum lws_callback_reasons reason,
+                                    void* user, void* in, size_t len) {
+  switch (reason) {
+    case LWS_CALLBACK_ESTABLISHED: {
+      auto path = GetPath(wsi);
+      auto handler = InstantiateHandler(path, wsi);
+      if (!handler) {
+        // This message came on an unexpected uri, close the connection.
+        lws_close_reason(wsi, LWS_CLOSE_STATUS_NOSTATUS, (uint8_t*)"404", 3);
+        return -1;
+      }
+      handlers_[wsi] = handler;
+      handler->OnConnected();
+      break;
+    }
+    case LWS_CALLBACK_CLOSED: {
+      auto handler = handlers_[wsi];
+      if (handler) {
+        handler->OnClosed();
+        handlers_.erase(wsi);
+      }
+      break;
+    }
+    case LWS_CALLBACK_SERVER_WRITEABLE: {
+      auto handler = handlers_[wsi];
+      if (handler) {
+        auto should_close = handler->OnWritable();
+        if (should_close) {
+          lws_close_reason(wsi, LWS_CLOSE_STATUS_NORMAL, nullptr, 0);
+          return 1;
+        }
+      } else {
+        LOG(WARNING) << "Unknown wsi became writable";
+        return -1;
+      }
+      break;
+    }
+    case LWS_CALLBACK_RECEIVE: {
+      auto handler = handlers_[wsi];
+      if (handler) {
+        bool is_final = (lws_remaining_packet_payload(wsi) == 0) &&
+                        lws_is_final_fragment(wsi);
+        handler->OnReceive(reinterpret_cast<const uint8_t*>(in), len,
+                           lws_frame_is_binary(wsi), is_final);
+      } else {
+        LOG(WARNING) << "Unkwnown wsi sent data";
+      }
+      break;
+    }
+    default:
+      return lws_callback_http_dummy(wsi, reason, user, in, len);
+  }
+  return 0;
+}
+
+std::shared_ptr<WebSocketHandler> WebSocketServer::InstantiateHandler(
+    const std::string& uri_path, struct lws* wsi) {
+  auto it = handler_factories_.find(uri_path);
+  if (it == handler_factories_.end()) {
+    LOG(ERROR) << "Wrong path provided in URI: " << uri_path;
+    return nullptr;
+  } else {
+    LOG(INFO) << "Creating handler for " << uri_path;
+    return it->second->Build(wsi);
+  }
+}
+
+}  // namespace cuttlefish
diff --git a/host/libs/websocket/websocket_server.h b/host/libs/websocket/websocket_server.h
new file mode 100644
index 0000000..0695b3b
--- /dev/null
+++ b/host/libs/websocket/websocket_server.h
@@ -0,0 +1,60 @@
+/*
+ * 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>
+#include <unordered_map>
+
+#include <android-base/logging.h>
+#include <libwebsockets.h>
+
+#include <host/libs/websocket/websocket_handler.h>
+
+namespace cuttlefish {
+class WebSocketServer {
+ public:
+  WebSocketServer(
+    const char* protocol_name,
+    const std::string &certs_dir,
+    const std::string &assets_dir,
+    int port);
+  ~WebSocketServer() = default;
+
+  void RegisterHandlerFactory(
+    const std::string &path,
+    std::unique_ptr<WebSocketHandlerFactory> handler_factory_p);
+  void Serve();
+
+
+ private:
+  static std::unordered_map<struct lws*, std::shared_ptr<WebSocketHandler>> handlers_;
+  static std::unordered_map<std::string, std::unique_ptr<WebSocketHandlerFactory>>
+      handler_factories_;
+
+  static std::string GetPath(struct lws* wsi);
+  static int ServerCallback(struct lws* wsi, enum lws_callback_reasons reason,
+                            void* user, void* in, size_t len);
+  static std::shared_ptr<WebSocketHandler> InstantiateHandler(
+      const std::string& uri_path, struct lws* wsi);
+
+  struct lws_context* context_;
+  struct lws_http_mount mount_;
+  struct lws_protocol_vhost_options headers_;
+  lws_retry_bo_t retry_;
+};
+
+}  // namespace cuttlefish
diff --git a/host_package.mk b/host_package.mk
index 6a2ba84..bd6b51f 100644
--- a/host_package.mk
+++ b/host_package.mk
@@ -1,130 +1,17 @@
-LOCAL_PATH := $(call my-dir)
-
-cvd_host_package_tar := $(HOST_OUT)/cvd-host_package.tar.gz
-
-.PHONY: hosttar
-hosttar: $(cvd_host_package_tar)
-
-# Build this by default when a developer types make
-droidcore: $(cvd_host_package_tar)
-
-# Build and store them on the build server.
-$(call dist-for-goals, dist_files, $(cvd_host_package_tar))
-
-bin_path := $(notdir $(HOST_OUT_EXECUTABLES))
-lib_path := $(notdir $(HOST_OUT_SHARED_LIBRARIES))
-tests_path := $(notdir $(HOST_OUT_NATIVE_TESTS))
-webrtc_files_path := usr/share/webrtc
-
-cvd_host_executables := \
-    adb \
-    adbshell \
-    launch_cvd \
-    lpmake \
-    lpunpack \
-    socket_vsock_proxy \
-    adb_connector \
-    stop_cvd \
-    vnc_server \
-    cf_bpttool \
-    kernel_log_monitor \
-    extract-vmlinux \
-    crosvm \
-    aarch64-linux-gnu/crosvm \
-    aarch64-linux-gnu/libepoxy.so.0 \
-    aarch64-linux-gnu/libgbm.so.1 \
-    aarch64-linux-gnu/libminijail.so \
-    aarch64-linux-gnu/libvirglrenderer.so.1 \
-    x86_64-linux-gnu/crosvm \
-    x86_64-linux-gnu/libepoxy.so.0 \
-    x86_64-linux-gnu/libgbm.so.1 \
-    x86_64-linux-gnu/libminijail.so \
-    x86_64-linux-gnu/libvirglrenderer.so.1 \
-    x86_64-linux-gnu/libc++.so.1 \
-    x86_64-linux-gnu/libandroid-emu-shared.so \
-    x86_64-linux-gnu/libemugl_common.so \
-    x86_64-linux-gnu/libOpenglRender.so \
-    x86_64-linux-gnu/libgfxstream_backend.so \
-    logcat_receiver \
-    config_server \
-    tombstone_receiver \
-    console_forwarder \
-    assemble_cvd \
-    run_cvd \
-    cvd_status \
-    webRTC \
-    fsck.f2fs \
-    resize.f2fs \
-    make_f2fs \
-    tapsetiff \
-    newfs_msdos \
-
-ifneq ($(wildcard device/google/trout),)
-    cvd_host_executables += android.hardware.automotive.vehicle@2.0-virtualization-grpc-server
+cvd_host_packages := $(SOONG_HOST_OUT)/cvd-host_package.tar.gz
+ifeq ($(HOST_CROSS_OS)_$(HOST_CROSS_ARCH),linux_bionic_arm64)
+  cvd_host_packages += $(SOONG_OUT_DIR)/host/$(HOST_CROSS_OS)-$(HOST_CROSS_ARCH)/cvd-host_package.tar.gz
 endif
 
-cvd_host_tests := \
-    monotonic_time_test \
-    cuttlefish_net_tests \
+.PHONY: hosttar
+hosttar: $(cvd_host_packages)
 
-cvd_host_shared_libraries := \
-    libbase.so \
-    libcutils.so \
-    libcuttlefish_fs.so \
-    libcuttlefish_utils.so \
-    cuttlefish_tcp_socket.so \
-    cuttlefish_net.so \
-    liblog.so \
-    libnl.so \
-    libc++.so \
-    liblp.so \
-    libsparse-host.so \
-    libcrypto-host.so \
-    libcrypto_utils.so \
-    libext4_utils.so \
-    libz-host.so \
-    libicuuc-host.so \
-    libicui18n-host.so \
-    libandroidicu-host.so \
-    libcuttlefish_device_config.so \
-    cdisk_spec.so \
-    libprotobuf-cpp-full.so \
-    libziparchive.so \
-    libvpx.so \
-    libssl-host.so \
-    libopus.so \
-    libyuv.so \
-    libjpeg.so \
-    libhidlbase.so \
-    libutils.so \
-    libjsoncpp.so \
-    libgrpc++.so \
-    android.hardware.automotive.vehicle@2.0.so \
+# Build this by default when a developer types make
+droidcore: $(cvd_host_packages)
 
-webrtc_assets := \
-    index.html \
-    style.css \
-    js/logcat.js \
-    js/receive.js \
-    js/viewpane.js \
+# Dist
+# Note that only the last package is dist'ed. It would be from x86 in case of cf_x86_phone,
+# and from arm64 in case of cf_arm64_phone.
+$(call dist-for-goals, dist_files,$(word $(words $(cvd_host_packages)), $(cvd_host_packages)))
 
-webrtc_certs := \
-    server.crt \
-    server.key \
-    server.p12 \
-    trusted.pem \
-
-cvd_host_webrtc_files := \
-    $(addprefix assets/,$(webrtc_assets)) \
-    $(addprefix certs/,$(webrtc_certs)) \
-
-cvd_host_package_files := \
-     $(addprefix $(bin_path)/,$(cvd_host_executables)) \
-     $(addprefix $(lib_path)/,$(cvd_host_shared_libraries)) \
-     $(foreach test,$(cvd_host_tests), ${tests_path}/$(test)/$(test)) \
-     $(addprefix $(webrtc_files_path)/,$(cvd_host_webrtc_files)) \
-
-$(cvd_host_package_tar): PRIVATE_FILES := $(cvd_host_package_files)
-$(cvd_host_package_tar): $(addprefix $(HOST_OUT)/,$(cvd_host_package_files))
-	$(hide) rm -rf $@ && tar Scfz $@.tmp -C $(HOST_OUT) $(PRIVATE_FILES)
-	$(hide) mv $@.tmp $@
+cvd_host_packages :=
diff --git a/recovery/Android.bp b/recovery/Android.bp
new file mode 100644
index 0000000..0923d17
--- /dev/null
+++ b/recovery/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+    name: "librecovery_ui_cuttlefish",
+    owner: "google",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-pedantic",
+    ],
+    srcs: [
+        "recovery_ui.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "librecovery_ui",
+    ],
+}
diff --git a/recovery/recovery_ui.cpp b/recovery/recovery_ui.cpp
new file mode 100644
index 0000000..217542e
--- /dev/null
+++ b/recovery/recovery_ui.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#include <recovery_ui/ethernet_device.h>
+#include <recovery_ui/ethernet_ui.h>
+
+class CuttlefishRecoveryUI : public EthernetRecoveryUI {
+  public:
+    bool IsUsbConnected() override {
+      return true;
+    }
+};
+
+Device* make_device() {
+    return new EthernetDevice(new CuttlefishRecoveryUI);
+}
diff --git a/required_images b/required_images
new file mode 100644
index 0000000..6f5c180
--- /dev/null
+++ b/required_images
@@ -0,0 +1,7 @@
+boot.img
+bootloader
+super.img
+userdata.img
+vbmeta.img
+vbmeta_system.img
+vendor_boot.img
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 120000
index 0000000..475ba8f
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
+../../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/shared/Android.mk b/shared/Android.mk
deleted file mode 100644
index c605e76..0000000
--- a/shared/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Copyright 2017 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/shared/BoardConfig.mk b/shared/BoardConfig.mk
index 7c5f6ed..5f118b0 100644
--- a/shared/BoardConfig.mk
+++ b/shared/BoardConfig.mk
@@ -18,37 +18,54 @@
 # Common BoardConfig for all supported architectures.
 #
 
+# TODO(b/170639028): Back up TARGET_NO_BOOTLOADER
+__TARGET_NO_BOOTLOADER := $(TARGET_NO_BOOTLOADER)
 include build/make/target/board/BoardConfigMainlineCommon.mk
+TARGET_NO_BOOTLOADER := $(__TARGET_NO_BOOTLOADER)
 
 TARGET_BOOTLOADER_BOARD_NAME := cutf
 
+BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE := $(TARGET_RO_FILE_SYSTEM_TYPE)
+
 # Boot partition size: 32M
 # This is only used for OTA update packages. The image size on disk
 # will not change (as is it not a filesystem.)
 BOARD_BOOTIMAGE_PARTITION_SIZE := 67108864
+ifdef TARGET_DEDICATED_RECOVERY
 BOARD_RECOVERYIMAGE_PARTITION_SIZE := 67108864
+endif
 BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE := 67108864
 
 # Build a separate vendor.img partition
 BOARD_USES_VENDORIMAGE := true
-BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := $(TARGET_RO_FILE_SYSTEM_TYPE)
 
 BOARD_USES_METADATA_PARTITION := true
 
 # Build a separate product.img partition
 BOARD_USES_PRODUCTIMAGE := true
-BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := $(TARGET_RO_FILE_SYSTEM_TYPE)
 
 # Build a separate system_ext.img partition
 BOARD_USES_SYSTEM_EXTIMAGE := true
-BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := $(TARGET_RO_FILE_SYSTEM_TYPE)
 TARGET_COPY_OUT_SYSTEM_EXT := system_ext
 
 # Build a separate odm.img partition
 BOARD_USES_ODMIMAGE := true
-BOARD_ODMIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_ODMIMAGE_FILE_SYSTEM_TYPE := $(TARGET_RO_FILE_SYSTEM_TYPE)
 TARGET_COPY_OUT_ODM := odm
 
+# Build a separate vendor_dlkm partition
+BOARD_USES_VENDOR_DLKMIMAGE := true
+BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE := ext4
+TARGET_COPY_OUT_VENDOR_DLKM := vendor_dlkm
+
+# Build a separate odm_dlkm partition
+BOARD_USES_ODM_DLKMIMAGE := true
+BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE := ext4
+TARGET_COPY_OUT_ODM_DLKM := odm_dlkm
+
 # FIXME: Remove this once we generate the vbmeta digest correctly
 BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS += --flag 2
 
@@ -59,9 +76,36 @@
 BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
 BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
 
+# Enable chained vbmeta for boot images
+BOARD_AVB_BOOT_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
+BOARD_AVB_BOOT_ALGORITHM := SHA256_RSA2048
+BOARD_AVB_BOOT_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
+BOARD_AVB_BOOT_ROLLBACK_INDEX_LOCATION := 2
+
+# Using sha256 for dm-verity partitions. b/178983355
+# system, system_other, product.
+TARGET_AVB_SYSTEM_HASHTREE_ALGORITHM ?= sha256
+TARGET_AVB_SYSTEM_OTHER_HASHTREE_ALGORITHM ?= sha256
+TARGET_AVB_PRODUCT_HASHTREE_ALGORITHM ?= sha256
+# Using blake2b-256 for system_ext. This give us move coverage of the
+# algorithms as we otherwise don't have a device using blake2b-256.
+TARGET_AVB_SYSTEM_EXT_HASHTREE_ALGORITHM ?= blake2b-256
+
+BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm $(TARGET_AVB_SYSTEM_HASHTREE_ALGORITHM)
+BOARD_AVB_SYSTEM_OTHER_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm $(TARGET_AVB_SYSTEM_OTHER_HASHTREE_ALGORITHM)
+BOARD_AVB_SYSTEM_EXT_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm $(TARGET_AVB_SYSTEM_EXT_HASHTREE_ALGORITHM)
+BOARD_AVB_PRODUCT_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm $(TARGET_AVB_PRODUCT_HASHTREE_ALGORITHM)
+
+# vendor and odm.
+BOARD_AVB_VENDOR_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm sha256
+BOARD_AVB_ODM_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm sha256
+
+# vendor_dlkm and odm_dlkm.
+BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm sha256
+BOARD_AVB_ODM_DLKM_ADD_HASHTREE_FOOTER_ARGS += --hash_algorithm sha256
+
 BOARD_USES_GENERIC_AUDIO := false
 USE_CAMERA_STUB := true
-TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
 
 # Hardware composer configuration
 TARGET_USES_HWC2 := true
@@ -69,16 +113,16 @@
 # The compiler will occasionally generate movaps, etc.
 BOARD_MALLOC_ALIGNMENT := 16
 
-# Make the userdata partition 4.25G to accomodate ASAN and CTS
-BOARD_USERDATAIMAGE_PARTITION_SIZE := 4563402752
+# Disable sparse on all filesystem images
+TARGET_USERIMAGES_SPARSE_EROFS_DISABLED := true
+TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
 TARGET_USERIMAGES_SPARSE_F2FS_DISABLED := true
+
+# Make the userdata partition 6G to accommodate ASAN and CTS
+BOARD_USERDATAIMAGE_PARTITION_SIZE := $(TARGET_USERDATAIMAGE_PARTITION_SIZE)
 BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE := $(TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE)
 TARGET_USERIMAGES_USE_F2FS := true
 
-# Cache partition size: 64M
-BOARD_CACHEIMAGE_PARTITION_SIZE := 67108864
-BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
-
 BOARD_GPU_DRIVERS := virgl
 
 # Enable goldfish's encoder.
@@ -103,6 +147,7 @@
 BOARD_WLAN_DEVICE           := wlan0
 BOARD_HOSTAPD_DRIVER        := NL80211
 BOARD_WPA_SUPPLICANT_DRIVER := NL80211
+BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated_cf
 WPA_SUPPLICANT_VERSION      := VER_0_8_X
 WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
 WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
@@ -111,34 +156,22 @@
 # vendor sepolicy
 BOARD_VENDOR_SEPOLICY_DIRS += device/google/cuttlefish/shared/sepolicy/vendor
 BOARD_VENDOR_SEPOLICY_DIRS += device/google/cuttlefish/shared/sepolicy/vendor/google
+
+BOARD_SEPOLICY_DIRS += system/bt/vendor_libs/linux/sepolicy
+
+# Avoid multiple includes of sepolicy already included by Pixel experience.
+ifneq ($(filter aosp_% %_auto %_go_phone trout_% %_tv,$(PRODUCT_NAME)),)
+
+SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS += hardware/google/pixel-sepolicy/flipendo
+
+endif
+
 # product sepolicy, allow other layers to append
 PRODUCT_PRIVATE_SEPOLICY_DIRS += device/google/cuttlefish/shared/sepolicy/product/private
 # PRODUCT_PUBLIC_SEPOLICY_DIRS += device/google/cuttlefish/shared/sepolicy/product/public
 # system_ext sepolicy
-BOARD_PLAT_PRIVATE_SEPOLICY_DIR += device/google/cuttlefish/shared/sepolicy/system_ext/private
-# BOARD_PLAT_PUBLIC_SEPOLICY_DIR += device/google/cuttlefish/shared/sepolicy/system_ext/public
-
-VSOC_STLPORT_INCLUDES :=
-VSOC_STLPORT_LIBS :=
-VSOC_STLPORT_STATIC_LIBS :=
-VSOC_TEST_INCLUDES := external/googletest/googlemock/include external/googletest/googletest/include
-VSOC_TEST_LIBRARIES := libgmock_main_host libgtest_host libgmock_host
-VSOC_LIBCXX_STATIC := libc++_static
-VSOC_PROTOBUF_SHARED_LIB := libprotobuf-cpp-full
-
-CUTTLEFISH_LIBRIL_NAME := libril-cuttlefish-fork
-ENABLE_CUTTLEFISH_RILD := true
-
-# TODO(ender): Remove all these once we stop depending on GCE code.
-GCE_VERSION_CFLAGS := -DGCE_PLATFORM_SDK_VERSION=${PLATFORM_SDK_VERSION}
-GCE_STLPORT_INCLUDES := $(VSOC_STLPORT_INCLUDES)
-GCE_STLPORT_LIBS := $(VSOC_STLPORT_LIBS)
-GCE_STLPORT_STATIC_LIBS := $(VSOC_STLPORT_STATIC_LIBS)
-GCE_TEST_INCLUDES := $(VSOC_TEST_INCLUDES)
-GCE_TEST_LIBRARIES := $(VSOC_TEST_LIBRARIES)
-GCE_LIBCXX_STATIC := $(VSOC_LIBCXX_STATIC)
-GCE_PROTOBUF_SHARED_LIB := $(VSOC_PROTOBUF_SHARED_LIB)
-# TODO(ender): up till here.
+SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS += device/google/cuttlefish/shared/sepolicy/system_ext/private
+# SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS += device/google/cuttlefish/shared/sepolicy/system_ext/public
 
 STAGEFRIGHT_AVCENC_CFLAGS := -DANDROID_GCE
 
@@ -151,17 +184,24 @@
 
 
 TARGET_RECOVERY_PIXEL_FORMAT := ABGR_8888
-
+TARGET_RECOVERY_UI_LIB := librecovery_ui_cuttlefish
 TARGET_RECOVERY_FSTAB ?= device/google/cuttlefish/shared/config/fstab.f2fs
 
-BOARD_SUPER_PARTITION_SIZE := 6442450944
-BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions
-BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := odm product system system_ext vendor
-BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 6442450944
+BOARD_SUPER_PARTITION_SIZE := 7516192768  # 7GiB
+BOARD_SUPER_PARTITION_GROUPS := google_system_dynamic_partitions google_vendor_dynamic_partitions
+BOARD_GOOGLE_SYSTEM_DYNAMIC_PARTITIONS_PARTITION_LIST := product system system_ext
+BOARD_GOOGLE_SYSTEM_DYNAMIC_PARTITIONS_SIZE := 5771362304  # 5.375GiB
+BOARD_GOOGLE_VENDOR_DYNAMIC_PARTITIONS_PARTITION_LIST := odm vendor vendor_dlkm odm_dlkm
+# 1404MiB, reserve 4MiB for dynamic partition metadata
+BOARD_GOOGLE_VENDOR_DYNAMIC_PARTITIONS_SIZE := 1472200704
 BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true
 BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE := true
 TARGET_RELEASETOOLS_EXTENSIONS := device/google/cuttlefish/shared
 
+# Generate a partial ota update package for partitions in vbmeta_system
+BOARD_PARTIAL_OTA_UPDATE_PARTITIONS_LIST := product system system_ext vbmeta_system
+
+BOARD_BOOTLOADER_IN_UPDATE_PACKAGE := true
 BOARD_RAMDISK_USE_LZ4 := true
 
 # To see full logs from init, disable ratelimiting.
@@ -170,21 +210,61 @@
 BOARD_KERNEL_CMDLINE += firmware_class.path=/vendor/etc/
 
 BOARD_KERNEL_CMDLINE += init=/init
-BOARD_KERNEL_CMDLINE += androidboot.hardware=cutf_cvm
-BOARD_KERNEL_CMDLINE += security=selinux
-BOARD_KERNEL_CMDLINE += androidboot.console=ttyS1
+BOARD_BOOTCONFIG += androidboot.hardware=cutf_cvm
+
+# TODO(b/179489292): Remove once kfence is enabled everywhere
+BOARD_KERNEL_CMDLINE += kfence.sample_interval=500
+
+BOARD_KERNEL_CMDLINE += loop.max_part=7
+
+# TODO(b/182417593): Move all of these module options to modules.options
+# TODO(b/176860479): Remove once goldfish and cuttlefish share a wifi implementation
+BOARD_BOOTCONFIG += kernel.mac80211_hwsim.radios=0
+# TODO(b/175151042): Remove once we are using virtio-snd on cuttlefish
+BOARD_BOOTCONFIG += kernel.snd-hda-intel.enable=0
+# Reduce slab size usage from virtio vsock to reduce slab fragmentation
+BOARD_BOOTCONFIG += \
+    kernel.vmw_vsock_virtio_transport_common.virtio_transport_max_vsock_pkt_buf_size=16384
 
 ifeq ($(TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE),f2fs)
-BOARD_KERNEL_CMDLINE += androidboot.fstab_suffix=f2fs
+BOARD_BOOTCONFIG += androidboot.fstab_suffix=f2fs
 endif
 
 ifeq ($(TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE),ext4)
-BOARD_KERNEL_CMDLINE += androidboot.fstab_suffix=ext4
+BOARD_BOOTCONFIG += androidboot.fstab_suffix=ext4
 endif
 
 BOARD_INCLUDE_DTB_IN_BOOTIMG := true
-BOARD_BOOT_HEADER_VERSION := 3
-BOARD_USES_RECOVERY_AS_BOOT := true
+BOARD_BOOT_HEADER_VERSION := 4
 BOARD_MKBOOTIMG_ARGS += --header_version $(BOARD_BOOT_HEADER_VERSION)
-PRODUCT_COPY_FILES += device/google/cuttlefish/dtb.img:dtb.img
+PRODUCT_COPY_FILES += \
+    device/google/cuttlefish/dtb.img:dtb.img \
+    device/google/cuttlefish/required_images:required_images \
+
 BOARD_BUILD_SYSTEM_ROOT_IMAGE := false
+
+# Cuttlefish doesn't support ramdump feature yet, exclude the ramdump debug tool.
+EXCLUDE_BUILD_RAMDUMP_UPLOADER_DEBUG_TOOL := true
+
+# GKI-related variables.
+BOARD_USES_GENERIC_KERNEL_IMAGE := true
+ifdef TARGET_DEDICATED_RECOVERY
+  BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE := true
+else
+  BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT := true
+endif
+BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT := true
+
+# TARGET_KERNEL_USE is defined in kernel.mk, if not defined in the environment variable.
+# Keep in sync with GKI APEX in device.mk
+ifneq (,$(TARGET_KERNEL_USE))
+  ifneq (,$(filter 5.4, $(TARGET_KERNEL_USE)))
+    BOARD_KERNEL_MODULE_INTERFACE_VERSIONS := 5.4-android12-0
+  else
+    BOARD_KERNEL_MODULE_INTERFACE_VERSIONS := $(TARGET_KERNEL_USE)-android12-unstable
+  endif
+endif
+
+BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko
+
+BOARD_HAVE_BLUETOOTH := true
diff --git a/shared/auto/android-info.txt b/shared/auto/android-info.txt
new file mode 100644
index 0000000..cc15c01
--- /dev/null
+++ b/shared/auto/android-info.txt
@@ -0,0 +1 @@
+config=auto
diff --git a/shared/auto/device.mk b/shared/auto/device.mk
index 1c036cc..fb1ccdf 100644
--- a/shared/auto/device.mk
+++ b/shared/auto/device.mk
@@ -17,7 +17,6 @@
 ################################################
 # Begin GCE specific configurations
 
-DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/config/manifest.xml
 DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/auto/manifest.xml
 
 $(call inherit-product, device/google/cuttlefish/shared/device.mk)
@@ -32,20 +31,25 @@
     packages/services/Car/car_product/init/init.bootstat.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw//init.bootstat.rc \
     packages/services/Car/car_product/init/init.car.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw//init.car.rc
 
+ifneq ($(LOCAL_SENSOR_FILE_OVERRIDES),true)
+    PRODUCT_COPY_FILES += \
+        frameworks/native/data/etc/android.hardware.sensor.accelerometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.accelerometer.xml \
+        frameworks/native/data/etc/android.hardware.sensor.compass.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.compass.xml
+endif
+
 PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.hardware.bluetooth.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth.xml \
     frameworks/native/data/etc/android.hardware.broadcastradio.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.broadcastradio.xml \
+    frameworks/native/data/etc/android.hardware.faketouch.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.faketouch.xml \
     frameworks/native/data/etc/android.hardware.screen.landscape.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.screen.landscape.xml \
-    frameworks/native/data/etc/android.hardware.sensor.accelerometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.accelerometer.xml \
-    frameworks/native/data/etc/android.hardware.sensor.compass.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.compass.xml \
     frameworks/native/data/etc/android.software.activities_on_secondary_displays.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.activities_on_secondary_displays.xml \
     frameworks/native/data/etc/car_core_hardware.xml:system/etc/permissions/car_core_hardware.xml \
 
-PRODUCT_PROPERTY_OVERRIDES += \
+PRODUCT_VENDOR_PROPERTIES += \
     keyguard.no_require_sim=true \
     ro.cdma.home.operator.alpha=Android \
     ro.cdma.home.operator.numeric=302780 \
     ro.com.android.dataroaming=true \
-    vendor.rild.libpath=libcuttlefish-ril.so \
 
 # vehicle HAL
 ifeq ($(LOCAL_VHAL_PRODUCT_PACKAGE),)
@@ -59,7 +63,7 @@
 
 # AudioControl HAL
 ifeq ($(LOCAL_AUDIOCONTROL_HAL_PRODUCT_PACKAGE),)
-    LOCAL_AUDIOCONTROL_HAL_PRODUCT_PACKAGE := android.hardware.automotive.audiocontrol@2.0-service
+    LOCAL_AUDIOCONTROL_HAL_PRODUCT_PACKAGE := android.hardware.automotive.audiocontrol-service.example
 endif
 PRODUCT_PACKAGES += $(LOCAL_AUDIOCONTROL_HAL_PRODUCT_PACKAGE)
 
@@ -70,7 +74,7 @@
     canhalsend
 
 PRODUCT_PACKAGES += \
-    libcuttlefish-ril \
+    libcuttlefish-ril-2 \
     libcuttlefish-rild
 
 # system_other support
@@ -86,6 +90,10 @@
 # Placed here due to b/110784510
 PRODUCT_BRAND := generic
 
+DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/auto/overlay
+
+TARGET_BOARD_INFO_FILE ?= device/google/cuttlefish/shared/auto/android-info.txt
+
 PRODUCT_ENFORCE_RRO_TARGETS := framework-res
 
 TARGET_NO_TELEPHONY := true
diff --git a/shared/auto/manifest.xml b/shared/auto/manifest.xml
index d115dbd..7bf5d3c 100644
--- a/shared/auto/manifest.xml
+++ b/shared/auto/manifest.xml
@@ -9,7 +9,7 @@
 */
 -->
 <!-- Android Auto Embedded specific HALs-->
-<manifest version="1.0" type="device" target-level="5">
+<manifest version="1.0" type="device">
     <!-- FIXME: Implement automotive.evs HAL
     <hal format="hidl">
         <name>android.hardware.automotive.evs</name>
diff --git a/shared/auto/overlay/frameworks/base/core/res/res/values/config.xml b/shared/auto/overlay/frameworks/base/core/res/res/values/config.xml
new file mode 100644
index 0000000..60c7ae9
--- /dev/null
+++ b/shared/auto/overlay/frameworks/base/core/res/res/values/config.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <!-- Enable multi-user. -->
+  <bool name="config_enableMultiUserUI" translatable="false">true</bool>
+  <!-- If true, all guest users created on the device will be ephemeral. -->
+  <bool name="config_guestUserEphemeral" translatable="false">true</bool>
+  <!--  Maximum number of users allowed on the device. -->
+  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
+  <!-- Restricting eth2 -->
+  <string-array translatable="false" name="config_ethernet_interfaces">
+    <item>eth2;11,12,14;;</item>
+  </string-array>
+</resources>
diff --git a/shared/config/Android.bp b/shared/config/Android.bp
new file mode 100644
index 0000000..03bbc08
--- /dev/null
+++ b/shared/config/Android.bp
@@ -0,0 +1,33 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+prebuilt_etc_host {
+    name: "cvd_config_auto.json",
+    src: "config_auto.json",
+    sub_dir: "cvd_config",
+}
+
+prebuilt_etc_host {
+    name: "cvd_config_foldable.json",
+    src: "config_foldable.json",
+    sub_dir: "cvd_config",
+}
+
+prebuilt_etc_host {
+    name: "cvd_config_phone.json",
+    src: "config_phone.json",
+    sub_dir: "cvd_config",
+}
+
+prebuilt_etc_host {
+    name: "cvd_config_tablet.json",
+    src: "config_tablet.json",
+    sub_dir: "cvd_config",
+}
+
+prebuilt_etc_host {
+    name: "cvd_config_tv.json",
+    src: "config_tv.json",
+    sub_dir: "cvd_config",
+}
diff --git a/shared/config/Android.mk b/shared/config/Android.mk
deleted file mode 100644
index 1397bcc..0000000
--- a/shared/config/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Copyright 2017 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# This section generates wpa_supplicant.conf using the target product name and
-# model as that file requires such build target specific fields.
-
-LOCAL_MODULE := wpa_supplicant.vsoc.conf
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/wifi
-LOCAL_MODULE_STEM := wpa_supplicant.conf
-LOCAL_MULTILIB := first
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/gen_wpa_supplicant_conf.sh
-	$(hide) echo "Generating $@"
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $< "${TARGET_PRODUCT}" "${PRODUCT_MODEL}" \
-	    "${PLATFORM_SDK_VERSION}" > $@
diff --git a/shared/config/CleanSpec.mk b/shared/config/CleanSpec.mk
index a74a710..9556fc5 100644
--- a/shared/config/CleanSpec.mk
+++ b/shared/config/CleanSpec.mk
@@ -50,3 +50,4 @@
 $(call add-clean-step, find $(PRODUCT_OUT)/vendor/bin/hw/ -type f -name "android.hardware.drm@*" -print0 | xargs -0 rm -f)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.graphics.allocator@4.0-service.minigbm.rc)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.graphics.allocator@4.0-service.minigbm)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.gnss@2.1-service)
diff --git a/shared/config/android.hardware.media.omx@1.0.xml b/shared/config/android.hardware.media.omx@1.0.xml
new file mode 100644
index 0000000..a04bcd0
--- /dev/null
+++ b/shared/config/android.hardware.media.omx@1.0.xml
@@ -0,0 +1,8 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.media.omx</name>
+        <transport>hwbinder</transport>
+        <fqname>@1.0::IOmx/default</fqname>
+        <fqname>@1.0::IOmxStore/default</fqname>
+    </hal>
+</manifest>
diff --git a/shared/config/camera_v1.json b/shared/config/camera_v1.json
deleted file mode 100644
index 8a2ae5b..0000000
--- a/shared/config/camera_v1.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
-  "__readme": [
-    "Basic Camera HAL v1 configuration."
-  ],
-
-  "camera_definitions": [
-    {
-      "orientation": "back",
-      "hal_version": "1",
-      "resolutions": [
-        {
-          "width": "1600",
-          "height": "1200"
-        },
-        {
-          "width": "1280",
-          "height": "720"
-        },
-        {
-          "width": "640",
-          "height": "480"
-        },
-        {
-          "width": "320",
-          "height": "240"
-        }
-      ]
-    },
-    {
-      "orientation": "front",
-      "hal_version": "1",
-      "resolutions": [
-        {
-          "width": "1024",
-          "height": "768"
-        },
-        {
-          "width": "800",
-          "height": "600"
-        },
-        {
-          "width": "640",
-          "height": "480"
-        },
-        {
-          "width": "320",
-          "height": "240"
-        }
-      ]
-    }
-  ]
-}
diff --git a/shared/config/camera_v3.json b/shared/config/camera_v3.json
deleted file mode 100644
index 3479004..0000000
--- a/shared/config/camera_v3.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
-  "__readme": [
-    "Basic Camera HAL v3 configuration."
-  ],
-
-  "camera_definitions": [
-    {
-      "orientation": "back",
-      "hal_version": "3",
-      "resolutions": [
-        {
-          "width": "1600",
-          "height": "1200"
-        },
-        {
-          "width": "1280",
-          "height": "720"
-        },
-        {
-          "width": "640",
-          "height": "480"
-        },
-        {
-          "width": "320",
-          "height": "240"
-        }
-      ]
-    },
-    {
-      "orientation": "front",
-      "hal_version": "3",
-      "resolutions": [
-        {
-          "width": "1024",
-          "height": "768"
-        },
-        {
-          "width": "800",
-          "height": "600"
-        },
-        {
-          "width": "640",
-          "height": "480"
-        },
-        {
-          "width": "320",
-          "height": "240"
-        }
-      ]
-    }
-  ]
-}
diff --git a/shared/config/config_auto.json b/shared/config/config_auto.json
new file mode 100644
index 0000000..b8f2bfe
--- /dev/null
+++ b/shared/config/config_auto.json
@@ -0,0 +1,6 @@
+{
+	"x_res" : 1280,
+	"y_res" : 800,
+	"dpi" : 160,
+	"memory_mb" : 4096
+}
diff --git a/shared/config/config_foldable.json b/shared/config/config_foldable.json
new file mode 100644
index 0000000..dd64d17
--- /dev/null
+++ b/shared/config/config_foldable.json
@@ -0,0 +1,34 @@
+{
+	"x_res" : 1768,
+	"y_res" : 2208,
+	"dpi" : 386,
+	"memory_mb" : 4096,
+	"custom_actions" : [
+                {
+                        "device_states": [
+                                {
+                                        "lid_switch_open": false,
+                                        "hinge_angle_value": 0
+                                }
+                        ],
+                        "button":{
+                                "command":"device_state_closed",
+                                "title":"Device State Closed",
+                                "icon_name":"smartphone"
+                        }
+                },
+                {
+                        "device_states": [
+                                {
+                                        "lid_switch_open": true,
+                                        "hinge_angle_value": 180
+                                }
+                        ],
+                        "button":{
+                                "command":"device_state_opened",
+                                "title":"Device State Opened",
+                                "icon_name":"tablet"
+                        }
+                }
+	]
+}
diff --git a/shared/config/config_phone.json b/shared/config/config_phone.json
new file mode 100644
index 0000000..69ad977
--- /dev/null
+++ b/shared/config/config_phone.json
@@ -0,0 +1,6 @@
+{
+	"x_res" : 720,
+	"y_res" : 1280,
+	"dpi" : 320,
+	"memory_mb" : 2048
+}
diff --git a/shared/config/config_tablet.json b/shared/config/config_tablet.json
new file mode 100644
index 0000000..832d637
--- /dev/null
+++ b/shared/config/config_tablet.json
@@ -0,0 +1,6 @@
+{
+	"x_res" : 2560,
+	"y_res" : 1800,
+	"dpi" : 320,
+	"memory_mb" : 4096
+}
diff --git a/shared/config/config_tv.json b/shared/config/config_tv.json
new file mode 100644
index 0000000..9698d01
--- /dev/null
+++ b/shared/config/config_tv.json
@@ -0,0 +1,6 @@
+{
+	"x_res" : 1920,
+	"y_res" : 1080,
+	"dpi" : 213,
+	"memory_mb" : 2048
+}
diff --git a/shared/config/fstab-erofs.ext4 b/shared/config/fstab-erofs.ext4
new file mode 100644
index 0000000..ec7b3fe
--- /dev/null
+++ b/shared/config/fstab-erofs.ext4
@@ -0,0 +1,18 @@
+/dev/block/by-name/boot /boot emmc defaults recoveryonly,slotselect
+/dev/block/by-name/vendor_boot /vendor_boot emmc defaults recoveryonly,slotselect
+system /system erofs ro wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
+# Add all non-dynamic partitions except system, after this comment
+/dev/block/by-name/userdata /data ext4 nodev,noatime,nosuid,errors=panic latemount,wait,check,quota,formattable,fileencryption=aes-256-xts:aes-256-cts,keydirectory=/metadata/vold/metadata_encryption,checkpoint=block
+/dev/block/by-name/metadata /metadata ext4 nodev,noatime,nosuid,errors=panic wait,formattable,first_stage_mount,check
+/dev/block/by-name/misc /misc emmc defaults defaults
+# Add all dynamic partitions except system, after this comment
+odm /odm erofs ro wait,logical,first_stage_mount,slotselect,avb
+product /product erofs ro wait,logical,first_stage_mount,slotselect,avb
+system_ext /system_ext erofs ro wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
+vendor /vendor erofs ro wait,logical,first_stage_mount,slotselect,avb=vbmeta
+vendor_dlkm /vendor_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
+odm_dlkm /odm_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
+/dev/block/zram0 none swap defaults zramsize=75%
+/dev/block/vdc1 /sdcard vfat defaults recoveryonly
+/devices/*/block/vdc auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
+shared /mnt/vendor/shared virtiofs nosuid,nodev,noatime nofail
diff --git a/shared/config/fstab-erofs.f2fs b/shared/config/fstab-erofs.f2fs
new file mode 100644
index 0000000..1b5486e
--- /dev/null
+++ b/shared/config/fstab-erofs.f2fs
@@ -0,0 +1,18 @@
+/dev/block/by-name/boot /boot emmc defaults recoveryonly,slotselect
+/dev/block/by-name/vendor_boot /vendor_boot emmc defaults recoveryonly,slotselect
+system /system erofs ro wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
+# Add all non-dynamic partitions except system, after this comment
+/dev/block/by-name/userdata /data f2fs nodev,noatime,nosuid,inlinecrypt,reserve_root=32768 latemount,wait,check,quota,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,fscompress,keydirectory=/metadata/vold/metadata_encryption,checkpoint=fs
+/dev/block/by-name/metadata /metadata ext4 nodev,noatime,nosuid,errors=panic wait,formattable,first_stage_mount,check
+/dev/block/by-name/misc /misc emmc defaults defaults
+# Add all dynamic partitions except system, after this comment
+odm /odm erofs ro wait,logical,first_stage_mount,slotselect,avb
+product /product erofs ro wait,logical,first_stage_mount,slotselect,avb
+system_ext /system_ext erofs ro wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
+vendor /vendor erofs ro wait,logical,first_stage_mount,slotselect,avb=vbmeta
+vendor_dlkm /vendor_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
+odm_dlkm /odm_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
+/dev/block/zram0 none swap defaults zramsize=75%
+/dev/block/vdc1 /sdcard vfat defaults recoveryonly
+/devices/*/block/vdc auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
+shared /mnt/vendor/shared virtiofs nosuid,nodev,noatime nofail
diff --git a/shared/config/fstab.ext4 b/shared/config/fstab.ext4
index 9b6eab5..1677941 100644
--- a/shared/config/fstab.ext4
+++ b/shared/config/fstab.ext4
@@ -2,8 +2,7 @@
 /dev/block/by-name/vendor_boot /vendor_boot emmc defaults recoveryonly,slotselect
 system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
 # Add all non-dynamic partitions except system, after this comment
-/dev/block/by-name/userdata /data ext4 nodev,noatime,nosuid,errors=panic wait,fileencryption=aes-256-xts:aes-256-cts,fsverity
-/dev/block/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait
+/dev/block/by-name/userdata /data ext4 nodev,noatime,nosuid,errors=panic latemount,wait,check,quota,formattable,fileencryption=aes-256-xts:aes-256-cts,keydirectory=/metadata/vold/metadata_encryption,checkpoint=block
 /dev/block/by-name/metadata /metadata ext4 nodev,noatime,nosuid,errors=panic wait,formattable,first_stage_mount,check
 /dev/block/by-name/misc /misc emmc defaults defaults
 # Add all dynamic partitions except system, after this comment
@@ -11,6 +10,9 @@
 product /product ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
 system_ext /system_ext ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
 vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb=vbmeta
+vendor_dlkm /vendor_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
+odm_dlkm /odm_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
 /dev/block/zram0 none swap defaults zramsize=75%
-/tmp /sdcard none defaults,bind recoveryonly
-/devices/*/block/vdb auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
+/dev/block/vdc1 /sdcard vfat defaults recoveryonly
+/devices/*/block/vdc auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
+shared /mnt/vendor/shared virtiofs nosuid,nodev,noatime nofail
diff --git a/shared/config/fstab.f2fs b/shared/config/fstab.f2fs
index 2e9f31f..597e3f0 100644
--- a/shared/config/fstab.f2fs
+++ b/shared/config/fstab.f2fs
@@ -2,8 +2,7 @@
 /dev/block/by-name/vendor_boot /vendor_boot emmc defaults recoveryonly,slotselect
 system /system ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
 # Add all non-dynamic partitions except system, after this comment
-/dev/block/by-name/userdata /data f2fs nodev,noatime,nosuid,inlinecrypt,reserve_root=32768 latemount,wait,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,fsverity,keydirectory=/metadata/vold/metadata_encryption
-/dev/block/by-name/cache /cache ext4 nodev,noatime,nosuid,errors=panic wait
+/dev/block/by-name/userdata /data f2fs nodev,noatime,nosuid,inlinecrypt,reserve_root=32768 latemount,wait,check,quota,formattable,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,fscompress,keydirectory=/metadata/vold/metadata_encryption,checkpoint=fs
 /dev/block/by-name/metadata /metadata ext4 nodev,noatime,nosuid,errors=panic wait,formattable,first_stage_mount,check
 /dev/block/by-name/misc /misc emmc defaults defaults
 # Add all dynamic partitions except system, after this comment
@@ -11,6 +10,9 @@
 product /product ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
 system_ext /system_ext ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb=vbmeta_system
 vendor /vendor ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb=vbmeta
+vendor_dlkm /vendor_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
+odm_dlkm /odm_dlkm ext4 noatime,ro,errors=panic wait,logical,first_stage_mount,slotselect,avb
 /dev/block/zram0 none swap defaults zramsize=75%
-/tmp /sdcard none defaults,bind recoveryonly
-/devices/*/block/vdb auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
+/dev/block/vdc1 /sdcard vfat defaults recoveryonly
+/devices/*/block/vdc auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
+shared /mnt/vendor/shared virtiofs nosuid,nodev,noatime nofail
diff --git a/shared/config/gen_wpa_supplicant_conf.sh b/shared/config/gen_wpa_supplicant_conf.sh
deleted file mode 100755
index 72ecb21..0000000
--- a/shared/config/gen_wpa_supplicant_conf.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Generates wpa_supplicant.conf file for wifi
-# Usage: generate_wpa_supplicant_conf.sh <device name> <model name> <SDK API level>
-
-if [ -n "$3" -a "$3" -lt "21" ]
-then
-  # before mnc.
-  cat <<eof
-ctrl_interface=wlan0
-eof
-fi
-
-cat <<eof
-update_config=1
-device_name=$1
-model_name=$2
-serial_number=
-device_type=10-0050F204-5
-eof
diff --git a/shared/config/init.product.rc b/shared/config/init.product.rc
index fe7130c..22371a3 100644
--- a/shared/config/init.product.rc
+++ b/shared/config/init.product.rc
@@ -1,19 +1,8 @@
 on early-init
     setprop ro.setupwizard.mode ${ro.boot.setupwizard_mode}
 
-on property:ro.boot.tombstone_transmit=1
-    enable tombstone_transmit
-
-
 service tombstone_transmit /product/bin/tombstone_transmit
     # Start tombstone_transmit after /data is mounted.
     class late_start
     group system
     user root
-    disabled
-
-# TODO: disable this service once cuttlefish implements system suspend
-service suspend_blocker /product/bin/suspend_blocker
-    class main
-    group system
-    user root
diff --git a/shared/config/init.recovery.rc b/shared/config/init.recovery.rc
index 6f9ca141..3fdd4b0 100644
--- a/shared/config/init.recovery.rc
+++ b/shared/config/init.recovery.rc
@@ -3,8 +3,8 @@
     console
     disabled
     user root
-    group shell log readproc
-    seclabel u:r:shell:s0
+    group root shell log readproc
+    seclabel u:r:su:s0
     setenv HOSTNAME console
 
 on property:ro.debuggable=1
diff --git a/shared/config/init.vendor.rc b/shared/config/init.vendor.rc
index 94da768..77b79dc 100644
--- a/shared/config/init.vendor.rc
+++ b/shared/config/init.vendor.rc
@@ -1,20 +1,16 @@
 on early-init
 #    loglevel 8
-    mkdir /var/run 0755 root root
-    mkdir /var/run/media 0755 media root
-    mkdir /var/run/system 0755 system root
-    mkdir /dev/gce 0750
-    chown system system /dev/gce
 
-    # For KCOV
-    mount debugfs debugfs /sys/kernel/debug
-    chmod 0755 /sys/kernel/debug
+    mount securityfs securityfs /sys/kernel/security
 
     setprop ro.sf.lcd_density ${ro.boot.lcd_density}
     setprop ro.hardware.egl ${ro.boot.hardware.egl}
+    setprop debug.sf.vsync_reactor_ignore_present_fences true
     setprop ro.hardware.gralloc ${ro.boot.hardware.gralloc}
     setprop ro.hardware.hwcomposer ${ro.boot.hardware.hwcomposer}
     setprop ro.hardware.vulkan ${ro.boot.hardware.vulkan}
+    setprop ro.cpuvulkan.version ${ro.boot.cpuvulkan.version}
+    setprop ro.hw_timeout_multiplier ${ro.boot.hw_timeout_multiplier}
 
     # start module load in the background
     start vendor.insmod_sh
@@ -22,9 +18,8 @@
 on init
     # ZRAM setup
     write /sys/block/zram0/comp_algorithm lz4
-    #
+
     # EAS uclamp interfaces
-    #
     mkdir /dev/cpuctl/foreground
     mkdir /dev/cpuctl/background
     mkdir /dev/cpuctl/top-app
@@ -45,8 +40,9 @@
     chmod 0664 /dev/cpuctl/top-app/tasks
     chmod 0664 /dev/cpuctl/rt/tasks
 
-
 on fs
+    mkdir /mnt/vendor/shared 0770 system system
+
     # Mount everything that does not require fsck
     mount_all --early
     restorecon_recursive /vendor
@@ -55,32 +51,19 @@
     # works around framework netiface enumeration issue
     start rename_eth1
 
-    # TODO(ender): Find better way to talk to serial port.
+    start bt_vhci_forwarder
+
+    # So GceBootReporter can print to kmsg
     chmod 622 /dev/kmsg
 
-    # for GCE camera HAL
-    mkdir /var/media 0770 audio media
-
-    chmod 0664 /sys/kernel/debug/ieee80211/phy1/hwsim/group
-    chmod 0664 /sys/kernel/debug/ieee80211/phy1/hwsim/ps
-    chmod 0664 /sys/kernel/debug/ieee80211/phy0/rc/fixed_rate_idx
-    chmod 0664 /sys/kernel/debug/ieee80211/phy0/hwsim/group
-    chmod 0664 /sys/kernel/debug/ieee80211/phy0/hwsim/ps
-    chmod 0664 /sys/kernel/debug/ieee80211/phy1/rc/fixed_rate_idx
-
-
 on post-fs
     # set RLIMIT_MEMLOCK to 64MB
     setrlimit 8 67108864 67108864
 
-
 on post-fs-data
-    start vport_trigger
-
     mkdir /data/vendor/modem_dump 0777 system system
     mkdir /data/vendor/radio 0777 system system
 
-
 on late-fs
     # Wait for keymaster
     exec_start wait_for_keymaster
@@ -90,7 +73,6 @@
 
     write /dev/kmsg "GUEST_BUILD_FINGERPRINT: ${ro.build.fingerprint}"
 
-
 on boot
     chmod 0660 /dev/cpuctl
     mkdir /data/vendor/wifi 0770 wifi wifi
@@ -98,19 +80,19 @@
     mkdir /data/vendor/wifi/wpa/sockets 0770 wifi wifi
     start socket_vsock_proxy
 
+service bt_vhci_forwarder /vendor/bin/bt_vhci_forwarder -virtio_console_dev=/dev/hvc5
+    user bluetooth
+    group bluetooth
 
 service setup_wifi /vendor/bin/setup_wifi
     oneshot
 
-
 service rename_eth1 /vendor/bin/rename_netiface eth1 rmnet0
     oneshot
 
-
 on property:sys.boot_completed=1
     trigger sys-boot-completed-set
 
-
 # We want one opportunity per boot to enable zram, so we
 # use a trigger we fire from the above stanza. If
 # persist.sys.zram_enabled becomes true after boot,
@@ -127,30 +109,10 @@
 
 service socket_vsock_proxy /vendor/bin/socket_vsock_proxy -server=vsock -tcp_port=5555 -vsock_port=6520
 
-
-service vport_trigger /vendor/bin/vport_trigger
-    oneshot
-
-
-on property:vendor.ser.cf-logcat=*
-    symlink ${vendor.ser.cf-logcat} /dev/cf-logcat
-    enable seriallogging
-
-
-service seriallogging /system/bin/logcat -b all -v threadtime -f /dev/cf-logcat *:V
+service seriallogging /system/bin/logcat -b all -v threadtime -f /dev/hvc2 *:V
     class main
-    user root
-    disabled
-
-
-on property:ro.boot.vsock_logcat_port=*
-   enable vsock_logcat
-
-
-service vsock_logcat /vendor/bin/vsock_logcat
-    class main
-    user root
-    disabled
+    user logd
+    group root logd
 
 service vsoc_input_service /vendor/bin/vsoc_input_service -touch_port=${ro.boot.vsock_touch_port} -keyboard_port=${ro.boot.vsock_keyboard_port}
     group root uhid
@@ -169,14 +131,20 @@
     interface android.hardware.wifi.supplicant@1.1::ISupplicant default
     interface android.hardware.wifi.supplicant@1.2::ISupplicant default
     interface android.hardware.wifi.supplicant@1.3::ISupplicant default
+    interface android.hardware.wifi.supplicant@1.4::ISupplicant default
     socket wpa_wlan0 dgram 660 wifi wifi
     group system wifi inet
     disabled
     oneshot
 
-
 service bugreport /system/bin/dumpstate -d -p -z
     class main
     disabled
     oneshot
     keycodes 30 48
+
+# TODO: disable this service once cuttlefish implements system suspend
+service suspend_blocker /vendor/bin/suspend_blocker
+    class early_hal # Start together with system_suspend HAL
+    group system
+    user root
diff --git a/shared/config/input/Crosvm_Virtio_Multitouch_Touchscreen.idc b/shared/config/input/Crosvm_Virtio_Multitouch_Touchscreen.idc
new file mode 100644
index 0000000..662f467
--- /dev/null
+++ b/shared/config/input/Crosvm_Virtio_Multitouch_Touchscreen.idc
@@ -0,0 +1,6 @@
+device.internal = 1
+
+touch.deviceType = touchScreen
+touch.orientationAware = 1
+
+# touch.displayId = local:0
diff --git a/shared/config/manifest.xml b/shared/config/manifest.xml
index 484952b..baca8df 100644
--- a/shared/config/manifest.xml
+++ b/shared/config/manifest.xml
@@ -16,8 +16,7 @@
 ** limitations under the License.
 */
 -->
-<manifest version="1.0" type="device" target-level="5">
-    <kernel  target-level="5" />
+<manifest version="1.0" type="device" target-level="6">
     <hal format="hidl">
         <name>android.hardware.audio</name>
         <transport>hwbinder</transport>
@@ -68,18 +67,9 @@
     </hal>
     -->
     <hal format="hidl">
-        <name>android.hardware.bluetooth</name>
-        <transport>hwbinder</transport>
-        <version>1.1</version>
-        <interface>
-            <name>IBluetoothHci</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl">
         <name>android.hardware.bluetooth.audio</name>
         <transport>hwbinder</transport>
-        <version>2.0</version>
+        <version>2.1</version>
         <interface>
             <name>IBluetoothAudioProvidersFactory</name>
             <instance>default</instance>
@@ -108,33 +98,14 @@
     </hal>
     -->
     <hal format="hidl">
-        <name>android.hardware.graphics.allocator</name>
-        <transport>hwbinder</transport>
-        <version>4.0</version>
-        <interface>
-            <name>IAllocator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <!-- TODO (b/130079341): -->
-    <hal format="hidl">
         <name>android.hardware.graphics.composer</name>
         <transport>hwbinder</transport>
-        <version>2.2</version>
+        <version>2.3</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl">
-        <name>android.hardware.graphics.mapper</name>
-        <transport arch="32+64">passthrough</transport>
-        <version>4.0</version>
-        <interface>
-            <name>IMapper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <!-- TODO (b/130075874):
     <hal format="hidl">
         <name>android.hardware.ir</name>
@@ -146,19 +117,6 @@
         </interface>
     </hal>
     -->
-    <hal format="hidl">
-        <name>android.hardware.media.omx</name>
-        <transport>hwbinder</transport>
-        <version>1.0</version>
-        <interface>
-            <name>IOmx</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IOmxStore</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <!-- TODO (b/130079342):
     <hal format="hidl">
         <name>android.hardware.memtrack</name>
@@ -195,7 +153,7 @@
     <hal format="hidl">
         <name>android.hardware.radio</name>
         <transport>hwbinder</transport>
-        <version>1.5</version>
+        <version>1.6</version>
         <interface>
             <name>IRadio</name>
             <instance>slot1</instance>
@@ -208,17 +166,15 @@
         </interface>
         -->
     </hal>
-    <!-- TODO (b/130076972):
     <hal format="hidl">
         <name>android.hardware.radio.config</name>
         <transport>hwbinder</transport>
-        <version>1.2</version>
+        <version>1.3</version>
         <interface>
             <name>IRadioConfig</name>
             <instance>default</instance>
         </interface>
     </hal>
-    -->
     <!-- TODO (b/130079239):
     <hal format="hidl">
         <name>android.hardware.secure_element</name>
@@ -230,6 +186,7 @@
         </interface>
     </hal>
     -->
+    <!--
     <hal format="hidl">
         <name>android.hardware.soundtrigger</name>
         <transport>hwbinder</transport>
@@ -239,6 +196,7 @@
             <instance>default</instance>
         </interface>
     </hal>
+    -->
     <!-- TODO (b/130079321):
     <hal format="hidl">
         <name>android.hardware.tetheroffload.config</name>
diff --git a/shared/config/manifest_android.hardware.bluetooth@1.1-service.xml b/shared/config/manifest_android.hardware.bluetooth@1.1-service.xml
new file mode 100644
index 0000000..4d70779
--- /dev/null
+++ b/shared/config/manifest_android.hardware.bluetooth@1.1-service.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2021, 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.
+*/
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.bluetooth</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/shared/config/media_codecs_performance.xml b/shared/config/media_codecs_performance.xml
index 4c44a23..a85067f 100644
--- a/shared/config/media_codecs_performance.xml
+++ b/shared/config/media_codecs_performance.xml
@@ -45,10 +45,24 @@
 
 <MediaCodecs>
     <Encoders>
+        <MediaCodec name="c2.android.h263.encoder" type="video/3gpp" update="true">
+            <!-- 3 runs, min 849 max 1008 gmean 943 -->
+            <Limit name="measured-frame-rate-176x144" range="849-1008" />
+        </MediaCodec>
         <MediaCodec name="OMX.google.h263.encoder" type="video/3gpp" update="true">
             <!-- 3 runs, min 849 max 1008 gmean 943 -->
             <Limit name="measured-frame-rate-176x144" range="849-1008" />
         </MediaCodec>
+        <MediaCodec name="c2.android.avc.encoder" type="video/avc" update="true">
+            <!-- 3 runs, min 496 max 629 gmean 565 -->
+            <Limit name="measured-frame-rate-320x240" range="496-629" />
+            <!-- 2 runs, min 197 max 203 gmean 201 -->
+            <Limit name="measured-frame-rate-720x480" range="197-203" />
+            <!-- 2 runs, min 93 max 97 gmean 95 -->
+            <Limit name="measured-frame-rate-1280x720" range="93-97" />
+            <!-- 2 runs, min 45 max 47 gmean 46 -->
+            <Limit name="measured-frame-rate-1920x1080" range="45-47" />
+        </MediaCodec>
         <MediaCodec name="OMX.google.h264.encoder" type="video/avc" update="true">
             <!-- 3 runs, min 496 max 629 gmean 565 -->
             <Limit name="measured-frame-rate-320x240" range="496-629" />
@@ -59,10 +73,28 @@
             <!-- 2 runs, min 45 max 47 gmean 46 -->
             <Limit name="measured-frame-rate-1920x1080" range="45-47" />
         </MediaCodec>
+        <MediaCodec name="c2.android.hevc.encoder" type="video/hevc" update="true">
+            <!-- MANUALLY ADJUSTED -->
+            <Limit name="measured-frame-rate-320x240" range="27-40" />
+        </MediaCodec>
+        <MediaCodec name="c2.android.mpeg4.encoder" type="video/mp4v-es" update="true">
+            <!-- 3 runs, min 881 max 1142 gmean 994 -->
+            <Limit name="measured-frame-rate-176x144" range="881-1142" />
+        </MediaCodec>
         <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es" update="true">
             <!-- 3 runs, min 881 max 1142 gmean 994 -->
             <Limit name="measured-frame-rate-176x144" range="881-1142" />
         </MediaCodec>
+        <MediaCodec name="c2.android.vp8.encoder" type="video/x-vnd.on2.vp8" update="true">
+            <!-- 3 runs, min 249 max 285 gmean 264 -->
+            <Limit name="measured-frame-rate-320x180" range="249-285" />
+            <!-- 3 runs, min 104 max 115 gmean 109 -->
+            <Limit name="measured-frame-rate-640x360" range="104-115" />
+            <!-- 3 runs, min 34 max 35 gmean 34 -->
+            <Limit name="measured-frame-rate-1280x720" range="34-35" />
+            <!-- 3 runs, min 26 max 29 gmean 27 -->
+            <Limit name="measured-frame-rate-1920x1080" range="26-29" />
+        </MediaCodec>
         <MediaCodec name="OMX.google.vp8.encoder" type="video/x-vnd.on2.vp8" update="true">
             <!-- 3 runs, min 249 max 285 gmean 264 -->
             <Limit name="measured-frame-rate-320x180" range="249-285" />
@@ -73,6 +105,14 @@
             <!-- 3 runs, min 26 max 29 gmean 27 -->
             <Limit name="measured-frame-rate-1920x1080" range="26-29" />
         </MediaCodec>
+        <MediaCodec name="c2.android.vp9.encoder" type="video/x-vnd.on2.vp9" update="true">
+            <!-- MANUALLY ADJUSTED -->
+            <Limit name="measured-frame-rate-320x180" range="158-281" />
+            <!-- MANUALLY ADJUSTED -->
+            <Limit name="measured-frame-rate-640x360" range="56-66" />
+            <!-- MANUALLY ADJUSTED -->
+            <Limit name="measured-frame-rate-1280x720" range="23-23" />
+        </MediaCodec>
     </Encoders>
     <Decoders>
         <MediaCodec name="c2.android.avc.decoder" type="video/avc" update="true">
diff --git a/shared/config/product_manifest.xml b/shared/config/product_manifest.xml
new file mode 100644
index 0000000..5a8c4ba
--- /dev/null
+++ b/shared/config/product_manifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<manifest version="1.0" type="framework" />
diff --git a/shared/config/spn-conf.xml b/shared/config/spn-conf.xml
deleted file mode 100644
index f1639df..0000000
--- a/shared/config/spn-conf.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-** Copyright 2017, 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.
-*/
--->
-<spnOverrides>
-    <spnOverride numeric="311740" spn="Android"/>
-</spnOverrides>
diff --git a/shared/config/system_ext_manifest.xml b/shared/config/system_ext_manifest.xml
new file mode 100644
index 0000000..5a8c4ba
--- /dev/null
+++ b/shared/config/system_ext_manifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<manifest version="1.0" type="framework" />
diff --git a/shared/config/task_profiles.json b/shared/config/task_profiles.json
index b883c46..42366fc 100644
--- a/shared/config/task_profiles.json
+++ b/shared/config/task_profiles.json
@@ -1,47 +1,4 @@
 {
-  "Attributes": [
-    {
-      "Name": "LowCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "background/cpus"
-    },
-    {
-      "Name": "HighCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "foreground/cpus"
-    },
-    {
-      "Name": "MaxCapacityCPUs",
-      "Controller": "cpuset",
-      "File": "top-app/cpus"
-    },
-    {
-      "Name": "MemLimit",
-      "Controller": "memory",
-      "File": "memory.limit_in_bytes"
-    },
-    {
-      "Name": "MemSoftLimit",
-      "Controller": "memory",
-      "File": "memory.soft_limit_in_bytes"
-    },
-    {
-      "Name": "MemSwappiness",
-      "Controller": "memory",
-      "File": "memory.swappiness"
-    },
-    {
-      "Name": "UClampMin",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.min"
-    },
-    {
-      "Name": "UClampMax",
-      "Controller": "cpu",
-      "File": "cpu.uclamp.max"
-    }
-  ],
-
   "Profiles": [
     {
       "Name": "HighEnergySaving",
@@ -57,32 +14,6 @@
       ]
     },
     {
-      "Name": "Frozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": "frozen"
-          }
-        }
-      ]
-    },
-    {
-      "Name": "Unfrozen",
-      "Actions": [
-        {
-          "Name": "JoinCgroup",
-          "Params":
-          {
-            "Controller": "freezer",
-            "Path": ""
-          }
-        }
-      ]
-    },
-    {
       "Name": "NormalPerformance",
       "Actions": [
         {
diff --git a/shared/config/ueventd.rc b/shared/config/ueventd.rc
index ba62a87..8f24201 100644
--- a/shared/config/ueventd.rc
+++ b/shared/config/ueventd.rc
@@ -1,6 +1,3 @@
-# android.permission.cts.FileSystemPermissionTest#testDevHwRandomLockedDown
-/dev/hw_random 0600 root root
-
 # virtio-gpu
 /dev/dri/card0 0660 system graphics
 /dev/dri/controlD64 0660 system graphics
@@ -11,3 +8,25 @@
 
 # resume-on-reboot
 /dev/block/pmem0 0770 system system
+
+# vtpm
+/dev/tpm0 0000 root root
+/dev/tpmrm0 000 system system
+
+# seriallogging
+/dev/hvc2 0660 system logd
+
+# keymaster
+/dev/hvc3 0666 system system
+
+# gatekeeper
+/dev/hvc4 0660 system system
+
+# bluetooth
+/dev/hvc5 0660 bluetooth bluetooth
+/dev/vhci 0660 bluetooth bluetooth
+
+/dev/gnss0 0666 system system
+
+# Factory Reset Protection
+/dev/block/by-name/frp 0660 system system
diff --git a/shared/wpa_supplicant_overlay.conf b/shared/config/wpa_supplicant_overlay.conf
similarity index 100%
rename from shared/wpa_supplicant_overlay.conf
rename to shared/config/wpa_supplicant_overlay.conf
diff --git a/shared/device.mk b/shared/device.mk
index 377db3b..1ae1c58 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -23,29 +23,44 @@
 # Enable userspace reboot
 $(call inherit-product, $(SRC_TARGET_DIR)/product/userspace_reboot.mk)
 
-PRODUCT_SHIPPING_API_LEVEL := 30
-PRODUCT_BUILD_BOOT_IMAGE := true
-PRODUCT_USE_DYNAMIC_PARTITIONS := true
-DISABLE_RILD_OEM_HOOK := true
+# Enforce generic ramdisk allow list
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
 
 PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for vulkan
 
+PRODUCT_SHIPPING_API_LEVEL := 31
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
+DISABLE_RILD_OEM_HOOK := true
+
+PRODUCT_SET_DEBUGFS_RESTRICTIONS := true
+
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for vulkan
+
+PRODUCT_FS_COMPRESSION := 1
+TARGET_RO_FILE_SYSTEM_TYPE ?= ext4
 TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE ?= f2fs
+TARGET_USERDATAIMAGE_PARTITION_SIZE ?= 6442450944
 
 TARGET_VULKAN_SUPPORT ?= true
+TARGET_ENABLE_HOST_BLUETOOTH_EMULATION ?= true
+TARGET_USE_BTLINUX_HAL_IMPL ?= true
 
 AB_OTA_UPDATER := true
 AB_OTA_PARTITIONS += \
+    boot \
     odm \
+    odm_dlkm \
     product \
     system \
     system_ext \
     vbmeta \
     vbmeta_system \
-    vendor
+    vendor \
+    vendor_boot \
+    vendor_dlkm \
 
 # Enable Virtual A/B
-$(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)
 
 # Enable Scoped Storage related
 $(call inherit-product, $(SRC_TARGET_DIR)/product/emulated_storage.mk)
@@ -56,43 +71,76 @@
 PRODUCT_PRODUCT_PROPERTIES += \
     persist.adb.tcp.port=5555 \
     ro.com.google.locationfeatures=1 \
+    persist.sys.fuse.passthrough.enable=true \
+
+# Storage: for factory reset protection feature
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.frp.pst=/dev/block/by-name/frp
 
 # Explanation of specific properties:
 #   debug.hwui.swap_with_damage avoids boot failure on M http://b/25152138
 #   ro.opengles.version OpenGLES 3.0
-PRODUCT_PROPERTY_OVERRIDES += \
+#   ro.hardware.keystore_desede=true needed for CtsKeystoreTestCases
+PRODUCT_VENDOR_PROPERTIES += \
     tombstoned.max_tombstone_count=500 \
-    bt.rootcanal_test_console=off \
+    vendor.bt.rootcanal_test_console=off \
     debug.hwui.swap_with_damage=0 \
     ro.carrier=unknown \
-    ro.com.android.dataroaming=false \
+    ro.com.android.dataroaming?=false \
     ro.hardware.virtual_device=1 \
     ro.logd.size=1M \
     ro.opengles.version=196608 \
     wifi.interface=wlan0 \
     persist.sys.zram_enabled=1 \
+    ro.hardware.keystore_desede=true \
     ro.rebootescrow.device=/dev/block/pmem0 \
     ro.incremental.enable=1 \
+    debug.c2.use_dmabufheaps=1 \
+    ro.camerax.extensions.enabled=true \
 
 # Below is a list of properties we probably should get rid of.
-PRODUCT_PROPERTY_OVERRIDES += \
+PRODUCT_VENDOR_PROPERTIES += \
     wlan.driver.status=ok
 
-# Codec 2.0 is unstable on x86
-PRODUCT_PROPERTY_OVERRIDES += \
-    debug.stagefright.ccodec=0
+ifneq ($(LOCAL_DISABLE_OMX),true)
+# Codec 1.0 requires the OMX services
+DEVICE_MANIFEST_FILE += \
+    device/google/cuttlefish/shared/config/android.hardware.media.omx@1.0.xml
+endif
 
-# Enforce privapp-permissions whitelist.
-PRODUCT_PROPERTY_OVERRIDES += ro.control_privapp_permissions=enforce
+PRODUCT_VENDOR_PROPERTIES += \
+    debug.stagefright.c2inputsurface=-1
+
+# Enforce privapp permissions control.
+PRODUCT_VENDOR_PROPERTIES += ro.control_privapp_permissions?=enforce
 
 # aes-256-heh default is not supported in standard kernels.
-PRODUCT_PROPERTY_OVERRIDES += ro.crypto.volume.filenames_mode=aes-256-cts
+PRODUCT_VENDOR_PROPERTIES += ro.crypto.volume.filenames_mode=aes-256-cts
 
 # Copy preopted files from system_b on first boot
-PRODUCT_PROPERTY_OVERRIDES += ro.cp_system_other_odex=1
+PRODUCT_VENDOR_PROPERTIES += ro.cp_system_other_odex=1
+
+AB_OTA_POSTINSTALL_CONFIG += \
+    RUN_POSTINSTALL_system=true \
+    POSTINSTALL_PATH_system=system/bin/otapreopt_script \
+    FILESYSTEM_TYPE_system=ext4 \
+    POSTINSTALL_OPTIONAL_system=true
+
+AB_OTA_POSTINSTALL_CONFIG += \
+    RUN_POSTINSTALL_vendor=true \
+    POSTINSTALL_PATH_vendor=bin/checkpoint_gc \
+    FILESYSTEM_TYPE_vendor=ext4 \
+    POSTINSTALL_OPTIONAL_vendor=true
+
+# Userdata Checkpointing OTA GC
+PRODUCT_PACKAGES += \
+    checkpoint_gc
+
+# Enable CameraX extension sample
+PRODUCT_PACKAGES += androidx.camera.extensions.impl sample_camera_extensions.xml
 
 # DRM service opt-in
-PRODUCT_PROPERTY_OVERRIDES += drm.service.enabled=true
+PRODUCT_VENDOR_PROPERTIES += drm.service.enabled=true
 
 PRODUCT_SOONG_NAMESPACES += hardware/google/camera
 PRODUCT_SOONG_NAMESPACES += hardware/google/camera/devices/EmulatedCamera
@@ -101,18 +149,25 @@
 # Packages for various GCE-specific utilities
 #
 PRODUCT_PACKAGES += \
-    socket_vsock_proxy \
     CuttlefishService \
-    wpa_supplicant.vsoc.conf \
-    vsoc_input_service \
-    vport_trigger \
+    cuttlefish_sensor_injection \
     rename_netiface \
-    ip_link_add \
     setup_wifi \
+    bt_vhci_forwarder \
+    socket_vsock_proxy \
     tombstone_transmit \
-    vsock_logcat \
     tombstone_producer \
     suspend_blocker \
+    vsoc_input_service \
+    vtpm_manager \
+
+SOONG_CONFIG_NAMESPACES += cvd
+SOONG_CONFIG_cvd += launch_configs
+SOONG_CONFIG_cvd_launch_configs += \
+    cvd_config_auto.json \
+    cvd_config_phone.json \
+    cvd_config_tablet.json \
+    cvd_config_tv.json \
 
 #
 # Packages for AOSP-available stuff we use from the framework
@@ -129,6 +184,13 @@
 # Packages for the OpenGL implementation
 #
 
+# ANGLE provides an OpenGL implementation built on top of Vulkan.
+PRODUCT_PACKAGES += \
+    libEGL_angle \
+    libGLESv1_CM_angle \
+    libGLESv2_angle \
+    libfeature_support_angle.so
+
 # SwiftShader provides a software-only implementation that is not thread-safe
 PRODUCT_PACKAGES += \
     libEGL_swiftshader \
@@ -151,6 +213,7 @@
 
 # GL/Vk implementation for gfxstream
 PRODUCT_PACKAGES += \
+    hwcomposer.ranchu \
     libandroidemu \
     libOpenglCodecCommon \
     libOpenglSystemCommon \
@@ -173,10 +236,27 @@
 # pick up every density resources.
 
 #
+# Common manifest for all targets
+#
+DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/config/manifest.xml
+
+#
 # General files
 #
+
+
+ifneq ($(LOCAL_SENSOR_FILE_OVERRIDES),true)
+    PRODUCT_COPY_FILES += \
+        frameworks/native/data/etc/android.hardware.sensor.ambient_temperature.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.ambient_temperature.xml \
+        frameworks/native/data/etc/android.hardware.sensor.barometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.barometer.xml \
+        frameworks/native/data/etc/android.hardware.sensor.gyroscope.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.gyroscope.xml \
+        frameworks/native/data/etc/android.hardware.sensor.hinge_angle.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.hinge_angle.xml \
+        frameworks/native/data/etc/android.hardware.sensor.light.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.light.xml \
+        frameworks/native/data/etc/android.hardware.sensor.proximity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.proximity.xml \
+        frameworks/native/data/etc/android.hardware.sensor.relative_humidity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.relative_humidity.xml
+endif
+
 PRODUCT_COPY_FILES += \
-    device/google/cuttlefish/shared/config/audio_policy.conf:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy.conf \
     hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_back.json:$(TARGET_COPY_OUT_VENDOR)/etc/config/emu_camera_back.json \
     hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_front.json:$(TARGET_COPY_OUT_VENDOR)/etc/config/emu_camera_front.json \
     hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_depth.json:$(TARGET_COPY_OUT_VENDOR)/etc/config/emu_camera_depth.json \
@@ -192,13 +272,12 @@
     frameworks/av/media/libeffects/data/audio_effects.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_effects.xml \
     frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_google_audio.xml \
     frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_google_telephony.xml \
-    frameworks/av/services/audiopolicy/config/audio_policy_configuration_generic.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml \
-    frameworks/av/services/audiopolicy/config/primary_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/primary_audio_policy_configuration.xml \
     frameworks/av/services/audiopolicy/config/r_submix_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/r_submix_audio_policy_configuration.xml \
     frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \
     frameworks/av/services/audiopolicy/config/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml \
     frameworks/av/services/audiopolicy/config/surround_sound_configuration_5_0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/surround_sound_configuration_5_0.xml \
     frameworks/native/data/etc/android.hardware.audio.low_latency.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.audio.low_latency.xml \
+    frameworks/native/data/etc/android.hardware.bluetooth.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth.xml \
     frameworks/native/data/etc/android.hardware.bluetooth_le.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth_le.xml \
     frameworks/native/data/etc/android.hardware.camera.concurrent.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.concurrent.xml \
     frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.flash-autofocus.xml \
@@ -206,35 +285,47 @@
     frameworks/native/data/etc/android.hardware.camera.full.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.full.xml \
     frameworks/native/data/etc/android.hardware.camera.raw.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.raw.xml \
     frameworks/native/data/etc/android.hardware.ethernet.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.ethernet.xml \
-    frameworks/native/data/etc/android.hardware.faketouch.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.faketouch.xml \
     frameworks/native/data/etc/android.hardware.location.gps.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.location.gps.xml \
     frameworks/native/data/etc/android.hardware.reboot_escrow.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.reboot_escrow.xml \
-    frameworks/native/data/etc/android.hardware.sensor.ambient_temperature.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.ambient_temperature.xml \
-    frameworks/native/data/etc/android.hardware.sensor.barometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.barometer.xml \
-    frameworks/native/data/etc/android.hardware.sensor.gyroscope.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.gyroscope.xml \
-    frameworks/native/data/etc/android.hardware.sensor.hinge_angle.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.hinge_angle.xml \
-    frameworks/native/data/etc/android.hardware.sensor.light.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.light.xml \
-    frameworks/native/data/etc/android.hardware.sensor.proximity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.proximity.xml \
-    frameworks/native/data/etc/android.hardware.sensor.relative_humidity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.relative_humidity.xml \
     frameworks/native/data/etc/android.hardware.usb.accessory.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.usb.accessory.xml \
+    frameworks/native/data/etc/android.hardware.usb.host.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.usb.host.xml \
     frameworks/native/data/etc/android.hardware.wifi.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.xml \
+    frameworks/native/data/etc/android.hardware.wifi.passpoint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.passpoint.xml \
     frameworks/native/data/etc/android.software.ipsec_tunnels.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.ipsec_tunnels.xml \
     frameworks/native/data/etc/android.software.sip.voip.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.sip.voip.xml \
     frameworks/native/data/etc/android.software.verified_boot.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.verified_boot.xml \
     system/bt/vendor_libs/test_vendor_lib/data/controller_properties.json:vendor/etc/bluetooth/controller_properties.json \
     device/google/cuttlefish/shared/config/task_profiles.json:$(TARGET_COPY_OUT_VENDOR)/etc/task_profiles.json \
-    device/google/cuttlefish/shared/config/fstab.f2fs:$(TARGET_COPY_OUT_RAMDISK)/fstab.f2fs \
+    device/google/cuttlefish/shared/config/input/Crosvm_Virtio_Multitouch_Touchscreen.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/Crosvm_Virtio_Multitouch_Touchscreen.idc
+
+ifeq ($(TARGET_RO_FILE_SYSTEM_TYPE),ext4)
+PRODUCT_COPY_FILES += \
+    device/google/cuttlefish/shared/config/fstab.f2fs:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.f2fs \
+    device/google/cuttlefish/shared/config/fstab.f2fs:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/fstab.f2fs \
     device/google/cuttlefish/shared/config/fstab.f2fs:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.f2fs \
     device/google/cuttlefish/shared/config/fstab.f2fs:$(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk/fstab.f2fs \
-    device/google/cuttlefish/shared/config/fstab.ext4:$(TARGET_COPY_OUT_RAMDISK)/fstab.ext4 \
+    device/google/cuttlefish/shared/config/fstab.ext4:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.ext4 \
+    device/google/cuttlefish/shared/config/fstab.ext4:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/fstab.ext4 \
     device/google/cuttlefish/shared/config/fstab.ext4:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ext4 \
     device/google/cuttlefish/shared/config/fstab.ext4:$(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk/fstab.ext4
+else
+PRODUCT_COPY_FILES += \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).f2fs:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.f2fs \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).f2fs:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/fstab.f2fs \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).f2fs:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.f2fs \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).f2fs:$(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk/fstab.f2fs \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).ext4:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.ext4 \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).ext4:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/fstab.ext4 \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).ext4:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ext4 \
+    device/google/cuttlefish/shared/config/fstab-$(TARGET_RO_FILE_SYSTEM_TYPE).ext4:$(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk/fstab.ext4
+endif
 
 ifeq ($(TARGET_VULKAN_SUPPORT),true)
 PRODUCT_COPY_FILES += \
     frameworks/native/data/etc/android.hardware.vulkan.level-0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.level.xml \
     frameworks/native/data/etc/android.hardware.vulkan.version-1_0_3.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml \
-    frameworks/native/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.vulkan.deqp.level.xml
+    frameworks/native/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.vulkan.deqp.level.xml \
+    frameworks/native/data/etc/android.software.opengles.deqp.level-2021-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.opengles.deqp.level.xml
 endif
 
 # Packages for HAL implementations
@@ -246,21 +337,37 @@
     android.hardware.atrace@1.0-service
 
 #
+# Weaver aidl HAL
+#
+PRODUCT_PACKAGES += \
+    android.hardware.weaver-service.example
+
+#
+# OemLock aidl HAL
+#
+PRODUCT_PACKAGES += \
+    android.hardware.oemlock-service.example
+
+#
 # Authsecret HAL
 #
 PRODUCT_PACKAGES += \
     android.hardware.authsecret@1.0-service
 
 #
+# Authsecret AIDL HAL
+#
+PRODUCT_PACKAGES += \
+    android.hardware.authsecret-service.example
+#
 # Hardware Composer HAL
 #
 PRODUCT_PACKAGES += \
     hwcomposer.drm_minigbm \
-    hwcomposer.cutf_cvm_ashmem \
-    hwcomposer.cutf_hwc2 \
+    hwcomposer.cutf \
     hwcomposer-stats \
-    android.hardware.graphics.composer@2.2-impl \
-    android.hardware.graphics.composer@2.2-service
+    android.hardware.graphics.composer@2.3-impl \
+    android.hardware.graphics.composer@2.3-service
 
 #
 # Gralloc HAL
@@ -272,39 +379,80 @@
 #
 # Bluetooth HAL and Compatibility Bluetooth library (for older revs).
 #
-PRODUCT_PACKAGES += \
-    android.hardware.bluetooth@1.1-service.sim \
-    android.hardware.bluetooth.audio@2.0-impl
+ifeq ($(LOCAL_BLUETOOTH_PRODUCT_PACKAGE),)
+ifeq ($(TARGET_ENABLE_HOST_BLUETOOTH_EMULATION),true)
+ifeq ($(TARGET_USE_BTLINUX_HAL_IMPL),true)
+    LOCAL_BLUETOOTH_PRODUCT_PACKAGE := android.hardware.bluetooth@1.1-service.btlinux
+else
+    LOCAL_BLUETOOTH_PRODUCT_PACKAGE := android.hardware.bluetooth@1.1-service.remote
+endif
+else
+    LOCAL_BLUETOOTH_PRODUCT_PACKAGE := android.hardware.bluetooth@1.1-service.sim
+endif
+    DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/config/manifest_android.hardware.bluetooth@1.1-service.xml
+endif
+
+PRODUCT_PACKAGES += $(LOCAL_BLUETOOTH_PRODUCT_PACKAGE)
+
+PRODUCT_PACKAGES += android.hardware.bluetooth.audio@2.1-impl
 
 #
 # Audio HAL
 #
-PRODUCT_PACKAGES += \
+LOCAL_AUDIO_PRODUCT_PACKAGE ?= \
     audio.primary.cutf \
     audio.r_submix.default \
-    android.hardware.audio@6.0-impl:32 \
-    android.hardware.audio.effect@6.0-impl:32 \
-    android.hardware.audio@2.0-service \
-    android.hardware.soundtrigger@2.3-impl \
+    android.hardware.audio@6.0-impl \
+    android.hardware.audio.effect@6.0-impl \
+    android.hardware.audio@2.0-service
+
+LOCAL_AUDIO_PRODUCT_COPY_FILES ?= \
+    device/google/cuttlefish/shared/config/audio_policy.conf:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy.conf \
+    frameworks/av/services/audiopolicy/config/audio_policy_configuration_generic.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml \
+    frameworks/av/services/audiopolicy/config/primary_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/primary_audio_policy_configuration.xml
+
+LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS ?=
+
+PRODUCT_PACKAGES += $(LOCAL_AUDIO_PRODUCT_PACKAGE)
+PRODUCT_COPY_FILES += $(LOCAL_AUDIO_PRODUCT_COPY_FILES)
+DEVICE_PACKAGE_OVERLAYS += $(LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS)
 
 #
-# BiometricsFace HAL
+# BiometricsFace HAL (HIDL)
 #
 PRODUCT_PACKAGES += \
     android.hardware.biometrics.face@1.0-service.example
 
 #
+# BiometricsFingerprint HAL (HIDL)
+#
+PRODUCT_PACKAGES += \
+    android.hardware.biometrics.fingerprint@2.2-service.example
+
+#
+# BiometricsFace HAL (AIDL)
+#
+PRODUCT_PACKAGES += \
+    android.hardware.biometrics.face-service.example
+
+#
+# BiometricsFingerprint HAL (AIDL)
+#
+PRODUCT_PACKAGES += \
+    android.hardware.biometrics.fingerprint-service.example
+
+#
 # Contexthub HAL
 #
 PRODUCT_PACKAGES += \
-    android.hardware.contexthub@1.1-service.mock
+    android.hardware.contexthub@1.2-service.mock
 
 #
 # Drm HAL
 #
 PRODUCT_PACKAGES += \
-    android.hardware.drm@1.3-service.clearkey \
-    android.hardware.drm@1.3-service.widevine
+    android.hardware.drm@1.4-service.clearkey \
+    android.hardware.drm@1.4-service.widevine
 
 #
 # Dumpstate HAL
@@ -318,21 +466,24 @@
 # Camera
 #
 PRODUCT_PACKAGES += \
-    android.hardware.camera.provider@2.6-service-google \
+    android.hardware.camera.provider@2.7-service-google \
     libgooglecamerahwl_impl \
-    android.hardware.camera.provider@2.6-impl-google \
+    android.hardware.camera.provider@2.7-impl-google \
 
 #
 # Gatekeeper
 #
+ifeq ($(LOCAL_GATEKEEPER_PRODUCT_PACKAGE),)
+       LOCAL_GATEKEEPER_PRODUCT_PACKAGE := android.hardware.gatekeeper@1.0-service.software
+endif
 PRODUCT_PACKAGES += \
-    android.hardware.gatekeeper@1.0-service.software
+    $(LOCAL_GATEKEEPER_PRODUCT_PACKAGE)
 
 #
 # GPS
 #
 PRODUCT_PACKAGES += \
-    android.hardware.gnss@2.1-service
+    android.hardware.gnss-service.example
 
 # Health
 ifeq ($(LOCAL_HEALTH_PRODUCT_PACKAGE),)
@@ -344,7 +495,7 @@
 
 # Health Storage
 PRODUCT_PACKAGES += \
-    android.hardware.health.storage@1.0-service.cuttlefish
+    android.hardware.health.storage-service.cuttlefish
 
 # Identity Credential
 PRODUCT_PACKAGES += \
@@ -375,10 +526,17 @@
     android.hardware.lights-service.example \
 
 #
-# Keymaster HAL
+# KeyMint HAL
 #
-PRODUCT_PACKAGES += \
-     android.hardware.keymaster@4.1-service
+ifeq ($(LOCAL_KEYMINT_PRODUCT_PACKAGE),)
+       LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service
+endif
+ PRODUCT_PACKAGES += \
+    $(LOCAL_KEYMINT_PRODUCT_PACKAGE)
+
+# Keymint configuration
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.software.device_id_attestation.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.device_id_attestation.xml
 
 #
 # Power HAL
@@ -390,7 +548,7 @@
 # PowerStats HAL
 #
 PRODUCT_PACKAGES += \
-    android.hardware.power.stats@1.0-service.mock
+    android.hardware.power.stats-service.example
 
 #
 # NeuralNetworks HAL
@@ -400,7 +558,13 @@
     android.hardware.neuralnetworks@1.3-service-sample-float-fast \
     android.hardware.neuralnetworks@1.3-service-sample-float-slow \
     android.hardware.neuralnetworks@1.3-service-sample-minimal \
-    android.hardware.neuralnetworks@1.3-service-sample-quant
+    android.hardware.neuralnetworks@1.3-service-sample-quant \
+    android.hardware.neuralnetworks-service-sample-all \
+    android.hardware.neuralnetworks-service-sample-float-fast \
+    android.hardware.neuralnetworks-service-sample-float-slow \
+    android.hardware.neuralnetworks-service-sample-minimal \
+    android.hardware.neuralnetworks-service-sample-quant \
+    android.hardware.neuralnetworks-shim-service-sample
 
 #
 # USB
@@ -413,17 +577,42 @@
 
 # BootControl HAL
 PRODUCT_PACKAGES += \
-    android.hardware.boot@1.1-impl \
-    android.hardware.boot@1.1-impl.recovery \
-    android.hardware.boot@1.1-service
+    android.hardware.boot@1.2-impl \
+    android.hardware.boot@1.2-impl.recovery \
+    android.hardware.boot@1.2-service
 
 # RebootEscrow HAL
 PRODUCT_PACKAGES += \
     android.hardware.rebootescrow-service.default
 
+# Memtrack HAL
+PRODUCT_PACKAGES += \
+    android.hardware.memtrack-service.example
+
+# GKI APEX
+# Keep in sync with BOARD_KERNEL_MODULE_INTERFACE_VERSIONS
+ifneq (,$(TARGET_KERNEL_USE))
+  ifneq (,$(filter 5.4, $(TARGET_KERNEL_USE)))
+    PRODUCT_PACKAGES += com.android.gki.kmi_5_4_android12_unstable
+  else
+    PRODUCT_PACKAGES += com.android.gki.kmi_$(subst .,_,$(TARGET_KERNEL_USE))_android12_unstable
+  endif
+endif
+
+# Prevent GKI and boot image downgrades
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.build.ab_update.gki.prevent_downgrade_version=true \
+    ro.build.ab_update.gki.prevent_downgrade_spl=true \
+
 # WLAN driver configuration files
 PRODUCT_COPY_FILES += \
-    $(LOCAL_PATH)/wpa_supplicant_overlay.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/wpa_supplicant_overlay.conf
+    external/wpa_supplicant_8/wpa_supplicant/wpa_supplicant_template.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/wpa_supplicant.conf \
+    $(LOCAL_PATH)/config/wpa_supplicant_overlay.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/wpa_supplicant_overlay.conf
+
+# Fastboot HAL & fastbootd
+PRODUCT_PACKAGES += \
+    android.hardware.fastboot@1.1-impl-mock \
+    fastbootd
 
 # Recovery mode
 ifneq ($(TARGET_NO_RECOVERY),true)
@@ -433,6 +622,16 @@
     device/google/cuttlefish/shared/config/cgroups.json:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/etc/cgroups.json \
     device/google/cuttlefish/shared/config/ueventd.rc:$(TARGET_COPY_OUT_RECOVERY)/root/ueventd.cutf_cvm.rc \
 
+PRODUCT_PACKAGES += \
+    update_engine_sideload
+
+endif
+
+ifdef TARGET_DEDICATED_RECOVERY
+PRODUCT_BUILD_RECOVERY_IMAGE := true
+PRODUCT_PACKAGES += linker.vendor_ramdisk shell_and_utilities_vendor_ramdisk
+else
+PRODUCT_PACKAGES += linker.recovery shell_and_utilities_recovery
 endif
 
 #
@@ -444,10 +643,26 @@
 # Host packages to install
 PRODUCT_HOST_PACKAGES += socket_vsock_proxy
 
-PRODUCT_EXTRA_VNDK_VERSIONS := 28 29
+PRODUCT_EXTRA_VNDK_VERSIONS := 28 29 30
 
 PRODUCT_SOONG_NAMESPACES += external/mesa3d
 
+#for Confirmation UI
+PRODUCT_SOONG_NAMESPACES += vendor/google_devices/common/proprietary/confirmatioui_hal
+
 # Need this so that the application's loop on reading input can be synchronized
 # with HW VSYNC
-PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.surface_flinger.running_without_sync_framework=true
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.surface_flinger.running_without_sync_framework=true
+
+# Set support one-handed mode
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.support_one_handed_mode=true
+
+# Set one_handed_mode screen translate offset percentage
+PRODUCT_PRODUCT_PROPERTIES += \
+    persist.debug.one_handed_offset_percentage=50
+
+# Set one_handed_mode translate animation duration milliseconds
+PRODUCT_PRODUCT_PROPERTIES += \
+    persist.debug.one_handed_translate_animation_duration=300
diff --git a/shared/foldable/android-info.txt b/shared/foldable/android-info.txt
new file mode 100644
index 0000000..8552685
--- /dev/null
+++ b/shared/foldable/android-info.txt
@@ -0,0 +1 @@
+config=foldable
diff --git a/shared/foldable/device_state_configuration.xml b/shared/foldable/device_state_configuration.xml
new file mode 100644
index 0000000..9618b11
--- /dev/null
+++ b/shared/foldable/device_state_configuration.xml
@@ -0,0 +1,37 @@
+<device-state-config>
+  <device-state>
+    <identifier>0</identifier>
+    <name>CLOSED</name>
+    <conditions>
+      <lid-switch>
+        <open>false</open>
+      </lid-switch>
+    </conditions>
+  </device-state>
+  <device-state>
+    <identifier>1</identifier>
+    <name>HALF_OPENED</name>
+    <conditions>
+      <lid-switch>
+        <open>true</open>
+      </lid-switch>
+      <sensor>
+        <type>android.sensor.hinge_angle</type>
+        <name>Hinge Angle Sensor</name>
+        <value>
+          <min>0</min>
+          <max>180</max>
+        </value>
+      </sensor>
+    </conditions>
+  </device-state>
+  <device-state>
+    <identifier>2</identifier>
+    <name>OPENED</name>
+    <conditions>
+      <lid-switch>
+        <open>true</open>
+      </lid-switch>
+    </conditions>
+  </device-state>
+</device-state-config>
diff --git a/shared/foldable/overlay/frameworks/base/core/res/res/values/config.xml b/shared/foldable/overlay/frameworks/base/core/res/res/values/config.xml
new file mode 100644
index 0000000..2c540e1
--- /dev/null
+++ b/shared/foldable/overlay/frameworks/base/core/res/res/values/config.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2021, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <!-- Indicate the display area rect for foldable devices in folded state. -->
+  <!-- left and right bounds come from:  (open_width/2) +/- (folded_width)/2 -->
+  <string name="config_foldedArea">476 0 1292 2208</string>
+  <!-- WindowsManager JetPack display features -->
+  <string name="config_display_features" translatable="false">fold-[884,0,884,2208]</string>
+  <!-- Map of System DeviceState supplied by DeviceStateManager to WM Jetpack posture. -->
+  <string-array name="config_device_state_postures" translatable="false">
+      <item>0:1</item> <!-- CLOSED : STATE_FLAT -->
+      <item>3:2</item> <!-- HALF_OPENED : STATE_HALF_OPENED -->
+      <item>2:3</item> <!-- OPENED : STATE_FLIPPED -->
+  </string-array>
+  <!-- The device states (supplied by DeviceStateManager) that should be treated as folded by the
+       display fold controller. -->
+  <integer-array name="config_foldedDeviceStates" translatable="false">
+    <item>0</item> <!-- CLOSED -->
+  </integer-array>
+  <!-- Controls whether the device support multi window modes like split-screen. -->
+  <bool name="config_supportsMultiWindow">true</bool>
+  <!-- Controls whether device supports split-screen mode. -->
+  <bool name="config_supportsSplitScreenMultiWindow">true</bool>
+  <!-- Radius of the software rounded corners. -->
+  <dimen name="rounded_corner_radius">34px</dimen>
+</resources>
diff --git a/shared/go/device.mk b/shared/go/device.mk
index 7c7f719..e165923 100644
--- a/shared/go/device.mk
+++ b/shared/go/device.mk
@@ -15,11 +15,11 @@
 #
 
 $(call inherit-product, build/target/product/go_defaults.mk)
+$(call inherit-product, device/google/cuttlefish/shared/phone/device.mk)
 
 # By default, enable zram; experiment can toggle the flag,
 # which takes effect on boot
-PRODUCT_PROPERTY_OVERRIDES += \
-    ro.statsd.enable=true \
+PRODUCT_VENDOR_PROPERTIES += \
     pm.dexopt.downgrade_after_inactive_days=10 \
     pm.dexopt.shared=quicken \
     dalvik.vm.heapgrowthlimit=128m \
diff --git a/shared/go_512/device.mk b/shared/go_512/device.mk
index 4a95a73..0ab601b 100644
--- a/shared/go_512/device.mk
+++ b/shared/go_512/device.mk
@@ -15,11 +15,11 @@
 #
 
 $(call inherit-product, build/target/product/go_defaults_512.mk)
+$(call inherit-product, device/google/cuttlefish/shared/phone/device.mk)
 
 # By default, enable zram; experiment can toggle the flag,
 # which takes effect on boot
-PRODUCT_PROPERTY_OVERRIDES += \
-    ro.statsd.enable=true \
+PRODUCT_VENDOR_PROPERTIES += \
     pm.dexopt.downgrade_after_inactive_days=10 \
     pm.dexopt.shared=quicken \
     dalvik.vm.heapgrowthlimit=128m \
diff --git a/shared/overlay/frameworks/base/core/res/res/xml/power_profile.xml b/shared/overlay/frameworks/base/core/res/res/xml/power_profile.xml
index bdcb48d..48c4448 100644
--- a/shared/overlay/frameworks/base/core/res/res/xml/power_profile.xml
+++ b/shared/overlay/frameworks/base/core/res/res/xml/power_profile.xml
@@ -20,7 +20,7 @@
 <device name="Android">
   <!-- Most values are the incremental current used by a feature,
        in mA (measured at nominal voltage).
-       The default values are deliberately incorrect dummy values.
+       The default values are deliberately incorrect unused values.
        OEM's must measure and provide actual values before
        shipping a device.
        Example real-world values are given in comments, but they
diff --git a/shared/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml b/shared/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
index 3213eab..baef765 100644
--- a/shared/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
+++ b/shared/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
@@ -20,4 +20,5 @@
     <bool name="def_stay_on_while_plugged_in">true</bool>
     <bool name="def_install_non_market_apps">true</bool>
     <bool name="def_package_verifier_enable">false</bool>
+    <bool name="def_accelerometer_rotation">true</bool>
 </resources>
diff --git a/shared/pc/OWNERS b/shared/pc/OWNERS
new file mode 100644
index 0000000..47eb80e
--- /dev/null
+++ b/shared/pc/OWNERS
@@ -0,0 +1,3 @@
+# pc cuttlefish leads
+armenk@google.com
+xutan@google.com
\ No newline at end of file
diff --git a/shared/pc/device_vendor.mk b/shared/pc/device_vendor.mk
new file mode 100644
index 0000000..ad597c5
--- /dev/null
+++ b/shared/pc/device_vendor.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2019 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.
+#
+
+PRODUCT_MANIFEST_FILES += device/google/cuttlefish/shared/config/product_manifest.xml
+SYSTEM_EXT_MANIFEST_FILES += device/google/cuttlefish/shared/config/system_ext_manifest.xml
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_vendor.mk)
+
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/pc_core_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/pc_core_hardware.xml
+
+$(call inherit-product, frameworks/native/build/tablet-7in-xhdpi-2048-dalvik-heap.mk)
+$(call inherit-product, device/google/cuttlefish/shared/device.mk)
+
+DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/pc/overlay
\ No newline at end of file
diff --git a/shared/pc/overlay/frameworks/base/core/res/res/values/config.xml b/shared/pc/overlay/frameworks/base/core/res/res/values/config.xml
new file mode 100644
index 0000000..86896be
--- /dev/null
+++ b/shared/pc/overlay/frameworks/base/core/res/res/values/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <bool name="config_showNavigationBar" translatable="false">true</bool>
+  <!--  Maximum number of supported users -->
+  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
+  <!-- Restricting eth2 -->
+  <string-array translatable="false" name="config_ethernet_interfaces">
+    <item>eth2;11,12,14;;</item>
+  </string-array>
+</resources>
\ No newline at end of file
diff --git a/shared/permissions/cuttlefish_excluded_hardware.xml b/shared/permissions/cuttlefish_excluded_hardware.xml
index 3660289..c3d03d5 100644
--- a/shared/permissions/cuttlefish_excluded_hardware.xml
+++ b/shared/permissions/cuttlefish_excluded_hardware.xml
@@ -14,7 +14,6 @@
      limitations under the License.
 -->
 <permissions>
-    <unavailable-feature name="android.hardware.microphone" />
     <unavailable-feature name="android.software.print" />
     <unavailable-feature name="android.software.voice_recognizers" />
 </permissions>
diff --git a/shared/phone/android-info.txt b/shared/phone/android-info.txt
new file mode 100644
index 0000000..2286c3d
--- /dev/null
+++ b/shared/phone/android-info.txt
@@ -0,0 +1 @@
+config=phone
diff --git a/shared/phone/device.mk b/shared/phone/device.mk
index 56bed4e..4b5f041 100644
--- a/shared/phone/device.mk
+++ b/shared/phone/device.mk
@@ -14,17 +14,18 @@
 # limitations under the License.
 #
 
-DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/config/manifest.xml
+PRODUCT_MANIFEST_FILES += device/google/cuttlefish/shared/config/product_manifest.xml
+SYSTEM_EXT_MANIFEST_FILES += device/google/cuttlefish/shared/config/system_ext_manifest.xml
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base_telephony.mk)
 $(call inherit-product, frameworks/native/build/phone-xhdpi-2048-dalvik-heap.mk)
 $(call inherit-product, device/google/cuttlefish/shared/device.mk)
 
-PRODUCT_PROPERTY_OVERRIDES += \
+PRODUCT_VENDOR_PROPERTIES += \
     keyguard.no_require_sim=true \
     ro.cdma.home.operator.alpha=Android \
     ro.cdma.home.operator.numeric=302780 \
-    vendor.rild.libpath=libcuttlefish-ril.so \
+    ro.telephony.default_network=9 \
 
 PRODUCT_PACKAGES += \
     MmsService \
@@ -32,12 +33,15 @@
     PhoneService \
     Telecom \
     TeleService \
-    libcuttlefish-ril \
+    libcuttlefish-ril-2 \
     libcuttlefish-rild
 
 PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.hardware.faketouch.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.faketouch.xml \
     frameworks/native/data/etc/android.hardware.telephony.gsm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.gsm.xml
 
+DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/phone/overlay
+
 # These flags are important for the GSI, but break auto
 # These are used by aosp_cf_x86_go_phone targets
 PRODUCT_ENFORCE_RRO_TARGETS := framework-res
diff --git a/shared/phone/device_vendor.mk b/shared/phone/device_vendor.mk
index 1c4d2d4..61f72c1 100644
--- a/shared/phone/device_vendor.mk
+++ b/shared/phone/device_vendor.mk
@@ -14,7 +14,8 @@
 # limitations under the License.
 #
 
-DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/config/manifest.xml
+PRODUCT_MANIFEST_FILES += device/google/cuttlefish/shared/config/product_manifest.xml
+SYSTEM_EXT_MANIFEST_FILES += device/google/cuttlefish/shared/config/system_ext_manifest.xml
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_vendor.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_vendor.mk)
@@ -25,12 +26,12 @@
 $(call inherit-product, frameworks/native/build/phone-xhdpi-2048-dalvik-heap.mk)
 $(call inherit-product, device/google/cuttlefish/shared/device.mk)
 
-PRODUCT_PROPERTY_OVERRIDES += \
+PRODUCT_VENDOR_PROPERTIES += \
     keyguard.no_require_sim=true \
     ro.cdma.home.operator.alpha=Android \
     ro.cdma.home.operator.numeric=302780 \
     ro.com.android.dataroaming=true \
-    vendor.rild.libpath=libcuttlefish-ril.so \
+    ro.telephony.default_network=9 \
 
 # TODO: not existing anymore?
 PRODUCT_PACKAGES += \
@@ -38,8 +39,16 @@
     PhoneService \
 
 PRODUCT_PACKAGES += \
-    libcuttlefish-ril \
+    libcuttlefish-ril-2 \
     libcuttlefish-rild
 
 PRODUCT_COPY_FILES += \
-    frameworks/native/data/etc/android.hardware.telephony.gsm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.gsm.xml
+    frameworks/native/data/etc/android.hardware.biometrics.face.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.biometrics.face.xml \
+    frameworks/native/data/etc/android.hardware.faketouch.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.faketouch.xml \
+    frameworks/native/data/etc/android.hardware.fingerprint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.fingerprint.xml \
+    frameworks/native/data/etc/android.hardware.telephony.gsm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.gsm.xml \
+    frameworks/native/data/etc/android.hardware.telephony.ims.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.ims.xml
+
+DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/phone/overlay
+
+TARGET_BOARD_INFO_FILE ?= device/google/cuttlefish/shared/phone/android-info.txt
diff --git a/shared/phone/overlay/frameworks/base/core/res/res/values/config.xml b/shared/phone/overlay/frameworks/base/core/res/res/values/config.xml
new file mode 100644
index 0000000..c1b0d3e
--- /dev/null
+++ b/shared/phone/overlay/frameworks/base/core/res/res/values/config.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="networkAttributes" translatable="false">
+    <item>"mobile,0,0,0,-1,true"</item>
+    <item>"wifi,1,1,1,-1,true"</item>
+    <item>"mobile_mms,2,0,2,60000,true"</item>
+    <item>"mobile_hipri,5,0,3,60000,true"</item>
+    <item>"bluetooth,7,7,2,-1,true"</item>
+  </string-array>
+  <string-array name="radioAttributes" translatable="false">
+    <item>"0,1"</item>
+    <item>"1,1"</item>
+    <item>"4,1"</item>
+    <item>"7,1"</item>
+    <item>"11,1"</item>
+  </string-array>
+  <string-array name="config_tether_wifi_regexs" translatable="false">
+    <item>"wlan0"</item>
+  </string-array>
+  <string-array name="config_tether_apndata" translatable="false">
+    <item>Android,android,,,,,,,,311,740,,default,dun,ims</item>
+  </string-array>
+  <bool name="config_bluetooth_address_validation" translatable="false">true</bool>
+  <bool name="config_sms_capable" translatable="false">true</bool>
+  <string name="default_sms_application" translatable="false">com.android.mms</string>
+  <bool name="config_showNavigationBar" translatable="false">true</bool>
+  <dimen name="config_viewConfigurationTouchSlop" translatable="false">12dp</dimen>
+  <integer name="config_mobile_mtu" translatable="false">1460</integer>
+  <!--  Whether Multiuser UI should be shown -->
+  <bool name="config_enableMultiUserUI" translatable="false">true</bool>
+  <!--  Maximum number of supported users -->
+  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
+  <!--  Support mic and camera muting -->
+  <bool name="config_supportsMicToggle">true</bool>
+  <bool name="config_supportsCamToggle">true</bool>
+
+  <string name="config_mms_user_agent" translatable="false">CuttlefishNexus</string>
+  <string name="config_mms_user_agent_profile_url" translatable="false">http://gsm.lge.com/html/gsm/Nexus5-M3.xml</string>
+  <string name="config_wlan_data_service_package" translatable="false">com.android.ims</string>
+  <string name="config_wlan_network_service_package" translatable="false">com.android.ims</string>
+  <!-- Restricting eth2 -->
+  <string-array translatable="false" name="config_ethernet_interfaces">
+    <item>eth2;11,12,14;;</item>
+  </string-array>
+
+  <!-- List of biometric sensors on the device, in decreasing strength. Consumed by AuthService
+  when registering authenticators with BiometricService. Format must be ID:Modality:Strength,
+  where: IDs are unique per device, Modality as defined in BiometricAuthenticator.java,
+  and Strength as defined in Authenticators.java -->
+  <string-array name="config_biometric_sensors" translatable="false" >
+    <item>2:2:255</item> <!-- ID2:Fingerprint(HIDL):Weak -->
+    <item>3:8:255</item> <!-- ID3:Face(HIDL):Weak -->
+  </string-array>
+</resources>
diff --git a/shared/sepolicy/OWNERS b/shared/sepolicy/OWNERS
index 854d2e9..2975ddf 100644
--- a/shared/sepolicy/OWNERS
+++ b/shared/sepolicy/OWNERS
@@ -9,5 +9,4 @@
 nnk@google.com
 smoreland@google.com
 sspatil@google.com
-tomcherry@google.com
 trong@google.com
diff --git a/shared/sepolicy/product/private/file_contexts b/shared/sepolicy/product/private/file_contexts
index f0255a0..0b92144 100644
--- a/shared/sepolicy/product/private/file_contexts
+++ b/shared/sepolicy/product/private/file_contexts
@@ -1,5 +1,4 @@
 #############################
 # Product files
 #
-/product/bin/suspend_blocker     u:object_r:suspend_blocker_exec:s0
 /product/bin/tombstone_transmit  u:object_r:tombstone_transmit_exec:s0
diff --git a/shared/sepolicy/product/private/suspend_blocker.te b/shared/sepolicy/product/private/suspend_blocker.te
deleted file mode 100644
index 41c72b9..0000000
--- a/shared/sepolicy/product/private/suspend_blocker.te
+++ /dev/null
@@ -1,6 +0,0 @@
-type suspend_blocker, domain, coredomain;
-type suspend_blocker_exec, exec_type, file_type;
-
-init_daemon_domain(suspend_blocker);
-
-wakelock_use(suspend_blocker);
diff --git a/shared/sepolicy/product/private/tombstone_transmit.te b/shared/sepolicy/product/private/tombstone_transmit.te
index a17ed10..289be52 100644
--- a/shared/sepolicy/product/private/tombstone_transmit.te
+++ b/shared/sepolicy/product/private/tombstone_transmit.te
@@ -1,9 +1,9 @@
 type tombstone_transmit, domain, coredomain;
-type tombstone_transmit_exec, exec_type, file_type;
+type tombstone_transmit_exec, exec_type, system_file_type, file_type;
 
 init_daemon_domain(tombstone_transmit);
 
-type vsock_tombstone_port_prop, property_type;
+product_internal_prop(vsock_tombstone_port_prop)
 get_prop(tombstone_transmit, vsock_tombstone_port_prop)
 
 allow tombstone_transmit self:capability net_admin;
diff --git a/shared/sepolicy/system_ext/private/con_monitor.te b/shared/sepolicy/system_ext/private/con_monitor.te
index d638ac1..c708b7a 100644
--- a/shared/sepolicy/system_ext/private/con_monitor.te
+++ b/shared/sepolicy/system_ext/private/con_monitor.te
@@ -1,10 +1,9 @@
 # ConnectivityMonitor app
-type con_monitor_app, domain;
+type con_monitor_app, domain, coredomain;
 
 app_domain(con_monitor_app)
 
 set_prop(con_monitor_app, radio_prop)
-set_prop(con_monitor_app, vendor_radio_prop)
 userdebug_or_eng(`set_prop(con_monitor_app, dumpstate_options_prop)')
 allow con_monitor_app app_api_service:service_manager find;
 allow con_monitor_app radio_vendor_data_file:dir rw_dir_perms;
diff --git a/shared/sepolicy/system_ext/private/flipendo.te b/shared/sepolicy/system_ext/private/flipendo.te
new file mode 100644
index 0000000..bdf57dc
--- /dev/null
+++ b/shared/sepolicy/system_ext/private/flipendo.te
@@ -0,0 +1 @@
+gpu_access(flipendo)
diff --git a/shared/sepolicy/system_ext/private/mediatranscoding.te b/shared/sepolicy/system_ext/private/mediatranscoding.te
new file mode 100644
index 0000000..47f6d8e
--- /dev/null
+++ b/shared/sepolicy/system_ext/private/mediatranscoding.te
@@ -0,0 +1,2 @@
+# Allow mediatranscoding service to access the GPU
+gpu_access(mediatranscoding)
diff --git a/shared/sepolicy/system_ext/private/property.te b/shared/sepolicy/system_ext/private/property.te
index ffe5680..c7cab20 100644
--- a/shared/sepolicy/system_ext/private/property.te
+++ b/shared/sepolicy/system_ext/private/property.te
@@ -1,4 +1,4 @@
 # Vendor aware available type
-type vendor_aware_available_prop, property_type;
+vendor_restricted_prop(vendor_aware_available_prop)
 
-type vendor_radio_prop, property_type;
+vendor_restricted_prop(vendor_radio_prop)
diff --git a/shared/sepolicy/system_ext/private/property_contexts b/shared/sepolicy/system_ext/private/property_contexts
index ba4a683..13c17c3 100644
--- a/shared/sepolicy/system_ext/private/property_contexts
+++ b/shared/sepolicy/system_ext/private/property_contexts
@@ -5,7 +5,5 @@
 persist.vendor.radio.VT_HYBRID_ENABLE           u:object_r:vendor_radio_prop:s0
 persist.vendor.radio.videopause.mode            u:object_r:vendor_radio_prop:s0
 persist.vendor.radio.smlog_switch               u:object_r:vendor_radio_prop:s0
-persist.radio.poweranomaly.start                u:object_r:vendor_radio_prop:s0
-persist.radio.lowpowermonitor.start             u:object_r:vendor_radio_prop:s0
 ro.vendor.radio.log_loc                         u:object_r:vendor_radio_prop:s0
 ro.vendor.radio.log_prefix                      u:object_r:vendor_radio_prop:s0
diff --git a/shared/sepolicy/system_ext/private/sample_tuner_tis_app.te b/shared/sepolicy/system_ext/private/sample_tuner_tis_app.te
new file mode 100644
index 0000000..60f5e69
--- /dev/null
+++ b/shared/sepolicy/system_ext/private/sample_tuner_tis_app.te
@@ -0,0 +1,7 @@
+# Sample Tuner TIS app
+type sample_tuner_tis_app, domain;
+
+app_domain(sample_tuner_tis_app)
+
+allow sample_tuner_tis_app app_api_service:service_manager find;
+hal_client_domain(sample_tuner_tis_app, hal_tv_tuner);
diff --git a/shared/sepolicy/system_ext/private/seapp_contexts b/shared/sepolicy/system_ext/private/seapp_contexts
index 23c3681..1cd8665 100644
--- a/shared/sepolicy/system_ext/private/seapp_contexts
+++ b/shared/sepolicy/system_ext/private/seapp_contexts
@@ -4,3 +4,6 @@
 
 # Connectivity monitor
 user=_app isPrivApp=true seinfo=platform name=com.google.android.connectivitymonitor domain=con_monitor_app type=app_data_file levelFrom=all
+
+# Sample Tuner TIS
+user=system isPrivApp=true seinfo=platform name=com.android.tv.samples.sampletunertvinput domain=sample_tuner_tis_app type=app_data_file levelFrom=all
diff --git a/shared/sepolicy/vendor/adbd.te b/shared/sepolicy/vendor/adbd.te
index 48c3e0c..4ed653a 100644
--- a/shared/sepolicy/vendor/adbd.te
+++ b/shared/sepolicy/vendor/adbd.te
@@ -4,8 +4,6 @@
 allow adbd kernel:system module_request;
 
 recovery_only(`
-allow adbd tmpfs:dir w_dir_perms;
-allow adbd tmpfs:file create_file_perms;
 # TODO(b/130668487): Label the vsock sockets.
 allow su unlabeled:{ socket vsock_socket } rw_socket_perms_no_ioctl;
 ')
diff --git a/shared/sepolicy/vendor/bt_device.te b/shared/sepolicy/vendor/bt_device.te
new file mode 100644
index 0000000..5c88bfb
--- /dev/null
+++ b/shared/sepolicy/vendor/bt_device.te
@@ -0,0 +1 @@
+type bt_device, dev_type;
\ No newline at end of file
diff --git a/shared/sepolicy/vendor/bt_vhci_forwarder.te b/shared/sepolicy/vendor/bt_vhci_forwarder.te
new file mode 100644
index 0000000..2172696
--- /dev/null
+++ b/shared/sepolicy/vendor/bt_vhci_forwarder.te
@@ -0,0 +1,6 @@
+type bt_vhci_forwarder, domain;
+type bt_vhci_forwarder_exec, exec_type, vendor_file_type, file_type;
+
+init_daemon_domain(bt_vhci_forwarder)
+
+allow bt_vhci_forwarder bt_device:chr_file { open read write ioctl};
diff --git a/shared/sepolicy/vendor/bug_map b/shared/sepolicy/vendor/bug_map
index e8f546e..57cbf3c 100644
--- a/shared/sepolicy/vendor/bug_map
+++ b/shared/sepolicy/vendor/bug_map
@@ -1,7 +1,6 @@
 init system_lib_file dir b/133444385
 init system_lib_file file b/133444385
-logpersist logpersist capability b/132911257
-logpersist device file b/143108875
 migrate_legacy_obb_data dalvikcache_data_file file b/152338071
-shell adbd vsock_socket b/131904985
 system_server system_server process b/65201432
+gmscore_app hal_camera_prop file b/156287758
+priv_app radio_vendor_data_file dir b/188833462
diff --git a/shared/sepolicy/vendor/cameraserver.te b/shared/sepolicy/vendor/cameraserver.te
index 94146e1..7bc3fbf 100644
--- a/shared/sepolicy/vendor/cameraserver.te
+++ b/shared/sepolicy/vendor/cameraserver.te
@@ -1,4 +1 @@
-# Read GCE initial metadata file
-allow cameraserver initial_metadata_file:file r_file_perms;
-
 gpu_access(cameraserver)
diff --git a/shared/sepolicy/vendor/crash_dump.te b/shared/sepolicy/vendor/crash_dump.te
new file mode 100644
index 0000000..9242e77
--- /dev/null
+++ b/shared/sepolicy/vendor/crash_dump.te
@@ -0,0 +1 @@
+dontaudit crash_dump gpu_device:dir *;
diff --git a/shared/sepolicy/vendor/cuttlefish_sensor_injection.te b/shared/sepolicy/vendor/cuttlefish_sensor_injection.te
new file mode 100644
index 0000000..9e7aca5
--- /dev/null
+++ b/shared/sepolicy/vendor/cuttlefish_sensor_injection.te
@@ -0,0 +1,15 @@
+type cuttlefish_sensor_injection, domain;
+type cuttlefish_sensor_injection_exec, exec_type, vendor_file_type, file_type;
+
+# Switch to cuttlefish_sensor_injection domain when executing from shell.
+domain_auto_trans(shell, cuttlefish_sensor_injection_exec, cuttlefish_sensor_injection)
+allow cuttlefish_sensor_injection shell:fd use;
+
+# Allow cuttlefish_sensor_injection to communicate over adb connection.
+allow cuttlefish_sensor_injection adbd:fd use;
+allow cuttlefish_sensor_injection adbd:unix_stream_socket { read write };
+# Needed to run the binary directly via adb socket.
+allow cuttlefish_sensor_injection devpts:chr_file { read write };
+
+# Grant cuttlefish_sensor_injection access to the ISensors HAL.
+hal_client_domain(cuttlefish_sensor_injection, hal_sensors)
diff --git a/shared/sepolicy/vendor/device.te b/shared/sepolicy/vendor/device.te
index e63eddf..b698e35 100644
--- a/shared/sepolicy/vendor/device.te
+++ b/shared/sepolicy/vendor/device.te
@@ -1,3 +1,2 @@
 # Device types
 type ab_block_device, dev_type;
-type virtual_serial_device, dev_type;
diff --git a/shared/sepolicy/vendor/dumpstate.te b/shared/sepolicy/vendor/dumpstate.te
index 34caf72..6233ca1 100644
--- a/shared/sepolicy/vendor/dumpstate.te
+++ b/shared/sepolicy/vendor/dumpstate.te
@@ -1 +1,5 @@
 allow dumpstate hal_neuralnetworks_sample:process signal;
+
+allow dumpstate system_data_file:dir w_dir_perms;
+
+allow dumpstate gpu_device:dir search;
\ No newline at end of file
diff --git a/shared/sepolicy/vendor/file.te b/shared/sepolicy/vendor/file.te
index 131c275..53c4628 100644
--- a/shared/sepolicy/vendor/file.te
+++ b/shared/sepolicy/vendor/file.te
@@ -1,5 +1,4 @@
 # File types
-type initial_metadata_file, file_type;
 type sensors_hal_socket, file_type;
 type tombstone_snapshot_file, file_type;
 type var_run_system_file, file_type;
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index 13ab517..aeffec1 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -2,47 +2,36 @@
 # Devices
 #
 
-# crosvm (x86) block devices
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/misc u:object_r:misc_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/boot_[ab] u:object_r:boot_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/vendor_boot_[ab] u:object_r:boot_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/verity_[ab] u:object_r:ab_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/verity_system_[ab] u:object_r:ab_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/super u:object_r:super_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/userdata u:object_r:userdata_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/cache u:object_r:cache_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:01\.0/by-name/metadata u:object_r:metadata_block_device:s0
-# crosvm (arm64) block devices
-/dev/block/platform/10000.pci/by-name/misc u:object_r:misc_block_device:s0
-/dev/block/platform/10000.pci/by-name/boot_[ab] u:object_r:boot_block_device:s0
-/dev/block/platform/10000.pci/by-name/vendor_boot_[ab] u:object_r:boot_block_device:s0
-/dev/block/platform/10000.pci/by-name/verity_[ab] u:object_r:ab_block_device:s0
-/dev/block/platform/10000.pci/by-name/verity_system_[ab] u:object_r:ab_block_device:s0
-/dev/block/platform/10000.pci/by-name/super u:object_r:super_block_device:s0
-/dev/block/platform/10000.pci/by-name/userdata u:object_r:userdata_block_device:s0
-/dev/block/platform/10000.pci/by-name/cache u:object_r:cache_block_device:s0
-/dev/block/platform/10000.pci/by-name/metadata u:object_r:metadata_block_device:s0
-# qemu block devices
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/misc u:object_r:misc_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/boot_[ab] u:object_r:boot_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/vendor_boot_[ab] u:object_r:boot_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/verity_[ab] u:object_r:ab_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/verity_system_[ab] u:object_r:ab_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/super u:object_r:super_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/userdata u:object_r:userdata_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/cache u:object_r:cache_block_device:s0
-/dev/block/pci/pci0000:00/0000:00:03\.0/by-name/metadata u:object_r:metadata_block_device:s0
+/dev/block/by-name/misc u:object_r:misc_block_device:s0
+/dev/block/by-name/boot_[ab] u:object_r:boot_block_device:s0
+/dev/block/by-name/vendor_boot_[ab] u:object_r:boot_block_device:s0
+/dev/block/by-name/vbmeta_[ab] u:object_r:ab_block_device:s0
+/dev/block/by-name/vbmeta_system_[ab] u:object_r:ab_block_device:s0
+/dev/block/by-name/super u:object_r:super_block_device:s0
+/dev/block/by-name/userdata u:object_r:userdata_block_device:s0
+/dev/block/by-name/metadata u:object_r:metadata_block_device:s0
+
+/dev/block/by-name/frp  u:object_r:frp_block_device:s0
 
 /dev/block/pmem0  u:object_r:rebootescrow_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
 /dev/dri/renderD128  u:object_r:gpu_device:s0
-/dev/vport[0-9]p[0-9]*  u:object_r:virtual_serial_device:s0
+/dev/hvc0  u:object_r:serial_device:s0
+/dev/hvc1  u:object_r:serial_device:s0
+/dev/hvc2  u:object_r:serial_device:s0
+/dev/hvc3  u:object_r:keymaster_device:s0
+/dev/hvc4  u:object_r:gatekeeper_device:s0
+/dev/hvc5  u:object_r:bt_device:s0
+
+/dev/vhci  u:object_r:bt_device:s0
+
+# ARM serial console device
+/dev/ttyAMA[0-9]*  u:object_r:serial_device:s0
 
 #############################
 # Root files
-/initial\.metadata  u:object_r:initial_metadata_file:s0
 /ts_snap\.txt  u:object_r:tombstone_snapshot_file:s0
 
 #############################
@@ -54,35 +43,56 @@
 /var/run/system(/.*)?  u:object_r:var_run_system_file:s0
 
 #############################
+# sys files
+# x86
+/sys/devices/pci0000:00/0000:00:[0-9a-fA-F]{2}\.0/virtio[0-9]+/net(/.*)? u:object_r:sysfs_net:s0
+# qemu (x86)
+/sys/devices/platform/10000.pci/pci0000:00/0000:00:[0-9a-fA-F]{2}\.0/virtio[0-9]+/net(/.*)? u:object_r:sysfs_net:s0
+# qemu (aarch64)
+/sys/devices/platform/4010000000.pcie/pci0000:00/0000:00:[0-9a-fA-F]{2}.0/virtio[0-9]+/net u:object_r:sysfs_net:s0
+# qemu (arm)
+/sys/devices/platform/3f000000.pcie/pci0000:00/0000:00:[0-9a-fA-F]{2}.0/virtio[0-9]+/net u:object_r:sysfs_net:s0
+
+#############################
 # Vendor files
 #
+/vendor/bin/cuttlefish_sensor_injection   u:object_r:cuttlefish_sensor_injection_exec:s0
 /vendor/bin/socket_vsock_proxy  u:object_r:socket_vsock_proxy_exec:s0
-/vendor/bin/vsock_logcat  u:object_r:vsock_logcat_exec:s0
 /vendor/bin/vsoc_input_service  u:object_r:vsoc_input_service_exec:s0
-/vendor/bin/vport_trigger  u:object_r:vport_trigger_exec:s0
 /vendor/bin/rename_netiface  u:object_r:rename_netiface_exec:s0
+/vendor/bin/suspend_blocker  u:object_r:suspend_blocker_exec:s0
 /vendor/bin/hw/libcuttlefish-rild  u:object_r:libcuttlefish_rild_exec:s0
-/vendor/bin/hw/android\.hardware\.camera\.provider@2\.6-service-google u:object_r:hal_camera_default_exec:s0
-/vendor/bin/hw/android\.hardware\.camera\.provider@2\.6-service-google-lazy u:object_r:hal_camera_default_exec:s0
+/vendor/bin/hw/android\.hardware\.camera\.provider@2\.7-service-google u:object_r:hal_camera_default_exec:s0
+/vendor/bin/hw/android\.hardware\.camera\.provider@2\.7-service-google-lazy u:object_r:hal_camera_default_exec:s0
 /vendor/bin/hw/android\.hardware\.power\.stats@1\.0-service\.mock  u:object_r:hal_power_stats_default_exec:s0
+/vendor/bin/hw/android\.hardware\.bluetooth@1\.1-service\.remote  u:object_r:hal_bluetooth_remote_exec:s0
 /vendor/bin/hw/android\.hardware\.bluetooth@1\.1-service\.sim  u:object_r:hal_bluetooth_sim_exec:s0
-/vendor/bin/hw/android\.hardware\.contexthub@1\.1-service\.mock  u:object_r:hal_contexthub_default_exec:s0
+/vendor/bin/hw/android\.hardware\.contexthub@1\.2-service\.mock  u:object_r:hal_contexthub_default_exec:s0
 /vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service\.clearkey  u:object_r:hal_drm_clearkey_exec:s0
 /vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service-lazy\.clearkey  u:object_r:hal_drm_clearkey_exec:s0
 /vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service\.widevine  u:object_r:hal_drm_widevine_exec:s0
 /vendor/bin/hw/android\.hardware\.drm@[0-9]+\.[0-9]+-service-lazy\.widevine  u:object_r:hal_drm_widevine_exec:s0
 /vendor/bin/hw/android\.hardware\.graphics\.allocator@4\.0-service\.minigbm   u:object_r:hal_graphics_allocator_default_exec:s0
 /vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service\.software  u:object_r:hal_gatekeeper_default_exec:s0
-/vendor/bin/hw/android\.hardware\.health\.storage@1\.0-service\.cuttlefish u:object_r:hal_health_storage_default_exec:s0
+/vendor/bin/hw/android\.hardware\.health\.storage-service\.cuttlefish u:object_r:hal_health_storage_default_exec:s0
 /vendor/bin/hw/android\.hardware\.lights-service\.example u:object_r:hal_light_default_exec:s0
 /vendor/bin/hw/android\.hardware\.neuralnetworks@1\.3-service-sample-.*   u:object_r:hal_neuralnetworks_sample_exec:s0
+/vendor/bin/hw/android\.hardware\.neuralnetworks-shim-service-sample   u:object_r:hal_neuralnetworks_sample_exec:s0
+/vendor/bin/hw/android\.hardware\.neuralnetworks-service-sample-.*   u:object_r:hal_neuralnetworks_sample_exec:s0
 /vendor/bin/hw/android\.hardware\.vibrator@1\.x-service\.example u:object_r:hal_vibrator_default_exec:s0
-/vendor/bin/ip_link_add  u:object_r:ip_link_add_exec:s0
 /vendor/bin/setup_wifi  u:object_r:setup_wifi_exec:s0
+/vendor/bin/bt_vhci_forwarder  u:object_r:bt_vhci_forwarder_exec:s0
+
 /vendor/bin/hw/android\.hardware\.sensors@2\.1-service\.mock  u:object_r:hal_sensors_default_exec:s0
 /vendor/bin/hw/android\.hardware\.input\.classifier@1\.0-service.default  u:object_r:hal_input_classifier_default_exec:s0
 /vendor/bin/hw/android\.hardware\.thermal@2\.0-service\.mock  u:object_r:hal_thermal_default_exec:s0
+/vendor/bin/hw/android\.hardware\.security\.keymint-service\.remote  u:object_r:hal_keymint_remote_exec:s0
+/vendor/bin/hw/android\.hardware\.keymaster@4\.1-service.remote  u:object_r:hal_keymaster_remote_exec:s0
+/vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service.remote  u:object_r:hal_gatekeeper_remote_exec:s0
+/vendor/bin/hw/android\.hardware\.oemlock-service.example u:object_r:hal_oemlock_default_exec:s0
+/vendor/bin/hw/android\.hardware\.weaver-service.example u:object_r:hal_weaver_default_exec:s0
 /vendor/bin/hw/android\.hardware\.authsecret@1\.0-service  u:object_r:hal_authsecret_default_exec:s0
+/vendor/bin/hw/android\.hardware\.authsecret-service.example u:object_r:hal_authsecret_default_exec:s0
 /vendor/bin/hw/android\.hardware\.rebootescrow-service\.default  u:object_r:hal_rebootescrow_default_exec:s0
 /vendor/bin/init\.insmod\.sh  u:object_r:init_insmod_sh_exec:s0
 
@@ -107,3 +117,7 @@
 /vendor/lib(64)?/libGLESv2_enc\.so       u:object_r:same_process_hal_file:s0
 /vendor/lib(64)?/libvulkan_enc\.so       u:object_r:same_process_hal_file:s0
 /vendor/lib(64)?/libandroidemu\.so       u:object_r:same_process_hal_file:s0
+/vendor/lib(64)?/libEGL_angle\.so          u:object_r:same_process_hal_file:s0
+/vendor/lib(64)?/libGLESv1_CM_angle\.so    u:object_r:same_process_hal_file:s0
+/vendor/lib(64)?/libGLESv2_angle\.so       u:object_r:same_process_hal_file:s0
+/vendor/lib(64)?/libfeature_support_angle\.so       u:object_r:same_process_hal_file:s0
diff --git a/shared/sepolicy/vendor/genfs_contexts b/shared/sepolicy/vendor/genfs_contexts
index 14b8131..22cb59f 100644
--- a/shared/sepolicy/vendor/genfs_contexts
+++ b/shared/sepolicy/vendor/genfs_contexts
@@ -1,54 +1,80 @@
+dnl Run "m4 genfs_contexts" to test
+dnl # $1 = pci prefix
+dnl # $2 = pci ID start (hex)
+dnl # $3 = virtio ID start (decimal)
+pushdef(`cf_pci_block_device', `dnl
+genfscon sysfs $1/0000:00:eval($2 + 0, 16, 2).0/virtio`'eval($3 + 0)`'/block u:object_r:sysfs_devices_block:s0 # vda
+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
+dnl')dnl
+dnl
+dnl # $1 = pci prefix
+dnl # $2 = pci ID start (hex)
+pushdef(`cf_pci_gpu_device', `dnl
+genfscon sysfs $1/0000:00:eval($2, 16, 2).0/device u:object_r:sysfs_gpu:s0
+genfscon sysfs $1/0000:00:eval($2, 16, 2).0/subsystem_device u:object_r:sysfs_gpu:s0
+genfscon sysfs $1/0000:00:eval($2, 16, 2).0/subsystem_vendor u:object_r:sysfs_gpu:s0
+genfscon sysfs $1/0000:00:eval($2, 16, 2).0/uevent u:object_r:sysfs_gpu:s0
+genfscon sysfs $1/0000:00:eval($2, 16, 2).0/vendor u:object_r:sysfs_gpu:s0
+dnl')dnl
+dnl
+dnl # $1 = rtc prefix
+dnl # $2 = rtc number (decimal)
+dnl # $3 = rtc wakeup offset (decimal)
+pushdef(`cf_rtc_wakeup_alarmtimer', `dnl
+genfscon sysfs $1/wakeup/wakeup$3 u:object_r:sysfs_wakeup:s0
+genfscon sysfs $1/rtc/rtc$2/wakeup`'eval($3 + 1)`' u:object_r:sysfs_wakeup:s0 # <= 5.5
+genfscon sysfs $1/rtc/rtc$2/alarmtimer.0.auto/wakeup/wakeup`'eval($3 + 1)`' u:object_r:sysfs_wakeup:s0 # >5.5
+dnl')dnl
+dnl
 # crosvm (x86)
-genfscon sysfs /devices/pci0000:00/0000:00:08.0/virtio7/net u:object_r:sysfs_net:s0 # buried_eth0 & wlan0
-genfscon sysfs /devices/pci0000:00/0000:00:09.0/virtio8/net u:object_r:sysfs_net:s0 # rmnet0
-genfscon sysfs /devices/pci0000:00/0000:00:0b.0/device u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/pci0000:00/0000:00:0b.0/subsystem_device u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/pci0000:00/0000:00:0b.0/subsystem_vendor u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/pci0000:00/0000:00:0b.0/uevent u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/pci0000:00/0000:00:0b.0/vendor u:object_r:sysfs_gpu:s0
+cf_pci_block_device(/devices/pci0000:00, 0x6, 5)
+cf_pci_gpu_device(/devices/pci0000:00, 0x11)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
-## x86 rtc_cmos on crosvm does not currently expose rtcN/hctosys
+genfscon sysfs /devices/platform/rtc_cmos/rtc u:object_r:sysfs_rtc:s0
 ## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
-genfscon sysfs /devices/platform/rtc_cmos/wakeup/wakeup0 u:object_r:sysfs_wakeup:s0
-genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup1 u:object_r:sysfs_wakeup:s0
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/wakeup2 u:object_r:sysfs_wakeup:s0 # <= 5.5
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/alarmtimer.0.auto/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0 # >5.5
+cf_rtc_wakeup_alarmtimer(/devices/platform/rtc_cmos, 0, 0)
+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
 
 # crosvm (arm64)
-genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:08.0/virtio7/net u:object_r:sysfs_net:s0 # buried_eth0 & wlan0
-genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:09.0/virtio8/net u:object_r:sysfs_net:s0 # rmnet0
-genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0b.0/device u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0b.0/subsystem_device u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0b.0/subsystem_vendor u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0b.0/uevent u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0b.0/vendor u:object_r:sysfs_gpu:s0
+cf_pci_block_device(/devices/platform/10000.pci, 0x6, 4)
+cf_pci_gpu_device(/devices/platform/10000.pci/pci0000:00, 0x11)
 ## 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
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc2/wakeup1 u:object_r:sysfs_wakeup:s0 # <= 5.5
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc2/alarmtimer.0.auto/wakeup/wakeup1 u:object_r:sysfs_wakeup:s0 # >5.5
+cf_rtc_wakeup_alarmtimer(/devices/platform/rtc-test.1, 2, 0)
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
 
 # qemu (x86)
-genfscon sysfs /devices/pci0000:00/0000:00:05.0/virtio3/net u:object_r:sysfs_net:s0 # buried_eth0 & wlan0
-genfscon sysfs /devices/pci0000:00/0000:00:06.0/virtio4/net u:object_r:sysfs_net:s0 # rmnet0
-# FIXME: Add sysfs_gpu labels for qemu
+cf_pci_block_device(/devices/pci0000:00, 0x7, 5)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
-genfscon sysfs /devices/pnp0/00:00/rtc u:object_r:sysfs_rtc:s0
+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]'
-genfscon sysfs /devices/pnp0/00:00/wakeup/wakeup13 u:object_r:sysfs_wakeup:s0
-genfscon sysfs /devices/pnp0/00:00/rtc/rtc0/wakeup14 u:object_r:sysfs_wakeup:s0 # <= 5.5
-genfscon sysfs /devices/pnp0/00:00/rtc/rtc0/alarmtimer.0.auto/wakeup/wakeup14 u:object_r:sysfs_wakeup:s0 # >5.5
-genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup15 u:object_r:sysfs_wakeup:s0
-genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup16 u:object_r:sysfs_wakeup:s0
+cf_rtc_wakeup_alarmtimer(/devices/pnp0/00:04, 0, 19)
+genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup21 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup22 u:object_r:sysfs_wakeup:s0
 
-# common to qemu (x86) and crosvm (arm64)
-genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup0 u:object_r:sysfs_wakeup:s0
-genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
+# qemu (arm64)
+cf_pci_block_device(/devices/platform/4010000000.pcie/pci0000:00, 0x6, 4)
+cf_pci_gpu_device(/devices/platform/4010000000.pcie/pci0000:00, 0x10)
+## 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, 0x6, 4)
+cf_pci_gpu_device(/devices/platform/3f000000.pcie/pci0000:00, 0xf)
 
 # common on all platforms / vm managers
 genfscon sysfs /devices/platform/rtc-test.0/rtc u:object_r:sysfs_rtc:s0
 genfscon sysfs /devices/platform/rtc-test.1/rtc u:object_r:sysfs_rtc:s0
 genfscon sysfs /devices/platform/rtc-test.2/rtc u:object_r:sysfs_rtc:s0
 genfscon sysfs /bus/iio/devices u:object_r:sysfs_iio_devices:s0
+dnl
+popdef(`cf_pci_block_device')dnl
+popdef(`cf_pci_gpu_device')dnl
+popdef(`cf_rtc_wakeup_alarmtimer')dnl
diff --git a/shared/sepolicy/vendor/google/bug_map b/shared/sepolicy/vendor/google/bug_map
index 26c5581..0521b52 100644
--- a/shared/sepolicy/vendor/google/bug_map
+++ b/shared/sepolicy/vendor/google/bug_map
@@ -1 +1,2 @@
+untrusted_app selinuxfs file b/175910397
 zygote ramdump_app process b/139558100
diff --git a/shared/sepolicy/vendor/google/gmscore_app.te b/shared/sepolicy/vendor/google/gmscore_app.te
index a29e3c4..44cd1a7 100644
--- a/shared/sepolicy/vendor/google/gmscore_app.te
+++ b/shared/sepolicy/vendor/google/gmscore_app.te
@@ -1,3 +1 @@
-get_prop(gmscore_app, hal_camera_prop)
-
 gpu_access(gmscore_app)
diff --git a/shared/sepolicy/vendor/google/hwservice.te b/shared/sepolicy/vendor/google/hwservice.te
index ca4766a..1c32f8f 100644
--- a/shared/sepolicy/vendor/google/hwservice.te
+++ b/shared/sepolicy/vendor/google/hwservice.te
@@ -1 +1 @@
-type hal_wlc_hwservice, hwservice_manager_type;
+type hal_wlc_hwservice, hwservice_manager_type, vendor_hwservice_type;
diff --git a/shared/sepolicy/vendor/google/mediaprovider.te b/shared/sepolicy/vendor/google/mediaprovider.te
new file mode 100644
index 0000000..515ef26
--- /dev/null
+++ b/shared/sepolicy/vendor/google/mediaprovider.te
@@ -0,0 +1 @@
+gpu_access(mediaprovider)
diff --git a/shared/sepolicy/vendor/google/traceur_app.te b/shared/sepolicy/vendor/google/traceur_app.te
new file mode 100644
index 0000000..ed1bead
--- /dev/null
+++ b/shared/sepolicy/vendor/google/traceur_app.te
@@ -0,0 +1 @@
+gpu_access(traceur_app)
diff --git a/shared/sepolicy/vendor/gpuservice.te b/shared/sepolicy/vendor/gpuservice.te
new file mode 100644
index 0000000..4deb99f
--- /dev/null
+++ b/shared/sepolicy/vendor/gpuservice.te
@@ -0,0 +1 @@
+allow gpuservice gpu_device:dir { search ioctl };
diff --git a/shared/sepolicy/vendor/hal_bluetooth_remote.te b/shared/sepolicy/vendor/hal_bluetooth_remote.te
new file mode 100644
index 0000000..459f891
--- /dev/null
+++ b/shared/sepolicy/vendor/hal_bluetooth_remote.te
@@ -0,0 +1,8 @@
+type hal_bluetooth_remote, domain;
+type hal_bluetooth_remote_exec, exec_type, vendor_file_type, file_type;
+
+hal_server_domain(hal_bluetooth_remote, hal_bluetooth)
+
+init_daemon_domain(hal_bluetooth_remote)
+
+allow hal_bluetooth_remote bt_device:chr_file { open read write ioctl};
\ No newline at end of file
diff --git a/shared/sepolicy/vendor/hal_bluetooth_sim.te b/shared/sepolicy/vendor/hal_bluetooth_sim.te
index 82bab59..d29b1a9 100644
--- a/shared/sepolicy/vendor/hal_bluetooth_sim.te
+++ b/shared/sepolicy/vendor/hal_bluetooth_sim.te
@@ -1,9 +1,9 @@
 type hal_bluetooth_sim, domain;
 type hal_bluetooth_sim_exec, exec_type, vendor_file_type, file_type;
-type hal_bluetooth_sim_prop, property_type;
+vendor_internal_prop(vendor_bt_rootcanal_prop)
 
 hal_server_domain(hal_bluetooth_sim, hal_bluetooth)
 
 init_daemon_domain(hal_bluetooth_sim)
 
-get_prop(hal_bluetooth_sim, hal_bluetooth_sim_prop)
+get_prop(hal_bluetooth_sim, vendor_bt_rootcanal_prop)
diff --git a/shared/sepolicy/vendor/hal_camera_default.te b/shared/sepolicy/vendor/hal_camera_default.te
index 2442d83..6bf571c 100644
--- a/shared/sepolicy/vendor/hal_camera_default.te
+++ b/shared/sepolicy/vendor/hal_camera_default.te
@@ -1,13 +1,12 @@
-type hal_camera_prop, property_type;
-
 vndbinder_use(hal_camera_default)
 
 hal_client_domain(hal_camera_default, hal_graphics_allocator)
 
-get_prop(hal_camera_default, hal_camera_prop)
-
 # For camera hal to talk with sensor service
 binder_call(hal_camera_default, sensor_service_server)
 binder_call(sensor_service_server, hal_camera_default)
 
+# Allow the Camera HAL to communicate with the thermal HAL.
+hal_client_domain(hal_camera_default, hal_thermal)
+
 gpu_access(hal_camera_default)
diff --git a/shared/sepolicy/vendor/hal_gatekeeper_remote.te b/shared/sepolicy/vendor/hal_gatekeeper_remote.te
new file mode 100644
index 0000000..db895dd
--- /dev/null
+++ b/shared/sepolicy/vendor/hal_gatekeeper_remote.te
@@ -0,0 +1,14 @@
+type hal_gatekeeper_remote, domain;
+hal_server_domain(hal_gatekeeper_remote, hal_gatekeeper)
+
+type hal_gatekeeper_remote_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_gatekeeper_remote)
+
+type gatekeeper_device, file_type;
+
+allow hal_gatekeeper_remote device:dir r_dir_perms;
+allow hal_gatekeeper_remote gatekeeper_device:chr_file rw_file_perms;
+
+# Write to kernel log (/dev/kmsg)
+allow hal_gatekeeper_remote kmsg_device:chr_file w_file_perms;
+allow hal_gatekeeper_remote kmsg_device:chr_file getattr;
diff --git a/shared/sepolicy/vendor/hal_graphics_allocator.te b/shared/sepolicy/vendor/hal_graphics_allocator.te
deleted file mode 100644
index 5975599..0000000
--- a/shared/sepolicy/vendor/hal_graphics_allocator.te
+++ /dev/null
@@ -1,5 +0,0 @@
-# TODO(b/64158954): Remove/update these	rules once gralloc impl	changes
-allow hal_graphics_allocator_client hal_graphics_allocator_default_tmpfs:file read;
-
-# Read GCE initial metadata file
-allow hal_graphics_allocator_server initial_metadata_file:file r_file_perms;
diff --git a/shared/sepolicy/vendor/hal_graphics_composer.te b/shared/sepolicy/vendor/hal_graphics_composer.te
index 6bba59d..4929038 100644
--- a/shared/sepolicy/vendor/hal_graphics_composer.te
+++ b/shared/sepolicy/vendor/hal_graphics_composer.te
@@ -1,8 +1,8 @@
-type vsock_frames_port_prop, property_type;
+vendor_restricted_prop(vendor_vsock_frames_port_prop)
 
 allow hal_graphics_composer_server hal_graphics_allocator_default_tmpfs:file read;
 allow hal_graphics_composer_server self:{ socket vsock_socket } create_socket_perms_no_ioctl;
 gpu_access(hal_graphics_composer_server)
 
-get_prop(hal_graphics_composer_server, vsock_frames_port_prop)
-get_prop(hal_graphics_composer_server, cuttlefish_config_server_port_prop)
+get_prop(hal_graphics_composer_server, vendor_vsock_frames_port_prop)
+get_prop(hal_graphics_composer_server, vendor_cuttlefish_config_server_port_prop)
diff --git a/shared/sepolicy/vendor/hal_graphics_composer_default.te b/shared/sepolicy/vendor/hal_graphics_composer_default.te
index c3a7cab..807ec73 100644
--- a/shared/sepolicy/vendor/hal_graphics_composer_default.te
+++ b/shared/sepolicy/vendor/hal_graphics_composer_default.te
@@ -2,4 +2,7 @@
 vndbinder_use(hal_graphics_composer_default)
 
 allow hal_graphics_composer_default self:netlink_kobject_uevent_socket { bind create read };
-get_prop(hal_graphics_composer_default, cf_graphics_config_prop)
+
+# Supress warnings for drm_hwcomposer trying to read some vendor.hwc.*
+# properties as Cuttlefish never configures these properties.
+dontaudit hal_graphics_composer_default default_prop:file read;
\ No newline at end of file
diff --git a/shared/sepolicy/vendor/hal_keymaster_remote.te b/shared/sepolicy/vendor/hal_keymaster_remote.te
new file mode 100644
index 0000000..f85da04
--- /dev/null
+++ b/shared/sepolicy/vendor/hal_keymaster_remote.te
@@ -0,0 +1,14 @@
+type hal_keymaster_remote, domain;
+hal_server_domain(hal_keymaster_remote, hal_keymaster)
+
+type hal_keymaster_remote_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_keymaster_remote)
+
+type keymaster_device, file_type;
+
+allow hal_keymaster_remote device:dir r_dir_perms;
+allow hal_keymaster_remote keymaster_device:chr_file rw_file_perms;
+
+# Write to kernel log (/dev/kmsg)
+allow hal_keymaster_remote kmsg_device:chr_file w_file_perms;
+allow hal_keymaster_remote kmsg_device:chr_file getattr;
diff --git a/shared/sepolicy/vendor/hal_keymint_remote.te b/shared/sepolicy/vendor/hal_keymint_remote.te
new file mode 100644
index 0000000..27f8291
--- /dev/null
+++ b/shared/sepolicy/vendor/hal_keymint_remote.te
@@ -0,0 +1,12 @@
+type hal_keymint_remote, domain;
+hal_server_domain(hal_keymint_remote, hal_keymint)
+
+type hal_keymint_remote_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_keymint_remote)
+
+allow hal_keymint_remote device:dir r_dir_perms;
+allow hal_keymint_remote keymaster_device:chr_file rw_file_perms;
+
+# Write to kernel log (/dev/kmsg)
+allow hal_keymint_remote kmsg_device:chr_file w_file_perms;
+allow hal_keymint_remote kmsg_device:chr_file getattr;
diff --git a/shared/sepolicy/vendor/init.te b/shared/sepolicy/vendor/init.te
index 26f7110..7f362ef 100644
--- a/shared/sepolicy/vendor/init.te
+++ b/shared/sepolicy/vendor/init.te
@@ -12,6 +12,18 @@
 allow init binfmt_miscfs:file w_file_perms;
 allow init proc:dir mounton;
 
+# init relabel vbmeta* symlinks
+allow init ab_block_device:lnk_file relabelto;
+
 # /mnt/sdcard -> /storage/self/primary symlink is deprecated. Ignore attempts to
 # create it. This denial is fixed in core policy in Android R aosp/943799.
 dontaudit init tmpfs:lnk_file create;
+
+# permit mount of virtiofs on /mnt/vendor/shared
+allow init mnt_vendor_file:dir mounton;
+
+allow init keymaster_device:chr_file rw_file_perms;
+allow init gatekeeper_device:chr_file rw_file_perms;
+allow init bt_device:chr_file rw_file_perms;
+
+allow init frp_block_device:blk_file setattr;
diff --git a/shared/sepolicy/vendor/ip_link_add.te b/shared/sepolicy/vendor/ip_link_add.te
deleted file mode 100644
index a1c13e2..0000000
--- a/shared/sepolicy/vendor/ip_link_add.te
+++ /dev/null
@@ -1,10 +0,0 @@
-type ip_link_add, domain;
-type ip_link_add_exec, exec_type, vendor_file_type, file_type;
-
-init_daemon_domain(ip_link_add)
-
-allow ip_link_add self:capability { net_admin net_raw sys_module };
-allow ip_link_add self:udp_socket { create ioctl };
-allow ip_link_add self:netlink_route_socket { bind create nlmsg_write read write };
-
-allow ip_link_add kernel:system module_request;
diff --git a/shared/sepolicy/vendor/kernel.te b/shared/sepolicy/vendor/kernel.te
deleted file mode 100644
index b4eec4b..0000000
--- a/shared/sepolicy/vendor/kernel.te
+++ /dev/null
@@ -1,19 +0,0 @@
-# kernel domain is used for all processes started before Android init installs SELinux policy.
-# Normally, no processes should be in this domain because clumping multiple processes into a single
-# SELinux domain overprivileges each of those processes.
-
-# TODO(b/65049764): Get rid of the hostapd instance started before Android init
-net_domain(kernel)
-allow kernel self:capability net_admin;
-allow kernel self:netlink_socket create_socket_perms_no_ioctl;
-allow kernel tmpfs:dir search;
-
-# TODO(b/65049764): Get rid of GCE proxy and similar daemons started before Android init
-# gce.meta.proxy and gce.ex.outer write to /dev/console which for some reason does not appear
-# labelled as console_device although it is labeled as such on the filesystem.
-allow kernel rootfs:chr_file write;
-
-# kdevtmpfs accesses devices before ueventd runs restorecon and relabels devices
-allow kernel device:chr_file { create setattr getattr unlink };
-allow kernel device:dir create_dir_perms;
-allow kernel self:capability mknod;
diff --git a/shared/sepolicy/vendor/libcuttlefish_rild.te b/shared/sepolicy/vendor/libcuttlefish_rild.te
index 49b7d50..8f3bbe7 100644
--- a/shared/sepolicy/vendor/libcuttlefish_rild.te
+++ b/shared/sepolicy/vendor/libcuttlefish_rild.te
@@ -8,6 +8,7 @@
 # Failing to create these sockets appears to be non-fatal
 net_domain(libcuttlefish_rild)
 
-get_prop(libcuttlefish_rild, cuttlefish_config_server_port_prop)
+get_prop(libcuttlefish_rild, vendor_cuttlefish_config_server_port_prop)
+get_prop(libcuttlefish_rild, vendor_modem_simulator_ports_prop)
 
 allow libcuttlefish_rild self:{ socket vsock_socket } create_socket_perms_no_ioctl;
diff --git a/shared/sepolicy/vendor/logpersist.te b/shared/sepolicy/vendor/logpersist.te
index 7152409..226cb00 100644
--- a/shared/sepolicy/vendor/logpersist.te
+++ b/shared/sepolicy/vendor/logpersist.te
@@ -1,8 +1,4 @@
 # Output to virtual serial console. Needed because seriallogging daemon
-# runs logcat and directs its output to vportXpY or cf_logcat_pipe under
-# the /dev filesystem.
+# runs logcat and directs its output to hvcX the /dev filesystem.
 allow logpersist device:dir r_dir_perms;
-allow logpersist device:fifo_file ra_file_perms;
-allow logpersist virtual_serial_device:chr_file ra_file_perms;
-
-allowxperm logpersist device:fifo_file ioctl F2FS_IOC_SET_PIN_FILE;
+allow logpersist serial_device:chr_file ra_file_perms;
diff --git a/shared/sepolicy/vendor/property.te b/shared/sepolicy/vendor/property.te
index 19e3896..a727365 100644
--- a/shared/sepolicy/vendor/property.te
+++ b/shared/sepolicy/vendor/property.te
@@ -1 +1,2 @@
-type cuttlefish_config_server_port_prop, property_type;
+vendor_restricted_prop(vendor_cuttlefish_config_server_port_prop)
+vendor_internal_prop(vendor_modem_simulator_ports_prop)
diff --git a/shared/sepolicy/vendor/property_contexts b/shared/sepolicy/vendor/property_contexts
index ab29527..ebbe271 100644
--- a/shared/sepolicy/vendor/property_contexts
+++ b/shared/sepolicy/vendor/property_contexts
@@ -1,27 +1,14 @@
-bt.rootcanal_mac_address  u:object_r:hal_bluetooth_sim_prop:s0
-bt.rootcanal_test_console  u:object_r:hal_bluetooth_sim_prop:s0
-qemu.sf.back_camera_caps  u:object_r:hal_camera_prop:s0
-qemu.sf.front_camera_caps  u:object_r:hal_camera_prop:s0
-qemu.sf.fake_camera  u:object_r:hal_camera_prop:s0
-ro.boot.cuttlefish_config_server_port  u:object_r:cuttlefish_config_server_port_prop:s0
-ro.boot.fstab_name u:object_r:cf_fstab_name_prop:s0 exact string
-ro.boot.hardware.egl u:object_r:cf_graphics_config_prop:s0 exact string
-ro.boot.hardware.gralloc u:object_r:cf_graphics_config_prop:s0 exact string
-ro.boot.hardware.hwcomposer u:object_r:cf_graphics_config_prop:s0 exact string
-ro.boot.hardware.vulkan u:object_r:cf_graphics_config_prop:s0 exact string
-ro.boot.lcd_density u:object_r:cf_graphics_config_prop:s0 exact int
-ro.boot.vsock_frames_port  u:object_r:vsock_frames_port_prop:s0
-ro.boot.vsock_keyboard_port  u:object_r:cuttlefish_vsock_keyboard_port:s0
-ro.boot.vsock_logcat_port  u:object_r:vsock_logcat_port_prop:s0
-ro.boot.vsock_touch_port  u:object_r:cuttlefish_vsock_touch_port:s0
-ro.boot.wifi_mac_address  u:object_r:cuttlefish_wifi_mac_address:s0
-ro.cdma.home.operator.alpha  u:object_r:vendor_init_radio_prop:s0
-ro.cdma.home.operator.numeric  u:object_r:vendor_init_radio_prop:s0
-sys.cf.ser.  u:object_r:sys_cf_ser_prop:s0
-vendor.ser.  u:object_r:vendor_ser_prop:s0
-vendor.vsock_logcat_status  u:object_r:vsock_logcat_status_prop:s0
-hwc.drm.device u:object_r:cf_graphics_config_prop:s0 exact string
-hwc.drm.exclude_non_hwfb_imports u:object_r:cf_graphics_config_prop:s0 exact int
-hwc.drm.primary_display_order u:object_r:cf_graphics_config_prop:s0 exact string
-hwc.drm.scale_with_gpu u:object_r:cf_graphics_config_prop:s0 exact int
-hwc.drm.use_overlay_planes u:object_r:cf_graphics_config_prop:s0 exact int
+ro.boot.cpuvulkan.version  u:object_r:vendor_graphics_config_prop:s0 exact int
+ro.boot.cuttlefish_config_server_port  u:object_r:vendor_cuttlefish_config_server_port_prop:s0
+ro.boot.hardware.egl u:object_r:vendor_graphics_config_prop:s0 exact string
+ro.boot.hardware.gralloc u:object_r:vendor_graphics_config_prop:s0 exact string
+ro.boot.hardware.hwcomposer u:object_r:vendor_graphics_config_prop:s0 exact string
+ro.boot.hardware.vulkan u:object_r:vendor_graphics_config_prop:s0 exact string
+ro.boot.lcd_density u:object_r:vendor_graphics_config_prop:s0 exact int
+ro.boot.vsock_frames_port  u:object_r:vendor_vsock_frames_port_prop:s0
+ro.boot.vsock_keyboard_port  u:object_r:vendor_vsock_keyboard_port:s0
+ro.boot.modem_simulator_ports  u:object_r:vendor_modem_simulator_ports_prop:s0
+ro.boot.vsock_touch_port  u:object_r:vendor_vsock_touch_port:s0
+ro.boot.wifi_mac_address  u:object_r:vendor_wifi_mac_address: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
diff --git a/shared/sepolicy/vendor/radio.te b/shared/sepolicy/vendor/radio.te
new file mode 100644
index 0000000..62b7582
--- /dev/null
+++ b/shared/sepolicy/vendor/radio.te
@@ -0,0 +1 @@
+gpu_access(radio)
diff --git a/shared/sepolicy/vendor/recovery.te b/shared/sepolicy/vendor/recovery.te
index b0e5157..dcb7100 100644
--- a/shared/sepolicy/vendor/recovery.te
+++ b/shared/sepolicy/vendor/recovery.te
@@ -3,10 +3,10 @@
 allow recovery graphics_device:chr_file rw_file_perms;
 
 # Allow sideload from file pushed to fake /sdcard
-allow recovery appdomain_tmpfs:file r_file_perms;
+allow recovery vfat:dir r_dir_perms;
+allow recovery vfat:file r_file_perms;
 
 # Seen during 'Wipe data/factory reset'
-allow recovery cache_block_device:blk_file rw_file_perms;
 allow recovery devpts:chr_file rw_file_perms;
 allow recovery kmsg_device:chr_file { getattr w_file_perms };
 # Note: fsetid checks are triggered when creating a file in a directory with
diff --git a/shared/sepolicy/vendor/seapp_contexts b/shared/sepolicy/vendor/seapp_contexts
index 820c416..f2a116f 100644
--- a/shared/sepolicy/vendor/seapp_contexts
+++ b/shared/sepolicy/vendor/seapp_contexts
@@ -1,2 +1,2 @@
 # GceService app
-user=_app isPrivApp=true seinfo=default name=com.android.google.gce.gceservice domain=gceservice type=app_data_file
+user=_app isPrivApp=true seinfo=default name=com.android.google.gce.gceservice domain=gceservice type=app_data_file levelFrom=all
diff --git a/shared/sepolicy/vendor/service_contexts b/shared/sepolicy/vendor/service_contexts
index 5a5ed00..d20d026 100644
--- a/shared/sepolicy/vendor/service_contexts
+++ b/shared/sepolicy/vendor/service_contexts
@@ -1,2 +1,9 @@
+android.hardware.neuralnetworks.IDevice/nnapi-sample_all u:object_r:hal_neuralnetworks_service:s0
+android.hardware.neuralnetworks.IDevice/nnapi-sample_float_fast u:object_r:hal_neuralnetworks_service:s0
+android.hardware.neuralnetworks.IDevice/nnapi-sample_float_slow u:object_r:hal_neuralnetworks_service:s0
+android.hardware.neuralnetworks.IDevice/nnapi-sample_minimal    u:object_r:hal_neuralnetworks_service:s0
+android.hardware.neuralnetworks.IDevice/nnapi-sample_quant    u:object_r:hal_neuralnetworks_service:s0
+android.hardware.neuralnetworks.IDevice/nnapi-sample_sl_shim  u:object_r:hal_neuralnetworks_service:s0
+
 # Binder service mappings
 gce                                       u:object_r:gce_service:s0
diff --git a/shared/sepolicy/vendor/setup_wifi.te b/shared/sepolicy/vendor/setup_wifi.te
index a6bd363..23a34eb 100644
--- a/shared/sepolicy/vendor/setup_wifi.te
+++ b/shared/sepolicy/vendor/setup_wifi.te
@@ -9,6 +9,6 @@
 
 allow setup_wifi kernel:system module_request;
 
-type cuttlefish_wifi_mac_address, property_type;
+vendor_internal_prop(vendor_wifi_mac_address)
 
-get_prop(setup_wifi, cuttlefish_wifi_mac_address)
+get_prop(setup_wifi, vendor_wifi_mac_address)
diff --git a/shared/sepolicy/vendor/shell.te b/shared/sepolicy/vendor/shell.te
index ea0ee61..cc26032 100644
--- a/shared/sepolicy/vendor/shell.te
+++ b/shared/sepolicy/vendor/shell.te
@@ -1 +1,5 @@
 allow shell serial_device:chr_file { getattr ioctl read write };
+allow shell cuttlefish_sensor_injection_exec:file rx_file_perms;
+
+# TODO(b/130668487): Label the vsock sockets.
+allow shell adbd:{ socket vsock_socket } rw_socket_perms_no_ioctl;
diff --git a/shared/sepolicy/vendor/socket_vsock_proxy.te b/shared/sepolicy/vendor/socket_vsock_proxy.te
index eaca909..d4e2b1a 100644
--- a/shared/sepolicy/vendor/socket_vsock_proxy.te
+++ b/shared/sepolicy/vendor/socket_vsock_proxy.te
@@ -4,7 +4,7 @@
 init_daemon_domain(socket_vsock_proxy)
 
 allow socket_vsock_proxy self:global_capability_class_set { net_admin net_raw };
-allow socket_vsock_proxy self:{ socket vsock_socket } { create read write listen accept bind };
+allow socket_vsock_proxy self:{ socket vsock_socket } { create getopt read write listen accept bind shutdown };
 
 # TODO: socket returned by accept() has unlabeled context on it. Give it a
 # specific label.
diff --git a/shared/sepolicy/vendor/surfaceflinger.te b/shared/sepolicy/vendor/surfaceflinger.te
index 05774e7..9b3e2c7 100644
--- a/shared/sepolicy/vendor/surfaceflinger.te
+++ b/shared/sepolicy/vendor/surfaceflinger.te
@@ -1,5 +1,6 @@
 allow surfaceflinger self:process execmem;
 
-# Read GCE initial metadata file
-allow surfaceflinger initial_metadata_file:file r_file_perms;
+allow surfaceflinger hal_graphics_composer_default:dir search;
+allow surfaceflinger hal_graphics_composer_default:file r_file_perms;
+
 gpu_access(surfaceflinger)
diff --git a/shared/sepolicy/vendor/suspend_blocker.te b/shared/sepolicy/vendor/suspend_blocker.te
new file mode 100644
index 0000000..fa6e02a
--- /dev/null
+++ b/shared/sepolicy/vendor/suspend_blocker.te
@@ -0,0 +1,6 @@
+type suspend_blocker, domain;
+type suspend_blocker_exec, exec_type, vendor_file_type, file_type;
+
+init_daemon_domain(suspend_blocker);
+
+wakelock_use(suspend_blocker);
diff --git a/shared/sepolicy/vendor/system_server.te b/shared/sepolicy/vendor/system_server.te
index 23497fc..372ca50 100644
--- a/shared/sepolicy/vendor/system_server.te
+++ b/shared/sepolicy/vendor/system_server.te
@@ -6,3 +6,6 @@
 # allow execmem rule were added here.
 permissive system_server;
 gpu_access(system_server)
+
+# Cuttlefish is still using the legacy wifi HAL (pre-HIDL)
+get_prop(system_server, wifi_hal_prop)
diff --git a/shared/sepolicy/vendor/ueventd.te b/shared/sepolicy/vendor/ueventd.te
index 985c8ec..9cb896f 100644
--- a/shared/sepolicy/vendor/ueventd.te
+++ b/shared/sepolicy/vendor/ueventd.te
@@ -1 +1,4 @@
 allow ueventd metadata_file:dir search;
+
+allow ueventd keymaster_device:chr_file { rw_file_perms create setattr };
+allow ueventd gatekeeper_device:chr_file { rw_file_perms create setattr };
diff --git a/shared/sepolicy/vendor/update_engine_common.te b/shared/sepolicy/vendor/update_engine_common.te
new file mode 100644
index 0000000..a79ce41
--- /dev/null
+++ b/shared/sepolicy/vendor/update_engine_common.te
@@ -0,0 +1 @@
+allow update_engine_common ab_block_device:blk_file rw_file_perms;
diff --git a/shared/sepolicy/vendor/usbforward.te b/shared/sepolicy/vendor/usbforward.te
deleted file mode 100644
index 6d0833e..0000000
--- a/shared/sepolicy/vendor/usbforward.te
+++ /dev/null
@@ -1,22 +0,0 @@
-type usbforward, domain;
-type usbforward_exec, exec_type, vendor_file_type, file_type;
-
-init_daemon_domain(usbforward)
-
-# Virtual serial device I/O
-allow usbforward virtual_serial_device:chr_file rw_file_perms;
-
-# USB I/O
-allow usbforward usb_device:dir r_dir_perms;
-allow usbforward usb_device:chr_file rw_file_perms;
-
-# Read /sys/devices/platform/dummy_hcd.0/usb1/1-1/speed. Although this file is labelled
-# It is acceptable to give usbforward this wide access because usbforward is not a stock Android
-# domain and it does not run Android apps. Thus, the laxer access restrictions of this domain
-# do not impact how compatible the resulting Android emulator appears to system services and apps.
-allow usbforward sysfs:file r_file_perms;
-
-# Do not audit attempts to read /dev directory. This access does not appear to be necessary.
-dontaudit usbforward device:dir r_dir_perms;
-
-allow usbforward self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl;
diff --git a/shared/sepolicy/vendor/vendor_init.te b/shared/sepolicy/vendor/vendor_init.te
index f4fffe6..37e76e1 100644
--- a/shared/sepolicy/vendor/vendor_init.te
+++ b/shared/sepolicy/vendor/vendor_init.te
@@ -1,17 +1,9 @@
-type vendor_init_radio_prop, property_type;
-type cf_graphics_config_prop, property_type;
-type cf_fstab_name_prop, property_type;
+vendor_internal_prop(vendor_graphics_config_prop)
 
 allow vendor_init {
   audio_device
 }:chr_file { getattr };
 
-set_prop(vendor_init, hal_bluetooth_sim_prop)
+set_prop(vendor_init, vendor_bt_rootcanal_prop)
 
-set_prop(vendor_init, vendor_init_radio_prop)
-
-get_prop(vendor_init, vendor_ser_prop)
-
-get_prop(vendor_init, cf_graphics_config_prop)
-
-get_prop(vendor_init, cf_fstab_name_prop)
+get_prop(vendor_init, vendor_graphics_config_prop)
diff --git a/shared/sepolicy/vendor/vold.te b/shared/sepolicy/vendor/vold.te
index 1dc963d..fdb36e8 100644
--- a/shared/sepolicy/vendor/vold.te
+++ b/shared/sepolicy/vendor/vold.te
@@ -1 +1,4 @@
 allow vold kernel:system module_request;
+
+# vold will access /mnt/vendor/shared for unknown reasons
+allow vold mnt_vendor_file:dir r_dir_perms;
diff --git a/shared/sepolicy/vendor/vport_trigger.te b/shared/sepolicy/vendor/vport_trigger.te
deleted file mode 100644
index a21e295..0000000
--- a/shared/sepolicy/vendor/vport_trigger.te
+++ /dev/null
@@ -1,12 +0,0 @@
-type vport_trigger, domain;
-type vport_trigger_exec, exec_type, vendor_file_type, file_type;
-
-type sys_cf_ser_prop, property_type;
-type vendor_ser_prop, property_type;
-
-init_daemon_domain(vport_trigger)
-
-r_dir_file(vport_trigger, sysfs_type)
-
-set_prop(vport_trigger, sys_cf_ser_prop)
-set_prop(vport_trigger, vendor_ser_prop)
diff --git a/shared/sepolicy/vendor/vsoc_input_service.te b/shared/sepolicy/vendor/vsoc_input_service.te
index ec20985..b934e12 100644
--- a/shared/sepolicy/vendor/vsoc_input_service.te
+++ b/shared/sepolicy/vendor/vsoc_input_service.te
@@ -1,7 +1,7 @@
 type vsoc_input_service, domain;
 type vsoc_input_service_exec, exec_type, vendor_file_type, file_type;
-type cuttlefish_vsock_keyboard_port, property_type;
-type cuttlefish_vsock_touch_port, property_type;
+vendor_internal_prop(vendor_vsock_keyboard_port)
+vendor_internal_prop(vendor_vsock_touch_port)
 
 init_daemon_domain(vsoc_input_service)
 
@@ -10,7 +10,7 @@
 
 net_domain(vsoc_input_service)
 
-get_prop(vsoc_input_service, cuttlefish_config_server_port_prop)
+get_prop(vsoc_input_service, vendor_cuttlefish_config_server_port_prop)
 
 allow vsoc_input_service self:{ socket vsock_socket } create_socket_perms_no_ioctl;
 
diff --git a/shared/sepolicy/vendor/vsock_logcat.te b/shared/sepolicy/vendor/vsock_logcat.te
deleted file mode 100644
index 7b7e8ff..0000000
--- a/shared/sepolicy/vendor/vsock_logcat.te
+++ /dev/null
@@ -1,17 +0,0 @@
-type vsock_logcat, domain;
-type vsock_logcat_exec, exec_type, vendor_file_type, file_type;
-type vsock_logcat_port_prop, property_type;
-type vsock_logcat_status_prop, property_type;
-
-init_daemon_domain(vsock_logcat)
-
-get_prop(vsock_logcat, vsock_logcat_port_prop)
-
-set_prop(vsock_logcat, vendor_ser_prop)
-set_prop(vsock_logcat, vsock_logcat_status_prop)
-
-allow vsock_logcat device:dir w_dir_perms;
-allow vsock_logcat device:fifo_file create_file_perms;
-allow vsock_logcat kmsg_device:chr_file rw_file_perms;
-allow vsock_logcat self:capability net_admin;
-allow vsock_logcat self:{ socket vsock_socket } create_socket_perms_no_ioctl;
diff --git a/shared/tv/android-info.txt b/shared/tv/android-info.txt
new file mode 100644
index 0000000..8eae902
--- /dev/null
+++ b/shared/tv/android-info.txt
@@ -0,0 +1 @@
+config=tv
diff --git a/shared/tv/device.mk b/shared/tv/device.mk
index a56b42b..9b78ee1 100644
--- a/shared/tv/device.mk
+++ b/shared/tv/device.mk
@@ -14,7 +14,6 @@
 # limitations under the License.
 #
 
-DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/config/manifest.xml
 DEVICE_MANIFEST_FILE += device/google/cuttlefish/shared/tv/manifest.xml
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_minimal.mk)
@@ -29,13 +28,19 @@
     frameworks/native/data/etc/android.hardware.hdmi.cec.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.hdmi.cec.xml \
     frameworks/native/data/etc/android.hardware.sensor.accelerometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.accelerometer.xml \
     frameworks/native/data/etc/android.hardware.sensor.compass.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.compass.xml \
-    frameworks/native/data/etc/android.hardware.touchscreen.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.touchscreen.xml \
+    hardware/interfaces/tv/tuner/config/sample_tuner_vts_config_1_0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/tuner_vts_config_1_0.xml \
+    hardware/interfaces/tv/tuner/config/sample_tuner_vts_config_1_1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/tuner_vts_config_1_1.xml \
 
 # HDMI CEC HAL
-PRODUCT_PACKAGES += android.hardware.tv.cec@1.0-service.mock
+PRODUCT_PACKAGES += android.hardware.tv.cec@1.1-service
+
+# Setup HDMI CEC as Playback Device
+PRODUCT_PROPERTY_OVERRIDES += ro.hdmi.device_type=4
 
 # Tuner HAL
-PRODUCT_PACKAGES += android.hardware.tv.tuner@1.0-service
+PRODUCT_PACKAGES += android.hardware.tv.tuner@1.1-service
 
 # Enabling managed profiles
 DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/tv/overlay
+
+TARGET_BOARD_INFO_FILE ?= device/google/cuttlefish/shared/tv/android-info.txt
diff --git a/shared/tv/manifest.xml b/shared/tv/manifest.xml
index 0dc4a45..8aab6ee 100644
--- a/shared/tv/manifest.xml
+++ b/shared/tv/manifest.xml
@@ -16,7 +16,7 @@
 ** limitations under the License.
 */
 -->
-<manifest version="1.0" type="device" target-level="5">
+<manifest version="1.0" type="device">
      <!-- FIXME: Implement tv.cec HAL
      <hal format="hidl">
         <name>android.hardware.tv.cec</name>
diff --git a/shared/tv/overlay/frameworks/base/core/res/res/values/config.xml b/shared/tv/overlay/frameworks/base/core/res/res/values/config.xml
index 195a8a7..5ec4e78 100644
--- a/shared/tv/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/shared/tv/overlay/frameworks/base/core/res/res/values/config.xml
@@ -17,4 +17,8 @@
 <resources>
     <!--  Maximum number of supported users -->
     <integer name="config_multiuserMaximumUsers">4</integer>
+    <!-- Restricting eth2 -->
+    <string-array translatable="false" name="config_ethernet_interfaces">
+        <item>eth2;11,12,14;;</item>
+    </string-array>
 </resources>
diff --git a/shared/tv/sepolicy/vendor/file_contexts b/shared/tv/sepolicy/vendor/file_contexts
index 267f831..88b1cf5 100644
--- a/shared/tv/sepolicy/vendor/file_contexts
+++ b/shared/tv/sepolicy/vendor/file_contexts
@@ -1,2 +1 @@
 /vendor/bin/hw/android\.hardware\.tv\.cec@1\.0-service\.mock u:object_r:hal_tv_cec_mock_exec:s0
-/vendor/bin/hw/android\.hardware\.tv\.tuner@1\.0-service u:object_r:hal_tv_tuner_default_exec:s0
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 337f5b9..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2017 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/graphics/Android.bp b/tests/graphics/Android.bp
new file mode 100644
index 0000000..6767817
--- /dev/null
+++ b/tests/graphics/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2021 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_host {
+    name: "GfxstreamEnabledTest",
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_options: {
+        unit_test: false,
+    },
+    test_suites: [
+        "device-tests",
+    ],
+    libs: [
+        "tradefed",
+    ],
+}
diff --git a/tests/graphics/src/com/android/cuttlefish/tests/GfxstreamEnabledTest.java b/tests/graphics/src/com/android/cuttlefish/tests/GfxstreamEnabledTest.java
new file mode 100644
index 0000000..c3400a0
--- /dev/null
+++ b/tests/graphics/src/com/android/cuttlefish/tests/GfxstreamEnabledTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+package com.android.cuttlefish.tests;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.tradefed.device.cloud.RemoteAndroidVirtualDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests that Gfxstream was enabled as the virtual device's OpenGL and Vulkan driver.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class GfxstreamEnabledTest extends BaseHostJUnit4Test {
+
+    @Test
+    public void testGfxstreamEnabled() throws Exception {
+        if (!(getDevice() instanceof RemoteAndroidVirtualDevice)) {
+            return;
+        }
+
+        assertThat(getDevice().getProperty("ro.hardware.egl")).isEqualTo("emulation");
+        assertThat(getDevice().getProperty("ro.hardware.vulkan")).isEqualTo("ranchu");
+    }
+}
\ No newline at end of file
diff --git a/tests/hal/Android.bp b/tests/hal/Android.bp
index 41cb2c0..5aa14ce 100644
--- a/tests/hal/Android.bp
+++ b/tests/hal/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_test {
     name: "hal_implementation_test",
     srcs: ["hal_implementation_test.cpp"],
diff --git a/tests/hal/hal_implementation_test.cpp b/tests/hal/hal_implementation_test.cpp
index 8c2ae50..e7bdc72 100644
--- a/tests/hal/hal_implementation_test.cpp
+++ b/tests/hal/hal_implementation_test.cpp
@@ -25,45 +25,47 @@
 
 static const std::set<std::string> kKnownMissingHidl = {
     "android.frameworks.bufferhub@1.0",
-    "android.frameworks.cameraservice.device@2.0",
+    "android.frameworks.cameraservice.device@2.1",
+    "android.frameworks.schedulerservice@1.0", // deprecated, see b/37226359
     "android.frameworks.vr.composer@1.0",
     "android.frameworks.vr.composer@2.0",
     "android.frameworks.automotive.display@1.0",
+    "android.frameworks.stats@1.0",  // converted to AIDL, see b/177667419
     "android.hardware.audio@2.0",
     "android.hardware.audio@4.0",
     "android.hardware.audio@5.0",
+    "android.hardware.audio@7.0",
     "android.hardware.audio.effect@2.0",
     "android.hardware.audio.effect@4.0",
     "android.hardware.audio.effect@5.0",
+    "android.hardware.audio.effect@7.0",
     "android.hardware.automotive.audiocontrol@1.0",
     "android.hardware.automotive.audiocontrol@2.0",
     "android.hardware.automotive.can@1.0",
-    "android.hardware.automotive.evs@1.0",
     "android.hardware.automotive.evs@1.1",
     "android.hardware.automotive.sv@1.0",
     "android.hardware.automotive.vehicle@2.0",
-    "android.hardware.biometrics.fingerprint@2.1",
-    "android.hardware.biometrics.fingerprint@2.2",
+    "android.hardware.biometrics.fingerprint@2.3",
     "android.hardware.bluetooth.a2dp@1.0",
     "android.hardware.broadcastradio@1.1",
     "android.hardware.broadcastradio@2.0",
     "android.hardware.cas.native@1.0",
     "android.hardware.confirmationui@1.0",
     "android.hardware.configstore@1.1", // deprecated, see b/149050985, b/149050733
-    "android.hardware.fastboot@1.0",
+    "android.hardware.fastboot@1.1",
     "android.hardware.gnss.measurement_corrections@1.1", // is sub-interface of gnss
     "android.hardware.gnss.visibility_control@1.0",
     "android.hardware.graphics.allocator@2.0",
     "android.hardware.graphics.allocator@3.0",
     "android.hardware.graphics.bufferqueue@1.0",
     "android.hardware.graphics.bufferqueue@2.0",
-    "android.hardware.graphics.composer@2.3",
     "android.hardware.graphics.composer@2.4",
     "android.hardware.graphics.mapper@2.1",
     "android.hardware.graphics.mapper@3.0",
-    "android.hardware.health@1.0",
+    "android.hardware.health.storage@1.0", // converted to AIDL, see b/177470478
     "android.hardware.ir@1.0",
     "android.hardware.keymaster@3.0",
+    "android.hardware.keymaster@4.1", // Replaced by KeyMint
     "android.hardware.light@2.0",
     "android.hardware.media.bufferpool@1.0",
     "android.hardware.media.bufferpool@2.0",
@@ -71,26 +73,25 @@
     "android.hardware.nfc@1.2",
     "android.hardware.oemlock@1.0",
     "android.hardware.power@1.3",
-    "android.hardware.radio.config@1.2",
+    "android.hardware.power.stats@1.0",
     "android.hardware.radio.deprecated@1.0",
     "android.hardware.renderscript@1.0",
+    "android.hardware.soundtrigger@2.3",
     "android.hardware.secure_element@1.2",
     "android.hardware.sensors@1.0",
     "android.hardware.tetheroffload.config@1.0",
-    "android.hardware.tetheroffload.control@1.0",
+    "android.hardware.tetheroffload.control@1.1", // see b/170699770
     "android.hardware.thermal@1.1",
-    "android.hardware.tv.cec@1.0",
-    "android.hardware.tv.cec@2.0",
+    "android.hardware.tv.cec@1.1",
     "android.hardware.tv.input@1.0",
-    "android.hardware.tv.tuner@1.0",
-    "android.hardware.usb@1.2",
-    "android.hardware.usb.gadget@1.1",
+    "android.hardware.tv.tuner@1.1",
+    "android.hardware.usb@1.3",
+    "android.hardware.usb.gadget@1.2",
     "android.hardware.vibrator@1.3",
     "android.hardware.vr@1.0",
     "android.hardware.weaver@1.0",
-    "android.hardware.wifi@1.3",
-    "android.hardware.wifi@1.4",
-    "android.hardware.wifi.hostapd@1.2",
+    "android.hardware.wifi@1.5",
+    "android.hardware.wifi.hostapd@1.3",
     "android.hardware.wifi.offload@1.0",
     "android.hidl.base@1.0",
     "android.hidl.memory.token@1.0",
@@ -98,19 +99,28 @@
 
 static const std::set<std::string> kKnownMissingAidl = {
     // types-only packages, which never expect a default implementation
-    "android.hardware.common.NativeHandle",
-    "android.hardware.graphics.common.ExtendableType",
+    "android.hardware.biometrics.common.",
+    "android.hardware.common.",
+    "android.hardware.common.fmq.",
+    "android.hardware.graphics.common.",
 
     // These KeyMaster types are in an AIDL types-only HAL because they're used
     // by the Identity Credential AIDL HAL. Remove this when fully porting
     // KeyMaster to AIDL.
-    "android.hardware.keymaster.HardwareAuthToken",
-    "android.hardware.keymaster.HardwareAuthenticatorType",
-    "android.hardware.keymaster.Timestamp",
+    "android.hardware.keymaster.",
+
+    // These types are only used in Automotive.
+    "android.automotive.computepipe.registry.",
+    "android.automotive.computepipe.runner.",
+    "android.automotive.watchdog.",
+    "android.frameworks.automotive.powerpolicy.",
+    "android.frameworks.automotive.telemetry.",
+    "android.hardware.automotive.audiocontrol.",
+    "android.hardware.automotive.occupant_awareness.",
 };
 
 // AOSP packages which are never considered
-static bool isHidlPackageWhitelist(const FQName& name) {
+static bool isHidlPackageConsidered(const FQName& name) {
     static std::vector<std::string> gAospExclude = {
         // packages not implemented now that we never expect to be implemented
         "android.hardware.tests",
@@ -119,10 +129,10 @@
     };
     for (const std::string& package : gAospExclude) {
         if (name.inPackage(package)) {
-            return true;
+            return false;
         }
     }
-    return false;
+    return true;
 }
 
 static bool isAospHidlInterface(const FQName& name) {
@@ -166,9 +176,8 @@
 
 static bool isAospAidlInterface(const std::string& name) {
     return base::StartsWith(name, "android.") &&
-        !base::StartsWith(name, "android.automotive.") &&
-        !base::StartsWith(name, "android.hardware.automotive.") &&
-        !base::StartsWith(name, "android.hardware.tests.");
+        !base::StartsWith(name, "android.hardware.tests.") &&
+        !base::StartsWith(name, "android.aidl.tests");
 }
 
 static std::set<std::string> allAidlManifestInterfaces() {
@@ -187,7 +196,9 @@
 
 TEST(Hal, AllHidlInterfacesAreInAosp) {
     for (const FQName& name : allHidlManifestInterfaces()) {
-        EXPECT_TRUE(isAospHidlInterface(name)) << name.string();
+      EXPECT_TRUE(isAospHidlInterface(name))
+          << "This device should only have AOSP interfaces, not: "
+          << name.string();
     }
 }
 
@@ -197,7 +208,7 @@
 
     for (const FQName& f : allTreeHidlInterfaces()) {
         if (!isAospHidlInterface(f)) continue;
-        if (isHidlPackageWhitelist(f)) continue;
+        if (!isHidlPackageConsidered(f)) continue;
 
         unimplemented[f.package()][f.getPackageMajorVersion()].insert(f.getPackageMinorVersion());
     }
@@ -209,8 +220,7 @@
 
     for (const FQName& f : allHidlManifestInterfaces()) {
         if (thoughtMissing.erase(f.getPackageAndVersion().string()) > 0) {
-             std::cout << "[ WARNING  ] Instance in missing list, but available: "
-                       << f.string() << std::endl;
+             ADD_FAILURE() << "Instance in missing list, but available: " << f.string();
         }
 
         std::set<size_t>& minors = unimplemented[f.package()][f.getPackageMajorVersion()];
@@ -239,17 +249,25 @@
     }
 
     for (const std::string& missing : thoughtMissing) {
-        std::cout << "[ WARNING  ] Instance in missing list and cannot find it anywhere: "
-                  << missing << std::endl;
+        ADD_FAILURE() << "Instance in missing list and cannot find it anywhere: " << missing
+                  << " (multiple versions in missing list?)";
     }
 }
 
 TEST(Hal, AllAidlInterfacesAreInAosp) {
     for (const std::string& name : allAidlManifestInterfaces()) {
-        EXPECT_TRUE(isAospAidlInterface(name)) << name;
+      EXPECT_TRUE(isAospAidlInterface(name))
+          << "This device should only have AOSP interfaces, not: " << name;
     }
 }
 
+// android.hardware.foo.IFoo -> android.hardware.foo.
+std::string getAidlPackage(const std::string& aidlType) {
+    size_t lastDot = aidlType.rfind('.');
+    CHECK(lastDot != std::string::npos);
+    return aidlType.substr(0, lastDot + 1);
+}
+
 TEST(Hal, AidlInterfacesImplemented) {
     std::set<std::string> manifest = allAidlManifestInterfaces();
     std::set<std::string> thoughtMissing = kKnownMissingAidl;
@@ -263,29 +281,28 @@
         bool knownMissing = false;
         for (const std::string& type : iface.types) {
             if (manifest.erase(type) > 0) hasRegistration = true;
-            if (thoughtMissing.erase(type) > 0) knownMissing = true;
+            if (thoughtMissing.erase(getAidlPackage(type)) > 0)  knownMissing = true;
         }
 
         if (knownMissing) {
             if (hasRegistration) {
-                std::cout << "[ WARNING  ] Interface in missing list, but available: " << iface.name
+                ADD_FAILURE() << "Interface in missing list, but available: " << iface.name
                           << " which declares the following types:\n    "
-                          << base::Join(iface.types, "\n    ") << std::endl;
+                          << base::Join(iface.types, "\n    ");
             }
 
             continue;
         }
 
         EXPECT_TRUE(hasRegistration) << iface.name << " which declares the following types:\n    "
-            << base::Join(iface.types, "\n    ") << std::endl;
+            << base::Join(iface.types, "\n    ");
     }
 
     for (const std::string& iface : thoughtMissing) {
-        std::cout << "[ WARNING  ] Interface in manifest list and cannot find it anywhere: "
-                  << iface << std::endl;
+        ADD_FAILURE() << "Interface in manifest list and cannot find it anywhere: " << iface;
     }
 
     for (const std::string& iface : manifest) {
-        std::cout << "[ WARNING  ] Can't find manifest entry in tree: " << iface << std::endl;
+        ADD_FAILURE() << "Can't find manifest entry in tree: " << iface;
     }
 }
diff --git a/tests/powerwash/Android.bp b/tests/powerwash/Android.bp
new file mode 100644
index 0000000..6ef1c92
--- /dev/null
+++ b/tests/powerwash/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_host {
+    name: "PowerwashTest",
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "device-tests",
+    ],
+    libs: [
+        "tradefed",
+    ],
+}
diff --git a/tests/powerwash/src/com/android/cuttlefish/tests/PowerwashTest.java b/tests/powerwash/src/com/android/cuttlefish/tests/PowerwashTest.java
new file mode 100644
index 0000000..84fa852
--- /dev/null
+++ b/tests/powerwash/src/com/android/cuttlefish/tests/PowerwashTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+package com.android.cuttlefish.tests;
+
+import com.android.tradefed.device.cloud.RemoteAndroidVirtualDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import java.io.File;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test powerwash function.
+ *
+ * <p>* This test resets the device thus it should not run with other tests in the same test suite
+ * to avoid unexpected behavior.
+ *
+ * <p>* The test logic relies on powerwash_cvd tool, so it can only run in a test lab setup.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class PowerwashTest extends BaseHostJUnit4Test {
+
+    @Test
+    public void testPowerwash() throws Exception {
+        // Create a file in tmp directory
+        final String tmpFile = "/data/local/tmp/powerwash_tmp";
+        getDevice().executeShellCommand("touch " + tmpFile);
+
+        // Reboot the device to make sure the file persits.
+        getDevice().reboot();
+        getDevice().waitForDeviceAvailable();
+        File file = getDevice().pullFile(tmpFile);
+        if (file == null) {
+            Assert.fail("Setup failed: tmp file failed to persist after device reboot.");
+        }
+
+        if (getDevice() instanceof RemoteAndroidVirtualDevice) {
+            ((RemoteAndroidVirtualDevice) getDevice()).powerwashGce();
+        } else {
+            Assert.fail("This test only supports running in test lab setup.");
+        }
+
+        // Verify that the device is back online and pre-xisting file is gone.
+        file = getDevice().pullFile(tmpFile);
+        if (file != null) {
+            Assert.fail("Powerwash failed: pre-existing file still exists.");
+        }
+    }
+}
diff --git a/tests/recovery/Android.bp b/tests/recovery/Android.bp
new file mode 100644
index 0000000..c361a0e
--- /dev/null
+++ b/tests/recovery/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_host {
+    name: "RebootRecoveryTest",
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "device-tests",
+    ],
+    libs: [
+        "tradefed",
+    ],
+}
diff --git a/tests/recovery/AndroidTest.xml b/tests/recovery/AndroidTest.xml
new file mode 100644
index 0000000..f21b659
--- /dev/null
+++ b/tests/recovery/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<configuration description="GKI Install test">
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="jar" value="RebootRecoveryTest.jar" />
+    </test>
+</configuration>
diff --git a/tests/recovery/src/com/android/cuttlefish/tests/RebootRecoveryTest.java b/tests/recovery/src/com/android/cuttlefish/tests/RebootRecoveryTest.java
new file mode 100644
index 0000000..f4d7757
--- /dev/null
+++ b/tests/recovery/src/com/android/cuttlefish/tests/RebootRecoveryTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package com.android.cuttlefish.tests;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test rebooting into recovery.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class RebootRecoveryTest extends BaseHostJUnit4Test {
+    @Test
+    public void testRebootRecovery() throws Exception {
+        getDevice().rebootIntoRecovery();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        getDevice().reboot();
+    }
+}
diff --git a/tests/ril/Android.bp b/tests/ril/Android.bp
new file mode 100644
index 0000000..ed1d30d
--- /dev/null
+++ b/tests/ril/Android.bp
@@ -0,0 +1,31 @@
+// Copyright 2020 Google Inc. All Rights Reserved.
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CuttlefishRilTests",
+    srcs: ["src/**/*.java"],
+    libs: ["android.test.runner.stubs"],
+    static_libs: [
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "hamcrest-library",
+        "platform-test-annotations",
+    ],
+    sdk_version: "current",
+    certificate: "platform",
+}
diff --git a/tests/ril/Android.mk b/tests/ril/Android.mk
deleted file mode 100644
index 178e916..0000000
--- a/tests/ril/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# 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.
-
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 24; echo $$?))
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CuttlefishRilTests
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?))
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-else
-LOCAL_JAVA_LIBRARIES := android.test.runner
-endif
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test espresso-core
-
-LOCAL_STATIC_JAVA_LIBRARIES+=platform-test-annotations
-
-include $(BUILD_PACKAGE)
-
-endif
diff --git a/tests/ril/AndroidManifest.xml b/tests/ril/AndroidManifest.xml
index 462daa6..4872109 100644
--- a/tests/ril/AndroidManifest.xml
+++ b/tests/ril/AndroidManifest.xml
@@ -29,7 +29,7 @@
         android:targetSdkVersion="25" />
 
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.cuttlefish.ril.tests" />
 
     <application>
diff --git a/tests/ril/runtests.sh b/tests/ril/runtests.sh
index d271455..2bb4bac 100755
--- a/tests/ril/runtests.sh
+++ b/tests/ril/runtests.sh
@@ -27,4 +27,4 @@
 adb uninstall com.android.cuttlefish.ril.tests || true
 adb install -r -g "$OUT/data/app/CuttlefishRilTests/CuttlefishRilTests.apk"
 # optionally: -e class com.android.cuttlefish.ril.RilE2eTests#testName
-adb shell am instrument -w "$@" 'com.android.cuttlefish.ril.tests/android.support.test.runner.AndroidJUnitRunner'
+adb shell am instrument -w "$@" 'com.android.cuttlefish.ril.tests/androidx.test.runner.AndroidJUnitRunner'
diff --git a/tests/ril/src/com/android/cuttlefish/ril/tests/RilE2eTests.java b/tests/ril/src/com/android/cuttlefish/ril/tests/RilE2eTests.java
index e09895f..3c5db3f 100644
--- a/tests/ril/src/com/android/cuttlefish/ril/tests/RilE2eTests.java
+++ b/tests/ril/src/com/android/cuttlefish/ril/tests/RilE2eTests.java
@@ -15,22 +15,25 @@
  */
 package com.android.cuttlefish.ril.tests;
 
+import static org.hamcrest.Matchers.greaterThan;
+
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkInfo;
-import android.net.wifi.SupplicantState;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.support.test.InstrumentationRegistry;
+import android.os.Build;
 import android.telephony.CellInfoGsm;
 import android.telephony.CellSignalStrengthGsm;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import static org.hamcrest.Matchers.greaterThan;
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.PropertyUtil;
+
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -38,7 +41,6 @@
 import org.junit.runners.JUnit4;
 
 import java.net.Socket;
-import java.util.List;
 
 /**
  * Tests used to validate E2E RIL functionality.
@@ -54,6 +56,13 @@
 
     @Before
     public void setUp() throws Exception {
+        // Ideally this should be done in the @BeforeClass hook, but that would
+        // make tradefed unhappy with a bunch "test did not run due to
+        // instrumentation issue. See run level error for reason." errors.
+        Assume.assumeFalse(
+                "Skip testing deprecated radio HAL from Q or earlier vendor",
+                PropertyUtil.getFirstApiLevel() <= Build.VERSION_CODES.Q);
+
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mWifiManager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
         mConnManager = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
diff --git a/tests/wifi/Android.bp b/tests/wifi/Android.bp
new file mode 100644
index 0000000..838e861
--- /dev/null
+++ b/tests/wifi/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2020 Google Inc. All Rights Reserved.
+//
+// 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CuttlefishWifiTests",
+    srcs: ["src/**/*.java"],
+    libs: ["android.test.runner.stubs"],
+    static_libs: [
+        "androidx.test.rules",
+        "platform-test-annotations",
+    ],
+    sdk_version: "current",
+    certificate: "platform",
+}
diff --git a/tests/wifi/Android.mk b/tests/wifi/Android.mk
deleted file mode 100644
index 50ba909..0000000
--- a/tests/wifi/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# 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.
-
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 24; echo $$?))
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CuttlefishWifiTests
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?))
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-else
-LOCAL_JAVA_LIBRARIES := android.test.runner
-endif
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test platform-test-annotations
-
-include $(BUILD_PACKAGE)
-endif
diff --git a/tests/wifi/AndroidManifest.xml b/tests/wifi/AndroidManifest.xml
index 0ff1388..9394ad0 100644
--- a/tests/wifi/AndroidManifest.xml
+++ b/tests/wifi/AndroidManifest.xml
@@ -28,7 +28,7 @@
         android:targetSdkVersion="25" />
 
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.cuttlefish.wifi.tests" />
 
     <application>
diff --git a/tests/wifi/runtests.sh b/tests/wifi/runtests.sh
index c867901..c6642d3 100755
--- a/tests/wifi/runtests.sh
+++ b/tests/wifi/runtests.sh
@@ -27,4 +27,4 @@
 adb uninstall com.android.cuttlefish.wifi.tests || true
 adb install -r -g "$OUT/data/app/CuttlefishWifiTests/CuttlefishWifiTests.apk"
 # optionally: -e class com.android.cuttlefish.wifi.WifiE2eTests#testName
-adb shell am instrument -w "$@" 'com.android.cuttlefish.wifi.tests/android.support.test.runner.AndroidJUnitRunner'
+adb shell am instrument -w "$@" 'com.android.cuttlefish.wifi.tests/androidx.test.runner.AndroidJUnitRunner'
diff --git a/tests/wifi/src/com/android/cuttlefish/wifi/tests/WifiE2eTests.java b/tests/wifi/src/com/android/cuttlefish/wifi/tests/WifiE2eTests.java
index e3d9e70..1ea4a1d 100644
--- a/tests/wifi/src/com/android/cuttlefish/wifi/tests/WifiE2eTests.java
+++ b/tests/wifi/src/com/android/cuttlefish/wifi/tests/WifiE2eTests.java
@@ -19,14 +19,14 @@
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkInfo;
-import android.net.ConnectivityManager;
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -121,9 +121,11 @@
         Assert.assertNotNull(configs);
         for (WifiConfiguration config : configs) {
             Log.i(TAG, "Removing network " + config.networkId + ": " + config.SSID);
-            Assert.assertTrue(mWifiManager.disableNetwork(config.networkId));
-            Assert.assertTrue(mWifiManager.removeNetwork(config.networkId));
+            mWifiManager.disableNetwork(config.networkId);
+            mWifiManager.removeNetwork(config.networkId);
         }
+        configs = mWifiManager.getConfiguredNetworks();
+        Assert.assertEquals(0, configs.size());
 
         waitForSupplicantState(
                 SupplicantState.INACTIVE,
diff --git a/tools/create_base_image_arm.sh b/tools/create_base_image_arm.sh
index 262d427..644d909 100755
--- a/tools/create_base_image_arm.sh
+++ b/tools/create_base_image_arm.sh
@@ -16,7 +16,7 @@
 
 script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
 
-source "${ANDROID_BUILD_TOP}/external/shflags/src/shflags"
+source "${ANDROID_BUILD_TOP}/external/shflags/shflags"
 
 DEFINE_boolean p1 \
 	false "Only generate/write the 1st partition (loader1)" "1"
@@ -281,7 +281,7 @@
 load mmc ${devnum}:${distro_bootpart} 0x01f00000 /boot/dtb/rockchip/rk3399-rock-pi-4.dtb
 setenv finduuid "part uuid mmc ${devnum}:${distro_bootpart} uuid"
 run finduuid
-setenv bootargs "earlycon=uart8250,mmio32,0xff1a0000 console=ttyS2,1500000n8 loglevel=7 root=PARTUUID=${uuid} rootwait rootfstype=ext4 sdhci.debug_quirks=0x20000000"
+setenv bootargs "earlycon=uart8250,mmio32,0xff1a0000 console=ttyS2,1500000n8 loglevel=7 root=PARTUUID=${uuid} rootwait rootfstype=ext4 sdhci.debug_quirks=0x20000000 of_devlink=0"
 booti 0x02080000 0x04000000 0x01f00000
 EOF
 	${ANDROID_HOST_OUT}/bin/mkimage \
@@ -307,7 +307,7 @@
 	echo "Installing required packages..."
 	chroot ${mntdir} /bin/bash <<EOF
 apt-get update
-apt-get install -y -f initramfs-tools u-boot-tools network-manager openssh-server sudo man-db vim git dpkg-dev cdbs debhelper config-package-dev gdisk eject lzop binfmt-support ntpdate
+apt-get install -y -f initramfs-tools u-boot-tools network-manager openssh-server sudo man-db vim git dpkg-dev cdbs debhelper config-package-dev gdisk eject lzop binfmt-support ntpdate lsof
 EOF
 
 	echo "Turning on DHCP client..."
@@ -456,7 +456,7 @@
 dest_dev=mmcblk1
 part_num=p5
 
-if [ -e /dev/mmcblk0p5 ]; then
+if [ -e /dev/mmcblk0p5 ] && [ -e /dev/mmcblk1p5 ]; then
 	led 1
 
 	sgdisk -Z -a1 /dev/${dest_dev}
diff --git a/tools/create_base_image_gce.sh b/tools/create_base_image_gce.sh
index 7c693c5..02797db 100755
--- a/tools/create_base_image_gce.sh
+++ b/tools/create_base_image_gce.sh
@@ -44,6 +44,7 @@
 cp "${debs[@]}" /mnt/image/tmp
 sudo mount -t sysfs none /mnt/image/sys
 sudo mount -t proc none /mnt/image/proc
+sudo mount --bind /boot/efi /mnt/image/boot/efi
 sudo mount --bind /dev/ /mnt/image/dev
 sudo mount --bind /dev/pts /mnt/image/dev/pts
 sudo mount --bind /run /mnt/image/run
@@ -99,10 +100,23 @@
   exit 1
 fi
 
+# Vulkan loader
+sudo chroot /mnt/image /usr/bin/apt install -y libvulkan1
+
+# Wayland-server needed to have Nvidia driver fail gracefully when attemping to
+# use the EGL API on GCE instances without a GPU.
+sudo chroot /mnt/image /usr/bin/apt install -y libwayland-server0
 
 # Clean up the builder's version of resolv.conf
 sudo rm /mnt/image/etc/resolv.conf
 
+# Make sure the image has /var/empty, and allow unprivileged_userns_clone for
+# minijail process sandboxing
+sudo chroot /mnt/image /usr/bin/mkdir -p /var/empty
+sudo tee /mnt/image/etc/sysctl.d/80-nsjail.conf >/dev/null <<EOF
+kernel.unprivileged_userns_clone=1
+EOF
+
 # Skip unmounting:
 #  Sometimes systemd starts, making it hard to unmount
 #  In any case we'll unmount cleanly when the instance shuts down
diff --git a/tools/create_base_image_hostlib.sh b/tools/create_base_image_hostlib.sh
index f9982a5..dafefbd 100755
--- a/tools/create_base_image_hostlib.sh
+++ b/tools/create_base_image_hostlib.sh
@@ -8,7 +8,7 @@
 # INTERNAL_IP can be set to --internal-ip run on a GCE instance
 # The instance will need --scope compute-rw
 
-source "${ANDROID_BUILD_TOP}/external/shflags/src/shflags"
+source "${ANDROID_BUILD_TOP}/external/shflags/shflags"
 
 DEFINE_string build_instance \
   "${USER}-build" "Instance name to create for the build" "i"
@@ -29,10 +29,8 @@
 DEFINE_string repository_url \
   "https://github.com/google/android-cuttlefish.git" \
   "URL to the repository with host changes" "u"
-DEFINE_string repository_branch master \
+DEFINE_string repository_branch main \
   "Branch to check out" "b"
-DEFINE_string variant master \
-  "Variant to build: generally master or stable"
 
 
 SSH_FLAGS=(${INTERNAL_IP})
diff --git a/tools/play_audio/.gitignore b/tools/play_audio/.gitignore
deleted file mode 100644
index a6795ba..0000000
--- a/tools/play_audio/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.o
-play_audio
-opuscpp
diff --git a/tools/play_audio/Makefile b/tools/play_audio/Makefile
deleted file mode 100644
index 30730ef..0000000
--- a/tools/play_audio/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-CXXFLAGS := -Wextra -Wall -pedantic-errors -std=c++17
-LDLIBS := -lopus -lgflags -lglog -lSDL2
-LINK.o := $(LINK.cc)
-
-PROG := play_audio
-OBJS := $(PROG).o client_socket.o sdl_wrapper.o opuscpp/opus_wrapper.o
-
-$(PROG): $(OBJS)
-
-clean:
-	rm -f $(OBJS) $(PROG)
-
diff --git a/tools/play_audio/README.md b/tools/play_audio/README.md
deleted file mode 100644
index 28c227f..0000000
--- a/tools/play_audio/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Play Audio
-
-Audio receiver for a cuttlefish instance. A binary to play audio from a remote
-Android virtual device.
-
-## Install Dependencies
-
-```
-git clone https://github.com/google/opuscpp
-sudo apt install libsdl2-2.0-0 libsdl2-dev libopus-dev libopus0 libgflags-dev libgoogle-glog-dev
-```
-
-## Build
-
-```
-make
-```
-
-## Run
-Use ssh port forwarding to forward `7444` from a running instance. Then run the
-`play_audio` binary.
-
-```
-./play_audio
-```
-
-If you are running multiple virtual devices on a host, you must pass the
-`device_num` flag to specify the device corresponding to the `vsoc-##` username,
-and you will have to add `1 - device_num` to the port that you forward (vsoc-02
-= port 7445).
diff --git a/tools/play_audio/client_socket.cpp b/tools/play_audio/client_socket.cpp
deleted file mode 100644
index 97c6b13..0000000
--- a/tools/play_audio/client_socket.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- *
- * Copyright (C) 2018 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.
- */
-#include "client_socket.h"
-
-#include "glog/logging.h"
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <cstdint>
-#include <cstring>
-#include <vector>
-
-namespace {
-std::uint16_t HostOrderUInt16(const void* src) {
-  std::uint16_t result{};
-  std::memcpy(&result, src, sizeof result);
-  return htons(result);
-}
-
-std::uint32_t HostOrderUInt32(const void* src) {
-  std::uint32_t result{};
-  std::memcpy(&result, src, sizeof result);
-  return htonl(result);
-}
-}  // namespace
-
-using cfp::ClientSocket;
-
-ClientSocket::ClientSocket(std::uint16_t port)
-    : socket_fd_{socket(AF_INET, SOCK_STREAM, 0)} {
-  sockaddr_in server_addr{};
-
-  if (socket_fd_ < 0) {
-    LOG(ERROR) << "couldn't create socket\n";
-    return;
-  }
-  server_addr.sin_family = AF_INET;
-  server_addr.sin_port = htons(port);
-
-  if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
-    LOG(ERROR) << "couldn't convert localhost address\n";
-    close();
-    return;
-  }
-
-  if (connect(socket_fd_, reinterpret_cast<sockaddr*>(&server_addr),
-              sizeof server_addr) < 0) {
-    LOG(ERROR) << "connection failed\n";
-    close();
-    return;
-  }
-}
-
-ClientSocket::~ClientSocket() { close(); }
-
-ClientSocket::ClientSocket(ClientSocket&& other)
-    : socket_fd_{other.socket_fd_} {
-  other.socket_fd_ = -1;
-}
-
-ClientSocket& ClientSocket::operator=(ClientSocket&& other) {
-  close();
-  socket_fd_ = other.socket_fd_;
-  other.socket_fd_ = -1;
-  return *this;
-}
-
-std::vector<unsigned char> ClientSocket::RecvAll(ssize_t count) {
-  std::vector<unsigned char> buf(count);
-  size_t total_read = 0;
-  while (total_read < buf.size()) {
-    auto just_read =
-        read(socket_fd_, buf.data() + total_read, buf.size() - total_read);
-    if (just_read <= 0) {
-      LOG(ERROR) << "read failed";
-      return {};
-    }
-    total_read += static_cast<size_t>(just_read);
-  }
-  return buf;
-}
-
-std::uint16_t ClientSocket::RecvUInt16() {
-  return HostOrderUInt16(RecvAll(sizeof(std::uint16_t)).data());
-}
-
-std::uint32_t ClientSocket::RecvUInt32() {
-  return HostOrderUInt32(RecvAll(sizeof(std::uint32_t)).data());
-}
-
-void ClientSocket::close() {
-  if (socket_fd_ >= 0) {
-    ::close(socket_fd_);
-    socket_fd_ = -1;
-  }
-}
diff --git a/tools/play_audio/client_socket.h b/tools/play_audio/client_socket.h
deleted file mode 100644
index f51cb6a..0000000
--- a/tools/play_audio/client_socket.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- * Copyright (C) 2018 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.
- */
-#ifndef CFP_CLIENT_SOCKET_
-#define CFP_CLIENT_SOCKET_
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-#include <vector>
-
-namespace cfp {
-
-class ClientSocket {
- public:
-  ClientSocket(std::uint16_t port);
-  ~ClientSocket();
-
-  ClientSocket(ClientSocket&& other);
-  ClientSocket& operator=(ClientSocket&& other);
-
-  ClientSocket(const ClientSocket&) = delete;
-  ClientSocket& operator=(const ClientSocket&) = delete;
-
-  bool valid() const { return socket_fd_ >= 0; }
-
-  std::vector<unsigned char> RecvAll(ssize_t count);
-
-  std::uint16_t RecvUInt16();
-  std::uint32_t RecvUInt32();
-
- private:
-  void close();
-  int socket_fd_ = -1;
-};
-
-}  // namespace cfp
-
-#endif
diff --git a/tools/play_audio/play_audio.cpp b/tools/play_audio/play_audio.cpp
deleted file mode 100644
index 2594396..0000000
--- a/tools/play_audio/play_audio.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- *
- * Copyright (C) 2018 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.
- */
-#include "client_socket.h"
-#include "sdl_wrapper.h"
-
-#include "glog/logging.h"
-#include "gflags/gflags.h"
-#include "opuscpp/opus_wrapper.h"
-#include <SDL2/SDL.h>
-
-#include <cstdint>
-#include <tuple>
-#include <vector>
-
-DEFINE_int32(
-    device_num, 1,
-    "Cuttlefish device number, corresponding to username vsoc-## number");
-
-namespace {
-std::uint16_t AudioPort() {
-  constexpr std::uint16_t kAudioStreamBasePort = 7444;
-  std::uint16_t audio_port = kAudioStreamBasePort + (FLAGS_device_num - 1);
-  return audio_port;
-}
-
-cfp::ClientSocket Connect() {
-  const auto port = AudioPort();
-  auto conn = cfp::ClientSocket{port};
-  if (!conn.valid()) {
-    LOG(FATAL) << "couldn't connect on port " << port;
-  }
-  return conn;
-}
-
-std::tuple<std::uint16_t, std::uint16_t> RecvHeader(cfp::ClientSocket* conn) {
-  // creating variables because these must be received in order
-  auto num_channels = conn->RecvUInt16();
-  auto frame_rate = conn->RecvUInt16();
-  LOG(INFO) << "\nnum_channels: " << num_channels
-            << "\nframe_rate: " << frame_rate << '\n';
-  return {num_channels, frame_rate};
-}
-
-// Returns frame_size and encoded audio
-std::tuple<std::uint32_t, std::vector<unsigned char>> RecvEncodedAudio(
-    cfp::ClientSocket* conn) {
-  auto length = conn->RecvUInt32();
-  auto frame_size = conn->RecvUInt32();
-  auto encoded = conn->RecvAll(length);
-
-  if (encoded.size() < length) {
-    encoded.clear();
-  }
-  return {frame_size, std::move(encoded)};
-}
-
-void PlayDecodedAudio(cfp::SDLAudioDevice* audio_device,
-                      const std::vector<opus_int16>& audio) {
-  auto sz = audio.size() * sizeof audio[0];
-  auto ret = audio_device->QueueAudio(audio.data(), sz);
-  if (ret < 0) {
-    LOG(ERROR) << "failed to queue audio: " << SDL_GetError() << '\n';
-  }
-}
-
-}  // namespace
-
-int main(int argc, char* argv[]) {
-  ::google::InitGoogleLogging(argv[0]);
-  ::gflags::ParseCommandLineFlags(&argc, &argv, true);
-  cfp::SDLLib sdl{};
-
-  auto conn = Connect();
-  const auto& [num_channels, frame_rate] = RecvHeader(&conn);
-
-  auto audio_device = sdl.OpenAudioDevice(frame_rate, num_channels);
-  auto dec =
-      opus::Decoder{static_cast<std::uint32_t>(frame_rate), num_channels};
-  CHECK(dec.valid()) << "Could not construct Decoder. Maybe bad frame_rate ("
-                     << frame_rate <<") or num_channels (" << num_channels
-                     << ")?";
-
-  while (true) {
-    CHECK(dec.valid()) << "decoder in invalid state";
-    const auto& [frame_size, encoded] = RecvEncodedAudio(&conn);
-    if (encoded.empty()) {
-      break;
-    }
-    auto decoded = dec.Decode(encoded, frame_size, false);
-    if (decoded.empty()) {
-      break;
-    }
-    PlayDecodedAudio(&audio_device, decoded);
-  }
-}
diff --git a/tools/play_audio/sdl_wrapper.cpp b/tools/play_audio/sdl_wrapper.cpp
deleted file mode 100644
index 11f76df..0000000
--- a/tools/play_audio/sdl_wrapper.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *
- * Copyright (C) 2018 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.
- */
-
-#include "sdl_wrapper.h"
-
-#include "glog/logging.h"
-#include <SDL2/SDL.h>
-
-#include <cstdint>
-
-using cfp::SDLAudioDevice;
-using cfp::SDLLib;
-
-SDLAudioDevice::SDLAudioDevice(SDLAudioDevice&& other)
-    : device_id_{other.device_id_} {
-  other.device_id_ = 0;
-}
-SDLAudioDevice& SDLAudioDevice::operator=(SDLAudioDevice&& other) {
-  close();
-  device_id_ = other.device_id_;
-  other.device_id_ = 0;
-  return *this;
-}
-
-SDLAudioDevice::~SDLAudioDevice() { close(); }
-
-int SDLAudioDevice::QueueAudio(const void* data, std::uint32_t len) {
-  return SDL_QueueAudio(device_id_, data, len);
-}
-
-SDLAudioDevice::SDLAudioDevice(SDL_AudioDeviceID device_id)
-    : device_id_{device_id} {}
-
-void SDLAudioDevice::close() {
-  if (device_id_ != 0) {
-    SDL_CloseAudioDevice(device_id_);
-  }
-}
-
-SDLLib::SDLLib() { SDL_Init(SDL_INIT_AUDIO); }
-SDLLib::~SDLLib() { SDL_Quit(); }
-
-SDLAudioDevice SDLLib::OpenAudioDevice(int freq, std::uint8_t num_channels) {
-  SDL_AudioSpec wav_spec{};
-  wav_spec.freq = freq;
-  wav_spec.format = AUDIO_S16LSB;
-  wav_spec.channels = num_channels;
-  wav_spec.silence = 0;
-  // .samples seems to work as low as 256,
-  // docs say this is 4096 when used with SDL_LoadWAV so I'm sticking with
-  // that
-  wav_spec.samples = 4096;
-  wav_spec.size = 0;
-
-  auto audio_device_id = SDL_OpenAudioDevice(nullptr, 0, &wav_spec, nullptr, 0);
-  if (audio_device_id == 0) {
-    LOG(FATAL) << "failed to open audio device: " << SDL_GetError() << '\n';
-  }
-  SDL_PauseAudioDevice(audio_device_id, false);
-  return SDLAudioDevice{audio_device_id};
-}
diff --git a/tools/play_audio/sdl_wrapper.h b/tools/play_audio/sdl_wrapper.h
deleted file mode 100644
index 9be1df5..0000000
--- a/tools/play_audio/sdl_wrapper.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright (C) 2018 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.
- */
-#include <SDL2/SDL.h>
-#include <cstdint>
-
-namespace cfp {
-
-class SDLLib;
-
-class SDLAudioDevice {
- public:
-  SDLAudioDevice(SDLAudioDevice&& other);
-  SDLAudioDevice& operator=(SDLAudioDevice&& other);
-
-  SDLAudioDevice(const SDLAudioDevice&) = delete;
-  SDLAudioDevice& operator=(const SDLAudioDevice&) = delete;
-
-  ~SDLAudioDevice();
-
-  int QueueAudio(const void* data, std::uint32_t len);
-
- private:
-  friend SDLLib;
-  explicit SDLAudioDevice(SDL_AudioDeviceID device_id);
-  void close();
-
-  SDL_AudioDeviceID device_id_{};
-};
-
-class SDLLib {
- public:
-  SDLLib();
-  ~SDLLib();
-
-  SDLLib(const SDLLib&) = delete;
-  SDLLib& operator=(const SDLLib&) = delete;
-
-  SDLAudioDevice OpenAudioDevice(int freq, std::uint8_t num_channels);
-};
-
-}  // namespace cfp
diff --git a/tools/upload_to_gce_and_run.py b/tools/upload_to_gce_and_run.py
index f9e796c..f4dc4b8 100755
--- a/tools/upload_to_gce_and_run.py
+++ b/tools/upload_to_gce_and_run.py
@@ -19,11 +19,14 @@
   dir = os.getcwd()
   try:
     os.chdir(args.image_dir)
-    images = glob.glob('*.img')
-    if len(images) == 0:
+    artifacts = []
+    artifact_patterns = ['*.img', 'bootloader']
+    for artifact_pattern in artifact_patterns:
+      artifacts.extend(glob.glob(artifact_pattern))
+    if len(artifacts) == 0:
       raise OSError('No images found in: %s' + args.image_dir)
     subprocess.check_call(
-        'tar -c -f - --lzop -S ' + ' '.join(images) +
+        'tar -c -f - --lzop -S ' + ' '.join(artifacts) +
         ' | ' +
         gcloud_ssh(args) + '-- tar -x -f - --lzop -S',
         shell=True)
@@ -55,13 +58,20 @@
       shell=True)
 
 
+def __get_default_hostdir():
+  soong_host_dir = os.environ.get('ANDROID_SOONG_HOST_OUT')
+  if soong_host_dir:
+    return soong_host_dir
+  return os.environ.get('ANDROID_HOST_OUT', '.')
+
+
 def main():
   parser = argparse.ArgumentParser(
       description='Upload a local build to Google Compute Engine and run it')
   parser.add_argument(
       '-host_dir',
       type=str,
-      default=os.environ.get('ANDROID_HOST_OUT', '.'),
+      default=__get_default_hostdir(),
       help='path to the dist directory')
   parser.add_argument(
       '-image_dir',
@@ -75,7 +85,7 @@
       '-zone', type=str, default=None,
       help='zone containing the instance')
   parser.add_argument(
-      '-user', type=str, default='vsoc-01',
+      '-user', type=str, default=os.environ.get('USER', 'vsoc-01'),
       help='user to update on the instance')
   parser.add_argument(
       '-data-image', type=str, default=None,
diff --git a/tools/upload_via_ssh.py b/tools/upload_via_ssh.py
index c20a57f..5359473 100755
--- a/tools/upload_via_ssh.py
+++ b/tools/upload_via_ssh.py
@@ -12,7 +12,7 @@
   dir = os.getcwd()
   try:
     os.chdir(args.image_dir)
-    images = glob.glob('*.img')
+    images = glob.glob('*.img') + ["bootloader"]
     if len(images) == 0:
       raise OSError('File not found: ' + args.image_dir + '/*.img')
     subprocess.check_call(
@@ -58,8 +58,8 @@
   parser.add_argument(
       '-host_dir',
       type=str,
-      default=os.environ.get('ANDROID_HOST_OUT', '.'),
-      help='path to the dist directory')
+      default=os.environ.get('ANDROID_SOONG_HOST_OUT', '.'),
+      help='path to soong host out directory')
   parser.add_argument(
       '-image_dir',
       type=str,
diff --git a/vsoc_arm64/BoardConfig.mk b/vsoc_arm64/BoardConfig.mk
index 32090f5..bc016a8 100644
--- a/vsoc_arm64/BoardConfig.mk
+++ b/vsoc_arm64/BoardConfig.mk
@@ -15,7 +15,7 @@
 #
 
 #
-# x86 target for Cuttlefish
+# arm64 target for Cuttlefish
 #
 
 -include device/google/cuttlefish/shared/BoardConfig.mk
@@ -32,7 +32,10 @@
 TARGET_2ND_CPU_VARIANT := cortex-a53
 TARGET_TRANSLATE_2ND_ARCH := false
 
-BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard device/google/cuttlefish_kernel/5.4-arm64/*.ko)
+ifeq ($(BOARD_VENDOR_RAMDISK_KERNEL_MODULES),)
+    BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard kernel/prebuilts/common-modules/virtual-device/$(TARGET_KERNEL_USE)/arm64/*.ko)
+endif
 
-# TODO(b/149410031): temporarily exclude sdcardfs
-BOARD_VENDOR_RAMDISK_KERNEL_MODULES := $(filter-out %/sdcardfs.ko,$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES))
+HOST_CROSS_OS := linux_bionic
+HOST_CROSS_ARCH := arm64
+HOST_CROSS_2ND_ARCH :=
diff --git a/vsoc_arm64/auto/aosp_cf.mk b/vsoc_arm64/auto/aosp_cf.mk
index 2d311db..51ae7a3 100644
--- a/vsoc_arm64/auto/aosp_cf.mk
+++ b/vsoc_arm64/auto/aosp_cf.mk
@@ -14,11 +14,15 @@
 # limitations under the License.
 #
 
-$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit_only.mk)
 $(call inherit-product, device/google/cuttlefish/shared/auto/device.mk)
-$(call inherit-product, device/google/cuttlefish/vsoc_arm64/device.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_arm64/kernel.mk)
 
 PRODUCT_NAME := aosp_cf_arm64_auto
 PRODUCT_DEVICE := vsoc_arm64
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish arm64 auto
-DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/vsoc_arm64/auto/overlay
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_arm64/auto/overlay/frameworks/base/core/res/res/values/config.xml b/vsoc_arm64/auto/overlay/frameworks/base/core/res/res/values/config.xml
deleted file mode 100644
index b3a4b68..0000000
--- a/vsoc_arm64/auto/overlay/frameworks/base/core/res/res/values/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2018, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <!-- Enable multi-user. -->
-  <bool name="config_enableMultiUserUI" translatable="false">true</bool>
-  <!-- If true, all guest users created on the device will be ephemeral. -->
-  <bool name="config_guestUserEphemeral" translatable="false">true</bool>
-  <!--  Maximum number of users allowed on the device. -->
-  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
-</resources>
diff --git a/vsoc_arm64/bootloader.mk b/vsoc_arm64/bootloader.mk
new file mode 100644
index 0000000..a5aea94
--- /dev/null
+++ b/vsoc_arm64/bootloader.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+TARGET_NO_BOOTLOADER := false
+# FIXME: Copying the QEMU bootloader for now, but this should be updated..
+BOARD_PREBUILT_BOOTLOADER := \
+    device/google/cuttlefish_prebuilts/bootloader/crosvm_aarch64/u-boot.bin
+PRODUCT_COPY_FILES += \
+    device/google/cuttlefish_prebuilts/bootloader/qemu_aarch64/u-boot.bin:bootloader.qemu
diff --git a/vsoc_arm64/device.mk b/vsoc_arm64/device.mk
deleted file mode 100644
index ea7d2dc..0000000
--- a/vsoc_arm64/device.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2019 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.
-
-PRODUCT_COPY_FILES += device/google/cuttlefish_kernel/5.4-arm64/kernel:kernel
diff --git a/vsoc_arm64/kernel.mk b/vsoc_arm64/kernel.mk
new file mode 100644
index 0000000..c27f7cb
--- /dev/null
+++ b/vsoc_arm64/kernel.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2019 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.
+
+TARGET_KERNEL_USE ?= 5.10
+
+PRODUCT_COPY_FILES += kernel/prebuilts/$(TARGET_KERNEL_USE)/arm64/kernel-$(TARGET_KERNEL_USE):kernel
diff --git a/vsoc_arm64/phone/aosp_cf.mk b/vsoc_arm64/phone/aosp_cf.mk
index ce1947f..b33e523 100644
--- a/vsoc_arm64/phone/aosp_cf.mk
+++ b/vsoc_arm64/phone/aosp_cf.mk
@@ -18,7 +18,7 @@
 # All components inherited here go to system image (same as GSI system)
 #
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
 
@@ -38,14 +38,20 @@
 #
 $(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
 
+# Nested virtualization support
+$(call inherit-product, packages/modules/Virtualization/apex/product_packages.mk)
+
 #
 # Special settings for the target
 #
-DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/vsoc_arm64/phone/overlay
-
-$(call inherit-product, device/google/cuttlefish/vsoc_arm64/device.mk)
-
+$(call inherit-product, device/google/cuttlefish/vsoc_arm64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_arm64/bootloader.mk)
 
 PRODUCT_NAME := aosp_cf_arm64_phone
 PRODUCT_DEVICE := vsoc_arm64
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish arm64 phone
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_arm64/phone/overlay/frameworks/base/core/res/res/values/config.xml b/vsoc_arm64/phone/overlay/frameworks/base/core/res/res/values/config.xml
deleted file mode 100644
index 5455fd4..0000000
--- a/vsoc_arm64/phone/overlay/frameworks/base/core/res/res/values/config.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="networkAttributes" translatable="false">
-    <item>"mobile,0,0,0,-1,true"</item>
-    <item>"wifi,1,1,1,-1,true"</item>
-    <item>"mobile_mms,2,0,2,60000,true"</item>
-    <item>"mobile_hipri,5,0,3,60000,true"</item>
-    <item>"bluetooth,7,7,2,-1,true"</item>
-  </string-array>
-  <string-array name="radioAttributes" translatable="false">
-    <item>"0,1"</item>
-    <item>"1,1"</item>
-    <item>"4,1"</item>
-    <item>"7,1"</item>
-    <item>"11,1"</item>
-  </string-array>
-  <string-array name="config_tether_wifi_regexs" translatable="false">
-    <item>"wlan0"</item>
-  </string-array>
-  <string-array name="config_tether_apndata" translatable="false">
-    <item>Android,android,,,,,,,,311,740,,default,dun,ims</item>
-  </string-array>
-  <bool name="config_bluetooth_address_validation" translatable="false">true</bool>
-  <bool name="config_sms_capable" translatable="false">true</bool>
-  <string name="default_sms_application" translatable="false">com.android.mms</string>
-  <bool name="config_showNavigationBar" translatable="false">true</bool>
-  <dimen name="config_viewConfigurationTouchSlop" translatable="false">12dp</dimen>
-  <integer name="config_mobile_mtu" translatable="false">1460</integer>
-  <!--  Maximum number of supported users -->
-  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
-</resources>
diff --git a/vsoc_arm64_only/BoardConfig.mk b/vsoc_arm64_only/BoardConfig.mk
new file mode 100644
index 0000000..b5a1340
--- /dev/null
+++ b/vsoc_arm64_only/BoardConfig.mk
@@ -0,0 +1,34 @@
+#
+# Copyright 2017 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.
+#
+
+#
+# arm64 (64-bit only) target for Cuttlefish
+#
+
+-include device/google/cuttlefish/shared/BoardConfig.mk
+
+TARGET_BOARD_PLATFORM := vsoc_arm64
+TARGET_ARCH := arm64
+TARGET_ARCH_VARIANT := armv8-a
+TARGET_CPU_ABI := arm64-v8a
+TARGET_CPU_VARIANT := cortex-a53
+
+AUDIOSERVER_MULTILIB := first
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard kernel/prebuilts/common-modules/virtual-device/5.10/arm64/*.ko)
+
+HOST_CROSS_OS := linux_bionic
+HOST_CROSS_ARCH := arm64
+HOST_CROSS_2ND_ARCH :=
diff --git a/vsoc_arm64_only/phone/aosp_cf.mk b/vsoc_arm64_only/phone/aosp_cf.mk
new file mode 100644
index 0000000..6de27b6
--- /dev/null
+++ b/vsoc_arm64_only/phone/aosp_cf.mk
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2019 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.
+#
+
+#
+# All components inherited here go to system image (same as GSI system)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit_only.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
+
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
+
+#
+# All components inherited here go to system_ext image (same as GSI system_ext)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system_ext.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system_ext.mk)
+
+#
+# All components inherited here go to product image (same as GSI product)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_product.mk)
+
+#
+# All components inherited here go to vendor image
+#
+LOCAL_DISABLE_OMX := true
+$(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
+
+# Nested virtualization support
+$(call inherit-product, packages/modules/Virtualization/apex/product_packages.mk)
+
+#
+# Special settings for the target
+#
+$(call inherit-product, device/google/cuttlefish/vsoc_arm64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_arm64/bootloader.mk)
+
+# Exclude features that are not available on AOSP devices.
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/aosp_excluded_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/aosp_excluded_hardware.xml
+
+PRODUCT_NAME := aosp_cf_arm64_only_phone
+PRODUCT_DEVICE := vsoc_arm64_only
+PRODUCT_MANUFACTURER := Google
+PRODUCT_MODEL := Cuttlefish arm64 phone (64-bit only)
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_arm_only/BoardConfig.mk b/vsoc_arm_only/BoardConfig.mk
new file mode 100644
index 0000000..e0cb5ce
--- /dev/null
+++ b/vsoc_arm_only/BoardConfig.mk
@@ -0,0 +1,34 @@
+#
+# Copyright 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.
+#
+
+#
+# arm (32-bit only) target for Cuttlefish
+#
+
+-include device/google/cuttlefish/shared/BoardConfig.mk
+
+TARGET_BOARD_PLATFORM := vsoc_arm
+TARGET_ARCH := arm
+TARGET_ARCH_VARIANT := armv7-a-neon
+TARGET_CPU_ABI := armeabi-v7a
+TARGET_CPU_ABI2 := armeabi
+TARGET_CPU_VARIANT := cortex-a15
+
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard device/google/cuttlefish_prebuilts/kernel/5.4-arm/*.ko)
+
+HOST_CROSS_OS := linux_bionic
+HOST_CROSS_ARCH := arm64
+HOST_CROSS_2ND_ARCH :=
diff --git a/vsoc_arm_only/bootloader.mk b/vsoc_arm_only/bootloader.mk
new file mode 100644
index 0000000..93de14e
--- /dev/null
+++ b/vsoc_arm_only/bootloader.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+TARGET_NO_BOOTLOADER := false
+# FIXME: Copying the QEMU bootloader for now, but this should be updated..
+BOARD_PREBUILT_BOOTLOADER := \
+    device/google/cuttlefish_prebuilts/bootloader/qemu_arm/u-boot.bin
+PRODUCT_COPY_FILES += \
+    device/google/cuttlefish_prebuilts/bootloader/qemu_arm/u-boot.bin:bootloader.qemu
diff --git a/vsoc_arm_only/kernel.mk b/vsoc_arm_only/kernel.mk
new file mode 100644
index 0000000..50b4e0b
--- /dev/null
+++ b/vsoc_arm_only/kernel.mk
@@ -0,0 +1,16 @@
+#
+# 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.
+
+PRODUCT_COPY_FILES += device/google/cuttlefish_prebuilts/kernel/5.4-arm/kernel-5.4:kernel
diff --git a/vsoc_arm_only/phone/aosp_cf.mk b/vsoc_arm_only/phone/aosp_cf.mk
new file mode 100644
index 0000000..0045506
--- /dev/null
+++ b/vsoc_arm_only/phone/aosp_cf.mk
@@ -0,0 +1,71 @@
+#
+# 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.
+#
+
+#
+# All components inherited here go to system image (same as GSI system)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
+
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
+
+#
+# All components inherited here go to system_ext image (same as GSI system_ext)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system_ext.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system_ext.mk)
+
+#
+# All components inherited here go to product image (same as GSI product)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_product.mk)
+PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS := false
+
+#
+# FIXME: Set up Go defaults because we are currently limited (by a U-Boot bug)
+#        to 512MB of RAM
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/go_defaults_512.mk)
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
+    system/apex/com.android.tethering.inprocess.apex \
+    system/apex/com.android.tethering.inprocess.capex \
+    system/app/PlatformCaptivePortalLogin/PlatformCaptivePortalLogin.apk \
+    system/priv-app/CellBroadcastServiceModulePlatform/CellBroadcastServiceModulePlatform.apk \
+    system/priv-app/InProcessNetworkStack/InProcessNetworkStack.apk \
+    system/priv-app/PlatformNetworkPermissionConfig/PlatformNetworkPermissionConfig.apk \
+
+#
+# All components inherited here go to vendor image
+#
+$(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
+
+#
+# Special settings for the target
+#
+$(call inherit-product, device/google/cuttlefish/vsoc_arm_only/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_arm_only/bootloader.mk)
+
+# Exclude features that are not available on AOSP devices.
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/aosp_excluded_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/aosp_excluded_hardware.xml
+
+PRODUCT_NAME := aosp_cf_arm_only_phone
+PRODUCT_DEVICE := vsoc_arm_only
+PRODUCT_MANUFACTURER := Google
+PRODUCT_MODEL := Cuttlefish arm phone (32-bit only)
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86/BoardConfig.mk b/vsoc_x86/BoardConfig.mk
index f12dc70..70db8c2 100644
--- a/vsoc_x86/BoardConfig.mk
+++ b/vsoc_x86/BoardConfig.mk
@@ -31,7 +31,12 @@
 TARGET_NATIVE_BRIDGE_ABI := armeabi-v7a armeabi
 
 BUILD_BROKEN_DUP_RULES := true
-BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard device/google/cuttlefish_kernel/5.4-x86_64/*.ko)
 
-# TODO(b/149410031): temporarily exclude sdcardfs
-BOARD_VENDOR_RAMDISK_KERNEL_MODULES := $(filter-out %/sdcardfs.ko,$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES))
+ifeq ($(BOARD_VENDOR_RAMDISK_KERNEL_MODULES),)
+    BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard kernel/prebuilts/common-modules/virtual-device/5.10/x86-64/*.ko)
+endif
+
+# TODO(b/156534160): Temporarily allow for the old style PRODUCT_COPY_FILES for ndk_translation_prebuilt
+ifeq ($(USE_NDK_TRANSLATION_BINARY),true)
+BUILD_BROKEN_ELF_PREBUILT_PRODUCT_COPY_FILES := true
+endif
diff --git a/vsoc_x86/auto/device.mk b/vsoc_x86/auto/device.mk
index 88399b8..c3ccba3 100644
--- a/vsoc_x86/auto/device.mk
+++ b/vsoc_x86/auto/device.mk
@@ -15,14 +15,18 @@
 #
 
 $(call inherit-product, device/google/cuttlefish/shared/auto/device.mk)
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/device.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
 
 PRODUCT_NAME := aosp_cf_x86_auto
 PRODUCT_DEVICE := vsoc_x86
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86 auto
-PRODUCT_PACKAGE_OVERLAYS += device/google/cuttlefish/vsoc_x86/auto/overlay
-
 
 # Whitelisted packages per user type
 PRODUCT_COPY_FILES += \
     device/google/cuttlefish/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/sysconfig/preinstalled-packages-product-car-cuttlefish.xml
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86/auto/overlay/frameworks/base/core/res/res/values/config.xml b/vsoc_x86/auto/overlay/frameworks/base/core/res/res/values/config.xml
deleted file mode 100644
index b3a4b68..0000000
--- a/vsoc_x86/auto/overlay/frameworks/base/core/res/res/values/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2018, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <!-- Enable multi-user. -->
-  <bool name="config_enableMultiUserUI" translatable="false">true</bool>
-  <!-- If true, all guest users created on the device will be ephemeral. -->
-  <bool name="config_guestUserEphemeral" translatable="false">true</bool>
-  <!--  Maximum number of users allowed on the device. -->
-  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
-</resources>
diff --git a/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml b/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
index 1536291..aef6dcc 100644
--- a/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
+++ b/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
@@ -71,11 +71,30 @@
         <install-in user-type="FULL" />
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
+    <!-- Required for Tethering -->
+    <install-in-user-type package="com.android.networkstack.tethering">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.connectivity.resources">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+    <!-- Required for Wifi -->
+    <install-in-user-type package="com.android.networkstack.inprocess">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
     <!-- Required when sysui queries for system user apps to handle the home intent -->
     <install-in-user-type package="com.android.car.carlauncher">
         <install-in user-type="FULL" />
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
+    <!-- Required when using Camera2 extensions -->
+    <install-in-user-type package="com.android.camera">
+        <install-in user-type="SYSTEM" />
+        <install-in user-type="FULL" />
+    </install-in-user-type>
 
 <!--
   Apps that do need to run on SYSTEM and evaluated by package owner.
@@ -129,106 +148,19 @@
     <install-in-user-type package="com.android.car.themeplayground">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.amethyst">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.aquamarine">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.black">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.tangerine">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.cinnamon">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.green">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.ocean">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.space">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.orchid">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.color.purple">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.font.notoserifsource">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon.pebble">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon.roundedrect">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon.squircle">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon.taperedrect">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon.teardrop">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon.vessel">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.circular.android">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.circular.launcher">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.circular.settings">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.circular.systemui">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.circular.themepicker">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.filled.android">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.filled.launcher">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.filled.settings">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.filled.systemui">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.filled.themepicker">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.rounded.android">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.rounded.launcher">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.rounded.settings">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.rounded.systemui">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
     <install-in-user-type package="com.android.car.linkviewer">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.car.retaildemo">
+    <install-in-user-type package="com.android.car.multidisplay">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.car.voicecontrol">
+      <install-in-user-type package="com.android.car.voicecontrol">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.google.android.car.multidisplaytest">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.car.retaildemo">
         <install-in user-type="FULL" />
     </install-in-user-type>
     <install-in-user-type package="com.android.documentsui">
@@ -246,17 +178,10 @@
     <install-in-user-type package="com.google.android.apps.geo.autograph.vms.client.systemstate">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.theme.icon_pack.rounded.themepicker">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
-    <install-in-user-type package="com.android.networkstack.tethering">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
     <install-in-user-type package="com.android.smspush">
         <install-in user-type="FULL" />
     </install-in-user-type>
     <install-in-user-type package="com.android.angle">
         <install-in user-type="FULL" />
     </install-in-user-type>
-
 </config>
diff --git a/vsoc_x86/device.mk b/vsoc_x86/device.mk
deleted file mode 100644
index 784cfdc..0000000
--- a/vsoc_x86/device.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2019 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.
-
-PRODUCT_COPY_FILES += device/google/cuttlefish_kernel/5.4-x86_64/kernel:kernel
diff --git a/vsoc_x86/go_512_phone/device.mk b/vsoc_x86/go_512_phone/device.mk
index b33d06e..2df9023 100644
--- a/vsoc_x86/go_512_phone/device.mk
+++ b/vsoc_x86/go_512_phone/device.mk
@@ -15,9 +15,14 @@
 #
 
 $(call inherit-product, device/google/cuttlefish/shared/go_512/device.mk)
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/phone/device.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
 
 PRODUCT_NAME := aosp_cf_x86_go_512_phone
 PRODUCT_DEVICE := vsoc_x86
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86 Go 512 phone
 PRODUCT_PACKAGE_OVERLAYS := device/google/cuttlefish/vsoc_x86/phone/overlay
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86/go_phone/device.mk b/vsoc_x86/go_phone/device.mk
index b61edc5..8b2a8f3 100644
--- a/vsoc_x86/go_phone/device.mk
+++ b/vsoc_x86/go_phone/device.mk
@@ -15,10 +15,14 @@
 #
 
 $(call inherit-product, device/google/cuttlefish/shared/go/device.mk)
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/phone/device.mk)
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/device.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
 
 PRODUCT_NAME := aosp_cf_x86_go_phone
 PRODUCT_DEVICE := vsoc_x86
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86 Go phone
 PRODUCT_PACKAGE_OVERLAYS := device/google/cuttlefish/vsoc_x86/phone/overlay
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86/pasan/aosp_cf.mk b/vsoc_x86/pasan/aosp_cf.mk
index e6b2adc..d4c8d57 100644
--- a/vsoc_x86/pasan/aosp_cf.mk
+++ b/vsoc_x86/pasan/aosp_cf.mk
@@ -17,7 +17,7 @@
 #
 # All components inherited here go to system image (same as GSI system)
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
 
@@ -40,11 +40,18 @@
 #
 # Special settings for the target
 #
-DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/vsoc_x86/phone/overlay
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
 
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/device.mk)
-
+# Exclude features that are not available on AOSP devices.
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/aosp_excluded_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/aosp_excluded_hardware.xml
 
 PRODUCT_NAME := aosp_cf_x86_pasan
 PRODUCT_DEVICE := vsoc_x86
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86 phone
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86/phone/aosp_cf.mk b/vsoc_x86/phone/aosp_cf.mk
index 2d75b08..3e6ec6b 100644
--- a/vsoc_x86/phone/aosp_cf.mk
+++ b/vsoc_x86/phone/aosp_cf.mk
@@ -17,7 +17,7 @@
 #
 # All components inherited here go to system image (same as GSI system)
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
 
@@ -40,9 +40,8 @@
 #
 # Special settings for the target
 #
-DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/vsoc_x86/phone/overlay
-
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/device.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
 
 # Exclude features that are not available on AOSP devices.
 PRODUCT_COPY_FILES += \
@@ -50,4 +49,9 @@
 
 PRODUCT_NAME := aosp_cf_x86_phone
 PRODUCT_DEVICE := vsoc_x86
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86 phone
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86/phone/device.mk b/vsoc_x86/phone/device.mk
deleted file mode 100644
index a3caa19..0000000
--- a/vsoc_x86/phone/device.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-$(call inherit-product, device/google/cuttlefish/shared/phone/device.mk)
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/device.mk)
-
-PRODUCT_NAME := aosp_cf_x86_phone
-PRODUCT_DEVICE := vsoc_x86
-PRODUCT_MODEL := Cuttlefish x86 phone
-PRODUCT_PACKAGE_OVERLAYS := device/google/cuttlefish/vsoc_x86/phone/overlay
diff --git a/vsoc_x86/phone/overlay/frameworks/base/core/res/res/values/config.xml b/vsoc_x86/phone/overlay/frameworks/base/core/res/res/values/config.xml
deleted file mode 100644
index 5455fd4..0000000
--- a/vsoc_x86/phone/overlay/frameworks/base/core/res/res/values/config.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="networkAttributes" translatable="false">
-    <item>"mobile,0,0,0,-1,true"</item>
-    <item>"wifi,1,1,1,-1,true"</item>
-    <item>"mobile_mms,2,0,2,60000,true"</item>
-    <item>"mobile_hipri,5,0,3,60000,true"</item>
-    <item>"bluetooth,7,7,2,-1,true"</item>
-  </string-array>
-  <string-array name="radioAttributes" translatable="false">
-    <item>"0,1"</item>
-    <item>"1,1"</item>
-    <item>"4,1"</item>
-    <item>"7,1"</item>
-    <item>"11,1"</item>
-  </string-array>
-  <string-array name="config_tether_wifi_regexs" translatable="false">
-    <item>"wlan0"</item>
-  </string-array>
-  <string-array name="config_tether_apndata" translatable="false">
-    <item>Android,android,,,,,,,,311,740,,default,dun,ims</item>
-  </string-array>
-  <bool name="config_bluetooth_address_validation" translatable="false">true</bool>
-  <bool name="config_sms_capable" translatable="false">true</bool>
-  <string name="default_sms_application" translatable="false">com.android.mms</string>
-  <bool name="config_showNavigationBar" translatable="false">true</bool>
-  <dimen name="config_viewConfigurationTouchSlop" translatable="false">12dp</dimen>
-  <integer name="config_mobile_mtu" translatable="false">1460</integer>
-  <!--  Maximum number of supported users -->
-  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
-</resources>
diff --git a/vsoc_x86/tv/device.mk b/vsoc_x86/tv/device.mk
index 7689ee3..b65f50c 100644
--- a/vsoc_x86/tv/device.mk
+++ b/vsoc_x86/tv/device.mk
@@ -15,9 +15,14 @@
 #
 
 $(call inherit-product, device/google/cuttlefish/shared/tv/device.mk)
-$(call inherit-product, device/google/cuttlefish/vsoc_x86/device.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
 
 PRODUCT_NAME := aosp_cf_x86_tv
 PRODUCT_DEVICE := vsoc_x86
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86 tv
-# PRODUCT_PACKAGE_OVERLAYS := device/google/cuttlefish/vsoc_x86/tv/overlay
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86_64/BoardConfig.mk b/vsoc_x86_64/BoardConfig.mk
index 9c2cbfe..52dde5c 100644
--- a/vsoc_x86_64/BoardConfig.mk
+++ b/vsoc_x86_64/BoardConfig.mk
@@ -41,7 +41,7 @@
 TARGET_NATIVE_BRIDGE_2ND_ABI := armeabi-v7a armeabi
 
 BUILD_BROKEN_DUP_RULES := true
-BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard device/google/cuttlefish_kernel/5.4-x86_64/*.ko)
 
-# TODO(b/149410031): temporarily exclude sdcardfs
-BOARD_VENDOR_RAMDISK_KERNEL_MODULES := $(filter-out %/sdcardfs.ko,$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES))
+ifeq ($(BOARD_VENDOR_RAMDISK_KERNEL_MODULES),)
+    BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard kernel/prebuilts/common-modules/virtual-device/$(TARGET_KERNEL_USE)/x86-64/*.ko)
+endif
diff --git a/vsoc_x86_64/auto/OWNERS b/vsoc_x86_64/auto/OWNERS
new file mode 100644
index 0000000..1b990ef
--- /dev/null
+++ b/vsoc_x86_64/auto/OWNERS
@@ -0,0 +1,5 @@
+# Android Auto leads
+ankitarora@google.com
+egranata@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/vsoc_x86_64/auto/device.mk b/vsoc_x86_64/auto/device.mk
new file mode 100644
index 0000000..b21f694
--- /dev/null
+++ b/vsoc_x86_64/auto/device.mk
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit_only.mk)
+$(call inherit-product, device/google/cuttlefish/shared/auto/device.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
+
+PRODUCT_NAME := aosp_cf_x86_64_auto
+PRODUCT_DEVICE := vsoc_x86_64
+PRODUCT_MANUFACTURER := Google
+PRODUCT_MODEL := Cuttlefish x86_64 auto
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86_64/bootloader.mk b/vsoc_x86_64/bootloader.mk
new file mode 100644
index 0000000..b0d8c5d
--- /dev/null
+++ b/vsoc_x86_64/bootloader.mk
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+TARGET_NO_BOOTLOADER := false
+BOARD_PREBUILT_BOOTLOADER := \
+    device/google/cuttlefish_prebuilts/bootloader/crosvm_x86_64/u-boot.rom
+PRODUCT_COPY_FILES += \
+    device/google/cuttlefish_prebuilts/bootloader/qemu_x86_64/u-boot.rom:bootloader.qemu
diff --git a/vsoc_x86_64/device.mk b/vsoc_x86_64/device.mk
deleted file mode 100644
index 784cfdc..0000000
--- a/vsoc_x86_64/device.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2019 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.
-
-PRODUCT_COPY_FILES += device/google/cuttlefish_kernel/5.4-x86_64/kernel:kernel
diff --git a/vsoc_x86_64/kernel.mk b/vsoc_x86_64/kernel.mk
new file mode 100644
index 0000000..5dded66
--- /dev/null
+++ b/vsoc_x86_64/kernel.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2019 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.
+
+TARGET_KERNEL_USE ?= 5.10
+
+PRODUCT_COPY_FILES += kernel/prebuilts/$(TARGET_KERNEL_USE)/x86_64/kernel-$(TARGET_KERNEL_USE):kernel
diff --git a/vsoc_x86_64/pc/OWNERS b/vsoc_x86_64/pc/OWNERS
new file mode 100644
index 0000000..47eb80e
--- /dev/null
+++ b/vsoc_x86_64/pc/OWNERS
@@ -0,0 +1,3 @@
+# pc cuttlefish leads
+armenk@google.com
+xutan@google.com
\ No newline at end of file
diff --git a/vsoc_x86_64/pc/aosp_cf.mk b/vsoc_x86_64/pc/aosp_cf.mk
new file mode 100644
index 0000000..1853785
--- /dev/null
+++ b/vsoc_x86_64/pc/aosp_cf.mk
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2019 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.
+#
+
+#
+# All components inherited here go to system image (same as GSI system)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
+
+#
+# All components inherited here go to system_ext image (same as GSI system_ext)a
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system_ext.mk)
+# $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system_ext.mk)
+
+#
+# All components inherited here go to product image (same as GSI product)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_product.mk)
+
+#
+# All components inherited here go to vendor image
+#
+$(call inherit-product, device/google/cuttlefish/shared/pc/device_vendor.mk)
+
+#
+# Special settings for the target
+#
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
+
+PRODUCT_NAME := aosp_cf_x86_64_pc
+PRODUCT_DEVICE := vsoc_x86_64
+PRODUCT_MANUFACTURER := Google
+PRODUCT_MODEL := Cuttlefish x86_64 pc
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86_64/phone/aosp_cf.mk b/vsoc_x86_64/phone/aosp_cf.mk
index 791a720..478452f 100644
--- a/vsoc_x86_64/phone/aosp_cf.mk
+++ b/vsoc_x86_64/phone/aosp_cf.mk
@@ -18,7 +18,7 @@
 # All components inherited here go to system image (same as GSI system)
 #
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
 
@@ -38,14 +38,24 @@
 #
 $(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
 
+# Nested virtualization support
+$(call inherit-product, packages/modules/Virtualization/apex/product_packages.mk)
+
 #
 # Special settings for the target
 #
-DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/vsoc_x86_64/phone/overlay
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
 
-$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/device.mk)
-
+# Exclude features that are not available on AOSP devices.
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/aosp_excluded_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/aosp_excluded_hardware.xml
 
 PRODUCT_NAME := aosp_cf_x86_64_phone
 PRODUCT_DEVICE := vsoc_x86_64
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86_64 phone
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86_64/phone/aosp_cf_foldable.mk b/vsoc_x86_64/phone/aosp_cf_foldable.mk
new file mode 100644
index 0000000..89b0ea3
--- /dev/null
+++ b/vsoc_x86_64/phone/aosp_cf_foldable.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2021 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.
+#
+
+# Inherit mostly from aosp_cf_x86_64_phone
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/phone/aosp_cf.mk)
+PRODUCT_NAME := aosp_cf_x86_64_foldable
+PRODUCT_MODEL := Cuttlefish x86_64 foldable
+
+# Include the device state configuration for a foldable device.
+PRODUCT_COPY_FILES += \
+    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.
+SOONG_CONFIG_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
diff --git a/vsoc_x86_64/phone/overlay/frameworks/base/core/res/res/values/config.xml b/vsoc_x86_64/phone/overlay/frameworks/base/core/res/res/values/config.xml
deleted file mode 100644
index 36184c8..0000000
--- a/vsoc_x86_64/phone/overlay/frameworks/base/core/res/res/values/config.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2011, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="networkAttributes" translatable="false">
-    <item>"mobile,0,0,0,-1,true"</item>
-    <item>"wifi,1,1,1,-1,true"</item>
-    <item>"mobile_mms,2,0,2,60000,true"</item>
-    <item>"mobile_hipri,5,0,3,60000,true"</item>
-    <item>"bluetooth,7,7,2,-1,true"</item>
-  </string-array>
-  <string-array name="radioAttributes" translatable="false">
-    <item>"0,1"</item>
-    <item>"1,1"</item>
-    <item>"4,1"</item>
-    <item>"7,1"</item>
-    <item>"11,1"</item>
-  </string-array>
-  <string-array name="config_tether_wifi_regexs" translatable="false">
-    <item>"wlan0"</item>
-  </string-array>
-  <string-array name="config_tether_apndata" translatable="false">
-    <item>Android,android,,,,,,,,302,780,,default,dun,ims</item>
-  </string-array>
-  <bool name="config_bluetooth_address_validation" translatable="false">true</bool>
-  <bool name="config_sms_capable" translatable="false">true</bool>
-  <string name="default_sms_application" translatable="false">com.android.mms</string>
-  <bool name="config_showNavigationBar" translatable="false">true</bool>
-  <dimen name="config_viewConfigurationTouchSlop" translatable="false">12dp</dimen>
-  <integer name="config_mobile_mtu" translatable="false">1460</integer>
-  <!--  Maximum number of supported users -->
-  <integer name="config_multiuserMaximumUsers" translatable="false">4</integer>
-</resources>
diff --git a/vsoc_x86_64_only/BoardConfig.mk b/vsoc_x86_64_only/BoardConfig.mk
new file mode 100644
index 0000000..d702533
--- /dev/null
+++ b/vsoc_x86_64_only/BoardConfig.mk
@@ -0,0 +1,35 @@
+#
+# Copyright 2017 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.
+#
+
+#
+# x86_64 (64-bit only) target for Cuttlefish
+#
+
+-include device/google/cuttlefish/shared/BoardConfig.mk
+
+TARGET_BOARD_PLATFORM := vsoc_x86_64
+TARGET_ARCH := x86_64
+TARGET_ARCH_VARIANT := silvermont
+TARGET_CPU_ABI := x86_64
+
+TARGET_NATIVE_BRIDGE_ARCH := arm64
+TARGET_NATIVE_BRIDGE_ARCH_VARIANT := armv8-a
+TARGET_NATIVE_BRIDGE_CPU_VARIANT := generic
+TARGET_NATIVE_BRIDGE_ABI := arm64-v8a
+
+AUDIOSERVER_MULTILIB := first
+BUILD_BROKEN_DUP_RULES := true
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard kernel/prebuilts/common-modules/virtual-device/5.10/x86-64/*.ko)
diff --git a/vsoc_x86_64_only/phone/aosp_cf.mk b/vsoc_x86_64_only/phone/aosp_cf.mk
new file mode 100644
index 0000000..9596d5a
--- /dev/null
+++ b/vsoc_x86_64_only/phone/aosp_cf.mk
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2019 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.
+#
+
+#
+# All components inherited here go to system image (same as GSI system)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit_only.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
+
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
+
+#
+# All components inherited here go to system_ext image (same as GSI system_ext)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system_ext.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system_ext.mk)
+
+#
+# All components inherited here go to product image (same as GSI product)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_product.mk)
+
+#
+# All components inherited here go to vendor image
+#
+LOCAL_DISABLE_OMX := true
+$(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
+
+# Nested virtualization support
+$(call inherit-product, packages/modules/Virtualization/apex/product_packages.mk)
+
+#
+# Special settings for the target
+#
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/kernel.mk)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
+
+# Exclude features that are not available on AOSP devices.
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/aosp_excluded_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/aosp_excluded_hardware.xml
+
+PRODUCT_NAME := aosp_cf_x86_64_only_phone
+PRODUCT_DEVICE := vsoc_x86_64_only
+PRODUCT_MANUFACTURER := Google
+PRODUCT_MODEL := Cuttlefish x86_64 phone (64-bit only)
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86_noapex/aosp_cf_noapex.mk b/vsoc_x86_noapex/aosp_cf_noapex.mk
index fcf7607..aa5d3b2 100644
--- a/vsoc_x86_noapex/aosp_cf_noapex.mk
+++ b/vsoc_x86_noapex/aosp_cf_noapex.mk
@@ -17,10 +17,15 @@
 # Order of this and the following statements is important.
 # Putting this first in the list takes precedence over the one inherited from
 # aosp_cf.
-PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=false
+OVERRIDE_TARGET_FLATTEN_APEX := true
 
 $(call inherit-product, device/google/cuttlefish/vsoc_x86/phone/aosp_cf.mk)
 
 PRODUCT_NAME := aosp_cf_x86_phone_noapex
 PRODUCT_DEVICE := vsoc_x86_noapex
+PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86 phone without APEX support
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86_only/BoardConfig.mk b/vsoc_x86_only/BoardConfig.mk
new file mode 100644
index 0000000..8703a10
--- /dev/null
+++ b/vsoc_x86_only/BoardConfig.mk
@@ -0,0 +1,28 @@
+#
+# Copyright 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.
+#
+
+#
+# x86 (32-bit kernel) target for Cuttlefish
+#
+
+-include device/google/cuttlefish/shared/BoardConfig.mk
+
+TARGET_BOARD_PLATFORM := vsoc_x86
+TARGET_ARCH := x86
+TARGET_ARCH_VARIANT := x86
+TARGET_CPU_ABI := x86
+
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard device/google/cuttlefish_prebuilts/kernel/$(TARGET_KERNEL_USE)-i686/*.ko)
diff --git a/vsoc_x86_only/kernel.mk b/vsoc_x86_only/kernel.mk
new file mode 100644
index 0000000..23cf086
--- /dev/null
+++ b/vsoc_x86_only/kernel.mk
@@ -0,0 +1,18 @@
+#
+# 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.
+
+TARGET_KERNEL_USE ?= 5.10
+
+PRODUCT_COPY_FILES += device/google/cuttlefish_prebuilts/kernel/$(TARGET_KERNEL_USE)-i686/kernel-$(TARGET_KERNEL_USE):kernel
diff --git a/vsoc_x86_only/phone/aosp_cf.mk b/vsoc_x86_only/phone/aosp_cf.mk
new file mode 100644
index 0000000..17324d4
--- /dev/null
+++ b/vsoc_x86_only/phone/aosp_cf.mk
@@ -0,0 +1,60 @@
+#
+# 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.
+#
+
+#
+# All components inherited here go to system image (same as GSI system)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
+
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
+
+#
+# All components inherited here go to system_ext image (same as GSI system_ext)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system_ext.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system_ext.mk)
+
+#
+# All components inherited here go to product image (same as GSI product)
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_product.mk)
+PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS := false
+
+#
+# All components inherited here go to vendor image
+#
+$(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
+
+#
+# Special settings for the target
+#
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_only/kernel.mk)
+# FIXME: For now, this uses the "64-bit" bootloader (for why, take a look at
+#        http://u-boot.10912.n7.nabble.com/64-bit-x86-U-Boot-td244620.html)
+$(call inherit-product, device/google/cuttlefish/vsoc_x86_64/bootloader.mk)
+
+# Exclude features that are not available on AOSP devices.
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/aosp_excluded_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/aosp_excluded_hardware.xml
+
+PRODUCT_NAME := aosp_cf_x86_only_phone
+PRODUCT_DEVICE := vsoc_x86_only
+PRODUCT_MANUFACTURER := Google
+PRODUCT_MODEL := Cuttlefish x86 phone (32-bit kernel)
+
+PRODUCT_VENDOR_PROPERTIES += \
+    ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
+    ro.soc.model=$(PRODUCT_DEVICE)