Create aosp_bramble target

Bug: 138083938
Bug: 137166127
Change-Id: I9c4c318e5c7942fed113131a90ad7a94fd3a8fa6
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..3463304
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+ColumnLimit: 99
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Right
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
+AllowShortIfStatementsOnASingleLine: false
+SpacesBeforeTrailingComments: 2
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..e69df8d
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,6 @@
+soong_namespace {
+    imports: [
+        "hardware/google/interfaces",
+        "hardware/google/pixel",
+    ],
+}
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..c764b3f
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(USES_DEVICE_GOOGLE_BRAMBLE),true)
+  subdir_makefiles=$(call first-makefiles-under,$(LOCAL_PATH))
+  $(foreach mk,$(subdir_makefiles),$(info including $(mk) ...)$(eval include $(mk)))
+endif
diff --git a/AndroidProducts.mk b/AndroidProducts.mk
new file mode 100644
index 0000000..1523d35
--- /dev/null
+++ b/AndroidProducts.mk
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+PRODUCT_MAKEFILES := \
+    $(LOCAL_DIR)/aosp_bramble.mk \
+
+COMMON_LUNCH_CHOICES := \
+    aosp_bramble-userdebug \
diff --git a/BoardConfig-common.mk b/BoardConfig-common.mk
new file mode 100644
index 0000000..afe13fe
--- /dev/null
+++ b/BoardConfig-common.mk
@@ -0,0 +1,262 @@
+#
+# 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 build/make/target/board/BoardConfigMainlineCommon.mk
+
+TARGET_BOARD_PLATFORM := lito
+TARGET_BOARD_INFO_FILE := device/google/bramble/board-info.txt
+USES_DEVICE_GOOGLE_BRAMBLE := true
+TARGET_ARCH := arm64
+TARGET_ARCH_VARIANT := armv8-2a
+TARGET_CPU_ABI := arm64-v8a
+TARGET_CPU_ABI2 :=
+TARGET_CPU_VARIANT := cortex-a76
+
+TARGET_2ND_ARCH := arm
+TARGET_2ND_ARCH_VARIANT := armv8-a
+TARGET_2ND_CPU_ABI := armeabi-v7a
+TARGET_2ND_CPU_ABI2 := armeabi
+TARGET_2ND_CPU_VARIANT := cortex-a76
+
+BUILD_BROKEN_ENG_DEBUG_TAGS := true
+
+TARGET_BOARD_COMMON_PATH := device/google/bramble/sm7250
+
+BOARD_KERNEL_CMDLINE += console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on
+BOARD_KERNEL_CMDLINE += msm_rtb.filter=0x237
+BOARD_KERNEL_CMDLINE += ehci-hcd.park=3
+BOARD_KERNEL_CMDLINE += service_locator.enable=1
+BOARD_KERNEL_CMDLINE += androidboot.memcg=1 cgroup.memory=nokmem
+BOARD_KERNEL_CMDLINE += lpm_levels.sleep_disabled=1 # STOPSHIP b/113233473
+BOARD_KERNEL_CMDLINE += usbcore.autosuspend=7
+BOARD_KERNEL_CMDLINE += androidboot.usbcontroller=a600000.dwc3 swiotlb=2048
+BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive # STOPSHIP b/113232677
+BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/1d84000.ufshc
+
+BOARD_KERNEL_BASE        := 0x00000000
+BOARD_KERNEL_PAGESIZE    := 4096
+
+BOARD_INCLUDE_DTB_IN_BOOTIMG := true
+BOARD_BOOT_HEADER_VERSION := 2
+BOARD_MKBOOTIMG_ARGS += --header_version $(BOARD_BOOT_HEADER_VERSION)
+
+# DTBO partition definitions
+BOARD_PREBUILT_DTBOIMAGE := device/google/bramble-kernel/dtbo.img
+BOARD_DTBOIMG_PARTITION_SIZE := 8388608
+
+TARGET_NO_KERNEL := false
+BOARD_USES_RECOVERY_AS_BOOT := true
+BOARD_USES_METADATA_PARTITION := true
+
+AB_OTA_UPDATER := true
+
+AB_OTA_PARTITIONS += \
+    boot \
+    system \
+    vbmeta \
+    dtbo \
+    product \
+    vbmeta_system
+
+# Partitions (listed in the file) to be wiped under recovery.
+TARGET_RECOVERY_WIPE := device/google/bramble/recovery.wipe
+TARGET_RECOVERY_FSTAB := device/google/bramble/fstab.hardware
+TARGET_RECOVERY_PIXEL_FORMAT := RGBX_8888
+TARGET_RECOVERY_UI_LIB := \
+  librecovery_ui_bramble \
+  libnos_citadel_for_recovery \
+  libnos_for_recovery
+
+# Enable chain partition for system.
+BOARD_AVB_VBMETA_SYSTEM := system
+BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
+BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048
+BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
+BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
+
+# product.img
+BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
+
+# userdata.img
+TARGET_USERIMAGES_USE_F2FS := true
+BOARD_USERDATAIMAGE_PARTITION_SIZE := 10737418240
+BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE := f2fs
+
+# persist.img
+BOARD_PERSISTIMAGE_PARTITION_SIZE := 33554432
+BOARD_PERSISTIMAGE_FILE_SYSTEM_TYPE := ext4
+
+# boot.img
+BOARD_BOOTIMAGE_PARTITION_SIZE := 0x04000000
+
+BOARD_FLASH_BLOCK_SIZE := 131072
+
+BOARD_ROOT_EXTRA_SYMLINKS := /vendor/lib/dsp:/dsp
+BOARD_ROOT_EXTRA_SYMLINKS += /mnt/vendor/persist:/persist
+
+include device/google/bramble-sepolicy/bramble-sepolicy.mk
+
+TARGET_FS_CONFIG_GEN := device/google/bramble/config.fs
+
+QCOM_BOARD_PLATFORMS += lito
+QC_PROP_ROOT := vendor/qcom/sm7250/proprietary
+QC_PROP_PATH := $(QC_PROP_ROOT)
+BOARD_HAVE_BLUETOOTH_QCOM := true
+BOARD_HAVE_QCOM_FM := false
+BOARD_USES_COMMON_BLUETOOTH_HAL := true
+
+# Camera
+TARGET_USES_AOSP := true
+BOARD_QTI_CAMERA_32BIT_ONLY := false
+CAMERA_DAEMON_NOT_PRESENT := true
+TARGET_USES_ION := true
+
+# GPS
+TARGET_NO_RPC := true
+TARGET_USES_HARDWARE_QCOM_GPS := false
+BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE := default
+BOARD_VENDOR_QCOM_LOC_PDK_FEATURE_SET := true
+
+# RenderScript
+OVERRIDE_RS_DRIVER := libRSDriver_adreno.so
+
+# Sensors
+USE_SENSOR_MULTI_HAL := true
+TARGET_SUPPORT_DIRECT_REPORT := true
+# Enable sensor Version V_2
+USE_SENSOR_HAL_VER := 2.0
+
+# wlan
+BOARD_WLAN_DEVICE := qcwcn
+BOARD_WPA_SUPPLICANT_DRIVER := NL80211
+BOARD_HOSTAPD_DRIVER := NL80211
+WIFI_DRIVER_DEFAULT := qca_cld3
+WPA_SUPPLICANT_VERSION := VER_0_8_X
+BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_$(BOARD_WLAN_DEVICE)
+BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_$(BOARD_WLAN_DEVICE)
+WIFI_HIDL_FEATURE_AWARE := true
+WIFI_HIDL_FEATURE_DUAL_INTERFACE:= true
+
+# Audio
+BOARD_USES_ALSA_AUDIO := true
+AUDIO_FEATURE_ENABLED_MULTI_VOICE_SESSIONS := true
+AUDIO_FEATURE_ENABLED_SND_MONITOR := true
+AUDIO_FEATURE_ENABLED_USB_TUNNEL := true
+AUDIO_FEATURE_ENABLED_CIRRUS_SPKR_PROTECTION := true
+BOARD_SUPPORTS_SOUND_TRIGGER := true
+AUDIO_FEATURE_FLICKER_SENSOR_INPUT := true
+SOUND_TRIGGER_FEATURE_LPMA_ENABLED := true
+AUDIO_FEATURE_ENABLED_MAXX_AUDIO := true
+AUDIO_FEATURE_ENABLED_24BITS_CAMCORDER := true
+AUDIO_FEATURE_ENABLED_AUDIO_ZOOM := true
+AUDIO_FEATURE_ENABLED_INSTANCE_ID := true
+
+# Audio hal flag
+TARGET_USES_HARDWARE_QCOM_AUDIO := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_PLATFORM_8974 := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_POSTPROC := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_VOLUME_LISTENER := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_GET_MMAP_DATA_FD := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_APP_TYPE_CFG := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_ACDB_INIT_V2_CVD := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_MAX_TARGET_SPECIFIC_CHANNEL_CNT := "4"
+TARGET_USES_HARDWARE_QCOM_AUDIO_INCALL_MUSIC_ENABLED := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_MULTIPLE_HW_VARIANTS_ENABLED := true
+TARGET_USES_HARDWARE_QCOM_AUDIO_INCALL_STEREO_CAPTURE_ENABLED := true
+
+# SoundTrigger hal flag of new codec
+USE_SOUND_TRIGGER_HAL := iaxxx
+
+# Graphics
+TARGET_USES_GRALLOC1 := true
+TARGET_USES_HWC2 := true
+
+VSYNC_EVENT_PHASE_OFFSET_NS := 2000000
+SF_VSYNC_EVENT_PHASE_OFFSET_NS := 6000000
+
+# Display
+TARGET_USES_DISPLAY_RENDER_INTENTS := true
+TARGET_USES_COLOR_METADATA := true
+TARGET_USES_DRM_PP := true
+
+# Misc
+TARGET_USES_HARDWARE_QCOM_BOOTCTRL := true
+
+
+# Vendor Interface Manifest
+DEVICE_MANIFEST_FILE := device/google/bramble/manifest.xml
+DEVICE_MATRIX_FILE := device/google/bramble/compatibility_matrix.xml
+DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := device/google/bramble/device_framework_matrix.xml
+DEVICE_FRAMEWORK_MANIFEST_FILE := device/google/bramble/framework_manifest.xml
+
+# Use mke2fs to create ext4 images
+TARGET_USES_MKE2FS := true
+
+BOARD_EXT4_SHARE_DUP_BLOCKS := true
+
+# Kernel modules
+ifeq (,$(filter-out bramble_kasan, $(TARGET_PRODUCT)))
+BOARD_VENDOR_KERNEL_MODULES += \
+    $(wildcard device/google/bramble-kernel/kasan/*.ko)
+else ifeq (,$(filter-out bramble_kernel_debug_memory, $(TARGET_PRODUCT)))
+BOARD_VENDOR_KERNEL_MODULES += \
+    $(wildcard device/google/bramble-kernel/debug_memory/*.ko)
+else ifeq (,$(filter-out bramble_kernel_debug_locking, $(TARGET_PRODUCT)))
+BOARD_VENDOR_KERNEL_MODULES += \
+    $(wildcard device/google/bramble-kernel/debug_locking/*.ko)
+else ifeq (,$(filter-out bramble_kernel_debug_hang, $(TARGET_PRODUCT)))
+BOARD_VENDOR_KERNEL_MODULES += \
+    $(wildcard device/google/bramble-kernel/debug_hang/*.ko)
+else ifeq (,$(filter-out bramble_kernel_debug_api, $(TARGET_PRODUCT)))
+BOARD_VENDOR_KERNEL_MODULES += \
+    $(wildcard device/google/bramble-kernel/debug_api/*.ko)
+else
+BOARD_VENDOR_KERNEL_MODULES += \
+    $(wildcard device/google/bramble-kernel/*.ko)
+endif
+
+BOARD_SUPER_PARTITION_SIZE := 9755951104
+BOARD_SUPER_PARTITION_GROUPS := google_dynamic_partitions
+BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST := \
+    system \
+    vendor \
+    product
+
+#BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE is set to BOARD_SUPER_PARTITION_SIZE / 2 - 4MB
+BOARD_GOOGLE_DYNAMIC_PARTITIONS_SIZE := 4873781248
+
+# Set error limit to BOARD_SUPER_PARTITON_SIZE - 500MB
+BOARD_SUPER_PARTITION_ERROR_LIMIT := 9231663104
+
+# DTB
+ifeq (,$(filter-out bramble_kasan, $(TARGET_PRODUCT)))
+BOARD_PREBUILT_DTBIMAGE_DIR := device/google/bramble-kernel/kasan
+else ifeq (,$(filter-out bramble_kernel_debug_memory, $(TARGET_PRODUCT)))
+BOARD_PREBUILT_DTBIMAGE_DIR := device/google/bramble-kernel/debug_memory
+else ifeq (,$(filter-out bramble_kernel_debug_locking, $(TARGET_PRODUCT)))
+BOARD_PREBUILT_DTBIMAGE_DIR := device/google/bramble-kernel/debug_locking
+else ifeq (,$(filter-out bramble_kernel_debug_hang, $(TARGET_PRODUCT)))
+BOARD_PREBUILT_DTBIMAGE_DIR := device/google/bramble-kernel/debug_hang
+else ifeq (,$(filter-out bramble_kernel_debug_api, $(TARGET_PRODUCT)))
+BOARD_PREBUILT_DTBIMAGE_DIR := device/google/bramble-kernel/debug_api
+else
+BOARD_PREBUILT_DTBIMAGE_DIR := device/google/bramble-kernel
+endif
+
+# Testing related defines
+BOARD_PERFSETUP_SCRIPT := platform_testing/scripts/perf-setup/b5-setup.sh
+
+-include vendor/google_devices/bramble/proprietary/BoardConfigVendor.mk
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..390a629
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,90 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+
+# Remove default android.hardware.health@2.0-service
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.health@2.0-service)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.health@2.0-service.rc)
+
+# Remove healthd
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/healthd)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/healthd.rc)
+
+# Move libnfc-nci.conf to /vendor
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/libnfc-nci.conf)
+
+# Remove /firmware which used to be a symlink to /vendor/firmware_mnt
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/firmware)
+
+# Remove thermalHAL 1.0
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.thermal@1.0-service.bramble.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.thermal@1.0-service.bramble)
+
+# Remove default android.hardware.composer@2.2
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.graphics.composer@2.2-service)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.graphics.composer@2.2-service.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/lib64/hw/android.hardware.graphics.composer@2.2-impl.so)
+
+# Remove default android.hardware.graphics.composer@2.3-service
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.graphics.composer@2.3-service)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.graphics.composer@2.3-service.rc)
+
+# Remove super_empty.img
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/super_empty.img)
+
+# Remove Vibrator HAL 1.2
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.vibrator@1.2-service.bramble.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.vibrator@1.2-service.bramble)
+
+# Remove Misnamed Vibrator VINTF Fragment
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/manifest.xml)
+
+# Rename power HAL
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.power@1.3-service.bramble-libperfmgr.rc)
+
+# Remove VR permission
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/permissions/android.hardware.vr.headtracking.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/permissions/android.hardware.vr.high_performance.xml)
diff --git a/WCNSS_qcom_cfg.ini b/WCNSS_qcom_cfg.ini
new file mode 100644
index 0000000..24563f7
--- /dev/null
+++ b/WCNSS_qcom_cfg.ini
@@ -0,0 +1,429 @@
+# This file allows user to override the factory
+# defaults for the WLAN Driver
+
+#############################################
+# Power related configurations
+#############################################
+# Phy Mode (auto, b, g, n, etc)
+# Valid values are 0-9, with 0 = Auto, 4 = 11n, 9 = 11ac
+# 1 = 11abg, 2 = 11b, 3 = 11g, 5 = 11g only, 6 = 11n only
+# 7 = 11b only 8 = 11ac only.
+gDot11Mode=0
+
+#############################################
+# STA related general configurations
+#############################################
+# UAPSD service interval for VO,VI, BE, BK traffic
+InfraUapsdVoSrvIntv=0
+InfraUapsdViSrvIntv=0
+InfraUapsdBeSrvIntv=0
+InfraUapsdBkSrvIntv=0
+
+# Flag to allow STA send AddTspec even when ACM is Off
+gAddTSWhenACMIsOff=1
+
+#############################################
+# SAP related configurations
+#############################################
+#Enable OBSS protection
+gEnableApOBSSProt=1
+
+# Maximum Tx power
+# gTxPowerCap=30
+
+# Fragmentation Threshold
+# gFragmentationThreshold=2346
+
+# RTS threshold
+RTSThreshold=1048576
+
+# 802.11d support
+g11dSupportEnabled=0
+
+# DFS Master Capability
+gEnableDFSMasterCap=1
+
+gNeighborLookupThreshold=76
+
+# Legacy (non-ESE, non-802.11r) Fast Roaming Support
+# To enable, set FastRoamEnabled=1
+# To disable, set FastRoamEnabled=0
+FastRoamEnabled=1
+
+# Check if the AP to which we are roaming is better than current AP in
+# terms of RSSI.  Checking is disabled if set to Zero.Otherwise it will
+# use this value as to how better the RSSI of the new/roamable AP should
+# be for roaming
+RoamRssiDiff=3
+
+#Channel Bonding
+gChannelBondingMode5GHz=1
+
+#Say gGoKeepAlivePeriod(5 seconds) and gGoLinkMonitorPeriod(10 seconds).
+#For every 10 seconds DUT send Qos Null frame(i.e., Keep Alive frame if link
+#is idle for last 10 seconds.) For both active and power save clients.
+
+#Power save clients: DUT set TIM bit from 10th second onwards and till client
+#honors TIM bit. If doesn't honor for 5 seconds then DUT remove client.
+
+#Active clients: DUT send Qos Null frame for 10th seconds onwards if it is not
+#success still we try on 11th second if not tries on 12th and so on till 15th
+#second. Hence before disconnection DUT will send 5 NULL frames. Hence in any
+#case DUT will detect client got removed in (10+5) seconds.
+#i.e., (gGoKeepAlivePeriod + gGoLinkMonitorPeriod)..
+
+#gGoLinkMonitorPeriod/ gApLinkMonitorPeriod is period where link is idle and
+#it is period where we send NULL frame.
+#gApLinkMonitorPeriod = 10
+#gGoLinkMonitorPeriod = 10
+
+# Enable DFS channel roam
+# 0: DISABLE, 1: ENABLED_NORMAL, 2: ENABLED_ACTIVE
+gAllowDFSChannelRoam=1
+
+# chain mask related params
+#
+# Set txchainmask and rxchainmask
+# These parameters are used only if gEnable2x2 is 0
+# Valid values are 1,2
+# Set gSetTxChainmask1x1=1 or gSetRxChainmask1x1=1 to select chain0.
+# Set gSetTxChainmask1x1=2 or gSetRxChainmask1x1=2 to select chain1.
+gSetTxChainmask1x1=1
+gSetRxChainmask1x1=1
+
+# MCC to SCC Switch mode:
+# 0-Disable
+# 1-Enable
+# 2-Force SCC if same band, with SAP restart
+# 3-Force SCC if same band, without SAP restart by sending (E)CSA
+# 4-Force SCC if same band (or) use SAP mandatory channel for DBS,
+#   without SAP restart by sending (E)CSA
+gWlanMccToSccSwitchMode = 3
+
+# 1=enable tx STBC; 0=disable
+gEnableTXSTBC=1
+
+# 1=enable rx LDPC; 0=disable
+gEnableRXLDPC=1
+
+#Enable/Disable Tx beamformee in SAP mode
+gEnableTxBFeeSAP=1
+
+# Enable Tx beamforming in VHT20MHz
+# Valid values are 0,1. If commented out, the default value is 0.
+# 0=disable, 1=enable
+gEnableTxBFin20MHz=1
+
+# 802.11K support
+gRrmEnable=1
+
+#Enable Power Save offload
+gEnablePowerSaveOffload=2
+
+# Maximum Receive AMPDU size (VHT only. Valid values:
+# 0->8k 1->16k 2->32k 3->64k 4->128k)
+gVhtAmpduLenExponent=7
+
+# Maximum MPDU length (VHT only. Valid values:
+# 0->3895 octets, 1->7991 octets, 2->11454 octets)
+gVhtMpduLen=2
+
+# Maximum number of wow filters required
+#gMaxWoWFilters=22
+
+# WOW Enable/Disable.
+# 0 - Disable both magic pattern match and pattern byte match.
+# 1 - Enable magic pattern match on all interfaces.
+# 2 - Enable pattern byte match on all interfaces.
+# 3 - Enable both magic pattern and pattern byte match on all interfaces.
+# Default value of gEnableWoW is 3.
+# gEnableWoW=0
+
+#############################################
+# P2P related configurations
+#############################################
+#Enable or Disable p2p device address administered
+isP2pDeviceAddrAdministrated=0
+
+# Set Thermal Power limit
+TxPower2g=10
+TxPower5g=10
+
+#Enable VHT on 2.4Ghz
+gEnableVhtFor24GHzBand=1
+
+#############################################
+# Offload related configurations
+#############################################
+#Maximum number of offload peers supported
+# gMaxOffloadPeers=2
+
+# controlling the following offload patterns
+# through ini parameter. Default value is 1
+# to disable set it to zero. ssdp = 0
+# Setup multicast pattern for mDNS 224.0.0.251,
+# SSDP 239.255.255.250 and LLMNR 224.0.0.252
+ssdp=0
+
+# Regulatory Setting; 0=STRICT; 1=CUSTOM
+gRegulatoryChangeCountry=1
+
+# RA filtering rate limit param, the current value would not
+# help if the lifetime in RA is less than 3*60=3min. Then
+# we need to change it, though it is uncommon.
+# gRAFilterEnable=0
+gRArateLimitInterval=600
+
+# Disable/Enable GreenAP
+# 0 to disable, 1 to enable, default: 1
+gEnableGreenAp=0
+
+#Enable/Disable LPASS support
+# 0 to disable, 1 to enable
+gEnableLpassSupport=1
+
+# Whether userspace country code setting shld have priority
+gCountryCodePriority=1
+
+# Enable or Disable Multi-user MIMO
+# 1=Enable (default), 0=Disable
+gEnableMuBformee=1
+
+# Inactivity time (in ms) to end TX Service Period while in IBSS power save mode
+gIbssTxSpEndInactivityTime=10
+
+#############################################
+# TDLS related configurations
+#############################################
+# Enable support for TDLS
+#  0 - disable
+#  1 - enable
+gEnableTDLSSupport=1
+
+# Enable support for Implicit Trigger of TDLS. That is, wlan driver shall
+# initiate TDLS Discovery towards a peer whenever setup criteria (throughput
+# and RSSI) is met and then will initiate teardown when teardown criteria
+# (idle packet count and RSSI) is met.
+#  0 - disable
+#  1 - enable
+gEnableTDLSImplicitTrigger=1
+
+# Enable support for TDLS off-channel operation
+#  0 - disable
+#  1 - enable
+# TDLS off-channel operation will be invoked when there is only one
+# TDLS connection.
+gEnableTDLSOffChannel=1
+
+# Tx/Rx Packet threshold for initiating TDLS.
+# This ini is used to configure the number of Tx/Rx packets during the period of
+# gTDLSTxStatsPeriod when exceeded, a TDLS Discovery request is triggered.
+gTDLSTxPacketThreshold=10
+
+# Number of idle packet.
+# This ini is used to configure the number of Tx/Rx packet, below which
+# within last gTDLSTxStatsPeriod period is considered as idle condition.
+gTDLSIdlePacketThreshold=1
+
+# VHT Tx/Rx MCS values
+# Valid values are 0,1,2. If commented out, the default value is 0.
+# 0=MCS0-7, 1=MCS0-8, 2=MCS0-9
+gVhtRxMCS=2
+gVhtTxMCS=2
+
+# VHT Tx/Rx MCS values for 2x2
+# Valid values are 0,1,2. If commented out, the default value is 0.
+# 0=MCS0-7, 1=MCS0-8, 2=MCS0-9
+gEnable2x2=1
+gVhtRxMCS2x2=2
+gVhtTxMCS2x2=2
+
+#IPA config is a bit mask and following are the configurations.
+#bit0 IPA Enable
+#bit1 IPA PRE Filter enable
+#bit2 IPv6 enable
+#bit3 IPA Resource Manager (RM) enable
+#bit4 IPA Clock scaling enable
+#bit5 IPA uC ENABLE
+#bit6 IPA uC STA ENABLE
+#bit8 IPA Real Time Debugging
+gIPAConfig=0x7d
+
+# Enable Rx handling options
+# Rx_thread=1 RPS=2(default for ROME) NAPI=4(default for ihelium)
+# Rx_thread + NAPI = 5
+rx_mode=5
+
+# Enable(Tx) fastpath for data traffic.
+# 1 - enable(default)  0 - disable
+gEnableFastPath=1
+
+# Enable TCP Segmentation Offload
+# 1 - enable  0 - disable
+TSOEnable=1
+
+# Enable Generic Receive Offload
+# LRO and GRO are exclusive to each other
+# LRO support is deprecated on latest 4.9(SDM845) kernel
+# 1 - enable(default)  0 - disable
+GROEnable=1
+
+# Enable HT MPDU Density
+# 4 for 2 micro sec
+ght_mpdu_density=4
+
+# Enable flow steering to enable multiple CEs for Rx flows.
+# Multiple Rx CEs<==>Multiple Rx IRQs<==>probably different CPUs.
+# Parallel Rx paths.
+# 1 - enable 0 - disable(default)
+gEnableFlowSteering=1
+
+# Time in microseconds after which a NAPI poll must yield
+ce_service_max_yield_time=500
+
+#Maximum number of HTT messages to be processed per NAPI poll
+ce_service_max_rx_ind_flush=1
+
+# Maximum number of MSDUs the firmware will pack in one HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND
+maxMSDUsPerRxInd=8
+################ Datapath feature set End ################
+
+################ NAN feature set start ###################
+
+# Enable NAN discovery (NAN 1.0)
+# 1 - enable  0 - disable(default)
+gEnableNanSupport=1
+################ NAN feature set end #####################
+
+hostscan_adaptive_dwell_mode=1
+
+# Create another interface during driver load
+gEnableConcurrentSTA=wlan1
+
+#Enable/Disable dual MAC feature
+# 0 - enable DBS
+# 1 - disable DBS
+# 2 - disable DBS for connection but keep DBS for scan
+# 3 - disable DBS for connection but keep DBS scan with async
+#     scan policy disabled
+# 4 - enable DBS for connection as well as for scan with async
+#     scan policy disabled
+# 5 - enable DBS for connection but disable dbs for scan.
+# 6 - enable DBS for connection but disable simultaneous scan from
+#     upper layer (DBS scan remains enabled in FW).
+gDualMacFeatureDisable=6
+
+#Enable/Disable latency mode
+# 0 disable
+# 1 enable
+wlm_latency_enable=1
+
+# Enable/Disable NUD Tracking within driver
+gEnableNUDTracking=0
+
+# Configure hardware filter for DTIM mode
+# The hardware filter is only effective in DTIM mode.
+# Use this configuration to blanket drop broadcast/multicast packets at the hardware level
+# without waking up the firmware
+#
+# Takes a bitmap of frame types to drop
+#
+# 0 = disable feature
+# 1 = drop all broadcast frames, except ARP (default)
+# 2 = drop all multicast frames, except ICMPv6
+# 3 = drop all broadcast and multicast frames, except ARP and ICMPv6
+gHwFilterMode=0
+
+# Enables SNR Monitoring
+# This ini is used to set default snr monitor
+gEnableSNRMonitoring=1
+
+# Control to enable TCP limit output byte
+# This ini is used to enable dynamic configuration of TCP limit output bytes
+# tcp_limit_output_bytes param.
+# Enabling this will let driver post message to cnss-daemon,
+# accordingly cnss-daemon will modify the tcp_limit_output_bytes.
+gTcpLimitOutputEnable=0
+
+# Enable Target Wake Time support.
+# This ini is used to enable or disable TWT support.
+enable_twt=0
+
+# For NLO/PNO, enable MAWC based scan
+# Enable/Disable the Motion Aided Wireless Connectivity based NLO using this parameter
+mawc_nlo_enabled=0
+
+# Force 1x1 when connecting to certain peer
+# This INI when enabled will force 1x1 connection with certain peer.
+gForce1x1Exception=0
+
+# Enable/disable oce feature for STA
+# This ini is used to enable/disable oce feature for STA
+oce_sta_enable=0
+
+# Enable/disable oce feature for SAP
+# This ini is used to enable/disable oce feature for SAP
+oce_sap_enable=0
+
+# Set probe request rate
+# This ini is used to set probe request rate to 5.5Mbps as per OCE requirement in 2.4G band
+oce_enable_probe_req_rate=0
+
+# HE caps Weightage to calculate best candidate
+# This ini is used to increase/decrease HE caps weightage in best candidate selection.
+# If AP supports HE caps, AP will get additional weightage with this param.
+# Weightage will be given only if dot11mode is HE capable.
+he_caps_weightage=0
+
+# PCL Weightage to calculate best candidate
+# This ini is used to increase/decrease PCL weightage in best candidate selection.
+# If some APs are in PCL list, those AP will get addition weightage.
+pcl_weightage=0
+
+# Enable/disable esp feature
+# This ini is used to enable/disable ESP(Estimated service parameters) IE parsing and decides
+# whether firmware will include this in its scoring algo.
+enable_esp_for_roam=0
+
+# Bitmask to enable 11k offload to FW.
+# This ini is used to set which of the 11k features is offloaded to FW
+# Currently Neighbor Report Request is supported for offload and is enabled by default.
+# B0: Offload 11k neighbor report requests
+# B1-B31: Reserved
+11k_offload_enable_bitmask=0
+
+# Set channel selection logic for different concurrency combinations to DBS or inter band MCC.
+# Default is DBS for STA+STA and STA+P2P.
+#  0 - inter-band MCC
+#  1 - DBS
+#
+# BIT 0: STA+STA
+# BIT 1: STA+P2P
+# BIT 2-31: Reserved
+channel_select_logic_conc=0
+
+# Configure BTM
+# Bit 0: Enable/Disable the BTM offload. Set this to 1 will enable and 0 will disable BTM offload.
+# BIT 2, 1: Action on non matching candidate with cache. If a BTM request is received from AP
+#           then the candidate AP's may/may-not be present in the firmware scan cache.
+#           Based on below config firmware will decide whether to forward BTM frame to host or
+#           consume with firmware and proceed with Roaming to candidate AP.
+#
+#           00 scan and consume
+#           01 no scan and forward to host
+#           10, 11 reserved
+# BIT 5, 4, 3: Roaming handoff decisions on multiple candidates match
+#              000 match if exact BSSIDs are found
+#              001 match if at least one top priority BSSID only
+#              010, 011, 100, 101, 110, 111 reserved
+# BIT 6: Set this to 1 will send BTM query frame and 0 not sent.
+# BIT 7-31: Reserved
+btm_offload_config=0
+
+#Timer waiting for interface up from the upper layer
+gInterfaceChangeWait=1000
+
+END
+
+# Note: Configuration parser would not read anything past the END marker
+
diff --git a/aosp_bramble.mk b/aosp_bramble.mk
new file mode 100644
index 0000000..c42e0dd
--- /dev/null
+++ b/aosp_bramble.mk
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+
+# Inherit from the common Open Source product configuration
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline.mk)
+
+$(call inherit-product, device/google/bramble/device-bramble.mk)
+$(call inherit-product-if-exists, vendor/google_devices/bramble/proprietary/device-vendor.mk)
+$(call inherit-product-if-exists, vendor/google_devices/bramble/prebuilts/device-vendor-bramble.mk)
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.config.ringtone=Ring_Synth_04.ogg \
+    ro.com.android.dataroaming=true \
+
+PRODUCT_PACKAGES += \
+    PhotoTable \
+    WallpaperPicker \
+    WAPPushManager \
+
+# Don't build super.img.
+PRODUCT_BUILD_SUPER_PARTITION := false
+
+# b/113232673 STOPSHIP deal with Qualcomm stuff later
+# PRODUCT_RESTRICT_VENDOR_FILES := all
+
+PRODUCT_MANUFACTURER := Google
+PRODUCT_BRAND := Android
+PRODUCT_NAME := aosp_bramble
+PRODUCT_DEVICE := bramble
+PRODUCT_MODEL := AOSP on bramble
+
+PRODUCT_COPY_FILES += \
+    device/sample/etc/apns-full-conf.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/apns-conf.xml
diff --git a/board-info.txt b/board-info.txt
new file mode 100644
index 0000000..1c7657c
--- /dev/null
+++ b/board-info.txt
@@ -0,0 +1 @@
+require board=bramble
diff --git a/bramble/AndroidBoard.mk b/bramble/AndroidBoard.mk
new file mode 100644
index 0000000..0099fda
--- /dev/null
+++ b/bramble/AndroidBoard.mk
@@ -0,0 +1,56 @@
+LOCAL_PATH := $(call my-dir)
+
+#A/B builds require us to create the mount points at compile time.
+#Just creating it for all cases since it does not hurt.
+FIRMWARE_MOUNT_POINT := $(TARGET_OUT_VENDOR)/firmware_mnt
+ALL_DEFAULT_INSTALLED_MODULES += $(FIRMWARE_MOUNT_POINT)
+
+$(FIRMWARE_MOUNT_POINT):
+	@echo "Creating $(FIRMWARE_MOUNT_POINT)"
+	@mkdir -p $(TARGET_OUT_VENDOR)/firmware_mnt
+
+#----------------------------------------------------------------------
+# Generate persist image (persist.img)
+#----------------------------------------------------------------------
+TARGET_OUT_PERSIST_IMG_PATH := $(PRODUCT_OUT)/persist
+
+INTERNAL_PERSISTIMAGE_FILES := \
+    $(foreach pair,$(PRODUCT_COPY_FILES),\
+        $(if $(filter persist/%,$(call word-colon,2,$(pair))),\
+            $(call word-colon,1,$(pair)):$(PRODUCT_OUT)/$(call word-colon,2,$(pair))))
+
+INSTALLED_PERSISTIMAGE_FILES := $(call copy-many-files,$(INTERNAL_PERSISTIMAGE_FILES))
+INSTALLED_PERSISTIMAGE_TARGET := $(PRODUCT_OUT)/persist.img
+
+$(INSTALLED_PERSISTIMAGE_TARGET): $(MKEXTUSERIMG) $(MAKE_EXT4FS) $(INSTALLED_PERSISTIMAGE_FILES)
+	$(call pretty,"Target persist fs image: $(INSTALLED_PERSISTIMAGE_TARGET)")
+	@mkdir -p $(TARGET_OUT_PERSIST_IMG_PATH)
+	$(hide) PATH=$(HOST_OUT_EXECUTABLES):$${PATH} $(MKEXTUSERIMG) -s $(TARGET_OUT_PERSIST_IMG_PATH) $@ ext4 persist $(BOARD_PERSISTIMAGE_PARTITION_SIZE)
+	$(hide) chmod a+r $@
+	$(hide) $(call assert-max-image-size,$@,$(BOARD_PERSISTIMAGE_PARTITION_SIZE))
+
+ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_PERSISTIMAGE_TARGET)
+ALL_MODULES.$(LOCAL_MODULE).INSTALLED += $(INSTALLED_PERSISTIMAGE_TARGET)
+INSTALLED_RADIOIMAGE_TARGET += $(INSTALLED_PERSISTIMAGE_TARGET)
+
+.PHONY: persistimage
+persistimage: $(INSTALLED_PERSISTIMAGE_TARGET)
+
+droidcore: $(INSTALLED_PERSISTIMAGE_TARGET)
+
+
+# copy kernel headers to the build tree
+$(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr: $(wildcard $(PRODUCT_VENDOR_KERNEL_HEADERS)/*)
+	rm -rf $@
+	mkdir -p $@/include
+	cp -a $(PRODUCT_VENDOR_KERNEL_HEADERS)/. $@/include
+
+#----------------------------------------------------------------------
+# build and sign the final stage of bootloader
+#----------------------------------------------------------------------
+.PHONY: aboot
+ifeq ($(USESECIMAGETOOL), true)
+aboot: gensecimage_target gensecimage_install
+else
+aboot: $(INSTALLED_BOOTLOADER_MODULE)
+endif
diff --git a/bramble/BoardConfig.mk b/bramble/BoardConfig.mk
new file mode 100644
index 0000000..e939343
--- /dev/null
+++ b/bramble/BoardConfig.mk
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+TARGET_BOOTLOADER_BOARD_NAME := bramble
+TARGET_SCREEN_DENSITY := 560
+TARGET_RECOVERY_UI_MARGIN_HEIGHT := 165
+
+include device/google/bramble/BoardConfig-common.mk
diff --git a/bramble/init.bramble.rc b/bramble/init.bramble.rc
new file mode 100644
index 0000000..3e7819a
--- /dev/null
+++ b/bramble/init.bramble.rc
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+import /vendor/etc/init/hw/init.${ro.boot.hardware.platform}.rc
+
+on property:vendor.all.modules.ready=1
+    chown system system /sys/class/spi_master/spi1/spi1.0/stm_fts_cmd
+
+service vendor.mdm_helper /vendor/bin/mdm_helper
+    class core
+    group system wakelock
diff --git a/bramble/overlay/frameworks/base/core/res/res/values/config.xml b/bramble/overlay/frameworks/base/core/res/res/values/config.xml
new file mode 100755
index 0000000..48abfd5
--- /dev/null
+++ b/bramble/overlay/frameworks/base/core/res/res/values/config.xml
@@ -0,0 +1,692 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
+         autodetected from the Configuration. -->
+    <bool name="config_showNavigationBar">true</bool>
+
+    <!-- Indicate whether closing the lid causes the device to go to sleep and opening
+         it causes the device to wake up.
+         The default is false. -->
+    <bool name="config_lidControlsSleep">true</bool>
+
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         Wifi interfaces.  If the device doesn't want to support tethering over Wifi this
+         should be empty.  An example would be "softap.*" -->
+    <string-array translatable="false" name="config_tether_wifi_regexs">
+        <item>"wlan0"</item>
+        <item>"softap.*"</item>
+    </string-array>
+
+    <!-- Enable doze mode
+         ComponentName of a dream to show whenever the system would otherwise have gone to sleep. -->
+    <string translatable="false" name="config_dozeComponent">com.android.systemui/com.android.systemui.doze.DozeService</string>
+
+    <!-- Type of the ambient tap sensor. Empty if ambient tap is not supported. -->
+    <string name="config_dozeTapSensorType" translatable="false">com.google.sensor.single_touch</string>
+
+    <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support.
+         The N entries of this array define N  1 zones as follows:
+
+         Zone 0:        0 <= LUX < array[0]
+         Zone 1:        array[0] <= LUX < array[1]
+         ...
+         Zone N:        array[N - 1] <= LUX < array[N]
+         Zone N + 1     array[N] <= LUX < infinity
+
+         Must be overridden in platform specific overlays -->
+    <integer-array name="config_autoBrightnessLevels">
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+        <item>4</item>
+        <item>8</item>
+        <item>12</item>
+        <item>20</item>
+        <item>33</item>
+        <item>55</item>
+        <item>90</item>
+        <item>148</item>
+        <item>245</item>
+        <item>403</item>
+        <item>665</item>
+        <item>1097</item>
+        <item>1808</item>
+        <item>2981</item>
+        <item>5000</item>
+    </integer-array>
+
+    <!-- Array of desired screen brightness in nits corresponding to the lux values
+         in the config_autoBrightnessLevels array. As with config_screenBrightnessMinimumNits and
+         config_screenBrightnessMaximumNits, the display brightness is defined as the measured
+         brightness of an all-white image.
+
+         If this is defined then:
+            - config_autoBrightnessLcdBacklightValues should not be defined
+            - config_screenBrightnessNits must be defined
+            - config_screenBrightnessBacklight must be defined
+
+         This array should have size one greater than the size of the config_autoBrightnessLevels
+         array. The brightness values must be non-negative and non-decreasing. This must be
+         overridden in platform specific overlays -->
+    <array name="config_autoBrightnessDisplayValuesNits">
+        <item>10.45935</item>   <!-- 0-1 -->
+        <item>29.25559</item>   <!-- 1-2 -->
+        <item>34.240692</item>  <!-- 2-3 -->
+        <item>37.514347</item>  <!-- 3-4 -->
+        <item>40.018696</item>  <!-- 4-8 -->
+        <item>46.885098</item>  <!-- 8-12 -->
+        <item>51.626434</item>  <!-- 12-20 -->
+        <item>58.610405</item>  <!-- 20-33 -->
+        <item>66.890915</item>  <!-- 33-55 -->
+        <item>77.61644</item>   <!-- 55-90 -->
+        <item>90.221886</item>  <!-- 90-148 -->
+        <item>105.80314</item>  <!-- 148-245 -->
+        <item>126.073845</item> <!-- 245-403 -->
+        <item>154.16931</item>  <!-- 403-665 -->
+        <item>191.83717</item>  <!-- 665-1097 -->
+        <item>240.74442</item>  <!-- 1097-1808 -->
+        <item>294.84857</item>  <!-- 1808-2981 -->
+        <item>348.05453</item>  <!-- 2981-5000 -->
+        <item>399.81</item>     <!-- 5000+ -->
+    </array>
+
+    <!-- Minimum screen brightness allowed by the power manager. -->
+    <integer name="config_screenBrightnessDim">6</integer>
+
+    <!-- Screen brightness when dozing. -->
+    <integer name="config_screenBrightnessDoze">34</integer>
+
+    <!-- Whether the always on display mode is available. -->
+    <bool name="config_dozeAlwaysOnDisplayAvailable">true</bool>
+
+    <!-- True if the display hardware only has brightness buckets rather than a full range of
+         backlight values -->
+    <bool name="config_displayBrightnessBucketsInDoze">true</bool>
+
+    <!-- Default screen brightness setting.
+         Must be in the range specified by minimum and maximum. -->
+    <integer name="config_screenBrightnessSettingDefault">98</integer>
+
+    <!-- Default screen brightness for VR setting. Target default value: 0x0BB for EVT1.1. -->
+    <!-- 8 bit brightness level of 6 corresponds to the 10 bit brightness level of 0x0B6,
+         8 bit brightness level of 7 corresponds to the 10 bit brightness level of 0x0C1 on EVT1.1. -->
+    <integer name="config_screenBrightnessForVrSettingDefault">7</integer>
+    <integer name="config_screenBrightnessForVrSettingMinimum">6</integer>
+    <integer name="config_screenBrightnessForVrSettingMaximum">7</integer>
+
+    <!-- Minimum screen brightness setting allowed by the power manager.
+         The user is forbidden from setting the brightness below this level. -->
+    <integer name="config_screenBrightnessSettingMinimum">1</integer>
+
+    <!-- Maximum screen brightness setting allowed by the power manager.
+         The user is forbidden from setting the brightness above this level. -->
+    <integer name="config_screenBrightnessSettingMaximum">255</integer>
+
+    <!-- An array describing the screen's backlight values corresponding to the brightness
+         values in the config_screenBrightnessNits array.
+
+         This array should be equal in size to config_screenBrightnessBacklight. -->
+    <integer-array name="config_screenBrightnessBacklight">
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+        <item>4</item>
+        <item>5</item>
+        <item>6</item>
+        <item>7</item>
+        <item>8</item>
+        <item>9</item>
+        <item>10</item>
+        <item>11</item>
+        <item>12</item>
+        <item>13</item>
+        <item>14</item>
+        <item>15</item>
+        <item>16</item>
+        <item>17</item>
+        <item>18</item>
+        <item>19</item>
+        <item>20</item>
+        <item>21</item>
+        <item>22</item>
+        <item>23</item>
+        <item>24</item>
+        <item>25</item>
+        <item>26</item>
+        <item>27</item>
+        <item>28</item>
+        <item>29</item>
+        <item>30</item>
+        <item>31</item>
+        <item>32</item>
+        <item>33</item>
+        <item>34</item>
+        <item>35</item>
+        <item>36</item>
+        <item>37</item>
+        <item>38</item>
+        <item>39</item>
+        <item>40</item>
+        <item>41</item>
+        <item>42</item>
+        <item>43</item>
+        <item>44</item>
+        <item>45</item>
+        <item>46</item>
+        <item>47</item>
+        <item>48</item>
+        <item>49</item>
+        <item>50</item>
+        <item>51</item>
+        <item>52</item>
+        <item>53</item>
+        <item>54</item>
+        <item>55</item>
+        <item>56</item>
+        <item>57</item>
+        <item>58</item>
+        <item>59</item>
+        <item>60</item>
+        <item>61</item>
+        <item>62</item>
+        <item>63</item>
+        <item>64</item>
+        <item>65</item>
+        <item>66</item>
+        <item>67</item>
+        <item>68</item>
+        <item>69</item>
+        <item>70</item>
+        <item>71</item>
+        <item>72</item>
+        <item>73</item>
+        <item>74</item>
+        <item>75</item>
+        <item>76</item>
+        <item>77</item>
+        <item>78</item>
+        <item>79</item>
+        <item>80</item>
+        <item>81</item>
+        <item>82</item>
+        <item>83</item>
+        <item>84</item>
+        <item>85</item>
+        <item>86</item>
+        <item>87</item>
+        <item>88</item>
+        <item>89</item>
+        <item>90</item>
+        <item>91</item>
+        <item>92</item>
+        <item>93</item>
+        <item>94</item>
+        <item>95</item>
+        <item>96</item>
+        <item>97</item>
+        <item>98</item>
+        <item>99</item>
+        <item>100</item>
+        <item>101</item>
+        <item>102</item>
+        <item>103</item>
+        <item>104</item>
+        <item>105</item>
+        <item>106</item>
+        <item>107</item>
+        <item>108</item>
+        <item>109</item>
+        <item>110</item>
+        <item>111</item>
+        <item>112</item>
+        <item>113</item>
+        <item>114</item>
+        <item>115</item>
+        <item>116</item>
+        <item>117</item>
+        <item>118</item>
+        <item>119</item>
+        <item>120</item>
+        <item>121</item>
+        <item>122</item>
+        <item>123</item>
+        <item>124</item>
+        <item>125</item>
+        <item>126</item>
+        <item>127</item>
+        <item>128</item>
+        <item>129</item>
+        <item>130</item>
+        <item>131</item>
+        <item>132</item>
+        <item>133</item>
+        <item>134</item>
+        <item>135</item>
+        <item>136</item>
+        <item>137</item>
+        <item>138</item>
+        <item>139</item>
+        <item>140</item>
+        <item>141</item>
+        <item>142</item>
+        <item>143</item>
+        <item>144</item>
+        <item>145</item>
+        <item>146</item>
+        <item>147</item>
+        <item>148</item>
+        <item>149</item>
+        <item>150</item>
+        <item>151</item>
+        <item>152</item>
+        <item>153</item>
+        <item>154</item>
+        <item>155</item>
+        <item>156</item>
+        <item>157</item>
+        <item>158</item>
+        <item>159</item>
+        <item>160</item>
+        <item>161</item>
+        <item>162</item>
+        <item>163</item>
+        <item>164</item>
+        <item>165</item>
+        <item>166</item>
+        <item>167</item>
+        <item>168</item>
+        <item>169</item>
+        <item>170</item>
+        <item>171</item>
+        <item>172</item>
+        <item>173</item>
+        <item>174</item>
+        <item>175</item>
+        <item>176</item>
+        <item>177</item>
+        <item>178</item>
+        <item>179</item>
+        <item>180</item>
+        <item>181</item>
+        <item>182</item>
+        <item>183</item>
+        <item>184</item>
+        <item>185</item>
+        <item>186</item>
+        <item>187</item>
+        <item>188</item>
+        <item>189</item>
+        <item>190</item>
+        <item>191</item>
+        <item>192</item>
+        <item>193</item>
+        <item>194</item>
+        <item>195</item>
+        <item>196</item>
+        <item>197</item>
+        <item>198</item>
+        <item>199</item>
+        <item>200</item>
+        <item>201</item>
+        <item>202</item>
+        <item>203</item>
+        <item>204</item>
+        <item>205</item>
+        <item>206</item>
+        <item>207</item>
+        <item>208</item>
+        <item>209</item>
+        <item>210</item>
+        <item>211</item>
+        <item>212</item>
+        <item>213</item>
+        <item>214</item>
+        <item>215</item>
+        <item>216</item>
+        <item>217</item>
+        <item>218</item>
+        <item>219</item>
+        <item>220</item>
+        <item>221</item>
+        <item>222</item>
+        <item>223</item>
+        <item>224</item>
+        <item>225</item>
+        <item>226</item>
+        <item>227</item>
+        <item>228</item>
+        <item>229</item>
+        <item>230</item>
+        <item>231</item>
+        <item>232</item>
+        <item>233</item>
+        <item>234</item>
+        <item>235</item>
+        <item>236</item>
+        <item>237</item>
+        <item>238</item>
+        <item>239</item>
+        <item>240</item>
+        <item>241</item>
+        <item>242</item>
+        <item>243</item>
+        <item>244</item>
+        <item>245</item>
+        <item>246</item>
+        <item>247</item>
+        <item>248</item>
+        <item>249</item>
+        <item>250</item>
+        <item>251</item>
+        <item>252</item>
+        <item>253</item>
+        <item>254</item>
+        <item>255</item>
+    </integer-array>
+
+    <!-- An array of floats describing the screen brightness in nits corresponding to the backlight
+         values in the config_screenBrightnessBacklight array.  On OLED displays these  values
+         should be measured with an all white image while the display is in the fully on state.
+         Note that this value should *not* reflect the maximum brightness value for any high
+         brightness modes but only the maximum brightness value obtainable in a sustainable manner.
+
+         This array should be equal in size to config_screenBrightnessBacklight -->
+    <array name="config_screenBrightnessNits">
+        <item>2.0</item>
+        <item>3.9</item>
+        <item>5.8</item>
+        <item>7.6</item>
+        <item>9.5</item>
+        <item>11.0</item>
+        <item>12.5</item>
+        <item>14.0</item>
+        <item>15.5</item>
+        <item>17.0</item>
+        <item>18.8</item>
+        <item>20.6</item>
+        <item>22.4</item>
+        <item>24.2</item>
+        <item>26.0</item>
+        <item>27.6</item>
+        <item>29.2</item>
+        <item>30.8</item>
+        <item>32.4</item>
+        <item>34.0</item>
+        <item>35.5</item>
+        <item>37.0</item>
+        <item>38.5</item>
+        <item>40.0</item>
+        <item>41.5</item>
+        <item>43.4</item>
+        <item>45.3</item>
+        <item>47.2</item>
+        <item>49.1</item>
+        <item>51.0</item>
+        <item>52.5</item>
+        <item>53.9</item>
+        <item>55.4</item>
+        <item>56.8</item>
+        <item>58.3</item>
+        <item>59.8</item>
+        <item>61.3</item>
+        <item>62.7</item>
+        <item>64.2</item>
+        <item>65.7</item>
+        <item>67.2</item>
+        <item>68.6</item>
+        <item>70.1</item>
+        <item>71.5</item>
+        <item>73.0</item>
+        <item>74.5</item>
+        <item>75.9</item>
+        <item>77.4</item>
+        <item>78.8</item>
+        <item>80.3</item>
+        <item>81.8</item>
+        <item>83.3</item>
+        <item>84.7</item>
+        <item>86.2</item>
+        <item>87.7</item>
+        <item>89.2</item>
+        <item>90.6</item>
+        <item>92.1</item>
+        <item>93.5</item>
+        <item>95.0</item>
+        <item>96.7</item>
+        <item>98.3</item>
+        <item>100.0</item>
+        <item>101.6</item>
+        <item>103.3</item>
+        <item>105.0</item>
+        <item>106.6</item>
+        <item>108.3</item>
+        <item>109.9</item>
+        <item>111.6</item>
+        <item>113.3</item>
+        <item>114.9</item>
+        <item>116.6</item>
+        <item>118.2</item>
+        <item>119.9</item>
+        <item>121.6</item>
+        <item>123.2</item>
+        <item>124.9</item>
+        <item>126.5</item>
+        <item>128.2</item>
+        <item>129.9</item>
+        <item>131.6</item>
+        <item>133.2</item>
+        <item>134.9</item>
+        <item>136.6</item>
+        <item>138.3</item>
+        <item>139.9</item>
+        <item>141.6</item>
+        <item>143.2</item>
+        <item>144.9</item>
+        <item>146.6</item>
+        <item>148.2</item>
+        <item>149.9</item>
+        <item>151.5</item>
+        <item>153.2</item>
+        <item>154.9</item>
+        <item>156.5</item>
+        <item>158.2</item>
+        <item>159.8</item>
+        <item>161.5</item>
+        <item>162.9</item>
+        <item>164.4</item>
+        <item>165.8</item>
+        <item>167.3</item>
+        <item>168.7</item>
+        <item>170.1</item>
+        <item>171.6</item>
+        <item>173.0</item>
+        <item>174.5</item>
+        <item>175.9</item>
+        <item>177.3</item>
+        <item>178.8</item>
+        <item>180.2</item>
+        <item>181.7</item>
+        <item>183.1</item>
+        <item>184.5</item>
+        <item>186.0</item>
+        <item>187.4</item>
+        <item>188.9</item>
+        <item>190.3</item>
+        <item>191.7</item>
+        <item>193.2</item>
+        <item>194.6</item>
+        <item>196.1</item>
+        <item>197.5</item>
+        <item>199.2</item>
+        <item>200.9</item>
+        <item>202.6</item>
+        <item>204.3</item>
+        <item>206.0</item>
+        <item>207.7</item>
+        <item>209.4</item>
+        <item>211.1</item>
+        <item>212.8</item>
+        <item>214.5</item>
+        <item>216.2</item>
+        <item>217.9</item>
+        <item>219.6</item>
+        <item>221.3</item>
+        <item>223.0</item>
+        <item>224.7</item>
+        <item>226.4</item>
+        <item>228.1</item>
+        <item>229.8</item>
+        <item>231.5</item>
+        <item>233.2</item>
+        <item>234.9</item>
+        <item>236.6</item>
+        <item>238.3</item>
+        <item>240.0</item>
+        <item>241.6</item>
+        <item>243.2</item>
+        <item>244.8</item>
+        <item>246.4</item>
+        <item>248.0</item>
+        <item>249.6</item>
+        <item>251.2</item>
+        <item>252.8</item>
+        <item>254.4</item>
+        <item>256.0</item>
+        <item>257.6</item>
+        <item>259.2</item>
+        <item>260.8</item>
+        <item>262.4</item>
+        <item>264.0</item>
+        <item>265.6</item>
+        <item>267.2</item>
+        <item>268.8</item>
+        <item>270.4</item>
+        <item>272.0</item>
+        <item>273.5</item>
+        <item>275.1</item>
+        <item>276.6</item>
+        <item>278.2</item>
+        <item>279.7</item>
+        <item>281.2</item>
+        <item>282.7</item>
+        <item>284.3</item>
+        <item>285.8</item>
+        <item>287.3</item>
+        <item>288.8</item>
+        <item>290.4</item>
+        <item>291.9</item>
+        <item>293.5</item>
+        <item>295.0</item>
+        <item>296.5</item>
+        <item>298.0</item>
+        <item>299.6</item>
+        <item>301.1</item>
+        <item>302.6</item>
+        <item>304.1</item>
+        <item>305.7</item>
+        <item>307.2</item>
+        <item>308.8</item>
+        <item>310.3</item>
+        <item>311.8</item>
+        <item>313.4</item>
+        <item>314.9</item>
+        <item>316.5</item>
+        <item>318.0</item>
+        <item>319.5</item>
+        <item>321.0</item>
+        <item>322.5</item>
+        <item>324.0</item>
+        <item>325.5</item>
+        <item>327.0</item>
+        <item>328.5</item>
+        <item>330.0</item>
+        <item>331.5</item>
+        <item>333.0</item>
+        <item>334.5</item>
+        <item>336.0</item>
+        <item>337.5</item>
+        <item>339.0</item>
+        <item>340.5</item>
+        <item>342.0</item>
+        <item>343.5</item>
+        <item>345.0</item>
+        <item>346.5</item>
+        <item>348.0</item>
+        <item>349.5</item>
+        <item>351.0</item>
+        <item>352.5</item>
+        <item>354.0</item>
+        <item>355.5</item>
+        <item>357.0</item>
+        <item>358.5</item>
+        <item>360.0</item>
+        <item>361.5</item>
+        <item>363.0</item>
+        <item>364.5</item>
+        <item>366.0</item>
+        <item>367.5</item>
+        <item>369.0</item>
+        <item>370.5</item>
+        <item>372.0</item>
+        <item>373.5</item>
+        <item>374.9</item>
+        <item>376.4</item>
+        <item>377.9</item>
+        <item>379.4</item>
+        <item>380.9</item>
+        <item>382.4</item>
+        <item>383.9</item>
+        <item>385.4</item>
+        <item>386.9</item>
+        <item>388.4</item>
+        <item>389.8</item>
+        <item>391.3</item>
+        <item>392.8</item>
+        <item>394.3</item>
+        <item>395.8</item>
+        <item>397.3</item>
+        <item>398.8</item>
+        <item>400.3</item>
+    </array>
+
+    <!-- The nominal white coordinates, in CIE1931 XYZ color space, for Display White Balance to
+         use in its calculations. AWB will adapt this white point to the target ambient white
+         point. The array must include a total of 3 float values (X, Y, Z) -->
+    <string-array name="config_displayWhiteBalanceDisplayNominalWhite">
+        <!-- Nominal White X --> <item>0.950352</item>
+        <!-- Nominal White Y --> <item>1.0     </item>
+        <!-- Nominal White Z --> <item>1.089366</item>
+    </string-array>
+
+    <!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. -->
+    <integer name="config_shutdownBatteryTemperature">600</integer>
+
+    <!-- Whether or not we should show the option to show battery percentage -->
+    <bool name="config_battery_percentage_setting_available">true</bool>
+
+    <!-- Default radius of the software rounded corners. -->
+    <dimen name="rounded_corner_radius">140px</dimen>
+
+    <!-- Height of the status bar -->
+    <dimen name="status_bar_height_portrait">28dp</dimen>
+
+</resources>
diff --git a/bramble/overlay/frameworks/base/core/res/res/xml/power_profile.xml b/bramble/overlay/frameworks/base/core/res/res/xml/power_profile.xml
new file mode 100644
index 0000000..bfb9d24
--- /dev/null
+++ b/bramble/overlay/frameworks/base/core/res/res/xml/power_profile.xml
@@ -0,0 +1,207 @@
+<?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.
+*/
+-->
+<device name="Android">
+    <!-- All values are in mA except as noted -->
+    <item name="battery.capacity">3800</item>
+
+    <!-- Number of cores each CPU cluster contains -->
+    <array name="cpu.clusters.cores">
+      <value>4</value> <!-- Cluster 0 has 4 cores (cpu0, cpu1, cpu2, cpu3) -->
+      <value>3</value> <!-- Cluster 1 has 3 cores (cpu4, cpu5, cpu6) -->
+      <value>1</value> <!-- Cluster 2 has 1 cores (cpu7) -->
+    </array>
+
+    <!-- Power consumption when CPU is suspended -->
+    <item name="cpu.suspend">5.6</item>
+    <!-- Additional power consumption when CPU is in a kernel idle loop -->
+    <item name="cpu.idle">5.4</item>
+
+    <!-- Additional power consumption by CPU excluding cluster and core when
+         running -->
+    <item name="cpu.active">8.4</item>
+
+    <!-- Additional power consumption by CPU cluster0 itself when running
+         excluding cores in it -->
+    <item name="cpu.cluster_power.cluster0">2</item>
+    <!-- Additional power consumption by CPU cluster1 itself when running
+         excluding cores in it -->
+    <item name="cpu.cluster_power.cluster1">2.2</item>
+    <!-- Additional power consumption by CPU cluster2 itself when running
+         excluding cores in it -->
+    <item name="cpu.cluster_power.cluster2">2.6</item>
+
+    <!-- Different CPU speeds as reported in
+         /sys/devices/system/cpu/cpufreq/ploicy0/scaling_available_frequencies -->
+    <array name="cpu.core_speeds.cluster0">
+      <value>300000</value> <!-- 300 MHz CPU speed -->
+      <value>403200</value> <!-- 403 MHz CPU speed -->
+      <value>499200</value> <!-- 499 MHz CPU speed -->
+      <value>576000</value> <!-- 576 MHz CPU speed -->
+      <value>672000</value> <!-- 672 MHz CPU speed -->
+      <value>768000</value> <!-- 768 MHz CPU speed -->
+      <value>844800</value> <!-- 844 MHz CPU speed -->
+      <value>940800</value> <!-- 940 MHz CPU speed -->
+      <value>1036800</value> <!-- 1036 MHz CPU speed -->
+      <value>1113600</value> <!-- 1113 MHz CPU speed -->
+      <value>1209600</value> <!-- 1209 MHz CPU speed -->
+      <value>1305600</value> <!-- 1305 MHz CPU speed -->
+      <value>1382400</value> <!-- 1382 MHz CPU speed -->
+      <value>1478400</value> <!-- 1478 MHz CPU speed -->
+      <value>1555200</value> <!-- 1555 MHz CPU speed -->
+      <value>1632000</value> <!-- 1632 MHz CPU speed -->
+      <value>1708800</value> <!-- 1708 MHz CPU speed -->
+      <value>1785600</value> <!-- 1785 MHz CPU speed -->
+    </array>
+    <!-- Different CPU speeds as reported in
+         /sys/devices/system/cpu/cpufreq/ploicy4/scaling_available_frequencies -->
+    <array name="cpu.core_speeds.cluster1">
+      <value>710400</value> <!-- 710 MHz CPU speed -->
+      <value>825600</value> <!-- 825 MHz CPU speed -->
+      <value>940800</value> <!-- 940 MHz CPU speed -->
+      <value>1056000</value> <!-- 1056 MHz CPU speed -->
+      <value>1171200</value> <!-- 1171 MHz CPU speed -->
+      <value>1286400</value> <!-- 1286 MHz CPU speed -->
+      <value>1401600</value> <!-- 1401 MHz CPU speed -->
+      <value>1497600</value> <!-- 1497 MHz CPU speed -->
+      <value>1612800</value> <!-- 1612 MHz CPU speed -->
+      <value>1708800</value> <!-- 1708 MHz CPU speed -->
+      <value>1804800</value> <!-- 1804 MHz CPU speed -->
+      <value>1920000</value> <!-- 1920 MHz CPU speed -->
+      <value>2016000</value> <!-- 2016 MHz CPU speed -->
+      <value>2131200</value> <!-- 2131 MHz CPU speed -->
+      <value>2227200</value> <!-- 2227 MHz CPU speed -->
+      <value>2323200</value> <!-- 2323 MHz CPU speed -->
+      <value>2419200</value> <!-- 2419 MHz CPU speed -->
+    </array>
+    <!-- Different CPU speeds as reported in
+         /sys/devices/system/cpu/cpufreq/ploicy7/scaling_available_frequencies -->
+    <array name="cpu.core_speeds.cluster2">
+      <value>825600</value> <!-- 825 MHz CPU speed -->
+      <value>940800</value> <!-- 940 MHz CPU speed -->
+      <value>1056000</value> <!-- 1056 MHz CPU speed -->
+      <value>1171200</value> <!-- 1171 MHz CPU speed -->
+      <value>1286400</value> <!-- 1286 MHz CPU speed -->
+      <value>1401600</value> <!-- 1401 MHz CPU speed -->
+      <value>1497600</value> <!-- 1497 MHz CPU speed -->
+      <value>1612800</value> <!-- 1612 MHz CPU speed -->
+      <value>1708800</value> <!-- 1708 MHz CPU speed -->
+      <value>1804800</value> <!-- 1804 MHz CPU speed -->
+      <value>1920000</value> <!-- 1920 MHz CPU speed -->
+      <value>2016000</value> <!-- 2016 MHz CPU speed -->
+      <value>2131200</value> <!-- 2131 MHz CPU speed -->
+      <value>2227200</value> <!-- 2227 MHz CPU speed -->
+      <value>2323200</value> <!-- 2323 MHz CPU speed -->
+      <value>2419200</value> <!-- 2419 MHz CPU speed -->
+      <value>2534400</value> <!-- 2534 MHz CPU speed -->
+      <value>2649600</value> <!-- 2649 MHz CPU speed -->
+      <value>2745600</value> <!-- 2745 MHz CPU speed -->
+      <value>2841600</value> <!-- 2814 MHz CPU speed -->
+    </array>
+
+    <!-- Additional power used by a CPU core from cluster 0 when running at
+         different speeds, excluding cluster and active cost -->
+    <array name="cpu.core_power.cluster0">
+      <value>39.44</value> <!-- 300 MHz CPU speed -->
+      <value>41.34</value> <!-- 403 MHz CPU speed -->
+      <value>43.57</value> <!-- 499 MHz CPU speed -->
+      <value>45.48</value> <!-- 576 MHz CPU speed -->
+      <value>47.20</value> <!-- 672 MHz CPU speed -->
+      <value>49.64</value> <!-- 768 MHz CPU speed -->
+      <value>51.88</value> <!-- 844 MHz CPU speed -->
+      <value>53.34</value> <!-- 940 MHz CPU speed -->
+      <value>56.69</value> <!-- 1036 MHz CPU speed -->
+      <value>58.78</value> <!-- 1113 MHz CPU speed -->
+      <value>61.41</value> <!-- 1209 MHz CPU speed -->
+      <value>65.11</value> <!-- 1305 MHz CPU speed -->
+      <value>67.49</value> <!-- 1382 MHz CPU speed -->
+      <value>70.61</value> <!-- 1478 MHz CPU speed -->
+      <value>72.39</value> <!-- 1555 MHz CPU speed -->
+      <value>75.43</value> <!-- 1632 MHz CPU speed -->
+      <value>80.21</value> <!-- 1708 MHz CPU speed -->
+      <value>85.05</value> <!-- 1785 MHz CPU speed -->
+    </array>
+    <!-- Additional power used by a CPU core from cluster 1 when running at
+         different speeds, excluding cluster and active cost -->
+    <array name="cpu.core_power.cluster1">
+      <value>50.35</value> <!-- 710 MHz CPU speed -->
+      <value>55.12</value> <!-- 825 MHz CPU speed -->
+      <value>61.45</value> <!-- 940 MHz CPU speed -->
+      <value>69.92</value> <!-- 1056 MHz CPU speed -->
+      <value>77.48</value> <!-- 1171 MHz CPU speed -->
+      <value>85.35</value> <!-- 1286 MHz CPU speed -->
+      <value>95.17</value> <!-- 1401 MHz CPU speed -->
+      <value>103.26</value> <!-- 1497 MHz CPU speed -->
+      <value>118.19</value> <!-- 1612 MHz CPU speed -->
+      <value>132.72</value> <!-- 1708 MHz CPU speed -->
+      <value>143.83</value> <!-- 1804 MHz CPU speed -->
+      <value>155.91</value> <!-- 1920 MHz CPU speed -->
+      <value>190.16</value> <!-- 2016 MHz CPU speed -->
+      <value>213.11</value> <!-- 2131 MHz CPU speed -->
+      <value>237.96</value> <!-- 2227 MHz CPU speed -->
+      <value>266.97</value> <!-- 2323 MHz CPU speed -->
+      <value>302.04</value> <!-- 2419 MHz CPU speed -->
+    </array>
+    <!-- Additional power used by a CPU core from cluster 2 when running at
+         different speeds, excluding cluster and active cost -->
+    <array name="cpu.core_power.cluster2">
+      <value>52.70</value> <!-- 825 MHz CPU speed -->
+      <value>55.90</value> <!-- 940 MHz CPU speed -->
+      <value>59.73</value> <!-- 1056 MHz CPU speed -->
+      <value>63.66</value> <!-- 1171 MHz CPU speed -->
+      <value>67.28</value> <!-- 1286 MHz CPU speed -->
+      <value>71.66</value> <!-- 1401 MHz CPU speed -->
+      <value>76.47</value> <!-- 1497 MHz CPU speed -->
+      <value>80.92</value> <!-- 1612 MHz CPU speed -->
+      <value>85.81</value> <!-- 1708 MHz CPU speed -->
+      <value>93.19</value> <!-- 1804 MHz CPU speed -->
+      <value>98.06</value> <!-- 1920 MHz CPU speed -->
+      <value>119.08</value> <!-- 2016 MHz CPU speed -->
+      <value>127.88</value> <!-- 2131 MHz CPU speed -->
+      <value>129.85</value> <!-- 2227 MHz CPU speed -->
+      <value>140.37</value> <!-- 2323 MHz CPU speed -->
+      <value>151.22</value> <!-- 2419 MHz CPU speed -->
+      <value>160.73</value> <!-- 2534 MHz CPU speed -->
+      <value>175.50</value> <!-- 2649 MHz CPU speed -->
+      <value>186.29</value> <!-- 2745 MHz CPU speed -->
+      <value>223.89</value> <!-- 2814 MHz CPU speed -->
+    </array>
+
+    <!-- Additional power used when screen is ambient mode -->
+    <item name="ambient.on">32</item>
+
+    <!-- Additional power used when screen is turned on at minimum brightness -->
+    <item name="screen.on">98</item>
+    <!-- Additional power used when screen is at maximum brightness, compared to
+         screen at minimum brightness -->
+    <item name="screen.full">470</item>
+
+    <!-- Average power used by the camera flash module when on -->
+    <item name="camera.flashlight">240.47</item>
+    <!-- Average power use by the camera subsystem for a typical camera
+         application. Intended as a rough estimate for an application running a
+         preview and capturing approximately 10 full-resolution pictures per
+         minute. -->
+    <item name="camera.avg">900</item>
+
+    <!-- Additional power used when video is playing -->
+    <item name="video">25</item>
+    <!-- Additional power used when audio is playing -->
+    <item name="audio">75</item>
+</device>
+
diff --git a/bramble/overlay/frameworks/base/packages/SystemUI/res/values/config.xml b/bramble/overlay/frameworks/base/packages/SystemUI/res/values/config.xml
new file mode 100644
index 0000000..d23059a
--- /dev/null
+++ b/bramble/overlay/frameworks/base/packages/SystemUI/res/values/config.xml
@@ -0,0 +1,61 @@
+<?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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Doze: does this device support STATE_DOZE?  -->
+    <bool name="doze_display_state_supported">true</bool>
+
+    <!-- Doze: does this device support STATE_DOZE_SUSPEND?  -->
+    <bool name="doze_suspend_display_state_supported">false</bool>
+
+    <!-- Type of a sensor that provides a low-power estimate of the desired display
+         brightness, suitable to listen to while the device is asleep (e.g. during
+         always-on display) -->
+    <string name="doze_brightness_sensor_type" translatable="false">com.google.sensor.binned_brightness</string>
+
+    <!-- Doze: can we assume the pickup sensor includes a proximity check? -->
+    <bool name="doze_pickup_performs_proximity_check">true</bool>
+
+    <!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
+    <bool name="doze_double_tap_reports_touch_coordinates">true</bool>
+
+    <!-- Doze: Table that translates sensor values from the doze_brightness_sensor_type sensor
+               to brightness values; -1 means keeping the current brightness. -->
+    <integer-array name="config_doze_brightness_sensor_to_brightness">
+        <item>-1</item> <!-- 0: OFF -->
+        <item>4</item> <!-- 1: NIGHT -->
+        <item>7</item> <!-- 2: LOW -->
+        <item>34</item> <!-- 3: HIGH -->
+        <item>34</item> <!-- 4: SUN -->
+    </integer-array>
+
+    <!-- Doze: Table that translates sensor values from the doze_brightness_sensor_type sensor
+               to an opacity value for a black scrim that is overlayed in AOD1.
+               Valid range is from 0 (transparent) to 255 (opaque).
+               -1 means keeping the current opacity. -->
+    <integer-array name="config_doze_brightness_sensor_to_scrim_opacity">
+        <item>-1</item> <!-- 0: OFF -->
+        <item>109</item> <!-- 1: NIGHT -->
+        <item>0</item> <!-- 2: LOW -->
+        <item>0</item> <!-- 3: HIGH -->
+        <item>0</item> <!-- 4: SUN -->
+    </integer-array>
+</resources>
diff --git a/compatibility_matrix.xml b/compatibility_matrix.xml
new file mode 100644
index 0000000..8b06eef
--- /dev/null
+++ b/compatibility_matrix.xml
@@ -0,0 +1,58 @@
+<compatibility-matrix version="1.0" type="device">
+    <hal format="hidl" optional="false">
+        <name>android.frameworks.schedulerservice</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISchedulingPolicyService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.frameworks.sensorservice</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISensorManager</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hidl.allocator</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>ashmem</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hidl.manager</name>
+        <version>1.0</version>
+        <interface>
+            <name>IServiceManager</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hidl.memory</name>
+        <version>1.0</version>
+        <interface>
+            <name>IMapper</name>
+            <instance>ashmem</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.hidl.token</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITokenManager</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="false">
+        <name>android.system.wifi.keystore</name>
+        <version>1.0</version>
+        <interface>
+            <name>IKeystore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</compatibility-matrix>
diff --git a/config.fs b/config.fs
new file mode 100644
index 0000000..18bbf66
--- /dev/null
+++ b/config.fs
@@ -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.
+#
+
+# This file is used to define the properties of the filesystem
+# images generated by build tools (mkbootfs and mkyaffs2image) and
+# by the device side of adb.
+
+[AID_VENDOR_QDSS]
+value:2902
+
+[AID_VENDOR_RFS]
+value:2903
+
+[AID_VENDOR_RFS_SHARED]
+value:2904
+
+[AID_VENDOR_ADPL_ODL]
+value:2905
+
+[AID_VENDOR_QRTR]
+value:2906
+
+[AID_VENDOR_AIRBRUSH]
+value:2907
+
+[vendor/bin/pm-service]
+mode: 0755
+user: AID_SYSTEM
+group: AID_SYSTEM
+caps: NET_BIND_SERVICE
+
+[vendor/bin/cnss-daemon]
+mode: 0755
+user: AID_SYSTEM
+group: AID_SYSTEM
+caps: NET_BIND_SERVICE
+
+[vendor/bin/imsdatadaemon]
+mode: 0755
+user: AID_SYSTEM
+group: AID_SYSTEM
+caps: NET_BIND_SERVICE
+
+[vendor/bin/imsrcsd]
+mode: 0755
+user: AID_SYSTEM
+group: AID_RADIO
+caps: NET_BIND_SERVICE BLOCK_SUSPEND WAKE_ALARM
+
+[vendor/bin/cnd]
+mode: 0755
+user: AID_SYSTEM
+group: AID_SYSTEM
+caps: NET_BIND_SERVICE BLOCK_SUSPEND NET_ADMIN
+
+[vendor/bin/ims_rtp_daemon]
+mode: 0755
+user: AID_SYSTEM
+group: AID_RADIO
+caps: NET_BIND_SERVICE
+
+[vendor/bin/hw/android.hardware.health@2.0-service.bramble]
+mode: 0755
+user: AID_SYSTEM
+group: AID_SYSTEM
+caps: WAKE_ALARM
+
+[vendor/bin/loc_launcher]
+mode: 0755
+user:  AID_GPS
+group: AID_GPS
+caps: SETUID SETGID
+
+[system/vendor/bin/loc_launcher]
+mode: 0755
+user:  AID_GPS
+group: AID_GPS
+caps: SETUID SETGID
+
diff --git a/default-permissions.xml b/default-permissions.xml
new file mode 100644
index 0000000..64f9eaf
--- /dev/null
+++ b/default-permissions.xml
@@ -0,0 +1,58 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+
+<!-- Copyright (C) 2019 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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 contains permissions to be granted by default. Default
+    permissions are granted to special platform components and to apps
+    that are approved to get default grants. The special components
+    are apps that are expected tto work out-of-the-box as they provide
+    core use cases such as default dialer, default email, etc. These
+    grants are managed by the platform. The apps that are additionally
+    approved for default grants are ones that provide carrier specific
+    functionality, ones legally required at some location, ones providing
+    alternative disclosure and opt-out UI, ones providing highlight features
+    of a dedicated device, etc. This file contains only the latter exceptions.
+    Fixed permissions cannot be controlled by the user and need a special
+    approval. Typically these are to ensure either legally mandated functions
+    or the app is considered a part of the OS.
+-->
+
+<exceptions>
+
+    <!-- This is an example of an exception:
+    <exception
+        package="foo.bar.permission"
+      <permission name="android.permission.READ_CONTACTS" fixed="true"/>
+      <permission name="android.permission.READ_CALENDAR" fixed="false"/>
+    </exception>
+    -->
+
+    <exception
+            package="com.google.intelligence.sense">
+        <!-- Record Audio -->
+        <permission name="android.permission.RECORD_AUDIO" fixed="false"/>
+    </exception>
+
+    <exception package="com.google.android.settings.intelligence">
+        <!-- Calendar -->
+        <permission name="android.permission.READ_CALENDAR" fixed="true"/>
+        <!-- Location -->
+        <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="true"/>
+        <permission name="android.permission.ACCESS_BACKGROUND_LOCATION" fixed="true"/>
+    </exception>
+
+</exceptions>
diff --git a/device-bramble.mk b/device-bramble.mk
new file mode 100644
index 0000000..23d7213
--- /dev/null
+++ b/device-bramble.mk
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+PRODUCT_HARDWARE := bramble
+
+include device/google/bramble/device-common.mk
+
+DEVICE_PACKAGE_OVERLAYS += device/google/bramble/bramble/overlay
+
+# Audio XMLs for bramble
diff --git a/device-common.mk b/device-common.mk
new file mode 100644
index 0000000..6f6c5d9
--- /dev/null
+++ b/device-common.mk
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+# define hardware platform
+PRODUCT_PLATFORM := sm7250
+
+include device/google/bramble/device.mk
+
+# Set Vendor SPL to match platform
+VENDOR_SECURITY_PATCH = $(PLATFORM_SECURITY_PATCH)
+
+# A2DP offload enabled for compilation
+AUDIO_FEATURE_ENABLED_A2DP_OFFLOAD := true
+
+# A2DP offload supported
+PRODUCT_PROPERTY_OVERRIDES += \
+ro.bluetooth.a2dp_offload.supported=true
+
+# A2DP offload disabled (UI toggle property)
+PRODUCT_PROPERTY_OVERRIDES += \
+persist.bluetooth.a2dp_offload.disabled=false
+
+# A2DP offload DSP supported encoder list
+PRODUCT_PROPERTY_OVERRIDES += \
+persist.bluetooth.a2dp_offload.cap=sbc-aac-aptx-aptxhd-ldac
+
+# Enable AAC frame ctl for A2DP sinks
+PRODUCT_PROPERTY_OVERRIDES += \
+persist.vendor.bt.aac_frm_ctl.enabled=true
+
+# Set lmkd options
+PRODUCT_PRODUCT_PROPERTIES += \
+	ro.config.low_ram = false \
+	ro.lmk.kill_heaviest_task = true \
+	ro.lmk.kill_timeout_ms = 100 \
+	ro.lmk.use_minfree_levels = true \
+	ro.lmk.log_stats = true \
+
+# Modem logging file
+PRODUCT_COPY_FILES += \
+    device/google/bramble/init.logging.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).logging.rc
+
+# Pixelstats broken mic detection
+PRODUCT_PROPERTY_OVERRIDES += vendor.audio.mic_break=true
+
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.surface_flinger.use_color_management=true
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.surface_flinger.has_wide_color_display=true
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.surface_flinger.has_HDR_display=true
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.surface_flinger.set_idle_timer_ms=50
+
+# MIDI feature
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.software.midi.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.midi.xml
diff --git a/device.mk b/device.mk
new file mode 100644
index 0000000..bc56bbe
--- /dev/null
+++ b/device.mk
@@ -0,0 +1,784 @@
+#
+# 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.
+#
+
+LOCAL_PATH := device/google/bramble
+
+PRODUCT_VENDOR_MOVE_ENABLED := true
+
+PRODUCT_SOONG_NAMESPACES += \
+    hardware/google/av \
+    hardware/google/interfaces \
+    hardware/google/pixel \
+    device/google/bramble \
+    hardware/qcom/sm7250 \
+    vendor/google/airbrush/floral \
+    vendor/google/biometrics/face \
+    vendor/google/darwinn \
+    hardware/qcom/sm7250/display \
+    vendor/google/camera \
+    vendor/qcom/sm7250 \
+    vendor/google/interfaces
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    keyguard.no_require_sim=true
+
+# enable cal by default on accel sensor
+PRODUCT_PRODUCT_PROPERTIES += \
+    persist.vendor.debug.sensors.accel_cal=1
+
+# The default value of this variable is false and should only be set to true when
+# the device allows users to retain eSIM profiles after factory reset of user data.
+PRODUCT_PRODUCT_PROPERTIES += \
+    masterclear.allow_retain_esim_profiles_after_fdr=true
+
+PRODUCT_COPY_FILES += \
+    device/google/bramble/default-permissions.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/default-permissions/default-permissions.xml \
+    frameworks/native/data/etc/handheld_core_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/handheld_core_hardware.xml \
+    frameworks/native/data/etc/android.software.verified_boot.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/android.software.verified_boot.xml
+
+PRODUCT_PACKAGES += \
+    messaging
+
+TARGET_PRODUCT_PROP := $(LOCAL_PATH)/product.prop
+
+$(call inherit-product, $(LOCAL_PATH)/utils.mk)
+
+# Installs gsi keys into ramdisk, to boot a GSI with verified boot.
+$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_keys.mk)
+
+ifeq ($(wildcard vendor/google_devices/bramble/proprietary/device-vendor-bramble.mk),)
+    BUILD_WITHOUT_VENDOR := true
+endif
+
+ifeq ($(TARGET_PREBUILT_KERNEL),)
+    LOCAL_KERNEL := device/google/bramble-kernel/Image.lz4
+else
+    LOCAL_KERNEL := $(TARGET_PREBUILT_KERNEL)
+endif
+PRODUCT_VENDOR_KERNEL_HEADERS := device/google/bramble-kernel/sm7250/kernel-headers
+
+
+PRODUCT_CHARACTERISTICS := nosdcard
+PRODUCT_SHIPPING_API_LEVEL := 28
+
+DEVICE_PACKAGE_OVERLAYS += $(LOCAL_PATH)/overlay
+
+#
+PRODUCT_COPY_FILES += \
+    $(LOCAL_KERNEL):kernel \
+    $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM) \
+    $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.$(PRODUCT_PLATFORM) \
+    $(LOCAL_PATH)/fstab.persist:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.persist \
+    $(LOCAL_PATH)/init.hardware.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).rc \
+    $(LOCAL_PATH)/init.power.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).power.rc \
+    $(LOCAL_PATH)/init.radio.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init.radio.sh \
+    $(LOCAL_PATH)/init.hardware.usb.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).usb.rc \
+    $(LOCAL_PATH)/init.insmod.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init.insmod.sh \
+    $(LOCAL_PATH)/init.qcom.wlan.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init.qcom.wlan.sh \
+    $(LOCAL_PATH)/init.sensors.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init.sensors.sh \
+    $(LOCAL_PATH)/sensors.hals.conf:$(TARGET_COPY_OUT_VENDOR)/etc/sensors/hals.conf \
+    $(LOCAL_PATH)/thermal-engine-$(PRODUCT_HARDWARE).conf:$(TARGET_COPY_OUT_VENDOR)/etc/thermal-engine-$(PRODUCT_HARDWARE).conf \
+    $(LOCAL_PATH)/ueventd.rc:$(TARGET_COPY_OUT_VENDOR)/ueventd.rc
+
+
+MSM_VIDC_TARGET_LIST := lito # Get the color format from kernel headers
+MASTER_SIDE_CP_TARGET_LIST := lito # ION specific settings
+
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+  PRODUCT_COPY_FILES += \
+      $(LOCAL_PATH)/init.hardware.mpssrfs.rc.userdebug:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).mpssrfs.rc
+  PRODUCT_COPY_FILES += \
+      $(LOCAL_PATH)/init.hardware.diag.rc.userdebug:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).diag.rc
+  PRODUCT_COPY_FILES += \
+      $(LOCAL_PATH)/init.hardware.chamber.rc.userdebug:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.$(PRODUCT_PLATFORM).chamber.rc
+  PRODUCT_COPY_FILES += \
+      $(LOCAL_PATH)/init.hardware.ipa.rc.userdebug:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.$(PRODUCT_PLATFORM).ipa.rc
+else
+  PRODUCT_COPY_FILES += \
+      $(LOCAL_PATH)/init.hardware.mpssrfs.rc.user:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).mpssrfs.rc
+  PRODUCT_COPY_FILES += \
+      $(LOCAL_PATH)/init.hardware.diag.rc.user:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.$(PRODUCT_PLATFORM).diag.rc
+endif
+
+# A/B support
+PRODUCT_PACKAGES += \
+    otapreopt_script \
+    cppreopts.sh \
+    update_engine \
+    update_verifier
+
+# Use Sdcardfs
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.sys.sdcardfs=1
+
+PRODUCT_PACKAGES += \
+    bootctrl.lito
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    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
+
+# Enable update engine sideloading by including the static version of the
+# boot_control HAL and its dependencies.
+PRODUCT_STATIC_BOOT_CONTROL_HAL := \
+    bootctrl.lito \
+    libgptutils \
+    libz \
+    libcutils
+
+PRODUCT_PACKAGES += \
+    update_engine_sideload \
+    sg_write_buffer \
+    f2fs_io \
+    check_f2fs
+
+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
+
+# The following modules are included in debuggable builds only.
+PRODUCT_PACKAGES_DEBUG += \
+    bootctl \
+    r.vendor \
+    update_engine_client
+
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.flash-autofocus.xml \
+    frameworks/native/data/etc/android.hardware.camera.front.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.front.xml \
+    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.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.biometrics.face.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.biometrics.face.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.assist.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.assist.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.sensor.gyroscope.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.gyroscope.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.barometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.barometer.xml \
+    frameworks/native/data/etc/android.hardware.sensor.stepcounter.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.stepcounter.xml \
+    frameworks/native/data/etc/android.hardware.sensor.stepdetector.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.stepdetector.xml \
+    frameworks/native/data/etc/android.hardware.sensor.hifi_sensors.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.hifi_sensors.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.telephony.gsm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.gsm.xml \
+    frameworks/native/data/etc/android.hardware.telephony.cdma.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.cdma.xml \
+    frameworks/native/data/etc/android.hardware.telephony.ims.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.ims.xml \
+    frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.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.direct.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.direct.xml \
+    frameworks/native/data/etc/android.hardware.wifi.aware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.aware.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.hardware.wifi.rtt.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.rtt.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.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.opengles.aep.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.opengles.aep.xml \
+    frameworks/native/data/etc/android.hardware.nfc.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.nfc.xml \
+    frameworks/native/data/etc/android.hardware.nfc.hce.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.nfc.hce.xml \
+    frameworks/native/data/etc/android.hardware.nfc.hcef.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.nfc.hcef.xml \
+    frameworks/native/data/etc/android.hardware.vulkan.level-1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.level.xml \
+    frameworks/native/data/etc/android.hardware.vulkan.compute-0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.compute.xml \
+    frameworks/native/data/etc/android.hardware.vulkan.version-1_1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml \
+    frameworks/native/data/etc/android.hardware.telephony.carrierlock.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.carrierlock.xml \
+    frameworks/native/data/etc/android.hardware.strongbox_keystore.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.strongbox_keystore.xml \
+    frameworks/native/data/etc/android.hardware.nfc.uicc.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.nfc.uicc.xml \
+    frameworks/native/data/etc/android.hardware.nfc.ese.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.nfc.ese.xml
+
+# Audio fluence, ns, aec property, voice and media volume steps
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.qc.sdk.audio.fluencetype=fluencepro \
+    persist.audio.fluence.voicecall=true \
+    persist.audio.fluence.speaker=true \
+    persist.audio.fluence.voicecomm=true \
+    persist.audio.fluence.voicerec=false \
+    ro.config.vc_call_vol_steps=7 \
+    ro.config.media_vol_steps=25 \
+
+# Audio Features
+PRODUCT_PROPERTY_OVERRIDES += \
+    vendor.audio.feature.external_dsp.enable=true \
+    vendor.audio.feature.external_speaker.enable=true \
+    vendor.audio.feature.concurrent_capture.enable=false \
+    vendor.audio.feature.a2dp_offload.enable=true \
+    vendor.audio.feature.hfp.enable=true \
+    vendor.audio.feature.hwdep_cal.enable=true \
+    vendor.audio.feature.incall_music.enable=true \
+    vendor.audio.feature.maxx_audio.enable=true \
+    vendor.audio.feature.spkr_prot.enable=true \
+    vendor.audio.feature.usb_offload.enable=true \
+    vendor.audio.feature.audiozoom.enable=true \
+    vendor.audio.feature.snd_mon.enable=true \
+
+# MaxxAudio effect and add rotation monitor
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.audio.monitorRotation=true
+
+# Iaxxx streming and factory binary
+PRODUCT_PACKAGES += \
+    libtunnel \
+    libodsp \
+    adnc_strm.primary.default \
+    sound_trigger.primary.lito
+
+# Add Oslo test for debug rom
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+PRODUCT_PACKAGES += \
+    tunneling_hal_test \
+    sensor_param_test \
+    oslo_config_test \
+    odsp_api_test \
+    crash_event_logger \
+    dump_debug_info \
+    get_pwr_stats \
+    crash_trigger_test
+endif
+
+# graphics
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.opengles.version=196610
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.vendor.display.foss=1 \
+    ro.vendor.display.paneltype=2 \
+    ro.vendor.display.sensortype=2 \
+    vendor.display.foss.config=1 \
+    vendor.display.foss.config_path=/vendor/etc/FOSSConfig.xml
+
+# camera google face detection
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.camera.googfd.enable=1
+
+# camera disable FaceSSD temporarily
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.camera.facessd.enable=0
+
+# camera hal buffer management
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.camera.managebuffer.enable=1
+
+# Lets the vendor library that Google Camera HWL is enabled
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.camera.google_hwl.enabled=true \
+    persist.camera.google_hwl.name=libgooglecamerahwl_impl.so
+
+# OEM Unlock reporting
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
+    ro.oem_unlock_supported=1
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.vendor.cne.feature=1 \
+    persist.vendor.data.iwlan.enable=true \
+    persist.radio.RATE_ADAPT_ENABLE=1 \
+    persist.radio.ROTATION_ENABLE=1 \
+    persist.radio.VT_ENABLE=1 \
+    persist.radio.VT_HYBRID_ENABLE=1 \
+    persist.vendor.radio.apm_sim_not_pwdn=1 \
+    persist.vendor.radio.custom_ecc=1 \
+    persist.vendor.radio.data_ltd_sys_ind=1 \
+    persist.radio.videopause.mode=1 \
+    persist.vendor.radio.multisim_switch_support=true \
+    persist.vendor.radio.sib16_support=1 \
+    persist.vendor.radio.data_con_rprt=true \
+    persist.vendor.radio.relay_oprt_change=1 \
+    persist.vendor.radio.no_wait_for_card=1 \
+    persist.vendor.radio.sap_silent_pin=1 \
+    persist.rcs.supported=1 \
+    vendor.rild.libpath=/vendor/lib64/libril-qc-hal-qmi.so \
+    ro.hardware.keystore_desede=true \
+
+# Disable snapshot timer
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.vendor.radio.snapshot_enabled=0 \
+    persist.vendor.radio.snapshot_timer=0
+
+PRODUCT_PACKAGES += \
+    hwcomposer.lito \
+    android.hardware.graphics.composer@2.3-service-sm7250 \
+    gralloc.lito \
+    android.hardware.graphics.mapper@3.0-impl-qti-display \
+    vendor.qti.hardware.display.allocator-service
+
+# RenderScript HAL
+PRODUCT_PACKAGES += \
+    android.hardware.renderscript@1.0-impl
+
+# Light HAL
+PRODUCT_PACKAGES += \
+    lights.lito \
+    hardware.google.light@1.0-service
+
+# Memtrack HAL
+PRODUCT_PACKAGES += \
+    memtrack.lito \
+    android.hardware.memtrack@1.0-impl \
+    android.hardware.memtrack@1.0-service
+
+# Bluetooth HAL
+PRODUCT_PACKAGES += \
+    android.hardware.bluetooth@1.0-impl-qti \
+    android.hardware.bluetooth@1.0-service-qti
+
+#Bluetooth SAR HAL
+PRODUCT_PACKAGES += \
+    vendor.qti.hardware.bluetooth_sar@1.0-impl
+
+# Bluetooth SoC
+PRODUCT_PROPERTY_OVERRIDES += \
+    vendor.qcom.bluetooth.soc=cherokee
+
+# Property for loading BDA from device tree
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.vendor.bt.bdaddr_path=/proc/device-tree/chosen/cdt/cdb2/bt_addr
+
+# Bluetooth WiPower
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.vendor.bluetooth.emb_wp_mode=false \
+    ro.vendor.bluetooth.wipower=false
+
+# DRM HAL
+PRODUCT_PACKAGES += \
+    android.hardware.drm@1.0-impl \
+    android.hardware.drm@1.0-service \
+    android.hardware.drm@1.2-service.clearkey \
+    android.hardware.drm@1.2-service.widevine
+
+# NFC and Secure Element packages
+PRODUCT_PACKAGES += \
+    NfcNci \
+    Tag \
+    SecureElement \
+    android.hardware.nfc@1.2-service.st \
+    android.hardware.secure_element@1.0-service.st
+
+PRODUCT_COPY_FILES += \
+    device/google/bramble/nfc/libnfc-hal-st.conf:$(TARGET_COPY_OUT_VENDOR)/etc/libnfc-hal-st.conf \
+    device/google/bramble/nfc/libese-hal-st.conf:$(TARGET_COPY_OUT_VENDOR)/etc/libese-hal-st.conf \
+    device/google/bramble/nfc/libnfc-nci.conf:$(TARGET_COPY_OUT_PRODUCT)/etc/libnfc-nci.conf
+
+PRODUCT_PACKAGES += \
+    android.hardware.usb@1.2-service.bramble
+
+PRODUCT_PACKAGES += \
+    android.hardware.health@2.0-service.bramble
+
+# Storage health HAL
+PRODUCT_PACKAGES += \
+    android.hardware.health.storage@1.0-service
+
+PRODUCT_PACKAGES += \
+    libmm-omxcore \
+    libOmxCore \
+    libstagefrighthw \
+    libOmxVdec \
+    libOmxVdecHevc \
+    libOmxVenc \
+    libc2dcolorconvert
+
+# Enable Codec 2.0
+PRODUCT_PACKAGES += \
+    libqcodec2 \
+    vendor.qti.media.c2@1.0-service \
+
+PRODUCT_PACKAGES += \
+    android.hardware.camera.provider@2.4-impl-google \
+    android.hardware.camera.provider@2.4-service-google \
+    camera.lito \
+    libgooglecamerahal \
+    libgooglecamerahwl_impl \
+    libgoogle_camera_hal_tests \
+    libqomx_core \
+    libmmjpeg_interface \
+    libmmcamera_interface \
+    libcameradepthcalibrator
+
+PRODUCT_PACKAGES += \
+    sensors.$(PRODUCT_HARDWARE) \
+    android.hardware.sensors@2.0-impl \
+    android.hardware.sensors@2.0-service \
+    android.hardware.sensors@2.0-service.rc
+
+PRODUCT_PACKAGES += \
+    fs_config_dirs \
+    fs_config_files
+
+# Context hub HAL
+PRODUCT_PACKAGES += \
+    android.hardware.contexthub@1.0-impl.generic \
+    android.hardware.contexthub@1.0-service
+
+# Boot control HAL
+PRODUCT_PACKAGES += \
+    android.hardware.boot@1.0-impl \
+    android.hardware.boot@1.0-service \
+
+# Vibrator HAL
+PRODUCT_PACKAGES += \
+    android.hardware.vibrator@1.3-service.bramble \
+
+# Thermal HAL
+PRODUCT_PACKAGES += \
+    android.hardware.thermal@2.0-service.pixel \
+
+# Thermal HAL config
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/thermal_info_config_$(PRODUCT_HARDWARE).json:$(TARGET_COPY_OUT_VENDOR)/etc/thermal_info_config.json \
+
+#GNSS HAL
+PRODUCT_PACKAGES += \
+    libgps.utils \
+    libgnss \
+    liblocation_api \
+    android.hardware.gnss@2.0-impl-qti \
+    android.hardware.gnss@2.0-service-qti
+
+# Wireless Charger HAL
+PRODUCT_PACKAGES += \
+    vendor.google.wireless_charger@1.0
+
+ENABLE_VENDOR_RIL_SERVICE := true
+
+HOSTAPD := hostapd
+HOSTAPD += hostapd_cli
+PRODUCT_PACKAGES += $(HOSTAPD)
+
+WPA := wpa_supplicant.conf
+WPA += wpa_supplicant_wcn.conf
+WPA += wpa_supplicant
+PRODUCT_PACKAGES += $(WPA)
+
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+PRODUCT_PACKAGES += wpa_cli
+endif
+
+# Wifi
+PRODUCT_PACKAGES += \
+    android.hardware.wifi@1.0-service \
+    wificond \
+    libwpa_client
+
+# WLAN driver configuration files
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/wpa_supplicant_overlay.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/wpa_supplicant_overlay.conf \
+    $(LOCAL_PATH)/p2p_supplicant_overlay.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/p2p_supplicant_overlay.conf \
+    $(LOCAL_PATH)/wifi_concurrency_cfg.txt:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/wifi_concurrency_cfg.txt \
+    $(LOCAL_PATH)/WCNSS_qcom_cfg.ini:$(TARGET_COPY_OUT_VENDOR)/firmware/wlan/qca_cld/WCNSS_qcom_cfg.ini \
+
+LIB_NL := libnl_2
+PRODUCT_PACKAGES += $(LIB_NL)
+
+# Factory OTA
+PRODUCT_PACKAGES += \
+    FactoryOta
+
+# Audio effects
+PRODUCT_PACKAGES += \
+    libvolumelistener \
+    libqcomvisualizer \
+    libqcomvoiceprocessing \
+    libqcomvoiceprocessingdescriptors \
+    libqcompostprocbundle
+
+PRODUCT_PACKAGES += \
+    audio.primary.lito \
+    audio.a2dp.default \
+    audio.usb.default \
+    audio.r_submix.default \
+    libaudio-resampler \
+    audio.hearing_aid.default \
+    audio.bluetooth.default
+
+PRODUCT_PACKAGES += \
+    android.hardware.audio@5.0-impl:32 \
+    android.hardware.audio.effect@5.0-impl:32 \
+    android.hardware.broadcastradio@1.0-impl \
+    android.hardware.soundtrigger@2.2-impl \
+    android.hardware.bluetooth.audio@2.0-impl \
+    android.hardware.audio@2.0-service
+
+# Modules for Audio HAL
+PRODUCT_PACKAGES += \
+    libcirrusspkrprot \
+    libsndmonitor \
+    libmalistener \
+    liba2dpoffload \
+    btaudio_offload_if \
+    libmaxxaudio \
+    libaudiozoom
+
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+PRODUCT_PACKAGES += \
+    tinyplay \
+    tinycap \
+    tinymix \
+    tinypcminfo \
+    cplay
+endif
+
+# Audio hal xmls
+
+# Audio Policy tables
+
+# Audio ACDB data
+
+# Audio ACDB workspace files for QACT
+
+# Audio speaker tunning config data
+
+# Audio audiozoom config data
+
+# and ensure that the xaac decoder is built
+PRODUCT_PACKAGES += \
+    libstagefright_soft_xaacdec.vendor
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/media_codecs.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs.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/media/libstagefright/data/media_codecs_google_video.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_google_video.xml \
+    $(LOCAL_PATH)/media_profiles_V1_0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_V1_0.xml
+
+# Vendor seccomp policy files for media components:
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/seccomp_policy/mediacodec.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediacodec.policy
+
+PRODUCT_PROPERTY_OVERRIDES += \
+    audio.snd_card.open.retries=50
+
+
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+# Subsystem ramdump
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.vendor.sys.ssr.enable_ramdumps=1
+endif
+
+# Subsystem silent restart
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.vendor.sys.ssr.restart_level=modem,SDXPRAIRIE,adsp,slpi
+
+# setup dalvik vm configs
+$(call inherit-product, frameworks/native/build/phone-xhdpi-2048-dalvik-heap.mk)
+
+# Use the default charger mode images
+PRODUCT_PACKAGES += \
+    charger_res_images
+
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+# b/36703476: Set default log size to 1M
+PRODUCT_PROPERTY_OVERRIDES += \
+  ro.logd.size=1M
+# b/114766334: persist all logs by default rotating on 30 files of 1MiB
+PRODUCT_PROPERTY_OVERRIDES += \
+  logd.logpersistd=logcatd \
+  logd.logpersistd.size=30
+endif
+
+# Dumpstate HAL
+PRODUCT_PACKAGES += \
+    android.hardware.dumpstate@1.0-service.bramble
+
+# Citadel
+PRODUCT_PACKAGES += \
+    citadeld \
+    citadel_updater \
+    android.hardware.authsecret@1.0-service.citadel \
+    android.hardware.oemlock@1.0-service.citadel \
+    android.hardware.weaver@1.0-service.citadel \
+    android.hardware.keymaster@4.0-service.citadel \
+    wait_for_strongbox
+
+# Citadel debug stuff
+PRODUCT_PACKAGES_DEBUG += \
+    test_citadel
+
+# Storage: for factory reset protection feature
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.frp.pst=/dev/block/bootdevice/by-name/frp
+
+PRODUCT_PACKAGES += \
+    vndk-sp
+
+PRODUCT_ENFORCE_RRO_TARGETS := *
+
+# Override heap growth limit due to high display density on device
+PRODUCT_PROPERTY_OVERRIDES += \
+    dalvik.vm.heapgrowthlimit=256m
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/hidl/android.hidl.base@1.0.so-32:system/lib/android.hidl.base@1.0.so \
+    $(LOCAL_PATH)/hidl/android.hidl.base@1.0.so-64:system/lib64/android.hidl.base@1.0.so \
+    $(LOCAL_PATH)/hidl/android.hidl.base@1.0.so-32:vendor/lib/android.hidl.base@1.0.so \
+    $(LOCAL_PATH)/hidl/android.hidl.base@1.0.so-64:vendor/lib64/android.hidl.base@1.0.so \
+
+PRODUCT_PACKAGES += \
+    ipacm \
+    IPACM_cfg.xml
+
+#Set default CDMA subscription to RUIM
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.telephony.default_cdma_sub=0
+
+# Set display color mode to Adaptive by default
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.sys.sf.color_saturation=1.0 \
+    persist.sys.sf.native_mode=2 \
+    persist.sys.sf.color_mode=9
+
+# Keymaster 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
+
+# Enable modem logging
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.radio.log_loc="/data/vendor/modem_dump" \
+    ro.radio.log_prefix="modem_log_"
+
+# Enable modem logging for debug
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+PRODUCT_PROPERTY_OVERRIDES += \
+    persist.vendor.sys.modem.diag.mdlog=true \
+    persist.vendor.sys.modem.diag.mdlog_br_num=5
+else
+endif
+
+# Preopt SystemUI
+PRODUCT_DEXPREOPT_SPEED_APPS += \
+    SystemUIGoogle
+
+# Enable stats logging in LMKD
+TARGET_LMKD_STATS_LOG := true
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.lmk.log_stats=true
+
+# default usb oem functions
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+  PRODUCT_PROPERTY_OVERRIDES += \
+      persist.vendor.usb.usbradio.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl_gsi,rmnet_gsi
+endif
+
+# Early phase offset configuration for SurfaceFlinger (b/75985430)
+PRODUCT_PROPERTY_OVERRIDES += \
+    debug.sf.early_phase_offset_ns=500000
+PRODUCT_PROPERTY_OVERRIDES += \
+    debug.sf.early_app_phase_offset_ns=500000
+PRODUCT_PROPERTY_OVERRIDES += \
+    debug.sf.early_gl_phase_offset_ns=3000000
+PRODUCT_PROPERTY_OVERRIDES += \
+    debug.sf.early_gl_app_phase_offset_ns=15000000
+
+# Do not skip init trigger by default
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
+    vendor.skip.init=0
+
+BOARD_USES_QCNE := true
+
+#per device
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/bramble/init.bramble.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.bramble.rc
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/sec_config:$(TARGET_COPY_OUT_VENDOR)/etc/sec_config
+
+# power HAL
+PRODUCT_PACKAGES += \
+    android.hardware.power@1.3-service.pixel-libperfmgr
+
+# Disable ro.adb.secure for the factory build to work around dead touchscreens
+# Bug: 116250643
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.adb.secure=0
+
+# GPS configuration file
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/gps.conf:$(TARGET_COPY_OUT_VENDOR)/etc/gps.conf
+
+# default atrace HAL
+PRODUCT_PACKAGES += \
+    android.hardware.atrace@1.0-service
+
+# Reliability reporting
+PRODUCT_PACKAGES += \
+    pixelstats-vendor
+
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
+
+# fastbootd
+PRODUCT_PACKAGES += \
+    android.hardware.fastboot@1.0-impl.pixel \
+    fastbootd
+
+# insmod files
+PRODUCT_COPY_FILES += \
+	$(LOCAL_PATH)/init.insmod.bramble.cfg:$(TARGET_COPY_OUT_VENDOR)/etc/init.insmod.bramble.cfg
+
+# Use /product/etc/fstab.postinstall to mount system_other
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.postinstall.fstab.prefix=/product
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/fstab.postinstall:$(TARGET_COPY_OUT_PRODUCT)/etc/fstab.postinstall
+
+# powerstats HAL
+PRODUCT_PACKAGES += \
+    android.hardware.power.stats@1.0-service.pixel
+
+# Recovery
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/init.recovery.device.rc:recovery/root/init.recovery.bramble.rc
+
+# Do not skip init trigger by default
+PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
+    vendor.skip.init=0
+
+# Oslo feature flag
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.vendor.aware_available=true
+
+QTI_TELEPHONY_UTILS := qti-telephony-utils
+QTI_TELEPHONY_UTILS += qti_telephony_utils.xml
+PRODUCT_PACKAGES += $(QTI_TELEPHONY_UTILS)
+
+HIDL_WRAPPER := qti-telephony-hidl-wrapper
+HIDL_WRAPPER += qti_telephony_hidl_wrapper.xml
+PRODUCT_PACKAGES += $(HIDL_WRAPPER)
+
+# Increment the SVN for any official public releases
+PRODUCT_PROPERTY_OVERRIDES += \
+	ro.vendor.build.svn=1
+
+# ZRAM writeback
+PRODUCT_PROPERTY_OVERRIDES += \
+    ro.zram.mark_idle_delay_mins=60 \
+    ro.zram.first_wb_delay_mins=180 \
+    ro.zram.periodic_wb_delay_hours=24
+
+# Disable SPU usage
+PRODUCT_PROPERTY_OVERRIDES += \
+    vendor.gatekeeper.disable_spu = true
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/powerhint.json:$(TARGET_COPY_OUT_VENDOR)/etc/powerhint.json
diff --git a/device_framework_matrix.xml b/device_framework_matrix.xml
new file mode 100644
index 0000000..d9f509f
--- /dev/null
+++ b/device_framework_matrix.xml
@@ -0,0 +1,241 @@
+<compatibility-matrix version="1.0" type="framework">
+   <hal format="hidl" optional="true">
+       <name>com.qualcomm.qti.imscmservice</name>
+       <version>2.1</version>
+       <interface>
+         <name>IImsCmService</name>
+         <instance>qti.ims.connectionmanagerservice</instance>
+       </interface>
+   </hal>
+    <hal format="hidl" optional="true">
+        <name>com.qualcomm.qti.uceservice</name>
+        <version>2.0</version>
+        <interface>
+            <name>IUceService</name>
+            <instance>com.qualcomm.qti.uceservice</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.data.factory</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>com.quicinc.cne.api</name>
+        <version>1.1</version>
+        <interface>
+            <name>IApiService</name>
+            <instance>cnd</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>com.quicinc.cne.server</name>
+        <version>2.1</version>
+        <interface>
+            <name>IServer</name>
+            <instance>cnd</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>hardware.google.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IComponentStore</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.radio.config</name>
+        <version>1.1</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.display.config</name>
+        <version>1.1</version>
+        <interface>
+            <name>IDisplayConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.google.radioext</name>
+        <version>1.1</version>
+        <interface>
+            <name>IRadioExt</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.google.wireless_charger</name>
+        <version>1.0</version>
+        <interface>
+            <name>IWirelessCharger</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.google.airbrush.manager</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAirbrushManager</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.am</name>
+        <version>1.0</version>
+        <interface>
+            <name>IQcRilAudio</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.atcmdfwd</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAtCmdFwd</name>
+            <instance>AtCmdFwdService</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.ims</name>
+        <version>1.4</version>
+        <interface>
+            <name>IImsRadio</name>
+            <instance>imsradio0</instance>
+            <instance>imsradio1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.lpa</name>
+        <version>1.0</version>
+        <interface>
+            <name>IUimLpa</name>
+            <instance>UimLpa0</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.qcrilhook</name>
+        <version>1.0</version>
+        <interface>
+            <name>IQtiOemHook</name>
+            <instance>oemhook0</instance>
+            <instance>oemhook1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.uim</name>
+        <version>1.1</version>
+        <interface>
+            <name>IUim</name>
+            <instance>Uim0</instance>
+            <instance>Uim1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.uim_remote_client</name>
+        <version>1.0</version>
+        <interface>
+            <name>IUimRemoteServiceClient</name>
+            <instance>uimRemoteClient0</instance>
+            <instance>uimRemoteClient1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.radio.uim_remote_server</name>
+        <version>1.0</version>
+        <interface>
+            <name>IUimRemoteServiceServer</name>
+            <instance>uimRemoteServer0</instance>
+            <instance>uimRemoteServer1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.tui_comm</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITuiComm</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.display.allocator</name>
+        <version>3.0</version>
+        <interface>
+            <name>IQtiAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.display.mapper</name>
+        <version>3.0</version>
+        <interface>
+            <name>IQtiMapper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.display.mapperextensions</name>
+        <version>1.0</version>
+        <interface>
+            <name>IQtiMapperExtensions</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.imsrtpservice</name>
+        <version>2.0</version>
+        <interface>
+            <name>IRTPService</name>
+            <instance>imsrtpservice</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.ims.callinfo</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>hardware.google.light</name>
+        <version>1.0</version>
+        <interface>
+            <name>ILight</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.qti.hardware.bluetooth_sar</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothSar</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>vendor.google.wifi_ext</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IWifiExt</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</compatibility-matrix>
diff --git a/dumpstate/Android.mk b/dumpstate/Android.mk
new file mode 100644
index 0000000..a38520f
--- /dev/null
+++ b/dumpstate/Android.mk
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.dumpstate@1.0-service.bramble
+LOCAL_INIT_RC := android.hardware.dumpstate@1.0-service.bramble.rc
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SRC_FILES := \
+    DumpstateDevice.cpp \
+    service.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    android.hardware.dumpstate@1.0 \
+    libbase \
+    libcutils \
+    libdumpstateutil \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    liblog \
+    libutils
+
+LOCAL_CFLAGS := -Werror -Wall
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_PROPRIETARY_MODULE := true
+
+include $(BUILD_EXECUTABLE)
diff --git a/dumpstate/DumpstateDevice.cpp b/dumpstate/DumpstateDevice.cpp
new file mode 100755
index 0000000..3f0143b
--- /dev/null
+++ b/dumpstate/DumpstateDevice.cpp
@@ -0,0 +1,488 @@
+/*
+ * 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 "dumpstate"
+
+#include "DumpstateDevice.h"
+
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <hidl/HidlBinderSupport.h>
+
+#include <log/log.h>
+#include <string.h>
+
+#define _SVID_SOURCE
+#include <dirent.h>
+
+#include "DumpstateUtil.h"
+
+#define MODEM_LOG_PREFIX_PROPERTY "ro.radio.log_prefix"
+#define MODEM_LOG_LOC_PROPERTY "ro.radio.log_loc"
+#define MODEM_LOGGING_SWITCH "persist.radio.smlog_switch"
+
+#define DIAG_MDLOG_PERSIST_PROPERTY "persist.vendor.sys.modem.diag.mdlog"
+#define DIAG_MDLOG_PROPERTY "vendor.sys.modem.diag.mdlog"
+#define DIAG_MDLOG_STATUS_PROPERTY "vendor.sys.modem.diag.mdlog_on"
+
+#define DIAG_MDLOG_NUMBER_BUGREPORT "persist.vendor.sys.modem.diag.mdlog_br_num"
+
+#define UFS_BOOTDEVICE "ro.boot.bootdevice"
+
+#define TCPDUMP_NUMBER_BUGREPORT "persist.vendor.tcpdump.log.br_num"
+#define TCPDUMP_PERSIST_PROPERTY "persist.vendor.tcpdump.log.alwayson"
+
+#define MODEM_EFS_DUMP_PROPERTY "vendor.sys.modem.diag.efsdump"
+
+using android::os::dumpstate::CommandOptions;
+using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::PropertiesHelper;
+using android::os::dumpstate::RunCommandToFd;
+
+namespace android {
+namespace hardware {
+namespace dumpstate {
+namespace V1_0 {
+namespace implementation {
+
+#define DIAG_LOG_PREFIX "diag_log_"
+#define TCPDUMP_LOG_PREFIX "tcpdump"
+#define EXTENDED_LOG_PREFIX "extended_log_"
+
+void DumpstateDevice::dumpLogs(int fd, std::string srcDir, std::string destDir,
+                               int maxFileNum, const char *logPrefix) {
+    struct dirent **dirent_list = NULL;
+    int num_entries = scandir(srcDir.c_str(),
+                              &dirent_list,
+                              0,
+                              (int (*)(const struct dirent **, const struct dirent **)) alphasort);
+    if (!dirent_list) {
+        return;
+    } else if (num_entries <= 0) {
+        return;
+    }
+
+    int copiedFiles = 0;
+
+    for (int i = num_entries - 1; i >= 0; i--) {
+        ALOGD("Found %s\n", dirent_list[i]->d_name);
+
+        if (0 != strncmp(dirent_list[i]->d_name, logPrefix, strlen(logPrefix))) {
+            continue;
+        }
+
+        if ((copiedFiles >= maxFileNum) && (maxFileNum != -1)) {
+            ALOGD("Skipped %s\n", dirent_list[i]->d_name);
+            continue;
+        }
+
+        copiedFiles++;
+
+        CommandOptions options = CommandOptions::WithTimeout(120).Build();
+        std::string srcLogFile = srcDir + "/" + dirent_list[i]->d_name;
+        std::string destLogFile = destDir + "/" + dirent_list[i]->d_name;
+
+        std::string copyCmd = "/vendor/bin/cp " + srcLogFile + " " + destLogFile;
+
+        ALOGD("Copying %s to %s\n", srcLogFile.c_str(), destLogFile.c_str());
+        RunCommandToFd(fd, "CP DIAG LOGS", { "/vendor/bin/sh", "-c", copyCmd.c_str() }, options);
+    }
+
+    while (num_entries--) {
+        free(dirent_list[num_entries]);
+    }
+
+    free(dirent_list);
+}
+
+void DumpstateDevice::dumpModem(int fd, int fdModem)
+{
+    std::string modemLogDir = android::base::GetProperty(MODEM_LOG_LOC_PROPERTY, "");
+    if (modemLogDir.empty()) {
+        ALOGD("No modem log place is set");
+        return;
+    }
+
+    std::string filePrefix = android::base::GetProperty(MODEM_LOG_PREFIX_PROPERTY, "");
+
+    if (filePrefix.empty()) {
+        ALOGD("Modem log prefix is not set");
+        return;
+    }
+
+    const std::string modemLogCombined = modemLogDir + "/" + filePrefix + "all.tar";
+    const std::string modemLogAllDir = modemLogDir + "/modem_log";
+
+    RunCommandToFd(fd, "MKDIR MODEM LOG", {"/vendor/bin/mkdir", "-p", modemLogAllDir.c_str()}, CommandOptions::WithTimeout(2).Build());
+
+    if (!PropertiesHelper::IsUserBuild()) {
+        char cmd[256] = { 0 };
+
+        RunCommandToFd(fd, "MODEM RFS INFO", {"/vendor/bin/find /data/vendor/rfs/mpss/OEMFI/"}, CommandOptions::WithTimeout(2).Build());
+        RunCommandToFd(fd, "MODEM DIAG SYSTEM PROPERTIES", {"/vendor/bin/getprop | grep vendor.sys.modem.diag"}, CommandOptions::WithTimeout(2).Build());
+
+        android::base::SetProperty(MODEM_EFS_DUMP_PROPERTY, "true");
+
+        const std::string diagLogDir = "/data/vendor/radio/diag_logs/logs";
+        const std::string tcpdumpLogDir = "/data/vendor/tcpdump_logger/logs";
+        const std::string extendedLogDir = "/data/vendor/radio/extended_logs";
+        const std::vector <std::string> rilAndNetmgrLogs
+            {
+                "/data/vendor/radio/ril_log0",
+                "/data/vendor/radio/ril_log0_old",
+                "/data/vendor/radio/ril_log1",
+                "/data/vendor/radio/ril_log1_old",
+                "/data/vendor/radio/qmi_fw_log",
+                "/data/vendor/radio/qmi_fw_log_old",
+                "/data/vendor/radio/imsdatadaemon_log",
+                "/data/vendor/radio/imsdatadaemon_log_old",
+                "/data/vendor/netmgr/netmgr_log",
+                "/data/vendor/netmgr/netmgr_log_old",
+                "/data/vendor/radio/power_anomaly_data.txt",
+                "/data/vendor/radio/diag_logs/diag_trace.txt",
+                "/data/vendor/radio/diag_logs/diag_trace_old.txt",
+                "/data/vendor/radio/diag_logs/logs/diag_poweron_log.qmdl",
+                "/data/vendor/radio/metrics_data",
+                "/data/vendor/ssrlog/ssr_log.txt",
+                "/data/vendor/ssrlog/ssr_log_old.txt",
+                "/data/vendor/rfs/mpss/modem_efs"
+            };
+
+        bool smlogEnabled = android::base::GetBoolProperty(MODEM_LOGGING_SWITCH, false) && !access("/vendor/bin/smlog_dump", X_OK);
+        bool diagLogEnabled = android::base::GetBoolProperty(DIAG_MDLOG_PERSIST_PROPERTY, false);
+        bool tcpdumpEnabled = android::base::GetBoolProperty(TCPDUMP_PERSIST_PROPERTY, false);
+
+        if (smlogEnabled) {
+            RunCommandToFd(fd, "SMLOG DUMP", {"smlog_dump", "-d", "-o", modemLogAllDir.c_str()}, CommandOptions::WithTimeout(10).Build());
+        } else if (diagLogEnabled) {
+            bool diagLogStarted = android::base::GetBoolProperty( DIAG_MDLOG_STATUS_PROPERTY, false);
+
+            if (diagLogStarted) {
+                android::base::SetProperty(DIAG_MDLOG_PROPERTY, "false");
+                ALOGD("Stopping diag_mdlog...\n");
+                if (android::base::WaitForProperty(DIAG_MDLOG_STATUS_PROPERTY, "false", std::chrono::seconds(20))) {
+                    ALOGD("diag_mdlog exited");
+                } else {
+                    ALOGE("Waited mdlog timeout after 20 second");
+                }
+            } else {
+                ALOGD("diag_mdlog is not running");
+            }
+
+            dumpLogs(fd, diagLogDir, modemLogAllDir, android::base::GetIntProperty(DIAG_MDLOG_NUMBER_BUGREPORT, 100), DIAG_LOG_PREFIX);
+
+            if (diagLogStarted) {
+                ALOGD("Restarting diag_mdlog...");
+                android::base::SetProperty(DIAG_MDLOG_PROPERTY, "true");
+            }
+        }
+
+        if (tcpdumpEnabled) {
+            dumpLogs(fd, tcpdumpLogDir, modemLogAllDir, android::base::GetIntProperty(TCPDUMP_NUMBER_BUGREPORT, 5), TCPDUMP_LOG_PREFIX);
+        }
+
+        for (const auto& logFile : rilAndNetmgrLogs) {
+            RunCommandToFd(fd, "CP MODEM LOG", {"/vendor/bin/cp", logFile.c_str(), modemLogAllDir.c_str()}, CommandOptions::WithTimeout(2).Build());
+        }
+
+        //Dump IPA log
+        snprintf(cmd, sizeof(cmd),
+                "cat /d/ipc_logging/ipa/log > %s/ipa_log",
+                modemLogAllDir.c_str());
+        RunCommandToFd(fd, "Dump IPA log", {"/vendor/bin/sh", "-c", cmd});
+
+        // Dump esoc-mdm log
+        snprintf(cmd, sizeof(cmd),
+                "cat /sys/kernel/debug/ipc_logging/esoc-mdm/log > %s/esoc-mdm_log.txt",
+                modemLogAllDir.c_str());
+        RunCommandToFd(fd, "ESOC-MDM LOG", {"/vendor/bin/sh", "-c", cmd});
+
+        // Dump pcie0 log
+        snprintf(cmd, sizeof(cmd),
+                "cat /sys/kernel/debug/ipc_logging/pcie0-long/log > %s/pcie0-long_log.txt",
+                modemLogAllDir.c_str());
+        RunCommandToFd(fd, "PCIE0-LONG LOG", {"/vendor/bin/sh", "-c", cmd});
+
+        snprintf(cmd, sizeof(cmd),
+                "cat /sys/kernel/debug/ipc_logging/pcie0-short/log > %s/pcie0-short_log.txt",
+                modemLogAllDir.c_str());
+        RunCommandToFd(fd, "PCIE0-SHORT LOG", {"/vendor/bin/sh", "-c", cmd});
+
+        dumpLogs(fd, extendedLogDir, modemLogAllDir, 100, EXTENDED_LOG_PREFIX);
+        android::base::SetProperty(MODEM_EFS_DUMP_PROPERTY, "false");
+    }
+
+    RunCommandToFd(fd, "TAR LOG", {"/vendor/bin/tar", "cvf", modemLogCombined.c_str(), "-C", modemLogAllDir.c_str(), "."}, CommandOptions::WithTimeout(120).Build());
+    RunCommandToFd(fd, "CHG PERM", {"/vendor/bin/chmod", "a+w", modemLogCombined.c_str()}, CommandOptions::WithTimeout(2).Build());
+
+    std::vector<uint8_t> buffer(65536);
+    android::base::unique_fd fdLog(TEMP_FAILURE_RETRY(open(modemLogCombined.c_str(), O_RDONLY | O_CLOEXEC | O_NONBLOCK)));
+
+    if (fdLog >= 0) {
+        while (1) {
+            ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fdLog, buffer.data(), buffer.size()));
+
+            if (bytes_read == 0) {
+                break;
+            } else if (bytes_read < 0) {
+                ALOGD("read(%s): %s\n", modemLogCombined.c_str(), strerror(errno));
+                break;
+            }
+
+            ssize_t result = TEMP_FAILURE_RETRY(write(fdModem, buffer.data(), bytes_read));
+
+            if (result != bytes_read) {
+                ALOGD("Failed to write %ld bytes, actually written: %ld", bytes_read, result);
+                break;
+            }
+        }
+    }
+
+    RunCommandToFd(fd, "RM MODEM DIR", { "/vendor/bin/rm", "-r", modemLogAllDir.c_str()}, CommandOptions::WithTimeout(2).Build());
+    RunCommandToFd(fd, "RM LOG", { "/vendor/bin/rm", modemLogCombined.c_str()}, CommandOptions::WithTimeout(2).Build());
+}
+
+static void DumpTouch(int fd) {
+    const char touch_spi_path[] = "/sys/class/spi_master/spi1/spi1.0";
+    char cmd[256];
+
+    snprintf(cmd, sizeof(cmd), "%s/appid", touch_spi_path);
+    if (!access(cmd, R_OK)) {
+        // Touch firmware version
+        DumpFileToFd(fd, "STM touch firmware version", cmd);
+
+        // Touch controller status
+        snprintf(cmd, sizeof(cmd), "%s/status", touch_spi_path);
+        DumpFileToFd(fd, "STM touch status", cmd);
+
+        // Mutual raw data
+        snprintf(cmd, sizeof(cmd),
+                 "echo 13 00 > %s/stm_fts_cmd && cat %s/stm_fts_cmd",
+                 touch_spi_path, touch_spi_path);
+        RunCommandToFd(fd, "Mutual Raw", {"/vendor/bin/sh", "-c", cmd});
+
+        // Mutual strength data
+        snprintf(cmd, sizeof(cmd),
+                 "echo 17 > %s/stm_fts_cmd && cat %s/stm_fts_cmd",
+                 touch_spi_path, touch_spi_path);
+        RunCommandToFd(fd, "Mutual Strength", {"/vendor/bin/sh", "-c", cmd});
+
+        // Self raw data
+        snprintf(cmd, sizeof(cmd),
+                 "echo 15 00 > %s/stm_fts_cmd && cat %s/stm_fts_cmd",
+                 touch_spi_path, touch_spi_path);
+        RunCommandToFd(fd, "Self Raw", {"/vendor/bin/sh", "-c", cmd});
+    }
+
+    if (!access("/proc/fts/driver_test", R_OK)) {
+        RunCommandToFd(fd, "Mutual Raw Data",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 23 00 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+        RunCommandToFd(fd, "Mutual Baseline Data",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 23 03 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+        RunCommandToFd(fd, "Mutual Strength Data",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 23 02 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+        RunCommandToFd(fd, "Self Raw Data",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 24 00 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+        RunCommandToFd(fd, "Self Baseline Data",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 24 03 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+        RunCommandToFd(fd, "Self Strength Data",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 24 02 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+        RunCommandToFd(fd, "Mutual Compensation",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 32 10 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+        RunCommandToFd(fd, "Self Compensation",
+                       {"/vendor/bin/sh", "-c",
+                        "echo 33 12 > /proc/fts/driver_test && "
+                        "cat /proc/fts/driver_test"});
+    }
+}
+
+static void DumpF2FS(int fd) {
+    DumpFileToFd(fd, "F2FS", "/sys/kernel/debug/f2fs/status");
+    DumpFileToFd(fd, "F2FS - fragmentation", "/proc/fs/f2fs/dm-3/segment_info");
+}
+
+static void DumpUFS(int fd) {
+    DumpFileToFd(fd, "UFS model", "/sys/block/sda/device/model");
+    DumpFileToFd(fd, "UFS rev", "/sys/block/sda/device/rev");
+    DumpFileToFd(fd, "UFS size", "/sys/block/sda/size");
+    DumpFileToFd(fd, "UFS show_hba", "/sys/kernel/debug/ufshcd0/show_hba");
+    DumpFileToFd(fd, "UFS err_stats", "/sys/kernel/debug/ufshcd0/stats/err_stats");
+    DumpFileToFd(fd, "UFS io_stats", "/sys/kernel/debug/ufshcd0/stats/io_stats");
+    DumpFileToFd(fd, "UFS req_stats", "/sys/kernel/debug/ufshcd0/stats/req_stats");
+
+    std::string bootdev = android::base::GetProperty(UFS_BOOTDEVICE, "");
+    if (!bootdev.empty()) {
+        DumpFileToFd(fd, "UFS Slow IO Read", "/sys/devices/platform/soc/" + bootdev + "/slowio_read_cnt");
+        DumpFileToFd(fd, "UFS Slow IO Write", "/sys/devices/platform/soc/" + bootdev + "/slowio_write_cnt");
+        DumpFileToFd(fd, "UFS Slow IO Unmap", "/sys/devices/platform/soc/" + bootdev + "/slowio_unmap_cnt");
+        DumpFileToFd(fd, "UFS Slow IO Sync", "/sys/devices/platform/soc/" + bootdev + "/slowio_sync_cnt");
+
+        std::string ufs_health = "for f in $(find /sys/devices/platform/soc/" + bootdev + "/health -type f); do if [[ -r $f && -f $f ]]; then echo --- $f; cat $f; echo ''; fi; done";
+        RunCommandToFd(fd, "UFS health", {"/vendor/bin/sh", "-c", ufs_health.c_str()});
+    }
+}
+
+static void DumpVibrator(int fd) {
+    const std::string dir = "/sys/class/leds/vibrator/device/";
+    const std::vector<std::string> files {
+        "asp_enable",
+        "comp_enable",
+        "cp_dig_scale",
+        "cp_trigger_duration",
+        "cp_trigger_index",
+        "cp_trigger_q_sub",
+        "cp_trigger_queue",
+        "dig_scale",
+        "exc_enable",
+        "f0_stored",
+        "fw_rev",
+        "heartbeat",
+        "hw_reset",
+        "leds/vibrator/activate",
+        "leds/vibrator/duration",
+        "leds/vibrator/state",
+        "num_waves",
+        "q_stored",
+        "redc_comp_enable",
+        "redc_stored",
+        "standby_timeout",
+        "vbatt_max",
+        "vbatt_min",
+    };
+
+    for (const auto &file : files) {
+        DumpFileToFd(fd, "Vibrator", dir+file);
+    }
+}
+
+// Methods from ::android::hardware::dumpstate::V1_0::IDumpstateDevice follow.
+Return<void> DumpstateDevice::dumpstateBoard(const hidl_handle& handle) {
+    // Exit when dump is completed since this is a lazy HAL.
+    addPostCommandTask([]() {
+        exit(0);
+    });
+
+    if (handle == nullptr || handle->numFds < 1) {
+        ALOGE("no FDs\n");
+        return Void();
+    }
+
+    int fd = handle->data[0];
+    if (fd < 0) {
+        ALOGE("invalid FD: %d\n", handle->data[0]);
+        return Void();
+    }
+
+    RunCommandToFd(fd, "VENDOR PROPERTIES", {"/vendor/bin/getprop"});
+    DumpFileToFd(fd, "SoC serial number", "/sys/devices/soc0/serial_number");
+    DumpFileToFd(fd, "CPU present", "/sys/devices/system/cpu/present");
+    DumpFileToFd(fd, "CPU online", "/sys/devices/system/cpu/online");
+    DumpTouch(fd);
+
+    DumpF2FS(fd);
+    DumpUFS(fd);
+
+    DumpFileToFd(fd, "INTERRUPTS", "/proc/interrupts");
+    DumpFileToFd(fd, "Sleep Stats", "/sys/power/system_sleep/stats");
+    DumpFileToFd(fd, "Power Management Stats", "/sys/power/rpmh_stats/master_stats");
+    DumpFileToFd(fd, "WLAN Power Stats", "/sys/kernel/wlan/power_stats");
+    DumpFileToFd(fd, "LL-Stats", "/d/wlan0/ll_stats");
+    DumpFileToFd(fd, "WLAN Connect Info", "/d/wlan0/connect_info");
+    DumpFileToFd(fd, "WLAN Offload Info", "/d/wlan0/offload_info");
+    DumpFileToFd(fd, "WLAN Roaming Stats", "/d/wlan0/roam_stats");
+    DumpFileToFd(fd, "ICNSS Stats", "/d/icnss/stats");
+    DumpFileToFd(fd, "SMD Log", "/d/ipc_logging/smd/log");
+    RunCommandToFd(fd, "ION HEAPS", {"/vendor/bin/sh", "-c", "for d in $(ls -d /d/ion/*); do for f in $(ls $d); do echo --- $d/$f; cat $d/$f; done; done"});
+    DumpFileToFd(fd, "dmabuf info", "/d/dma_buf/bufinfo");
+    DumpFileToFd(fd, "dmabuf process info", "/d/dma_buf/dmaprocs");
+    RunCommandToFd(fd, "Temperatures", {"/vendor/bin/sh", "-c", "for f in /sys/class/thermal/thermal* ; do type=`cat $f/type` ; temp=`cat $f/temp` ; echo \"$type: $temp\" ; done"});
+    RunCommandToFd(fd, "Cooling Device Current State", {"/vendor/bin/sh", "-c", "for f in /sys/class/thermal/cooling* ; do type=`cat $f/type` ; temp=`cat $f/cur_state` ; echo \"$type: $temp\" ; done"});
+    RunCommandToFd(
+        fd, "LMH info",
+        {"/vendor/bin/sh", "-c",
+         "for f in /sys/bus/platform/drivers/msm_lmh_dcvs/*qcom,limits-dcvs@*/lmh_freq_limit; do "
+         "state=`cat $f` ; echo \"$f: $state\" ; done"});
+    RunCommandToFd(fd, "CPU time-in-state", {"/vendor/bin/sh", "-c", "for cpu in /sys/devices/system/cpu/cpu*; do f=$cpu/cpufreq/stats/time_in_state; if [ ! -f $f ]; then continue; fi; echo $f:; cat $f; done"});
+    RunCommandToFd(fd, "CPU cpuidle", {"/vendor/bin/sh", "-c", "for cpu in /sys/devices/system/cpu/cpu*; do for d in $cpu/cpuidle/state*; do if [ ! -d $d ]; then continue; fi; echo \"$d: `cat $d/name` `cat $d/desc` `cat $d/time` `cat $d/usage`\"; done; done"});
+    RunCommandToFd(fd, "Airbrush debug info", {"/vendor/bin/sh", "-c", "for f in `ls /sys/devices/platform/soc/c84000.i2c/i2c-4/4-0066/@(*curr|temperature|vbat|total_power)`; do echo \"$f: `cat $f`\" ; done; file=/d/airbrush/airbrush_sm/chip_state; echo \"$file: `cat $file`\""});
+    DumpFileToFd(fd, "MDP xlogs", "/data/vendor/display/mdp_xlog");
+    DumpFileToFd(fd, "TCPM logs", "/d/tcpm/usbpd0");
+    DumpFileToFd(fd, "PD Engine", "/d/pd_engine/usbpd0");
+    DumpFileToFd(fd, "ipc-local-ports", "/d/msm_ipc_router/dump_local_ports");
+    RunCommandToFd(fd, "USB Device Descriptors", {"/vendor/bin/sh", "-c", "cd /sys/bus/usb/devices/1-1 && cat product && cat bcdDevice; cat descriptors | od -t x1 -w16 -N96"});
+    RunCommandToFd(fd, "Power supply properties", {"/vendor/bin/sh", "-c", "for f in `ls /sys/class/power_supply/*/uevent` ; do echo \"------ $f\\n`cat $f`\\n\" ; done"});
+    RunCommandToFd(fd, "PMIC Votables", {"/vendor/bin/sh", "-c", "cat /sys/kernel/debug/pmic-votable/*/status"});
+    DumpFileToFd(fd, "Battery cycle count", "/d/google_battery/cycle_count_bins");
+    DumpFileToFd(fd, "Maxim FG History", "/dev/maxfg_history");
+    DumpFileToFd(fd, "Maxim FG registers", "/d/regmap/1-0036/registers");
+    DumpFileToFd(fd, "Maxim FG NV RAM", "/d/regmap/1-000b/registers");
+    RunCommandToFd(fd, "Google Charger", {"/vendor/bin/sh", "-c", "cd /d/google_charger/; for f in `ls pps_*` ; do echo \"$f: `cat $f`\" ; done"});
+    RunCommandToFd(fd, "Google Battery", {"/vendor/bin/sh", "-c", "cd /d/google_battery/; for f in `ls ssoc_*` ; do echo \"$f: `cat $f`\" ; done"});
+    DumpFileToFd(fd, "WLC VER", "/sys/devices/platform/soc/a88000.i2c/i2c-0/0-0061/version");
+    DumpFileToFd(fd, "WLC STATUS", "/sys/devices/platform/soc/a88000.i2c/i2c-0/0-0061/status");
+
+    RunCommandToFd(fd, "eSIM Status", {"/vendor/bin/sh", "-c", "od -t x1 /sys/firmware/devicetree/base/chosen/cdt/cdb2/esim"});
+    DumpFileToFd(fd, "Modem Stat", "/data/vendor/modem_stat/debug.txt");
+    DumpFileToFd(fd, "Pixel trace", "/d/tracing/instances/pixel-trace/trace");
+
+    // Slower dump put later in case stuck the rest of dump
+    // Timeout after 3s as TZ log missing EOF
+    RunCommandToFd(fd, "QSEE logs", {"/vendor/bin/sh", "-c", "/vendor/bin/timeout 3 cat /d/tzdbg/qsee_log"});
+    if (handle->numFds < 2) {
+        ALOGE("no FD for modem\n");
+    } else {
+        int fdModem = handle->data[1];
+        dumpModem(fd, fdModem);
+    }
+
+    // Citadel info (only enabled on -eng and -userdebug builds)
+    if (!PropertiesHelper::IsUserBuild()) {
+        RunCommandToFd(fd, "Citadel ID", {"/vendor/bin/hw/citadel_updater", "--id"});
+        RunCommandToFd(fd, "Citadel VER", {"/vendor/bin/hw/citadel_updater", "-lv"});
+        RunCommandToFd(fd, "Citadel SELFTEST", {"/vendor/bin/hw/citadel_updater", "--selftest"});
+    }
+
+    DumpVibrator(fd);
+
+    // Dump various events in WiFi data path
+    DumpFileToFd(fd, "WLAN DP Trace", "/d/wlan/dpt_stats/dump_set_dpt_logs");
+
+    // Keep this at the end as very long on not for humans
+    DumpFileToFd(fd, "WLAN FW Log Symbol Table", "/vendor/firmware/Data.msc");
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace dumpstate
+}  // namespace hardware
+}  // namespace android
diff --git a/dumpstate/DumpstateDevice.h b/dumpstate/DumpstateDevice.h
new file mode 100644
index 0000000..7c60083
--- /dev/null
+++ b/dumpstate/DumpstateDevice.h
@@ -0,0 +1,54 @@
+/*
+ * 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 ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H
+#define ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H
+
+#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace dumpstate {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct DumpstateDevice : public IDumpstateDevice {
+  // Methods from ::android::hardware::dumpstate::V1_0::IDumpstateDevice follow.
+  Return<void> dumpstateBoard(const hidl_handle& h) override;
+
+  void dumpLogs(int fd, std::string srcDir, std::string destDir, int maxFileNum,
+                const char *logPrefix);
+  void dumpModem(int fd, int fdModem);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace dumpstate
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H
diff --git a/dumpstate/android.hardware.dumpstate@1.0-service.bramble.rc b/dumpstate/android.hardware.dumpstate@1.0-service.bramble.rc
new file mode 100644
index 0000000..1933a1c
--- /dev/null
+++ b/dumpstate/android.hardware.dumpstate@1.0-service.bramble.rc
@@ -0,0 +1,10 @@
+service vendor.dumpstate-1-0 /vendor/bin/hw/android.hardware.dumpstate@1.0-service.bramble
+    class hal
+    user system
+    group system vendor_rfs
+    interface android.hardware.dumpstate@1.0::IDumpstateDevice default
+    oneshot
+    disabled
+
+on boot
+    chmod 0444 /sys/kernel/debug/tzdbg/qsee_log
diff --git a/dumpstate/service.cpp b/dumpstate/service.cpp
new file mode 100644
index 0000000..842c52c
--- /dev/null
+++ b/dumpstate/service.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "android.hardware.dumpstate@1.0-service.bramble"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "DumpstateDevice.h"
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using ::android::hardware::dumpstate::V1_0::implementation::DumpstateDevice;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+
+int main(int /* argc */, char* /* argv */ []) {
+  sp<IDumpstateDevice> dumpstate = new DumpstateDevice;
+  configureRpcThreadpool(1, true);
+
+  android::status_t status = dumpstate->registerAsService();
+
+  if (status != android::OK)
+  {
+    ALOGE("Could not register DumpstateDevice service (%d).", status);
+    return -1;
+  }
+
+  joinRpcThreadpool();
+}
diff --git a/framework_manifest.xml b/framework_manifest.xml
new file mode 100644
index 0000000..b2276a5
--- /dev/null
+++ b/framework_manifest.xml
@@ -0,0 +1,39 @@
+<!-- Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<manifest version="1.0" type="framework">
+    <!-- atfwd -->
+    <hal format="hidl">
+        <name>vendor.qti.hardware.radio.atcmdfwd</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IAtCmdFwd</name>
+            <instance>AtCmdFwdService</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/fstab.hardware b/fstab.hardware
new file mode 100644
index 0000000..b601aad
--- /dev/null
+++ b/fstab.hardware
@@ -0,0 +1,12 @@
+# Android fstab file.
+
+#<src>                                                  <mnt_point>            <type>  <mnt_flags and options>                              <fs_mgr_flags>
+system                                                  /system                ext4    ro,barrier=1                                         wait,slotselect,avb=vbmeta_system,logical,first_stage_mount
+vendor                                                  /vendor                ext4    ro,barrier=1                                         wait,slotselect,avb=vbmeta,logical,first_stage_mount
+product                                                 /product               ext4    ro,barrier=1                                         wait,slotselect,avb,logical,first_stage_mount
+/dev/block/by-name/metadata                             /metadata              ext4    noatime,nosuid,nodev,discard,sync                    wait,formattable,first_stage_mount
+/dev/block/bootdevice/by-name/modem                     /vendor/firmware_mnt   vfat    ro,shortname=lower,uid=0,gid=1000,dmask=227,fmask=337,context=u:object_r:firmware_file:s0 wait,slotselect
+/dev/block/bootdevice/by-name/misc                      /misc                  emmc    defaults                                             defaults
+/dev/block/bootdevice/by-name/userdata                  /data                  f2fs    noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier       latemount,wait,check,quota,formattable,fileencryption=ice,reservedsize=128M,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,keydirectory=/metadata/vold/metadata_encryption,checkpoint=fs
+/devices/platform/soc/a600000.ssusb/a600000.dwc3*       auto                   vfat    defaults                                             voldmanaged=usb:auto
+/dev/block/zram0                                        none                   swap    defaults                                             zramsize=2147483648,max_comp_streams=8,zram_loopback_path=/data/unencrypted/zram_swap,zram_loopback_size=512M
diff --git a/fstab.persist b/fstab.persist
new file mode 100644
index 0000000..f3840b1
--- /dev/null
+++ b/fstab.persist
@@ -0,0 +1,4 @@
+# Keep persist in an fstab file, since we need to run fsck on it after abnormal shutdown.
+
+#<src>                                                <mnt_point>         <type>  <mnt_flags and options>         <fs_mgr_flags>
+/dev/block/platform/soc/1d84000.ufshc/by-name/persist /mnt/vendor/persist ext4    nosuid,nodev,noatime,barrier=1  wait
diff --git a/fstab.postinstall b/fstab.postinstall
new file mode 100644
index 0000000..83bb3c6
--- /dev/null
+++ b/fstab.postinstall
@@ -0,0 +1,17 @@
+#
+# 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.
+
+#<src>                    <mnt_point>  <type> <mnt_flags and options> <fs_mgr_flags>
+system                    /postinstall ext4   ro,nosuid,nodev,noexec  slotselect_other,logical,avb_keys=/product/etc/security/avb/system_other.avbpubkey
diff --git a/gps.conf b/gps.conf
new file mode 100644
index 0000000..9f5a702
--- /dev/null
+++ b/gps.conf
@@ -0,0 +1,297 @@
+#Version check for XTRA
+#DISABLE = 0
+#AUTO    = 1
+#XTRA2   = 2
+#XTRA3   = 3
+XTRA_VERSION_CHECK=0
+
+# Error Estimate
+# _SET = 1
+# _CLEAR = 0
+ERR_ESTIMATE=0
+
+#NTP server
+#NTP_SERVER setting is in modem NV
+
+#XTRA CA path
+XTRA_CA_PATH=/system/etc/security/cacerts
+
+# DEBUG LEVELS: 0 - none, 1 - Error, 2 - Warning, 3 - Info
+#               4 - Debug, 5 - Verbose
+# If DEBUG_LEVEL is commented, Android's logging levels will be used
+DEBUG_LEVEL = 2
+
+# Intermediate position report, 1=enable, 0=disable
+INTERMEDIATE_POS=0
+
+# Below bit mask configures how GPS functionalities
+# should be locked when user turns off GPS on Settings
+# Set bit 0x1 if MO GPS functionalities are to be locked
+# Set bit 0x2 if NI GPS functionalities are to be locked
+# default – both MO and NI locked for maximal privacy
+#GPS_LOCK = 3
+
+# supl version 1.0
+#SUPL_VER=0x10000
+
+# Emergency SUPL, 1=enable, 0=disable
+SUPL_ES=1
+
+#Choose PDN for Emergency SUPL
+#1 - Use emergency PDN
+#0 - Use regular SUPL PDN for Emergency SUPL
+#USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=0
+
+#SUPL_MODE is a bit mask set in config.xml per carrier by default.
+#If it is uncommented here, this value will overwrite the value from
+#config.xml.
+#MSA=0X2
+#MSB=0X1
+#SUPL_MODE=
+
+# GPS Capabilities bit mask
+# SCHEDULING = 0x01
+# MSB = 0x02
+# MSA = 0x04
+# ON_DEMAND_TIME = 0x10
+# GEOFENCE = 0x20
+# default = ON_DEMAND_TIME | MSA | MSB | SCHEDULING | GEOFENCE
+CAPABILITIES=0x37
+
+# Accuracy threshold for intermediate positions
+# less accurate positions are ignored, 0 for passing all positions
+# ACCURACY_THRES=5000
+
+################################
+##### AGPS server settings #####
+################################
+
+# FOR SUPL SUPPORT, set the following
+# SUPL_HOST=supl.host.com or IP
+# SUPL_PORT=1234
+
+# FOR MO SUPL SUPPORT, set the following
+# MO_SUPL_HOST=supl.host.com or IP
+# MO_SUPL_PORT=1234
+
+# FOR C2K PDE SUPPORT, set the following
+# C2K_HOST=c2k.pde.com or IP
+# C2K_PORT=1234
+
+# Bitmask of slots that are available
+# for write/install to, where 1s indicate writable,
+# and the default value is 0 where no slots
+# are writable. For example, AGPS_CERT_WRITABLE_MASK
+# of b1000001010 makes 3 slots available
+# and the remaining 7 slots unwritable.
+#AGPS_CERT_WRITABLE_MASK=0
+
+####################################
+#  LTE Positioning Profile Settings
+####################################
+# 0: Enable RRLP on LTE(Default)
+# 1: Enable LPP_User_Plane on LTE
+# 2: Enable LPP_Control_Plane
+# 3: Enable both LPP_User_Plane and LPP_Control_Plane
+#LPP_PROFILE = 2
+
+####################################
+#Datum Type
+####################################
+# 0: WGS-84
+# 1: PZ-90
+DATUM_TYPE = 0
+
+################################
+# EXTRA SETTINGS
+################################
+# NMEA provider (1=Modem Processor, 0=Application Processor)
+NMEA_PROVIDER=0
+# Mark if it is a SGLTE target (1=SGLTE, 0=nonSGLTE)
+SGLTE_TARGET=0
+
+##################################################
+# Select Positioning Protocol on A-GLONASS system
+##################################################
+# 0x1: RRC CPlane
+# 0x2: RRLP UPlane
+# 0x4: LLP Uplane
+#A_GLONASS_POS_PROTOCOL_SELECT = 0
+
+##################################################
+# Select technology for LPPe Control Plane
+##################################################
+# 0x1: DBH for LPPe CP
+# 0x2: WLAN AP Measurements for LPPe CP
+# 0x4: SRN AP measurement for CP
+# 0x8: Sensor Barometer Measurement LPPe CP
+#LPPE_CP_TECHNOLOGY = 0
+
+##################################################
+# Select technology for LPPe User Plane
+##################################################
+# 0x1: DBH for LPPe UP
+# 0x2: WLAN AP Measurements for LPPe UP
+# 0x4: SRN AP measurement for UP
+# 0x8: Sensor Barometer Measurement LPPe UP
+#LPPE_UP_TECHNOLOGY = 0
+
+##################################################
+# AGPS_CONFIG_INJECT
+##################################################
+# enable/disable injection of AGPS configurations:
+#     SUPL_VER
+#     SUPL_HOST
+#     SUPL_PORT
+#     MO_SUPL_HOST
+#     MO_SUPL_PORT
+#     C2K_HOST
+#     C2K_PORT
+#     LPP_PROFILE
+#     A_GLONASS_POS_PROTOCOL_SELECT
+# 0: disable
+# 1: enable
+AGPS_CONFIG_INJECT = 1
+
+##################################################
+# GNSS settings for automotive use cases
+# Configurations in following section are
+# specific to automotive use cases, others
+# please do not change, keep the default values
+##################################################
+
+# AP Coarse Timestamp Uncertainty
+##################################################
+# default : 10
+# AP time stamp uncertainty, until GNSS receiver
+# is able to acquire better timing information
+AP_TIMESTAMP_UNCERTAINTY = 10
+
+##################################################
+# QDR engine availability status
+##################################################
+# 0 : NO QDR (default)
+# 1 : QDR enabled
+# This settings enables QDR Configuration for
+# automotive use case, if enabled then
+# DR_AP_Service needs to be enabled in izat.conf
+#EXTERNAL_DR_ENABLED = 0
+
+#####################################
+# DR_SYNC Pulse Availability
+#####################################
+# 0 : DR_SYNC pulse not available (default)
+# 1 : DR_SYNC pulse available
+# This configuration enables the driver to make use
+# of PPS events generated by DR_SYNC pulse
+# Standard Linux PPS driver needs to be enabled
+DR_SYNC_ENABLED = 0
+
+#####################################
+# PPS Device name
+#####################################
+PPS_DEVICENAME = /dev/pps0
+
+#####################################
+# Ignore PPS at Startup and after long outage
+#####################################
+IGNORE_PPS_PULSE_COUNT = 1
+
+#####################################
+# Long GNSS RF outage in seconds
+#####################################
+GNSS_OUTAGE_DURATION = 10
+
+#####################################
+# AP Clock Accuracy
+#####################################
+# Quality of APPS processor clock (in PPM).
+# Value specified is used for calculation of
+# APPS time stamp uncertainty
+AP_CLOCK_PPM = 100
+
+#####################################
+# MAX ms difference to detect missing pulse
+#####################################
+# Specifies time threshold in ms to validate any missing PPS pulses
+MISSING_PULSE_TIME_DELTA = 900
+
+#####################################
+# Propagation time uncertainty
+#####################################
+# This settings enables time uncertainty propagation
+# logic incase of missing PPS pulse
+PROPAGATION_TIME_UNCERTAINTY = 1
+
+#######################################
+#  APN / IP Type Configuration
+#  APN and IP Type to use for setting
+#  up WWAN call.
+#  Use below values for IP Type:
+#  v4 = 4
+#  v6 = 6
+#  v4v6 = 10
+#######################################
+# INTERNET_APN = abc.xyz
+# INTERNET_IP_TYPE = 4
+# SUPL_APN = abc.xyz
+# SUPL_IP_TYPE = 4
+
+#####################################
+# Modem type
+#####################################
+# This setting configures modem type
+# (external=0 or internal=1)
+# comment out the next line to vote
+# for the first modem in the list
+MODEM_TYPE = 0
+
+##################################################
+# CONSTRAINED TIME UNCERTAINTY MODE
+##################################################
+# 0 : disabled (default)
+# 1 : enabled
+# This setting enables GPS engine to keep its time
+# uncertainty below the specified constraint
+#CONSTRAINED_TIME_UNCERTAINTY_ENABLED = 0
+
+# If constrained time uncertainty mode is enabled,
+# this setting specifies the time uncertainty
+# threshold that gps engine need to maintain.
+# In unit of milli-seconds.
+# Default is 0.0 meaning that modem default value
+# of time uncertainty threshold will be used.
+#CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD = 0.0
+
+# If constrained time uncertainty mode is enabled,
+# this setting specifies the power budget that
+# gps engine is allowed to spend to maintain the time
+# uncertainty.
+# Default is 0 meaning that GPS engine is not constained
+# by power budget and can spend as much power as needed.
+# In unit of 0.1 milli watt second.
+#CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET = 0
+
+##################################################
+# POSITION ASSISTED CLOCK ESTIMATOR
+##################################################
+# 0 : disabled (default)
+# 1 : enabled
+# This setting enables GPS engine to estimate clock
+# bias and drift when the signal from at least 1
+# SV is available and the UEÂ’s position is known by
+# other position engines.
+#POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED = 0
+
+#####################################
+# proxyAppPackageName
+#####################################
+# This is a string that is sent to the framework
+# in nfwNotifyCb callback
+PROXY_APP_PACKAGE_NAME = com.google.android.carrierlocation
+
+#####################################
+# CP_MTLR_ES
+#####################################
+# CP MTLR ES, 1=enable, 0=disable
+CP_MTLR_ES=1
diff --git a/gpt-utils/Android.mk b/gpt-utils/Android.mk
new file mode 100644
index 0000000..6dd1a44
--- /dev/null
+++ b/gpt-utils/Android.mk
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := gpt-utils.cpp
+ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true)
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+endif
+LOCAL_SHARED_LIBRARIES := liblog libz
+LOCAL_MODULE := libgptutils
+LOCAL_MODULE_OWNER := qti
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := gpt-utils.cpp
+ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true)
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+endif
+LOCAL_SHARED_LIBRARIES += liblog libcutils libz
+LOCAL_EXPORT_HEADER_LIBRARY_HEADERS := libgptutils_headers
+LOCAL_MODULE := libgptutils
+LOCAL_MODULE_OWNER := qti
+LOCAL_PROPRIETARY_MODULE := true
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgptutils_headers
+LOCAL_EXPORT_C_INCLUDE_DIRS:=$(LOCAL_PATH)
+include $(BUILD_HEADER_LIBRARY)
diff --git a/gpt-utils/gpt-utils.cpp b/gpt-utils/gpt-utils.cpp
new file mode 100644
index 0000000..8636c40
--- /dev/null
+++ b/gpt-utils/gpt-utils.cpp
@@ -0,0 +1,1542 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _LARGEFILE64_SOURCE /* enable lseek64() */
+
+/******************************************************************************
+ * INCLUDE SECTION
+ ******************************************************************************/
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <scsi/ufs/ioctl.h>
+#include <scsi/ufs/ufs.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <limits.h>
+#include <dirent.h>
+#include <inttypes.h>
+#include <linux/kernel.h>
+#include <asm/byteorder.h>
+#include <map>
+#include <vector>
+#include <string>
+#define LOG_TAG "gpt-utils"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include "gpt-utils.h"
+#include <endian.h>
+#include <zlib.h>
+
+
+/******************************************************************************
+ * DEFINE SECTION
+ ******************************************************************************/
+#define BLK_DEV_FILE    "/dev/block/mmcblk0"
+/* list the names of the backed-up partitions to be swapped */
+/* extension used for the backup partitions - tzbak, abootbak, etc. */
+#define BAK_PTN_NAME_EXT    "bak"
+#define XBL_PRIMARY         "/dev/block/platform/soc/1d84000.ufshc/by-name/xbl"
+#define XBL_BACKUP          "/dev/block/platform/soc/1d84000.ufshc/by-name/xblbak"
+#define XBL_AB_PRIMARY      "/dev/block/platform/soc/1d84000.ufshc/by-name/xbl_a"
+#define XBL_AB_SECONDARY    "/dev/block/platform/soc/1d84000.ufshc/by-name/xbl_b"
+/* GPT defines */
+#define MAX_LUNS                    26
+//Size of the buffer that needs to be passed to the UFS ioctl
+#define UFS_ATTR_DATA_SIZE          32
+//This will allow us to get the root lun path from the path to the partition.
+//i.e: from /dev/block/sdaXXX get /dev/block/sda. The assumption here is that
+//the boot critical luns lie between sda to sdz which is acceptable because
+//only user added external disks,etc would lie beyond that limit which do not
+//contain partitions that interest us here.
+#define PATH_TRUNCATE_LOC (sizeof("/dev/block/sda") - 1)
+
+//From /dev/block/sda get just sda
+#define LUN_NAME_START_LOC (sizeof("/dev/block/") - 1)
+#define BOOT_LUN_A_ID 1
+#define BOOT_LUN_B_ID 2
+/******************************************************************************
+ * MACROS
+ ******************************************************************************/
+
+
+#define GET_4_BYTES(ptr)    ((uint32_t) *((uint8_t *)(ptr)) | \
+        ((uint32_t) *((uint8_t *)(ptr) + 1) << 8) | \
+        ((uint32_t) *((uint8_t *)(ptr) + 2) << 16) | \
+        ((uint32_t) *((uint8_t *)(ptr) + 3) << 24))
+
+#define GET_8_BYTES(ptr)    ((uint64_t) *((uint8_t *)(ptr)) | \
+        ((uint64_t) *((uint8_t *)(ptr) + 1) << 8) | \
+        ((uint64_t) *((uint8_t *)(ptr) + 2) << 16) | \
+        ((uint64_t) *((uint8_t *)(ptr) + 3) << 24) | \
+        ((uint64_t) *((uint8_t *)(ptr) + 4) << 32) | \
+        ((uint64_t) *((uint8_t *)(ptr) + 5) << 40) | \
+        ((uint64_t) *((uint8_t *)(ptr) + 6) << 48) | \
+        ((uint64_t) *((uint8_t *)(ptr) + 7) << 56))
+
+#define PUT_4_BYTES(ptr, y)   *((uint8_t *)(ptr)) = (y) & 0xff; \
+        *((uint8_t *)(ptr) + 1) = ((y) >> 8) & 0xff; \
+        *((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
+        *((uint8_t *)(ptr) + 3) = ((y) >> 24) & 0xff;
+
+/******************************************************************************
+ * TYPES
+ ******************************************************************************/
+using namespace std;
+enum gpt_state {
+    GPT_OK = 0,
+    GPT_BAD_SIGNATURE,
+    GPT_BAD_CRC
+};
+//List of LUN's containing boot critical images.
+//Required in the case of UFS devices
+struct update_data {
+     char lun_list[MAX_LUNS][PATH_MAX];
+     uint32_t num_valid_entries;
+};
+
+/******************************************************************************
+ * FUNCTIONS
+ ******************************************************************************/
+/**
+ *  ==========================================================================
+ *
+ *  \brief  Read/Write len bytes from/to block dev
+ *
+ *  \param [in] fd      block dev file descriptor (returned from open)
+ *  \param [in] rw      RW flag: 0 - read, != 0 - write
+ *  \param [in] offset  block dev offset [bytes] - RW start position
+ *  \param [in] buf     Pointer to the buffer containing the data
+ *  \param [in] len     RW size in bytes. Buf must be at least that big
+ *
+ *  \return  0 on success
+ *
+ *  ==========================================================================
+ */
+static int blk_rw(int fd, int rw, int64_t offset, uint8_t *buf, unsigned len)
+{
+    int r;
+
+    if (lseek64(fd, offset, SEEK_SET) < 0) {
+        fprintf(stderr, "block dev lseek64 %" PRIi64 " failed: %s\n", offset,
+                strerror(errno));
+        return -1;
+    }
+
+    if (rw)
+        r = write(fd, buf, len);
+    else
+        r = read(fd, buf, len);
+
+    if (r < 0)
+        fprintf(stderr, "block dev %s failed: %s\n", rw ? "write" : "read",
+                strerror(errno));
+    else
+        r = 0;
+
+    return r;
+}
+
+
+
+/**
+ *  ==========================================================================
+ *
+ *  \brief  Search within GPT for partition entry with the given name
+ *  or it's backup twin (name-bak).
+ *
+ *  \param [in] ptn_name        Partition name to seek
+ *  \param [in] pentries_start  Partition entries array start pointer
+ *  \param [in] pentries_end    Partition entries array end pointer
+ *  \param [in] pentry_size     Single partition entry size [bytes]
+ *
+ *  \return  First partition entry pointer that matches the name or NULL
+ *
+ *  ==========================================================================
+ */
+static uint8_t *gpt_pentry_seek(const char *ptn_name,
+                                const uint8_t *pentries_start,
+                                const uint8_t *pentries_end,
+                                uint32_t pentry_size)
+{
+    char *pentry_name;
+    unsigned len = strlen(ptn_name);
+
+    for (pentry_name = (char *) (pentries_start + PARTITION_NAME_OFFSET);
+         pentry_name < (char *) pentries_end; pentry_name += pentry_size) {
+        char name8[MAX_GPT_NAME_SIZE / 2];
+        unsigned i;
+
+        /* Partition names in GPT are UTF-16 - ignoring UTF-16 2nd byte */
+        for (i = 0; i < sizeof(name8); i++)
+            name8[i] = pentry_name[i * 2];
+        if (!strncmp(ptn_name, name8, len))
+            if (name8[len] == 0 || !strcmp(&name8[len], BAK_PTN_NAME_EXT))
+                return (uint8_t *) (pentry_name - PARTITION_NAME_OFFSET);
+    }
+
+    return NULL;
+}
+
+
+
+/**
+ *  ==========================================================================
+ *
+ *  \brief  Swaps boot chain in GPT partition entries array
+ *
+ *  \param [in] pentries_start  Partition entries array start
+ *  \param [in] pentries_end    Partition entries array end
+ *  \param [in] pentry_size     Single partition entry size
+ *
+ *  \return  0 on success, 1 if no backup partitions found
+ *
+ *  ==========================================================================
+ */
+static int gpt_boot_chain_swap(const uint8_t *pentries_start,
+                                const uint8_t *pentries_end,
+                                uint32_t pentry_size)
+{
+    const char ptn_swap_list[][MAX_GPT_NAME_SIZE] = { PTN_SWAP_LIST };
+
+    int backup_not_found = 1;
+    unsigned i;
+
+    for (i = 0; i < ARRAY_SIZE(ptn_swap_list); i++) {
+        uint8_t *ptn_entry;
+        uint8_t *ptn_bak_entry;
+        uint8_t ptn_swap[PTN_ENTRY_SIZE];
+        //Skip the xbl partition on UFS devices. That is handled
+        //seperately.
+        if (gpt_utils_is_ufs_device() && !strncmp(ptn_swap_list[i],
+                                PTN_XBL,
+                                strlen(PTN_XBL)))
+            continue;
+
+        ptn_entry = gpt_pentry_seek(ptn_swap_list[i], pentries_start,
+                        pentries_end, pentry_size);
+        if (ptn_entry == NULL)
+            continue;
+
+        ptn_bak_entry = gpt_pentry_seek(ptn_swap_list[i],
+                        ptn_entry + pentry_size, pentries_end, pentry_size);
+        if (ptn_bak_entry == NULL) {
+            fprintf(stderr, "'%s' partition not backup - skip safe update\n",
+                    ptn_swap_list[i]);
+            continue;
+        }
+
+        /* swap primary <-> backup partition entries */
+        memcpy(ptn_swap, ptn_entry, PTN_ENTRY_SIZE);
+        memcpy(ptn_entry, ptn_bak_entry, PTN_ENTRY_SIZE);
+        memcpy(ptn_bak_entry, ptn_swap, PTN_ENTRY_SIZE);
+        backup_not_found = 0;
+    }
+
+    return backup_not_found;
+}
+
+
+
+/**
+ *  ==========================================================================
+ *
+ *  \brief  Sets secondary GPT boot chain
+ *
+ *  \param [in] fd    block dev file descriptor
+ *  \param [in] boot  Boot chain to switch to
+ *
+ *  \return  0 on success
+ *
+ *  ==========================================================================
+ */
+static int gpt2_set_boot_chain(int fd, enum boot_chain boot)
+{
+    int64_t  gpt2_header_offset;
+    uint64_t pentries_start_offset;
+    uint32_t gpt_header_size;
+    uint32_t pentry_size;
+    uint32_t pentries_array_size;
+
+    uint8_t *gpt_header = NULL;
+    uint8_t  *pentries = NULL;
+    uint32_t crc;
+    uint32_t blk_size = 0;
+    int r;
+
+    if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
+            fprintf(stderr, "Failed to get GPT device block size: %s\n",
+                            strerror(errno));
+            r = -1;
+            goto EXIT;
+    }
+    gpt_header = (uint8_t*)malloc(blk_size);
+    if (!gpt_header) {
+            fprintf(stderr, "Failed to allocate memory to hold GPT block\n");
+            r = -1;
+            goto EXIT;
+    }
+    gpt2_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
+    if (gpt2_header_offset < 0) {
+        fprintf(stderr, "Getting secondary GPT header offset failed: %s\n",
+                strerror(errno));
+        r = -1;
+        goto EXIT;
+    }
+
+    /* Read primary GPT header from block dev */
+    r = blk_rw(fd, 0, blk_size, gpt_header, blk_size);
+
+    if (r) {
+            fprintf(stderr, "Failed to read primary GPT header from blk dev\n");
+            goto EXIT;
+    }
+    pentries_start_offset =
+        GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * blk_size;
+    pentry_size = GET_4_BYTES(gpt_header + PENTRY_SIZE_OFFSET);
+    pentries_array_size =
+        GET_4_BYTES(gpt_header + PARTITION_COUNT_OFFSET) * pentry_size;
+
+    pentries = (uint8_t *) calloc(1, pentries_array_size);
+    if (pentries == NULL) {
+        fprintf(stderr,
+                    "Failed to alloc memory for GPT partition entries array\n");
+        r = -1;
+        goto EXIT;
+    }
+    /* Read primary GPT partititon entries array from block dev */
+    r = blk_rw(fd, 0, pentries_start_offset, pentries, pentries_array_size);
+    if (r)
+        goto EXIT;
+
+    crc = crc32(0, pentries, pentries_array_size);
+    if (GET_4_BYTES(gpt_header + PARTITION_CRC_OFFSET) != crc) {
+        fprintf(stderr, "Primary GPT partition entries array CRC invalid\n");
+        r = -1;
+        goto EXIT;
+    }
+
+    /* Read secondary GPT header from block dev */
+    r = blk_rw(fd, 0, gpt2_header_offset, gpt_header, blk_size);
+    if (r)
+        goto EXIT;
+
+    gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
+    pentries_start_offset =
+        GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * blk_size;
+
+    if (boot == BACKUP_BOOT) {
+        r = gpt_boot_chain_swap(pentries, pentries + pentries_array_size,
+                                pentry_size);
+        if (r)
+            goto EXIT;
+    }
+
+    crc = crc32(0, pentries, pentries_array_size);
+    PUT_4_BYTES(gpt_header + PARTITION_CRC_OFFSET, crc);
+
+    /* header CRC is calculated with this field cleared */
+    PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
+    crc = crc32(0, gpt_header, gpt_header_size);
+    PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
+
+    /* Write the modified GPT header back to block dev */
+    r = blk_rw(fd, 1, gpt2_header_offset, gpt_header, blk_size);
+    if (!r)
+        /* Write the modified GPT partititon entries array back to block dev */
+        r = blk_rw(fd, 1, pentries_start_offset, pentries,
+                    pentries_array_size);
+
+EXIT:
+    if(gpt_header)
+            free(gpt_header);
+    if (pentries)
+            free(pentries);
+    return r;
+}
+
+/**
+ *  ==========================================================================
+ *
+ *  \brief  Checks GPT state (header signature and CRC)
+ *
+ *  \param [in] fd      block dev file descriptor
+ *  \param [in] gpt     GPT header to be checked
+ *  \param [out] state  GPT header state
+ *
+ *  \return  0 on success
+ *
+ *  ==========================================================================
+ */
+static int gpt_get_state(int fd, enum gpt_instance gpt, enum gpt_state *state)
+{
+    int64_t gpt_header_offset;
+    uint32_t gpt_header_size;
+    uint8_t  *gpt_header = NULL;
+    uint32_t crc;
+    uint32_t blk_size = 0;
+
+    *state = GPT_OK;
+
+    if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
+            fprintf(stderr, "Failed to get GPT device block size: %s\n",
+                            strerror(errno));
+            goto error;
+    }
+    gpt_header = (uint8_t*)malloc(blk_size);
+    if (!gpt_header) {
+            fprintf(stderr, "gpt_get_state:Failed to alloc memory for header\n");
+            goto error;
+    }
+    if (gpt == PRIMARY_GPT)
+        gpt_header_offset = blk_size;
+    else {
+        gpt_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
+        if (gpt_header_offset < 0) {
+            fprintf(stderr, "gpt_get_state:Seek to end of GPT part fail\n");
+            goto error;
+        }
+    }
+
+    if (blk_rw(fd, 0, gpt_header_offset, gpt_header, blk_size)) {
+        fprintf(stderr, "gpt_get_state: blk_rw failed\n");
+        goto error;
+    }
+    if (memcmp(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE)))
+        *state = GPT_BAD_SIGNATURE;
+    gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
+
+    crc = GET_4_BYTES(gpt_header + HEADER_CRC_OFFSET);
+    /* header CRC is calculated with this field cleared */
+    PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
+    if (crc32(0, gpt_header, gpt_header_size) != crc)
+        *state = GPT_BAD_CRC;
+    free(gpt_header);
+    return 0;
+error:
+    if (gpt_header)
+            free(gpt_header);
+    return -1;
+}
+
+
+
+/**
+ *  ==========================================================================
+ *
+ *  \brief  Sets GPT header state (used to corrupt and fix GPT signature)
+ *
+ *  \param [in] fd     block dev file descriptor
+ *  \param [in] gpt    GPT header to be checked
+ *  \param [in] state  GPT header state to set (GPT_OK or GPT_BAD_SIGNATURE)
+ *
+ *  \return  0 on success
+ *
+ *  ==========================================================================
+ */
+static int gpt_set_state(int fd, enum gpt_instance gpt, enum gpt_state state)
+{
+    int64_t gpt_header_offset;
+    uint32_t gpt_header_size;
+    uint8_t  *gpt_header = NULL;
+    uint32_t crc;
+    uint32_t blk_size = 0;
+
+    if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
+            fprintf(stderr, "Failed to get GPT device block size: %s\n",
+                            strerror(errno));
+            goto error;
+    }
+    gpt_header = (uint8_t*)malloc(blk_size);
+    if (!gpt_header) {
+            fprintf(stderr, "Failed to alloc memory for gpt header\n");
+            goto error;
+    }
+    if (gpt == PRIMARY_GPT)
+        gpt_header_offset = blk_size;
+    else {
+        gpt_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
+        if (gpt_header_offset < 0) {
+            fprintf(stderr, "Failed to seek to end of GPT device\n");
+            goto error;
+        }
+    }
+    if (blk_rw(fd, 0, gpt_header_offset, gpt_header, blk_size)) {
+        fprintf(stderr, "Failed to r/w gpt header\n");
+        goto error;
+    }
+    if (state == GPT_OK)
+        memcpy(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE));
+    else if (state == GPT_BAD_SIGNATURE)
+        *gpt_header = 0;
+    else {
+        fprintf(stderr, "gpt_set_state: Invalid state\n");
+        goto error;
+    }
+
+    gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
+
+    /* header CRC is calculated with this field cleared */
+    PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
+    crc = crc32(0, gpt_header, gpt_header_size);
+    PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
+
+    if (blk_rw(fd, 1, gpt_header_offset, gpt_header, blk_size)) {
+        fprintf(stderr, "gpt_set_state: blk write failed\n");
+        goto error;
+    }
+    return 0;
+error:
+    if(gpt_header)
+           free(gpt_header);
+    return -1;
+}
+
+int get_scsi_node_from_bootdevice(const char *bootdev_path,
+                char *sg_node_path,
+                size_t buf_size)
+{
+        char sg_dir_path[PATH_MAX] = {0};
+        char real_path[PATH_MAX] = {0};
+        DIR *scsi_dir = NULL;
+        struct dirent *de;
+        int node_found = 0;
+        if (!bootdev_path || !sg_node_path) {
+                fprintf(stderr, "%s : invalid argument\n",
+                                 __func__);
+                goto error;
+        }
+        if (readlink(bootdev_path, real_path, sizeof(real_path) - 1) < 0) {
+                        fprintf(stderr, "failed to resolve link for %s(%s)\n",
+                                        bootdev_path,
+                                        strerror(errno));
+                        goto error;
+        }
+        if(strlen(real_path) < PATH_TRUNCATE_LOC + 1){
+            fprintf(stderr, "Unrecognized path :%s:\n",
+                           real_path);
+            goto error;
+        }
+        //For the safe side in case there are additional partitions on
+        //the XBL lun we truncate the name.
+        real_path[PATH_TRUNCATE_LOC] = '\0';
+        if(strlen(real_path) < LUN_NAME_START_LOC + 1){
+            fprintf(stderr, "Unrecognized truncated path :%s:\n",
+                           real_path);
+            goto error;
+        }
+        //This will give us /dev/block/sdb/device/scsi_generic
+        //which contains a file sgY whose name gives us the path
+        //to /dev/sgY which we return
+        snprintf(sg_dir_path, sizeof(sg_dir_path) - 1,
+                        "/sys/block/%s/device/scsi_generic",
+                        &real_path[LUN_NAME_START_LOC]);
+        scsi_dir = opendir(sg_dir_path);
+        if (!scsi_dir) {
+                fprintf(stderr, "%s : Failed to open %s(%s)\n",
+                                __func__,
+                                sg_dir_path,
+                                strerror(errno));
+                goto error;
+        }
+        while((de = readdir(scsi_dir))) {
+                if (de->d_name[0] == '.')
+                        continue;
+                else if (!strncmp(de->d_name, "sg", 2)) {
+                          snprintf(sg_node_path,
+                                        buf_size -1,
+                                        "/dev/%s",
+                                        de->d_name);
+                          fprintf(stderr, "%s:scsi generic node is :%s:\n",
+                                          __func__,
+                                          sg_node_path);
+                          node_found = 1;
+                          break;
+                }
+        }
+        if(!node_found) {
+                fprintf(stderr,"%s: Unable to locate scsi generic node\n",
+                               __func__);
+                goto error;
+        }
+        closedir(scsi_dir);
+        return 0;
+error:
+        if (scsi_dir)
+                closedir(scsi_dir);
+        return -1;
+}
+
+int set_boot_lun(char *sg_dev, uint8_t boot_lun_id)
+{
+        int fd = -1;
+        int rc;
+        struct ufs_ioctl_query_data *data = NULL;
+        size_t ioctl_data_size = sizeof(struct ufs_ioctl_query_data) + UFS_ATTR_DATA_SIZE;
+
+        data = (struct ufs_ioctl_query_data*)malloc(ioctl_data_size);
+        if (!data) {
+                fprintf(stderr, "%s: Failed to alloc query data struct\n",
+                                __func__);
+                goto error;
+        }
+        memset(data, 0, ioctl_data_size);
+        data->opcode = UPIU_QUERY_OPCODE_WRITE_ATTR;
+        data->idn = QUERY_ATTR_IDN_BOOT_LU_EN;
+        data->buf_size = UFS_ATTR_DATA_SIZE;
+        data->buffer[0] = boot_lun_id;
+        fd = open(sg_dev, O_RDWR);
+        if (fd < 0) {
+                fprintf(stderr, "%s: Failed to open %s(%s)\n",
+                                __func__,
+                                sg_dev,
+                                strerror(errno));
+                goto error;
+        }
+        rc = ioctl(fd, UFS_IOCTL_QUERY, data);
+        if (rc) {
+                fprintf(stderr, "%s: UFS query ioctl failed(%s)\n",
+                                __func__,
+                                strerror(errno));
+                goto error;
+        }
+        close(fd);
+        free(data);
+        return 0;
+error:
+        if (fd >= 0)
+                close(fd);
+        if (data)
+                free(data);
+        return -1;
+}
+
+//Swtich betwieen using either the primary or the backup
+//boot LUN for boot. This is required since UFS boot partitions
+//cannot have a backup GPT which is what we use for failsafe
+//updates of the other 'critical' partitions. This function will
+//not be invoked for emmc targets and on UFS targets is only required
+//to be invoked for XBL.
+//
+//The algorithm to do this is as follows:
+//- Find the real block device(eg: /dev/block/sdb) that corresponds
+//  to the /dev/block/bootdevice/by-name/xbl(bak) symlink
+//
+//- Once we have the block device 'node' name(sdb in the above example)
+//  use this node to to locate the scsi generic device that represents
+//  it by checking the file /sys/block/sdb/device/scsi_generic/sgY
+//
+//- Once we locate sgY we call the query ioctl on /dev/sgy to switch
+//the boot lun to either LUNA or LUNB
+int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
+{
+        struct stat st;
+        ///sys/block/sdX/device/scsi_generic/
+        char sg_dev_node[PATH_MAX] = {0};
+        uint8_t boot_lun_id = 0;
+        const char *boot_dev = NULL;
+
+        if (chain == BACKUP_BOOT) {
+                boot_lun_id = BOOT_LUN_B_ID;
+                if (!stat(XBL_BACKUP, &st))
+                        boot_dev = XBL_BACKUP;
+                else if (!stat(XBL_AB_SECONDARY, &st))
+                        boot_dev = XBL_AB_SECONDARY;
+                else {
+                        fprintf(stderr, "%s: Failed to locate secondary xbl\n",
+                                        __func__);
+                        goto error;
+                }
+        } else if (chain == NORMAL_BOOT) {
+                boot_lun_id = BOOT_LUN_A_ID;
+                if (!stat(XBL_PRIMARY, &st))
+                        boot_dev = XBL_PRIMARY;
+                else if (!stat(XBL_AB_PRIMARY, &st))
+                        boot_dev = XBL_AB_PRIMARY;
+                else {
+                        fprintf(stderr, "%s: Failed to locate primary xbl\n",
+                                        __func__);
+                        goto error;
+                }
+        } else {
+                fprintf(stderr, "%s: Invalid boot chain id\n", __func__);
+                goto error;
+        }
+        //We need either both xbl and xblbak or both xbl_a and xbl_b to exist at
+        //the same time. If not the current configuration is invalid.
+        if((stat(XBL_PRIMARY, &st) ||
+                                stat(XBL_BACKUP, &st)) &&
+                        (stat(XBL_AB_PRIMARY, &st) ||
+                         stat(XBL_AB_SECONDARY, &st))) {
+                fprintf(stderr, "%s:primary/secondary XBL prt not found(%s)\n",
+                                __func__,
+                                strerror(errno));
+                goto error;
+        }
+        fprintf(stderr, "%s: setting %s lun as boot lun\n",
+                        __func__,
+                        boot_dev);
+        if (get_scsi_node_from_bootdevice(boot_dev,
+                                sg_dev_node,
+                                sizeof(sg_dev_node))) {
+                fprintf(stderr, "%s: Failed to get scsi node path for xblbak\n",
+                                __func__);
+                goto error;
+        }
+        if (set_boot_lun(sg_dev_node, boot_lun_id)) {
+                fprintf(stderr, "%s: Failed to set xblbak as boot partition\n",
+                                __func__);
+                goto error;
+        }
+        return 0;
+error:
+        return -1;
+}
+
+int gpt_utils_is_ufs_device()
+{
+    char bootdevice[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.boot.bootdevice", bootdevice, "N/A");
+    if (strlen(bootdevice) < strlen(".ufshc") + 1)
+        return 0;
+    return (!strncmp(&bootdevice[strlen(bootdevice) - strlen(".ufshc")],
+                            ".ufshc",
+                            sizeof(".ufshc")));
+}
+//dev_path is the path to the block device that contains the GPT image that
+//needs to be updated. This would be the device which holds one or more critical
+//boot partitions and their backups. In the case of EMMC this function would
+//be invoked only once on /dev/block/mmcblk1 since it holds the GPT image
+//containing all the partitions For UFS devices it could potentially be
+//invoked multiple times, once for each LUN containing critical image(s) and
+//their backups
+int prepare_partitions(enum boot_update_stage stage, const char *dev_path)
+{
+    int r = 0;
+    int fd = -1;
+    int is_ufs = gpt_utils_is_ufs_device();
+    enum gpt_state gpt_prim, gpt_second;
+    enum boot_update_stage internal_stage;
+    struct stat xbl_partition_stat;
+    struct stat ufs_dir_stat;
+
+    if (!dev_path) {
+        fprintf(stderr, "%s: Invalid dev_path\n",
+                        __func__);
+        r = -1;
+        goto EXIT;
+    }
+    fd = open(dev_path, O_RDWR);
+    if (fd < 0) {
+        fprintf(stderr, "%s: Opening '%s' failed: %s\n",
+                        __func__,
+                       BLK_DEV_FILE,
+                       strerror(errno));
+        r = -1;
+        goto EXIT;
+    }
+    r = gpt_get_state(fd, PRIMARY_GPT, &gpt_prim) ||
+        gpt_get_state(fd, SECONDARY_GPT, &gpt_second);
+    if (r) {
+        fprintf(stderr, "%s: Getting GPT headers state failed\n",
+                        __func__);
+        goto EXIT;
+    }
+
+    /* These 2 combinations are unexpected and unacceptable */
+    if (gpt_prim == GPT_BAD_CRC || gpt_second == GPT_BAD_CRC) {
+        fprintf(stderr, "%s: GPT headers CRC corruption detected, aborting\n",
+                        __func__);
+        r = -1;
+        goto EXIT;
+    }
+    if (gpt_prim == GPT_BAD_SIGNATURE && gpt_second == GPT_BAD_SIGNATURE) {
+        fprintf(stderr, "%s: Both GPT headers corrupted, aborting\n",
+                        __func__);
+        r = -1;
+        goto EXIT;
+    }
+
+    /* Check internal update stage according GPT headers' state */
+    if (gpt_prim == GPT_OK && gpt_second == GPT_OK)
+        internal_stage = UPDATE_MAIN;
+    else if (gpt_prim == GPT_BAD_SIGNATURE)
+        internal_stage = UPDATE_BACKUP;
+    else if (gpt_second == GPT_BAD_SIGNATURE)
+        internal_stage = UPDATE_FINALIZE;
+    else {
+        fprintf(stderr, "%s: Abnormal GPTs state: primary (%d), secondary (%d), "
+                "aborting\n", __func__, gpt_prim, gpt_second);
+        r = -1;
+        goto EXIT;
+    }
+
+    /* Stage already set - ready for update, exitting */
+    if ((int) stage == (int) internal_stage - 1)
+        goto EXIT;
+    /* Unexpected stage given */
+    if (stage != internal_stage) {
+        r = -1;
+        goto EXIT;
+    }
+
+    switch (stage) {
+    case UPDATE_MAIN:
+            if (is_ufs) {
+                if(stat(XBL_PRIMARY, &xbl_partition_stat)||
+                                stat(XBL_BACKUP, &xbl_partition_stat)){
+                        //Non fatal error. Just means this target does not
+                        //use XBL but relies on sbl whose update is handled
+                        //by the normal methods.
+                        fprintf(stderr, "%s: xbl part not found(%s).Assuming sbl in use\n",
+                                        __func__,
+                                        strerror(errno));
+                } else {
+                        //Switch the boot lun so that backup boot LUN is used
+                        r = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
+                        if(r){
+                                fprintf(stderr, "%s: Failed to set xbl backup partition as boot\n",
+                                                __func__);
+                                goto EXIT;
+                        }
+                }
+        }
+        //Fix up the backup GPT table so that it actually points to
+        //the backup copy of the boot critical images
+        fprintf(stderr, "%s: Preparing for primary partition update\n",
+                        __func__);
+        r = gpt2_set_boot_chain(fd, BACKUP_BOOT);
+        if (r) {
+            if (r < 0)
+                fprintf(stderr,
+                                "%s: Setting secondary GPT to backup boot failed\n",
+                                __func__);
+            /* No backup partitions - do not corrupt GPT, do not flag error */
+            else
+                r = 0;
+            goto EXIT;
+        }
+        //corrupt the primary GPT so that the backup(which now points to
+        //the backup boot partitions is used)
+        r = gpt_set_state(fd, PRIMARY_GPT, GPT_BAD_SIGNATURE);
+        if (r) {
+            fprintf(stderr, "%s: Corrupting primary GPT header failed\n",
+                            __func__);
+            goto EXIT;
+        }
+        break;
+    case UPDATE_BACKUP:
+        if (is_ufs) {
+                if(stat(XBL_PRIMARY, &xbl_partition_stat)||
+                                stat(XBL_BACKUP, &xbl_partition_stat)){
+                        //Non fatal error. Just means this target does not
+                        //use XBL but relies on sbl whose update is handled
+                        //by the normal methods.
+                        fprintf(stderr, "%s: xbl part not found(%s).Assuming sbl in use\n",
+                                        __func__,
+                                        strerror(errno));
+                } else {
+                        //Switch the boot lun so that backup boot LUN is used
+                        r = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
+                        if(r) {
+                                fprintf(stderr, "%s: Failed to set xbl backup partition as boot\n",
+                                                __func__);
+                                goto EXIT;
+                        }
+                }
+        }
+        //Fix the primary GPT header so that is used
+        fprintf(stderr, "%s: Preparing for backup partition update\n",
+                        __func__);
+        r = gpt_set_state(fd, PRIMARY_GPT, GPT_OK);
+        if (r) {
+            fprintf(stderr, "%s: Fixing primary GPT header failed\n",
+                             __func__);
+            goto EXIT;
+        }
+        //Corrupt the scondary GPT header
+        r = gpt_set_state(fd, SECONDARY_GPT, GPT_BAD_SIGNATURE);
+        if (r) {
+            fprintf(stderr, "%s: Corrupting secondary GPT header failed\n",
+                            __func__);
+            goto EXIT;
+        }
+        break;
+    case UPDATE_FINALIZE:
+        //Undo the changes we had made in the UPDATE_MAIN stage so that the
+        //primary/backup GPT headers once again point to the same set of
+        //partitions
+        fprintf(stderr, "%s: Finalizing partitions\n",
+                        __func__);
+        r = gpt2_set_boot_chain(fd, NORMAL_BOOT);
+        if (r < 0) {
+            fprintf(stderr, "%s: Setting secondary GPT to normal boot failed\n",
+                            __func__);
+            goto EXIT;
+        }
+
+        r = gpt_set_state(fd, SECONDARY_GPT, GPT_OK);
+        if (r) {
+            fprintf(stderr, "%s: Fixing secondary GPT header failed\n",
+                            __func__);
+            goto EXIT;
+        }
+        break;
+    default:;
+    }
+
+EXIT:
+    if (fd >= 0) {
+       fsync(fd);
+       close(fd);
+    }
+    return r;
+}
+
+int add_lun_to_update_list(char *lun_path, struct update_data *dat)
+{
+        uint32_t i = 0;
+        struct stat st;
+        if (!lun_path || !dat){
+                fprintf(stderr, "%s: Invalid data",
+                                __func__);
+                return -1;
+        }
+        if (stat(lun_path, &st)) {
+                fprintf(stderr, "%s: Unable to access %s. Skipping adding to list",
+                                __func__,
+                                lun_path);
+                return -1;
+        }
+        if (dat->num_valid_entries == 0) {
+                fprintf(stderr, "%s: Copying %s into lun_list[%d]\n",
+                                __func__,
+                                lun_path,
+                                i);
+                strlcpy(dat->lun_list[0], lun_path,
+                                PATH_MAX * sizeof(char));
+                dat->num_valid_entries = 1;
+        } else {
+                for (i = 0; (i < dat->num_valid_entries) &&
+                                (dat->num_valid_entries < MAX_LUNS - 1); i++) {
+                        //Check if the current LUN is not already part
+                        //of the lun list
+                        if (!strncmp(lun_path,dat->lun_list[i],
+                                                strlen(dat->lun_list[i]))) {
+                                //LUN already in list..Return
+                                return 0;
+                        }
+                }
+                fprintf(stderr, "%s: Copying %s into lun_list[%d]\n",
+                                __func__,
+                                lun_path,
+                                dat->num_valid_entries);
+                //Add LUN path lun list
+                strlcpy(dat->lun_list[dat->num_valid_entries], lun_path,
+                                PATH_MAX * sizeof(char));
+                dat->num_valid_entries++;
+        }
+        return 0;
+}
+
+int prepare_boot_update(enum boot_update_stage stage)
+{
+        int r, fd;
+        int is_ufs = gpt_utils_is_ufs_device();
+        struct stat ufs_dir_stat;
+        struct update_data data;
+        int rcode = 0;
+        uint32_t i = 0;
+        int is_error = 0;
+        const char ptn_swap_list[][MAX_GPT_NAME_SIZE] = { PTN_SWAP_LIST };
+        //Holds /dev/block/bootdevice/by-name/*bak entry
+        char buf[PATH_MAX] = {0};
+        //Holds the resolved path of the symlink stored in buf
+        char real_path[PATH_MAX] = {0};
+
+        if (!is_ufs) {
+                //emmc device. Just pass in path to mmcblk0
+                return prepare_partitions(stage, BLK_DEV_FILE);
+        } else {
+                //Now we need to find the list of LUNs over
+                //which the boot critical images are spread
+                //and set them up for failsafe updates.To do
+                //this we find out where the symlinks for the
+                //each of the paths under
+                ///dev/block/bootdevice/by-name/PTN_SWAP_LIST
+                //actually point to.
+                fprintf(stderr, "%s: Running on a UFS device\n",
+                                __func__);
+                memset(&data, '\0', sizeof(struct update_data));
+                for (i=0; i < ARRAY_SIZE(ptn_swap_list); i++) {
+                        //XBL on UFS does not follow the convention
+                        //of being loaded based on well known GUID'S.
+                        //We take care of switching the UFS boot LUN
+                        //explicitly later on.
+                        if (!strncmp(ptn_swap_list[i],
+                                                PTN_XBL,
+                                                strlen(PTN_XBL)))
+                                continue;
+                        snprintf(buf, sizeof(buf),
+                                        "%s/%sbak",
+                                        BOOT_DEV_DIR,
+                                        ptn_swap_list[i]);
+                        if (stat(buf, &ufs_dir_stat)) {
+                                continue;
+                        }
+                        if (readlink(buf, real_path, sizeof(real_path) - 1) < 0)
+                        {
+                                fprintf(stderr, "%s: readlink error. Skipping %s",
+                                                __func__,
+                                                strerror(errno));
+                        } else {
+                              if(strlen(real_path) < PATH_TRUNCATE_LOC + 1){
+                                    fprintf(stderr, "Unknown path.Skipping :%s:\n",
+                                                real_path);
+                                } else {
+                                    real_path[PATH_TRUNCATE_LOC] = '\0';
+                                    add_lun_to_update_list(real_path, &data);
+                                }
+                        }
+                        memset(buf, '\0', sizeof(buf));
+                        memset(real_path, '\0', sizeof(real_path));
+                }
+                for (i=0; i < data.num_valid_entries; i++) {
+                        fprintf(stderr, "%s: Preparing %s for update stage %d\n",
+                                        __func__,
+                                        data.lun_list[i],
+                                        stage);
+                        rcode = prepare_partitions(stage, data.lun_list[i]);
+                        if (rcode != 0)
+                        {
+                                fprintf(stderr, "%s: Failed to prepare %s.Continuing..\n",
+                                                __func__,
+                                                data.lun_list[i]);
+                                is_error = 1;
+                        }
+                }
+        }
+        if (is_error)
+                return -1;
+        return 0;
+}
+
+//Given a parttion name(eg: rpm) get the path to the block device that
+//represents the GPT disk the partition resides on. In the case of emmc it
+//would be the default emmc dev(/dev/block/mmcblk0). In the case of UFS we look
+//through the /dev/block/bootdevice/by-name/ tree for partname, and resolve
+//the path to the LUN from there.
+static int get_dev_path_from_partition_name(const char *partname,
+                char *buf,
+                size_t buflen)
+{
+        struct stat st;
+        char path[PATH_MAX] = {0};
+        if (!partname || !buf || buflen < ((PATH_TRUNCATE_LOC) + 1)) {
+                ALOGE("%s: Invalid argument", __func__);
+                goto error;
+        }
+        if (gpt_utils_is_ufs_device()) {
+                //Need to find the lun that holds partition partname
+                snprintf(path, sizeof(path),
+                                "%s/%s",
+                                BOOT_DEV_DIR,
+                                partname);
+                if (stat(path, &st)) {
+                        goto error;
+                }
+                if (readlink(path, buf, buflen) < 0)
+                {
+                        goto error;
+                } else {
+                        buf[PATH_TRUNCATE_LOC] = '\0';
+                }
+        } else {
+                snprintf(buf, buflen, "/dev/block/mmcblk0");
+        }
+        return 0;
+
+error:
+        return -1;
+}
+
+int gpt_utils_get_partition_map(vector<string>& ptn_list,
+                map<string, vector<string>>& partition_map) {
+        char devpath[PATH_MAX] = {'\0'};
+        map<string, vector<string>>::iterator it;
+        if (ptn_list.size() < 1) {
+                fprintf(stderr, "%s: Invalid ptn list\n", __func__);
+                return -1;
+        }
+        //Go through the passed in list
+        for (uint32_t i = 0; i < ptn_list.size(); i++)
+        {
+                //Key in the map is the path to the device that holds the
+                //partition
+                if (get_dev_path_from_partition_name(ptn_list[i].c_str(),
+                                devpath,
+                                sizeof(devpath))) {
+                        //Not necessarily an error. The partition may just
+                        //not be present.
+                        continue;
+                }
+                string path = devpath;
+                it = partition_map.find(path);
+                if (it != partition_map.end()) {
+                        it->second.push_back(ptn_list[i]);
+                } else {
+                        vector<string> str_vec;
+                        str_vec.push_back( ptn_list[i]);
+                        partition_map.insert(pair<string, vector<string>>
+                                        (path, str_vec));
+                }
+                memset(devpath, '\0', sizeof(devpath));
+        }
+        return 0;
+}
+
+//Get the block size of the disk represented by decsriptor fd
+static uint32_t gpt_get_block_size(int fd)
+{
+        uint32_t block_size = 0;
+        if (fd < 0) {
+                ALOGE("%s: invalid descriptor",
+                                __func__);
+                goto error;
+        }
+        if (ioctl(fd, BLKSSZGET, &block_size) != 0) {
+                ALOGE("%s: Failed to get GPT dev block size : %s",
+                                __func__,
+                                strerror(errno));
+                goto error;
+        }
+        return block_size;
+error:
+        return 0;
+}
+
+//Write the GPT header present in the passed in buffer back to the
+//disk represented by fd
+static int gpt_set_header(uint8_t *gpt_header, int fd,
+                enum gpt_instance instance)
+{
+        uint32_t block_size = 0;
+        off_t gpt_header_offset = 0;
+        if (!gpt_header || fd < 0) {
+                ALOGE("%s: Invalid arguments",
+                                __func__);
+                goto error;
+        }
+        block_size = gpt_get_block_size(fd);
+        ALOGI("%s: Block size is : %d", __func__, block_size);
+        if (block_size == 0) {
+                ALOGE("%s: Failed to get block size", __func__);
+                goto error;
+        }
+        if (instance == PRIMARY_GPT)
+                gpt_header_offset = block_size;
+        else
+                gpt_header_offset = lseek64(fd, 0, SEEK_END) - block_size;
+        if (gpt_header_offset <= 0) {
+                ALOGE("%s: Failed to get gpt header offset",__func__);
+                goto error;
+        }
+        ALOGI("%s: Writing back header to offset %ld", __func__,
+                gpt_header_offset);
+        if (blk_rw(fd, 1, gpt_header_offset, gpt_header, block_size)) {
+                ALOGE("%s: Failed to write back GPT header", __func__);
+                goto error;
+        }
+        return 0;
+error:
+        return -1;
+}
+
+//Read out the GPT header for the disk that contains the partition partname
+static uint8_t* gpt_get_header(const char *partname, enum gpt_instance instance)
+{
+        uint8_t* hdr = NULL;
+        char devpath[PATH_MAX] = {0};
+        int64_t hdr_offset = 0;
+        uint32_t block_size = 0;
+        int fd = -1;
+        if (!partname) {
+                ALOGE("%s: Invalid partition name", __func__);
+                goto error;
+        }
+        if (get_dev_path_from_partition_name(partname, devpath, sizeof(devpath))
+                        != 0) {
+                ALOGE("%s: Failed to resolve path for %s",
+                                __func__,
+                                partname);
+                goto error;
+        }
+        fd = open(devpath, O_RDWR);
+        if (fd < 0) {
+                ALOGE("%s: Failed to open %s : %s",
+                                __func__,
+                                devpath,
+                                strerror(errno));
+                goto error;
+        }
+        block_size = gpt_get_block_size(fd);
+        if (block_size == 0)
+        {
+                ALOGE("%s: Failed to get gpt block size for %s",
+                                __func__,
+                                partname);
+                goto error;
+        }
+
+        hdr = (uint8_t*)malloc(block_size);
+        if (!hdr) {
+                ALOGE("%s: Failed to allocate memory for gpt header",
+                                __func__);
+        }
+        if (instance == PRIMARY_GPT)
+                hdr_offset = block_size;
+        else {
+                hdr_offset = lseek64(fd, 0, SEEK_END) - block_size;
+        }
+        if (hdr_offset < 0) {
+                ALOGE("%s: Failed to get gpt header offset",
+                                __func__);
+                goto error;
+        }
+        if (blk_rw(fd, 0, hdr_offset, hdr, block_size)) {
+                ALOGE("%s: Failed to read GPT header from device",
+                                __func__);
+                goto error;
+        }
+        close(fd);
+        return hdr;
+error:
+        if (fd >= 0)
+                close(fd);
+        if (hdr)
+                free(hdr);
+        return NULL;
+}
+
+//Returns the partition entry array based on the
+//passed in buffer which contains the gpt header.
+//The fd here is the descriptor for the 'disk' which
+//holds the partition
+static uint8_t* gpt_get_pentry_arr(uint8_t *hdr, int fd)
+{
+        uint64_t pentries_start = 0;
+        uint32_t pentry_size = 0;
+        uint32_t block_size = 0;
+        uint32_t pentries_arr_size = 0;
+        uint8_t *pentry_arr = NULL;
+        int rc = 0;
+        if (!hdr) {
+                ALOGE("%s: Invalid header", __func__);
+                goto error;
+        }
+        if (fd < 0) {
+                ALOGE("%s: Invalid fd", __func__);
+                goto error;
+        }
+        block_size = gpt_get_block_size(fd);
+        if (!block_size) {
+                ALOGE("%s: Failed to get gpt block size for",
+                                __func__);
+                goto error;
+        }
+        pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
+        pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
+        pentries_arr_size =
+                GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
+        pentry_arr = (uint8_t*)calloc(1, pentries_arr_size);
+        if (!pentry_arr) {
+                ALOGE("%s: Failed to allocate memory for partition array",
+                                __func__);
+                goto error;
+        }
+        rc = blk_rw(fd, 0,
+                        pentries_start,
+                        pentry_arr,
+                        pentries_arr_size);
+        if (rc) {
+                ALOGE("%s: Failed to read partition entry array",
+                                __func__);
+                goto error;
+        }
+        return pentry_arr;
+error:
+        if (pentry_arr)
+                free(pentry_arr);
+        return NULL;
+}
+
+static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t* arr)
+{
+        uint32_t block_size = 0;
+        uint64_t pentries_start = 0;
+        uint32_t pentry_size = 0;
+        uint32_t pentries_arr_size = 0;
+        int rc = 0;
+        if (!hdr || fd < 0 || !arr) {
+                ALOGE("%s: Invalid argument", __func__);
+                goto error;
+        }
+        block_size = gpt_get_block_size(fd);
+        if (!block_size) {
+                ALOGE("%s: Failed to get gpt block size for",
+                                __func__);
+                goto error;
+        }
+        ALOGI("%s : Block size is %d", __func__, block_size);
+        pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
+        pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
+        pentries_arr_size =
+                GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
+        ALOGI("%s: Writing partition entry array of size %d to offset %" PRIu64,
+                        __func__,
+                        pentries_arr_size,
+                        pentries_start);
+        rc = blk_rw(fd, 1,
+                        pentries_start,
+                        arr,
+                        pentries_arr_size);
+        if (rc) {
+                ALOGE("%s: Failed to read partition entry array",
+                                __func__);
+                goto error;
+        }
+        return 0;
+error:
+        return -1;
+}
+
+
+
+//Allocate a handle used by calls to the "gpt_disk" api's
+struct gpt_disk * gpt_disk_alloc()
+{
+        struct gpt_disk *disk;
+        disk = (struct gpt_disk *)malloc(sizeof(struct gpt_disk));
+        if (!disk) {
+                ALOGE("%s: Failed to allocate memory", __func__);
+                goto end;
+        }
+        memset(disk, 0, sizeof(struct gpt_disk));
+end:
+        return disk;
+}
+
+//Free previously allocated/initialized handle
+void gpt_disk_free(struct gpt_disk *disk)
+{
+        if (!disk)
+                return;
+        if (disk->hdr)
+                free(disk->hdr);
+        if (disk->hdr_bak)
+                free(disk->hdr_bak);
+        if (disk->pentry_arr)
+                free(disk->pentry_arr);
+        if (disk->pentry_arr_bak)
+                free(disk->pentry_arr_bak);
+        free(disk);
+        return;
+}
+
+//fills up the passed in gpt_disk struct with information about the
+//disk represented by path dev. Returns 0 on success and -1 on error.
+int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *dsk)
+{
+        struct gpt_disk *disk = NULL;
+        int fd = -1;
+        uint32_t gpt_header_size = 0;
+
+        if (!dsk || !dev) {
+                ALOGE("%s: Invalid arguments", __func__);
+                goto error;
+        }
+        disk = dsk;
+        disk->hdr = gpt_get_header(dev, PRIMARY_GPT);
+        if (!disk->hdr) {
+                ALOGE("%s: Failed to get primary header", __func__);
+                goto error;
+        }
+        gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
+        disk->hdr_crc = crc32(0, disk->hdr, gpt_header_size);
+        disk->hdr_bak = gpt_get_header(dev, PRIMARY_GPT);
+        if (!disk->hdr_bak) {
+                ALOGE("%s: Failed to get backup header", __func__);
+                goto error;
+        }
+        disk->hdr_bak_crc = crc32(0, disk->hdr_bak, gpt_header_size);
+
+        //Descriptor for the block device. We will use this for further
+        //modifications to the partition table
+        if (get_dev_path_from_partition_name(dev,
+                                disk->devpath,
+                                sizeof(disk->devpath)) != 0) {
+                ALOGE("%s: Failed to resolve path for %s",
+                                __func__,
+                                dev);
+                goto error;
+        }
+        fd = open(disk->devpath, O_RDWR);
+        if (fd < 0) {
+                ALOGE("%s: Failed to open %s: %s",
+                                __func__,
+                                disk->devpath,
+                                strerror(errno));
+                goto error;
+        }
+        disk->pentry_arr = gpt_get_pentry_arr(disk->hdr, fd);
+        if (!disk->pentry_arr) {
+                ALOGE("%s: Failed to obtain partition entry array",
+                                __func__);
+                goto error;
+        }
+        disk->pentry_arr_bak = gpt_get_pentry_arr(disk->hdr_bak, fd);
+        if (!disk->pentry_arr_bak) {
+                ALOGE("%s: Failed to obtain backup partition entry array",
+                                __func__);
+                goto error;
+        }
+        disk->pentry_size = GET_4_BYTES(disk->hdr + PENTRY_SIZE_OFFSET);
+        disk->pentry_arr_size =
+                GET_4_BYTES(disk->hdr + PARTITION_COUNT_OFFSET) *
+                disk->pentry_size;
+        disk->pentry_arr_crc = GET_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET);
+        disk->pentry_arr_bak_crc = GET_4_BYTES(disk->hdr_bak +
+                        PARTITION_CRC_OFFSET);
+        disk->block_size = gpt_get_block_size(fd);
+        close(fd);
+        disk->is_initialized = GPT_DISK_INIT_MAGIC;
+        return 0;
+error:
+        if (fd >= 0)
+                close(fd);
+        return -1;
+}
+
+//Get pointer to partition entry from a allocated gpt_disk structure
+uint8_t* gpt_disk_get_pentry(struct gpt_disk *disk,
+                const char *partname,
+                enum gpt_instance instance)
+{
+        uint8_t *ptn_arr = NULL;
+        if (!disk || !partname || disk->is_initialized != GPT_DISK_INIT_MAGIC) {
+                ALOGE("%s: Invalid argument",__func__);
+                goto error;
+        }
+        ptn_arr = (instance == PRIMARY_GPT) ?
+                disk->pentry_arr : disk->pentry_arr_bak;
+        return (gpt_pentry_seek(partname, ptn_arr,
+                        ptn_arr + disk->pentry_arr_size ,
+                        disk->pentry_size));
+error:
+        return NULL;
+}
+
+//Update CRC values for the various components of the gpt_disk
+//structure. This function should be called after any of the fields
+//have been updated before the structure contents are written back to
+//disk.
+int gpt_disk_update_crc(struct gpt_disk *disk)
+{
+        uint32_t gpt_header_size = 0;
+        if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)) {
+                ALOGE("%s: invalid argument", __func__);
+                goto error;
+        }
+        //Recalculate the CRC of the primary partiton array
+        disk->pentry_arr_crc = crc32(0,
+                        disk->pentry_arr,
+                        disk->pentry_arr_size);
+        //Recalculate the CRC of the backup partition array
+        disk->pentry_arr_bak_crc = crc32(0,
+                        disk->pentry_arr_bak,
+                        disk->pentry_arr_size);
+        //Update the partition CRC value in the primary GPT header
+        PUT_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET, disk->pentry_arr_crc);
+        //Update the partition CRC value in the backup GPT header
+        PUT_4_BYTES(disk->hdr_bak + PARTITION_CRC_OFFSET,
+                        disk->pentry_arr_bak_crc);
+        //Update the CRC value of the primary header
+        gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
+        //Header CRC is calculated with its own CRC field set to 0
+        PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, 0);
+        PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, 0);
+        disk->hdr_crc = crc32(0, disk->hdr, gpt_header_size);
+        disk->hdr_bak_crc = crc32(0, disk->hdr_bak, gpt_header_size);
+        PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, disk->hdr_crc);
+        PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, disk->hdr_bak_crc);
+        return 0;
+error:
+        return -1;
+}
+
+//Write the contents of struct gpt_disk back to the actual disk
+int gpt_disk_commit(struct gpt_disk *disk)
+{
+        int fd = -1;
+        if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)){
+                ALOGE("%s: Invalid args", __func__);
+                goto error;
+        }
+        fd = open(disk->devpath, O_RDWR);
+        if (fd < 0) {
+                ALOGE("%s: Failed to open %s: %s",
+                                __func__,
+                                disk->devpath,
+                                strerror(errno));
+                goto error;
+        }
+        ALOGI("%s: Writing back primary GPT header", __func__);
+        //Write the primary header
+        if(gpt_set_header(disk->hdr, fd, PRIMARY_GPT) != 0) {
+                ALOGE("%s: Failed to update primary GPT header",
+                                __func__);
+                goto error;
+        }
+        ALOGI("%s: Writing back primary partition array", __func__);
+        //Write back the primary partition array
+        if (gpt_set_pentry_arr(disk->hdr, fd, disk->pentry_arr)) {
+                ALOGE("%s: Failed to write primary GPT partition arr",
+                                __func__);
+                goto error;
+        }
+        close(fd);
+        return 0;
+error:
+        if (fd >= 0)
+                close(fd);
+        return -1;
+}
diff --git a/gpt-utils/gpt-utils.h b/gpt-utils/gpt-utils.h
new file mode 100644
index 0000000..da473be
--- /dev/null
+++ b/gpt-utils/gpt-utils.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GPT_UTILS_H__
+#define __GPT_UTILS_H__
+#include <vector>
+#include <string>
+#include <map>
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+/******************************************************************************
+ * GPT HEADER DEFINES
+ ******************************************************************************/
+#define GPT_SIGNATURE               "EFI PART"
+#define HEADER_SIZE_OFFSET          12
+#define HEADER_CRC_OFFSET           16
+#define PRIMARY_HEADER_OFFSET       24
+#define BACKUP_HEADER_OFFSET        32
+#define FIRST_USABLE_LBA_OFFSET     40
+#define LAST_USABLE_LBA_OFFSET      48
+#define PENTRIES_OFFSET             72
+#define PARTITION_COUNT_OFFSET      80
+#define PENTRY_SIZE_OFFSET          84
+#define PARTITION_CRC_OFFSET        88
+
+#define TYPE_GUID_OFFSET            0
+#define TYPE_GUID_SIZE              16
+#define PTN_ENTRY_SIZE              128
+#define UNIQUE_GUID_OFFSET          16
+#define FIRST_LBA_OFFSET            32
+#define LAST_LBA_OFFSET             40
+#define ATTRIBUTE_FLAG_OFFSET       48
+#define PARTITION_NAME_OFFSET       56
+#define MAX_GPT_NAME_SIZE           72
+
+/******************************************************************************
+ * AB RELATED DEFINES
+ ******************************************************************************/
+//Bit 48 onwords in the attribute field are the ones where we are allowed to
+//store our AB attributes.
+#define AB_FLAG_OFFSET (ATTRIBUTE_FLAG_OFFSET + 6)
+#define GPT_DISK_INIT_MAGIC 0xABCD
+#define AB_PARTITION_ATTR_SLOT_ACTIVE (0x1<<2)
+#define AB_PARTITION_ATTR_BOOT_SUCCESSFUL (0x1<<6)
+#define AB_PARTITION_ATTR_UNBOOTABLE (0x1<<7)
+#define AB_SLOT_ACTIVE_VAL              0x3F
+#define AB_SLOT_INACTIVE_VAL            0x0
+#define AB_SLOT_ACTIVE                  1
+#define AB_SLOT_INACTIVE                0
+#define AB_SLOT_A_SUFFIX                "_a"
+#define AB_SLOT_B_SUFFIX                "_b"
+#define PTN_XBL                         "xbl"
+#define PTN_SWAP_LIST                   PTN_XBL, \
+            "abl", "aop", "devcfg", \
+            "dtbo", "hyp", "keymaster", "qupfw", "storsec", \
+            "tz", "vbmeta", "vbmeta_system", "xbl_config"
+
+#define AB_PTN_LIST PTN_SWAP_LIST, "boot", "system", "vendor", "modem", "product"
+#define BOOT_DEV_DIR    "/dev/block/bootdevice/by-name"
+
+/******************************************************************************
+ * HELPER MACROS
+ ******************************************************************************/
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+/******************************************************************************
+ * TYPES
+ ******************************************************************************/
+enum boot_update_stage {
+	UPDATE_MAIN = 1,
+	UPDATE_BACKUP,
+	UPDATE_FINALIZE
+};
+
+enum gpt_instance {
+	PRIMARY_GPT = 0,
+	SECONDARY_GPT
+};
+
+enum boot_chain {
+	NORMAL_BOOT = 0,
+	BACKUP_BOOT
+};
+
+struct gpt_disk {
+	//GPT primary header
+	uint8_t *hdr;
+	//primary header crc
+	uint32_t hdr_crc;
+	//GPT backup header
+	uint8_t *hdr_bak;
+	//backup header crc
+	uint32_t hdr_bak_crc;
+	//Partition entries array
+	uint8_t *pentry_arr;
+	//Partition entries array for backup table
+	uint8_t *pentry_arr_bak;
+	//Size of the pentry array
+	uint32_t pentry_arr_size;
+	//Size of each element in the pentry array
+	uint32_t pentry_size;
+	//CRC of the partition entry array
+	uint32_t pentry_arr_crc;
+	//CRC of the backup partition entry array
+	uint32_t pentry_arr_bak_crc;
+	//Path to block dev representing the disk
+	char devpath[PATH_MAX];
+	//Block size of disk
+	uint32_t block_size;
+	uint32_t is_initialized;
+};
+
+/******************************************************************************
+ * FUNCTION PROTOTYPES
+ ******************************************************************************/
+int prepare_boot_update(enum boot_update_stage stage);
+//GPT disk methods
+struct gpt_disk* gpt_disk_alloc();
+//Free previously allocated gpt_disk struct
+void gpt_disk_free(struct gpt_disk *disk);
+//Get the details of the disk holding the partition whose name
+//is passed in via dev
+int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk);
+
+//Get pointer to partition entry from a allocated gpt_disk structure
+uint8_t* gpt_disk_get_pentry(struct gpt_disk *disk,
+		const char *partname,
+		enum gpt_instance instance);
+
+//Update the crc fields of the modified disk structure
+int gpt_disk_update_crc(struct gpt_disk *disk);
+
+//Write the contents of struct gpt_disk back to the actual disk
+int gpt_disk_commit(struct gpt_disk *disk);
+
+//Return if the current device is UFS based or not
+int gpt_utils_is_ufs_device();
+
+//Swtich betwieen using either the primary or the backup
+//boot LUN for boot. This is required since UFS boot partitions
+//cannot have a backup GPT which is what we use for failsafe
+//updates of the other 'critical' partitions. This function will
+//not be invoked for emmc targets and on UFS targets is only required
+//to be invoked for XBL.
+//
+//The algorithm to do this is as follows:
+//- Find the real block device(eg: /dev/block/sdb) that corresponds
+//  to the /dev/block/bootdevice/by-name/xbl(bak) symlink
+//
+//- Once we have the block device 'node' name(sdb in the above example)
+//  use this node to to locate the scsi generic device that represents
+//  it by checking the file /sys/block/sdb/device/scsi_generic/sgY
+//
+//- Once we locate sgY we call the query ioctl on /dev/sgy to switch
+//the boot lun to either LUNA or LUNB
+int gpt_utils_set_xbl_boot_partition(enum boot_chain chain);
+
+//Given a vector of partition names as a input and a reference to a map,
+//populate the map to indicate which physical disk each of the partitions
+//sits on. The key in the map is the path to the block device where the
+//partition lies and the value is a vector of strings indicating which of
+//the passed in partition names sits on that device.
+int gpt_utils_get_partition_map(std::vector<std::string>& partition_list,
+                std::map<std::string,std::vector<std::string>>& partition_map);
+#ifdef __cplusplus
+}
+#endif
+#endif /* __GPT_UTILS_H__ */
diff --git a/health/Android.bp b/health/Android.bp
new file mode 100644
index 0000000..874b965
--- /dev/null
+++ b/health/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * 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_binary {
+    name: "android.hardware.health@2.0-service.bramble",
+    init_rc: ["android.hardware.health@2.0-service.bramble.rc"],
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: [
+        "HealthService.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    static_libs: [
+        "android.hardware.health@2.0-impl",
+        "android.hardware.health@1.0-convert",
+        "libhealthservice",
+        "libbatterymonitor",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libpixelhealth",
+        "libutils",
+        "android.hardware.health@2.0",
+    ],
+
+    header_libs: ["libhealthd_headers"],
+
+    overrides: [
+        "healthd",
+    ],
+}
diff --git a/health/HealthService.cpp b/health/HealthService.cpp
new file mode 100644
index 0000000..6496f45
--- /dev/null
+++ b/health/HealthService.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "android.hardware.health@2.0-service.bramble"
+#include <android-base/logging.h>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <health2/Health.h>
+#include <health2/service.h>
+#include <healthd/healthd.h>
+#include <hidl/HidlTransportSupport.h>
+#include <pixelhealth/BatteryMetricsLogger.h>
+#include <pixelhealth/CycleCountBackupRestore.h>
+#include <pixelhealth/DeviceHealth.h>
+#include <pixelhealth/LowBatteryShutdownMetrics.h>
+
+#include <fstream>
+#include <iomanip>
+#include <string>
+#include <vector>
+
+namespace {
+
+using android::hardware::health::V2_0::DiskStats;
+using android::hardware::health::V2_0::StorageAttribute;
+using android::hardware::health::V2_0::StorageInfo;
+using hardware::google::pixel::health::BatteryMetricsLogger;
+using hardware::google::pixel::health::CycleCountBackupRestore;
+using hardware::google::pixel::health::DeviceHealth;
+using hardware::google::pixel::health::LowBatteryShutdownMetrics;
+
+#define FG_DIR "/sys/class/power_supply/maxfg"
+constexpr char kBatteryResistance[] {FG_DIR "/resistance"};
+constexpr char kBatteryOCV[] {FG_DIR "/voltage_ocv"};
+constexpr char kVoltageAvg[] {FG_DIR "/voltage_avg"};
+constexpr char kCycleCountsBins[] {FG_DIR "/cycle_counts_bins"};
+constexpr char kGaugeSerial[] {FG_DIR "/serial_number"};
+
+static BatteryMetricsLogger battMetricsLogger(kBatteryResistance, kBatteryOCV);
+static LowBatteryShutdownMetrics shutdownMetrics(kVoltageAvg);
+static CycleCountBackupRestore ccBackupRestoreMAX(
+    10, kCycleCountsBins, "/persist/battery/max_cycle_counts_bins", kGaugeSerial);
+static DeviceHealth deviceHealth;
+
+#define UFS_DIR "/sys/devices/platform/soc/1d84000.ufshc"
+constexpr char kUfsHealthEol[]{UFS_DIR "/health/eol"};
+constexpr char kUfsHealthLifetimeA[]{UFS_DIR "/health/lifetimeA"};
+constexpr char kUfsHealthLifetimeB[]{UFS_DIR "/health/lifetimeB"};
+constexpr char kUfsVersion[]{UFS_DIR "/version"};
+constexpr char kDiskStatsFile[]{"/sys/block/sda/stat"};
+constexpr char kUFSName[]{"UFS0"};
+
+constexpr char kTCPMPSYName[]{"tcpm-source-psy-usbpd0"};
+
+std::ifstream assert_open(const std::string &path) {
+  std::ifstream stream(path);
+  if (!stream.is_open()) {
+    LOG(FATAL) << "Cannot read " << path;
+  }
+  return stream;
+}
+
+template <typename T>
+void read_value_from_file(const std::string &path, T *field) {
+  auto stream = assert_open(path);
+  stream.unsetf(std::ios_base::basefield);
+  stream >> *field;
+}
+
+void read_ufs_version(StorageInfo *info) {
+  uint64_t value;
+  read_value_from_file(kUfsVersion, &value);
+  std::stringstream ss;
+  ss << "ufs " << std::hex << value;
+  info->version = ss.str();
+}
+
+void fill_ufs_storage_attribute(StorageAttribute *attr) {
+  attr->isInternal = true;
+  attr->isBootDevice = true;
+  attr->name = kUFSName;
+}
+
+}  // anonymous namespace
+
+void healthd_board_init(struct healthd_config *hc) {
+  hc->ignorePowerSupplyNames.push_back(android::String8(kTCPMPSYName));
+  ccBackupRestoreMAX.Restore();
+}
+
+int healthd_board_battery_update(struct android::BatteryProperties *props) {
+  deviceHealth.update(props);
+  battMetricsLogger.logBatteryProperties(props);
+  shutdownMetrics.logShutdownVoltage(props);
+  ccBackupRestoreMAX.Backup(props->batteryLevel);
+  return 0;
+}
+
+void get_storage_info(std::vector<StorageInfo> &vec_storage_info) {
+  vec_storage_info.resize(1);
+  StorageInfo *storage_info = &vec_storage_info[0];
+  fill_ufs_storage_attribute(&storage_info->attr);
+
+  read_ufs_version(storage_info);
+  read_value_from_file(kUfsHealthEol, &storage_info->eol);
+  read_value_from_file(kUfsHealthLifetimeA, &storage_info->lifetimeA);
+  read_value_from_file(kUfsHealthLifetimeB, &storage_info->lifetimeB);
+  return;
+}
+
+void get_disk_stats(std::vector<DiskStats> &vec_stats) {
+  vec_stats.resize(1);
+  DiskStats *stats = &vec_stats[0];
+  fill_ufs_storage_attribute(&stats->attr);
+
+  auto stream = assert_open(kDiskStatsFile);
+  // Regular diskstats entries
+  stream >> stats->reads >> stats->readMerges >> stats->readSectors >>
+      stats->readTicks >> stats->writes >> stats->writeMerges >>
+      stats->writeSectors >> stats->writeTicks >> stats->ioInFlight >>
+      stats->ioTicks >> stats->ioInQueue;
+  return;
+}
+
+int main(void) { return health_service_main(); }
diff --git a/health/android.hardware.health@2.0-service.bramble.rc b/health/android.hardware.health@2.0-service.bramble.rc
new file mode 100644
index 0000000..7026c5b
--- /dev/null
+++ b/health/android.hardware.health@2.0-service.bramble.rc
@@ -0,0 +1,5 @@
+service vendor.health-hal-2-0 /vendor/bin/hw/android.hardware.health@2.0-service.bramble
+    class hal
+    user system
+    group system
+    file /dev/kmsg w
diff --git a/hidl/android.hidl.base@1.0.so-32 b/hidl/android.hidl.base@1.0.so-32
new file mode 100755
index 0000000..b8c51c8
--- /dev/null
+++ b/hidl/android.hidl.base@1.0.so-32
Binary files differ
diff --git a/hidl/android.hidl.base@1.0.so-64 b/hidl/android.hidl.base@1.0.so-64
new file mode 100755
index 0000000..a3c76e7
--- /dev/null
+++ b/hidl/android.hidl.base@1.0.so-64
Binary files differ
diff --git a/init.hardware.chamber.rc.userdebug b/init.hardware.chamber.rc.userdebug
new file mode 100644
index 0000000..ebfb336
--- /dev/null
+++ b/init.hardware.chamber.rc.userdebug
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+on property:init.svc.vendor.thermal-engine=running && property:persist.vendor.disable.thermal.control=1
+  stop vendor.thermal-engine
+
+on property:persist.vendor.disable.thermal.control=1
+  write /sys/devices/virtual/thermal/tz-by-name/sdm-therm/emul_temp 25000
+  write /sys/devices/virtual/thermal/tz-by-name/usbc-therm/emul_temp 25000
+  write /sys/module/overheat_mitigation/parameters/enable 0
+
+on property:persist.vendor.disable.usb.overheat.mitigation=1
+  write /sys/devices/virtual/thermal/tz-by-name/usbc-therm/emul_temp 25000
diff --git a/init.hardware.diag.rc.user b/init.hardware.diag.rc.user
new file mode 100644
index 0000000..2f1a417
--- /dev/null
+++ b/init.hardware.diag.rc.user
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+on property:ro.boot.mode=normal
+    rm /dev/diag
+    rm /dev/diagtest
diff --git a/init.hardware.diag.rc.userdebug b/init.hardware.diag.rc.userdebug
new file mode 100644
index 0000000..43661e7
--- /dev/null
+++ b/init.hardware.diag.rc.userdebug
@@ -0,0 +1,110 @@
+#
+# 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.
+#
+
+on init
+    chmod 666 /dev/diag
+
+on post-fs-data
+    # Modem logging collection
+    mkdir /data/vendor/radio 0777 radio radio
+    mkdir /data/vendor/radio/diag_logs 0777 system system
+    rm /data/vendor/radio/diag_logs/logs/diag_poweron_log.qmdl
+    # WLAN logging collection
+    mkdir /data/vendor/wifi 0777 system system
+    mkdir /data/vendor/wifi/cnss_diag 0777 system system
+
+service diag_mdlog_start /vendor/bin/diag_mdlog
+    class late_start
+    user shell
+    group system diag media_rw
+    disabled
+    oneshot
+
+service diag_mdlog_stop /vendor/bin/diag_mdlog -k
+    class late_start
+    user shell
+    group system diag media_rw
+    disabled
+    oneshot
+
+on boot && property:persist.vendor.sys.modem.diag.mdlog=*
+    rm /data/vendor/radio/diag_logs/diag_mdlog_pid
+    setprop vendor.sys.modem.diag.mdlog ${persist.vendor.sys.modem.diag.mdlog}
+
+on property:vendor.sys.modem.diag.mdlog=true
+    start diag_mdlog_start
+
+on property:vendor.sys.modem.diag.mdlog=false
+    start diag_mdlog_stop
+
+on property:persist.vendor.sys.cnss.diag_qxdm=true
+    start vendor.cnss_diag
+
+on property:persist.vendor.sys.cnss.diag_qxdm=false
+    stop vendor.cnss_diag
+
+on property:persist.vendor.sys.cnss.diag_txt=true
+    start vendor.cnss_diag_txt
+
+on property:persist.vendor.sys.cnss.diag_txt=false
+    stop vendor.cnss_diag_txt
+
+service vendor.cnss_diag /vendor/bin/cnss_diag -q -u -w
+    class late_start
+    user system
+    group system
+    disabled
+    oneshot
+
+service vendor.cnss_diag_txt /vendor/bin/cnss_diag -s -f -P -m /data/vendor/wifi/cnss_diag/cnss_diag.conf -t HELIUM
+    class late_start
+    user system
+    group system
+    disabled
+    oneshot
+
+on property:vendor.debug.ramdump.force_crash=true
+    write /proc/sysrq-trigger "c"
+
+on property:ro.vendor.bluetooth.ftm_enabled=true
+    start ftmd
+
+service ftmd /vendor/bin/ftmdaemon
+    class late_start
+    user root
+    group bluetooth net_bt_admin misc diag net_bt
+    disabled
+    oneshot
+
+on property:vendor.sys.logger.bluetooth=true
+   setprop persist.vendor.service.bdroid.snooplog true
+   setprop persist.vendor.service.bdroid.fwsnoop true
+
+on property:vendor.sys.logger.bluetooth=false
+   setprop persist.vendor.service.bdroid.snooplog false
+   setprop persist.vendor.service.bdroid.fwsnoop false
+
+on property:persist.bluetooth.btsnoopenable=true
+   setprop persist.vendor.service.bdroid.soclog true
+
+on property:persist.bluetooth.btsnoopenable=false
+   setprop persist.vendor.service.bdroid.soclog false
+
+on property:vendor.usb.config=*
+   start usbd
+
+on property:persist.vendor.usb.usbradio.config=*
+   start usbd
diff --git a/init.hardware.ipa.rc.userdebug b/init.hardware.ipa.rc.userdebug
new file mode 100644
index 0000000..a690c0d
--- /dev/null
+++ b/init.hardware.ipa.rc.userdebug
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+on boot
+    # Enable RmNet IPA3 TX timeout detection
+    write /d/ipawwan/debug 1
diff --git a/init.hardware.mpssrfs.rc.user b/init.hardware.mpssrfs.rc.user
new file mode 100644
index 0000000..f75a413
--- /dev/null
+++ b/init.hardware.mpssrfs.rc.user
@@ -0,0 +1,5 @@
+on post-fs-data
+    # Modem Remote FS
+    mkdir /data/vendor/rfs      0770 vendor_rfs vendor_rfs
+    mkdir /data/vendor/rfs/mpss 0770 vendor_rfs vendor_rfs
+    mkdir /data/vendor/tombstones/rfs      0770 vendor_rfs vendor_rfs
diff --git a/init.hardware.mpssrfs.rc.userdebug b/init.hardware.mpssrfs.rc.userdebug
new file mode 100644
index 0000000..5939bfc
--- /dev/null
+++ b/init.hardware.mpssrfs.rc.userdebug
@@ -0,0 +1,11 @@
+on post-fs-data
+    # Modem Remote FS
+    mkdir /data/vendor/rfs      0770 vendor_rfs vendor_rfs
+    mkdir /data/vendor/rfs/mpss 0770 vendor_rfs vendor_rfs
+    mkdir /data/vendor/tombstones/rfs      0770 vendor_rfs vendor_rfs
+    write /data/vendor/rfs/mpss/mcfg_nv_list_flag "1"
+    chown vendor_rfs vendor_rfs /data/vendor/rfs/mpss/mcfg_nv_list_flag
+    chmod 0700 /data/vendor/rfs/mpss/mcfg_nv_list_flag
+
+on property:vendor.sys.modem.diag.efsdump=true
+    chmod 0660 /data/vendor/rfs/mpss/modem_efs
diff --git a/init.hardware.rc b/init.hardware.rc
new file mode 100644
index 0000000..449c277
--- /dev/null
+++ b/init.hardware.rc
@@ -0,0 +1,755 @@
+#
+# 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.
+#
+
+import /vendor/etc/init/hw/init.${ro.boot.hardware.platform}.usb.rc
+import /vendor/etc/init/hw/init.${ro.boot.hardware.platform}.diag.rc
+import /vendor/etc/init/hw/init.${ro.boot.hardware.platform}.logging.rc
+import /vendor/etc/init/hw/init.${ro.boot.hardware.platform}.mpssrfs.rc
+import /vendor/etc/init/hw/init.${ro.boot.hardware.platform}.power.rc
+
+service vendor.charger /charger
+    class charger
+    seclabel u:r:charger:s0
+
+on early-init
+    mount debugfs debugfs /sys/kernel/debug
+    chmod 0755 /sys/kernel/debug
+
+    # Disable EAS
+    write /sys/kernel/debug/sched_features NO_ENERGY_AWARE
+    mount_all /vendor/etc/fstab.persist --early
+
+# Disable VDSO on JAWS boards.
+on early-init && property:ro.revision="DEV1.0"
+    write /sys/module/vdso/parameters/enable_32 0
+
+# Skip init trigger for charger mode
+on early-init && property:ro.boot.mode=charger
+    setprop vendor.skip.init 1
+
+# We need vold early for metadata encryption
+on early-fs
+    start vold
+
+on init && property:vendor.skip.init=0
+    # Disable UFS powersaving
+    write /sys/devices/platform/soc/${ro.boot.bootdevice}/clkgate_enable 0
+    write /sys/devices/platform/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0
+
+    # Disable powersaving
+    write /sys/module/lpm_levels/parameters/sleep_disabled 1
+
+    wait /dev/block/platform/soc/${ro.boot.bootdevice}
+    symlink /dev/block/platform/soc/${ro.boot.bootdevice} /dev/block/bootdevice
+
+    # start qseecomd early as we mount system/ vendor/ early
+    # vold needs keymaster that needs qseecomd
+    start vendor.qseecomd
+    start keymaster-4-0
+
+    start vendor.citadeld
+    start vendor.keymaster-4-0-citadel
+
+    # Support legacy paths
+    symlink /sdcard /mnt/sdcard
+    symlink /sdcard /storage/sdcard0
+
+    # Loading kernel modules in background
+    start insmod_sh
+
+    # bring back all cores
+    write /sys/devices/system/cpu/cpu0/online 1
+    write /sys/devices/system/cpu/cpu1/online 1
+    write /sys/devices/system/cpu/cpu2/online 1
+    write /sys/devices/system/cpu/cpu3/online 1
+    write /sys/devices/system/cpu/cpu4/online 1
+    write /sys/devices/system/cpu/cpu5/online 1
+    write /sys/devices/system/cpu/cpu6/online 1
+    write /sys/devices/system/cpu/cpu7/online 1
+
+    # configure governor settings for little cluster
+    write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor schedutil
+    write /sys/devices/system/cpu/cpu0/cpufreq/schedutil/up_rate_limit_us 500
+    write /sys/devices/system/cpu/cpu0/cpufreq/schedutil/down_rate_limit_us 20000
+
+    # configure governor settings for big cluster
+    write /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor schedutil
+    write /sys/devices/system/cpu/cpu4/cpufreq/schedutil/up_rate_limit_us 500
+    write /sys/devices/system/cpu/cpu4/cpufreq/schedutil/down_rate_limit_us 20000
+
+    # configure governor settings for big big CPU
+    write /sys/devices/system/cpu/cpu7/cpufreq/scaling_governor schedutil
+    write /sys/devices/system/cpu/cpu7/cpufreq/schedutil/up_rate_limit_us 500
+    write /sys/devices/system/cpu/cpu7/cpufreq/schedutil/down_rate_limit_us 20000
+
+    # ZRAM setup
+    write /sys/block/zram0/comp_algorithm lz4
+    write /proc/sys/vm/page-cluster 0
+
+    # Some user code relies on ro.boot.hardware.revision
+    setprop ro.boot.hardware.revision ${ro.revision}
+
+    # set default schedTune value for foreground/top-app
+    write /dev/stune/foreground/schedtune.prefer_idle 1
+    write /dev/stune/top-app/schedtune.boost 10
+    write /dev/stune/top-app/schedtune.prefer_idle 1
+
+    mkdir /dev/cpuset/camera-daemon
+    write /dev/cpuset/camera-daemon/cpus 0-7
+    write /dev/cpuset/camera-daemon/mems 0
+    chown system system /dev/cpuset/camera-daemon
+    chown system system /dev/cpuset/camera-daemon/tasks
+    chmod 0664 /dev/cpuset/camera-daemon/tasks
+
+    # Enable suspend clock reporting
+    write /sys/kernel/debug/clk/debug_suspend 1
+
+on late-init
+    setprop vendor.thermal.config thermal_info_config.json
+
+on fs
+    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --early
+
+    mkdir /mnt/vendor/persist/audio 0770 media audio
+    mkdir /mnt/vendor/persist/data 0700 system system
+    mkdir /mnt/vendor/persist/display 0770 system graphics
+    mkdir /mnt/vendor/persist/haptics 0770 system system
+    mkdir /mnt/vendor/persist/rfs 0770 root system
+    mkdir /mnt/vendor/persist/hlos_rfs 0770 root system
+    mkdir /mnt/vendor/persist/oslo 0770 system system
+    mkdir /mnt/vendor/persist/touch 0770 system system
+    chmod 0770 /mnt/vendor/persist/rfs
+    chmod 0770 /mnt/vendor/persist/rfs/shared
+    chmod 0770 /mnt/vendor/persist/rfs/msm
+    chmod 0770 /mnt/vendor/persist/rfs/msm/adsp
+    chmod 0770 /mnt/vendor/persist/rfs/msm/mpss
+    chmod 0770 /mnt/vendor/persist/rfs/msm/slpi
+    chmod 0770 /mnt/vendor/persist/rfs/mdm
+    chmod 0770 /mnt/vendor/persist/rfs/mdm/adsp
+    chmod 0770 /mnt/vendor/persist/rfs/mdm/mpss
+    chmod 0770 /mnt/vendor/persist/rfs/mdm/slpi
+    chmod 0770 /mnt/vendor/persist/rfs/mdm/tn
+    chmod 0770 /mnt/vendor/persist/rfs/apq
+    chmod 0770 /mnt/vendor/persist/rfs/apq/gnss
+    chmod 0770 /mnt/vendor/persist/hlos_rfs
+
+    # for cycle count backup
+    mkdir /mnt/vendor/persist/battery 0700 system system
+
+    restorecon_recursive /mnt/vendor/persist
+
+on post-fs
+    # set RLIMIT_MEMLOCK to 64MB
+    setrlimit 8 67108864 67108864
+
+    # Wait qseecomd started
+    wait_for_prop vendor.sys.listeners.registered true
+
+    # load IPA FWs
+    # This must be started when vendor.sys.listeners.registered is true
+    write /dev/ipa 1
+
+on late-fs
+    # Start services for bootanim
+    start color_init
+    wait_for_prop vendor.display.native_display_primaries_ready 1
+    setprop ro.surface_flinger.display_primary_red ${vendor.display.primary_red}
+    setprop ro.surface_flinger.display_primary_green ${vendor.display.primary_green}
+    setprop ro.surface_flinger.display_primary_blue ${vendor.display.primary_blue}
+    setprop ro.surface_flinger.display_primary_white ${vendor.display.primary_white}
+    start surfaceflinger
+    start bootanim
+    start vendor.hwcomposer-2-3
+    start vendor.configstore-hal
+    start vendor.qti.hardware.display.allocator
+
+    # Wait for keymaster HALs (TEE and StrongBox)
+    exec_start wait_for_strongbox
+
+
+    # Mount RW partitions which need run fsck
+    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late
+
+    # Required for time_daemon
+    mkdir /mnt/vendor/persist/time 0770 system system
+
+    # Start time daemon early so that the system time can be set early
+    start time_daemon
+
+    # Init sensor specific services
+    start init-sensors-sh
+
+    # turn off vblank irq immediately after turning off
+    write /sys/module/drm/parameters/vblankoffdelay -1
+
+on post-fs-data
+    mkdir /vendor/data/tombstones 0771 system system
+    mkdir /tombstones/modem 0771 system system
+    mkdir /tombstones/lpass 0771 system system
+    mkdir /tombstones/wcnss 0771 system system
+    mkdir /tombstones/dsps 0771 system system
+    mkdir /data/vendor/hbtp 0750 system system
+    mkdir /data/misc/seemp 0700 system system
+    mkdir /data/vendor/tloc 0700 system drmrpc
+    mkdir /data/vendor/nnhal 0700 system system
+    mkdir /data/vendor/time 0770 system system
+    mkdir /data/vendor/modem_fdr 0700 root system
+    mkdir /data/vendor/display 0770 system graphics
+
+on zygote-start
+    # zygote is started in common init.rc
+    # and now we can continue initialize /data/
+    mkdir /data/vendor/ipa 0770 radio radio
+    chown radio radio /data/vendor/ipa
+
+    # Create the directories used by the Wireless subsystem
+    mkdir /data/vendor/wifi 0771 wifi wifi
+    mkdir /data/vendor/wifi/wpa 0770 wifi wifi
+    mkdir /data/vendor/wifi/wpa/sockets 0770 wifi wifi
+
+    # Create the directories used by CnE subsystem
+    mkdir /data/vendor/connectivity 0771 radio radio
+    chown radio radio /data/vendor/connectivity
+
+    # Create directory for radio
+    mkdir /data/vendor/radio 0773 system radio
+    mkdir /data/vendor/modem_stat 0771 system radio
+    write /data/vendor/modem_stat/debug.txt ""
+    chown system radio /data/vendor/modem_stat/debug.txt
+    chmod 0664 /data/vendor/modem_stat/debug.txt
+
+    # Mark the copy complete flag to not completed
+    write /data/vendor/radio/copy_complete 0
+    chown radio radio /data/vendor/radio/copy_complete
+    chmod 0660 /data/vendor/radio/copy_complete
+
+    # File flags for prebuilt ril db file
+    write /data/vendor/radio/prebuilt_db_support 1
+    chown radio radio /data/vendor/radio/prebuilt_db_support
+    chmod 0400 /data/vendor/radio/prebuilt_db_support
+    write /data/vendor/radio/db_check_done 0
+    chown radio radio /data/vendor/radio/db_check_done
+    chmod 0660 /data/vendor/radio/db_check_done
+
+    # Create directories for Location services
+    mkdir /data/vendor/location 0770 gps gps
+    mkdir /data/vendor/location/mq 0770 gps gps
+    mkdir /data/vendor/location/xtwifi 0770 gps gps
+    mkdir /dev/socket/location 0770 gps gps
+    mkdir /dev/socket/location/mq 0770 gps gps
+    mkdir /dev/socket/location/xtra 0770 gps gps
+
+on early-boot
+    # Set up sensors-related directories and permissions
+    chmod 775 /mnt/vendor/persist/sensors
+    chmod 664 /mnt/vendor/persist/sensors/sensors_settings
+    chown root system /mnt/vendor/persist/sensors/registry
+    chmod 775 /mnt/vendor/persist/sensors/registry
+    chown root system /mnt/vendor/persist/sensors/registry/registry
+    chmod 775 /mnt/vendor/persist/sensors/registry/registry
+    chmod 664 /mnt/vendor/persist/sensors/registry/registry/sensors_registry
+    chown system root /mnt/vendor/persist/sensors/sensors_settings
+    chown root root /mnt/vendor/persist/sensors/registry/registry/sensors_settings
+
+    mkdir /data/vendor/sensors 0770
+    chown system system /data/vendor/sensors
+
+    chmod 770 /mnt/vendor/persist/audio
+    chmod 660 /mnt/vendor/persist/audio/audio.cal
+    chown media audio /mnt/vendor/persist/audio
+    chown audioserver audio /mnt/vendor/persist/audio/audio.cal
+
+    # Set up haptics-related directories and permissions
+    chmod 770 /mnt/vendor/persist/haptics
+    chmod 440 /mnt/vendor/persist/haptics/cs40l25a.cal
+    chown system system /mnt/vendor/persist/haptics
+    chown system system /mnt/vendor/persist/haptics/cs40l25a.cal
+
+    # Set up oslo-related directories and permissions
+    chmod 770 /mnt/vendor/persist/oslo
+    chmod 660 /mnt/vendor/persist/oslo/oslo.cal
+    chown system system /mnt/vendor/persist/oslo
+    chown system system /mnt/vendor/persist/oslo/oslo.cal
+
+    # Set up touch directories and permissions
+    chmod 770 /mnt/vendor/persist/touch
+    chown system system /mnt/vendor/persist/touch
+
+    # Permission for lights driver
+    chown system system /sys/class/backlight/panel0-backlight/brightness
+    chown system system /sys/class/backlight/panel0-backlight/vr_mode
+    chown system system /sys/class/backlight/panel0-backlight/hbm_mode
+
+    # Wait for insmod_sh to finish all modules
+    wait_for_prop vendor.all.modules.ready 1
+
+    # Update dm-verity state and set partition.*.verified properties
+    verity_update_state
+
+    # Wait for insmod_sh to finish all boot devices
+    wait_for_prop vendor.all.devices.ready 1
+
+    # Permission for Vibrator
+    chown system system /sys/class/leds/vibrator/device/asp_enable
+    chown system system /sys/class/leds/vibrator/device/comp_enable
+    chown system system /sys/class/leds/vibrator/device/cp_dig_scale
+    chown system system /sys/class/leds/vibrator/device/cp_trigger_duration
+    chown system system /sys/class/leds/vibrator/device/cp_trigger_index
+    chown system system /sys/class/leds/vibrator/device/cp_trigger_q_sub
+    chown system system /sys/class/leds/vibrator/device/cp_trigger_queue
+    chown system system /sys/class/leds/vibrator/device/dig_scale
+    chown system system /sys/class/leds/vibrator/device/exc_enable
+    chown system system /sys/class/leds/vibrator/device/f0_stored
+    chown system system /sys/class/leds/vibrator/device/fw_rev
+    chown system system /sys/class/leds/vibrator/device/gpio1_fall_dig_scale
+    chown system system /sys/class/leds/vibrator/device/gpio1_fall_index
+    chown system system /sys/class/leds/vibrator/device/gpio1_rise_dig_scale
+    chown system system /sys/class/leds/vibrator/device/gpio1_rise_index
+    chown system system /sys/class/leds/vibrator/device/heartbeat
+    chown system system /sys/class/leds/vibrator/device/hw_reset
+    chown system system /sys/class/leds/vibrator/device/num_waves
+    chown system system /sys/class/leds/vibrator/device/q_stored
+    chown system system /sys/class/leds/vibrator/device/redc_comp_enable
+    chown system system /sys/class/leds/vibrator/device/redc_stored
+    chown system system /sys/class/leds/vibrator/device/standby_timeout
+    chown system system /sys/class/leds/vibrator/device/vbatt_max
+    chown system system /sys/class/leds/vibrator/device/vbatt_min
+
+    # Permission for Rainbow sensor
+    chown system system /sys/devices/platform/soc/ac4b000.qcom,cci/ac4b000.qcom,cci:st,rainbow@20/rainbow_enable
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,rainbow@20/rainbow_enable
+    chown system system /sys/devices/platform/soc/ac4b000.qcom,cci/ac4b000.qcom,cci:st,rainbow@20/rainbow_read_byte
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,rainbow@20/rainbow_read_byte
+    chown system system /sys/devices/platform/soc/ac4b000.qcom,cci/ac4b000.qcom,cci:st,rainbow@20/rainbow_write_byte
+    chmod 0660 /sys/devices/platform/soc/ac4b000.qcom,cci/ac4b000.qcom,cci:st,rainbow@20/rainbow_write_byte
+    chown system system /dev/vd6281
+    chmod 0660 /dev/vd6281
+
+    # Permission for Athletico
+    chown system system /dev/sensor_tunnel
+    chmod 0660 /dev/sensor_tunnel
+
+    # Permission for Dot and Flood
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/led_laser_enable
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/led_laser_enable
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/is_certified
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/is_certified
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/led_laser_write_byte
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/led_laser_write_byte
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/is_silego_validated
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/is_silego_validated
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/led_laser_read_byte
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/led_laser_read_byte
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/itoc_cali_data_store
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-flood@64/itoc_cali_data_store
+    chown system system /dev/lm36011_flood
+    chmod 0660 /dev/lm36011_flood
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/led_laser_enable
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/led_laser_enable
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/is_certified
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/is_certified
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/led_laser_write_byte
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/led_laser_write_byte
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/is_silego_validated
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/is_silego_validated
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/led_laser_read_byte
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/led_laser_read_byte
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/itoc_cali_data_store
+    chmod 0660 /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-led-laser-dot@64/itoc_cali_data_store
+    chown system system /dev/lm36011_dot
+    chmod 0660 /dev/lm36011_dot
+
+    # Permission for camera sensor
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-sensor@3/set_strobe_type
+    chmod 0660 sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-sensor@3/set_strobe_type
+    chown system system /sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-sensor@4/set_strobe_type
+    chmod 0660 sys/devices/platform/soc/ac4a000.qcom,cci/ac4a000.qcom,cci:qcom,cam-sensor@4/set_strobe_type
+
+    # FG cycle count read from dumpstate + backup restore from health HAL (and pixelstats)
+    chown system system /sys/class/power_supply/maxfg/cycle_counts_bins
+
+    # Permission for Pixelstats
+    chown system system /sys/class/misc/msm_cirrus_playback/resistance_left_right
+    chown system system /sys/devices/platform/soc/1d84000.ufshc/slowio_read_cnt
+    chown system system /sys/devices/platform/soc/1d84000.ufshc/slowio_write_cnt
+    chown system system /sys/devices/platform/soc/1d84000.ufshc/slowio_unmap_cnt
+    chown system system /sys/devices/platform/soc/1d84000.ufshc/slowio_sync_cnt
+
+    # Permission for Health Storage HAL
+    chown system system /sys/devices/platform/soc/1d84000.ufshc/manual_gc
+
+    # Permissions for reading display native color gamut
+    chown system graphics /mnt/vendor/persist/display/native_gamut.csv
+
+on boot
+    # This location is used by QCRIL to host UNIX domain
+    # socket files used for internal IPC within QCRIL
+    # modules
+    mkdir /dev/socket/qmux_radio 0770 radio radio
+    chmod 2770 /dev/socket/qmux_radio
+
+    setprop wifi.interface wlan0
+
+    chown system system /sys/kernel/hbtp/display_pwr
+    start rmt_storage
+    start rfs_access
+
+    # default country code
+    setprop ro.boot.wificountrycode 00
+
+    # WLAN debug access
+    chown system system /d/icnss/stats
+
+service init-radio-sh /vendor/bin/init.radio.sh
+    class late_start
+    user radio
+    group root radio
+    oneshot
+
+on charger
+    stop vendor.qseecomd
+    stop keymaster-4-0
+    setprop sys.usb.configfs 1
+
+    # Enable UFS powersaving
+    write /sys/devices/platform/soc/${ro.boot.bootdevice}/clkgate_enable 1
+    write /sys/devices/platform/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
+
+    # Enable EAS
+    write /sys/kernel/debug/sched_features ENERGY_AWARE
+
+    # Enable powersaving
+    write /sys/module/lpm_levels/parameters/sleep_disabled 0
+
+on property:sys.boot_completed=1
+    # Enable EAS
+    write /sys/kernel/debug/sched_features ENERGY_AWARE
+
+    # No sleep till proto!
+    exec - system system -- svc power stayon true
+
+    # Enable UFS powersaving
+    write /sys/devices/platform/soc/${ro.boot.bootdevice}/clkgate_enable 1
+    write /sys/devices/platform/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
+
+    # Enable powersaving
+    write /sys/module/lpm_levels/parameters/sleep_disabled 0
+
+    # F2FS tuning: issue discard commands up to 128MB
+    write /sys/block/dm-7/queue/discard_max_bytes 134217728
+
+    # Block layer tuning: discard chunk size up to 128MB
+    # Otherwise, contiguous discards can be merged
+    write /sys/block/sda/queue/discard_max_bytes 134217728
+
+    # Enable ZRAM on boot_complete
+    swapon_all /vendor/etc/fstab.${ro.boot.hardware.platform}
+    write /proc/sys/vm/swappiness 100
+
+    # Setup runtime cpusets
+    write /dev/cpuset/top-app/cpus 0-7
+    write /dev/cpuset/foreground/cpus 0-3,5-6
+    write /dev/cpuset/background/cpus 0-1
+    write /dev/cpuset/system-background/cpus 0-3
+    write /dev/cpuset/restricted/cpus 0-3
+
+    # Setup runtime blkio
+    # value for group_idle is us
+    write /dev/blkio/blkio.weight 1000
+    write /dev/blkio/background/blkio.weight 10
+    write /dev/blkio/blkio.group_idle 2000
+    write /dev/blkio/background/blkio.group_idle 0
+
+    # UFS health
+    chmod 755 /sys/kernel/debug/ufshcd0
+    chmod 644 /sys/kernel/debug/ufshcd0/show_hba
+    chmod 644 /sys/kernel/debug/ufshcd0/stats/err_stats
+    chmod 644 /sys/kernel/debug/ufshcd0/stats/io_stats
+    chmod 644 /sys/kernel/debug/ufshcd0/stats/req_stats
+
+    # HardwareInfo needs to be able to read display info
+    chmod 444 /sys/devices/platform/soc/soc:qcom,dsi-display-primary/panel_info/panel0/serial_number
+    chmod 444 /sys/devices/platform/soc/soc:qcom,dsi-display-primary/panel_info/panel0/panel_vendor_name
+
+    # Maxim FG dump for dumpstate
+    chown system system /sys/kernel/debug/regmap/1-0036/registers
+    chown system system /sys/kernel/debug/regmap/1-000b/registers
+    chown system system /sys/kernel/debug/google_battery/cycle_count_bins
+    chown system system /sys/kernel/debug/google_battery/ssoc_gdf
+    chown system system /sys/kernel/debug/google_battery/ssoc_rls
+    chown system system /sys/kernel/debug/google_battery/ssoc_uic
+    chown system system /sys/kernel/debug/google_battery/ssoc_uicurve
+    chown system system /sys/kernel/debug/google_charger/pps_op_ua
+    chown system system /sys/kernel/debug/google_charger/pps_out_uv
+
+    # Permission for Athletico
+    chown system system /dev/iaxxx-module-celldrv
+    chmod 0660 /dev/iaxxx-module-celldrv
+
+service vendor.per_mgr /vendor/bin/pm-service
+    class core
+    user system
+    group system
+    ioprio rt 4
+
+service per_proxy /vendor/bin/pm-proxy
+    class core
+    user system
+    group system
+    disabled
+
+on property:init.svc.vendor.per_mgr=running
+    start per_proxy
+
+on property:sys.shutdown.requested=*
+    stop per_proxy
+
+service vendor.qseecomd /vendor/bin/qseecomd
+    class core
+    user root
+    group root
+
+service vendor.thermal-engine /vendor/bin/thermal-engine -c /vendor/etc/thermal-engine-${ro.hardware}.conf
+   class main
+   user root
+   socket thermal-send-client stream 0666 system system
+   socket thermal-recv-client stream 0660 system system
+   socket thermal-recv-passive-client stream 0666 system system
+   socket thermal-send-rule stream 0660 system system
+   group root
+
+service init-sensors-sh /vendor/bin/init.sensors.sh
+    class main
+    user root
+    group root system
+    disabled
+    oneshot
+
+service sensors.qti /vendor/bin/sensors.qti
+    class core
+    user system
+    group system
+    # Grants the ability for this daemon to bind IPC router ports so it can
+    # register QMI services
+    capabilities NET_BIND_SERVICE
+
+service vendor.sscrpcd  /vendor/bin/sscrpcd sensorspd
+    class core
+    user system
+    group system
+
+service vendor.adsprpcd /vendor/bin/adsprpcd
+   class main
+   user root
+   group media
+   setenv ADSP_LIBRARY_PATH /vendor/dsp;/vendor/lib/rfsa/adsp;/system/lib/rfsa/adsp
+
+service vendor.adsprpcd_audiopd /vendor/bin/adsprpcd audiopd
+   class main
+   user media
+   group media
+
+service vendor.cdsprpcd /vendor/bin/cdsprpcd
+   class main
+   user system
+   group system
+
+service vendor.lowi /vendor/bin/sscrpcd
+   class core
+   user system
+   group system
+
+service vendor.imsqmidaemon /system/vendor/bin/imsqmidaemon
+    class main
+    user radio
+    socket ims_qmid stream 0660 system radio
+    group radio log diag
+
+service vendor.imsdatadaemon /system/vendor/bin/imsdatadaemon
+    class main
+    user radio
+    socket ims_datad stream 0660 system radio
+    group radio wifi inet log diag
+    disabled
+
+service vendor.imsrcsservice /system/vendor/bin/imsrcsd
+    class main
+    user radio
+    group radio diag inet log wakelock
+
+on property:vendor.ims.QMI_DAEMON_STATUS=1
+    start vendor.imsdatadaemon
+
+service vendor.ims_rtp_daemon /system/vendor/bin/ims_rtp_daemon
+   class main
+   user radio
+   group radio inet log
+
+service cnd /vendor/bin/cnd
+   class main
+   user system
+   group system wifi inet radio wakelock net_admin
+
+service vendor.chre /vendor/bin/chre
+    class late_start
+    user system
+    group system wakelock
+    capabilities BLOCK_SUSPEND
+    socket chre seqpacket 0660 root system
+    shutdown critical
+
+service wait_for_strongbox /vendor/bin/hw/wait_for_strongbox
+    user root
+    group root system
+    priority -20
+    ioprio rt 0
+
+on property:vendor.ims.DATA_DAEMON_STATUS=1
+    restart vendor.ims_rtp_daemon
+
+service time_daemon /vendor/bin/time_daemon
+   class core
+   user root
+   group root
+
+service vendor.qrtr-ns /vendor/bin/qrtr-ns -f
+   class core
+   user vendor_qrtr
+   group vendor_qrtr
+   capabilities NET_BIND_SERVICE
+
+service irsc_util /vendor/bin/irsc_util "/vendor/etc/sec_config"
+   class core
+   user root
+   oneshot
+
+service rmt_storage /vendor/bin/rmt_storage
+    class core
+    user root
+    ioprio rt 0
+    shutdown critical
+
+service tftp_server /vendor/bin/tftp_server
+   class core
+   user root
+   group root system
+
+service modem_svc /vendor/bin/modem_svc
+   class core
+   user root
+   group system
+   capabilities NET_BIND_SERVICE
+
+service vendor.ss_ramdump /vendor/bin/subsystem_ramdump
+    class main
+    user root
+    group system
+    disabled
+
+service vendor.ssr_setup /vendor/bin/ssr_setup
+    oneshot
+    disabled
+
+on property:persist.vendor.sys.ssr.restart_level=*
+    start vendor.ssr_setup
+
+on property:persist.vendor.sys.ssr.enable_ramdumps=1
+    write /sys/module/subsystem_restart/parameters/enable_ramdumps 1
+    mkdir /data/vendor/wifidump 771 root system
+    mkdir /data/vendor/ramdump 771 root system
+    mkdir /data/vendor/ssrdump 771 root system
+    mkdir /data/vendor/ssrlog  771 root system
+    start vendor.ss_ramdump
+
+on property:persist.vendor.sys.ssr.enable_ramdumps=0
+    write /sys/module/subsystem_restart/parameters/enable_ramdumps 0
+
+service wpa_supplicant /vendor/bin/hw/wpa_supplicant \
+    -O/data/vendor/wifi/wpa/sockets -puse_p2p_group_interface=1 -dd \
+    -g@android:wpa_wlan0
+    #   we will start as root and wpa_supplicant will switch to user wifi
+    #   after setting up the capabilities required for WEXT
+    #   user wifi
+    #   group wifi inet keystore
+    interface android.hardware.wifi.supplicant@1.0::ISupplicant default
+    interface android.hardware.wifi.supplicant@1.1::ISupplicant default
+    class main
+    socket wpa_wlan0 dgram 660 wifi wifi
+    disabled
+    oneshot
+
+on property:init.svc.vendor.hwcomposer-2-3=stopped
+    stop ppd
+
+on property:init.svc.vendor.hwcomposer-2-3=running
+    start ppd
+
+on property:wlan.driver.status=ok
+    # Get the wlan driver/fw version
+    start vendor.wlan_sh
+
+    # Change permission for dumpstate
+    chmod 444 /sys/kernel/wlan/power_stats
+
+service insmod_sh /vendor/bin/init.insmod.sh /vendor/etc/init.insmod.${ro.hardware}.cfg
+    class main
+    user root
+    group root system
+    disabled
+    oneshot
+
+service vendor.msm_irqbalance /vendor/bin/msm_irqbalance -f /vendor/etc/msm_irqbalance.conf
+    socket msm_irqbalance seqpacket 660 root system
+    class core
+    user root
+    group root
+    writepid /dev/cpuset/system-background/tasks
+
+service pd_mapper /vendor/bin/pd-mapper
+     class core
+     user system
+     group system
+     capabilities NET_BIND_SERVICE
+
+service cnss-daemon /vendor/bin/cnss-daemon -n -l
+   class late_start
+   user system
+   group system inet wifi
+
+service loc_launcher /vendor/bin/loc_launcher
+    class late_start
+    user gps
+    group gps
+
+# bugreport is triggered by holding down volume down, volume up and power
+service bugreport /system/bin/dumpstate -d -p -B -z \
+        -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
+    class main
+    disabled
+    oneshot
+    keycodes 114 115 116
+
+service vendor.wlan_sh /vendor/bin/init.qcom.wlan.sh
+    class main
+    user root
+    group root
+    disabled
+    oneshot
+
+# DSDS feature
+# Enable 2nd qcrild when the property set to dsds
+on property:persist.radio.multisim.config=dsds
+    start vendor.qcrild2
diff --git a/init.hardware.usb.rc b/init.hardware.usb.rc
new file mode 100644
index 0000000..9eb5b1e
--- /dev/null
+++ b/init.hardware.usb.rc
@@ -0,0 +1,103 @@
+#
+# 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.
+#
+
+on early-boot
+    mkdir /config/usb_gadget/g1 0770
+    mkdir /config/usb_gadget/g1/strings/0x409 0770
+    write /config/usb_gadget/g1/bcdUSB 0x0200
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/bcdDevice 0x0440
+    write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
+    write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
+    write /config/usb_gadget/g1/strings/0x409/product ${ro.product.model}
+    mkdir /config/usb_gadget/g1/functions/accessory.gs2
+    mkdir /config/usb_gadget/g1/functions/audio_source.gs3
+    mkdir /config/usb_gadget/g1/functions/midi.gs5
+    mkdir /config/usb_gadget/g1/functions/ffs.adb
+    mkdir /config/usb_gadget/g1/functions/ffs.mtp
+    mkdir /config/usb_gadget/g1/functions/ffs.ptp
+    mkdir /config/usb_gadget/g1/functions/diag.diag
+    mkdir /config/usb_gadget/g1/functions/diag.diag_mdm
+    mkdir /config/usb_gadget/g1/functions/cser.dun.0
+    mkdir /config/usb_gadget/g1/functions/cser.nmea.1
+    mkdir /config/usb_gadget/g1/functions/gsi.rmnet
+    mkdir /config/usb_gadget/g1/functions/gsi.rndis
+    mkdir /config/usb_gadget/g1/functions/gsi.dpl
+    mkdir /config/usb_gadget/g1/functions/qdss.qdss
+    mkdir /config/usb_gadget/g1/functions/qdss.qdss_mdm
+    mkdir /config/usb_gadget/g1/configs/b.1 0770
+    mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770
+    write /config/usb_gadget/g1/os_desc/b_vendor_code 0x1
+    write /config/usb_gadget/g1/os_desc/qw_sign "MSFT100"
+    mkdir /dev/usb-ffs 0775 shell shell
+    mkdir /dev/usb-ffs/adb 0770 shell shell
+    mount functionfs adb /dev/usb-ffs/adb rmode=0770,fmode=0660,uid=2000,gid=2000,no_disconnect=1
+    mkdir /dev/usb-ffs/mtp 0770 mtp mtp
+    mkdir /dev/usb-ffs/ptp 0770 mtp mtp
+    mount functionfs mtp /dev/usb-ffs/mtp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
+    mount functionfs ptp /dev/usb-ffs/ptp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
+    setprop sys.usb.mtp.device_type 3
+    setprop sys.usb.controller "a600000.dwc3"
+    symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1
+    write /sys/module/libcomposite/parameters/disable_l1_for_hs "y"
+    write /config/usb_gadget/g1/functions/gsi.rndis/rndis_class_id 1
+
+on property:init.svc.console=running
+    write /sys/class/power_supply/usb/moisture_detection_enabled 0
+
+on boot
+    setprop sys.usb.configfs 2
+
+on property:sys.usb.config=none && property:sys.usb.configfs=1
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+
+on charger
+    mkdir /config/usb_gadget/g1 0770
+    mkdir /config/usb_gadget/g1/strings/0x409 0770
+    write /config/usb_gadget/g1/bcdUSB 0x0200
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/bcdDevice 0x0440
+    write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
+    write /config/usb_gadget/g1/strings/0x409/manufacturer Google
+    write /config/usb_gadget/g1/strings/0x409/product Pixel
+    mkdir /config/usb_gadget/g1/functions/midi.gs5
+    mkdir /config/usb_gadget/g1/configs/b.1 0770
+    mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770
+    symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1
+    setprop sys.usb.controller "a600000.dwc3"
+
+on property:ro.bootmode=charger
+    setprop sys.usb.config midi
+
+on property:sys.usb.config=midi && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "midi"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4eea
+    symlink /config/usb_gadget/g1/functions/midi.gs5 /config/usb_gadget/g1/configs/b.1/f1
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
diff --git a/init.insmod.bramble.cfg b/init.insmod.bramble.cfg
new file mode 100644
index 0000000..d8d0efe
--- /dev/null
+++ b/init.insmod.bramble.cfg
@@ -0,0 +1,19 @@
+#############################################
+#           init.insmod.cfg                 #
+# This file contains kernel modules to load #
+# at init time by init.insmod.sh script     #
+#############################################
+
+# Load kernel modules
+modprobe|wlan.ko msm_11ad_proxy.ko pinctrl_wcd_dlkm.ko wcd_core_dlkm.ko wcd_spi_dlkm.ko wglink_dlkm.ko q6_pdr_dlkm.ko q6_notifier_dlkm.ko apr_dlkm.ko swr_dlkm.ko q6_dlkm.ko cs35l36_dlkm.ko swr_ctrl_dlkm.ko wcd9xxx_dlkm.ko mbhc_dlkm.ko wcd9360_dlkm.ko wcd934x_dlkm.ko wsa881x_dlkm.ko wcd_cpe_dlkm.ko platform_dlkm.ko machine_dlkm.ko native_dlkm.ko usf_dlkm.ko stub_dlkm.ko adsp_loader_dlkm.ko lkdtm.ko videobuf2-memops.ko videobuf2-vmalloc.ko heatmap.ko ftm5.ko
+
+# All modules loaded
+setprop|vendor.all.modules.ready
+
+# Boot devices
+enable|/sys/kernel/boot_adsp/boot
+enable|/sys/kernel/boot_cdsp/boot
+enable|/sys/kernel/boot_slpi/boot
+
+# All devices enabled
+setporp|vendor.all.devices.ready
diff --git a/init.insmod.sh b/init.insmod.sh
new file mode 100755
index 0000000..c7ac027
--- /dev/null
+++ b/init.insmod.sh
@@ -0,0 +1,31 @@
+#!/vendor/bin/sh
+
+########################################################
+### init.insmod.cfg format:                          ###
+### -----------------------------------------------  ###
+### [insmod|setprop|enable/moprobe] [path|prop name] ###
+### ...                                              ###
+########################################################
+
+if [ $# -eq 1 ]; then
+  cfg_file=$1
+else
+  exit 1
+fi
+
+if [ -f $cfg_file ]; then
+  while IFS="|" read -r action arg
+  do
+    case $action in
+      "insmod") insmod $arg ;;
+      "setprop") setprop $arg 1 ;;
+      "enable") echo 1 > $arg ;;
+      "modprobe") modprobe -a -d /vendor/lib/modules $arg ;;
+    esac
+  done < $cfg_file
+fi
+
+# set property even if there is no insmod config
+# as property value "1" is expected in early-boot trigger
+setprop vendor.all.modules.ready 1
+setprop vendor.all.devices.ready 1
diff --git a/init.logging.rc b/init.logging.rc
new file mode 100644
index 0000000..969d548
--- /dev/null
+++ b/init.logging.rc
@@ -0,0 +1,4 @@
+on post-fs-data
+    mkdir /data/vendor/modem_dump 0777 system system
+    mkdir /data/vendor/radio/diag_logs/logs 0777 system system
+    mkdir /data/vendor/radio/extended_logs 0770 system radio
diff --git a/init.mdm.sh b/init.mdm.sh
new file mode 100644
index 0000000..3ed7ed5
--- /dev/null
+++ b/init.mdm.sh
@@ -0,0 +1,34 @@
+#! /vendor/bin/sh
+
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of Linux Foundation nor
+#       the names of its contributors may be used to endorse or promote
+#       products derived from this software without specific prior written
+#       permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+baseband=`getprop ro.baseband`
+if [ "$baseband" = "mdm" ] || [ "$baseband" = "mdm2" ]; then
+	start vendor.mdm_helper
+fi
+
diff --git a/init.msm.usb.configfs.rc b/init.msm.usb.configfs.rc
new file mode 100644
index 0000000..e57f699
--- /dev/null
+++ b/init.msm.usb.configfs.rc
@@ -0,0 +1,1216 @@
+# Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#     * Redistributions of source code must retain the above copyright
+# 	notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#	copyright notice, this list of conditions and the following
+#	disclaimer in the documentation and/or other materials provided
+#	with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#	from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# USB compositions
+on property:sys.usb.config=none && property:sys.usb.configfs=1
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+
+on property:sys.usb.config=mass_storage && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "msc"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0xF000
+    symlink /config/usb_gadget/g1/functions/mass_storage.0 /config/usb_gadget/g1/configs/b.1/f1
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mass_storage,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mass_storage,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb_msc"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9015
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/mass_storage.0 /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x901D
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x900E
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,serial_cdev,rmnet,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "Default composition"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9091
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "Default comp without ADB"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9092
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:vendor.usb.tethering=true
+    write /sys/class/net/rndis0/queues/rx-0/rps_cpus ${vendor.usb.rps_mask}
+
+on property:sys.usb.config=rndis
+    setprop sys.usb.config rndis,${persist.vendor.usb.config.extra}
+
+on property:sys.usb.config=rndis,none && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0xF00E
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,adb
+    setprop sys.usb.config rndis,${persist.vendor.usb.config.extra},adb
+
+on property:sys.usb.config=rndis,none,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,none,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9024
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,diag && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x902C
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,diag,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,diag,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x902D
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,serial_cdev && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_dun"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90B3
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,serial_cdev,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,serial_cdev,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_dun_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90B4
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,serial_cdev,diag && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_dun_diag"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90B5
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,serial_cdev,diag,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,serial_cdev,diag,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_dun_diag"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90B6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=mtp,diag && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_diag"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x901B
+    symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,diag,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,diag,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_diag_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x903A
+    symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_qdss"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x904A
+    write /config/usb_gadget/g1/functions/qdss.qdss/enable_debug_inface 1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,qdss,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_qdss_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9060
+    write /config/usb_gadget/g1/functions/qdss.qdss/enable_debug_inface 1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_qdss_rmnet"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9083
+    write /config/usb_gadget/g1/functions/qdss.qdss/enable_debug_inface 1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,qdss,rmnet,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_qdss_rmnet_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9084
+    write /config/usb_gadget/g1/functions/qdss.qdss/enable_debug_inface 1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=rndis,diag,qdss && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag_qdss"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9081
+    write /config/usb_gadget/g1/functions/qdss.qdss/enable_debug_inface 1
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=rndis,diag,qdss,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,diag,qdss,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag_qdss_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9082
+    write /config/usb_gadget/g1/functions/qdss.qdss/enable_debug_inface 1
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ncm && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ncm"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0xA4A1
+    symlink /config/usb_gadget/g1/functions/ncm.0 /config/usb_gadget/g1/configs/b.1/f1
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ncm,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ncm,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ncm_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x908C
+    symlink /config/usb_gadget/g1/functions/ncm.0 /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_dun"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x9004
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,adb,serial_cdev && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,adb,serial_cdev && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_adb_dun"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x901f
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet,dpl && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_dun_rmnet_dpl"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90b7
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet,dpl,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,serial_cdev,rmnet,dpl,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_dun_rmnet_dpl_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90b8
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f5
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=rndis,diag,dpl && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag_dpl"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90bf
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,diag,dpl,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,diag,dpl,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag_dpl_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90c0
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=ccid && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ccid"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90CE
+    symlink /config/usb_gadget/g1/functions/ccid.ccid /config/usb_gadget/g1/configs/b.1/f1
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ccid,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ccid,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ccid_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90CF
+    symlink /config/usb_gadget/g1/functions/ccid.ccid /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ccid,diag && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ccid_diag"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90D0
+    symlink /config/usb_gadget/g1/functions/ccid.ccid /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ccid,diag,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ccid,diag,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ccid_diag_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90D1
+    symlink /config/usb_gadget/g1/functions/ccid.ccid /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet,ccid && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_dun_rmnet_ccid"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90D2
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/ccid.ccid /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet,ccid,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,serial_cdev,rmnet,ccid,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_dun_rmnet_ccid_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90D3
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/ccid.ccid /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f5
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,serial_cdev_mdm,rmnet && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_diag_mdm,qdss_qdss_mdm_dun_dun_mdm_rmnet"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90D7
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/cser.dun.2 /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,serial_cdev_mdm,rmnet,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,serial_cdev_mdm,rmnet,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_diag_mdm,qdss_qdss_mdm_dun_dun_mdm_rmnet_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90D8
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/cser.dun.2 /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f8
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,serial_cdev_mdm,dpl,rmnet && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_diag_mdm,qdss_qdss_mdm_dun_dun_mdm_dpl_rmnet"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90DD
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/cser.dun.2 /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f8
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,serial_cdev_mdm,dpl,rmnet,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,serial_cdev_mdm,dpl,rmnet,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_diag_mdm,qdss_qdss_mdm_dun_dun_mdm_dpl_rmnet_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90DE
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/cser.dun.2 /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f8
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet,dpl,qdss && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_dun_rmnet_dpl_qdss"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90DC
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f5
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,rmnet,dpl,qdss,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,serial_cdev,rmnet,dpl,qdss,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_dun_rmnet_dpl_qdss_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90DB
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f6
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,uac2,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,uac2,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_uac2_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90CA
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/uac2.0 /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,uac2 && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_uac2"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x901C
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/uac2.0 /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,uvc,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,uvc,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_uvc_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90CB
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/uvc.0 /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,uvc && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_uvc"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90DF
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/uvc.0 /config/usb_gadget/g1/configs/b.1/f2
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,uac2,uvc,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,uac2,uvc,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_uac2_uvc_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90CC
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/uac2.0 /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/uvc.0 /config/usb_gadget/g1/configs/b.1/f4
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,uac2,uvc && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_uac2_uvc"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90E0
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/uac2.0 /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/uvc.0 /config/usb_gadget/g1/configs/b.1/f3
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,rmnet && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_diag_mdm_qdss_qdss_mdm_dun_dpl_rmnet"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90E4
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,rmnet,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,rmnet,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_diag_mdm_qdss_qdss_mdm_dun_dpl_rmnet_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90E5
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.rmnet.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f8
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag_diag_mdm_qdss_qdss_mdm_dun_dpl"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90E6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,adb && property:sys.usb.configfs=1
+    start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_diag_diag_mdm_qdss_qdss_mdm_dun_dpl_adb"
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rm /config/usb_gadget/g1/configs/b.1/f4
+    rm /config/usb_gadget/g1/configs/b.1/f5
+    rm /config/usb_gadget/g1/configs/b.1/f6
+    rm /config/usb_gadget/g1/configs/b.1/f7
+    rm /config/usb_gadget/g1/configs/b.1/f8
+    rm /config/usb_gadget/g1/configs/b.1/f9
+    write /config/usb_gadget/g1/idVendor 0x05C6
+    write /config/usb_gadget/g1/idProduct 0x90E7
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rndis.func.name}.rndis /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f2
+    symlink /config/usb_gadget/g1/functions/diag.diag_mdm /config/usb_gadget/g1/configs/b.1/f3
+    symlink /config/usb_gadget/g1/functions/qdss.qdss /config/usb_gadget/g1/configs/b.1/f4
+    symlink /config/usb_gadget/g1/functions/qdss.qdss_mdm /config/usb_gadget/g1/configs/b.1/f5
+    symlink /config/usb_gadget/g1/functions/cser.dun.0 /config/usb_gadget/g1/configs/b.1/f6
+    symlink /config/usb_gadget/g1/functions/${vendor.usb.rmnet.func.name}.${vendor.usb.dpl.inst.name} /config/usb_gadget/g1/configs/b.1/f7
+    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f8
+    write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4ee7
+
+on property:sys.usb.config=mtp && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4ee1
+
+on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4ee2
+
+on property:sys.usb.config=ptp && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4ee5
+
+on property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4ee6
+
+on property:sys.usb.config=accessory && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x2d00
+
+on property:sys.usb.config=accessory,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x2d01
+
+on property:sys.usb.config=audio_source && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x2d02
+
+on property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x2d03
+
+on property:sys.usb.config=accessory,audio_source && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x2d04
+
+on property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x2d05
+
+on property:sys.usb.config=midi && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4ee8
+
+on property:sys.usb.config=midi,adb && property:sys.usb.configfs=1
+    write /config/usb_gadget/g1/idVendor 0x18d1
+    write /config/usb_gadget/g1/idProduct 0x4ee9
+
+on property:vendor.usb.eud=1
+    write /config/usb_gadget/g1/configs/b.1/MaxPower 1
+    write /sys/module/eud/parameters/enable 1
+    write /sys/kernel/debug/pmic-votable/USB_ICL/force_active 1
+    write /sys/kernel/debug/pmic-votable/USB_ICL/force_val 500
+
+on property:vendor.usb.eud=0
+    write /sys/kernel/debug/pmic-votable/USB_ICL/force_active 0
+    write /sys/kernel/debug/pmic-votable/USB_ICL/force_val 0
+    write /config/usb_gadget/g1/configs/b.1/MaxPower 0
+    write /sys/module/eud/parameters/enable 0
diff --git a/init.power.rc b/init.power.rc
new file mode 100644
index 0000000..221805a
--- /dev/null
+++ b/init.power.rc
@@ -0,0 +1,114 @@
+#
+# 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.
+#
+
+on property:sys.boot_completed=1
+    # Enable bus-dcvs
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/governor bw_hwmon
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/polling_interval 40
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/mbps_zones "2288 4577 7110 9155 12298 14236 15258"
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/sample_ms 4
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/io_percent 50
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/hist_memory 20
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/hyst_length 10
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/down_thres 30
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/guard_band_mbps 0
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/up_scale 250
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/idle_mbps 1600
+    write /sys/devices/platform/soc/soc:qcom,cpu-cpu-llcc-bw/devfreq/soc:qcom,cpu-cpu-llcc-bw/max_freq 14236
+
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/governor bw_hwmon
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/polling_interval 40
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/mbps_zones "1720 2929 3879 5931 6881 7980"
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/sample_ms 4
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/io_percent 80
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/hist_memory 20
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/hyst_length 10
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/down_thres 30
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/guard_band_mbps 0
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/up_scale 250
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/idle_mbps 1600
+    write /sys/devices/platform/soc/soc:qcom,cpu-llcc-ddr-bw/devfreq/soc:qcom,cpu-llcc-ddr-bw/max_freq 6881
+
+    write /sys/devices/virtual/npu/msm_npu/pwr 1
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/governor bw_hwmon
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/polling_interval 40
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/mbps_zones "1720 2929 3879 5931 6881 7980"
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/sample_ms 4
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/io_percent 80
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/hist_memory 20
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/hyst_length 6
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/down_thres 30
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/guard_band_mbps 0
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/up_scale 250
+    write /sys/devices/platform/soc/soc:qcom,npu-npu-ddr-bw/devfreq/soc:qcom,npu-npu-ddr-bw/bw_hwmon/idle_mbps 0
+    write /sys/devices/virtual/npu/msm_npu/pwr 0
+
+    #Enable mem_latency governor for L3, LLCC, and DDR scaling
+    write /sys/devices/platform/soc/soc:qcom,cpu0-cpu-llcc-lat/devfreq/soc:qcom,cpu0-cpu-llcc-lat/governor mem_latency
+    write /sys/devices/platform/soc/soc:qcom,cpu0-cpu-llcc-lat/devfreq/soc:qcom,cpu0-cpu-llcc-lat/polling_interval 10
+    write /sys/devices/platform/soc/soc:qcom,cpu0-cpu-llcc-lat/devfreq/soc:qcom,cpu0-cpu-llcc-lat/mem_latency/ratio_ceil 400
+
+    write /sys/devices/platform/soc/soc:qcom,cpu0-cpu-l3-lat/devfreq/soc:qcom,cpu0-cpu-l3-lat/governor mem_latency
+    write /sys/devices/platform/soc/soc:qcom,cpu0-cpu-l3-lat/devfreq/soc:qcom,cpu0-cpu-l3-lat/polling_interval 10
+    write /sys/devices/platform/soc/soc:qcom,cpu0-cpu-l3-lat/devfreq/soc:qcom,cpu0-cpu-l3-lat/mem_latency/ratio_ceil 400
+
+    write /sys/devices/platform/soc/soc:qcom,cpu0-llcc-ddr-lat/devfreq/soc:qcom,cpu0-llcc-ddr-lat/governor mem_latency
+    write /sys/devices/platform/soc/soc:qcom,cpu0-llcc-ddr-lat/devfreq/soc:qcom,cpu0-llcc-ddr-lat/polling_interval 10
+    write /sys/devices/platform/soc/soc:qcom,cpu0-llcc-ddr-lat/devfreq/soc:qcom,cpu0-llcc-ddr-lat/mem_latency/ratio_ceil 400
+
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-llcc-lat/devfreq/soc:qcom,cpu4-cpu-llcc-lat/governor mem_latency
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-llcc-lat/devfreq/soc:qcom,cpu4-cpu-llcc-lat/polling_interval 10
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-llcc-lat/devfreq/soc:qcom,cpu4-cpu-llcc-lat/mem_latency/ratio_ceil 400
+
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-l3-lat/devfreq/soc:qcom,cpu4-cpu-l3-lat/governor mem_latency
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-l3-lat/devfreq/soc:qcom,cpu4-cpu-l3-lat/polling_interval 10
+    #Gold L3 ratio ceil is 4000
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-l3-lat/devfreq/soc:qcom,cpu4-cpu-l3-lat/mem_latency/ratio_ceil 4000
+
+    write /sys/devices/platform/soc/soc:qcom,cpu7-cpu-l3-lat/devfreq/soc:qcom,cpu7-cpu-l3-lat/governor mem_latency
+    write /sys/devices/platform/soc/soc:qcom,cpu7-cpu-l3-lat/devfreq/soc:qcom,cpu7-cpu-l3-lat/polling_interval 10
+    #Gold+ L3 ratio ceil is 20000
+    write /sys/devices/platform/soc/soc:qcom,cpu7-cpu-l3-lat/devfreq/soc:qcom,cpu7-cpu-l3-lat/mem_latency/ratio_ceil 20000
+
+    write /sys/devices/platform/soc/soc:qcom,cpu4-llcc-ddr-lat/devfreq/soc:qcom,cpu4-llcc-ddr-lat/governor mem_latency
+    write /sys/devices/platform/soc/soc:qcom,cpu4-llcc-ddr-lat/devfreq/soc:qcom,cpu4-llcc-ddr-lat/polling_interval 10
+    write /sys/devices/platform/soc/soc:qcom,cpu4-llcc-ddr-lat/devfreq/soc:qcom,cpu4-llcc-ddr-lat/mem_latency/ratio_ceil 400
+
+    #Enable userspace governor for L3 cdsp nodes
+    write /sys/devices/platform/soc/soc:qcom,cdsp-cdsp-l3-lat/devfreq/soc:qcom,cdsp-cdsp-l3-lat/governor cdspl3
+
+    #Enable compute governor for gold latfloor
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-ddr-latfloor/devfreq/soc:qcom,cpu4-cpu-ddr-latfloor/governor compute
+    write /sys/devices/platform/soc/soc:qcom,cpu4-cpu-ddr-latfloor/devfreq/soc:qcom,cpu4-cpu-ddr-latfloor/polling_interval 10
+
+    write /sys/module/lpm_levels/parameters/sleep_disabled 0
+
+    # Enable idle state listener
+    write /sys/class/drm/card0/device/idle_encoder_mask 1
+    write /sys/class/drm/card0/device/idle_timeout_ms 100
+
+    chown system system /sys/class/devfreq/soc:qcom,l3-cdsp/userspace/set_freq
+
+    #Enable PowerHAL hint processing
+    setprop vendor.powerhal.init 1
+
+# Disable console_suspend to get better logging for kernel crashes
+on boot
+    write /sys/module/printk/parameters/console_suspend N
+
+# If UART is on, enable console_suspend on boot_complete to save power
+on property:sys.boot_completed=1 && property:init.svc.console=running
+    write /sys/module/printk/parameters/console_suspend Y
diff --git a/init.qcom.modem_links.sh b/init.qcom.modem_links.sh
new file mode 100644
index 0000000..8aba652
--- /dev/null
+++ b/init.qcom.modem_links.sh
@@ -0,0 +1,132 @@
+#!/system/bin/sh
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+
+# No path is set up at this point so we have to do it here.
+PATH=/sbin:/system/sbin:/system/bin:/system/xbin
+export PATH
+
+# Check for images and set up symlinks
+cd /firmware/image
+
+# Get the list of files in /firmware/image
+# for which sym links have to be created
+
+fwfiles=`ls modem* adsp* wcnss* mba*`
+
+# Check if the links with similar names
+# have been created in /system/etc/firmware
+
+cd /system/etc/firmware
+linksNeeded=0
+
+# For everyfile in fwfiles check if
+# the corresponding file exists
+for fwfile in $fwfiles; do
+
+   # if (condition) does not seem to work
+   # with the android shell. Therefore
+   # make do with case statements instead.
+   # if a file named $fwfile is present
+   # no need to create links. If the file
+   # with the name $fwfile is not present
+   # need to create links.
+
+   case `ls $fwfile` in
+      $fwfile)
+         continue;;
+      *)
+         # file with $fwfile does not exist
+         # need to create links
+         linksNeeded=1
+         break;;
+   esac
+
+done
+
+# symlinks created for qca6714 firmware
+ln -s /firmware/image/athwlan.bin /system/etc/firmware/athwlan.bin
+ln -s /firmware/image/fakeboar.bin /system/etc/firmware/fakeBoardData_AR6004.bin
+ln -s /firmware/image/otp.bin /system/etc/firmware/otp.bin
+ln -s /firmware/image/utf.bin /system/etc/firmware/utf.bin
+
+case $linksNeeded in
+   1)
+      cd /firmware/image
+
+      case `ls modem.mdt 2>/dev/null` in
+         modem.mdt)
+            for imgfile in modem*; do
+               ln -s /firmware/image/$imgfile /system/etc/firmware/$imgfile 2>/dev/null
+            done
+            ;;
+        *)
+            # trying to log here but nothing will be logged since it is
+            # early in the boot process. Is there a way to log this message?
+            log -p w -t PIL no modem image found;;
+      esac
+
+      case `ls adsp.mdt 2>/dev/null` in
+         adsp.mdt)
+            for imgfile in adsp*; do
+               ln -s /firmware/image/$imgfile /system/etc/firmware/$imgfile 2>/dev/null
+            done
+            ;;
+         *)
+            log -p w -t PIL no adsp image found;;
+      esac
+
+      case `ls wcnss.mdt 2>/dev/null` in
+         wcnss.mdt)
+            for imgfile in wcnss*; do
+               ln -s /firmware/image/$imgfile /system/etc/firmware/$imgfile 2>/dev/null
+            done
+            ;;
+         *)
+            log -p w -t PIL no wcnss image found;;
+      esac
+
+      case `ls mba.mdt 2>/dev/null` in
+         mba.mdt)
+            for imgfile in mba*; do
+               ln -s /firmware/image/$imgfile /system/etc/firmware/$imgfile 2>/dev/null
+            done
+            ;;
+         *)
+            log -p w -t PIL no mba image found;;
+      esac
+
+      ;;
+
+   *)
+      # Nothing to do. No links needed
+      ;;
+esac
+
+cd /
diff --git a/init.qcom.usb.rc b/init.qcom.usb.rc
new file mode 100644
index 0000000..bebc807
--- /dev/null
+++ b/init.qcom.usb.rc
@@ -0,0 +1,1665 @@
+# Copyright (c) 2011-2016, 2018 The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of The Linux Foundation nor
+#       the names of its contributors may be used to endorse or promote
+#       products derived from this software without specific prior written
+#       permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# controller name can be overridden from boot command line
+on init 
+    setprop sys.usb.controller ${ro.boot.usbcontroller}
+   
+on property:ro.boot.usbcontroller=* 
+    setprop sys.usb.controller ${ro.boot.usbcontroller}
+
+on charger
+    mkdir /dev/usb-ffs 0770 shell shell
+    mkdir /dev/usb-ffs/adb 0770 shell shell
+    mount configfs none /config
+    mkdir /config/usb_gadget/g1 0770 shell shell
+    mkdir /config/usb_gadget/g1/strings/0x409 0770 shell shell
+    write /config/usb_gadget/g1/bcdUSB 0x0200
+    write /config/usb_gadget/g1/os_desc/use 1
+    write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
+    write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
+    write /config/usb_gadget/g1/strings/0x409/product ${ro.product.model}
+    mkdir /config/usb_gadget/g1/functions/mass_storage.0
+    mkdir /config/usb_gadget/g1/functions/ffs.adb
+    mkdir /config/usb_gadget/g1/configs/b.1 0770 shell shell
+    mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770 shell shell
+    write /config/usb_gadget/g1/os_desc/b_vendor_code 0x1
+    symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1
+    mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
+    write /sys/class/android_usb/android0/f_ffs/aliases adb
+    enable vendor.qcom-usb-sh
+    start vendor.qcom-usb-sh
+    setprop sys.usb.config mass_storage
+
+on boot
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    mkdir /dev/usb-ffs 0770 shell shell
+    mkdir /dev/usb-ffs/adb 0770 shell shell
+    mount configfs none /config
+    mkdir /config/usb_gadget/g1 0770 shell shell
+    mkdir /config/usb_gadget/g1/strings/0x409 0770 shell shell
+    write /config/usb_gadget/g1/bcdUSB 0x0200
+    write /config/usb_gadget/g1/os_desc/use 1
+    write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
+    write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
+    write /config/usb_gadget/g1/strings/0x409/product ${ro.product.model}
+    mkdir /config/usb_gadget/g1/functions/mass_storage.0
+    mkdir /config/usb_gadget/g1/functions/mtp.gs0
+    mkdir /config/usb_gadget/g1/functions/ptp.gs1
+    mkdir /config/usb_gadget/g1/functions/accessory.gs2
+    mkdir /config/usb_gadget/g1/functions/audio_source.gs3
+    mkdir /config/usb_gadget/g1/functions/midi.gs5
+    mkdir /config/usb_gadget/g1/functions/ffs.adb
+    mkdir /config/usb_gadget/g1/functions/diag.diag
+    mkdir /config/usb_gadget/g1/functions/diag.diag_mdm
+    mkdir /config/usb_gadget/g1/functions/cser.dun.0
+    mkdir /config/usb_gadget/g1/functions/cser.nmea.1
+    mkdir /config/usb_gadget/g1/functions/cser.dun.2
+    mkdir /config/usb_gadget/g1/functions/gsi.rmnet
+    mkdir /config/usb_gadget/g1/functions/gsi.rndis
+    mkdir /config/usb_gadget/g1/functions/gsi.dpl
+    mkdir /config/usb_gadget/g1/functions/qdss.qdss
+    mkdir /config/usb_gadget/g1/functions/qdss.qdss_mdm
+    mkdir /config/usb_gadget/g1/functions/rndis_bam.rndis
+    mkdir /config/usb_gadget/g1/functions/rndis.rndis
+    mkdir /config/usb_gadget/g1/functions/rmnet_bam.rmnet
+    mkdir /config/usb_gadget/g1/functions/rmnet_bam.dpl
+    mkdir /config/usb_gadget/g1/functions/rmnet_bam.rmnet_bam_dmux
+    mkdir /config/usb_gadget/g1/functions/rmnet_bam.dpl_bam_dmux
+    mkdir /config/usb_gadget/g1/functions/ncm.0
+    mkdir /config/usb_gadget/g1/functions/ccid.ccid
+    mkdir /config/usb_gadget/g1/functions/uac2.0
+    mkdir /config/usb_gadget/g1/functions/uvc.0
+    mkdir /config/usb_gadget/g1/configs/b.1 0770 shell shell
+    mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770 shell shell
+    write /config/usb_gadget/g1/os_desc/b_vendor_code 0x1
+    write /config/usb_gadget/g1/os_desc/qw_sign "MSFT100"
+    symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1
+    mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
+    write /sys/class/android_usb/android0/f_ffs/aliases adb
+
+on load_persist_props_action
+    enable vendor.qcom-usb-sh
+
+service vendor.qcom-usb-sh /vendor/bin/init.qcom.usb.sh
+    class core
+    user root
+    oneshot
+    disabled
+
+on property:persist.vendor.usb.config=*
+    setprop persist.sys.usb.config ${persist.vendor.usb.config}
+
+on boot && property:ro.boot.usbconfigfs=true
+        setprop sys.usb.configfs 1
+
+# Following are the parameters required for usb functionality. They provide configurable options like
+# product_id/vendor id and allows specifying required functions:
+#
+# Required parameters:
+#
+# /sys/class/android_usb/android0/enable: Enables/disables usb composition
+# Value: 0 (disable), 1 (enable)
+#
+# /sys/class/android_usb/android0/idVendor: Stores Vendor ID
+# Value: 05c6 (Vendor id for Qualcomm Inc)
+#
+# /sys/class/android_usb/android0/idProduct: Stores Product id corresponding to usb composition
+# Value: 0x9xxx for composite interface, 0xFxxx for single interface
+#
+# /sys/class/android_usb/android0/f_diag/clients: Stores name of clients representing a diag interface.
+# Value: Passed one per interface. e.g. diag[,diag_mdm, diag_qsc, diag_mdm2]
+#
+# /sys/class/android_usb/android0/functions: Stores name of the function drivers used in usb composition.
+# Value: Passed one per function driver. e.g. diag[,adb]
+#
+#Optional parameters:
+#
+# /sys/class/android_usb/android0/f_serial/transports: Stores type of underlying transports used to
+# communicate to serial interface.
+# Value: Passed one per interface. One value represents control and data transport together.
+# e.g. smd[,sdio,tty,hsic]
+# Only required if serial interface is present.
+#
+# /sys/class/android_usb/android0/f_serial/transport_names: Stores name of the underlying transports
+# used to communicate to serial interface. This is used to distinguish between more than one interface
+# using same transport type.
+# Value: Passed one per interface. One value represents control and data transport together.
+# e.g. serial_hsic[,serial_hsusb]
+# Only required for transport type hsic, optional for other transport types.
+#
+# /sys/class/android_usb/android0/f_rmnet/transports: Stores type of underlying transports used to
+# communicate to rmnet interface.
+# Value: Passed two per interface as control, data transport type pair.
+# e.g. smd,bam[,hsuart,hsuart]
+# Only required if rmnet interface is present.
+#
+# /sys/class/android_usb/android0/f_rmnet/transport_names: Stores name of the underlying transports
+# used to communicate to rmnet interface. This is used to distinguish between more than one interface
+# using same transport type.
+# Value: Passed one per interface. One value represents control and data transport together.
+# e.g. rmnet_hsic[,rmnet_hsusb]
+# Only required for transport type hsic, optional for other transport types.
+
+# USB compositions
+on property:sys.usb.config=diag,serial_tty,serial_smd && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9002
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports tty,smd
+    write /sys/class/android_usb/android0/functions diag,serial
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_tty,serial_smd,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9020
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/functions diag,adb,serial
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 901D
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 900E
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_bam,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9091
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_qti_bam,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9091
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_bam && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9092
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_qti_bam && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9092
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,serial_tty,rmnet_ipa,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9025
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,serial_tty,rmnet_ipa,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9026
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_bam,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9025
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,acm_smd,acm_tty,rmnet_bam,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903D
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_acm/acm_transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,adb,acm,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_bam,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9026
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,acm_smd,acm_tty,rmnet_bam,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903E
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_acm/acm_transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,serial_sdio,serial_smd,rmnet_smd_sdio,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9037
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports sdio,smd
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet_smd_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,acm_sdio,acm_smd,rmnet_smd_sdio,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903B
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_acm/acm_transports sdio,smd
+    write /sys/class/android_usb/android0/functions diag,adb,acm,rmnet_smd_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,serial_sdio,serial_smd,rmnet_smd_sdio,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9038
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports sdio,smd
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet_smd_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,acm_sdio,acm_smd,rmnet_smd_sdio,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903C
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_acm/acm_transports sdio,smd
+    write /sys/class/android_usb/android0/functions diag,acm,rmnet_smd_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,serial_sdio,serial_tty,rmnet_sdio,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9031
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports sdio,tty
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,acm_sdio,acm_tty,rmnet_sdio,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903B
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_acm/acm_transports sdio,tty
+    write /sys/class/android_usb/android0/functions diag,adb,acm,rmnet_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,serial_sdio,serial_tty,rmnet_sdio,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9032
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports sdio,tty
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,acm_sdio,acm_tty,rmnet_sdio,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903C
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_acm/acm_transports sdio,tty
+    write /sys/class/android_usb/android0/functions diag,acm,rmnet_sdio,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_tty,serial_tty,rmnet_smd,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9025
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports tty,tty
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    start vendor.port-bridge
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,acm_tty,acm_tty,rmnet_smd,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903D
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_acm/acm_transports tty,tty
+    write /sys/class/android_usb/android0/functions diag,adb,acm,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    start vendor.port-bridge
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_tty,serial_tty,rmnet_smd,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9026
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports tty,tty
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start vendor.port-bridge
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,acm_tty,acm_tty,rmnet_smd,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903E
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_acm/acm_transports tty,tty
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_smd,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9025
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,acm_smd,acm_tty,rmnet_smd,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903D
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_acm/acm_transports smd,tty
+    write /sys/class/android_usb/android0/functions diag,adb,acm,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    start vendor.port-bridge
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_smd,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9026
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,acm_smd,acm_tty,rmnet_smd,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903E
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_acm/acm_transports smd,tty
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet_smd,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+# RmNet using USB BAM to IPA BAM
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_ipa,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9025
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_ipa,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9026
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_ipa,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9091
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_ipa && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9092
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 3 composition
+on property:sys.usb.config=diag,serial_hsic,serial_tty,rmnet_hsic,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9025
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports hsic,tty
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_rmnet/transport_names rmnet_hsic
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/module/mdm_bridge/parameters/rx_rmnet_buffer_size 16384
+    write /sys/module/mdm_bridge/parameters/max_rx_urbs 20
+    write /sys/module/g_android/parameters/ghsic_data_rx_req_size 16384
+    write /sys/module/g_android/parameters/ghsic_data_rmnet_rx_q_size 20
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 3 composition with diag_mdm and adb
+on property:sys.usb.config=diag,diag_mdm,serial_hsic,serial_tty,rmnet_hsic,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9031
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports hsic,tty
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_rmnet/transport_names rmnet_hsic
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/module/mdm_bridge/parameters/rx_rmnet_buffer_size 16384
+    write /sys/module/mdm_bridge/parameters/max_rx_urbs 20
+    write /sys/module/g_android/parameters/ghsic_data_rx_req_size 16384
+    write /sys/module/g_android/parameters/ghsic_data_rmnet_rx_q_size 20
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 3 composition with diag_mdm
+on property:sys.usb.config=diag,diag_mdm,serial_hsic,serial_tty,rmnet_hsic,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9032
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports hsic,tty
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_rmnet/transport_names rmnet_hsic
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/module/mdm_bridge/parameters/rx_rmnet_buffer_size 16384
+    write /sys/module/mdm_bridge/parameters/max_rx_urbs 20
+    write /sys/module/g_android/parameters/ghsic_data_rx_req_size 16384
+    write /sys/module/g_android/parameters/ghsic_data_rmnet_rx_q_size 20
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 3 DSDA composition with adb
+on property:sys.usb.config=diag,diag_mdm,diag_qsc,serial_hsic,serial_hsuart,rmnet_hsic,rmnet_hsuart,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9065
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_qsc
+    write /sys/class/android_usb/android0/f_serial/transports hsic,hsuart
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic,serial_hsuart
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic,hsuart,hsuart
+    write /sys/class/android_usb/android0/f_rmnet/transport_names rmnet_hsic,rmnet_hsuart
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/module/mdm_bridge/parameters/rx_rmnet_buffer_size 16384
+    write /sys/module/mdm_bridge/parameters/max_rx_urbs 20
+    write /sys/module/g_android/parameters/ghsic_data_rx_req_size 16384
+    write /sys/module/g_android/parameters/ghsic_data_rmnet_rx_q_size 20
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 3 DSDA composition without adb
+on property:sys.usb.config=diag,diag_mdm,diag_qsc,serial_hsic,serial_hsuart,rmnet_hsic,rmnet_hsuart,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9066
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_qsc
+    write /sys/class/android_usb/android0/f_serial/transports hsic,hsuart
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic,serial_hsuart
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic,hsuart,hsuart
+    write /sys/class/android_usb/android0/f_rmnet/transport_names rmnet_hsic,rmnet_hsuart
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/module/mdm_bridge/parameters/rx_rmnet_buffer_size 16384
+    write /sys/module/mdm_bridge/parameters/max_rx_urbs 20
+    write /sys/module/g_android/parameters/ghsic_data_rx_req_size 16384
+    write /sys/module/g_android/parameters/ghsic_data_rmnet_rx_q_size 20
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 3 DSDA2 composition with adb
+on property:sys.usb.config=diag,diag_mdm,diag_mdm2,serial_hsic,serial_hsusb,rmnet_hsic,rmnet_hsusb,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9065
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_mdm2
+    write /sys/class/android_usb/android0/f_serial/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic,serial_hsusb
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic,hsic,hsic
+    write /sys/class/android_usb/android0/f_rmnet/transport_names rmnet_hsic,rmnet_hsusb
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/module/mdm_bridge/parameters/rx_rmnet_buffer_size 16384
+    write /sys/module/mdm_bridge/parameters/max_rx_urbs 20
+    write /sys/module/g_android/parameters/ghsic_data_rx_req_size 16384
+    write /sys/module/g_android/parameters/ghsic_data_rmnet_rx_q_size 20
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 3 DSDA2 composition without adb
+on property:sys.usb.config=diag,diag_mdm,diag_mdm2,serial_hsic,serial_hsusb,rmnet_hsic,rmnet_hsusb,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9066
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_mdm2
+    write /sys/class/android_usb/android0/f_serial/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic,serial_hsusb
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic,hsic,hsic
+    write /sys/class/android_usb/android0/f_rmnet/transport_names rmnet_hsic,rmnet_hsusb
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/module/mdm_bridge/parameters/rx_rmnet_buffer_size 16384
+    write /sys/module/mdm_bridge/parameters/max_rx_urbs 20
+    write /sys/module/g_android/parameters/ghsic_data_rx_req_size 16384
+    write /sys/module/g_android/parameters/ghsic_data_rmnet_rx_q_size 20
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion PCIe composition with diag_mdm and adb
+# Serial & RmNet bridged in userspace with tty and qti/ether
+on property:sys.usb.config=diag,diag_mdm,serial_tty,rmnet_qti_ether,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9035
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion PCIe composition with diag_mdm
+# Serial & RmNet bridged in userspace with tty and qti/ether
+on property:sys.usb.config=diag,diag_mdm,serial_hsic,rmnet_hsic,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9036
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion HSIC/PCIe Hybrid composition with diag_mdm and adb
+# RmNet is bridged over PCIe using qti,ether ctrl/data transports
+on property:sys.usb.config=diag,diag_mdm,serial_hsic,rmnet_qti_ether,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9035
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports hsic
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion HSIC/PCIe Hybrid composition with diag_mdm
+# RmNet is bridged over PCIe using qti,ether ctrl/data transports
+on property:sys.usb.config=diag,diag_mdm,serial_hsic,rmnet_hsic,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9036
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports hsic
+    write /sys/class/android_usb/android0/f_serial/transport_names serial_hsic
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion PCIe composition with diag_mdm
+# Serial & RmNet bridged in userspace with port bridge and qti/ether
+on property:sys.usb.config=diag,diag_mdm,serial_cdev,rmnet_qti_ether,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9036
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,serial_cdev,rmnet_qti_ether,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9035
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 2.2 composition with diag_qsc and adb
+on property:sys.usb.config=diag,diag_qsc,serial_smd,serial_tty,serial_hsuart,rmnet_hsuart,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9053
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_qsc
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty,hsuart
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam,hsuart,hsuart
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# Fusion 2.2 composition with diag_qsc
+on property:sys.usb.config=diag,diag_qsc,serial_smd,serial_tty,serial_hsuart,rmnet_hsuart,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9054
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_qsc
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty,hsuart
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam,hsuart,hsuart
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:vendor.usb.tethering=true
+    write /sys/class/net/rndis0/queues/rx-0/rps_cpus ${vendor.usb.rps_mask}
+
+on property:sys.usb.config=rndis
+    setprop sys.usb.config rndis,${persist.vendor.usb.config.extra}
+
+on property:sys.usb.config=rndis,none && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct F00E
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/functions rndis
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,adb && property:sys.usb.configfs=0
+    setprop sys.usb.config rndis,${persist.vendor.usb.config.extra},adb
+
+on property:sys.usb.config=rndis,none,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9024
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/functions rndis,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,diag && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 902C
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions rndis,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,diag,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 902D
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions rndis,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+# DPL is implemented using QDSS
+on property:sys.usb.config=rndis,diag,dpl && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90BF
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions rndis,diag,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+# DPL is implemented using QDSS
+on property:sys.usb.config=rndis,diag,dpl,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90C0
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions rndis,diag,qdss,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,serial_smd && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B3
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/functions rndis,serial
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,serial_smd,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B4
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/functions rndis,serial,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,serial_smd,diag && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B5
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/functions rndis,serial,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,serial_smd,diag,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B6
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/functions rndis,serial,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,serial_cdev,diag && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B5
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge
+    write /sys/class/android_usb/android0/functions rndis,serial,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,serial_cdev,diag,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B6
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge
+    write /sys/class/android_usb/android0/functions rndis,serial,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,diag,diag_mdm && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9041
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/functions rndis,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,diag,diag_mdm,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9042
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/functions rndis,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=rndis,diag,diag_mdm,diag_qsc && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9086
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_qsc
+    write /sys/class/android_usb/android0/functions rndis,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state rndis
+
+on property:sys.usb.config=rndis,diag,diag_mdm,diag_qsc,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9087
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_qsc
+    write /sys/class/android_usb/android0/functions rndis,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state rndis,adb
+
+on property:sys.usb.config=ptp && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 904D
+    write /sys/class/android_usb/android0/functions ptp
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ptp,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 904E
+    write /sys/class/android_usb/android0/functions ptp,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct F003
+    write /sys/class/android_usb/android0/functions mtp
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9039
+    write /sys/class/android_usb/android0/functions mtp,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,diag && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 901B
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions mtp,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,diag,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903A
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions mtp,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,diag,diag_mdm && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9040
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/functions mtp,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,diag,diag_mdm,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 903F
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/functions mtp,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,diag,diag_mdm,diag_qsc && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9088
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_qsc
+    write /sys/class/android_usb/android0/functions mtp,diag
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,diag,diag_mdm,diag_qsc,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9089
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm,diag_qsc
+    write /sys/class/android_usb/android0/functions mtp,diag,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,ccid && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9045
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/functions diag,ccid
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,ccid,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9044
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/functions diag,adb,ccid
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9015
+    write /sys/class/android_usb/android0/functions adb,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+#Mass-storage only composition
+on property:sys.usb.config=mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct F000
+    write /sys/class/android_usb/android0/functions mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 904A
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9060
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9099
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9098
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet_bam && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9083
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet_qti_bam && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9083
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet_bam,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9084
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,adb,rmnet
+    write /sys/module/dwc3/parameters/tx_fifo_resize_enable 1
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet_qti_bam,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9084
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,adb,rmnet
+    write /sys/module/dwc3/parameters/tx_fifo_resize_enable 1
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet_ipa && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9083
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,qdss,rmnet_ipa,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9084
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,adb,rmnet
+    write /sys/module/dwc3/parameters/tx_fifo_resize_enable 1
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,rmnet_hsic && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 909B
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss,rmnet_hsic,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 909A
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions diag,qdss,adb,rmnet
+    write /sys/module/dwc3/parameters/tx_fifo_resize_enable 1
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss_apq,qdss_mdm,rmnet_hsic && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90A3
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports bam,hsic
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam,qdss_hsic
+    write /sys/class/android_usb/android0/functions diag,qdss,rmnet
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,qdss_apq,qdss_mdm,rmnet_hsic,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90A2
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_rmnet/transports hsic,hsic
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports bam,hsic
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam,qdss_hsic
+    write /sys/class/android_usb/android0/functions diag,qdss,adb,rmnet
+    write /sys/module/dwc3/parameters/tx_fifo_resize_enable 1
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=rndis,diag,qdss && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9081
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions rndis,diag,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=rndis,diag,qdss,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 9082
+    write /sys/class/android_usb/android0/f_rndis/wceis 1
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 1
+    write /sys/class/android_usb/android0/f_qdss/transports bam
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/functions rndis,diag,qdss,adb
+    write /sys/module/dwc3/parameters/tx_fifo_resize_enable 1
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# same as 9025, plus data packet logging (DPL) using QDSS
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_ipa,mass_storage,dpl,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90AD
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+# DPL is implemented using QDSS
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage,qdss
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+# same as 9026, plus data packet logging (DPL)
+on property:sys.usb.config=diag,serial_smd,serial_tty,rmnet_ipa,mass_storage,dpl && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B0
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+# DPL is implemented using QDSS
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,serial_tty,rmnet_ipa,mass_storage,dpl,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90AD
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge,tty
+# DPL is implemented using QDSS
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,mass_storage,qdss
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_cdev,serial_tty,rmnet_ipa,mass_storage,dpl && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B0
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports char_bridge,tty
+# DPL is implemented using QDSS
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,mass_storage,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ncm && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 0525
+    write /sys/class/android_usb/android0/idProduct A4A1
+    write /sys/class/android_usb/android0/functions ncm
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ncm,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 908C
+    write /sys/class/android_usb/android0/functions ncm,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=charging && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct F006
+    write /sys/class/android_usb/android0/functions charging
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_qti_bam,dpl_qti_bam_dmux && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B7
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam_dmux
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_qti_bam,dpl_qti_bam_dmux,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B8
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam_dmux
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,qdss,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_cnss,serial_smd,serial_tty,rmnet_bam,mass_storage,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B2
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_cnss
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,diag_cnss,adb,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_cnss,serial_smd,serial_tty,rmnet_bam,mass_storage && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B3
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_cnss
+    write /sys/class/android_usb/android0/f_serial/transports smd,tty
+    write /sys/class/android_usb/android0/f_rmnet/transports smd,bam
+    write /sys/class/android_usb/android0/functions diag,diag_cnss,serial,rmnet,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=midi && property:sys.usb.configfs=0
+     write /sys/class/android_usb/android0/enable 0
+     write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+     write /sys/class/android_usb/android0/idVendor 05C6
+     write /sys/class/android_usb/android0/idProduct 90BA
+     write /sys/class/android_usb/android0/functions midi
+     write /sys/class/android_usb/android0/enable 1
+     setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=midi,adb && property:sys.usb.configfs=0
+     write /sys/class/android_usb/android0/enable 0
+     write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+     write /sys/class/android_usb/android0/idVendor 05C6
+     write /sys/class/android_usb/android0/idProduct 90BB
+     write /sys/class/android_usb/android0/functions midi,adb
+     write /sys/class/android_usb/android0/enable 1
+     start adbd
+     setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_ipa,dpl && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B7
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+# DPL is implemented using QDSS
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,qdss
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,serial_smd,rmnet_ipa,dpl,adb && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90B8
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/f_serial/transports smd
+# DPL is implemented using QDSS
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_bam
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,bam2bam_ipa
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,qdss,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,serial_tty,rmnet_qti_ether,dpl_ether,mass_storage,adb
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90AE
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,ether
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_dpl
+    write /sys/class/android_usb/android0/functions diag,adb,serial,rmnet,qdss,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,diag_mdm,serial_tty,rmnet_qti_ether,dpl_ether,mass_storage
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90AF
+    write /sys/class/android_usb/android0/f_diag/clients diag,diag_mdm
+    write /sys/class/android_usb/android0/f_serial/transports tty
+    write /sys/class/android_usb/android0/f_rmnet/transports qti,ether
+    write /sys/class/android_usb/android0/f_qdss/debug_intf 0
+    write /sys/class/android_usb/android0/f_qdss/transports qti,ether
+    write /sys/class/android_usb/android0/f_qdss/transport_names qdss_dpl
+    write /sys/class/android_usb/android0/functions diag,serial,rmnet,qdss,mass_storage
+    write /sys/class/android_usb/android0/enable 1
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,adb,uac2
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90CA
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions diag,adb,uac2_func
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,adb,video && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90CB
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions diag,adb,video
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=diag,adb,uac2,video && property:sys.usb.configfs=0
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/idVendor 05C6
+    write /sys/class/android_usb/android0/idProduct 90CC
+    write /sys/class/android_usb/android0/f_diag/clients diag
+    write /sys/class/android_usb/android0/functions diag,adb,uac2_func,video
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+    setprop sys.usb.state ${sys.usb.config}
+
diff --git a/init.qcom.usb.sh b/init.qcom.usb.sh
new file mode 100644
index 0000000..081a125
--- /dev/null
+++ b/init.qcom.usb.sh
@@ -0,0 +1,245 @@
+#!/vendor/bin/sh
+# Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#      from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+
+# Set platform variables
+if [ -f /sys/devices/soc0/hw_platform ]; then
+    soc_hwplatform=`cat /sys/devices/soc0/hw_platform` 2> /dev/null
+else
+    soc_hwplatform=`cat /sys/devices/system/soc/soc0/hw_platform` 2> /dev/null
+fi
+
+if [ -f /sys/devices/soc0/machine ]; then
+    soc_machine=`cat /sys/devices/soc0/machine` 2> /dev/null
+else
+    soc_machine=`cat /sys/devices/system/soc/soc0/machine` 2> /dev/null
+fi
+
+#
+# Check ESOC for external MDM
+#
+# Note: currently only a single MDM is supported
+#
+if [ -d /sys/bus/esoc/devices ]; then
+for f in /sys/bus/esoc/devices/*; do
+    if [ -d $f ]; then
+    if [ `grep -e "^MDM" -e "^SDX" $f/esoc_name` ]; then
+            esoc_link=`cat $f/esoc_link`
+            break
+        fi
+    fi
+done
+fi
+
+target=`getprop ro.board.platform`
+
+# soc_ids for 8937
+if [ -f /sys/devices/soc0/soc_id ]; then
+	soc_id=`cat /sys/devices/soc0/soc_id`
+else
+	soc_id=`cat /sys/devices/system/soc/soc0/id`
+fi
+
+#
+# Allow USB enumeration with default PID/VID
+#
+baseband=`getprop ro.baseband`
+
+echo 1  > /sys/class/android_usb/f_mass_storage/lun/nofua
+usb_config=`getprop persist.vendor.usb.config`
+if [ "$usb_config" == "" ]; then #USB persist config not set, select default configuration
+      if [ "$esoc_link" != "" ]; then
+	  setprop persist.vendor.usb.config diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,rmnet,adb
+      else
+	  case "$baseband" in
+	      "apq")
+	          setprop persist.vendor.usb.config diag,adb
+	      ;;
+	      *)
+	      case "$soc_hwplatform" in
+	          "Dragon" | "SBC")
+	              setprop persist.vendor.usb.config diag,adb
+	          ;;
+                  *)
+		  soc_machine=${soc_machine:0:3}
+		  case "$soc_machine" in
+		    "SDA")
+	              setprop persist.vendor.usb.config diag,adb
+		    ;;
+		    *)
+	            case "$target" in
+	              "msm8996")
+	                  setprop persist.vendor.usb.config diag,serial_cdev,serial_tty,rmnet_ipa,mass_storage,adb
+		      ;;
+	              "msm8909")
+		          setprop persist.vendor.usb.config diag,serial_smd,rmnet_qti_bam,adb
+		      ;;
+	              "msm8937")
+			    if [ -d /config/usb_gadget ]; then
+				       setprop persist.vendor.usb.config diag,serial_cdev,rmnet,dpl,adb
+			    else
+			               case "$soc_id" in
+				               "313" | "320")
+						  echo BAM2BAM_IPA > /sys/class/android_usb/android0/f_rndis_qc/rndis_transports
+				                  setprop persist.vendor.usb.config diag,serial_smd,rmnet_ipa,adb
+				               ;;
+				               *)
+				                  setprop persist.vendor.usb.config diag,serial_smd,rmnet_qti_bam,adb
+				               ;;
+			               esac
+			    fi
+		      ;;
+	              "msm8953")
+			      if [ -d /config/usb_gadget ]; then
+				      setprop persist.vendor.usb.config diag,serial_cdev,rmnet,dpl,adb
+			      else
+				      setprop persist.vendor.usb.config diag,serial_smd,rmnet_ipa,adb
+			      fi
+		      ;;
+	              "msm8998" | "sdm660" | "apq8098_latv")
+		          setprop persist.vendor.usb.config diag,serial_cdev,rmnet,adb
+		      ;;
+	              "sdm845" | "sdm710")
+		          setprop persist.vendor.usb.config diag,serial_cdev,rmnet,dpl,adb
+		      ;;
+	              #"lito")
+			#  setprop persist.vendor.usb.config diag,serial_cdev,rmnet,dpl,qdss,adb
+		      #;;
+	              *)
+		          setprop persist.vendor.usb.config diag,adb
+		      ;;
+                    esac
+		    ;;
+		  esac
+	          ;;
+	      esac
+	      ;;
+	  esac
+      fi
+fi
+
+# set device mode notification to USB driver for SA8150 Auto ADP
+product=`getprop ro.build.product`
+
+case "$product" in
+	"lito_au")
+	echo peripheral > /sys/bus/platform/devices/a600000.ssusb/mode
+         ;;
+	*)
+	;;
+esac
+
+# check configfs is mounted or not
+if [ -d /config/usb_gadget ]; then
+	# Chip-serial is used for unique MSM identification in Product string
+	msm_serial=`cat /sys/devices/soc0/serial_number`;
+	msm_serial_hex=`printf %08X $msm_serial`
+	machine_type=`cat /sys/devices/soc0/machine`
+	product_string="$machine_type-$soc_hwplatform _SN:$msm_serial_hex"
+	echo "$product_string" > /config/usb_gadget/g1/strings/0x409/product
+
+	# ADB requires valid iSerialNumber; if ro.serialno is missing, use dummy
+	serialnumber=`cat /config/usb_gadget/g1/strings/0x409/serialnumber` 2> /dev/null
+	if [ "$serialnumber" == "" ]; then
+		serialno=1234567
+		echo $serialno > /config/usb_gadget/g1/strings/0x409/serialnumber
+	fi
+fi
+
+#
+# Initialize RNDIS Diag option. If unset, set it to 'none'.
+#
+diag_extra=`getprop persist.vendor.usb.config.extra`
+if [ "$diag_extra" == "" ]; then
+	setprop persist.vendor.usb.config.extra none
+fi
+
+# enable rps cpus on msm8937 target
+setprop vendor.usb.rps_mask 0
+case "$soc_id" in
+	"294" | "295" | "353" | "354")
+		setprop vendor.usb.rps_mask 40
+	;;
+esac
+
+#
+# Initialize UVC conifguration.
+#
+if [ -d /config/usb_gadget/g1/functions/uvc.0 ]; then
+	cd /config/usb_gadget/g1/functions/uvc.0
+
+	echo 3072 > streaming_maxpacket
+	echo 1 > streaming_maxburst
+	mkdir control/header/h
+	ln -s control/header/h control/class/fs/
+	ln -s control/header/h control/class/ss
+
+	mkdir -p streaming/uncompressed/u/360p
+	echo "666666\n1000000\n5000000\n" > streaming/uncompressed/u/360p/dwFrameInterval
+
+	mkdir -p streaming/uncompressed/u/720p
+	echo 1280 > streaming/uncompressed/u/720p/wWidth
+	echo 720 > streaming/uncompressed/u/720p/wWidth
+	echo 29491200 > streaming/uncompressed/u/720p/dwMinBitRate
+	echo 29491200 > streaming/uncompressed/u/720p/dwMaxBitRate
+	echo 1843200 > streaming/uncompressed/u/720p/dwMaxVideoFrameBufferSize
+	echo 5000000 > streaming/uncompressed/u/720p/dwDefaultFrameInterval
+	echo "5000000\n" > streaming/uncompressed/u/720p/dwFrameInterval
+
+	mkdir -p streaming/mjpeg/m/360p
+	echo "666666\n1000000\n5000000\n" > streaming/mjpeg/m/360p/dwFrameInterval
+
+	mkdir -p streaming/mjpeg/m/720p
+	echo 1280 > streaming/mjpeg/m/720p/wWidth
+	echo 720 > streaming/mjpeg/m/720p/wWidth
+	echo 29491200 > streaming/mjpeg/m/720p/dwMinBitRate
+	echo 29491200 > streaming/mjpeg/m/720p/dwMaxBitRate
+	echo 1843200 > streaming/mjpeg/m/720p/dwMaxVideoFrameBufferSize
+	echo 5000000 > streaming/mjpeg/m/720p/dwDefaultFrameInterval
+	echo "5000000\n" > streaming/mjpeg/m/720p/dwFrameInterval
+
+	echo 0x04 > /config/usb_gadget/g1/functions/uvc.0/streaming/mjpeg/m/bmaControls
+
+	mkdir -p streaming/h264/h/960p
+	echo 1920 > streaming/h264/h/960p/wWidth
+	echo 960 > streaming/h264/h/960p/wWidth
+	echo 40 > streaming/h264/h/960p/bLevelIDC
+	echo "333667\n" > streaming/h264/h/960p/dwFrameInterval
+
+	mkdir -p streaming/h264/h/1920p
+	echo "333667\n" > streaming/h264/h/1920p/dwFrameInterval
+
+	mkdir streaming/header/h
+	ln -s streaming/uncompressed/u streaming/header/h
+	ln -s streaming/mjpeg/m streaming/header/h
+	ln -s streaming/h264/h streaming/header/h
+	ln -s streaming/header/h streaming/class/fs/
+	ln -s streaming/header/h streaming/class/hs/
+	ln -s streaming/header/h streaming/class/ss/
+fi
diff --git a/init.qcom.wlan.sh b/init.qcom.wlan.sh
new file mode 100644
index 0000000..92dd25b
--- /dev/null
+++ b/init.qcom.wlan.sh
@@ -0,0 +1,6 @@
+#! /vendor/bin/sh
+
+wlan_driver_version=`cat /sys/kernel/wlan/wlan/driver_version`
+setprop vendor.wlan.driver.version "${wlan_driver_version:0:91}"
+wlan_fw_version=`cat /sys/kernel/wlan/fw/1/version`
+setprop vendor.wlan.firmware.version "${wlan_fw_version:0:91}"
diff --git a/init.qti.getbootdevice.sh b/init.qti.getbootdevice.sh
new file mode 100644
index 0000000..fa6f740
--- /dev/null
+++ b/init.qti.getbootdevice.sh
@@ -0,0 +1,55 @@
+#!/vendor/bin/sh
+# Copyright (c) 2018, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+#Script to find if the boot device is SD card or UFS
+
+
+echo "Bootdevice setup:  Starting..." > /dev/kmsg
+
+bootdevice=`getprop ro.boot.bootdevice`
+
+if [ "$bootdevice" = "8804000.sdhci" ]; then
+	ln -s /dev/block/platform/soc/8804000.sdhci /dev/block/bootdevice
+	echo "Waiting for SDHCI device to show up..." > /dev/kmsg
+	while [ ! -e "/dev/block/platform/soc/8804000.sdhci" ]; do
+		sleep 1
+	done
+elif [ "$bootdevice" = "1d84000.ufshc" ]; then
+	ln -s /dev/block/platform/soc/1d84000.ufshc /dev/block/bootdevice
+	echo "Waiting for UFS device to show up..." > /dev/kmsg
+	while [ ! -e "/dev/block/platform/soc/1d84000.ufshc" ]; do
+		sleep 1;
+	done
+else
+	while true; do
+		echo "Boot failure - invalid bootdevice ($bootdevice)" > /dev/kmsg
+		sleep 30;
+	done
+fi
+echo "Bootdevice setup:  Completed ($bootdevice)" > /dev/kmsg
diff --git a/init.qti.qseecomd.sh b/init.qti.qseecomd.sh
new file mode 100644
index 0000000..eb2eec9
--- /dev/null
+++ b/init.qti.qseecomd.sh
@@ -0,0 +1,35 @@
+#!/vendor/bin/sh
+# Copyright (c) 2017, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of The Linux Foundation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+
+while [ "$registered" != "true" ]
+do
+    sleep 0.1
+    registered="`getprop vendor.sys.listeners.registered`"
+done
diff --git a/init.radio.sh b/init.radio.sh
new file mode 100644
index 0000000..df54a66
--- /dev/null
+++ b/init.radio.sh
@@ -0,0 +1,38 @@
+#! /vendor/bin/sh
+
+#
+# Copy qcril.db if needed for RIL
+#
+if [ -f /vendor/radio/qcril_database/qcril.db -a ! -f /data/vendor/radio/qcril.db ]; then
+    cp /vendor/radio/qcril_database/qcril.db /data/vendor/radio/qcril.db
+    chown -h radio.radio /data/vendor/radio/qcril.db
+fi
+echo 1 > /data/vendor/radio/db_check_done
+
+cp /vendor/radio/qcril_database/qcril.db /data/vendor/radio/qcril_prebuilt.db
+chown radio.radio /data/vendor/radio/qcril_prebuilt.db
+chmod 0660 /data/vendor/radio/qcril_prebuilt.db
+
+#
+# Make modem config folder and copy firmware config to that folder for RIL
+#
+if [ -f /data/vendor/radio/ver_info.txt ]; then
+    prev_version_info=`cat /data/vendor/radio/ver_info.txt`
+else
+    prev_version_info=""
+fi
+
+cur_version_info=`cat /vendor/firmware_mnt/verinfo/ver_info.txt`
+if [ ! -f /vendor/firmware_mnt/verinfo/ver_info.txt -o "$prev_version_info" != "$cur_version_info" ]; then
+    rm -rf /data/vendor/radio/modem_config
+    mkdir /data/vendor/radio/modem_config
+    chmod 770 /data/vendor/radio/modem_config
+    cp -r /vendor/firmware_mnt/image/modem_pr/mcfg/configs/* /data/vendor/radio/modem_config
+    chown -hR radio.radio /data/vendor/radio/modem_config
+    cp /vendor/firmware_mnt/verinfo/ver_info.txt /data/vendor/radio/ver_info.txt
+    chown radio.radio /data/vendor/radio/ver_info.txt
+fi
+cp /vendor/firmware_mnt/image/modem_pr/mbn_ota.txt /data/vendor/radio/modem_config
+chown radio.radio /data/vendor/radio/modem_config/mbn_ota.txt
+echo 1 > /data/vendor/radio/copy_complete
+
diff --git a/init.recovery.device.rc b/init.recovery.device.rc
new file mode 100644
index 0000000..092221a
--- /dev/null
+++ b/init.recovery.device.rc
@@ -0,0 +1,10 @@
+on fs
+    wait /dev/block/platform/soc/${ro.boot.bootdevice}
+    symlink /dev/block/platform/soc/${ro.boot.bootdevice} /dev/block/bootdevice
+
+on init
+    setprop sys.usb.configfs 1
+    # Don't lose recovery logs- keep warm reset for coming out of recovery.
+    write /sys/module/msm_poweroff/parameters/warm_reset 1
+    # Enable thermal mitigation
+    write /sys/devices/virtual/thermal/tz-by-name/backup-charge/mode enabled
diff --git a/init.sensors.sh b/init.sensors.sh
new file mode 100644
index 0000000..6325038
--- /dev/null
+++ b/init.sensors.sh
@@ -0,0 +1,6 @@
+#! /vendor/bin/sh
+
+version=`grep -ao "OEM_IMAGE_VERSION_STRING[ -~]*" \
+              /vendor/firmware/slpi.b04 | \
+         sed -e s/OEM_IMAGE_VERSION_STRING=SLPI.version.// -e s/\(.*\).//`
+setprop sys.slpi.firmware.version "$version"
diff --git a/json-c/AUTHORS b/json-c/AUTHORS
new file mode 100644
index 0000000..b389989
--- /dev/null
+++ b/json-c/AUTHORS
@@ -0,0 +1,5 @@
+Michael Clark <michael@metaparadigm.com>
+Jehiah Czebotar <jehiah@gmail.com>
+Eric Haszlakiewicz <hawicz+json-c@gmail.com>
+C. Watford (christopher.watford@gmail.com)
+
diff --git a/json-c/Android.configure.mk b/json-c/Android.configure.mk
new file mode 100644
index 0000000..a6265ad
--- /dev/null
+++ b/json-c/Android.configure.mk
@@ -0,0 +1,39 @@
+# This file is the top android makefile for all sub-modules.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+json_c_TOP := $(LOCAL_PATH)
+
+JSON_C_BUILT_SOURCES := Android.mk
+
+JSON_C_BUILT_SOURCES := $(patsubst %, $(abspath $(json_c_TOP))/%, $(JSON_C_BUILT_SOURCES))
+
+.PHONY: json-c-configure json-c-configure-real
+json-c-configure-real:
+	echo $(JSON_C_BUILT_SOURCES)
+	cd $(json_c_TOP) ; \
+	$(abspath $(json_c_TOP))/autogen.sh && \
+	CC="$(CONFIGURE_CC)" \
+	CFLAGS="$(CONFIGURE_CFLAGS)" \
+	LD=$(TARGET_LD) \
+	LDFLAGS="$(CONFIGURE_LDFLAGS)" \
+	CPP=$(CONFIGURE_CPP) \
+	CPPFLAGS="$(CONFIGURE_CPPFLAGS)" \
+	PKG_CONFIG_LIBDIR=$(CONFIGURE_PKG_CONFIG_LIBDIR) \
+	PKG_CONFIG_TOP_BUILD_DIR=/ \
+	ac_cv_func_malloc_0_nonnull=yes \
+	ac_cv_func_realloc_0_nonnull=yes \
+	$(abspath $(json_c_TOP))/$(CONFIGURE) --host=$(CONFIGURE_HOST) \
+	--prefix=/system \
+	&& \
+	for file in $(JSON_C_BUILT_SOURCES); do \
+		rm -f $$file && \
+		make -C $$(dirname $$file) $$(basename $$file) ; \
+	done
+
+json-c-configure: json-c-configure-real
+
+PA_CONFIGURE_TARGETS += json-c-configure
+
+-include $(json_c_TOP)/Android.mk
diff --git a/json-c/Android.mk b/json-c/Android.mk
new file mode 100644
index 0000000..139a10c
--- /dev/null
+++ b/json-c/Android.mk
@@ -0,0 +1,35 @@
+LIBJSON_ROOT := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libjson
+LOCAL_PATH := $(LIBJSON_ROOT)
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+LOCAL_COPY_HEADERS_TO := libjson/inc
+LOCAL_COPY_HEADERS := bits.h \
+		config.h \
+		debug.h \
+		linkhash.h \
+		arraylist.h \
+		json.h \
+		json_config.h \
+		json_inttypes.h \
+		json_util.h \
+		json_object.h \
+		json_tokener.h \
+		json_object_iterator.h \
+		json_c_version.h
+LOCAL_SRC_FILES := arraylist.c \
+		debug.c \
+		json_c_version.c \
+		json_object.c \
+		json_object_iterator.c \
+		json_tokener.c \
+		json_util.c \
+		libjson.c \
+		linkhash.c \
+		printbuf.c \
+		random_seed.c
+LOCAL_SHARED_LIBRARIES := libcutils libutils
+LOCAL_MODULE_TAG := optional
+LOCAL_VENDOR_MODULE := true
+include $(BUILD_SHARED_LIBRARY)
diff --git a/json-c/COPYING b/json-c/COPYING
new file mode 100644
index 0000000..740d125
--- /dev/null
+++ b/json-c/COPYING
@@ -0,0 +1,42 @@
+
+Copyright (c) 2009-2012 Eric Haszlakiewicz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is 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 Software.
+
+THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+----------------------------------------------------------------
+
+Copyright (c) 2004, 2005 Metaparadigm Pte Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is 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 Software.
+
+THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/json-c/ChangeLog b/json-c/ChangeLog
new file mode 100644
index 0000000..584ed1f
--- /dev/null
+++ b/json-c/ChangeLog
@@ -0,0 +1,218 @@
+
+NEXT.VERSION
+
+  ...nothing yet...
+
+0.12
+
+  * Address security issues:
+    * CVE-2013-6371: hash collision denial of service
+    * CVE-2013-6370: buffer overflow if size_t is larger than int
+
+  * Avoid potential overflow in json_object_get_double
+
+  * Eliminate the mc_abort() function and MC_ABORT macro.
+
+  * Make the json_tokener_errors array local.  It has been deprecated for
+     a while, and json_tokener_error_desc() should be used instead.
+
+  * change the floating point output format to %.17g so values with 
+     more than 6 digits show up in the output.
+
+  * Remove the old libjson.so name compatibility support.  The library is
+      only created as libjson-c.so now and headers are only installed 
+      into the ${prefix}/json-c directory.
+
+  * When supported by the linker, add the -Bsymbolic-functions flag.
+
+  * Various changes to fix the build on MSVC.
+
+  * Make strict mode more strict:
+    * number must not start with 0
+    * no single-quote strings
+    * no comments
+    * trailing char not allowed
+    * only allow lowercase literals
+
+  * Added a json_object_new_double_s() convenience function to allow
+    an exact string representation of a double to be specified when
+    creating the object and use it in json_tokener_parse_ex() so
+    a re-serialized object more exactly matches the input.
+
+  * Add support NaN and Infinity
+
+
+0.11
+
+  * IMPORTANT: the name of the library has changed to libjson-c.so and
+     the header files are now in include/json-c.
+     The pkgconfig name has also changed from json to json-c.
+     You should change your build to use appropriate -I and -l options.
+     A compatibility shim is in place so builds using the old name will
+     continue to work, but that will be removed in the next release.
+  * Maximum recursion depth is now a runtime option.
+     json_tokener_new() is provided for compatibility.
+     json_tokener_new_ex(depth)
+  * Include json_object_iterator.h in the installed headers.
+  * Add support for building on Android.
+  * Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid.
+  * Make it safe to delete keys while iterating with the json_object_object_foreach macro.
+  * Add a json_set_serializer() function to allow the string output of a json_object to be customized.
+  * Make float parsing locale independent.
+  * Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag.
+  * Enable -Werror when building.
+  * speed improvements to parsing 64-bit integers on systems with working sscanf
+  * Add a json_object_object_length function.
+  * Fix a bug (buffer overrun) when expanding arrays to more than 64 entries.
+
+0.10
+
+  * Add a json_object_to_json_string_ext() function to allow output to be
+     formatted in a more human readable form.
+  * Add json_object_object_get_ex(), a NULL-safe get object method, to be able
+     to distinguish between a key not present and the value being NULL.
+  * Add an alternative iterator implementation, see json_object_iterator.h
+  * Make json_object_iter public to enable external use of the
+     json_object_object_foreachC macro.
+  * Add a printbuf_memset() function to provide an effecient way to set and
+     append things like whitespace indentation.
+  * Adjust json_object_is_type and json_object_get_type so they return
+      json_type_null for NULL objects and handle NULL passed to
+      json_objct_object_get().
+  * Rename boolean type to json_bool.
+  * Fix various compile issues for Visual Studio and MinGW.
+  * Allow json_tokener_parse_ex() to be re-used to parse multiple object.
+     Also, fix some parsing issues with capitalized hexadecimal numbers and
+     number in E notation.
+  * Add json_tokener_get_error() and json_tokener_error_desc() to better 
+     encapsulate the process of retrieving errors while parsing.
+  * Various improvements to the documentation of many functions.
+  * Add new json_object_array_sort() function.
+  * Fix a bug in json_object_get_int(), which would incorrectly return 0
+    when called on a string type object.
+    Eric Haszlakiewicz
+  * Add a json_type_to_name() function.
+    Eric Haszlakiewicz
+  * Add a json_tokener_parse_verbose() function.
+    Jehiah Czebotar
+  * Improve support for null bytes within JSON strings.
+    Jehiah Czebotar
+  * Fix file descriptor leak if memory allocation fails in json_util
+    Zachary Blair, zack_blair at hotmail dot com
+  * Add int64 support. Two new functions json_object_net_int64 and
+    json_object_get_int64. Binary compatibility preserved.
+    Eric Haszlakiewicz, EHASZLA at transunion com
+    Rui Miguel Silva Seabra, rms at 1407 dot org
+  * Fix subtle bug in linkhash where lookup could hang after all slots
+    were filled then successively freed.
+    Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com
+  * Make json_object_from_file take const char *filename
+    Spotted by Vikram Raj V, vsagar at attinteractive dot com
+  * Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am)
+    Brent Miller, bdmiller at yahoo dash inc dot com
+  * Correction to comment describing printbuf_memappend in printbuf.h
+    Brent Miller, bdmiller at yahoo dash inc dot com
+
+0.9
+  * Add README.html README-WIN32.html config.h.win32 to Makefile.am
+    Michael Clark, <michael@metaparadigm.com>
+  * Add const qualifier to the json_tokener_parse functions
+    Eric Haszlakiewicz, EHASZLA at transunion dot com
+  * Rename min and max so we can never clash with C or C++ std library
+    Ian Atha, thatha at yahoo dash inc dot com
+  * Fix any noticeable spelling or grammar errors.
+  * Make sure every va_start has a va_end.
+  * Check all pointers for validity.
+    Erik Hovland, erik at hovland dot org
+  * Fix json_object_get_boolean to return false for empty string
+    Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com
+  * optimizations to json_tokener_parse_ex(), printbuf_memappend()
+    Brent Miller, bdmiller at yahoo dash inc dot com
+  * Disable REFCOUNT_DEBUG by default in json_object.c
+  * Don't use this as a variable, so we can compile with a C++ compiler
+  * Add casts from void* to type of assignment when using malloc 
+  * Add #ifdef __cplusplus guards to all of the headers
+  * Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table
+    Michael Clark, <michael@metaparadigm.com>
+  * Null pointer dereference fix. Fix json_object_get_boolean strlen test
+    to not return TRUE for zero length string. Remove redundant includes.
+    Erik Hovland, erik at hovland dot org
+  * Fixed warning reported by adding -Wstrict-prototypes
+    -Wold-style-definition to the compilatin flags.
+    Dotan Barak, dotanba at gmail dot com
+  * Add const correctness to public interfaces
+    Gerard Krol, g dot c dot krol at student dot tudelft dot nl
+
+0.8
+  * Add va_end for every va_start
+    Dotan Barak, dotanba at gmail dot com
+  * Add macros to enable compiling out debug code
+    Geoffrey Young, geoff at modperlcookbook dot org
+  * Fix bug with use of capital E in numbers with exponents
+    Mateusz Loskot, mateusz at loskot dot net
+  * Add stddef.h include
+  * Patch allows for json-c compile with -Werror and not fail due to
+    -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
+    Geoffrey Young, geoff at modperlcookbook dot org
+
+0.7
+  * Add escaping of backslash to json output
+  * Add escaping of foward slash on tokenizing and output
+  * Changes to internal tokenizer from using recursion to
+    using a depth state structure to allow incremental parsing
+
+0.6
+  * Fix bug in escaping of control characters
+    Johan Björklund, johbjo09 at kth dot se
+  * Remove include "config.h" from headers (should only
+    be included from .c files)
+    Michael Clark <michael@metaparadigm.com>
+
+0.5
+  * Make headers C++ compatible by change *this to *obj
+  * Add ifdef C++ extern "C" to headers
+  * Use simpler definition of min and max in bits.h
+    Larry Lansing, llansing at fuzzynerd dot com
+
+  * Remove automake 1.6 requirement
+  * Move autogen commands into autogen.sh. Update README
+  * Remove error pointer special case for Windows
+  * Change license from LGPL to MIT
+    Michael Clark <michael@metaparadigm.com>
+
+0.4
+  * Fix additional error case in object parsing
+  * Add back sign reversal in nested object parse as error pointer
+    value is negative, while error value is positive.
+    Michael Clark <michael@metaparadigm.com>
+
+0.3
+  * fix pointer arithmetic bug for error pointer check in is_error() macro
+  * fix type passed to printbuf_memappend in json_tokener
+  * update autotools bootstrap instructions in README
+    Michael Clark <michael@metaparadigm.com>
+
+0.2
+  * printbuf.c - C. Watford (christopher.watford@gmail.com)
+    Added a Win32/Win64 compliant implementation of vasprintf
+  * debug.c - C. Watford (christopher.watford@gmail.com)
+    Removed usage of vsyslog on Win32/Win64 systems, needs to be handled
+    by a configure script
+  * json_object.c - C. Watford (christopher.watford@gmail.com)
+    Added scope operator to wrap usage of json_object_object_foreach, this
+    needs to be rethought to be more ANSI C friendly
+  * json_object.h - C. Watford (christopher.watford@gmail.com)
+    Added Microsoft C friendly version of json_object_object_foreach
+  * json_tokener.c - C. Watford (christopher.watford@gmail.com)
+    Added a Win32/Win64 compliant implementation of strndup
+  * json_util.c - C. Watford (christopher.watford@gmail.com)
+    Added cast and mask to suffice size_t v. unsigned int conversion
+    correctness 
+  * json_tokener.c - sign reversal issue on error info for nested object parse
+    spotted by Johan Björklund (johbjo09 at kth.se)
+  * json_object.c - escape " in json_escape_str
+  * Change to automake and libtool to build shared and static library
+    Michael Clark <michael@metaparadigm.com>
+	
+0.1
+  * initial release
diff --git a/json-c/Doxyfile b/json-c/Doxyfile
new file mode 100644
index 0000000..da39aca
--- /dev/null
+++ b/json-c/Doxyfile
@@ -0,0 +1,1153 @@
+# Doxyfile 1.3.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = json-c
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 0.12.99
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of source 
+# files, where putting all generated files in the same directory would otherwise 
+# cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, 
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, 
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, 
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is used 
+# as the annotated text. Otherwise, the brief description is used as-is. If left 
+# blank, the following values are used ("$name" is automatically replaced with the 
+# name of the entity): "The $name class" "The $name widget" "The $name file" 
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = 
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS          = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes that 
+# lay further from the root node will be omitted. Note that setting this option to 
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also 
+# note that a graph may be further truncated if the graph's image dimensions are 
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). 
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/json-c/Makefile.am b/json-c/Makefile.am
new file mode 100644
index 0000000..26ced27
--- /dev/null
+++ b/json-c/Makefile.am
@@ -0,0 +1,74 @@
+include Makefile.am.inc
+
+EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj
+SUBDIRS = . tests
+
+lib_LTLIBRARIES = libjson-c.la 
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = json-c.pc
+
+libjson_cincludedir = $(includedir)/json-c
+libjson_cinclude_HEADERS = \
+	arraylist.h \
+	bits.h \
+	debug.h \
+	json.h \
+	json_config.h \
+	json_c_version.h \
+	json_inttypes.h \
+	json_object.h \
+	json_object_iterator.h \
+	json_object_private.h \
+	json_tokener.h \
+	json_util.h \
+	linkhash.h \
+	printbuf.h \
+	random_seed.h
+
+#libjsonx_includedir = $(libdir)/json-c-@VERSION@
+#
+#libjsonx_include_HEADERS = \
+#	json_config.h
+
+libjson_c_la_LDFLAGS = -version-info 2:0:0 -no-undefined @JSON_BSYMBOLIC_LDFLAGS@
+
+libjson_c_la_SOURCES = \
+	arraylist.c \
+	debug.c \
+	json_c_version.c \
+	json_object.c \
+	json_object_iterator.c \
+	json_tokener.c \
+	json_util.c \
+	linkhash.c \
+	printbuf.c \
+	random_seed.c
+
+
+distclean-local:
+	-rm -rf $(testsubdir)
+	-rm -rf config.h.in~ Makefile.in aclocal.m4 autom4te.cache/ config.guess config.sub depcomp install-sh ltmain.sh missing
+	-rm -f INSTALL test-driver tests/Makefile.in compile
+
+maintainer-clean-local:
+	-rm -rf configure
+
+uninstall-local:
+	rm -rf "$(DESTDIR)@includedir@/json-c"
+	rm -f "$(DESTDIR)@includedir@/json"
+
+ANDROID_CFLAGS = -I$(top_srcdir) -DHAVE_CONFIG_H
+
+Android.mk: Makefile.am
+	androgenizer -:PROJECT json-c \
+		-:SHARED libjson-c \
+		-:TAGS eng debug \
+		-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+		-:SOURCES $(libjson_c_la_SOURCES) $(nodist_libjson_c_la_SOURCES) \
+		-:CFLAGS $(DEFS) $(ANDROID_CFLAGS) $(libjson_c_la_CFLAGS) \
+		-:LDFLAGS $(libjson_c_la_LDFLAGS) $(libjson_c_la_LIBADD) \
+		-:HEADER_TARGET json-c \
+		-:HEADERS $(libjson_cinclude_HEADERS) \
+		-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+	> $@
diff --git a/json-c/Makefile.am.inc b/json-c/Makefile.am.inc
new file mode 100644
index 0000000..fec591b
--- /dev/null
+++ b/json-c/Makefile.am.inc
@@ -0,0 +1,2 @@
+AM_CFLAGS = -Wall -Werror -Wno-error=deprecated-declarations -Wextra -Wwrite-strings -Wno-unused-parameter -std=gnu99 -D_GNU_SOURCE -D_REENTRANT
+
diff --git a/json-c/README b/json-c/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/json-c/README
diff --git a/json-c/README-WIN32.html b/json-c/README-WIN32.html
new file mode 100644
index 0000000..abdb39e
--- /dev/null
+++ b/json-c/README-WIN32.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

+	<head>

+		<title>JSON-C - A JSON implementation in C - Win32 specific notes</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

+	</head>

+	<body>

+		<h2>Windows specific notes for JSON-C</h2>

+		<p>Please send Win32 bug reports to <a href="mailto:christopher.watford@gmail.com">christopher.watford@gmail.com</a></p>

+		<p><b>Win32 Specific Changes:</b></p>

+		<ul>

+			<li>

+				Various functions have been redefined to their Win32 version (i.e. <tt>open</tt>

+				on win32 is <tt>_open</tt>)</li>

+			<li>

+				Implemented missing functions from MS's libc (i.e. <tt>vasprintf</tt>)</li>

+			<li>

+				Added code to allow Win64 support without integer resizing issues, this 

+				probably makes it much nicer on 64bit machines everywhere (i.e. using <tt>ptrdiff_t</tt>

+				for pointer math)</li>

+		</ul>

+		<p><b>Porting Changelog:</b></p>

+		<dl>

+			<dt><tt>printbuf.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>

+			<dd>

+				Added a Win32/Win64 compliant implementation of <tt>vasprintf</tt></dd>

+			<dt><tt>debug.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>

+			<dd>

+				Removed usage of <tt>vsyslog</tt> on Win32/Win64 systems, needs to be handled 

+				by a configure script</dd>

+			<dt><tt>json_object.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>

+			<dd>

+				Added scope operator to wrap usage of <tt>json_object_object_foreach</tt>, this needs to be

+				rethought to be more ANSI C friendly</dd>

+			<dt><tt>json_object.h</tt> - C. Watford (christopher.watford@gmail.com)</dt>

+			<dd>

+				Added Microsoft C friendly version of <tt>json_object_object_foreach</tt></dd>

+			<dt><tt>json_tokener.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>

+			<dd>

+				Added a Win32/Win64 compliant implementation of <tt>strndup</tt></dd>

+			<dt><tt>json_util.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>

+			<dd>

+				Added cast and mask to suffice <tt>size_t</tt> v. <tt>unsigned int</tt>

+				conversion correctness</dd>

+		</dl>

+		<p>This program is free software; you can redistribute it and/or modify it under 

+			the terms of the MIT License. See COPYING for details.</p>

+		<hr />

+	</body>

+</html>

diff --git a/json-c/README.html b/json-c/README.html
new file mode 100644
index 0000000..dc696af
--- /dev/null
+++ b/json-c/README.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+	<head>
+		<title>JSON-C - A JSON implementation in C</title>
+		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+	</head>
+	<body>
+		<h2>JSON-C - A JSON implementation in C</h2>
+
+		<h3>Overview</h3>
+		<p>JSON-C implements a reference counting object model that allows you to easily 
+		construct JSON objects in C, output them as JSON formatted strings and parse 
+		JSON formatted strings back into the C representation of JSON objects.</p>
+
+		<h3>Building</h3>
+		<p>To setup JSON-C to build on your system please run <tt>configure</tt> and <tt>make</tt>.</p>
+		<p>If you are on Win32 and are not using the VS project file, be sure 
+		to rename <tt>config.h.win32</tt> to <tt>config.h</tt> before building.</p>
+
+		<h3>Documentation</h3>
+		<P>Doxygen generated documentation exists <a href="doc/html/json__object_8h.html">here</a>
+		and Win32 specific notes can be found <a href="README-WIN32.html">here</a>.</P>
+
+		<h3><a href="https://github.com/json-c/json-c">GIT Reposository</a></h3>
+		<p><strong><code>git clone https://github.com/json-c/json-c.git</code></strong></p>
+
+		<h3><a href="http://groups.google.com/group/json-c">Mailing List</a></h3>
+                <pi>Send email to <strong><code>json-c <i>&lt;at&gt;</i> googlegroups <i>&lt;dot&gt;</i> com</code></strong></p>
+
+		<h3><a href="COPYING">License</a></h3>
+		<p>This program is free software; you can redistribute it and/or modify it under the terms of the MIT License..</p>
+		<hr/>
+	</body>
+</html>
diff --git a/json-c/README.md b/json-c/README.md
new file mode 100644
index 0000000..bf4d2e4
--- /dev/null
+++ b/json-c/README.md
@@ -0,0 +1,63 @@
+`json-c`
+========
+
+Building on Unix with `git`, `gcc` and `autotools`
+--------------------------------------------------
+
+Home page for json-c: https://github.com/json-c/json-c/wiki
+
+Caution: do **NOT** use sources from svn.metaparadigm.com,
+they are old.
+
+Prerequisites:
+
+ - `gcc`, `clang`, or another C compiler
+ - `libtool`
+
+If you're not using a release tarball, you'll also need:
+
+ - `autoconf` (`autoreconf`)
+ - `automake`
+
+Make sure you have a complete `libtool` install, including `libtoolize`.
+
+`json-c` GitHub repo: https://github.com/json-c/json-c
+
+```bash
+$ git clone https://github.com/json-c/json-c.git
+$ cd json-c
+$ sh autogen.sh
+```
+
+followed by
+
+```bash
+$ ./configure
+$ make
+$ make install
+```
+
+To build and run the test programs:
+
+```bash
+$ make check
+```
+
+Linking to `libjson-c`
+----------------------
+
+If your system has `pkgconfig`,
+then you can just add this to your `makefile`:
+
+```make
+CFLAGS += $(shell pkg-config --cflags json-c)
+LDFLAGS += $(shell pkg-config --libs json-c)
+```
+
+Without `pkgconfig`, you would do something like this:
+
+```make
+JSON_C_DIR=/path/to/json_c/install
+CFLAGS += -I$(JSON_C_DIR)/include/json-c
+LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c
+```
diff --git a/json-c/RELEASE_CHECKLIST.txt b/json-c/RELEASE_CHECKLIST.txt
new file mode 100644
index 0000000..4713258
--- /dev/null
+++ b/json-c/RELEASE_CHECKLIST.txt
@@ -0,0 +1,132 @@
+
+Release checklist:
+
+release=0.12
+git clone https://github.com/json-c/json-c json-c-${release}
+cd json-c-${release}
+
+Check that the compile works on Linux
+Check that the compile works on NetBSD
+Check that the compile works on Windows
+Check ChangeLog to see if anything should be added.
+Make any fixes/changes *before* branching.
+
+  git branch json-c-${release}
+  git checkout json-c-${release}
+
+------------
+
+Update the version in json_c_version.h
+Update the version in Doxyfile
+Update the version in configure.ac
+	Use ${release}.
+
+Update the libjson_la_LDFLAGS line in Makefile.am to the new version.
+	Generally, unless we're doing a major release, change:
+		-version-info x:y:z
+	to
+		-version-info x:y+1:z
+
+------------
+
+Generate the configure script and other files:
+  sh autogen.sh
+  git add -f Makefile.in aclocal.m4 config.guess \
+       config.sub configure depcomp install-sh \
+       ltmain.sh missing tests/Makefile.in \
+       INSTALL
+
+  # check for anything else to be added:
+  git status --ignored
+  git commit
+
+------------
+
+Generate the doxygen documentation:
+  doxygen
+  git add -f doc
+  git commit doc
+
+------------
+
+cd ..
+echo .git > excludes
+echo autom4te.cache >> excludes
+tar -czf json-c-${release}.tar.gz -X excludes json-c-${release}
+
+echo doc >> excludes
+tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release}
+
+------------
+
+Tag the branch:
+cd json-c-${release}
+git tag -a json-c-${release}-$(date +%Y%m%d) -m "Release json-c-${release}"
+
+git push origin json-c-${release}
+git push --tags
+
+------------
+
+Go to Amazon S3 service at:
+    https://console.aws.amazon.com/s3/
+
+Upload the two tarballs in the json-c_releases folder.
+	When uploading, use "Reduced Redundancy", and make the uploaded files publicly accessible.
+
+Logout of Amazon S3, and verify that the files are visible.
+    https://s3.amazonaws.com/json-c_releases/releases/index.html
+
+===================================
+
+Post-release checklist:
+
+git checkout master
+Add new section to ChangeLog
+Update the version in json_c_version.h
+Update the version in Doxyfile
+Update the version in configure.ac
+    Use ${release}.99 to indicate a version "newer" than anything on the branch.
+
+Leave the libjson_la_LDFLAGS line in Makefile.am alone.
+	For more details see:
+	http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+
+------------
+
+Update the gh-pages branch with new docs:
+
+cd json-c-${release}
+git checkout json-c-${release}
+cd ..
+
+git clone -b gh-pages https://github.com/json-c/json-c json-c-pages
+cd json-c-pages
+mkdir json-c-${release}
+cp -R ../json-c-${release}/doc json-c-${release}/.
+cp ../json-c-${release}/README-WIN32.html json-c-${release}/.
+git add json-c-${release}
+git commit
+
+vi index.html
+    Add/change links to current release.
+
+git commit index.html
+
+git push
+
+------------
+
+Update checksums on wiki page.
+
+cd ..
+openssl sha -sha256 json-c*gz
+openssl md5 json-c*gz
+
+Copy and paste this output into the wiki page at:
+	https://github.com/json-c/json-c/wiki
+
+------------
+
+Send an email to the mailing list.
+
diff --git a/json-c/arraylist.c b/json-c/arraylist.c
new file mode 100644
index 0000000..1d899fa
--- /dev/null
+++ b/json-c/arraylist.c
@@ -0,0 +1,102 @@
+/*
+ * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#include "config.h"
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif /* STDC_HEADERS */
+
+#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD)
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+
+#include "arraylist.h"
+
+struct array_list*
+array_list_new(array_list_free_fn *free_fn)
+{
+  struct array_list *arr;
+
+  arr = (struct array_list*)calloc(1, sizeof(struct array_list));
+  if(!arr) return NULL;
+  arr->size = ARRAY_LIST_DEFAULT_SIZE;
+  arr->length = 0;
+  arr->free_fn = free_fn;
+  if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) {
+    free(arr);
+    return NULL;
+  }
+  return arr;
+}
+
+extern void
+array_list_free(struct array_list *arr)
+{
+  int i;
+  for(i = 0; i < arr->length; i++)
+    if(arr->array[i]) arr->free_fn(arr->array[i]);
+  free(arr->array);
+  free(arr);
+}
+
+void*
+array_list_get_idx(struct array_list *arr, int i)
+{
+  if(i >= arr->length) return NULL;
+  return arr->array[i];
+}
+
+static int array_list_expand_internal(struct array_list *arr, int max)
+{
+  void *t;
+  int new_size;
+
+  if(max < arr->size) return 0;
+  new_size = arr->size << 1;
+  if (new_size < max)
+    new_size = max;
+  if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1;
+  arr->array = (void**)t;
+  (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*));
+  arr->size = new_size;
+  return 0;
+}
+
+int
+array_list_put_idx(struct array_list *arr, int idx, void *data)
+{
+  if(array_list_expand_internal(arr, idx+1)) return -1;
+  if(arr->array[idx]) arr->free_fn(arr->array[idx]);
+  arr->array[idx] = data;
+  if(arr->length <= idx) arr->length = idx + 1;
+  return 0;
+}
+
+int
+array_list_add(struct array_list *arr, void *data)
+{
+  return array_list_put_idx(arr, arr->length, data);
+}
+
+void
+array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *))
+{
+  qsort(arr->array, arr->length, sizeof(arr->array[0]),
+	(int (*)(const void *, const void *))sort_fn);
+}
+
+int
+array_list_length(struct array_list *arr)
+{
+  return arr->length;
+}
diff --git a/json-c/arraylist.h b/json-c/arraylist.h
new file mode 100644
index 0000000..4f3113c
--- /dev/null
+++ b/json-c/arraylist.h
@@ -0,0 +1,56 @@
+/*
+ * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _arraylist_h_
+#define _arraylist_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ARRAY_LIST_DEFAULT_SIZE 32
+
+typedef void (array_list_free_fn) (void *data);
+
+struct array_list
+{
+  void **array;
+  int length;
+  int size;
+  array_list_free_fn *free_fn;
+};
+
+extern struct array_list*
+array_list_new(array_list_free_fn *free_fn);
+
+extern void
+array_list_free(struct array_list *al);
+
+extern void*
+array_list_get_idx(struct array_list *al, int i);
+
+extern int
+array_list_put_idx(struct array_list *al, int i, void *data);
+
+extern int
+array_list_add(struct array_list *al, void *data);
+
+extern int
+array_list_length(struct array_list *al);
+
+extern void
+array_list_sort(struct array_list *arr, int(*compar)(const void *, const void *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/autogen.sh b/json-c/autogen.sh
new file mode 100755
index 0000000..69e765a
--- /dev/null
+++ b/json-c/autogen.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+autoreconf -v --install || exit 1
+
+# If there are any options, assume the user wants to run configure.
+# To run configure w/o any options, use ./autogen.sh --configure
+if [ $# -gt 0 ] ; then
+	case "$1" in
+	--conf*)
+		shift 1
+		;;
+	esac
+    exec ./configure  "$@"
+fi
diff --git a/json-c/bits.h b/json-c/bits.h
new file mode 100644
index 0000000..d14a1db
--- /dev/null
+++ b/json-c/bits.h
@@ -0,0 +1,35 @@
+/**
+ * @file
+ * @deprecated Use json_util.h instead.
+ *
+ * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _bits_h_
+#define _bits_h_
+
+/**
+ * @deprecated
+ */
+#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
+/**
+ * @deprecated
+ */
+#define error_ptr(error) ((void*)error)
+/**
+ * @deprecated
+ */
+#define error_description(error)  (json_tokener_get_error(error))
+/**
+ * @deprecated
+ */
+#define is_error(ptr) (ptr == NULL)
+
+#endif
diff --git a/json-c/check.log b/json-c/check.log
new file mode 100644
index 0000000..3c73d2a
--- /dev/null
+++ b/json-c/check.log
@@ -0,0 +1,2 @@
+HEAD is now at 6442a2f... json-c: Add libjson to the vendor image
+HEAD is now at 6442a2f... json-c: Add libjson to the vendor image
diff --git a/json-c/config.h b/json-c/config.h
new file mode 100644
index 0000000..f958d44
--- /dev/null
+++ b/json-c/config.h
@@ -0,0 +1,178 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Enable RDRANR Hardware RNG Hash Seed */
+/* #undef ENABLE_RDRAND */
+
+/* Define if .gnu.warning accepts long strings. */
+/* #undef HAS_GNU_WARNING_LONG */
+
+/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you
+   don't. */
+#define HAVE_DECL_INFINITY 1
+
+/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
+   */
+#define HAVE_DECL_ISINF 1
+
+/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
+   */
+#define HAVE_DECL_ISNAN 1
+
+/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */
+#define HAVE_DECL_NAN 1
+
+/* Define to 1 if you have the declaration of `_finite', and to 0 if you
+   don't. */
+#define HAVE_DECL__FINITE 0
+
+/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't.
+   */
+#define HAVE_DECL__ISNAN 0
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the <endian.h> header file. */
+#define HAVE_ENDIAN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+   to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `open' function. */
+#define HAVE_OPEN 1
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+   and to 0 otherwise. */
+#define HAVE_REALLOC 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#define HAVE_SYS_CDEFS_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 if you have the `vsyslog' function. */
+#define HAVE_VSYSLOG 1
+
+/* Public define for json_inttypes.h */
+#define JSON_C_HAVE_INTTYPES_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "json-c"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "json-c@googlegroups.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "json-c"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "json-c 0.12.99"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "json-c"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.12.99"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.12.99"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to rpl_malloc if the replacement function should be used. */
+/* #undef malloc */
+
+/* Define to rpl_realloc if the replacement function should be used. */
+/* #undef realloc */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/json-c/config.h.in b/json-c/config.h.in
new file mode 100644
index 0000000..af2e5fc
--- /dev/null
+++ b/json-c/config.h.in
@@ -0,0 +1,177 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Enable RDRANR Hardware RNG Hash Seed */
+#undef ENABLE_RDRAND
+
+/* Define if .gnu.warning accepts long strings. */
+#undef HAS_GNU_WARNING_LONG
+
+/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you
+   don't. */
+#undef HAVE_DECL_INFINITY
+
+/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
+   */
+#undef HAVE_DECL_ISINF
+
+/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
+   */
+#undef HAVE_DECL_ISNAN
+
+/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */
+#undef HAVE_DECL_NAN
+
+/* Define to 1 if you have the declaration of `_finite', and to 0 if you
+   don't. */
+#undef HAVE_DECL__FINITE
+
+/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't.
+   */
+#undef HAVE_DECL__ISNAN
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+#undef HAVE_DOPRNT
+
+/* Define to 1 if you have the <endian.h> header file. */
+#undef HAVE_ENDIAN_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+   to 0 otherwise. */
+#undef HAVE_MALLOC
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `open' function. */
+#undef HAVE_OPEN
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+   and to 0 otherwise. */
+#undef HAVE_REALLOC
+
+/* Define to 1 if you have the `setlocale' function. */
+#undef HAVE_SETLOCALE
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vprintf' function. */
+#undef HAVE_VPRINTF
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `vsyslog' function. */
+#undef HAVE_VSYSLOG
+
+/* Public define for json_inttypes.h */
+#undef JSON_C_HAVE_INTTYPES_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to rpl_realloc if the replacement function should be used. */
+#undef realloc
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/json-c/configure.ac b/json-c/configure.ac
new file mode 100644
index 0000000..c50f81b
--- /dev/null
+++ b/json-c/configure.ac
@@ -0,0 +1,107 @@
+AC_PREREQ(2.52)
+
+# Process this file with autoconf to produce a configure script.
+AC_INIT([json-c], 0.12.99, [json-c@googlegroups.com])
+
+AM_INIT_AUTOMAKE
+
+AC_PROG_MAKE_SET
+
+AC_ARG_ENABLE(rdrand,
+ AS_HELP_STRING([--enable-rdrand],
+   [Enable RDRAND Hardware RNG Hash Seed generation on supported x86/x64 platforms.]),
+[if test x$enableval = xyes; then
+  enable_rdrand=yes
+  AC_DEFINE(ENABLE_RDRAND, 1, [Enable RDRANR Hardware RNG Hash Seed])
+fi])
+
+if test "x$enable_rdrand" = "xyes"; then
+  AC_MSG_RESULT([RDRAND Hardware RNG Hash Seed enabled on supported x86/x64 platforms])
+else
+  AC_MSG_RESULT([RDRAND Hardware RNG Hash Seed disabled. Use --enable-rdrand to enable])
+fi
+
+# Checks for programs.
+
+# Checks for libraries.
+
+# Checks for header files.
+AM_PROG_CC_C_O
+AC_CONFIG_HEADER(config.h)
+AC_CONFIG_HEADER(json_config.h)
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h endian.h)
+AC_CHECK_HEADER(inttypes.h,[AC_DEFINE([JSON_C_HAVE_INTTYPES_H],[1],[Public define for json_inttypes.h])])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_VPRINTF
+AC_FUNC_MEMCMP
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale)
+AC_CHECK_DECLS([INFINITY], [], [], [[#include <math.h>]])
+AC_CHECK_DECLS([nan], [], [], [[#include <math.h>]])
+AC_CHECK_DECLS([isnan], [], [], [[#include <math.h>]])
+AC_CHECK_DECLS([isinf], [], [], [[#include <math.h>]])
+AC_CHECK_DECLS([_isnan], [], [], [[#include <float.h>]])
+AC_CHECK_DECLS([_finite], [], [], [[#include <float.h>]])
+
+#check if .section.gnu.warning accepts long strings (for __warn_references)
+AC_LANG_PUSH([C])
+
+AC_MSG_CHECKING([if .gnu.warning accepts long strings])
+AC_LINK_IFELSE([AC_LANG_SOURCE([[
+extern void json_object_get();
+__asm__(".section .gnu.json_object_get,\n\t.ascii \"Please link against libjson-c instead of libjson\"\n\t.text");
+
+int main(int c,char* v) {return 0;}
+]])], [
+    AC_DEFINE(HAS_GNU_WARNING_LONG, 1, [Define if .gnu.warning accepts long strings.])
+    AC_MSG_RESULT(yes)
+], [
+   AC_MSG_RESULT(no)
+])
+
+AC_LANG_POP([C])
+
+AM_PROG_LIBTOOL
+
+# Check for the -Bsymbolic-functions linker flag
+AC_ARG_ENABLE([Bsymbolic],
+              [AS_HELP_STRING([--disable-Bsymbolic], [Avoid linking with -Bsymbolic-function])],
+              [],
+              [enable_Bsymbolic=check])
+
+AS_IF([test "x$enable_Bsymbolic" = "xcheck"],
+      [
+        saved_LDFLAGS="${LDFLAGS}"
+        AC_MSG_CHECKING([for -Bsymbolic-functions linker flag])
+        LDFLAGS=-Wl,-Bsymbolic-functions
+        AC_TRY_LINK([], [int main (void) { return 0; }],
+                    [
+                      AC_MSG_RESULT([yes])
+                      enable_Bsymbolic=yes
+                    ],
+                    [
+                      AC_MSG_RESULT([no])
+                      enable_Bsymbolic=no
+                    ])
+        LDFLAGS="${saved_LDFLAGS}"
+      ])
+
+AS_IF([test "x$enable_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
+AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
+
+AC_CONFIG_FILES([
+Makefile
+json-c.pc
+tests/Makefile
+json-c-uninstalled.pc
+])
+
+AC_OUTPUT
+
diff --git a/json-c/debug.c b/json-c/debug.c
new file mode 100644
index 0000000..3b64b59
--- /dev/null
+++ b/json-c/debug.c
@@ -0,0 +1,83 @@
+/*
+ * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif /* HAVE_SYSLOG_H */
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif /* HAVE_SYS_PARAM_H */
+
+#include "debug.h"
+
+static int _syslog = 0;
+static int _debug = 0;
+
+void mc_set_debug(int debug) { _debug = debug; }
+int mc_get_debug(void) { return _debug; }
+
+extern void mc_set_syslog(int syslog)
+{
+  _syslog = syslog;
+}
+
+void mc_debug(const char *msg, ...)
+{
+  va_list ap;
+  if(_debug) {
+    va_start(ap, msg);
+#if HAVE_VSYSLOG
+    if(_syslog) {
+		vsyslog(LOG_DEBUG, msg, ap);
+	} else
+#endif
+		vprintf(msg, ap);
+    va_end(ap);
+  }
+}
+
+void mc_error(const char *msg, ...)
+{
+  va_list ap;
+  va_start(ap, msg);
+#if HAVE_VSYSLOG
+    if(_syslog) {
+		vsyslog(LOG_ERR, msg, ap);
+	} else
+#endif
+		vfprintf(stderr, msg, ap);
+  va_end(ap);
+}
+
+void mc_info(const char *msg, ...)
+{
+  va_list ap;
+  va_start(ap, msg);
+#if HAVE_VSYSLOG
+    if(_syslog) {
+		vsyslog(LOG_INFO, msg, ap);
+	} else 
+#endif
+		vfprintf(stderr, msg, ap);
+  va_end(ap);
+}
diff --git a/json-c/debug.h b/json-c/debug.h
new file mode 100644
index 0000000..80ca3e4
--- /dev/null
+++ b/json-c/debug.h
@@ -0,0 +1,71 @@
+/*
+ * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void mc_set_debug(int debug);
+extern int mc_get_debug(void);
+
+extern void mc_set_syslog(int syslog);
+
+extern void mc_debug(const char *msg, ...);
+extern void mc_error(const char *msg, ...);
+extern void mc_info(const char *msg, ...);
+
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+#ifndef PARSER_BROKEN_FIXED
+
+#define JASSERT(cond) do {} while(0)
+
+#else
+
+#define JASSERT(cond) do { \
+		if (!(cond)) { \
+			mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \
+			*(int *)0 = 1;\
+			abort(); \
+		}\
+	} while(0)
+
+#endif
+
+#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)
+
+#ifdef MC_MAINTAINER_MODE
+#define MC_SET_DEBUG(x) mc_set_debug(x)
+#define MC_GET_DEBUG() mc_get_debug()
+#define MC_SET_SYSLOG(x) mc_set_syslog(x)
+#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)
+#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__)
+#else
+#define MC_SET_DEBUG(x) if (0) mc_set_debug(x)
+#define MC_GET_DEBUG() (0)
+#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x)
+#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__)
+#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/json-c-uninstalled.pc.in b/json-c/json-c-uninstalled.pc.in
new file mode 100644
index 0000000..dab2bab
--- /dev/null
+++ b/json-c/json-c-uninstalled.pc.in
@@ -0,0 +1,11 @@
+prefix=
+exec_prefix=
+libdir=@abs_top_builddir@
+includedir=@abs_top_srcdir@
+
+Name: json
+Description: JSON implementation in C
+Version: @VERSION@
+Requires:
+Libs:  -L@abs_top_builddir@ -ljson-c
+Cflags: -I@abs_top_srcdir@
diff --git a/json-c/json-c.pc.in b/json-c/json-c.pc.in
new file mode 100644
index 0000000..037739d
--- /dev/null
+++ b/json-c/json-c.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: json-c
+Description: JSON implementation in C
+Version: @VERSION@
+Requires: 
+Libs:  -L${libdir} -ljson-c
+Cflags: -I${includedir}/json-c
diff --git a/json-c/json.h b/json-c/json.h
new file mode 100644
index 0000000..e198f5d
--- /dev/null
+++ b/json-c/json.h
@@ -0,0 +1,33 @@
+/*
+ * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _json_h_
+#define _json_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "debug.h"
+#include "linkhash.h"
+#include "arraylist.h"
+#include "json_util.h"
+#include "json_object.h"
+#include "json_tokener.h"
+#include "json_object_iterator.h"
+#include "json_c_version.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/json_c_version.c b/json-c/json_c_version.c
new file mode 100644
index 0000000..13eb188
--- /dev/null
+++ b/json-c/json_c_version.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012 Eric Haszlakiewicz
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ */
+#include "config.h"
+
+#include "json_c_version.h"
+
+const char *json_c_version(void)
+{
+	return JSON_C_VERSION;
+}
+
+int json_c_version_num(void)
+{
+	return JSON_C_VERSION_NUM;
+}
+
diff --git a/json-c/json_c_version.h b/json-c/json_c_version.h
new file mode 100644
index 0000000..d77f1a7
--- /dev/null
+++ b/json-c/json_c_version.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 Eric Haszlakiewicz
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ */
+
+#ifndef _json_c_version_h_
+#define _json_c_version_h_
+
+#define JSON_C_MAJOR_VERSION 0
+#define JSON_C_MINOR_VERSION 12
+#define JSON_C_MICRO_VERSION 99
+#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \
+                            (JSON_C_MINOR_VERSION << 8) | \
+                            JSON_C_MICRO_VERSION)
+#define JSON_C_VERSION "0.12.99"
+
+const char *json_c_version(void); /* Returns JSON_C_VERSION */
+int json_c_version_num(void);     /* Returns JSON_C_VERSION_NUM */
+
+#endif
diff --git a/json-c/json_config.h b/json-c/json_config.h
new file mode 100644
index 0000000..965ff1c
--- /dev/null
+++ b/json-c/json_config.h
@@ -0,0 +1,4 @@
+/* json_config.h.  Generated from json_config.h.in by configure.  */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define JSON_C_HAVE_INTTYPES_H 1
diff --git a/json-c/json_config.h.in b/json-c/json_config.h.in
new file mode 100644
index 0000000..7888e02
--- /dev/null
+++ b/json-c/json_config.h.in
@@ -0,0 +1,3 @@
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef JSON_C_HAVE_INTTYPES_H
diff --git a/json-c/json_inttypes.h b/json-c/json_inttypes.h
new file mode 100644
index 0000000..9de8d24
--- /dev/null
+++ b/json-c/json_inttypes.h
@@ -0,0 +1,28 @@
+
+#ifndef _json_inttypes_h_
+#define _json_inttypes_h_
+
+#include "json_config.h"
+
+#if defined(_MSC_VER) && _MSC_VER <= 1700
+
+/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */
+typedef __int32 int32_t;
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    ((int32_t)_I32_MAX)
+typedef __int64 int64_t;
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    ((int64_t)_I64_MAX)
+#define PRId64 "I64d"
+#define SCNd64 "I64d"
+
+#else
+
+#ifdef JSON_C_HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+/* inttypes.h includes stdint.h */
+
+#endif
+
+#endif
diff --git a/json-c/json_object.c b/json-c/json_object.c
new file mode 100644
index 0000000..8ed0239
--- /dev/null
+++ b/json-c/json_object.c
@@ -0,0 +1,913 @@
+/*
+ * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "printbuf.h"
+#include "linkhash.h"
+#include "arraylist.h"
+#include "json_inttypes.h"
+#include "json_object.h"
+#include "json_object_private.h"
+#include "json_util.h"
+#include "math_compat.h"
+
+#if !defined(HAVE_STRDUP) && defined(_MSC_VER)
+  /* MSC has the version as _strdup */
+# define strdup _strdup
+#elif !defined(HAVE_STRDUP)
+# error You do not have strdup on your system.
+#endif /* HAVE_STRDUP */
+
+#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)
+  /* MSC has the version as _snprintf */
+# define snprintf _snprintf
+#elif !defined(HAVE_SNPRINTF)
+# error You do not have snprintf on your system.
+#endif /* HAVE_SNPRINTF */
+
+// Don't define this.  It's not thread-safe.
+/* #define REFCOUNT_DEBUG 1 */
+
+const char *json_number_chars = "0123456789.+-eE";
+const char *json_hex_chars = "0123456789abcdefABCDEF";
+
+static void json_object_generic_delete(struct json_object* jso);
+static struct json_object* json_object_new(enum json_type o_type);
+
+static json_object_to_json_string_fn json_object_object_to_json_string;
+static json_object_to_json_string_fn json_object_boolean_to_json_string;
+static json_object_to_json_string_fn json_object_int_to_json_string;
+static json_object_to_json_string_fn json_object_double_to_json_string;
+static json_object_to_json_string_fn json_object_string_to_json_string;
+static json_object_to_json_string_fn json_object_array_to_json_string;
+
+
+/* ref count debugging */
+
+#ifdef REFCOUNT_DEBUG
+
+static struct lh_table *json_object_table;
+
+static void json_object_init(void) __attribute__ ((constructor));
+static void json_object_init(void) {
+	MC_DEBUG("json_object_init: creating object table\n");
+	json_object_table = lh_kptr_table_new(128, "json_object_table", NULL);
+}
+
+static void json_object_fini(void) __attribute__ ((destructor));
+static void json_object_fini(void)
+{
+	struct lh_entry *ent;
+	if (MC_GET_DEBUG())
+	{
+		if (json_object_table->count)
+		{
+			MC_DEBUG("json_object_fini: %d referenced objects at exit\n",
+			   json_object_table->count);
+			lh_foreach(json_object_table, ent)
+			{
+				struct json_object* obj = (struct json_object*)ent->v;
+				MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj);
+			}
+		}
+	}
+	MC_DEBUG("json_object_fini: freeing object table\n");
+	lh_table_free(json_object_table);
+}
+#endif /* REFCOUNT_DEBUG */
+
+
+/* string escaping */
+
+static int json_escape_str(struct printbuf *pb, char *str, int len)
+{
+	int pos = 0, start_offset = 0;
+	unsigned char c;
+	while (len--)
+	{
+		c = str[pos];
+		switch(c)
+		{
+		case '\b':
+		case '\n':
+		case '\r':
+		case '\t':
+		case '\f':
+		case '"':
+		case '\\':
+		case '/':
+			if(pos - start_offset > 0)
+				printbuf_memappend(pb, str + start_offset, pos - start_offset);
+
+			if(c == '\b') printbuf_memappend(pb, "\\b", 2);
+			else if(c == '\n') printbuf_memappend(pb, "\\n", 2);
+			else if(c == '\r') printbuf_memappend(pb, "\\r", 2);
+			else if(c == '\t') printbuf_memappend(pb, "\\t", 2);
+			else if(c == '\f') printbuf_memappend(pb, "\\f", 2);
+			else if(c == '"') printbuf_memappend(pb, "\\\"", 2);
+			else if(c == '\\') printbuf_memappend(pb, "\\\\", 2);
+			else if(c == '/') printbuf_memappend(pb, "\\/", 2);
+
+			start_offset = ++pos;
+			break;
+		default:
+			if(c < ' ')
+			{
+				if(pos - start_offset > 0)
+				printbuf_memappend(pb, str + start_offset, pos - start_offset);
+				sprintbuf(pb, "\\u00%c%c",
+				json_hex_chars[c >> 4],
+				json_hex_chars[c & 0xf]);
+				start_offset = ++pos;
+			} else
+				pos++;
+		}
+	}
+	if (pos - start_offset > 0)
+		printbuf_memappend(pb, str + start_offset, pos - start_offset);
+	return 0;
+}
+
+
+/* reference counting */
+
+extern struct json_object* json_object_get(struct json_object *jso)
+{
+	if (jso)
+		jso->_ref_count++;
+	return jso;
+}
+
+int json_object_put(struct json_object *jso)
+{
+	if(jso)
+	{
+		jso->_ref_count--;
+		if(!jso->_ref_count)
+		{
+			if (jso->_user_delete)
+				jso->_user_delete(jso, jso->_userdata);
+			jso->_delete(jso);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+
+/* generic object construction and destruction parts */
+
+static void json_object_generic_delete(struct json_object* jso)
+{
+#ifdef REFCOUNT_DEBUG
+	MC_DEBUG("json_object_delete_%s: %p\n",
+	   json_type_to_name(jso->o_type), jso);
+	lh_table_delete(json_object_table, jso);
+#endif /* REFCOUNT_DEBUG */
+	printbuf_free(jso->_pb);
+	free(jso);
+}
+
+static struct json_object* json_object_new(enum json_type o_type)
+{
+	struct json_object *jso;
+
+	jso = (struct json_object*)calloc(sizeof(struct json_object), 1);
+	if (!jso)
+		return NULL;
+	jso->o_type = o_type;
+	jso->_ref_count = 1;
+	jso->_delete = &json_object_generic_delete;
+#ifdef REFCOUNT_DEBUG
+	lh_table_insert(json_object_table, jso, jso);
+	MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso);
+#endif /* REFCOUNT_DEBUG */
+	return jso;
+}
+
+
+/* type checking functions */
+
+int json_object_is_type(struct json_object *jso, enum json_type type)
+{
+	if (!jso)
+		return (type == json_type_null);
+	return (jso->o_type == type);
+}
+
+enum json_type json_object_get_type(struct json_object *jso)
+{
+	if (!jso)
+		return json_type_null;
+	return jso->o_type;
+}
+
+/* set a custom conversion to string */
+
+void json_object_set_serializer(json_object *jso,
+	json_object_to_json_string_fn to_string_func,
+	void *userdata,
+	json_object_delete_fn *user_delete)
+{
+	// First, clean up any previously existing user info
+	if (jso->_user_delete)
+	{
+		jso->_user_delete(jso, jso->_userdata);
+	}
+	jso->_userdata = NULL;
+	jso->_user_delete = NULL;
+
+	if (to_string_func == NULL)
+	{
+		// Reset to the standard serialization function
+		switch(jso->o_type)
+		{
+		case json_type_null:
+			jso->_to_json_string = NULL;
+			break;
+		case json_type_boolean:
+			jso->_to_json_string = &json_object_boolean_to_json_string;
+			break;
+		case json_type_double:
+			jso->_to_json_string = &json_object_double_to_json_string;
+			break;
+		case json_type_int:
+			jso->_to_json_string = &json_object_int_to_json_string;
+			break;
+		case json_type_object:
+			jso->_to_json_string = &json_object_object_to_json_string;
+			break;
+		case json_type_array:
+			jso->_to_json_string = &json_object_array_to_json_string;
+			break;
+		case json_type_string:
+			jso->_to_json_string = &json_object_string_to_json_string;
+			break;
+		}
+		return;
+	}
+
+	jso->_to_json_string = to_string_func;
+	jso->_userdata = userdata;
+	jso->_user_delete = user_delete;
+}
+
+
+/* extended conversion to string */
+
+const char* json_object_to_json_string_ext(struct json_object *jso, int flags)
+{
+	if (!jso)
+		return "null";
+
+	if ((!jso->_pb) && !(jso->_pb = printbuf_new()))
+		return NULL;
+
+	printbuf_reset(jso->_pb);
+
+	if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0)
+		return NULL;
+
+	return jso->_pb->buf;
+}
+
+/* backwards-compatible conversion to string */
+
+const char* json_object_to_json_string(struct json_object *jso)
+{
+	return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED);
+}
+
+static void indent(struct printbuf *pb, int level, int flags)
+{
+	if (flags & JSON_C_TO_STRING_PRETTY)
+	{
+		printbuf_memset(pb, -1, ' ', level * 2);
+	}
+}
+
+/* json_object_object */
+
+static int json_object_object_to_json_string(struct json_object* jso,
+					     struct printbuf *pb,
+					     int level,
+						 int flags)
+{
+	int had_children = 0;
+	struct json_object_iter iter;
+
+	sprintbuf(pb, "{" /*}*/);
+	if (flags & JSON_C_TO_STRING_PRETTY)
+		sprintbuf(pb, "\n");
+	json_object_object_foreachC(jso, iter)
+	{
+		if (had_children)
+		{
+			sprintbuf(pb, ",");
+			if (flags & JSON_C_TO_STRING_PRETTY)
+				sprintbuf(pb, "\n");
+		}
+		had_children = 1;
+		if (flags & JSON_C_TO_STRING_SPACED)
+			sprintbuf(pb, " ");
+		indent(pb, level+1, flags);
+		sprintbuf(pb, "\"");
+		json_escape_str(pb, iter.key, strlen(iter.key));
+		if (flags & JSON_C_TO_STRING_SPACED)
+			sprintbuf(pb, "\": ");
+		else
+			sprintbuf(pb, "\":");
+		if(iter.val == NULL)
+			sprintbuf(pb, "null");
+		else
+			iter.val->_to_json_string(iter.val, pb, level+1,flags);
+	}
+	if (flags & JSON_C_TO_STRING_PRETTY)
+	{
+		if (had_children)
+			sprintbuf(pb, "\n");
+		indent(pb,level,flags);
+	}
+	if (flags & JSON_C_TO_STRING_SPACED)
+		return sprintbuf(pb, /*{*/ " }");
+	else
+		return sprintbuf(pb, /*{*/ "}");
+}
+
+
+static void json_object_lh_entry_free(struct lh_entry *ent)
+{
+	free(ent->k);
+	json_object_put((struct json_object*)ent->v);
+}
+
+static void json_object_object_delete(struct json_object* jso)
+{
+	lh_table_free(jso->o.c_object);
+	json_object_generic_delete(jso);
+}
+
+struct json_object* json_object_new_object(void)
+{
+	struct json_object *jso = json_object_new(json_type_object);
+	if (!jso)
+		return NULL;
+	jso->_delete = &json_object_object_delete;
+	jso->_to_json_string = &json_object_object_to_json_string;
+	jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES,
+					NULL, &json_object_lh_entry_free);
+	if (!jso->o.c_object)
+	{
+		json_object_generic_delete(jso);
+		errno = ENOMEM;
+		return NULL;
+	}
+	return jso;
+}
+
+struct lh_table* json_object_get_object(struct json_object *jso)
+{
+	if (!jso)
+		return NULL;
+	switch(jso->o_type)
+	{
+	case json_type_object:
+		return jso->o.c_object;
+	default:
+		return NULL;
+	}
+}
+
+void json_object_object_add(struct json_object* jso, const char *key,
+			    struct json_object *val)
+{
+	// We lookup the entry and replace the value, rather than just deleting
+	// and re-adding it, so the existing key remains valid.
+	json_object *existing_value = NULL;
+	struct lh_entry *existing_entry;
+	existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key);
+	if (!existing_entry)
+	{
+		lh_table_insert(jso->o.c_object, strdup(key), val);
+		return;
+	}
+	existing_value = (void *)existing_entry->v;
+	if (existing_value)
+		json_object_put(existing_value);
+	existing_entry->v = val;
+}
+
+int json_object_object_length(struct json_object *jso)
+{
+	return lh_table_length(jso->o.c_object);
+}
+
+struct json_object* json_object_object_get(struct json_object* jso, const char *key)
+{
+	struct json_object *result = NULL;
+	json_object_object_get_ex(jso, key, &result);
+	return result;
+}
+
+json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value)
+{
+	if (value != NULL)
+		*value = NULL;
+
+	if (NULL == jso)
+		return FALSE;
+
+	switch(jso->o_type)
+	{
+	case json_type_object:
+		return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value);
+	default:
+		if (value != NULL)
+			*value = NULL;
+		return FALSE;
+	}
+}
+
+void json_object_object_del(struct json_object* jso, const char *key)
+{
+	lh_table_delete(jso->o.c_object, key);
+}
+
+
+/* json_object_boolean */
+
+static int json_object_boolean_to_json_string(struct json_object* jso,
+					      struct printbuf *pb,
+					      int level,
+						  int flags)
+{
+	if (jso->o.c_boolean)
+		return sprintbuf(pb, "true");
+	else
+		return sprintbuf(pb, "false");
+}
+
+struct json_object* json_object_new_boolean(json_bool b)
+{
+	struct json_object *jso = json_object_new(json_type_boolean);
+	if (!jso)
+		return NULL;
+	jso->_to_json_string = &json_object_boolean_to_json_string;
+	jso->o.c_boolean = b;
+	return jso;
+}
+
+json_bool json_object_get_boolean(struct json_object *jso)
+{
+	if (!jso)
+		return FALSE;
+	switch(jso->o_type)
+	{
+	case json_type_boolean:
+		return jso->o.c_boolean;
+	case json_type_int:
+		return (jso->o.c_int64 != 0);
+	case json_type_double:
+		return (jso->o.c_double != 0);
+	case json_type_string:
+		return (jso->o.c_string.len != 0);
+	default:
+		return FALSE;
+	}
+}
+
+
+/* json_object_int */
+
+static int json_object_int_to_json_string(struct json_object* jso,
+					  struct printbuf *pb,
+					  int level,
+					  int flags)
+{
+	return sprintbuf(pb, "%"PRId64, jso->o.c_int64);
+}
+
+struct json_object* json_object_new_int(int32_t i)
+{
+	struct json_object *jso = json_object_new(json_type_int);
+	if (!jso)
+		return NULL;
+	jso->_to_json_string = &json_object_int_to_json_string;
+	jso->o.c_int64 = i;
+	return jso;
+}
+
+int32_t json_object_get_int(struct json_object *jso)
+{
+  int64_t cint64;
+  enum json_type o_type;
+
+  if(!jso) return 0;
+
+  o_type = jso->o_type;
+  cint64 = jso->o.c_int64;
+
+  if (o_type == json_type_string)
+  {
+	/*
+	 * Parse strings into 64-bit numbers, then use the
+	 * 64-to-32-bit number handling below.
+	 */
+	if (json_parse_int64(jso->o.c_string.str, &cint64) != 0)
+		return 0; /* whoops, it didn't work. */
+	o_type = json_type_int;
+  }
+
+  switch(o_type) {
+  case json_type_int:
+	/* Make sure we return the correct values for out of range numbers. */
+	if (cint64 <= INT32_MIN)
+		return INT32_MIN;
+	else if (cint64 >= INT32_MAX)
+		return INT32_MAX;
+	else
+		return (int32_t)cint64;
+  case json_type_double:
+    return (int32_t)jso->o.c_double;
+  case json_type_boolean:
+    return jso->o.c_boolean;
+  default:
+    return 0;
+  }
+}
+
+struct json_object* json_object_new_int64(int64_t i)
+{
+	struct json_object *jso = json_object_new(json_type_int);
+	if (!jso)
+		return NULL;
+	jso->_to_json_string = &json_object_int_to_json_string;
+	jso->o.c_int64 = i;
+	return jso;
+}
+
+int64_t json_object_get_int64(struct json_object *jso)
+{
+	int64_t cint;
+
+	if (!jso)
+		return 0;
+	switch(jso->o_type)
+	{
+	case json_type_int:
+		return jso->o.c_int64;
+	case json_type_double:
+		return (int64_t)jso->o.c_double;
+	case json_type_boolean:
+		return jso->o.c_boolean;
+	case json_type_string:
+		if (json_parse_int64(jso->o.c_string.str, &cint) == 0)
+			return cint;
+	default:
+		return 0;
+	}
+}
+
+
+/* json_object_double */
+
+static int json_object_double_to_json_string(struct json_object* jso,
+					     struct printbuf *pb,
+					     int level,
+						 int flags)
+{
+  char buf[128], *p, *q;
+  int size;
+  /* Although JSON RFC does not support
+     NaN or Infinity as numeric values
+     ECMA 262 section 9.8.1 defines
+     how to handle these cases as strings */
+  if(isnan(jso->o.c_double))
+    size = snprintf(buf, sizeof(buf), "NaN");
+  else if(isinf(jso->o.c_double))
+    if(jso->o.c_double > 0)
+      size = snprintf(buf, sizeof(buf), "Infinity");
+    else
+      size = snprintf(buf, sizeof(buf), "-Infinity");
+  else
+    size = snprintf(buf, sizeof(buf), "%.17g", jso->o.c_double);
+
+  p = strchr(buf, ',');
+  if (p) {
+    *p = '.';
+  } else {
+    p = strchr(buf, '.');
+  }
+  if (p && (flags & JSON_C_TO_STRING_NOZERO)) {
+    /* last useful digit, always keep 1 zero */
+    p++;
+    for (q=p ; *q ; q++) {
+      if (*q!='0') p=q;
+    }
+    /* drop trailing zeroes */
+    *(++p) = 0;
+    size = p-buf;
+  }
+  printbuf_memappend(pb, buf, size);
+  return size;
+}
+
+struct json_object* json_object_new_double(double d)
+{
+	struct json_object *jso = json_object_new(json_type_double);
+	if (!jso)
+		return NULL;
+	jso->_to_json_string = &json_object_double_to_json_string;
+	jso->o.c_double = d;
+	return jso;
+}
+
+struct json_object* json_object_new_double_s(double d, const char *ds)
+{
+	struct json_object *jso = json_object_new_double(d);
+	if (!jso)
+		return NULL;
+
+	char *new_ds = strdup(ds);
+	if (!new_ds)
+	{
+		json_object_generic_delete(jso);
+		errno = ENOMEM;
+		return NULL;
+	}
+	json_object_set_serializer(jso, json_object_userdata_to_json_string,
+	    new_ds, json_object_free_userdata);
+	return jso;
+}
+
+int json_object_userdata_to_json_string(struct json_object *jso,
+	struct printbuf *pb, int level, int flags)
+{
+	int userdata_len = strlen(jso->_userdata);
+	printbuf_memappend(pb, jso->_userdata, userdata_len);
+	return userdata_len;
+}
+
+void json_object_free_userdata(struct json_object *jso, void *userdata)
+{
+	free(userdata);
+}
+
+double json_object_get_double(struct json_object *jso)
+{
+  double cdouble;
+  char *errPtr = NULL;
+
+  if(!jso) return 0.0;
+  switch(jso->o_type) {
+  case json_type_double:
+    return jso->o.c_double;
+  case json_type_int:
+    return jso->o.c_int64;
+  case json_type_boolean:
+    return jso->o.c_boolean;
+  case json_type_string:
+    errno = 0;
+    cdouble = strtod(jso->o.c_string.str,&errPtr);
+
+    /* if conversion stopped at the first character, return 0.0 */
+    if (errPtr == jso->o.c_string.str)
+        return 0.0;
+
+    /*
+     * Check that the conversion terminated on something sensible
+     *
+     * For example, { "pay" : 123AB } would parse as 123.
+     */
+    if (*errPtr != '\0')
+        return 0.0;
+
+    /*
+     * If strtod encounters a string which would exceed the
+     * capacity of a double, it returns +/- HUGE_VAL and sets
+     * errno to ERANGE. But +/- HUGE_VAL is also a valid result
+     * from a conversion, so we need to check errno.
+     *
+     * Underflow also sets errno to ERANGE, but it returns 0 in
+     * that case, which is what we will return anyway.
+     *
+     * See CERT guideline ERR30-C
+     */
+    if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) &&
+        (ERANGE == errno))
+            cdouble = 0.0;
+    return cdouble;
+  default:
+    return 0.0;
+  }
+}
+
+
+/* json_object_string */
+
+static int json_object_string_to_json_string(struct json_object* jso,
+					     struct printbuf *pb,
+					     int level,
+						 int flags)
+{
+	sprintbuf(pb, "\"");
+	json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len);
+	sprintbuf(pb, "\"");
+	return 0;
+}
+
+static void json_object_string_delete(struct json_object* jso)
+{
+	free(jso->o.c_string.str);
+	json_object_generic_delete(jso);
+}
+
+struct json_object* json_object_new_string(const char *s)
+{
+	struct json_object *jso = json_object_new(json_type_string);
+	if (!jso)
+		return NULL;
+	jso->_delete = &json_object_string_delete;
+	jso->_to_json_string = &json_object_string_to_json_string;
+	jso->o.c_string.str = strdup(s);
+	if (!jso->o.c_string.str)
+	{
+		json_object_generic_delete(jso);
+		errno = ENOMEM;
+		return NULL;
+	}
+	jso->o.c_string.len = strlen(s);
+	return jso;
+}
+
+struct json_object* json_object_new_string_len(const char *s, int len)
+{
+	struct json_object *jso = json_object_new(json_type_string);
+	if (!jso)
+		return NULL;
+	jso->_delete = &json_object_string_delete;
+	jso->_to_json_string = &json_object_string_to_json_string;
+	jso->o.c_string.str = (char*)malloc(len + 1);
+	if (!jso->o.c_string.str)
+	{
+		json_object_generic_delete(jso);
+		errno = ENOMEM;
+		return NULL;
+	}
+	memcpy(jso->o.c_string.str, (void *)s, len);
+	jso->o.c_string.str[len] = '\0';
+	jso->o.c_string.len = len;
+	return jso;
+}
+
+const char* json_object_get_string(struct json_object *jso)
+{
+	if (!jso)
+		return NULL;
+	switch(jso->o_type)
+	{
+	case json_type_string:
+		return jso->o.c_string.str;
+	default:
+		return json_object_to_json_string(jso);
+	}
+}
+
+int json_object_get_string_len(struct json_object *jso)
+{
+	if (!jso)
+		return 0;
+	switch(jso->o_type)
+	{
+	case json_type_string:
+		return jso->o.c_string.len;
+	default:
+		return 0;
+	}
+}
+
+
+/* json_object_array */
+
+static int json_object_array_to_json_string(struct json_object* jso,
+                                            struct printbuf *pb,
+                                            int level,
+                                            int flags)
+{
+	int had_children = 0;
+	int ii;
+	sprintbuf(pb, "[");
+	if (flags & JSON_C_TO_STRING_PRETTY)
+		sprintbuf(pb, "\n");
+	for(ii=0; ii < json_object_array_length(jso); ii++)
+	{
+		struct json_object *val;
+		if (had_children)
+		{
+			sprintbuf(pb, ",");
+			if (flags & JSON_C_TO_STRING_PRETTY)
+				sprintbuf(pb, "\n");
+		}
+		had_children = 1;
+		if (flags & JSON_C_TO_STRING_SPACED)
+			sprintbuf(pb, " ");
+		indent(pb, level + 1, flags);
+		val = json_object_array_get_idx(jso, ii);
+		if(val == NULL)
+			sprintbuf(pb, "null");
+		else
+			val->_to_json_string(val, pb, level+1, flags);
+	}
+	if (flags & JSON_C_TO_STRING_PRETTY)
+	{
+		if (had_children)
+			sprintbuf(pb, "\n");
+		indent(pb,level,flags);
+	}
+
+	if (flags & JSON_C_TO_STRING_SPACED)
+		return sprintbuf(pb, " ]");
+	else
+		return sprintbuf(pb, "]");
+}
+
+static void json_object_array_entry_free(void *data)
+{
+	json_object_put((struct json_object*)data);
+}
+
+static void json_object_array_delete(struct json_object* jso)
+{
+	array_list_free(jso->o.c_array);
+	json_object_generic_delete(jso);
+}
+
+struct json_object* json_object_new_array(void)
+{
+	struct json_object *jso = json_object_new(json_type_array);
+	if (!jso)
+		return NULL;
+	jso->_delete = &json_object_array_delete;
+	jso->_to_json_string = &json_object_array_to_json_string;
+	jso->o.c_array = array_list_new(&json_object_array_entry_free);
+	return jso;
+}
+
+struct array_list* json_object_get_array(struct json_object *jso)
+{
+	if (!jso)
+		return NULL;
+	switch(jso->o_type)
+	{
+	case json_type_array:
+		return jso->o.c_array;
+	default:
+		return NULL;
+	}
+}
+
+void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *))
+{
+	array_list_sort(jso->o.c_array, sort_fn);
+}
+
+int json_object_array_length(struct json_object *jso)
+{
+	return array_list_length(jso->o.c_array);
+}
+
+int json_object_array_add(struct json_object *jso,struct json_object *val)
+{
+	return array_list_add(jso->o.c_array, val);
+}
+
+int json_object_array_put_idx(struct json_object *jso, int idx,
+			      struct json_object *val)
+{
+	return array_list_put_idx(jso->o.c_array, idx, val);
+}
+
+struct json_object* json_object_array_get_idx(struct json_object *jso,
+					      int idx)
+{
+	return (struct json_object*)array_list_get_idx(jso->o.c_array, idx);
+}
+
diff --git a/json-c/json_object.h b/json-c/json_object.h
new file mode 100644
index 0000000..0dca0b1
--- /dev/null
+++ b/json-c/json_object.h
@@ -0,0 +1,617 @@
+/*
+ * $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _json_object_h_
+#define _json_object_h_
+
+#ifdef __GNUC__
+#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
+#elif defined(_MSC_VER)
+#define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func
+#else
+#define THIS_FUNCTION_IS_DEPRECATED(func) func
+#endif
+
+#include "json_inttypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define JSON_OBJECT_DEF_HASH_ENTRIES 16
+
+/**
+ * A flag for the json_object_to_json_string_ext() and
+ * json_object_to_file_ext() functions which causes the output
+ * to have no extra whitespace or formatting applied.
+ */
+#define JSON_C_TO_STRING_PLAIN      0
+/**
+ * A flag for the json_object_to_json_string_ext() and
+ * json_object_to_file_ext() functions which causes the output to have
+ * minimal whitespace inserted to make things slightly more readable.
+ */
+#define JSON_C_TO_STRING_SPACED     (1<<0)
+/**
+ * A flag for the json_object_to_json_string_ext() and
+ * json_object_to_file_ext() functions which causes
+ * the output to be formatted.
+ *
+ * See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/
+ * for an example of the format.
+ */
+#define JSON_C_TO_STRING_PRETTY     (1<<1)
+/**
+ * A flag to drop trailing zero for float values
+ */
+#define JSON_C_TO_STRING_NOZERO     (1<<2)
+
+#undef FALSE
+#define FALSE ((json_bool)0)
+
+#undef TRUE
+#define TRUE ((json_bool)1)
+
+extern const char *json_number_chars;
+extern const char *json_hex_chars;
+
+/* CAW: added for ANSI C iteration correctness */
+struct json_object_iter
+{
+	char *key;
+	struct json_object *val;
+	struct lh_entry *entry;
+};
+
+/* forward structure definitions */
+
+typedef int json_bool;
+typedef struct printbuf printbuf;
+typedef struct lh_table lh_table;
+typedef struct array_list array_list;
+typedef struct json_object json_object;
+typedef struct json_object_iter json_object_iter;
+typedef struct json_tokener json_tokener;
+
+/**
+ * Type of custom user delete functions.  See json_object_set_serializer.
+ */
+typedef void (json_object_delete_fn)(struct json_object *jso, void *userdata);
+
+/**
+ * Type of a custom serialization function.  See json_object_set_serializer.
+ */
+typedef int (json_object_to_json_string_fn)(struct json_object *jso,
+						struct printbuf *pb,
+						int level,
+						int flags);
+
+/* supported object types */
+
+typedef enum json_type {
+  /* If you change this, be sure to update json_type_to_name() too */
+  json_type_null,
+  json_type_boolean,
+  json_type_double,
+  json_type_int,
+  json_type_object,
+  json_type_array,
+  json_type_string
+} json_type;
+
+/* reference counting functions */
+
+/**
+ * Increment the reference count of json_object, thereby grabbing shared 
+ * ownership of obj.
+ *
+ * @param obj the json_object instance
+ */
+extern struct json_object* json_object_get(struct json_object *obj);
+
+/**
+ * Decrement the reference count of json_object and free if it reaches zero.
+ * You must have ownership of obj prior to doing this or you will cause an
+ * imbalance in the reference count.
+ *
+ * @param obj the json_object instance
+ * @returns 1 if the object was freed.
+ */
+int json_object_put(struct json_object *obj);
+
+/**
+ * Check if the json_object is of a given type
+ * @param obj the json_object instance
+ * @param type one of:
+     json_type_null (i.e. obj == NULL),
+     json_type_boolean,
+     json_type_double,
+     json_type_int,
+     json_type_object,
+     json_type_array,
+     json_type_string
+ */
+extern int json_object_is_type(struct json_object *obj, enum json_type type);
+
+/**
+ * Get the type of the json_object.  See also json_type_to_name() to turn this
+ * into a string suitable, for instance, for logging.
+ *
+ * @param obj the json_object instance
+ * @returns type being one of:
+     json_type_null (i.e. obj == NULL),
+     json_type_boolean,
+     json_type_double,
+     json_type_int,
+     json_type_object,
+     json_type_array,
+     json_type_string
+ */
+extern enum json_type json_object_get_type(struct json_object *obj);
+
+
+/** Stringify object to json format.
+ * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED)
+ * The pointer you get is an internal of your json object. You don't
+ * have to free it, later use of json_object_put() should be sufficient.
+ * If you can not ensure there's no concurrent access to *obj use
+ * strdup().
+ * @param obj the json_object instance
+ * @returns a string in JSON format
+ */
+extern const char* json_object_to_json_string(struct json_object *obj);
+
+/** Stringify object to json format
+ * @see json_object_to_json_string() for details on how to free string.
+ * @param obj the json_object instance
+ * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants
+ * @returns a string in JSON format
+ */
+extern const char* json_object_to_json_string_ext(struct json_object *obj, int
+flags);
+
+/**
+ * Set a custom serialization function to be used when this particular object
+ * is converted to a string by json_object_to_json_string.
+ *
+ * If a custom serializer is already set on this object, any existing 
+ * user_delete function is called before the new one is set.
+ *
+ * If to_string_func is NULL, the other parameters are ignored
+ * and the default behaviour is reset.
+ *
+ * The userdata parameter is optional and may be passed as NULL.  If provided,
+ * it is passed to to_string_func as-is.  This parameter may be NULL even
+ * if user_delete is non-NULL.
+ *
+ * The user_delete parameter is optional and may be passed as NULL, even if
+ * the userdata parameter is non-NULL.  It will be called just before the
+ * json_object is deleted, after it's reference count goes to zero
+ * (see json_object_put()).
+ * If this is not provided, it is up to the caller to free the userdata at
+ * an appropriate time. (i.e. after the json_object is deleted)
+ *
+ * @param jso the object to customize
+ * @param to_string_func the custom serialization function
+ * @param userdata an optional opaque cookie
+ * @param user_delete an optional function from freeing userdata
+ */
+extern void json_object_set_serializer(json_object *jso,
+	json_object_to_json_string_fn to_string_func,
+	void *userdata,
+	json_object_delete_fn *user_delete);
+
+/**
+ * Simply call free on the userdata pointer.
+ * Can be used with json_object_set_serializer().
+ *
+ * @param jso unused
+ * @param userdata the pointer that is passed to free().
+ */
+json_object_delete_fn json_object_free_userdata;
+
+/**
+ * Copy the jso->_userdata string over to pb as-is.
+ * Can be used with json_object_set_serializer().
+ *
+ * @param jso The object whose _userdata is used.
+ * @param pb The destination buffer.
+ * @param level Ignored.
+ * @param flags Ignored.
+ */
+json_object_to_json_string_fn json_object_userdata_to_json_string;
+
+
+/* object type methods */
+
+/** Create a new empty object with a reference count of 1.  The caller of
+ * this object initially has sole ownership.  Remember, when using
+ * json_object_object_add or json_object_array_put_idx, ownership will
+ * transfer to the object/array.  Call json_object_get if you want to maintain
+ * shared ownership or also add this object as a child of multiple objects or
+ * arrays.  Any ownerships you acquired but did not transfer must be released
+ * through json_object_put.
+ *
+ * @returns a json_object of type json_type_object
+ */
+extern struct json_object* json_object_new_object(void);
+
+/** Get the hashtable of a json_object of type json_type_object
+ * @param obj the json_object instance
+ * @returns a linkhash
+ */
+extern struct lh_table* json_object_get_object(struct json_object *obj);
+
+/** Get the size of an object in terms of the number of fields it has.
+ * @param obj the json_object whose length to return
+ */
+extern int json_object_object_length(struct json_object* obj);
+
+/** Add an object field to a json_object of type json_type_object
+ *
+ * The reference count will *not* be incremented. This is to make adding
+ * fields to objects in code more compact. If you want to retain a reference
+ * to an added object, independent of the lifetime of obj, you must wrap the
+ * passed object with json_object_get.
+ *
+ * Upon calling this, the ownership of val transfers to obj.  Thus you must
+ * make sure that you do in fact have ownership over this object.  For instance,
+ * json_object_new_object will give you ownership until you transfer it,
+ * whereas json_object_object_get does not.
+ *
+ * @param obj the json_object instance
+ * @param key the object field name (a private copy will be duplicated)
+ * @param val a json_object or NULL member to associate with the given field
+ */
+extern void json_object_object_add(struct json_object* obj, const char *key,
+				   struct json_object *val);
+
+/** Get the json_object associate with a given object field
+ *
+ * *No* reference counts will be changed.  There is no need to manually adjust
+ * reference counts through the json_object_put/json_object_get methods unless
+ * you need to have the child (value) reference maintain a different lifetime
+ * than the owning parent (obj). Ownership of the returned value is retained
+ * by obj (do not do json_object_put unless you have done a json_object_get).
+ * If you delete the value from obj (json_object_object_del) and wish to access
+ * the returned reference afterwards, make sure you have first gotten shared
+ * ownership through json_object_get (& don't forget to do a json_object_put
+ * or transfer ownership to prevent a memory leak).
+ *
+ * @param obj the json_object instance
+ * @param key the object field name
+ * @returns the json_object associated with the given field name
+ * @deprecated Please use json_object_object_get_ex
+ */
+THIS_FUNCTION_IS_DEPRECATED(extern struct json_object* json_object_object_get(struct json_object* obj,
+						  const char *key));
+
+/** Get the json_object associated with a given object field.  
+ *
+ * This returns true if the key is found, false in all other cases (including 
+ * if obj isn't a json_type_object).
+ *
+ * *No* reference counts will be changed.  There is no need to manually adjust
+ * reference counts through the json_object_put/json_object_get methods unless
+ * you need to have the child (value) reference maintain a different lifetime
+ * than the owning parent (obj).  Ownership of value is retained by obj.
+ *
+ * @param obj the json_object instance
+ * @param key the object field name
+ * @param value a pointer where to store a reference to the json_object 
+ *              associated with the given field name.
+ *
+ *              It is safe to pass a NULL value.
+ * @returns whether or not the key exists
+ */
+extern json_bool json_object_object_get_ex(struct json_object* obj,
+						  const char *key,
+                                                  struct json_object **value);
+
+/** Delete the given json_object field
+ *
+ * The reference count will be decremented for the deleted object.  If there
+ * are no more owners of the value represented by this key, then the value is
+ * freed.  Otherwise, the reference to the value will remain in memory.
+ *
+ * @param obj the json_object instance
+ * @param key the object field name
+ */
+extern void json_object_object_del(struct json_object* obj, const char *key);
+
+/**
+ * Iterate through all keys and values of an object.
+ *
+ * Adding keys to the object while iterating is NOT allowed.
+ *
+ * Deleting an existing key, or replacing an existing key with a
+ * new value IS allowed.
+ *
+ * @param obj the json_object instance
+ * @param key the local name for the char* key variable defined in the body
+ * @param val the local name for the json_object* object variable defined in
+ *            the body
+ */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L
+
+# define json_object_object_foreach(obj,key,val) \
+	char *key; \
+	struct json_object *val __attribute__((__unused__)); \
+	for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \
+		({ if(entry ## key) { \
+			key = (char*)entry ## key->k; \
+			val = (struct json_object*)entry ## key->v; \
+			entry_next ## key = entry ## key->next; \
+		} ; entry ## key; }); \
+		entry ## key = entry_next ## key )
+
+#else /* ANSI C or MSC */
+
+# define json_object_object_foreach(obj,key,val) \
+	char *key;\
+	struct json_object *val; \
+	struct lh_entry *entry ## key; \
+	struct lh_entry *entry_next ## key = NULL; \
+	for(entry ## key = json_object_get_object(obj)->head; \
+		(entry ## key ? ( \
+			key = (char*)entry ## key->k, \
+			val = (struct json_object*)entry ## key->v, \
+			entry_next ## key = entry ## key->next, \
+			entry ## key) : 0); \
+		entry ## key = entry_next ## key)
+
+#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */
+
+/** Iterate through all keys and values of an object (ANSI C Safe)
+ * @param obj the json_object instance
+ * @param iter the object iterator
+ */
+#define json_object_object_foreachC(obj,iter) \
+ for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next)
+
+/* Array type methods */
+
+/** Create a new empty json_object of type json_type_array
+ * @returns a json_object of type json_type_array
+ */
+extern struct json_object* json_object_new_array(void);
+
+/** Get the arraylist of a json_object of type json_type_array
+ * @param obj the json_object instance
+ * @returns an arraylist
+ */
+extern struct array_list* json_object_get_array(struct json_object *obj);
+
+/** Get the length of a json_object of type json_type_array
+ * @param obj the json_object instance
+ * @returns an int
+ */
+extern int json_object_array_length(struct json_object *obj);
+
+/** Sorts the elements of jso of type json_type_array
+*
+* Pointers to the json_object pointers will be passed as the two arguments
+* to @sort_fn
+*
+* @param obj the json_object instance
+* @param sort_fn a sorting function
+*/
+extern void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *));
+
+/** Add an element to the end of a json_object of type json_type_array
+ *
+ * The reference count will *not* be incremented. This is to make adding
+ * fields to objects in code more compact. If you want to retain a reference
+ * to an added object you must wrap the passed object with json_object_get
+ *
+ * @param obj the json_object instance
+ * @param val the json_object to be added
+ */
+extern int json_object_array_add(struct json_object *obj,
+				 struct json_object *val);
+
+/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array)
+ *
+ * The reference count will *not* be incremented. This is to make adding
+ * fields to objects in code more compact. If you want to retain a reference
+ * to an added object you must wrap the passed object with json_object_get
+ *
+ * The reference count of a replaced object will be decremented.
+ *
+ * The array size will be automatically be expanded to the size of the
+ * index if the index is larger than the current size.
+ *
+ * @param obj the json_object instance
+ * @param idx the index to insert the element at
+ * @param val the json_object to be added
+ */
+extern int json_object_array_put_idx(struct json_object *obj, int idx,
+				     struct json_object *val);
+
+/** Get the element at specificed index of the array (a json_object of type json_type_array)
+ * @param obj the json_object instance
+ * @param idx the index to get the element at
+ * @returns the json_object at the specified index (or NULL)
+ */
+extern struct json_object* json_object_array_get_idx(struct json_object *obj,
+						     int idx);
+
+/* json_bool type methods */
+
+/** Create a new empty json_object of type json_type_boolean
+ * @param b a json_bool TRUE or FALSE (0 or 1)
+ * @returns a json_object of type json_type_boolean
+ */
+extern struct json_object* json_object_new_boolean(json_bool b);
+
+/** Get the json_bool value of a json_object
+ *
+ * The type is coerced to a json_bool if the passed object is not a json_bool.
+ * integer and double objects will return FALSE if there value is zero
+ * or TRUE otherwise. If the passed object is a string it will return
+ * TRUE if it has a non zero length. If any other object type is passed
+ * TRUE will be returned if the object is not NULL.
+ *
+ * @param obj the json_object instance
+ * @returns a json_bool
+ */
+extern json_bool json_object_get_boolean(struct json_object *obj);
+
+
+/* int type methods */
+
+/** Create a new empty json_object of type json_type_int
+ * Note that values are stored as 64-bit values internally.
+ * To ensure the full range is maintained, use json_object_new_int64 instead.
+ * @param i the integer
+ * @returns a json_object of type json_type_int
+ */
+extern struct json_object* json_object_new_int(int32_t i);
+
+
+/** Create a new empty json_object of type json_type_int
+ * @param i the integer
+ * @returns a json_object of type json_type_int
+ */
+extern struct json_object* json_object_new_int64(int64_t i);
+
+
+/** Get the int value of a json_object
+ *
+ * The type is coerced to a int if the passed object is not a int.
+ * double objects will return their integer conversion. Strings will be
+ * parsed as an integer. If no conversion exists then 0 is returned
+ * and errno is set to EINVAL. null is equivalent to 0 (no error values set)
+ *
+ * Note that integers are stored internally as 64-bit values.
+ * If the value of too big or too small to fit into 32-bit, INT32_MAX or
+ * INT32_MIN are returned, respectively.
+ *
+ * @param obj the json_object instance
+ * @returns an int
+ */
+extern int32_t json_object_get_int(struct json_object *obj);
+
+/** Get the int value of a json_object
+ *
+ * The type is coerced to a int64 if the passed object is not a int64.
+ * double objects will return their int64 conversion. Strings will be
+ * parsed as an int64. If no conversion exists then 0 is returned.
+ *
+ * NOTE: Set errno to 0 directly before a call to this function to determine
+ * whether or not conversion was successful (it does not clear the value for
+ * you).
+ *
+ * @param obj the json_object instance
+ * @returns an int64
+ */
+extern int64_t json_object_get_int64(struct json_object *obj);
+
+
+/* double type methods */
+
+/** Create a new empty json_object of type json_type_double
+ * @param d the double
+ * @returns a json_object of type json_type_double
+ */
+extern struct json_object* json_object_new_double(double d);
+
+/**
+ * Create a new json_object of type json_type_double, using
+ * the exact serialized representation of the value.
+ *
+ * This allows for numbers that would otherwise get displayed
+ * inefficiently (e.g. 12.3 => "12.300000000000001") to be
+ * serialized with the more convenient form.
+ *
+ * Note: this is used by json_tokener_parse_ex() to allow for
+ *   an exact re-serialization of a parsed object.
+ *
+ * An equivalent sequence of calls is:
+ * @code
+ *   jso = json_object_new_double(d);
+ *   json_object_set_serializer(d, json_object_userdata_to_json_string,
+ *       strdup(ds), json_object_free_userdata)
+ * @endcode
+ *
+ * @param d the numeric value of the double.
+ * @param ds the string representation of the double.  This will be copied.
+ */
+extern struct json_object* json_object_new_double_s(double d, const char *ds);
+
+/** Get the double floating point value of a json_object
+ *
+ * The type is coerced to a double if the passed object is not a double.
+ * integer objects will return their double conversion. Strings will be
+ * parsed as a double. If no conversion exists then 0.0 is returned and
+ * errno is set to EINVAL. null is equivalent to 0 (no error values set)
+ *
+ * If the value is too big to fit in a double, then the value is set to
+ * the closest infinity with errno set to ERANGE. If strings cannot be
+ * converted to their double value, then EINVAL is set & NaN is returned.
+ *
+ * Arrays of length 0 are interpreted as 0 (with no error flags set).
+ * Arrays of length 1 are effectively cast to the equivalent object and
+ * converted using the above rules.  All other arrays set the error to
+ * EINVAL & return NaN.
+ *
+ * NOTE: Set errno to 0 directly before a call to this function to
+ * determine whether or not conversion was successful (it does not clear
+ * the value for you).
+ *
+ * @param obj the json_object instance
+ * @returns a double floating point number
+ */
+extern double json_object_get_double(struct json_object *obj);
+
+
+/* string type methods */
+
+/** Create a new empty json_object of type json_type_string
+ *
+ * A copy of the string is made and the memory is managed by the json_object
+ *
+ * @param s the string
+ * @returns a json_object of type json_type_string
+ */
+extern struct json_object* json_object_new_string(const char *s);
+
+extern struct json_object* json_object_new_string_len(const char *s, int len);
+
+/** Get the string value of a json_object
+ *
+ * If the passed object is not of type json_type_string then the JSON
+ * representation of the object is returned.
+ *
+ * The returned string memory is managed by the json_object and will
+ * be freed when the reference count of the json_object drops to zero.
+ *
+ * @param obj the json_object instance
+ * @returns a string
+ */
+extern const char* json_object_get_string(struct json_object *obj);
+
+/** Get the string length of a json_object
+ *
+ * If the passed object is not of type json_type_string then zero
+ * will be returned.
+ *
+ * @param obj the json_object instance
+ * @returns int
+ */
+extern int json_object_get_string_len(struct json_object *obj);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/json_object_iterator.c b/json-c/json_object_iterator.c
new file mode 100644
index 0000000..7066649
--- /dev/null
+++ b/json-c/json_object_iterator.c
@@ -0,0 +1,168 @@
+/**
+*******************************************************************************
+* @file json_object_iterator.c
+*
+* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
+*
+* This library is free software; you can redistribute it and/or modify
+* it under the terms of the MIT license. See COPYING for details.
+*
+* @brief  json-c forces clients to use its private data
+*         structures for JSON Object iteration.  This API
+*         implementation corrects that by abstracting the
+*         private json-c details.
+*
+*******************************************************************************
+*/
+
+#include <stddef.h>
+
+#include "json.h"
+#include "json_object_private.h"
+
+#include "json_object_iterator.h"
+
+/**
+ * How It Works
+ *
+ * For each JSON Object, json-c maintains a linked list of zero
+ * or more lh_entry (link-hash entry) structures inside the
+ * Object's link-hash table (lh_table).
+ *
+ * Each lh_entry structure on the JSON Object's linked list
+ * represents a single name/value pair.  The "next" field of the
+ * last lh_entry in the list is set to NULL, which terminates
+ * the list.
+ *
+ * We represent a valid iterator that refers to an actual
+ * name/value pair via a pointer to the pair's lh_entry
+ * structure set as the iterator's opaque_ field.
+ *
+ * We follow json-c's current pair list representation by
+ * representing a valid "end" iterator (one that refers past the
+ * last pair) with a NULL value in the iterator's opaque_ field.
+ *
+ * A JSON Object without any pairs in it will have the "head"
+ * field of its lh_table structure set to NULL.  For such an
+ * object, json_object_iter_begin will return an iterator with
+ * the opaque_ field set to NULL, which is equivalent to the
+ * "end" iterator.
+ *
+ * When iterating, we simply update the iterator's opaque_ field
+ * to point to the next lh_entry structure in the linked list.
+ * opaque_ will become NULL once we iterate past the last pair
+ * in the list, which makes the iterator equivalent to the "end"
+ * iterator.
+ */
+
+/// Our current representation of the "end" iterator;
+///
+/// @note May not always be NULL
+static const void* kObjectEndIterValue = NULL;
+
+/**
+ * ****************************************************************************
+ */
+struct json_object_iterator
+json_object_iter_begin(struct json_object* obj)
+{
+    struct json_object_iterator iter;
+    struct lh_table* pTable;
+
+    /// @note json_object_get_object will return NULL if passed NULL
+    ///       or a non-json_type_object instance
+    pTable = json_object_get_object(obj);
+    JASSERT(NULL != pTable);
+
+    /// @note For a pair-less Object, head is NULL, which matches our
+    ///       definition of the "end" iterator
+    iter.opaque_ = pTable->head;
+    return iter;
+}
+
+/**
+ * ****************************************************************************
+ */
+struct json_object_iterator
+json_object_iter_end(const struct json_object* obj)
+{
+    struct json_object_iterator iter;
+
+    JASSERT(NULL != obj);
+    JASSERT(json_object_is_type(obj, json_type_object));
+
+    iter.opaque_ = kObjectEndIterValue;
+
+    return iter;
+}
+
+/**
+ * ****************************************************************************
+ */
+void
+json_object_iter_next(struct json_object_iterator* iter)
+{
+    JASSERT(NULL != iter);
+    JASSERT(kObjectEndIterValue != iter->opaque_);
+
+    iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next;
+}
+
+
+/**
+ * ****************************************************************************
+ */
+const char*
+json_object_iter_peek_name(const struct json_object_iterator* iter)
+{
+    JASSERT(NULL != iter);
+    JASSERT(kObjectEndIterValue != iter->opaque_);
+
+    return (const char*)(((struct lh_entry *)iter->opaque_)->k);
+}
+
+
+/**
+ * ****************************************************************************
+ */
+struct json_object*
+json_object_iter_peek_value(const struct json_object_iterator* iter)
+{
+    JASSERT(NULL != iter);
+    JASSERT(kObjectEndIterValue != iter->opaque_);
+
+    return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v);
+}
+
+
+/**
+ * ****************************************************************************
+ */
+json_bool
+json_object_iter_equal(const struct json_object_iterator* iter1,
+                       const struct json_object_iterator* iter2)
+{
+    JASSERT(NULL != iter1);
+    JASSERT(NULL != iter2);
+
+    return (iter1->opaque_ == iter2->opaque_);
+}
+
+
+/**
+ * ****************************************************************************
+ */
+struct json_object_iterator
+json_object_iter_init_default(void)
+{
+    struct json_object_iterator iter;
+
+    /**
+     * @note Make this a negative, invalid value, such that
+     *       accidental access to it would likely be trapped by the
+     *       hardware as an invalid address.
+     */
+    iter.opaque_ = NULL;
+
+    return iter;
+}
diff --git a/json-c/json_object_iterator.h b/json-c/json_object_iterator.h
new file mode 100644
index 0000000..44c9fb2
--- /dev/null
+++ b/json-c/json_object_iterator.h
@@ -0,0 +1,239 @@
+/**
+*******************************************************************************
+* @file json_object_iterator.h
+*
+* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
+*
+* This library is free software; you can redistribute it and/or modify
+* it under the terms of the MIT license. See COPYING for details.
+*
+* @brief  json-c forces clients to use its private data
+*         structures for JSON Object iteration.  This API
+*         corrects that by abstracting the private json-c
+*         details.
+*
+* API attributes: <br>
+*   * Thread-safe: NO<br>
+*   * Reentrant: NO
+*
+*******************************************************************************
+*/
+
+
+#ifndef JSON_OBJECT_ITERATOR_H
+#define JSON_OBJECT_ITERATOR_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Forward declaration for the opaque iterator information.
+ */
+struct json_object_iter_info_;
+
+/**
+ * The opaque iterator that references a name/value pair within
+ * a JSON Object instance or the "end" iterator value.
+ */
+struct json_object_iterator {
+    const void* opaque_;
+};
+
+
+/**
+ * forward declaration of json-c's JSON value instance structure
+ */
+struct json_object;
+
+
+/**
+ * Initializes an iterator structure to a "default" value that
+ * is convenient for initializing an iterator variable to a
+ * default state (e.g., initialization list in a class'
+ * constructor).
+ *
+ * @code
+ * struct json_object_iterator iter = json_object_iter_init_default();
+ * MyClass() : iter_(json_object_iter_init_default())
+ * @endcode
+ *
+ * @note The initialized value doesn't reference any specific
+ *       pair, is considered an invalid iterator, and MUST NOT
+ *       be passed to any json-c API that expects a valid
+ *       iterator.
+ *
+ * @note User and internal code MUST NOT make any assumptions
+ *       about and dependencies on the value of the "default"
+ *       iterator value.
+ *
+ * @return json_object_iterator
+ */
+struct json_object_iterator
+json_object_iter_init_default(void);
+
+/** Retrieves an iterator to the first pair of the JSON Object.
+ *
+ * @warning 	Any modification of the underlying pair invalidates all
+ * 		iterators to that pair.
+ *
+ * @param obj	JSON Object instance (MUST be of type json_object)
+ *
+ * @return json_object_iterator If the JSON Object has at
+ *              least one pair, on return, the iterator refers
+ *              to the first pair. If the JSON Object doesn't
+ *              have any pairs, the returned iterator is
+ *              equivalent to the "end" iterator for the same
+ *              JSON Object instance.
+ *
+ * @code
+ * struct json_object_iterator it;
+ * struct json_object_iterator itEnd;
+ * struct json_object* obj;
+ *
+ * obj = json_tokener_parse("{'first':'george', 'age':100}");
+ * it = json_object_iter_begin(obj);
+ * itEnd = json_object_iter_end(obj);
+ *
+ * while (!json_object_iter_equal(&it, &itEnd)) {
+ *     printf("%s\n",
+ *            json_object_iter_peek_name(&it));
+ *     json_object_iter_next(&it);
+ * }
+ *
+ * @endcode
+ */
+struct json_object_iterator
+json_object_iter_begin(struct json_object* obj);
+
+/** Retrieves the iterator that represents the position beyond the
+ *  last pair of the given JSON Object instance.
+ *
+ *  @warning Do NOT write code that assumes that the "end"
+ *        iterator value is NULL, even if it is so in a
+ *        particular instance of the implementation.
+ *
+ *  @note The reason we do not (and MUST NOT) provide
+ *        "json_object_iter_is_end(json_object_iterator* iter)"
+ *        type of API is because it would limit the underlying
+ *        representation of name/value containment (or force us
+ *        to add additional, otherwise unnecessary, fields to
+ *        the iterator structure). The "end" iterator and the
+ *        equality test method, on the other hand, permit us to
+ *        cleanly abstract pretty much any reasonable underlying
+ *        representation without burdening the iterator
+ *        structure with unnecessary data.
+ *
+ *  @note For performance reasons, memorize the "end" iterator prior
+ *        to any loop.
+ *
+ * @param obj JSON Object instance (MUST be of type json_object)
+ *
+ * @return json_object_iterator On return, the iterator refers
+ *              to the "end" of the Object instance's pairs
+ *              (i.e., NOT the last pair, but "beyond the last
+ *              pair" value)
+ */
+struct json_object_iterator
+json_object_iter_end(const struct json_object* obj);
+
+/** Returns an iterator to the next pair, if any
+ *
+ * @warning	Any modification of the underlying pair
+ *       	invalidates all iterators to that pair.
+ *
+ * @param iter [IN/OUT] Pointer to iterator that references a
+ *         name/value pair; MUST be a valid, non-end iterator.
+ *         WARNING: bad things will happen if invalid or "end"
+ *         iterator is passed. Upon return will contain the
+ *         reference to the next pair if there is one; if there
+ *         are no more pairs, will contain the "end" iterator
+ *         value, which may be compared against the return value
+ *         of json_object_iter_end() for the same JSON Object
+ *         instance.
+ */
+void
+json_object_iter_next(struct json_object_iterator* iter);
+
+
+/** Returns a const pointer to the name of the pair referenced
+ *  by the given iterator.
+ *
+ * @param iter pointer to iterator that references a name/value
+ *             pair; MUST be a valid, non-end iterator.
+ *
+ * @warning	bad things will happen if an invalid or
+ *             	"end" iterator is passed.
+ *
+ * @return const char* Pointer to the name of the referenced
+ *         name/value pair.  The name memory belongs to the
+ *         name/value pair, will be freed when the pair is
+ *         deleted or modified, and MUST NOT be modified or
+ *         freed by the user.
+ */
+const char*
+json_object_iter_peek_name(const struct json_object_iterator* iter);
+
+
+/** Returns a pointer to the json-c instance representing the
+ *  value of the referenced name/value pair, without altering
+ *  the instance's reference count.
+ *
+ * @param iter 	pointer to iterator that references a name/value
+ *             	pair; MUST be a valid, non-end iterator.
+ *
+ * @warning	bad things will happen if invalid or
+ *             "end" iterator is passed.
+ *
+ * @return struct json_object* Pointer to the json-c value
+ *         instance of the referenced name/value pair;  the
+ *         value's reference count is not changed by this
+ *         function: if you plan to hold on to this json-c node,
+ *         take a look at json_object_get() and
+ *         json_object_put(). IMPORTANT: json-c API represents
+ *         the JSON Null value as a NULL json_object instance
+ *         pointer.
+ */
+struct json_object*
+json_object_iter_peek_value(const struct json_object_iterator* iter);
+
+
+/** Tests two iterators for equality.  Typically used to test
+ *  for end of iteration by comparing an iterator to the
+ *  corresponding "end" iterator (that was derived from the same
+ *  JSON Object instance).
+ *
+ *  @note The reason we do not (and MUST NOT) provide
+ *        "json_object_iter_is_end(json_object_iterator* iter)"
+ *        type of API is because it would limit the underlying
+ *        representation of name/value containment (or force us
+ *        to add additional, otherwise unnecessary, fields to
+ *        the iterator structure). The equality test method, on
+ *        the other hand, permits us to cleanly abstract pretty
+ *        much any reasonable underlying representation.
+ *
+ * @param iter1 Pointer to first valid, non-NULL iterator
+ * @param iter2 POinter to second valid, non-NULL iterator
+ *
+ * @warning	if a NULL iterator pointer or an uninitialized
+ *       	or invalid iterator, or iterators derived from
+ *       	different JSON Object instances are passed, bad things
+ *       	will happen!
+ *
+ * @return json_bool non-zero if iterators are equal (i.e., both
+ *         reference the same name/value pair or are both at
+ *         "end"); zero if they are not equal.
+ */
+json_bool
+json_object_iter_equal(const struct json_object_iterator* iter1,
+                       const struct json_object_iterator* iter2);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* JSON_OBJECT_ITERATOR_H */
diff --git a/json-c/json_object_private.h b/json-c/json_object_private.h
new file mode 100644
index 0000000..5ed791b
--- /dev/null
+++ b/json-c/json_object_private.h
@@ -0,0 +1,47 @@
+/*
+ * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _json_object_private_h_
+#define _json_object_private_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (json_object_private_delete_fn)(struct json_object *o);
+
+struct json_object
+{
+  enum json_type o_type;
+  json_object_private_delete_fn *_delete;
+  json_object_to_json_string_fn *_to_json_string;
+  int _ref_count;
+  struct printbuf *_pb;
+  union data {
+    json_bool c_boolean;
+    double c_double;
+    int64_t c_int64;
+    struct lh_table *c_object;
+    struct array_list *c_array;
+    struct {
+        char *str;
+        int len;
+    } c_string;
+  } o;
+  json_object_delete_fn *_user_delete;
+  void *_userdata;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/json_tokener.c b/json-c/json_tokener.c
new file mode 100644
index 0000000..60e81f2
--- /dev/null
+++ b/json-c/json_tokener.c
@@ -0,0 +1,887 @@
+/*
+ * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ *
+ * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.
+ * The copyrights to the contents of this file are licensed under the MIT License
+ * (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#include "debug.h"
+#include "printbuf.h"
+#include "arraylist.h"
+#include "json_inttypes.h"
+#include "json_object.h"
+#include "json_tokener.h"
+#include "json_util.h"
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif /* HAVE_LOCALE_H */
+
+#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
+
+#if !HAVE_STRDUP && defined(_MSC_VER)
+  /* MSC has the version as _strdup */
+# define strdup _strdup
+#elif !HAVE_STRDUP
+# error You do not have strdup on your system.
+#endif /* HAVE_STRDUP */
+
+#if !HAVE_STRNCASECMP && defined(_MSC_VER)
+  /* MSC has the version as _strnicmp */
+# define strncasecmp _strnicmp
+#elif !HAVE_STRNCASECMP
+# error You do not have strncasecmp on your system.
+#endif /* HAVE_STRNCASECMP */
+
+/* Use C99 NAN by default; if not available, nan("") should work too. */
+#ifndef NAN
+#define NAN nan("")
+#endif /* !NAN */
+
+static const char json_null_str[] = "null";
+static const int json_null_str_len = sizeof(json_null_str) - 1;
+static const char json_inf_str[] = "Infinity";
+static const int json_inf_str_len = sizeof(json_inf_str) - 1;
+static const char json_nan_str[] = "NaN";
+static const int json_nan_str_len = sizeof(json_nan_str) - 1;
+static const char json_true_str[] = "true";
+static const int json_true_str_len = sizeof(json_true_str) - 1;
+static const char json_false_str[] = "false";
+static const int json_false_str_len = sizeof(json_false_str) - 1;
+
+static const char* json_tokener_errors[] = {
+  "success",
+  "continue",
+  "nesting too deep",
+  "unexpected end of data",
+  "unexpected character",
+  "null expected",
+  "boolean expected",
+  "number expected",
+  "array value separator ',' expected",
+  "quoted object property name expected",
+  "object property name separator ':' expected",
+  "object value separator ',' expected",
+  "invalid string sequence",
+  "expected comment",
+  "buffer size overflow"
+};
+
+const char *json_tokener_error_desc(enum json_tokener_error jerr)
+{
+	int jerr_int = (int)jerr;
+	if (jerr_int < 0 || jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0])))
+		return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()";
+	return json_tokener_errors[jerr];
+}
+
+enum json_tokener_error json_tokener_get_error(json_tokener *tok)
+{
+	return tok->err;
+}
+
+/* Stuff for decoding unicode sequences */
+#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800)
+#define IS_LOW_SURROGATE(uc)  (((uc) & 0xFC00) == 0xDC00)
+#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000)
+static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD };
+
+struct json_tokener* json_tokener_new_ex(int depth)
+{
+  struct json_tokener *tok;
+
+  tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener));
+  if (!tok) return NULL;
+  tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec));
+  if (!tok->stack) {
+    free(tok);
+    return NULL;
+  }
+  tok->pb = printbuf_new();
+  tok->max_depth = depth;
+  json_tokener_reset(tok);
+  return tok;
+}
+
+struct json_tokener* json_tokener_new(void)
+{
+  return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH);
+}
+
+void json_tokener_free(struct json_tokener *tok)
+{
+  json_tokener_reset(tok);
+  if (tok->pb) printbuf_free(tok->pb);
+  if (tok->stack) free(tok->stack);
+  free(tok);
+}
+
+static void json_tokener_reset_level(struct json_tokener *tok, int depth)
+{
+  tok->stack[depth].state = json_tokener_state_eatws;
+  tok->stack[depth].saved_state = json_tokener_state_start;
+  json_object_put(tok->stack[depth].current);
+  tok->stack[depth].current = NULL;
+  free(tok->stack[depth].obj_field_name);
+  tok->stack[depth].obj_field_name = NULL;
+}
+
+void json_tokener_reset(struct json_tokener *tok)
+{
+  int i;
+  if (!tok)
+    return;
+
+  for(i = tok->depth; i >= 0; i--)
+    json_tokener_reset_level(tok, i);
+  tok->depth = 0;
+  tok->err = json_tokener_success;
+}
+
+struct json_object* json_tokener_parse(const char *str)
+{
+    enum json_tokener_error jerr_ignored;
+    struct json_object* obj;
+    obj = json_tokener_parse_verbose(str, &jerr_ignored);
+    return obj;
+}
+
+struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error)
+{
+    struct json_tokener* tok;
+    struct json_object* obj;
+
+    tok = json_tokener_new();
+    if (!tok)
+      return NULL;
+    obj = json_tokener_parse_ex(tok, str, -1);
+    *error = tok->err;
+    if(tok->err != json_tokener_success) {
+		if (obj != NULL)
+			json_object_put(obj);
+        obj = NULL;
+    }
+
+    json_tokener_free(tok);
+    return obj;
+}
+
+#define state  tok->stack[tok->depth].state
+#define saved_state  tok->stack[tok->depth].saved_state
+#define current tok->stack[tok->depth].current
+#define obj_field_name tok->stack[tok->depth].obj_field_name
+
+/* Optimization:
+ * json_tokener_parse_ex() consumed a lot of CPU in its main loop,
+ * iterating character-by character.  A large performance boost is
+ * achieved by using tighter loops to locally handle units such as
+ * comments and strings.  Loops that handle an entire token within
+ * their scope also gather entire strings and pass them to
+ * printbuf_memappend() in a single call, rather than calling
+ * printbuf_memappend() one char at a time.
+ *
+ * PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is
+ * common to both the main loop and the tighter loops.
+ */
+
+/* PEEK_CHAR(dest, tok) macro:
+ *   Peeks at the current char and stores it in dest.
+ *   Returns 1 on success, sets tok->err and returns 0 if no more chars.
+ *   Implicit inputs:  str, len vars
+ */
+#define PEEK_CHAR(dest, tok)                                                  \
+  (((tok)->char_offset == len) ?                                          \
+   (((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \
+    (((tok)->err = json_tokener_success), 0)                              \
+    :                                                                   \
+    (((tok)->err = json_tokener_continue), 0)                             \
+    ) :                                                                 \
+   (((dest) = *str), 1)                                                 \
+   )
+
+/* ADVANCE_CHAR() macro:
+ *   Incrementes str & tok->char_offset.
+ *   For convenience of existing conditionals, returns the old value of c (0 on eof)
+ *   Implicit inputs:  c var
+ */
+#define ADVANCE_CHAR(str, tok) \
+  ( ++(str), ((tok)->char_offset)++, c)
+
+
+/* End optimization macro defs */
+
+
+struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
+					  const char *str, int len)
+{
+  struct json_object *obj = NULL;
+  char c = '\1';
+#ifdef HAVE_SETLOCALE
+  char *oldlocale=NULL, *tmplocale;
+
+  tmplocale = setlocale(LC_NUMERIC, NULL);
+  if (tmplocale) oldlocale = strdup(tmplocale);
+  setlocale(LC_NUMERIC, "C");
+#endif
+
+  tok->char_offset = 0;
+  tok->err = json_tokener_success;
+
+  /* this interface is presently not 64-bit clean due to the int len argument
+     and the internal printbuf interface that takes 32-bit int len arguments
+     so the function limits the maximum string size to INT32_MAX (2GB).
+     If the function is called with len == -1 then strlen is called to check
+     the string length is less than INT32_MAX (2GB) */
+  if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) {
+    tok->err = json_tokener_error_size;
+    return NULL;
+  }
+
+  while (PEEK_CHAR(c, tok)) {
+
+  redo_char:
+    switch(state) {
+
+    case json_tokener_state_eatws:
+      /* Advance until we change state */
+      while (isspace((int)c)) {
+	if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok)))
+	  goto out;
+      }
+      if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) {
+	printbuf_reset(tok->pb);
+	printbuf_memappend_fast(tok->pb, &c, 1);
+	state = json_tokener_state_comment_start;
+      } else {
+	state = saved_state;
+	goto redo_char;
+      }
+      break;
+
+    case json_tokener_state_start:
+      switch(c) {
+      case '{':
+	state = json_tokener_state_eatws;
+	saved_state = json_tokener_state_object_field_start;
+	current = json_object_new_object();
+	break;
+      case '[':
+	state = json_tokener_state_eatws;
+	saved_state = json_tokener_state_array;
+	current = json_object_new_array();
+	break;
+      case 'I':
+      case 'i':
+	state = json_tokener_state_inf;
+	printbuf_reset(tok->pb);
+	tok->st_pos = 0;
+	goto redo_char;
+      case 'N':
+      case 'n':
+	state = json_tokener_state_null; // or NaN
+	printbuf_reset(tok->pb);
+	tok->st_pos = 0;
+	goto redo_char;
+      case '\'':
+        if (tok->flags & JSON_TOKENER_STRICT) {
+            /* in STRICT mode only double-quote are allowed */
+            tok->err = json_tokener_error_parse_unexpected;
+            goto out;
+        }
+      case '"':
+	state = json_tokener_state_string;
+	printbuf_reset(tok->pb);
+	tok->quote_char = c;
+	break;
+      case 'T':
+      case 't':
+      case 'F':
+      case 'f':
+	state = json_tokener_state_boolean;
+	printbuf_reset(tok->pb);
+	tok->st_pos = 0;
+	goto redo_char;
+#if defined(__GNUC__)
+	  case '0' ... '9':
+#else
+	  case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+#endif
+      case '-':
+	state = json_tokener_state_number;
+	printbuf_reset(tok->pb);
+	tok->is_double = 0;
+	goto redo_char;
+      default:
+	tok->err = json_tokener_error_parse_unexpected;
+	goto out;
+      }
+      break;
+
+    case json_tokener_state_finish:
+      if(tok->depth == 0) goto out;
+      obj = json_object_get(current);
+      json_tokener_reset_level(tok, tok->depth);
+      tok->depth--;
+      goto redo_char;
+
+    case json_tokener_state_inf: /* aka starts with 'i' */
+      {
+	int size_inf;
+	int is_negative = 0;
+
+	printbuf_memappend_fast(tok->pb, &c, 1);
+	size_inf = json_min(tok->st_pos+1, json_inf_str_len);
+	char *infbuf = tok->pb->buf;
+	if (*infbuf == '-')
+	{
+		infbuf++;
+		is_negative = 1;
+	}
+	if ((!(tok->flags & JSON_TOKENER_STRICT) &&
+	          strncasecmp(json_inf_str, infbuf, size_inf) == 0) ||
+	         (strncmp(json_inf_str, infbuf, size_inf) == 0)
+	        )
+	{
+		if (tok->st_pos == json_inf_str_len)
+		{
+			current = json_object_new_double(is_negative ? -INFINITY : INFINITY); 
+			saved_state = json_tokener_state_finish;
+			state = json_tokener_state_eatws;
+			goto redo_char;
+		}
+	} else {
+		tok->err = json_tokener_error_parse_unexpected;
+		goto out;
+	}
+	tok->st_pos++;
+      }
+      break;
+    case json_tokener_state_null: /* aka starts with 'n' */
+      {
+	int size;
+	int size_nan;
+	printbuf_memappend_fast(tok->pb, &c, 1);
+	size = json_min(tok->st_pos+1, json_null_str_len);
+	size_nan = json_min(tok->st_pos+1, json_nan_str_len);
+	if((!(tok->flags & JSON_TOKENER_STRICT) &&
+	  strncasecmp(json_null_str, tok->pb->buf, size) == 0)
+	  || (strncmp(json_null_str, tok->pb->buf, size) == 0)
+	  ) {
+	  if (tok->st_pos == json_null_str_len) {
+	    current = NULL;
+	    saved_state = json_tokener_state_finish;
+	    state = json_tokener_state_eatws;
+	    goto redo_char;
+	  }
+	}
+	else if ((!(tok->flags & JSON_TOKENER_STRICT) &&
+	          strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) ||
+	         (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0)
+	        )
+	{
+		if (tok->st_pos == json_nan_str_len)
+		{
+			current = json_object_new_double(NAN);
+			saved_state = json_tokener_state_finish;
+			state = json_tokener_state_eatws;
+			goto redo_char;
+		}
+	} else {
+	  tok->err = json_tokener_error_parse_null;
+	  goto out;
+	}
+	tok->st_pos++;
+      }
+      break;
+
+    case json_tokener_state_comment_start:
+      if(c == '*') {
+	state = json_tokener_state_comment;
+      } else if(c == '/') {
+	state = json_tokener_state_comment_eol;
+      } else {
+	tok->err = json_tokener_error_parse_comment;
+	goto out;
+      }
+      printbuf_memappend_fast(tok->pb, &c, 1);
+      break;
+
+    case json_tokener_state_comment:
+              {
+          /* Advance until we change state */
+          const char *case_start = str;
+          while(c != '*') {
+            if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
+              printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+              goto out;
+            }
+          }
+          printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start);
+          state = json_tokener_state_comment_end;
+        }
+            break;
+
+    case json_tokener_state_comment_eol:
+      {
+	/* Advance until we change state */
+	const char *case_start = str;
+	while(c != '\n') {
+	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
+	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	    goto out;
+	  }
+	}
+	printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
+	state = json_tokener_state_eatws;
+      }
+      break;
+
+    case json_tokener_state_comment_end:
+      printbuf_memappend_fast(tok->pb, &c, 1);
+      if(c == '/') {
+	MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
+	state = json_tokener_state_eatws;
+      } else {
+	state = json_tokener_state_comment;
+      }
+      break;
+
+    case json_tokener_state_string:
+      {
+	/* Advance until we change state */
+	const char *case_start = str;
+	while(1) {
+	  if(c == tok->quote_char) {
+	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	    current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos);
+	    saved_state = json_tokener_state_finish;
+	    state = json_tokener_state_eatws;
+	    break;
+	  } else if(c == '\\') {
+	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	    saved_state = json_tokener_state_string;
+	    state = json_tokener_state_string_escape;
+	    break;
+	  }
+	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
+	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	    goto out;
+	  }
+	}
+      }
+      break;
+
+    case json_tokener_state_string_escape:
+      switch(c) {
+      case '"':
+      case '\\':
+      case '/':
+	printbuf_memappend_fast(tok->pb, &c, 1);
+	state = saved_state;
+	break;
+      case 'b':
+      case 'n':
+      case 'r':
+      case 't':
+      case 'f':
+	if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1);
+	else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1);
+	else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1);
+	else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1);
+	else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1);
+	state = saved_state;
+	break;
+      case 'u':
+	tok->ucs_char = 0;
+	tok->st_pos = 0;
+	state = json_tokener_state_escape_unicode;
+	break;
+      default:
+	tok->err = json_tokener_error_parse_string;
+	goto out;
+      }
+      break;
+
+    case json_tokener_state_escape_unicode:
+	{
+          unsigned int got_hi_surrogate = 0;
+
+	  /* Handle a 4-byte sequence, or two sequences if a surrogate pair */
+	  while(1) {
+	    if(strchr(json_hex_chars, c)) {
+	      tok->ucs_char += ((unsigned int)jt_hexdigit(c) << ((3-tok->st_pos++)*4));
+	      if(tok->st_pos == 4) {
+		unsigned char unescaped_utf[4];
+
+                if (got_hi_surrogate) {
+		  if (IS_LOW_SURROGATE(tok->ucs_char)) {
+                    /* Recalculate the ucs_char, then fall thru to process normally */
+                    tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char);
+                  } else {
+                    /* Hi surrogate was not followed by a low surrogate */
+                    /* Replace the hi and process the rest normally */
+		    printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
+                  }
+                  got_hi_surrogate = 0;
+                }
+
+		if (tok->ucs_char < 0x80) {
+		  unescaped_utf[0] = tok->ucs_char;
+		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1);
+		} else if (tok->ucs_char < 0x800) {
+		  unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6);
+		  unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f);
+		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2);
+		} else if (IS_HIGH_SURROGATE(tok->ucs_char)) {
+                  /* Got a high surrogate.  Remember it and look for the
+                   * the beginning of another sequence, which should be the
+                   * low surrogate.
+                   */
+                  got_hi_surrogate = tok->ucs_char;
+                  /* Not at end, and the next two chars should be "\u" */
+                  if ((tok->char_offset+1 != len) &&
+                      (tok->char_offset+2 != len) &&
+                      (str[1] == '\\') &&
+                      (str[2] == 'u'))
+                  {
+                /* Advance through the 16 bit surrogate, and move on to the
+                 * next sequence. The next step is to process the following
+                 * characters.
+                 */
+	            if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) {
+                    printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
+                }
+                    /* Advance to the first char of the next sequence and
+                     * continue processing with the next sequence.
+                     */
+	            if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
+	              printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
+	              goto out;
+                    }
+	            tok->ucs_char = 0;
+                    tok->st_pos = 0;
+                    continue; /* other json_tokener_state_escape_unicode */
+                  } else {
+                    /* Got a high surrogate without another sequence following
+                     * it.  Put a replacement char in for the hi surrogate
+                     * and pretend we finished.
+                     */
+		    printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
+                  }
+		} else if (IS_LOW_SURROGATE(tok->ucs_char)) {
+                  /* Got a low surrogate not preceded by a high */
+		  printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
+                } else if (tok->ucs_char < 0x10000) {
+		  unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12);
+		  unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
+		  unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f);
+		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3);
+		} else if (tok->ucs_char < 0x110000) {
+		  unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07);
+		  unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f);
+		  unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
+		  unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f);
+		  printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4);
+		} else {
+                  /* Don't know what we got--insert the replacement char */
+		  printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
+                }
+		state = saved_state;
+		break;
+	      }
+	    } else {
+	      tok->err = json_tokener_error_parse_string;
+	      goto out;
+	    }
+	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
+            if (got_hi_surrogate) /* Clean up any pending chars */
+	      printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
+	    goto out;
+	  }
+	}
+      }
+      break;
+
+    case json_tokener_state_boolean:
+      {
+	int size1, size2;
+	printbuf_memappend_fast(tok->pb, &c, 1);
+	size1 = json_min(tok->st_pos+1, json_true_str_len);
+	size2 = json_min(tok->st_pos+1, json_false_str_len);
+	if((!(tok->flags & JSON_TOKENER_STRICT) &&
+	  strncasecmp(json_true_str, tok->pb->buf, size1) == 0)
+	  || (strncmp(json_true_str, tok->pb->buf, size1) == 0)
+	  ) {
+	  if(tok->st_pos == json_true_str_len) {
+	    current = json_object_new_boolean(1);
+	    saved_state = json_tokener_state_finish;
+	    state = json_tokener_state_eatws;
+	    goto redo_char;
+	  }
+	} else if((!(tok->flags & JSON_TOKENER_STRICT) &&
+	  strncasecmp(json_false_str, tok->pb->buf, size2) == 0)
+	  || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) {
+	  if(tok->st_pos == json_false_str_len) {
+	    current = json_object_new_boolean(0);
+	    saved_state = json_tokener_state_finish;
+	    state = json_tokener_state_eatws;
+	    goto redo_char;
+	  }
+	} else {
+	  tok->err = json_tokener_error_parse_boolean;
+	  goto out;
+	}
+	tok->st_pos++;
+      }
+      break;
+
+    case json_tokener_state_number:
+      {
+	/* Advance until we change state */
+	const char *case_start = str;
+	int case_len=0;
+	while(c && strchr(json_number_chars, c)) {
+	  ++case_len;
+	  if(c == '.' || c == 'e' || c == 'E')
+	    tok->is_double = 1;
+	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
+	    printbuf_memappend_fast(tok->pb, case_start, case_len);
+	    goto out;
+	  }
+	}
+        if (case_len>0)
+          printbuf_memappend_fast(tok->pb, case_start, case_len);
+
+	// Check for -Infinity
+	if (tok->pb->buf[0] == '-' && case_len == 1 &&
+	    (c == 'i' || c == 'I'))
+	{
+		state = json_tokener_state_inf;
+		goto redo_char;
+	}
+      }
+      {
+	int64_t num64;
+	double  numd;
+	if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) {
+		if (num64 && tok->pb->buf[0]=='0' && (tok->flags & JSON_TOKENER_STRICT)) {
+			/* in strict mode, number must not start with 0 */
+			tok->err = json_tokener_error_parse_number;
+			goto out;
+		}
+		current = json_object_new_int64(num64);
+	}
+	else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0)
+	{
+          current = json_object_new_double_s(numd, tok->pb->buf);
+        } else {
+          tok->err = json_tokener_error_parse_number;
+          goto out;
+        }
+        saved_state = json_tokener_state_finish;
+        state = json_tokener_state_eatws;
+        goto redo_char;
+      }
+      break;
+
+    case json_tokener_state_array_after_sep:
+    case json_tokener_state_array:
+      if(c == ']') {
+		if (state == json_tokener_state_array_after_sep &&
+			(tok->flags & JSON_TOKENER_STRICT))
+		{
+			tok->err = json_tokener_error_parse_unexpected;
+			goto out;
+		}
+	saved_state = json_tokener_state_finish;
+	state = json_tokener_state_eatws;
+      } else {
+	if(tok->depth >= tok->max_depth-1) {
+	  tok->err = json_tokener_error_depth;
+	  goto out;
+	}
+	state = json_tokener_state_array_add;
+	tok->depth++;
+	json_tokener_reset_level(tok, tok->depth);
+	goto redo_char;
+      }
+      break;
+
+    case json_tokener_state_array_add:
+      json_object_array_add(current, obj);
+      saved_state = json_tokener_state_array_sep;
+      state = json_tokener_state_eatws;
+      goto redo_char;
+
+    case json_tokener_state_array_sep:
+      if(c == ']') {
+	saved_state = json_tokener_state_finish;
+	state = json_tokener_state_eatws;
+      } else if(c == ',') {
+	saved_state = json_tokener_state_array_after_sep;
+	state = json_tokener_state_eatws;
+      } else {
+	tok->err = json_tokener_error_parse_array;
+	goto out;
+      }
+      break;
+
+    case json_tokener_state_object_field_start:
+    case json_tokener_state_object_field_start_after_sep:
+      if(c == '}') {
+		if (state == json_tokener_state_object_field_start_after_sep &&
+		    (tok->flags & JSON_TOKENER_STRICT))
+		{
+			tok->err = json_tokener_error_parse_unexpected;
+			goto out;
+		}
+	saved_state = json_tokener_state_finish;
+	state = json_tokener_state_eatws;
+      } else if (c == '"' || c == '\'') {
+	tok->quote_char = c;
+	printbuf_reset(tok->pb);
+	state = json_tokener_state_object_field;
+      } else {
+	tok->err = json_tokener_error_parse_object_key_name;
+	goto out;
+      }
+      break;
+
+    case json_tokener_state_object_field:
+      {
+	/* Advance until we change state */
+	const char *case_start = str;
+	while(1) {
+	  if(c == tok->quote_char) {
+	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	    obj_field_name = strdup(tok->pb->buf);
+	    saved_state = json_tokener_state_object_field_end;
+	    state = json_tokener_state_eatws;
+	    break;
+	  } else if(c == '\\') {
+	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	    saved_state = json_tokener_state_object_field;
+	    state = json_tokener_state_string_escape;
+	    break;
+	  }
+	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
+	    printbuf_memappend_fast(tok->pb, case_start, str-case_start);
+	    goto out;
+	  }
+	}
+      }
+      break;
+
+    case json_tokener_state_object_field_end:
+      if(c == ':') {
+	saved_state = json_tokener_state_object_value;
+	state = json_tokener_state_eatws;
+      } else {
+	tok->err = json_tokener_error_parse_object_key_sep;
+	goto out;
+      }
+      break;
+
+    case json_tokener_state_object_value:
+      if(tok->depth >= tok->max_depth-1) {
+	tok->err = json_tokener_error_depth;
+	goto out;
+      }
+      state = json_tokener_state_object_value_add;
+      tok->depth++;
+      json_tokener_reset_level(tok, tok->depth);
+      goto redo_char;
+
+    case json_tokener_state_object_value_add:
+      json_object_object_add(current, obj_field_name, obj);
+      free(obj_field_name);
+      obj_field_name = NULL;
+      saved_state = json_tokener_state_object_sep;
+      state = json_tokener_state_eatws;
+      goto redo_char;
+
+    case json_tokener_state_object_sep:
+      if(c == '}') {
+	saved_state = json_tokener_state_finish;
+	state = json_tokener_state_eatws;
+      } else if(c == ',') {
+	saved_state = json_tokener_state_object_field_start_after_sep;
+	state = json_tokener_state_eatws;
+      } else {
+	tok->err = json_tokener_error_parse_object_value_sep;
+	goto out;
+      }
+      break;
+
+    }
+    if (!ADVANCE_CHAR(str, tok))
+      goto out;
+  } /* while(POP_CHAR) */
+
+ out:
+  if (c &&
+     (state == json_tokener_state_finish) &&
+     (tok->depth == 0) &&
+     (tok->flags & JSON_TOKENER_STRICT)) {
+      /* unexpected char after JSON data */
+      tok->err = json_tokener_error_parse_unexpected;
+  }
+  if (!c) { /* We hit an eof char (0) */
+    if(state != json_tokener_state_finish &&
+       saved_state != json_tokener_state_finish)
+      tok->err = json_tokener_error_parse_eof;
+  }
+
+#ifdef HAVE_SETLOCALE
+  setlocale(LC_NUMERIC, oldlocale);
+  if (oldlocale) free(oldlocale);
+#endif
+
+  if (tok->err == json_tokener_success)
+  {
+    json_object *ret = json_object_get(current);
+	int ii;
+
+	/* Partially reset, so we parse additional objects on subsequent calls. */
+    for(ii = tok->depth; ii >= 0; ii--)
+      json_tokener_reset_level(tok, ii);
+    return ret;
+  }
+
+  MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n",
+	   json_tokener_errors[tok->err], tok->char_offset);
+  return NULL;
+}
+
+void json_tokener_set_flags(struct json_tokener *tok, int flags)
+{
+	tok->flags = flags;
+}
diff --git a/json-c/json_tokener.h b/json-c/json_tokener.h
new file mode 100644
index 0000000..a72d2bd
--- /dev/null
+++ b/json-c/json_tokener.h
@@ -0,0 +1,208 @@
+/*
+ * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _json_tokener_h_
+#define _json_tokener_h_
+
+#include <stddef.h>
+#include "json_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum json_tokener_error {
+  json_tokener_success,
+  json_tokener_continue,
+  json_tokener_error_depth,
+  json_tokener_error_parse_eof,
+  json_tokener_error_parse_unexpected,
+  json_tokener_error_parse_null,
+  json_tokener_error_parse_boolean,
+  json_tokener_error_parse_number,
+  json_tokener_error_parse_array,
+  json_tokener_error_parse_object_key_name,
+  json_tokener_error_parse_object_key_sep,
+  json_tokener_error_parse_object_value_sep,
+  json_tokener_error_parse_string,
+  json_tokener_error_parse_comment,
+  json_tokener_error_size
+};
+
+enum json_tokener_state {
+  json_tokener_state_eatws,
+  json_tokener_state_start,
+  json_tokener_state_finish,
+  json_tokener_state_null,
+  json_tokener_state_comment_start,
+  json_tokener_state_comment,
+  json_tokener_state_comment_eol,
+  json_tokener_state_comment_end,
+  json_tokener_state_string,
+  json_tokener_state_string_escape,
+  json_tokener_state_escape_unicode,
+  json_tokener_state_boolean,
+  json_tokener_state_number,
+  json_tokener_state_array,
+  json_tokener_state_array_add,
+  json_tokener_state_array_sep,
+  json_tokener_state_object_field_start,
+  json_tokener_state_object_field,
+  json_tokener_state_object_field_end,
+  json_tokener_state_object_value,
+  json_tokener_state_object_value_add,
+  json_tokener_state_object_sep,
+  json_tokener_state_array_after_sep,
+  json_tokener_state_object_field_start_after_sep,
+  json_tokener_state_inf
+};
+
+struct json_tokener_srec
+{
+  enum json_tokener_state state, saved_state;
+  struct json_object *obj;
+  struct json_object *current;
+  char *obj_field_name;
+};
+
+#define JSON_TOKENER_DEFAULT_DEPTH 32
+
+struct json_tokener
+{
+  char *str;
+  struct printbuf *pb;
+  int max_depth, depth, is_double, st_pos, char_offset;
+  enum json_tokener_error err;
+  unsigned int ucs_char;
+  char quote_char;
+  struct json_tokener_srec *stack;
+  int flags;
+};
+
+/**
+ * Be strict when parsing JSON input.  Use caution with
+ * this flag as what is considered valid may become more
+ * restrictive from one release to the next, causing your
+ * code to fail on previously working input.
+ *
+ * This flag is not set by default.
+ *
+ * @see json_tokener_set_flags()
+ */
+#define JSON_TOKENER_STRICT  0x01
+
+/**
+ * Given an error previously returned by json_tokener_get_error(),
+ * return a human readable description of the error.
+ *
+ * @return a generic error message is returned if an invalid error value is provided.
+ */
+const char *json_tokener_error_desc(enum json_tokener_error jerr);
+
+/**
+ * Retrieve the error caused by the last call to json_tokener_parse_ex(),
+ * or json_tokener_success if there is no error.
+ *
+ * When parsing a JSON string in pieces, if the tokener is in the middle
+ * of parsing this will return json_tokener_continue.
+ *
+ * See also json_tokener_error_desc().
+ */
+enum json_tokener_error json_tokener_get_error(struct json_tokener *tok);
+
+extern struct json_tokener* json_tokener_new(void);
+extern struct json_tokener* json_tokener_new_ex(int depth);
+extern void json_tokener_free(struct json_tokener *tok);
+extern void json_tokener_reset(struct json_tokener *tok);
+extern struct json_object* json_tokener_parse(const char *str);
+extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error);
+
+/**
+ * Set flags that control how parsing will be done.
+ */
+extern void json_tokener_set_flags(struct json_tokener *tok, int flags);
+
+/** 
+ * Parse a string and return a non-NULL json_object if a valid JSON value
+ * is found.  The string does not need to be a JSON object or array;
+ * it can also be a string, number or boolean value.
+ *
+ * A partial JSON string can be parsed.  If the parsing is incomplete,
+ * NULL will be returned and json_tokener_get_error() will be return 
+ * json_tokener_continue.
+ * json_tokener_parse_ex() can then be called with additional bytes in str
+ * to continue the parsing.  
+ *
+ * If json_tokener_parse_ex() returns NULL and the error anything other than
+ * json_tokener_continue, a fatal error has occurred and parsing must be
+ * halted.  Then tok object must not be re-used until json_tokener_reset() is
+ * called.
+ *
+ * When a valid JSON value is parsed, a non-NULL json_object will be
+ * returned.  Also, json_tokener_get_error() will return json_tokener_success.
+ * Be sure to check the type with json_object_is_type() or
+ * json_object_get_type() before using the object.
+ *
+ * @b XXX this shouldn't use internal fields:
+ * Trailing characters after the parsed value do not automatically cause an 
+ * error.  It is up to the caller to decide whether to treat this as an
+ * error or to handle the additional characters, perhaps by parsing another
+ * json value starting from that point.
+ *
+ * Extra characters can be detected by comparing the tok->char_offset against
+ * the length of the last len parameter passed in.
+ *
+ * The tokener does \b not maintain an internal buffer so the caller is
+ * responsible for calling json_tokener_parse_ex with an appropriate str
+ * parameter starting with the extra characters.
+ *
+ * This interface is presently not 64-bit clean due to the int len argument
+ * so the function limits the maximum string size to INT32_MAX (2GB).
+ * If the function is called with len == -1 then strlen is called to check
+ * the string length is less than INT32_MAX (2GB)
+ *
+ * Example:
+ * @code
+json_object *jobj = NULL;
+const char *mystring = NULL;
+int stringlen = 0;
+enum json_tokener_error jerr;
+do {
+	mystring = ...  // get JSON string, e.g. read from file, etc...
+	stringlen = strlen(mystring);
+	jobj = json_tokener_parse_ex(tok, mystring, stringlen);
+} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);
+if (jerr != json_tokener_success)
+{
+	fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
+	// Handle errors, as appropriate for your application.
+}
+if (tok->char_offset < stringlen) // XXX shouldn't access internal fields
+{
+	// Handle extra characters after parsed object as desired.
+	// e.g. issue an error, parse another object from that point, etc...
+}
+// Success, use jobj here.
+
+@endcode
+ *
+ * @param tok a json_tokener previously allocated with json_tokener_new()
+ * @param str an string with any valid JSON expression, or portion of.  This does not need to be null terminated.
+ * @param len the length of str
+ */
+extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
+						 const char *str, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/json_util.c b/json-c/json_util.c
new file mode 100644
index 0000000..2a5621b
--- /dev/null
+++ b/json-c/json_util.c
@@ -0,0 +1,299 @@
+/*
+ * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#include "config.h"
+#undef realloc
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#ifdef WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <io.h>
+#endif /* defined(WIN32) */
+
+#if !defined(HAVE_OPEN) && defined(WIN32)
+# define open _open
+#endif
+
+#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)
+  /* MSC has the version as _snprintf */
+# define snprintf _snprintf
+#elif !defined(HAVE_SNPRINTF)
+# error You do not have snprintf on your system.
+#endif /* HAVE_SNPRINTF */
+
+#include "debug.h"
+#include "printbuf.h"
+#include "json_inttypes.h"
+#include "json_object.h"
+#include "json_tokener.h"
+#include "json_util.h"
+
+static int sscanf_is_broken = 0;
+static int sscanf_is_broken_testdone = 0;
+static void sscanf_is_broken_test(void);
+
+struct json_object* json_object_from_file(const char *filename)
+{
+  struct printbuf *pb;
+  struct json_object *obj;
+  char buf[JSON_FILE_BUF_SIZE];
+  int fd, ret;
+
+  if((fd = open(filename, O_RDONLY)) < 0) {
+    MC_ERROR("json_object_from_file: error opening file %s: %s\n",
+	     filename, strerror(errno));
+    return NULL;
+  }
+  if(!(pb = printbuf_new())) {
+    close(fd);
+    MC_ERROR("json_object_from_file: printbuf_new failed\n");
+    return NULL;
+  }
+  while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
+    printbuf_memappend(pb, buf, ret);
+  }
+  close(fd);
+  if(ret < 0) {
+    MC_ERROR("json_object_from_file: error reading file %s: %s\n",
+	     filename, strerror(errno));
+    printbuf_free(pb);
+    return NULL;
+  }
+  obj = json_tokener_parse(pb->buf);
+  printbuf_free(pb);
+  return obj;
+}
+
+/* extended "format and write to file" function */
+
+int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags)
+{
+  const char *json_str;
+  int fd, ret;
+  unsigned int wpos, wsize;
+
+  if(!obj) {
+    MC_ERROR("json_object_to_file: object is null\n");
+    return -1;
+  }
+
+  if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
+    MC_ERROR("json_object_to_file: error opening file %s: %s\n",
+	     filename, strerror(errno));
+    return -1;
+  }
+
+  if(!(json_str = json_object_to_json_string_ext(obj,flags))) {
+    close(fd);
+    return -1;
+  }
+
+  wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
+  wpos = 0;
+  while(wpos < wsize) {
+    if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) {
+      close(fd);
+      MC_ERROR("json_object_to_file: error writing file %s: %s\n",
+	     filename, strerror(errno));
+      return -1;
+    }
+
+	/* because of the above check for ret < 0, we can safely cast and add */
+    wpos += (unsigned int)ret;
+  }
+
+  close(fd);
+  return 0;
+}
+
+// backwards compatible "format and write to file" function
+
+int json_object_to_file(const char *filename, struct json_object *obj)
+{
+  return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
+}
+
+int json_parse_double(const char *buf, double *retval)
+{
+  return (sscanf(buf, "%lf", retval)==1 ? 0 : 1);
+}
+
+/*
+ * Not all implementations of sscanf actually work properly.
+ * Check whether the one we're currently using does, and if
+ * it's broken, enable the workaround code.
+ */
+static void sscanf_is_broken_test()
+{
+	int64_t num64;
+	int ret_errno, is_int64_min, ret_errno2, is_int64_max;
+
+	(void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64);
+	ret_errno = errno;
+	is_int64_min = (num64 == INT64_MIN);
+
+	(void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64);
+	ret_errno2 = errno;
+	is_int64_max = (num64 == INT64_MAX);
+
+	if (ret_errno != ERANGE || !is_int64_min ||
+	    ret_errno2 != ERANGE || !is_int64_max)
+	{
+		MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n");
+		sscanf_is_broken = 1;
+	}
+}
+
+int json_parse_int64(const char *buf, int64_t *retval)
+{
+	int64_t num64;
+	const char *buf_sig_digits;
+	int orig_has_neg;
+	int saved_errno;
+
+	if (!sscanf_is_broken_testdone)
+	{
+		sscanf_is_broken_test();
+		sscanf_is_broken_testdone = 1;
+	}
+
+	// Skip leading spaces
+	while (isspace((int)*buf) && *buf)
+		buf++;
+
+	errno = 0; // sscanf won't always set errno, so initialize
+	if (sscanf(buf, "%" SCNd64, &num64) != 1)
+	{
+		MC_DEBUG("Failed to parse, sscanf != 1\n");
+		return 1;
+	}
+
+	saved_errno = errno;
+	buf_sig_digits = buf;
+	orig_has_neg = 0;
+	if (*buf_sig_digits == '-')
+	{
+		buf_sig_digits++;
+		orig_has_neg = 1;
+	}
+
+	// Not all sscanf implementations actually work
+	if (sscanf_is_broken && saved_errno != ERANGE)
+	{
+		char buf_cmp[100];
+		char *buf_cmp_start = buf_cmp;
+		int recheck_has_neg = 0;
+		int buf_cmp_len;
+
+		// Skip leading zeros, but keep at least one digit
+		while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0')
+			buf_sig_digits++;
+		if (num64 == 0) // assume all sscanf impl's will parse -0 to 0
+			orig_has_neg = 0; // "-0" is the same as just plain "0"
+
+		snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
+		if (*buf_cmp_start == '-')
+		{
+			recheck_has_neg = 1;
+			buf_cmp_start++;
+		}
+		// No need to skip leading spaces or zeros here.
+
+		buf_cmp_len = strlen(buf_cmp_start);
+		/**
+		 * If the sign is different, or
+		 * some of the digits are different, or
+		 * there is another digit present in the original string
+		 * then we have NOT successfully parsed the value.
+		 */
+		if (orig_has_neg != recheck_has_neg ||
+		    strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||
+			((int)strlen(buf_sig_digits) != buf_cmp_len &&
+			 isdigit((int)buf_sig_digits[buf_cmp_len])
+		    )
+		   )
+		{
+			saved_errno = ERANGE;
+		}
+	}
+
+	// Not all sscanf impl's set the value properly when out of range.
+	// Always do this, even for properly functioning implementations,
+	// since it shouldn't slow things down much.
+	if (saved_errno == ERANGE)
+	{
+		if (orig_has_neg)
+			num64 = INT64_MIN;
+		else
+			num64 = INT64_MAX;
+	}
+	*retval = num64;
+	return 0;
+}
+
+#ifndef HAVE_REALLOC
+void* rpl_realloc(void* p, size_t n)
+{
+	if (n == 0)
+		n = 1;
+	if (p == 0)
+		return malloc(n);
+	return realloc(p, n);
+}
+#endif
+
+#define NELEM(a)        (sizeof(a) / sizeof(a[0]))
+static const char* json_type_name[] = {
+  /* If you change this, be sure to update the enum json_type definition too */
+  "null",
+  "boolean",
+  "double",
+  "int",
+  "object",
+  "array",
+  "string",
+};
+
+const char *json_type_to_name(enum json_type o_type)
+{
+	int o_type_int = (int)o_type;
+	if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name))
+	{
+		MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name));
+		return NULL;
+	}
+	return json_type_name[o_type];
+}
+
diff --git a/json-c/json_util.h b/json-c/json_util.h
new file mode 100644
index 0000000..387dbc4
--- /dev/null
+++ b/json-c/json_util.h
@@ -0,0 +1,50 @@
+/*
+ * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef _json_util_h_
+#define _json_util_h_
+
+#include "json_object.h"
+
+#ifndef json_min
+#define json_min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef json_max
+#define json_max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define JSON_FILE_BUF_SIZE 4096
+
+/* utility functions */
+extern struct json_object* json_object_from_file(const char *filename);
+extern int json_object_to_file(const char *filename, struct json_object *obj);
+extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags);
+extern int json_parse_int64(const char *buf, int64_t *retval);
+extern int json_parse_double(const char *buf, double *retval);
+
+
+/**
+ * Return a string describing the type of the object.
+ * e.g. "int", or "object", etc...
+ */
+extern const char *json_type_to_name(enum json_type o_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/libjson.c b/json-c/libjson.c
new file mode 100644
index 0000000..5284fd0
--- /dev/null
+++ b/json-c/libjson.c
@@ -0,0 +1,26 @@
+
+/* dummy source file for compatibility purposes */
+
+#if defined(HAVE_CDEFS_H)
+#include <sys/cdefs.h>
+#endif
+
+#ifndef __warn_references
+
+#if defined(__GNUC__)  && defined (HAS_GNU_WARNING_LONG)
+
+#define __warn_references(sym,msg)                  \
+  __asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text");
+
+#else
+#define __warn_references(sym,msg)    /* nothing */
+#endif
+
+#endif 
+
+#include "json_object.h"
+
+__warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson");
+
+/*        __asm__(".section .gnu.warning." __STRING(sym)  \
+            " ; .ascii \"" msg "\" ; .text") */
diff --git a/json-c/linkhash.c b/json-c/linkhash.c
new file mode 100644
index 0000000..712c387
--- /dev/null
+++ b/json-c/linkhash.c
@@ -0,0 +1,602 @@
+/*
+ * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <limits.h>
+
+#ifdef HAVE_ENDIAN_H
+# include <endian.h>    /* attempt to define endianness */
+#endif
+
+#include "random_seed.h"
+#include "linkhash.h"
+
+void lh_abort(const char *msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	vprintf(msg, ap);
+	va_end(ap);
+	exit(1);
+}
+
+unsigned long lh_ptr_hash(const void *k)
+{
+	/* CAW: refactored to be 64bit nice */
+	return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX);
+}
+
+int lh_ptr_equal(const void *k1, const void *k2)
+{
+	return (k1 == k2);
+}
+
+/* 
+ * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+ * http://burtleburtle.net/bob/c/lookup3.c
+ * minor modifications to make functions static so no symbols are exported
+ * minor mofifications to compile with -Werror
+ */
+
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+are externally useful functions.  Routines to test the hash are included 
+if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+the public domain.  It has no warranty.
+
+You probably want to use hashlittle().  hashlittle() and hashbig()
+hash byte arrays.  hashlittle() is is faster than hashbig() on
+little-endian machines.  Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.  
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+  a = i1;  b = i2;  c = i3;
+  mix(a,b,c);
+  a += i4; b += i5; c += i6;
+  mix(a,b,c);
+  a += i7;
+  final(a,b,c);
+then use c as the hash value.  If you have a variable length array of
+4-byte integers to hash, use hashword().  If you have a byte array (like
+a character string), use hashlittle().  If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().  
+
+Why is this so big?  I read 12 bytes at a time into 3 4-byte integers, 
+then mix those integers.  This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+
+/*
+ * My best guess at if you are big-endian or little-endian.  This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+     __BYTE_ORDER == __LITTLE_ENDIAN) || \
+    (defined(i386) || defined(__i386__) || defined(__i486__) || \
+     defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+       __BYTE_ORDER == __BIG_ENDIAN) || \
+      (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or 
+  all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+    4  6  8 16 19  4
+    9 15  3 18 27 15
+   14  9  3  7 17  3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta.  I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose 
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche.  There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a.  The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism.  Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism.  I did what I could.  Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different.  This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or 
+  all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+  4  8 15 26 3 22 24
+ 10  8 15 26 3 22 24
+ 11  8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+  k       : the key (the unaligned variable-length array of bytes)
+  length  : the length of the key, counting by bytes
+  initval : can be any 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.  It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+static uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+  u.ptr = key;
+  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /* 
+     * "k[2]&0xffffff" actually reads beyond the end of the string, but
+     * then masks off the part it's not allowed to read.  Because the
+     * string is aligned, the masked-off tail is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     */
+#ifndef VALGRIND
+
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff; break;
+    case 2 : a+=k[0]&0xffff; break;
+    case 1 : a+=k[0]&0xff; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    }
+
+#else /* make valgrind happy */
+
+    const uint8_t  *k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
+    case 9 : c+=k8[8];                   /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
+    case 5 : b+=k8[4];                   /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
+    case 1 : a+=k8[0]; break;
+    case 0 : return c;
+    }
+
+#endif /* !valgrind */
+
+  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+    const uint8_t  *k8;
+
+    /*--------------- all but last block: aligned reads and different mixing */
+    while (length > 12)
+    {
+      a += k[0] + (((uint32_t)k[1])<<16);
+      b += k[2] + (((uint32_t)k[3])<<16);
+      c += k[4] + (((uint32_t)k[5])<<16);
+      mix(a,b,c);
+      length -= 12;
+      k += 6;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
+    case 10: c+=k[4];
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 9 : c+=k8[8];                      /* fall through */
+    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
+    case 6 : b+=k[2];
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 5 : b+=k8[4];                      /* fall through */
+    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
+    case 2 : a+=k[0];
+             break;
+    case 1 : a+=k8[0];
+             break;
+    case 0 : return c;                     /* zero length requires no mixing */
+    }
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      a += ((uint32_t)k[1])<<8;
+      a += ((uint32_t)k[2])<<16;
+      a += ((uint32_t)k[3])<<24;
+      b += k[4];
+      b += ((uint32_t)k[5])<<8;
+      b += ((uint32_t)k[6])<<16;
+      b += ((uint32_t)k[7])<<24;
+      c += k[8];
+      c += ((uint32_t)k[9])<<8;
+      c += ((uint32_t)k[10])<<16;
+      c += ((uint32_t)k[11])<<24;
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=((uint32_t)k[11])<<24;
+    case 11: c+=((uint32_t)k[10])<<16;
+    case 10: c+=((uint32_t)k[9])<<8;
+    case 9 : c+=k[8];
+    case 8 : b+=((uint32_t)k[7])<<24;
+    case 7 : b+=((uint32_t)k[6])<<16;
+    case 6 : b+=((uint32_t)k[5])<<8;
+    case 5 : b+=k[4];
+    case 4 : a+=((uint32_t)k[3])<<24;
+    case 3 : a+=((uint32_t)k[2])<<16;
+    case 2 : a+=((uint32_t)k[1])<<8;
+    case 1 : a+=k[0];
+             break;
+    case 0 : return c;
+    }
+  }
+
+  final(a,b,c);
+  return c;
+}
+
+unsigned long lh_char_hash(const void *k)
+{
+	static volatile int random_seed = -1;
+
+	if (random_seed == -1) {
+		int seed;
+		/* we can't use -1 as it is the unitialized sentinel */
+		while ((seed = json_c_get_random_seed()) == -1);
+#if defined __GNUC__
+		__sync_val_compare_and_swap(&random_seed, -1, seed);
+#elif defined _MSC_VER
+		InterlockedCompareExchange(&random_seed, seed, -1);
+#else
+#warning "racy random seed initializtion if used by multiple threads"
+		random_seed = seed; /* potentially racy */
+#endif
+	}
+
+	return hashlittle((const char*)k, strlen((const char*)k), random_seed); 
+}
+
+int lh_char_equal(const void *k1, const void *k2)
+{
+	return (strcmp((const char*)k1, (const char*)k2) == 0);
+}
+
+struct lh_table* lh_table_new(int size, const char *name,
+			      lh_entry_free_fn *free_fn,
+			      lh_hash_fn *hash_fn,
+			      lh_equal_fn *equal_fn)
+{
+	int i;
+	struct lh_table *t;
+
+	t = (struct lh_table*)calloc(1, sizeof(struct lh_table));
+	if(!t) lh_abort("lh_table_new: calloc failed\n");
+	t->count = 0;
+	t->size = size;
+	t->name = name;
+	t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry));
+	if(!t->table) lh_abort("lh_table_new: calloc failed\n");
+	t->free_fn = free_fn;
+	t->hash_fn = hash_fn;
+	t->equal_fn = equal_fn;
+	for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY;
+	return t;
+}
+
+struct lh_table* lh_kchar_table_new(int size, const char *name,
+				    lh_entry_free_fn *free_fn)
+{
+	return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal);
+}
+
+struct lh_table* lh_kptr_table_new(int size, const char *name,
+				   lh_entry_free_fn *free_fn)
+{
+	return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal);
+}
+
+void lh_table_resize(struct lh_table *t, int new_size)
+{
+	struct lh_table *new_t;
+	struct lh_entry *ent;
+
+	new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn);
+	ent = t->head;
+	while(ent) {
+		lh_table_insert(new_t, ent->k, ent->v);
+		ent = ent->next;
+	}
+	free(t->table);
+	t->table = new_t->table;
+	t->size = new_size;
+	t->head = new_t->head;
+	t->tail = new_t->tail;
+	t->resizes++;
+	free(new_t);
+}
+
+void lh_table_free(struct lh_table *t)
+{
+	struct lh_entry *c;
+	for(c = t->head; c != NULL; c = c->next) {
+		if(t->free_fn) {
+			t->free_fn(c);
+		}
+	}
+	free(t->table);
+	free(t);
+}
+
+
+int lh_table_insert(struct lh_table *t, void *k, const void *v)
+{
+	unsigned long h, n;
+
+	t->inserts++;
+	if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2);
+
+	h = t->hash_fn(k);
+	n = h % t->size;
+
+	while( 1 ) {
+		if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break;
+		t->collisions++;
+		if ((int)++n == t->size) n = 0;
+	}
+
+	t->table[n].k = k;
+	t->table[n].v = v;
+	t->count++;
+
+	if(t->head == NULL) {
+		t->head = t->tail = &t->table[n];
+		t->table[n].next = t->table[n].prev = NULL;
+	} else {
+		t->tail->next = &t->table[n];
+		t->table[n].prev = t->tail;
+		t->table[n].next = NULL;
+		t->tail = &t->table[n];
+	}
+
+	return 0;
+}
+
+
+struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k)
+{
+	unsigned long h = t->hash_fn(k);
+	unsigned long n = h % t->size;
+	int count = 0;
+
+	t->lookups++;
+	while( count < t->size ) {
+		if(t->table[n].k == LH_EMPTY) return NULL;
+		if(t->table[n].k != LH_FREED &&
+		   t->equal_fn(t->table[n].k, k)) return &t->table[n];
+		if ((int)++n == t->size) n = 0;
+		count++;
+	}
+	return NULL;
+}
+
+
+const void* lh_table_lookup(struct lh_table *t, const void *k)
+{
+	void *result;
+	lh_table_lookup_ex(t, k, &result);
+	return result;
+}
+
+json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v)
+{
+	struct lh_entry *e = lh_table_lookup_entry(t, k);
+	if (e != NULL) {
+		if (v != NULL) *v = (void *)e->v;
+		return TRUE; /* key found */
+	}
+	if (v != NULL) *v = NULL;
+	return FALSE; /* key not found */
+}
+
+int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e)
+{
+	ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */
+
+	/* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */
+	if(n < 0) { return -2; }
+
+	if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1;
+	t->count--;
+	if(t->free_fn) t->free_fn(e);
+	t->table[n].v = NULL;
+	t->table[n].k = LH_FREED;
+	if(t->tail == &t->table[n] && t->head == &t->table[n]) {
+		t->head = t->tail = NULL;
+	} else if (t->head == &t->table[n]) {
+		t->head->next->prev = NULL;
+		t->head = t->head->next;
+	} else if (t->tail == &t->table[n]) {
+		t->tail->prev->next = NULL;
+		t->tail = t->tail->prev;
+	} else {
+		t->table[n].prev->next = t->table[n].next;
+		t->table[n].next->prev = t->table[n].prev;
+	}
+	t->table[n].next = t->table[n].prev = NULL;
+	return 0;
+}
+
+
+int lh_table_delete(struct lh_table *t, const void *k)
+{
+	struct lh_entry *e = lh_table_lookup_entry(t, k);
+	if(!e) return -1;
+	return lh_table_delete_entry(t, e);
+}
+
+int lh_table_length(struct lh_table *t)
+{
+	return t->count;
+}
diff --git a/json-c/linkhash.h b/json-c/linkhash.h
new file mode 100644
index 0000000..950d09f
--- /dev/null
+++ b/json-c/linkhash.h
@@ -0,0 +1,292 @@
+/*
+ * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+ 
+#ifndef _linkhash_h_
+#define _linkhash_h_
+
+#include "json_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * golden prime used in hash functions
+ */
+#define LH_PRIME 0x9e370001UL
+
+/**
+ * The fraction of filled hash buckets until an insert will cause the table
+ * to be resized.  
+ * This can range from just above 0 up to 1.0.
+ */
+#define LH_LOAD_FACTOR 0.66
+
+/**
+ * sentinel pointer value for empty slots
+ */
+#define LH_EMPTY (void*)-1
+
+/**
+ * sentinel pointer value for freed slots
+ */
+#define LH_FREED (void*)-2
+
+struct lh_entry;
+
+/**
+ * callback function prototypes
+ */
+typedef void (lh_entry_free_fn) (struct lh_entry *e);
+/**
+ * callback function prototypes
+ */
+typedef unsigned long (lh_hash_fn) (const void *k);
+/**
+ * callback function prototypes
+ */
+typedef int (lh_equal_fn) (const void *k1, const void *k2);
+
+/**
+ * An entry in the hash table
+ */
+struct lh_entry {
+	/**
+	 * The key.
+	 */
+	void *k;
+	/**
+	 * The value.
+	 */
+	const void *v;
+	/**
+	 * The next entry
+	 */
+	struct lh_entry *next;
+	/**
+	 * The previous entry.
+	 */
+	struct lh_entry *prev;
+};
+
+
+/**
+ * The hash table structure.
+ */
+struct lh_table {
+	/**
+	 * Size of our hash.
+	 */
+	int size;
+	/**
+	 * Numbers of entries.
+	 */
+	int count;
+
+	/**
+	 * Number of collisions.
+	 */
+	int collisions;
+
+	/**
+	 * Number of resizes.
+	 */
+	int resizes;
+
+	/**
+	 * Number of lookups.
+	 */
+	int lookups;
+
+	/**
+	 * Number of inserts.
+	 */
+	int inserts;
+
+	/**
+	 * Number of deletes.
+	 */
+	int deletes;
+
+	/**
+	 * Name of the hash table.
+	 */
+	const char *name;
+
+	/**
+	 * The first entry.
+	 */
+	struct lh_entry *head;
+
+	/**
+	 * The last entry.
+	 */
+	struct lh_entry *tail;
+
+	struct lh_entry *table;
+
+	/**
+	 * A pointer onto the function responsible for freeing an entry.
+	 */
+	lh_entry_free_fn *free_fn;
+	lh_hash_fn *hash_fn;
+	lh_equal_fn *equal_fn;
+};
+
+
+/**
+ * Pre-defined hash and equality functions
+ */
+extern unsigned long lh_ptr_hash(const void *k);
+extern int lh_ptr_equal(const void *k1, const void *k2);
+
+extern unsigned long lh_char_hash(const void *k);
+extern int lh_char_equal(const void *k1, const void *k2);
+
+
+/**
+ * Convenience list iterator.
+ */
+#define lh_foreach(table, entry) \
+for(entry = table->head; entry; entry = entry->next)
+
+/**
+ * lh_foreach_safe allows calling of deletion routine while iterating.
+ */
+#define lh_foreach_safe(table, entry, tmp) \
+for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp)
+
+
+
+/**
+ * Create a new linkhash table.
+ * @param size initial table size. The table is automatically resized
+ * although this incurs a performance penalty.
+ * @param name the table name.
+ * @param free_fn callback function used to free memory for entries
+ * when lh_table_free or lh_table_delete is called.
+ * If NULL is provided, then memory for keys and values
+ * must be freed by the caller.
+ * @param hash_fn  function used to hash keys. 2 standard ones are defined:
+ * lh_ptr_hash and lh_char_hash for hashing pointer values
+ * and C strings respectively.
+ * @param equal_fn comparison function to compare keys. 2 standard ones defined:
+ * lh_ptr_hash and lh_char_hash for comparing pointer values
+ * and C strings respectively.
+ * @return a pointer onto the linkhash table.
+ */
+extern struct lh_table* lh_table_new(int size, const char *name,
+				     lh_entry_free_fn *free_fn,
+				     lh_hash_fn *hash_fn,
+				     lh_equal_fn *equal_fn);
+
+/**
+ * Convenience function to create a new linkhash
+ * table with char keys.
+ * @param size initial table size.
+ * @param name table name.
+ * @param free_fn callback function used to free memory for entries.
+ * @return a pointer onto the linkhash table.
+ */
+extern struct lh_table* lh_kchar_table_new(int size, const char *name,
+					   lh_entry_free_fn *free_fn);
+
+
+/**
+ * Convenience function to create a new linkhash
+ * table with ptr keys.
+ * @param size initial table size.
+ * @param name table name.
+ * @param free_fn callback function used to free memory for entries.
+ * @return a pointer onto the linkhash table.
+ */
+extern struct lh_table* lh_kptr_table_new(int size, const char *name,
+					  lh_entry_free_fn *free_fn);
+
+
+/**
+ * Free a linkhash table.
+ * If a callback free function is provided then it is called for all
+ * entries in the table.
+ * @param t table to free.
+ */
+extern void lh_table_free(struct lh_table *t);
+
+
+/**
+ * Insert a record into the table.
+ * @param t the table to insert into.
+ * @param k a pointer to the key to insert.
+ * @param v a pointer to the value to insert.
+ */
+extern int lh_table_insert(struct lh_table *t, void *k, const void *v);
+
+
+/**
+ * Lookup a record into the table.
+ * @param t the table to lookup
+ * @param k a pointer to the key to lookup
+ * @return a pointer to the record structure of the value or NULL if it does not exist.
+ */
+extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k);
+
+/**
+ * Lookup a record into the table
+ * @param t the table to lookup
+ * @param k a pointer to the key to lookup
+ * @return a pointer to the found value or NULL if it does not exist.
+ * @deprecated Use lh_table_lookup_ex instead.
+ */
+THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k));
+
+/**
+ * Lookup a record in the table
+ * @param t the table to lookup
+ * @param k a pointer to the key to lookup
+ * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist).
+ * @return whether or not the key was found
+ */
+extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v);
+
+/**
+ * Delete a record from the table.
+ * If a callback free function is provided then it is called for the
+ * for the item being deleted.
+ * @param t the table to delete from.
+ * @param e a pointer to the entry to delete.
+ * @return 0 if the item was deleted.
+ * @return -1 if it was not found.
+ */
+extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e);
+
+
+/**
+ * Delete a record from the table.
+ * If a callback free function is provided then it is called for the
+ * for the item being deleted.
+ * @param t the table to delete from.
+ * @param k a pointer to the key to delete.
+ * @return 0 if the item was deleted.
+ * @return -1 if it was not found.
+ */
+extern int lh_table_delete(struct lh_table *t, const void *k);
+
+extern int lh_table_length(struct lh_table *t);
+
+void lh_abort(const char *msg, ...);
+void lh_table_resize(struct lh_table *t, int new_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/math_compat.h b/json-c/math_compat.h
new file mode 100644
index 0000000..f40b8fa
--- /dev/null
+++ b/json-c/math_compat.h
@@ -0,0 +1,28 @@
+#ifndef __math_compat_h
+#define __math_compat_h
+
+/* Define isnan and isinf on Windows/MSVC */
+
+#ifndef HAVE_DECL_ISNAN
+# ifdef HAVE_DECL__ISNAN
+#include <float.h>
+#define isnan(x) _isnan(x)
+# endif
+#endif
+
+#ifndef HAVE_DECL_ISINF
+# ifdef HAVE_DECL__FINITE
+#include <float.h>
+#define isinf(x) (!_finite(x))
+# endif
+#endif
+
+#ifndef HAVE_DECL_NAN
+#error This platform does not have nan()
+#endif
+
+#ifndef HAVE_DECL_INFINITY
+#error This platform does not have INFINITY
+#endif
+
+#endif
diff --git a/json-c/printbuf.c b/json-c/printbuf.c
new file mode 100644
index 0000000..fe952b4
--- /dev/null
+++ b/json-c/printbuf.c
@@ -0,0 +1,193 @@
+/*
+ * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ *
+ * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.
+ * The copyrights to the contents of this file are licensed under the MIT License
+ * (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_STDARG_H
+# include <stdarg.h>
+#else /* !HAVE_STDARG_H */
+# error Not enough var arg support!
+#endif /* HAVE_STDARG_H */
+
+#include "debug.h"
+#include "printbuf.h"
+
+static int printbuf_extend(struct printbuf *p, int min_size);
+
+struct printbuf* printbuf_new(void)
+{
+  struct printbuf *p;
+
+  p = (struct printbuf*)calloc(1, sizeof(struct printbuf));
+  if(!p) return NULL;
+  p->size = 32;
+  p->bpos = 0;
+  if(!(p->buf = (char*)malloc(p->size))) {
+    free(p);
+    return NULL;
+  }
+  return p;
+}
+
+
+/**
+ * Extend the buffer p so it has a size of at least min_size.
+ *
+ * If the current size is large enough, nothing is changed.
+ *
+ * Note: this does not check the available space!  The caller
+ *  is responsible for performing those calculations.
+ */
+static int printbuf_extend(struct printbuf *p, int min_size)
+{
+	char *t;
+	int new_size;
+
+	if (p->size >= min_size)
+		return 0;
+
+	new_size = p->size * 2;
+	if (new_size < min_size + 8)
+		new_size =  min_size + 8;
+#ifdef PRINTBUF_DEBUG
+	MC_DEBUG("printbuf_memappend: realloc "
+	  "bpos=%d min_size=%d old_size=%d new_size=%d\n",
+	  p->bpos, min_size, p->size, new_size);
+#endif /* PRINTBUF_DEBUG */
+	if(!(t = (char*)realloc(p->buf, new_size)))
+		return -1;
+	p->size = new_size;
+	p->buf = t;
+	return 0;
+}
+
+int printbuf_memappend(struct printbuf *p, const char *buf, int size)
+{
+  if (p->size <= p->bpos + size + 1) {
+    if (printbuf_extend(p, p->bpos + size + 1) < 0)
+      return -1;
+  }
+  memcpy(p->buf + p->bpos, buf, size);
+  p->bpos += size;
+  p->buf[p->bpos]= '\0';
+  return size;
+}
+
+int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
+{
+	int size_needed;
+
+	if (offset == -1)
+		offset = pb->bpos;
+	size_needed = offset + len;
+	if (pb->size < size_needed)
+	{
+		if (printbuf_extend(pb, size_needed) < 0)
+			return -1;
+	}
+
+	memset(pb->buf + offset, charvalue, len);
+	if (pb->bpos < size_needed)
+		pb->bpos = size_needed;
+
+	return 0;
+}
+
+#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER)
+# define vsnprintf _vsnprintf
+#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */
+# error Need vsnprintf!
+#endif /* !HAVE_VSNPRINTF && defined(WIN32) */
+
+#if !defined(HAVE_VASPRINTF)
+/* CAW: compliant version of vasprintf */
+static int vasprintf(char **buf, const char *fmt, va_list ap)
+{
+#ifndef WIN32
+	static char _T_emptybuffer = '\0';
+#endif /* !defined(WIN32) */
+	int chars;
+	char *b;
+
+	if(!buf) { return -1; }
+
+#ifdef WIN32
+	chars = _vscprintf(fmt, ap)+1;
+#else /* !defined(WIN32) */
+	/* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
+	   our buffer like on some 64bit sun systems.... but hey, its time to move on */
+	chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1;
+	if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */
+#endif /* defined(WIN32) */
+
+	b = (char*)malloc(sizeof(char)*chars);
+	if(!b) { return -1; }
+
+	if((chars = vsprintf(b, fmt, ap)) < 0)
+	{
+		free(b);
+	} else {
+		*buf = b;
+	}
+
+	return chars;
+}
+#endif /* !HAVE_VASPRINTF */
+
+int sprintbuf(struct printbuf *p, const char *msg, ...)
+{
+  va_list ap;
+  char *t;
+  int size;
+  char buf[128];
+
+  /* user stack buffer first */
+  va_start(ap, msg);
+  size = vsnprintf(buf, 128, msg, ap);
+  va_end(ap);
+  /* if string is greater than stack buffer, then use dynamic string
+     with vasprintf.  Note: some implementation of vsnprintf return -1
+     if output is truncated whereas some return the number of bytes that
+     would have been written - this code handles both cases. */
+  if(size == -1 || size > 127) {
+    va_start(ap, msg);
+    if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }
+    va_end(ap);
+    printbuf_memappend(p, t, size);
+    free(t);
+    return size;
+  } else {
+    printbuf_memappend(p, buf, size);
+    return size;
+  }
+}
+
+void printbuf_reset(struct printbuf *p)
+{
+  p->buf[0] = '\0';
+  p->bpos = 0;
+}
+
+void printbuf_free(struct printbuf *p)
+{
+  if(p) {
+    free(p->buf);
+    free(p);
+  }
+}
diff --git a/json-c/printbuf.h b/json-c/printbuf.h
new file mode 100644
index 0000000..b1bde7f
--- /dev/null
+++ b/json-c/printbuf.h
@@ -0,0 +1,77 @@
+/*
+ * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
+ *
+ * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ *
+ * Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.
+ * The copyrights to the contents of this file are licensed under the MIT License
+ * (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+#ifndef _printbuf_h_
+#define _printbuf_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct printbuf {
+  char *buf;
+  int bpos;
+  int size;
+};
+
+extern struct printbuf*
+printbuf_new(void);
+
+/* As an optimization, printbuf_memappend_fast is defined as a macro
+ * that handles copying data if the buffer is large enough; otherwise
+ * it invokes printbuf_memappend_real() which performs the heavy
+ * lifting of realloc()ing the buffer and copying data.
+ * Your code should not use printbuf_memappend directly--use
+ * printbuf_memappend_fast instead.
+ */
+extern int
+printbuf_memappend(struct printbuf *p, const char *buf, int size);
+
+#define printbuf_memappend_fast(p, bufptr, bufsize)          \
+do {                                                         \
+  if ((p->size - p->bpos) > bufsize) {                       \
+    memcpy(p->buf + p->bpos, (bufptr), bufsize);             \
+    p->bpos += bufsize;                                      \
+    p->buf[p->bpos]= '\0';                                   \
+  } else {  printbuf_memappend(p, (bufptr), bufsize); }      \
+} while (0)
+
+#define printbuf_length(p) ((p)->bpos)
+
+/**
+ * Set len bytes of the buffer to charvalue, starting at offset offset.
+ * Similar to calling memset(x, charvalue, len);
+ *
+ * The memory allocated for the buffer is extended as necessary.
+ *
+ * If offset is -1, this starts at the end of the current data in the buffer.
+ */
+extern int
+printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len);
+
+extern int
+sprintbuf(struct printbuf *p, const char *msg, ...);
+
+extern void
+printbuf_reset(struct printbuf *p);
+
+extern void
+printbuf_free(struct printbuf *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json-c/random_seed.c b/json-c/random_seed.c
new file mode 100644
index 0000000..f671929
--- /dev/null
+++ b/json-c/random_seed.c
@@ -0,0 +1,237 @@
+/*
+ * random_seed.c
+ *
+ * Copyright (c) 2013 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#include <stdio.h>
+#include "config.h"
+
+#define DEBUG_SEED(s)
+
+
+#if defined ENABLE_RDRAND
+
+/* cpuid */
+
+#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+#define HAS_X86_CPUID 1
+
+static void do_cpuid(int regs[], int h)
+{
+    __asm__ __volatile__(
+#if defined __x86_64__
+                         "pushq %%rbx;\n"
+#else
+                         "pushl %%ebx;\n"
+#endif
+                         "cpuid;\n"
+#if defined __x86_64__
+                         "popq %%rbx;\n"
+#else
+                         "popl %%ebx;\n"
+#endif
+                         : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
+                         : "a"(h));
+}
+
+#elif defined _MSC_VER
+
+#define HAS_X86_CPUID 1
+#define do_cpuid __cpuid
+
+#endif
+
+/* has_rdrand */
+
+#if HAS_X86_CPUID
+
+static int has_rdrand()
+{
+    // CPUID.01H:ECX.RDRAND[bit 30] == 1
+    int regs[4];
+    do_cpuid(regs, 1);
+    return (regs[2] & (1 << 30)) != 0;
+}
+
+#endif
+
+/* get_rdrand_seed - GCC x86 and X64 */
+
+#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+
+#define HAVE_RDRAND 1
+
+static int get_rdrand_seed()
+{
+    DEBUG_SEED("get_rdrand_seed");
+    int _eax;
+    // rdrand eax
+    __asm__ __volatile__("1: .byte 0x0F\n"
+                         "   .byte 0xC7\n"
+                         "   .byte 0xF0\n"
+                         "   jnc 1b;\n"
+                         : "=a" (_eax));
+    return _eax;
+}
+
+#endif
+
+#if defined _MSC_VER
+
+#if _MSC_VER >= 1700
+#define HAVE_RDRAND 1
+
+/* get_rdrand_seed - Visual Studio 2012 and above */
+
+static int get_rdrand_seed()
+{
+    DEBUG_SEED("get_rdrand_seed");
+    int r;
+    while (_rdrand32_step(&r) == 0);
+    return r;
+}
+
+#elif defined _M_IX86
+#define HAVE_RDRAND 1
+
+/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */
+
+static int get_rdrand_seed()
+{
+	DEBUG_SEED("get_rdrand_seed");
+	int _eax;
+retry:
+	// rdrand eax
+	__asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0
+	__asm jnc retry
+	__asm mov _eax, eax
+	return _eax;
+}
+
+#endif
+#endif
+
+#endif /* defined ENABLE_RDRAND */
+
+
+/* has_dev_urandom */
+
+#if defined (__APPLE__) || defined(__unix__) || defined(__linux__)
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#define HAVE_DEV_RANDOM 1
+
+static const char *dev_random_file = "/dev/urandom";
+
+static int has_dev_urandom()
+{
+    struct stat buf;
+    if (stat(dev_random_file, &buf)) {
+        return 0;
+    }
+    return ((buf.st_mode & S_IFCHR) != 0);
+}
+
+
+/* get_dev_random_seed */
+
+static int get_dev_random_seed()
+{
+    DEBUG_SEED("get_dev_random_seed");
+    
+    int fd = open(dev_random_file, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno));
+        exit(1);
+    }
+    
+    int r;
+    ssize_t nread = read(fd, &r, sizeof(r));
+    if (nread != sizeof(r)) {
+        fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno));
+        exit(1);
+    }
+
+    close(fd);
+    return r;
+}
+
+#endif
+
+
+/* get_cryptgenrandom_seed */
+
+#ifdef WIN32
+
+#define HAVE_CRYPTGENRANDOM 1
+
+#include <windows.h>
+#include <wincrypt.h>
+#ifndef __GNUC__
+#pragma comment(lib, "advapi32.lib")
+#endif
+
+static int get_cryptgenrandom_seed()
+{
+    DEBUG_SEED("get_cryptgenrandom_seed");
+    
+    HCRYPTPROV hProvider = 0;
+    int r;
+    
+    if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+        fprintf(stderr, "error CryptAcquireContextW");
+        exit(1);
+    }
+    
+    if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) {
+        fprintf(stderr, "error CryptGenRandom");
+        exit(1);
+    }
+    
+    CryptReleaseContext(hProvider, 0);
+    
+    return r;
+}
+
+#endif
+
+
+/* get_time_seed */
+
+#include <time.h>
+
+static int get_time_seed()
+{
+    DEBUG_SEED("get_time_seed");
+    
+    return (int)time(NULL) * 433494437;
+}
+
+
+/* json_c_get_random_seed */
+
+int json_c_get_random_seed()
+{
+#if HAVE_RDRAND
+    if (has_rdrand()) return get_rdrand_seed();
+#endif
+#if HAVE_DEV_RANDOM
+    if (has_dev_urandom()) return get_dev_random_seed();
+#endif
+#if HAVE_CRYPTGENRANDOM
+    return get_cryptgenrandom_seed();
+#endif
+    return get_time_seed();
+}
diff --git a/json-c/random_seed.h b/json-c/random_seed.h
new file mode 100644
index 0000000..7362d67
--- /dev/null
+++ b/json-c/random_seed.h
@@ -0,0 +1,25 @@
+/*
+ * random_seed.h
+ *
+ * Copyright (c) 2013 Metaparadigm Pte. Ltd.
+ * Michael Clark <michael@metaparadigm.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See COPYING for details.
+ *
+ */
+
+#ifndef seed_h
+#define seed_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int json_c_get_random_seed();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/keymaster/Android.bp b/keymaster/Android.bp
new file mode 100644
index 0000000..02d52a9
--- /dev/null
+++ b/keymaster/Android.bp
@@ -0,0 +1,27 @@
+//
+// 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_binary {
+    name: "wait_for_strongbox",
+    relative_install_path: "hw",
+    srcs: [ "wait_for_strongbox.cpp" ],
+    cflags: [ "-Werror", "-Wall" ],
+    shared_libs: [
+        "android.hardware.keymaster@4.0",
+        "libbase",
+        "libkeymaster4support",
+    ],
+    proprietary: true,
+}
diff --git a/keymaster/wait_for_strongbox.cpp b/keymaster/wait_for_strongbox.cpp
new file mode 100644
index 0000000..8f95741
--- /dev/null
+++ b/keymaster/wait_for_strongbox.cpp
@@ -0,0 +1,59 @@
+/*
+ ** 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 <unistd.h>
+
+#define LOG_TAG "wait_for_strongbox"
+#include <android-base/logging.h>
+
+#include <keymasterV4_0/Keymaster.h>
+
+using android::hardware::keymaster::V4_0::SecurityLevel;
+using android::hardware::keymaster::V4_0::support::Keymaster;
+
+useconds_t kWaitTimeMicroseconds = 1 * 1000;  // 1 milliseconds
+
+int main() {
+    for (unsigned cycleCount = 0; /* Forever */; ++cycleCount) {
+        auto keymasters = Keymaster::enumerateAvailableDevices();
+
+        bool foundStrongBox = false;
+        bool foundTee = false;
+        for (auto &dev : keymasters) {
+            SecurityLevel securityLevel = dev->halVersion().securityLevel;
+            uint8_t majorVersion = dev->halVersion().majorVersion;
+            if (securityLevel == SecurityLevel::STRONGBOX && majorVersion == 4) {
+                foundStrongBox = true;
+            }
+            if (securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT && majorVersion == 4) {
+                foundTee = true;
+            }
+        }
+
+        if (foundTee && foundStrongBox) {
+            return 0;
+        }
+        if (cycleCount % 10 == 1) {
+            if (!foundStrongBox) {
+                LOG(WARNING) << "Still waiting for StrongBox Keymaster";
+            }
+            if (!foundTee) {
+                LOG(WARNING) << "Still waiting for TEE Keymaster";
+            }
+        }
+        usleep(kWaitTimeMicroseconds);
+    }
+}
diff --git a/manifest.xml b/manifest.xml
new file mode 100644
index 0000000..574bf49
--- /dev/null
+++ b/manifest.xml
@@ -0,0 +1,605 @@
+<!-- Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<manifest version="1.0" type="device" target-level="3">
+    <hal format="hidl">
+        <name>android.hardware.boot</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.0</version>
+        <interface>
+            <name>IBootControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.health</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>IHealth</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.audio</name>
+        <transport>hwbinder</transport>
+        <version>5.0</version>
+        <interface>
+            <name>IDevicesFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.audio.effect</name>
+        <transport>hwbinder</transport>
+        <version>5.0</version>
+        <interface>
+            <name>IEffectsFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.usb</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>IUsb</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.usb.gadget</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.confirmationui</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.soundtrigger</name>
+        <transport>hwbinder</transport>
+        <version>2.2</version>
+        <interface>
+            <name>ISoundTriggerHw</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <!-- video omx hal -->
+    <hal format="hidl">
+        <name>android.hardware.media.omx</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.0</version>
+        <interface>
+            <name>IOmx</name>
+            <instance>default</instance>
+        </interface>
+        <interface>
+            <name>IOmxStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <!-- /video omx hal -->
+    <!-- display -->
+    <hal format="hidl">
+        <name>android.hardware.graphics.allocator</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>3.0</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.graphics.mapper</name>
+        <transport arch="32+64">passthrough</transport>
+        <impl level="generic"></impl>
+        <version>3.0</version>
+        <interface>
+            <name>IMapper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.display.allocator</name>
+        <transport>hwbinder</transport>
+        <version>3.0</version>
+        <interface>
+            <name>IQtiAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.display.mapper</name>
+        <transport arch="32+64">passthrough</transport>
+        <version>3.0</version>
+        <interface>
+            <name>IQtiMapper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.display.mapperextensions</name>
+        <transport arch="32+64">passthrough</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IQtiMapperExtensions</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.graphics.composer</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>2.3</version>
+        <interface>
+            <name>IComposer</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.display.config</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.1</version>
+        <interface>
+            <name>IDisplayConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.google.radioext</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IRadioExt</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.configstore</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.1</version>
+        <interface>
+            <name>ISurfaceFlingerConfigs</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.memtrack</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.0</version>
+        <interface>
+            <name>IMemtrack</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.secure_element</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ISecureElement</name>
+            <instance>eSE1</instance>
+            <instance>SIM1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.sensors</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.camera.provider</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>2.4</version>
+        <interface>
+            <name>ICameraProvider</name>
+            <instance>internal/0</instance>
+        </interface>
+    </hal>
+    <!-- gatekeeper -->
+    <hal format="hidl">
+       <name>android.hardware.gatekeeper</name>
+       <transport>hwbinder</transport>
+       <version>1.0</version>
+       <interface>
+           <name>IGatekeeper</name>
+           <instance>default</instance>
+       </interface>
+   </hal>
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <fqname>@1.1::IGnss/default</fqname>
+        <fqname>@2.0::IGnss/default</fqname>
+    </hal>
+    <!-- qcrilhook -->
+    <hal format="hidl">
+        <name>vendor.qti.hardware.radio.qcrilhook</name>
+           <transport>hwbinder</transport>
+           <version>1.0</version>
+           <interface>
+               <name>IQtiOemHook</name>
+               <instance>oemhook0</instance>
+               <instance>oemhook1</instance>
+           </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.radio.ims</name>
+        <transport>hwbinder</transport>
+        <version>1.4</version>
+        <interface>
+            <name>IImsRadio</name>
+            <instance>imsradio0</instance>
+            <instance>imsradio1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.radio.uim</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IUim</name>
+            <instance>Uim0</instance>
+            <instance>Uim1</instance>
+        </interface>
+    </hal>
+    <!-- RIL UIM REMOTE CLIENT -->
+    <hal format="hidl">
+        <name>vendor.qti.hardware.radio.uim_remote_client</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IUimRemoteServiceClient</name>
+            <instance>uimRemoteClient0</instance>
+            <instance>uimRemoteClient1</instance>
+        </interface>
+    </hal>
+    <!-- RIL UIM REMOTE SERVER -->
+    <hal format="hidl">
+        <name>vendor.qti.hardware.radio.uim_remote_server</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IUimRemoteServiceServer</name>
+            <instance>uimRemoteServer0</instance>
+            <instance>uimRemoteServer1</instance>
+        </interface>
+    </hal>
+    <!-- IMS RTP Service -->
+    <hal format="hidl">
+        <name>vendor.qti.imsrtpservice</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>2.0</version>
+        <interface>
+            <name>IRTPService</name>
+            <instance>imsrtpservice</instance>
+        </interface>
+    </hal>
+    <!-- bluetooth -->
+    <hal format="hidl">
+        <name>android.hardware.bluetooth</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.bluetooth.a2dp</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothAudioOffload</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.bluetooth.audio</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>IBluetoothAudioProvidersFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <!-- IMS UCE Service -->
+   <hal format="hidl">
+       <name>com.qualcomm.qti.uceservice</name>
+       <transport>hwbinder</transport>
+       <version>2.0</version>
+       <interface>
+         <name>IUceService</name>
+         <instance>com.qualcomm.qti.uceservice</instance>
+       </interface>
+   </hal>
+   <!-- IMS callinfo Service -->
+   <hal format="hidl">
+       <name>vendor.qti.ims.callinfo</name>
+       <transport>hwbinder</transport>
+       <version>1.0</version>
+       <interface>
+         <name>IService</name>
+         <instance>default</instance>
+       </interface>
+   </hal>
+   <hal format="hidl">
+       <name>com.qualcomm.qti.imscmservice</name>
+       <transport>hwbinder</transport>
+       <version>2.1</version>
+       <interface>
+         <name>IImsCmService</name>
+         <instance>qti.ims.connectionmanagerservice</instance>
+       </interface>
+   </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.radio.am</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IQcRilAudio</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.wifi</name>
+        <transport>hwbinder</transport>
+        <version>1.3</version>
+        <interface>
+            <name>IWifi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.wifi.supplicant</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>ISupplicant</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.wifi.hostapd</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IHostapd</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.data.factory</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>com.quicinc.cne.server</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>2.1</version>
+        <interface>
+            <name>IServer</name>
+            <instance>cnd</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>com.quicinc.cne.api</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.1</version>
+        <interface>
+            <name>IApiService</name>
+            <instance>cnd</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.drm</name>
+        <transport>hwbinder</transport>
+        <impl level="generic"></impl>
+        <version>1.0</version>
+        <interface>
+            <name>ICryptoFactory</name>
+            <instance>widevine</instance>
+            <instance>default</instance>
+        </interface>
+        <interface>
+            <name>IDrmFactory</name>
+            <instance>widevine</instance>
+            <instance>default</instance>
+        </interface>
+        <fqname>@1.2::ICryptoFactory/clearkey</fqname>
+        <fqname>@1.2::IDrmFactory/clearkey</fqname>
+        <fqname>@1.2::ICryptoFactory/widevine</fqname>
+        <fqname>@1.2::IDrmFactory/widevine</fqname>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.radio</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>IRadio</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+        </interface>
+        <interface>
+            <name>ISap</name>
+            <instance>slot1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+      <name>android.hardware.radio.config</name>
+      <transport>hwbinder</transport>
+      <version>1.1</version>
+      <interface>
+        <name>IRadioConfig</name>
+        <instance>default</instance>
+      </interface>
+    </hal>
+   <hal format="hidl">
+       <name>android.hardware.nfc</name>
+       <transport>hwbinder</transport>
+       <version>1.2</version>
+       <interface>
+           <name>INfc</name>
+           <instance>default</instance>
+       </interface>
+    </hal>
+    <!-- Context Hub HAL Service -->
+    <hal format="hidl">
+        <name>android.hardware.contexthub</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IContexthub</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <!-- Neural Network HAL -->
+    <hal format="hidl">
+        <name>android.hardware.neuralnetworks</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>IDevice</name>
+            <instance>darwinn</instance>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <!-- keymaster -->
+    <hal format="hidl">
+       <name>android.hardware.keymaster</name>
+       <transport>hwbinder</transport>
+       <version>4.0</version>
+       <interface>
+           <name>IKeymasterDevice</name>
+           <instance>default</instance>
+           <instance>strongbox</instance>
+       </interface>
+     </hal>
+     <hal format="hidl">
+        <name>android.hardware.power.stats</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IPowerStats</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <!-- light HAL -->
+    <hal format="hidl">
+        <name>android.hardware.light</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>ILight</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>hardware.google.light</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ILight</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.google.airbrush.manager</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IAirbrushManager</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.weaver</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IWeaver</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.dumpstate</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IDumpstateDevice</name>
+            <instance>default</instance>
+        </interface>
+      </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.bluetooth_sar</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothSar</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>vendor.qti.hardware.tui_comm</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ITuiComm</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/media_codecs.xml b/media_codecs.xml
new file mode 100644
index 0000000..5685092
--- /dev/null
+++ b/media_codecs.xml
@@ -0,0 +1,422 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012-2018 The Linux Foundation. All rights reserved.
+     Not a contribution.
+     Copyright (C) 2012-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.
+-->
+
+<!--
+<!DOCTYPE MediaCodecs [
+<!ELEMENT Include EMPTY>
+<!ATTLIST Include href CDATA #REQUIRED>
+<!ELEMENT MediaCodecs (Decoders|Encoders|Include)*>
+<!ELEMENT Decoders (MediaCodec|Include)*>
+<!ELEMENT Encoders (MediaCodec|Include)*>
+<!ELEMENT MediaCodec (Type|Quirk|Include)*>
+<!ATTLIST MediaCodec name CDATA #REQUIRED>
+<!ATTLIST MediaCodec type CDATA>
+<!ELEMENT Type EMPTY>
+<!ATTLIST Type name CDATA #REQUIRED>
+<!ELEMENT Quirk EMPTY>
+<!ATTLIST Quirk name CDATA #REQUIRED>
+]>
+
+There's a simple and a complex syntax to declare the availability of a
+media codec:
+
+A codec that properly follows the OpenMax spec and therefore doesn't have any
+quirks and that only supports a single content type can be declared like so:
+
+    <MediaCodec name="OMX.foo.bar" type="something/interesting" />
+
+If a codec has quirks OR supports multiple content types, the following syntax
+can be used:
+
+    <MediaCodec name="OMX.foo.bar" >
+        <Type name="something/interesting" />
+        <Type name="something/else" />
+        ...
+        <Quirk name="requires-allocate-on-input-ports" />
+        <Quirk name="requires-allocate-on-output-ports" />
+        <Quirk name="output-buffers-are-unreadable" />
+    </MediaCodec>
+
+Only the three quirks included above are recognized at this point:
+
+"requires-allocate-on-input-ports"
+    must be advertised if the component does not properly support specification
+    of input buffers using the OMX_UseBuffer(...) API but instead requires
+    OMX_AllocateBuffer to be used.
+
+"requires-allocate-on-output-ports"
+    must be advertised if the component does not properly support specification
+    of output buffers using the OMX_UseBuffer(...) API but instead requires
+    OMX_AllocateBuffer to be used.
+
+"output-buffers-are-unreadable"
+    must be advertised if the emitted output buffers of a decoder component
+    are not readable, i.e. use a custom format even though abusing one of
+    the official OMX colorspace constants.
+    Clients of such decoders will not be able to access the decoded data,
+    naturally making the component much less useful. The only use for
+    a component with this quirk is to render the output to the screen.
+    Audio decoders MUST NOT advertise this quirk.
+    Video decoders that advertise this quirk must be accompanied by a
+    corresponding color space converter for thumbnail extraction,
+    matching surfaceflinger support that can render the custom format to
+    a texture and possibly other code, so just DON'T USE THIS QUIRK.
+
+
+-->
+
+<!--
+ Non-Secure decoder capabilities
+ (MB is defined as 16x16)
+ _____________________________________________________________________
+ | Codec       | W       H       fps     Mbps    MB/s        Max MB/s|
+ |_____________|_____________________________________________________|
+ | h264        | 1920    1088    480     220     3916800     3916800 |
+ |             | 3820    2160    120     220     3888000             |
+ |             | 4096    2160    96      220     3317760             |
+ |             | 4096    2304    60      220     2211840             |
+ |             | 7680    4320    30      220     3888000             |
+ |             | 8192    4320    24      220     3317760             |
+ | hevc        | 1920    1088    480     220     3916800     3916800 |
+ |             | 3820    2160    120     220     3888000             |
+ |             | 4096    2160    96      220     3317760             |
+ |             | 4096    2304    60      220     2211840             |
+ |             | 7680    4320    30      220     3888000             |
+ |             | 8192    4320    24      220     3317760             |
+ | mpeg4-sw    | 1920    1088    30      40      244800      244800  |
+ | vp8         | 1280    720     240     100     864000      1036800 |
+ |             | 1920    1088    120     100     979200              |
+ |             | 3840    2160    30      100     972000              |
+ |             | 4096    2160    30      100     1036800             |
+ |             | 4096    2304    24      100     884736              |
+ | vp9         | 1920    1088    480     220     3916800     3916800 |
+ |             | 3820    2160    120     220     3888000             |
+ |             | 4096    2160    96      220     3317760             |
+ |             | 4096    2304    60      220     2211840             |
+ |             | 7680    4320    30      220     3888000             |
+ |             | 8192    4320    24      220     3317760             |
+ | vc1         | 1920    1088    30      20      244800      244800  |
+ | div4/5/6-sw | 1920    1088    30      10      244800      244800  |
+ | h263-sw     | 864     480     30      2       48600       48600   |
+ | mpeg2       | 1920    1088    30      40      244800      244800  |
+ |_____________|_____________________________________________________|
+
+ Secure decoder capabilities
+ (MB is defined as 16x16)
+ __________________________________________________________________
+ | Codec    | W       H       fps     Mbps    MB/s        Max MB/s|
+ |__________|_____________________________________________________|
+ | h264     | 1280    720     60      40      216000      2073600 |
+ |          | 1920    1088    60      40      489600              |
+ |          | 3840    2160    60      40      1944000             |
+ |          | 4096    2160    60      40      2073600             |
+ |          | 4096    2304    30      40      1105920             |
+ | hevc     | 1280    720     60      40      216000      2073600 |
+ |          | 1920    1088    60      40      489600              |
+ |          | 3840    2160    60      40      1944000             |
+ |          | 4096    2160    60      40      2073600             |
+ |          | 4096    2304    30      40      1105920             |
+ | vp9      | 1280    720     60      40      216000      2073600 |
+ |          | 1920    1088    60      40      489600              |
+ |          | 3840    2160    60      40      1944000             |
+ |          | 4096    2160    60      40      2073600             |
+ |          | 4096    2304    30      40      1105920             |
+ | mpeg2    | 1920    1088    30      40      244800      244800  |
+ |__________|_____________________________________________________|
+
+ Non-Secure encoder capabilities (Secure not supported)
+ (MB is defined as 16x16)
+ __________________________________________________________________
+ | Codec    | W       H       fps     Mbps    MB/s        Max MB/s|
+ |__________|_____________________________________________________|
+ | h264     | 1280    720     480     160     1728000     1958400 |
+ |          | 1920    1088    240     160     1958400             |
+ |          | 3840    2160    60      160     1944000             |
+ |          | 4096    2160    48      160     1658880             |
+ |          | 4096    2304    30      160     1105920             |
+ | hevc     | 1280    720     480     160     1728000     1958400 |
+ |          | 1920    1088    240     160     1958400             |
+ |          | 3840    2160    60      160     1944000             |
+ |          | 4096    2160    48      160     1658880             |
+ |          | 4096    2304    30      160     1105920             |
+ | mpeg4-sw | 1280    720     30      40      108000      108000  |
+ | vp8      | 1280    720     240     40      864000      1036800 |
+ |          | 1920    1088    120     40      979200              |
+ |          | 3840    2160    30      40      972000              |
+ |          | 4096    2160    30      40      1036800             |
+ |          | 4096    2304    24      40      884736              |
+ | h263-sw  | 864     480     30      2       48600       48600   |
+ |__________|_____________________________________________________|
+-->
+
+<MediaCodecs>
+    <Include href="media_codecs_google_audio.xml" />
+    <Include href="media_codecs_google_telephony.xml" />
+    <Settings>
+        <Setting name="max-video-encoder-input-buffers" value="11" />
+    </Settings>
+    <Encoders>
+        <!-- Video Hardware  -->
+        <MediaCodec name="OMX.qcom.video.encoder.avc" type="video/avc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation" />
+            <Limit name="size" min="96x96" max="4096x2304" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="1958400" />
+            <Limit name="bitrate" range="1-160000000" />
+            <Limit name="frame-rate" range="1-480" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.vp8" type="video/x-vnd.on2.vp8" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation" />
+            <Limit name="size" min="96x96" max="4096x2304" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="1036800" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="frame-rate" range="1-240" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.hevc" type="video/hevc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation" />
+            <Limit name="size" min="96x96" max="4096x2304" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="1958400" />
+            <Limit name="bitrate" range="1-160000000" />
+            <Limit name="frame-rate" range="1-480" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <!-- Video Software -->
+        <MediaCodec name="OMX.qcom.video.encoder.h263sw" type="video/3gpp" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation" />
+            <Limit name="size" min="96x96" max="864x480" />
+            <Limit name="alignment" value="4x4" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="48600" />
+            <Limit name="bitrate" range="1-2000000" />
+            <Limit name="frame-rate" range="1-30" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.mpeg4sw" type="video/mp4v-es" >
+             <Quirk name="requires-allocate-on-input-ports" />
+             <Quirk name="requires-allocate-on-output-ports" />
+             <Quirk name="requires-loaded-to-idle-after-allocation" />
+             <Limit name="size" min="96x96" max="1280x720" />
+             <Limit name="alignment" value="2x2" />
+             <Limit name="block-size" value="16x16" />
+             <Limit name="blocks-per-second" min="36" max="108000" />
+             <Limit name="bitrate" range="1-4000000" />
+             <Limit name="frame-rate" range="1-30" />
+             <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+    </Encoders>
+    <Decoders>
+       <!-- Video Hardware  -->
+        <MediaCodec name="OMX.qcom.video.decoder.avc" type="video/avc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="8192x4320" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="3916800" />
+            <Limit name="bitrate" range="1-220000000" />
+            <Limit name="frame-rate" range="1-480" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.avc.secure" type="video/avc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="4096x2304" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="2073600" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="frame-rate" range="1-60" />
+            <Feature name="adaptive-playback" />
+            <Feature name="secure-playback" required="true" />
+            <Limit name="concurrent-instances" max="6" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.mpeg2" type="video/mpeg2" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="244800" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="frame-rate" range="1-30" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.mpeg2.secure" type="video/mpeg2" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="244800" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="frame-rate" range="1-30" />
+            <Feature name="adaptive-playback" />
+            <Feature name="secure-playback" required="true" />
+            <Limit name="concurrent-instances" max="6" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.vp8" type="video/x-vnd.on2.vp8" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="4096x2304" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="1036800" />
+            <Limit name="bitrate" range="1-100000000" />
+            <Limit name="frame-rate" range="1-240" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.vp9" type="video/x-vnd.on2.vp9" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="8192x4320" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="3916800" />
+            <Limit name="bitrate" range="1-220000000" />
+            <Limit name="frame-rate" range="1-480" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="6" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.vp9.secure" type="video/x-vnd.on2.vp9" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="4096x2304" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="2073600" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="frame-rate" range="1-60" />
+            <Feature name="adaptive-playback" />
+            <Feature name="secure-playback" required="true" />
+            <Limit name="concurrent-instances" max="6" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.hevc" type="video/hevc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="8192x4320" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="3916800" />
+            <Limit name="bitrate" range="1-220000000" />
+            <Limit name="frame-rate" range="1-480" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.hevc.secure" type="video/hevc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="4096x2304" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="2073600" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="frame-rate" range="1-60" />
+            <Feature name="adaptive-playback" />
+            <Feature name="secure-playback" required="true" />
+            <Limit name="concurrent-instances" max="6" />
+        </MediaCodec>
+        <!-- Video Software -->
+        <MediaCodec name="OMX.qti.video.decoder.h263sw" type="video/3gpp" >
+             <Quirk name="requires-allocate-on-input-ports" />
+             <Quirk name="requires-allocate-on-output-ports" />
+             <Limit name="size" min="96x96" max="864x480" />
+             <Limit name="alignment" value="4x4" />
+             <Limit name="block-size" value="16x16" />
+             <Limit name="blocks-per-second" min="36" max="48600" />
+             <Limit name="bitrate" range="1-2000000" />
+             <Limit name="frame-rate" range="1-30" />
+             <Feature name="adaptive-playback" />
+             <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qti.video.decoder.mpeg4sw">
+             <Quirk name="requires-allocate-on-input-ports" />
+             <Quirk name="requires-allocate-on-output-ports" />
+             <Type name="video/mp4v-es">
+                <Limit name="size" min="96x96" max="1920x1088" />
+                <Limit name="alignment" value="2x2" />
+                <Limit name="block-size" value="16x16" />
+                <Limit name="blocks-per-second" min="36" max="244800" />
+                <Limit name="bitrate" range="1-40000000" />
+                <Limit name="frame-rate" range="1-30" />
+                <Limit name="concurrent-instances" max="16" />
+             </Type>
+             <Type name="video/mp4v-esdp">
+                <Limit name="size" min="96x96" max="1920x1088" />
+                <Limit name="alignment" value="2x2" />
+                <Limit name="block-size" value="16x16" />
+                <Limit name="blocks-per-second" min="36" max="244800" />
+                <Limit name="bitrate" range="1-40000000" />
+                <Limit name="frame-rate" range="1-30" />
+                <Limit name="concurrent-instances" max="16" />
+             </Type>
+        </MediaCodec>
+        <MediaCodec name="OMX.qti.video.decoder.divxsw" type="video/divx" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="244800" />
+            <Limit name="frame-rate" range="1-30" />
+            <Limit name="bitrate" range="1-10000000" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qti.video.decoder.divx4sw" type="video/divx4" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="244800" />
+            <Limit name="frame-rate" range="1-30" />
+            <Limit name="bitrate" range="1-10000000" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qti.video.decoder.vc1sw" type="video/x-ms-wmv" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x96" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="36" max="244800" />
+            <Limit name="bitrate" range="1-20000000" />
+            <Limit name="frame-rate" range="1-30" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="16" />
+        </MediaCodec>
+    </Decoders>
+    <Include href="media_codecs_google_video.xml" />
+</MediaCodecs>
diff --git a/media_codecs_performance.xml b/media_codecs_performance.xml
new file mode 100644
index 0000000..b0fbf33
--- /dev/null
+++ b/media_codecs_performance.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+
+Not a Contribution.
+
+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.
+u may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<MediaCodecs>
+    <Encoders>
+        <MediaCodec name="OMX.qcom.video.encoder.avc" type="video/avc" update="true">
+            <Limit name="measured-frame-rate-320x240" range="238-238" />
+            <Limit name="measured-frame-rate-720x480" range="123-123" />
+            <Limit name="measured-frame-rate-1280x720" range="50-50" />
+            <Limit name="measured-frame-rate-1920x1080" range="16-40" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.hevc" type="video/hevc" update="true">
+            <Limit name="measured-frame-rate-320x240" range="226-226" />
+            <Limit name="measured-frame-rate-720x480" range="121-121" />
+            <Limit name="measured-frame-rate-1280x720" range="49-49" />
+            <Limit name="measured-frame-rate-1920x1080" range="16-45" />
+            <Limit name="measured-frame-rate-3840x2160" range="6-24" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.h263sw" type="video/3gpp" update="true">
+            <Limit name="measured-frame-rate-176x144" range="303-303" />
+            <Limit name="measured-frame-rate-352x288" range="259-259" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.mpeg4sw" type="video/mp4v-es" update="true">
+            <Limit name="measured-frame-rate-176x144" range="299-299" />
+            <Limit name="measured-frame-rate-352x288" range="245-245" />
+            <Limit name="measured-frame-rate-640x480" range="148-148" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.vp8" type="video/x-vnd.on2.vp8" update="true">
+            <Limit name="measured-frame-rate-320x180" range="266-266" />
+            <Limit name="measured-frame-rate-640x360" range="165-165" />
+            <Limit name="measured-frame-rate-1280x720" range="49-49" />
+            <Limit name="measured-frame-rate-1920x1080" range="16-40" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.h264.encoder" type="video/avc" update="true">
+            <Limit name="measured-frame-rate-320x240" range="215-215" />
+            <Limit name="measured-frame-rate-720x480" range="100-100" />
+            <Limit name="measured-frame-rate-1280x720" range="56-56" />
+            <Limit name="measured-frame-rate-1920x1080" range="30-30" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.h263.encoder" type="video/3gpp" update="true">
+            <Limit name="measured-frame-rate-176x144" range="200-200" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es" update="true">
+            <Limit name="measured-frame-rate-176x144" range="180-180" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.vp8.encoder" type="video/x-vnd.on2.vp8" update="true">
+            <Limit name="measured-frame-rate-320x180" range="39-39" />
+            <Limit name="measured-frame-rate-640x360" range="32-32" />
+            <Limit name="measured-frame-rate-1280x720" range="17-24" />
+            <Limit name="measured-frame-rate-1920x1080" range="8-12" />
+        </MediaCodec>
+    </Encoders>
+    <Decoders>
+        <MediaCodec name="OMX.qcom.video.decoder.avc" type="video/avc" update="true">
+            <Limit name="measured-frame-rate-320x240" range="221-221" />
+            <Limit name="measured-frame-rate-720x480" range="156-156" />
+            <Limit name="measured-frame-rate-1280x720" range="111-111" />
+            <Limit name="measured-frame-rate-1920x1088" range="71-71" />
+        </MediaCodec>
+            <MediaCodec name="OMX.qcom.video.decoder.hevc" type="video/hevc" update="true">
+            <Limit name="measured-frame-rate-352x288" range="222-222" />
+            <Limit name="measured-frame-rate-720x480" range="165-165" />
+            <Limit name="measured-frame-rate-1280x720" range="88-88" />
+            <Limit name="measured-frame-rate-1920x1080" range="56-56" />
+            <Limit name="measured-frame-rate-3840x2160" range="12-12" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qti.video.decoder.h263sw" type="video/3gpp" update="true">
+            <Limit name="measured-frame-rate-176x144" range="356-356" />
+            <Limit name="measured-frame-rate-352x288" range="292-292" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qti.video.decoder.mpeg4sw" type="video/mp4v-es" update="true">
+            <Limit name="measured-frame-rate-176x144" range="146-146" />
+            <Limit name="measured-frame-rate-480x360" range="145-145" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.vp8" type="video/x-vnd.on2.vp8" update="true">
+            <Limit name="measured-frame-rate-320x240" range="337-337" />
+            <Limit name="measured-frame-rate-640x360" range="337-337" />
+            <Limit name="measured-frame-rate-1280x720" range="337-337" />
+            <Limit name="measured-frame-rate-1920x1080" range="248-248" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.vp9" type="video/x-vnd.on2.vp9" update="true">
+            <Limit name="measured-frame-rate-320x240" range="377-377" />
+            <Limit name="measured-frame-rate-640x360" range="323-323" />
+            <Limit name="measured-frame-rate-1280x720" range="262-262" />
+            <Limit name="measured-frame-rate-1920x1080" range="220-220" />
+            <Limit name="measured-frame-rate-3840x2160" range="51-51" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.h264.decoder" type="video/avc" update="true">
+            <Limit name="measured-frame-rate-320x240" range="122-122" />
+            <Limit name="measured-frame-rate-720x480" range="68-68" />
+            <Limit name="measured-frame-rate-1280x720" range="32-32" />
+            <Limit name="measured-frame-rate-1920x1080" range="6-10" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.h263.decoder" type="video/3gpp" update="true">
+            <Limit name="measured-frame-rate-176x144" range="104-279" />
+            <Limit name="measured-frame-rate-352x288" range="200-200" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.hevc.decoder" type="video/hevc" update="true">
+            <Limit name="measured-frame-rate-352x288" range="170-170" />
+            <Limit name="measured-frame-rate-640x360" range="89-89" />
+            <Limit name="measured-frame-rate-720x480" range="73-73" />
+            <Limit name="measured-frame-rate-1280x720" range="32-32" />
+            <Limit name="measured-frame-rate-1920x1080" range="21-21" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.mpeg4.decoder" update="true">
+            <Type name="video/mp4v-es">
+                <Limit name="measured-frame-rate-176x144" range="430-450" />
+            </Type>
+        </MediaCodec>
+        <MediaCodec name="OMX.google.vp8.decoder" type="video/x-vnd.on2.vp8" update="true">
+            <Limit name="measured-frame-rate-320x240" range="330-381" />
+            <Limit name="measured-frame-rate-640x360" range="139-185" />
+            <Limit name="measured-frame-rate-1280x720" range="22-38" />
+            <Limit name="measured-frame-rate-1920x1080" range="9-18" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.vp9.decoder" type="video/x-vnd.on2.vp9" update="true">
+            <Limit name="measured-frame-rate-320x240" range="200-230" />
+            <Limit name="measured-frame-rate-640x360" range="81-90" />
+            <Limit name="measured-frame-rate-1280x720" range="32-40" />
+            <Limit name="measured-frame-rate-1920x1080" range="19-23" />
+        </MediaCodec>
+    </Decoders>
+</MediaCodecs>
diff --git a/media_codecs_vendor_audio.xml b/media_codecs_vendor_audio.xml
new file mode 100644
index 0000000..dd77026
--- /dev/null
+++ b/media_codecs_vendor_audio.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (C) 2015-2018 The Linux Foundation. All rights reserved.
+     Not a contribution.
+     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.
+-->
+<Included>
+    <Decoders>
+        <!-- SimpleOMXComponet based software decoder-->
+        <MediaCodec name="OMX.qti.audio.decoder.flac" type="audio/flac" >
+            <Limit name="concurrent-instances" max="10" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qti.audio.decoder.mpegh" type="audio/mhas" >
+            <Limit name="concurrent-instances" max="10" />
+        </MediaCodec>
+    </Decoders>
+</Included>
diff --git a/media_profiles.xml b/media_profiles.xml
new file mode 100644
index 0000000..24f4475
--- /dev/null
+++ b/media_profiles.xml
@@ -0,0 +1,1650 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012-2017 The Linux Foundation. All rights reserved.
+     Not a contribution.
+     Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!DOCTYPE MediaSettings [
+<!ELEMENT MediaSettings (CamcorderProfiles,
+                         EncoderOutputFileFormat+,
+                         VideoEncoderCap+,
+                         AudioEncoderCap+,
+                         VideoDecoderCap,
+                         AudioDecoderCap)>
+<!ELEMENT CamcorderProfiles (EncoderProfile+, ImageEncoding+, ImageDecoding, Camera)>
+<!ELEMENT EncoderProfile (Video, Audio)>
+<!ATTLIST EncoderProfile quality (high|low) #REQUIRED>
+<!ATTLIST EncoderProfile fileFormat (mp4|3gp) #REQUIRED>
+<!ATTLIST EncoderProfile duration (30|60) #REQUIRED>
+<!ATTLIST EncoderProfile cameraId (0|1|2|3) #REQUIRED>
+<!ELEMENT Video EMPTY>
+<!ATTLIST Video codec (h264|h263|m4v) #REQUIRED>
+<!ATTLIST Video bitRate CDATA #REQUIRED>
+<!ATTLIST Video width CDATA #REQUIRED>
+<!ATTLIST Video height CDATA #REQUIRED>
+<!ATTLIST Video frameRate CDATA #REQUIRED>
+<!ELEMENT Audio EMPTY>
+<!ATTLIST Audio codec (amrnb|amrwb|aac|lpcm) #REQUIRED>
+<!ATTLIST Audio bitRate CDATA #REQUIRED>
+<!ATTLIST Audio sampleRate CDATA #REQUIRED>
+<!ATTLIST Audio channels (1|2|6) #REQUIRED>
+<!ELEMENT ImageEncoding EMPTY>
+<!ATTLIST ImageEncoding quality (90|80|70|60|50|40) #REQUIRED>
+<!ELEMENT ImageDecoding EMPTY>
+<!ATTLIST ImageDecoding memCap CDATA #REQUIRED>
+<!ELEMENT Camera EMPTY>
+<!ELEMENT EncoderOutputFileFormat EMPTY>
+<!ATTLIST EncoderOutputFileFormat name (mp4|3gp) #REQUIRED>
+<!ELEMENT VideoEncoderCap EMPTY>
+<!ATTLIST VideoEncoderCap name (hevc|h264|h263|m4v|wmv) #REQUIRED>
+<!ATTLIST VideoEncoderCap enabled (true|false) #REQUIRED>
+<!ATTLIST VideoEncoderCap minBitRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxBitRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxHFRFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxHFRFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxHFRMode CDATA #REQUIRED>
+<!ELEMENT AudioEncoderCap EMPTY>
+<!ATTLIST AudioEncoderCap name (amrnb|amrwb|aac|wma|lpcm) #REQUIRED>
+<!ATTLIST AudioEncoderCap enabled (true|false) #REQUIRED>
+<!ATTLIST AudioEncoderCap minBitRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap maxBitRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap minSampleRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap maxSampleRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap minChannels (1|2|6) #REQUIRED>
+<!ATTLIST AudioEncoderCap maxChannels (1|2|6) #REQUIRED>
+<!ELEMENT VideoDecoderCap EMPTY>
+<!ATTLIST VideoDecoderCap name (wmv) #REQUIRED>
+<!ATTLIST VideoDecoderCap enabled (true|false) #REQUIRED>
+<!ELEMENT AudioDecoderCap EMPTY>
+<!ATTLIST AudioDecoderCap name (wma) #REQUIRED>
+<!ATTLIST AudioDecoderCap enabled (true|false) #REQUIRED>
+<!ELEMENT VideoEditorCap EMPTY>
+<!ATTLIST VideoEditorCap maxInputFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxInputFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxOutputFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxOutputFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxPrefetchYUVFrames CDATA #REQUIRED>
+<!ELEMENT ExportVideoProfile EMPTY>
+<!ATTLIST ExportVideoProfile name (h264|h263|m4v) #REQUIRED>
+<!ATTLIST ExportVideoProfile profile CDATA #REQUIRED>
+<!ATTLIST ExportVideoProfile level CDATA #REQUIRED>
+]>
+<!--
+     This file is used to declare the multimedia profiles and capabilities
+     on an android-powered device.
+-->
+<MediaSettings>
+    <!-- Each camcorder profile defines a set of predefined configuration parameters -->
+    <!-- Back Camera -->
+    <CamcorderProfiles cameraId="0">
+
+    <EncoderProfile quality="low" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="high" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="3840"
+             height="2160"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="cif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="720000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="720"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="14000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qhd" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="2560"
+             height="1440"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="2k" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="2048"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="4kdci" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="4096"
+            height="2160"
+            frameRate="24" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="2160p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="3840"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qcif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="vga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapselow" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsehigh" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="3840"
+             height="2160"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsecif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="720000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+
+    <EncoderProfile quality="timelapseqvga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsevga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="14000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqhd" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="2560"
+             height="1440"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse2k" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="2048"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse4kdci" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="4096"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse2160p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="3840"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+    <!-- Front Camera -->
+    <CamcorderProfiles cameraId="1">
+
+    <EncoderProfile quality="low" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="high" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="cif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="720000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="720"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="14000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qcif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+     <EncoderProfile quality="vga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <!-- TIMELAPSE profiles for front camera -->
+    <EncoderProfile quality="timelapselow" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsehigh" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsecif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="1200000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqvga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsevga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="5000000"
+             width="720"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="8000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+    <!-- Camera ID 2 -->
+    <CamcorderProfiles cameraId="2">
+
+    <EncoderProfile quality="low" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="high" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="3840"
+             height="2160"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="cif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="720000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="720"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="14000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qhd" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="2560"
+             height="1440"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="2k" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="2048"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="4kdci" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="4096"
+            height="2160"
+            frameRate="24" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="2160p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="3840"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qcif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="vga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapselow" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsehigh" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="3840"
+             height="2160"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsecif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="720000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+
+    <EncoderProfile quality="timelapseqvga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsevga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="14000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqhd" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="2560"
+             height="1440"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse2k" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="2048"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse4kdci" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="4096"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse2160p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="3840"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeed1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="1920"
+             height="1080"
+             frameRate="120" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeedhigh" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="24000000"
+             width="1280"
+             height="720"
+             frameRate="240" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeed720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="24000000"
+             width="1280"
+             height="720"
+             frameRate="240" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeed480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="12000000"
+             width="640"
+             height="480"
+             frameRate="240" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <CamcorderProfiles cameraId="3">
+
+    <EncoderProfile quality="low" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="high" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="3840"
+             height="2160"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="cif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="720000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="720"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="14000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qhd" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="2560"
+             height="1440"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="2k" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="2048"
+             height="1080"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="4kdci" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="4096"
+            height="2160"
+            frameRate="24" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="2160p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="3840"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="qcif" fileFormat="3gp" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="vga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapselow" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsehigh" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="3840"
+             height="2160"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="192000"
+             width="176"
+             height="144"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsecif" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="720000"
+             width="352"
+             height="288"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+
+    <EncoderProfile quality="timelapseqvga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="512000"
+             width="320"
+             height="240"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapsevga" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="amrnb"
+             bitRate="12200"
+             sampleRate="8000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="2000000"
+             width="640"
+             height="480"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="14000000"
+             width="1280"
+             height="720"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="1920"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapseqhd" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="2560"
+             height="1440"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse2k" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="20000000"
+             width="2048"
+             height="1080"
+             frameRate="30" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse4kdci" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="4096"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="timelapse2160p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+            bitRate="42000000"
+            width="3840"
+            height="2160"
+            frameRate="30" />
+
+      <Audio codec="aac"
+            bitRate="156000"
+            sampleRate="48000"
+            channels="2" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeed1080p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="42000000"
+             width="1920"
+             height="1080"
+             frameRate="120" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeedhigh" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="24000000"
+             width="1280"
+             height="720"
+             frameRate="240" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeed720p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="24000000"
+             width="1280"
+             height="720"
+             frameRate="240" />
+
+      <!-- audio setting is ignored -->
+      <Audio codec="aac"
+             bitRate="96000"
+             sampleRate="48000"
+             channels="1" />
+    </EncoderProfile>
+
+    <EncoderProfile quality="highspeed480p" fileFormat="mp4" duration="30">
+      <Video codec="h264"
+             bitRate="12000000"
+             width="640"
+             height="480"
+             frameRate="240" />
+
+      <Audio codec="aac"
+             bitRate="156000"
+             sampleRate="48000"
+             channels="2" />
+    </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <EncoderOutputFileFormat name="3gp" />
+    <EncoderOutputFileFormat name="mp4" />
+
+    <!--
+         If a codec is not enabled, it is invisible to the applications
+         In other words, the applications won't be able to use the codec
+         or query the capabilities of the codec at all if it is disabled
+    -->
+    <VideoEncoderCap name="h264" enabled="true"
+        minBitRate="64000" maxBitRate="42000000"
+        minFrameWidth="176" maxFrameWidth="4096"
+        minFrameHeight="144" maxFrameHeight="2160"
+        minFrameRate="15" maxFrameRate="30"
+        maxHFRFrameWidth="1920" maxHFRFrameHeight="1080"
+        maxHFRMode="120"  />
+
+    <VideoEncoderCap name="h263" enabled="true"
+        minBitRate="64000" maxBitRate="2000000"
+        minFrameWidth="176" maxFrameWidth="800"
+        minFrameHeight="144" maxFrameHeight="480"
+        minFrameRate="15" maxFrameRate="30"
+        maxHFRFrameWidth="0" maxHFRFrameHeight="0"
+        maxHFRMode="0"  />
+
+    <VideoEncoderCap name="m4v" enabled="true"
+        minBitRate="64000" maxBitRate="20000000"
+        minFrameWidth="176" maxFrameWidth="1920"
+        minFrameHeight="144" maxFrameHeight="1088"
+        minFrameRate="15" maxFrameRate="30"
+        maxHFRFrameWidth="0" maxHFRFrameHeight="0"
+        maxHFRMode="0"  />
+
+    <VideoEncoderCap name="hevc" enabled="true"
+        minBitRate="64000" maxBitRate="100000000"
+        minFrameWidth="176" maxFrameWidth="4096"
+        minFrameHeight="144" maxFrameHeight="2160"
+        minFrameRate="15" maxFrameRate="30"
+        maxHFRFrameWidth="0" maxHFRFrameHeight="0"
+        maxHFRMode="0"  />
+
+    <AudioEncoderCap name="aac" enabled="true"
+        minBitRate="8000" maxBitRate="96000"
+        minSampleRate="8000" maxSampleRate="48000"
+        minChannels="1" maxChannels="6" />
+
+    <AudioEncoderCap name="heaac" enabled="true"
+        minBitRate="8000" maxBitRate="64000"
+        minSampleRate="16000" maxSampleRate="48000"
+        minChannels="1" maxChannels="1" />
+
+    <AudioEncoderCap name="aaceld" enabled="true"
+        minBitRate="16000" maxBitRate="192000"
+        minSampleRate="16000" maxSampleRate="48000"
+        minChannels="1" maxChannels="1" />
+
+    <AudioEncoderCap name="amrwb" enabled="true"
+        minBitRate="6600" maxBitRate="23850"
+        minSampleRate="16000" maxSampleRate="16000"
+        minChannels="1" maxChannels="1" />
+
+    <AudioEncoderCap name="amrnb" enabled="true"
+        minBitRate="5525" maxBitRate="12200"
+        minSampleRate="8000" maxSampleRate="8000"
+        minChannels="1" maxChannels="1" />
+
+    <AudioEncoderCap name="lpcm" enabled="true"
+        minBitRate="768000" maxBitRate="4608000"
+        minSampleRate="8000" maxSampleRate="48000"
+        minChannels="1" maxChannels="6" />
+
+    <!--
+        FIXME:
+        We do not check decoder capabilities at present
+        At present, we only check whether windows media is visible
+        for TEST applications. For other applications, we do
+        not perform any checks at all.
+    -->
+    <VideoDecoderCap name="wmv" enabled="true"/>
+    <AudioDecoderCap name="wma" enabled="true"/>
+
+    <!--
+        The VideoEditor Capability configuration:
+        - maxInputFrameWidth: maximum video width of imported video clip.
+        - maxInputFrameHeight: maximum video height of imported video clip.
+        - maxOutputFrameWidth: maximum video width of exported video clip.
+        - maxOutputFrameHeight: maximum video height of exported video clip.
+        - maxPrefetchYUVFrames: maximum prefetch YUV frames for encoder,
+        used to limit the amount of memory for prefetched YUV frames.
+        For this platform, it allows maximum 30MB(3MB per 1080p frame x 10
+        frames) memory.
+    -->
+    <VideoEditorCap  maxInputFrameWidth="1920"
+        maxInputFrameHeight="1088" maxOutputFrameWidth="1920"
+        maxOutputFrameHeight="1088" maxPrefetchYUVFrames="10"/>
+    <!--
+        The VideoEditor Export codec profile and level values
+        correspond to the values in OMX_Video.h.
+        E.g. for h264, profile value 1 means OMX_VIDEO_AVCProfileBaseline
+        and  level 4096 means OMX_VIDEO_AVCLevel41.
+        Please note that the values are in decimal.
+        These values are for video encoder.
+    -->
+    <!--
+      Codec = h.264, Baseline profile, level 4.0
+    -->
+    <ExportVideoProfile name="h264" profile= "1" level="2048"/>
+    <!--
+      Codec = h.263, Baseline profile, level 70
+    -->
+    <ExportVideoProfile name="h263" profile= "1" level="128"/>
+    <!--
+      Codec = mpeg4, Simple profile, level 5
+    -->
+    <ExportVideoProfile name="m4v" profile= "1" level="128"/>
+</MediaSettings>
diff --git a/media_profiles_V1_0.xml b/media_profiles_V1_0.xml
new file mode 100644
index 0000000..bee4016
--- /dev/null
+++ b/media_profiles_V1_0.xml
@@ -0,0 +1,551 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<!DOCTYPE MediaSettings SYSTEM "/system/etc/media_profiles_V1_0.dtd">
+<!--
+     This file is used to declare the multimedia profiles and capabilities
+     on an android-powered device.
+-->
+<MediaSettings>
+    <!-- ****************************************************************** -->
+    <!-- camera id = 0 : logical dual rear cameras (wide is 3, tele is 4)   -->
+    <!-- ****************************************************************** -->
+    <CamcorderProfiles cameraId="0">
+
+        <!-- low: 176 x 144 30fps -->
+        <EncoderProfile quality="low" fileFormat="3gp" duration="60">
+            <Video codec="h264"
+                   bitRate="128000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- high: 3840 x 2160 30fps -->
+        <EncoderProfile quality="high" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="48000000"
+                   width="3840"
+                   height="2160"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- qcif: 176 x 144 30fps -->
+        <EncoderProfile quality="qcif" fileFormat="3gp" duration="60">
+            <Video codec="h264"
+                   bitRate="128000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- qvga: 320 x 240 30fps -->
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="h264"
+                   bitRate="512000"
+                   width="320"
+                   height="240"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="156000"
+                   sampleRate="48000"
+                   channels="2" />
+        </EncoderProfile>
+
+        <!-- cif: 352 x 288 30fps -->
+        <EncoderProfile quality="cif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="1200000"
+                   width="352"
+                   height="288"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- 480p: 720 x 480 30fps -->
+        <EncoderProfile quality="480p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="6000000"
+                   width="720"
+                   height="480"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- 720p: 1280 x 720 60fps -->
+        <EncoderProfile quality="720p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="18000000"
+                   width="1280"
+                   height="720"
+                   frameRate="60" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- 1080p: 1920 x 1080 60fps -->
+        <EncoderProfile quality="1080p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="33000000"
+                   width="1920"
+                   height="1080"
+                   frameRate="60" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- 2160p: 3840 x 2160 30fps -->
+        <EncoderProfile quality="2160p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="48000000"
+                   width="3840"
+                   height="2160"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_qcif: 176 x 144 30fps -->
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_cif: 352 x 288 30fps -->
+        <EncoderProfile quality="timelapsecif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="1200000"
+                   width="352"
+                   height="288"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_480p: 720 x 480 30fps -->
+        <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="6000000"
+                   width="720"
+                   height="480"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_720p: 1280 x 720 30fps -->
+        <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="12000000"
+                   width="1280"
+                   height="720"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_1080p: 1920 x 1080 30fps -->
+        <EncoderProfile quality="timelapse1080p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="17000000"
+                   width="1920"
+                   height="1080"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_2160p: 3840 x 2160 30fps -->
+        <EncoderProfile quality="timelapse2160p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="42000000"
+                   width="3840"
+                   height="2160"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- highspeed_low: 1920 x 1080 240fps 63.0 Mbps -->
+        <EncoderProfile quality="highspeedlow" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="63000000"
+                   width="1920"
+                   height="1080"
+                   frameRate="240" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- highspeed_high: 1920 x 1080 240fps 63.0 Mbps -->
+        <EncoderProfile quality="highspeedhigh" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="63000000"
+                   width="1920"
+                   height="1080"
+                   frameRate="240" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- highspeed_1080p: 1920 x 1080 240fps 63.0 Mbps -->
+        <EncoderProfile quality="highspeed1080p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="63000000"
+                   width="1920"
+                   height="1080"
+                   frameRate="240" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+    </CamcorderProfiles>
+
+    <!-- ****************************************************************** -->
+    <!-- camera id = 1 : front RGBD cameras                                 -->
+    <!-- ****************************************************************** -->
+    <CamcorderProfiles cameraId="1">
+
+        <!-- low: 176 x 144 30fps -->
+        <EncoderProfile quality="low" fileFormat="3gp" duration="60">
+            <Video codec="h264"
+                   bitRate="128000"
+                    width="176"
+                    height="144"
+                    frameRate="30" />
+            <Audio codec="amrnb"
+                    bitRate="12200"
+                    sampleRate="8000"
+                    channels="1" />
+        </EncoderProfile>
+
+        <!-- high: 1920 x 1080 30fps -->
+        <EncoderProfile quality="high" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="22000000"
+                   width="1920"
+                   height="1080"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- qcif: 176 x 144 30fps -->
+        <EncoderProfile quality="qcif" fileFormat="3gp" duration="60">
+            <Video codec="h264"
+                   bitRate="128000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- qvga: 320 x 240 30fps -->
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="h264"
+                   bitRate="512000"
+                   width="320"
+                   height="240"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="156000"
+                   sampleRate="48000"
+                   channels="2" />
+        </EncoderProfile>
+
+        <!-- cif: 352 x 288 30fps -->
+        <EncoderProfile quality="cif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="1200000"
+                   width="352"
+                   height="288"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- 480p: 720 x 480 30fps -->
+        <EncoderProfile quality="480p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="6000000"
+                   width="720"
+                   height="480"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- 720p: 1280 x 720 30fps -->
+        <EncoderProfile quality="720p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="12000000"
+                   width="1280"
+                   height="720"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- 1080p: 1920 x 1080 30fps -->
+        <EncoderProfile quality="1080p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="22000000"
+                   width="1920"
+                   height="1080"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_qcif: 176 x 144 30fps -->
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_cif: 352 x 288 30fps -->
+        <EncoderProfile quality="timelapsecif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="1200000"
+                   width="352"
+                   height="288"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_480p: 720 x 480 30fps -->
+        <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="6000000"
+                   width="720"
+                   height="480"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_720p: 1280 x 720 30fps -->
+        <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="12000000"
+                   width="1280"
+                   height="720"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+    </CamcorderProfiles>
+
+    <!-- ****************************************************************** -->
+    <!-- camera id = 2 : logical dual IR cameras (lead is 6, follower is 7) -->
+    <!-- ****************************************************************** -->
+    <CamcorderProfiles cameraId="2">
+
+        <!-- 480p: 640 x 480 30fps -->
+        <EncoderProfile quality="480p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="6000000"
+                   width="640"
+                   height="480"
+                   frameRate="30" />
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <!-- timelapse_480p: 640 x 480 30fps -->
+        <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="6000000"
+                   width="640"
+                   height="480"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="aac"
+                   bitRate="96000"
+                   sampleRate="48000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+    </CamcorderProfiles>
+
+    <EncoderOutputFileFormat name="3gp" />
+    <EncoderOutputFileFormat name="mp4" />
+
+    <!--
+         If a codec is not enabled, it is invisible to the applications
+         In other words, the applications won't be able to use the codec
+         or query the capabilities of the codec at all if it is disabled
+    -->
+    <VideoEncoderCap name="hevc" enabled="true"
+        minBitRate="64000" maxBitRate="100000000"
+        minFrameWidth="176" maxFrameWidth="3840"
+        minFrameHeight="144" maxFrameHeight="2160"
+        minFrameRate="15" maxFrameRate="30" />
+
+    <VideoEncoderCap name="h264" enabled="true"
+        minBitRate="64000" maxBitRate="100000000"
+        minFrameWidth="176" maxFrameWidth="3840"
+        minFrameHeight="144" maxFrameHeight="2160"
+        minFrameRate="15" maxFrameRate="30" />
+
+    <VideoEncoderCap name="h263" enabled="true"
+        minBitRate="64000" maxBitRate="2000000"
+        minFrameWidth="176" maxFrameWidth="800"
+        minFrameHeight="144" maxFrameHeight="480"
+        minFrameRate="15" maxFrameRate="30" />
+
+    <VideoEncoderCap name="m4v" enabled="true"
+        minBitRate="64000" maxBitRate="40000000"
+        minFrameWidth="176" maxFrameWidth="1920"
+        minFrameHeight="144" maxFrameHeight="1080"
+        minFrameRate="15" maxFrameRate="30" />
+
+    <AudioEncoderCap name="aac" enabled="true"
+        minBitRate="758" maxBitRate="288000"
+        minSampleRate="8000" maxSampleRate="48000"
+        minChannels="1" maxChannels="2" />
+
+    <AudioEncoderCap name="heaac" enabled="true"
+        minBitRate="8000" maxBitRate="64000"
+        minSampleRate="16000" maxSampleRate="48000"
+        minChannels="1" maxChannels="2" />
+
+    <AudioEncoderCap name="aaceld" enabled="true"
+        minBitRate="16000" maxBitRate="192000"
+        minSampleRate="16000" maxSampleRate="48000"
+        minChannels="1" maxChannels="2" />
+
+    <AudioEncoderCap name="amrwb" enabled="true"
+        minBitRate="6600" maxBitRate="23050"
+        minSampleRate="16000" maxSampleRate="16000"
+        minChannels="1" maxChannels="1" />
+
+    <AudioEncoderCap name="amrnb" enabled="true"
+        minBitRate="5525" maxBitRate="12200"
+        minSampleRate="8000" maxSampleRate="8000"
+        minChannels="1" maxChannels="1" />
+
+    <!--
+        FIXME:
+        We do not check decoder capabilities at present
+        At present, we only check whether windows media is visible
+        for TEST applications. For other applications, we do
+        not perform any checks at all.
+    -->
+    <VideoDecoderCap name="wmv" enabled="false"/>
+    <AudioDecoderCap name="wma" enabled="false"/>
+</MediaSettings>
diff --git a/nfc/libese-hal-st.conf b/nfc/libese-hal-st.conf
new file mode 100644
index 0000000..1954bf7
--- /dev/null
+++ b/nfc/libese-hal-st.conf
@@ -0,0 +1,6 @@
+########################### Start of libese-hal-st.conf ###########################
+###############################################################################
+###############################################################################
+# ST HAL trace log level
+STESE_HAL_LOGLEVEL=1
+ST_ESE_DEV_NODE="/dev/st54j_se"
diff --git a/nfc/libnfc-hal-st.conf b/nfc/libnfc-hal-st.conf
new file mode 100644
index 0000000..47153d9
--- /dev/null
+++ b/nfc/libnfc-hal-st.conf
@@ -0,0 +1,148 @@
+########################### Start of libnf-hal-st_aosp.conf ###########################
+
+###############################################################################
+###############################################################################
+# ST HAL trace log level
+STNFC_HAL_LOGLEVEL=1
+NFC_DEBUG_ENABLED=0
+
+###############################################################################
+# Vendor specific mode to enable FW (RF & SWP) traces.
+STNFC_FW_DEBUG_ENABLED=0
+
+###############################################################################
+# File used for NFA storage
+NFA_STORAGE="/data/nfc"
+
+###############################################################################
+# Keep the nfa storage file.
+PRESERVE_STORAGE=1
+
+###############################################################################
+# In Switch OFF mode (phone switched-off), specify the desired CE mode to
+# the controller.
+# 0: No card-emulation; DEFAULT
+# 1: Switch-off card-emulation enabled
+CE_ON_SWITCH_OFF_STATE=1
+
+###############################################################################
+# Vendor specific mode to support the USB charging mode if VPSIO=1 in switch off.
+STNFC_USB_CHARGING_MODE=1
+
+###############################################################################
+# Vendor Specific Proprietary Protocol & Discovery Configuration
+# Set to 0xFF if unsupported
+#  byte[0] NCI_PROTOCOL_18092_ACTIVE
+#  byte[1] NCI_PROTOCOL_B_PRIME
+#  byte[2] NCI_PROTOCOL_DUAL
+#  byte[3] NCI_PROTOCOL_15693
+#  byte[4] NCI_PROTOCOL_KOVIO
+#  byte[5] NCI_PROTOCOL_MIFARE
+#  byte[6] NCI_DISCOVERY_TYPE_POLL_KOVIO
+#  byte[7] NCI_DISCOVERY_TYPE_POLL_B_PRIME
+#  byte[8] NCI_DISCOVERY_TYPE_LISTEN_B_PRIME
+NFA_PROPRIETARY_CFG={05:FF:FF:06:8A:90:77:FF:FF}
+
+###############################################################################
+# Choose the presence-check algorithm for type-4 tag.  If not defined,
+# the default value is 1.
+# 0  NFA_RW_PRES_CHK_DEFAULT; Let stack selects an algorithm
+# 1  NFA_RW_PRES_CHK_I_BLOCK; ISO-DEP protocol's empty I-block
+# 2  NFA_RW_PRES_CHK_RESET; Deactivate to Sleep, then re-activate
+# 3  NFA_RW_PRES_CHK_RB_CH0; Type-4 tag protocol's ReadBinary command on channel 0
+# 4  NFA_RW_PRES_CHK_RB_CH3; Type-4 tag protocol's ReadBinary command on channel 3
+# 5  NFA_RW_PRES_CHK_ISO_DEP_NAK; presence check command ISO-DEP NAK as per NCI2.0
+PRESENCE_CHECK_ALGORITHM=5
+
+###############################################################################
+# Name of the NCI HAL module to use
+# If unset, falls back to nfc_nci.bcm2079x
+NCI_HAL_MODULE="nfc_nci.st21nfc"
+
+###############################################################################
+# White list to be set at startup.
+DEVICE_HOST_WHITE_LIST={02:C0}
+
+###############################################################################
+# BAIL OUT value for P2P
+# Implements algorithm for NFC-DEP protocol priority over ISO-DEP protocol.
+POLL_BAIL_OUT_MODE=1
+
+###############################################################################
+# Extended APDU length for ISO_DEP
+ISO_DEP_MAX_TRANSCEIVE=0xFEFF
+
+###############################################################################
+# Configure the NFC Extras to open and use a static pipe.  If the value is
+# not set or set to 0, then the default is use a dynamic pipe based on a
+# destination gate (see NFA_HCI_DEFAULT_DEST_GATE).  Note there is a value
+# for each EE (ESE/SIM)
+OFF_HOST_ESE_PIPE_ID=0x5E
+OFF_HOST_SIM_PIPE_ID=0x3E
+
+###############################################################################
+#Set the default Felica T3T System Code OffHost route Location :
+#This settings will be used when application does not set this parameter
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_SYS_CODE_ROUTE=0x86
+
+###############################################################################
+#Set the Felica T3T System Code supported power state:
+DEFAULT_SYS_CODE_PWR_STATE=0x3B
+
+###############################################################################
+# Path and Files used for FW update binaries storage
+STNFC_FW_PATH_STORAGE="/vendor/firmware"
+STNFC_FW_BIN_NAME="/st54j_fw.bin"
+STNFC_FW_CONF_NAME="/st54j_conf.bin"
+
+###############################################################################
+# Default off-host route for Felica.
+# This settings will be used when application does not set this parameter
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_NFCF_ROUTE=0x86
+
+###############################################################################
+# Configure the default off-host route.
+# used for technology A and B routing
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_OFFHOST_ROUTE=0x81
+
+###############################################################################
+# Configure the default AID route.
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_ROUTE=0x00
+
+###############################################################################
+# Configure the NFCEEIDs of offhost UICC.
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+OFFHOST_ROUTE_UICC={81}
+
+###############################################################################
+# Configure the NFCEEIDs of offhost eSEs.
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+OFFHOST_ROUTE_ESE={86}
+
+###############################################################################
+# Configure the list of NFCEE for the ISO-DEP routing.
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_ISODEP_ROUTE=0x81
+
+###############################################################################
+# Core configuration settings
+CORE_CONF_PROP={ 20, 02, 0a, 03,
+        a1, 01, 1e,
+        a2, 01, 19,
+        80, 01, 01
+}
+
+
diff --git a/nfc/libnfc-nci.conf b/nfc/libnfc-nci.conf
new file mode 100644
index 0000000..149f1bb
--- /dev/null
+++ b/nfc/libnfc-nci.conf
@@ -0,0 +1,102 @@
+###############################################################################
+# Application options
+NFC_DEBUG_ENABLED=0
+
+###############################################################################
+# File used for NFA storage
+NFA_STORAGE="/data/nfc"
+
+###############################################################################
+# Force UICC to only listen to the following technology(s).
+# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
+# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B | NFA_TECHNOLOGY_MASK_F
+UICC_LISTEN_TECH_MASK=0x07
+
+###############################################################################
+# AID for Empty Select command
+# If specified, this AID will be substituted when an Empty SELECT command is
+# detected.  The first byte is the length of the AID.  Maximum length is 16.
+AID_FOR_EMPTY_SELECT={08:A0:00:00:01:51:00:00:00}
+
+###############################################################################
+# When screen is turned off, specify the desired power state of the controller.
+# 0: power-off-sleep state; DEFAULT
+# 1: full-power state
+# 2: screen-off card-emulation (CE4/CE3/CE1 modes are used)
+SCREEN_OFF_POWER_STATE=1
+
+###############################################################################
+# Force tag polling for the following technology(s).
+# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
+# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B |
+#            NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_ISO15693 |
+#            NFA_TECHNOLOGY_MASK_B_PRIME | NFA_TECHNOLOGY_MASK_KOVIO |
+#            NFA_TECHNOLOGY_MASK_ACTIVE
+#
+# Notable bits:
+# NFA_TECHNOLOGY_MASK_A             0x01    /* NFC Technology A             */
+# NFA_TECHNOLOGY_MASK_B             0x02    /* NFC Technology B             */
+# NFA_TECHNOLOGY_MASK_F             0x04    /* NFC Technology F             */
+# NFA_TECHNOLOGY_MASK_ISO15693      0x08    /* Proprietary Technology       */
+# NFA_TECHNOLOGY_MASK_KOVIO         0x20    /* Proprietary Technology       */
+# NFA_TECHNOLOGY_MASK_ACTIVE        0x40    /* NFC Technology Active        */
+POLLING_TECH_MASK=0x2F
+
+###############################################################################
+# Force P2P to only listen for the following technology(s).
+# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
+# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_F |
+# NFA_TECHNOLOGY_MASK_ACTIVE
+#
+# Notable bits:
+# NFA_TECHNOLOGY_MASK_A             0x01    /* NFC Technology A             */
+# NFA_TECHNOLOGY_MASK_F             0x04    /* NFC Technology F             */
+# NFA_TECHNOLOGY_MASK_ACTIVE         0x40    /* NFC Technology Active        */
+P2P_LISTEN_TECH_MASK=0x00
+
+PRESERVE_STORAGE=0x01
+
+###############################################################################
+# Override the stack default for NFA_EE_MAX_EE_SUPPORTED set in nfc_target.h.
+# The value is set to 3 by default as it assumes we will discover 0xF2,
+# 0xF3, and 0xF4. If a platform will exclude and SE, this value can be reduced
+# so that the stack will not wait any longer than necessary.
+# Maximum EE supported number
+# NXP PN547C2 0x02
+# NXP PN65T 0x03
+# NXP PN548C2 0x02
+# NXP PN66T 0x03
+NFA_MAX_EE_SUPPORTED=0x02
+
+###############################################################################
+# AID_MATCHING constants
+# AID_MATCHING_EXACT_ONLY 0x00
+# AID_MATCHING_EXACT_OR_PREFIX 0x01
+# AID_MATCHING_PREFIX_ONLY 0x02
+# AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX 0x03
+AID_MATCHING_MODE=0x03
+
+###############################################################################
+#Set the default Felica T3T System Code :
+#This settings will be used when application does not set this parameter
+DEFAULT_SYS_CODE={FE:FE}
+
+###############################################################################
+# Value of NIC parameter NFCC_COFNIG_CONTROL
+# 0x00  NFCC is not allowed to manage RF configuration
+# 0x01  NFCC is allowed to manage RF configuration
+NFCC_CONFIG_CONTROL=0x01
+
+###############################################################################
+#Set if the AID routing should be blocked for the power modes not supported.
+NFA_AID_BLOCK_ROUTE=1
+
+###############################################################################
+#Set the OffHost AID supported power state:
+OFFHOST_AID_ROUTE_PWR_STATE=0x3B
+
+###############################################################################
+# Mifare Tag implementation
+# 0: General implementation
+# 1: Legacy implementation
+LEGACY_MIFARE_READER=0
diff --git a/overlay/frameworks/base/core/res/res/values-mcc440-mnc20/config.xml b/overlay/frameworks/base/core/res/res/values-mcc440-mnc20/config.xml
new file mode 100644
index 0000000..0fdd49e
--- /dev/null
+++ b/overlay/frameworks/base/core/res/res/values-mcc440-mnc20/config.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Entitlement APP provisioning for Tethering -->
+    <string-array translatable="false" name="config_mobile_hotspot_provision_app">
+        <item>com.google.android.tetheringentitlement</item>
+        <item>com.google.android.tetheringentitlement.CarrierEntitlementActivity</item>
+    </string-array>
+    <string translatable="false" name="config_mobile_hotspot_provision_app_no_ui">com.google.android.carrierentitlement.SILENT_ENTITLEMENT_CHECK</string>
+    <string translatable="false" name="config_mobile_hotspot_provision_response">com.google.android.carrierentitlement.SILENT_ENTITLEMENT_CHECK_RESULT</string>
+</resources>
\ No newline at end of file
diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml
new file mode 100755
index 0000000..6bbec7c
--- /dev/null
+++ b/overlay/frameworks/base/core/res/res/values/config.xml
@@ -0,0 +1,293 @@
+<?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">
+
+    <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
+         Software implementation will be used if config_hardware_auto_brightness_available is not set -->
+    <bool name="config_automatic_brightness_available">true</bool>
+
+    <!-- Stability requirements in milliseconds for accepting a new brightness level.  This is used
+     for debouncing the light sensor.  Different constants are used to debounce the light sensor
+     when adapting to brighter or darker environments.  This parameter controls how quickly
+     brightness changes occur in response to an observed change in light level that exceeds the
+     hysteresis threshold. -->
+    <integer name="config_autoBrightnessBrighteningLightDebounce">2000</integer>
+    <integer name="config_autoBrightnessDarkeningLightDebounce">4000</integer>
+
+    <!-- If this is true, the screen will come on when you unplug usb/power/whatever. -->
+    <bool name="config_unplugTurnsOnScreen">true</bool>
+
+    <!-- Enable Night display, which requires HWC 2.0. -->
+    <bool name="config_nightDisplayAvailable">true</bool>
+
+    <!-- Boolean indicating whether display white balance is supported. -->
+    <bool name="config_displayWhiteBalanceAvailable">true</bool>
+
+    <!-- List supported color modes. -->
+    <integer-array name="config_availableColorModes">
+        <item>0</item> <!-- COLOR_MODE_NATURAL -->
+        <item>1</item> <!-- COLOR_MODE_BOOSTED -->
+        <item>3</item> <!-- COLOR_MODE_AUTOMATIC -->
+    </integer-array>
+
+    <!-- Color mode to use when accessibility transforms are enabled. This color mode must be
+     supported by the device, but not necessarily appear in config_availableColorModes. The
+     regularly selected color mode will be used if this value is negative. -->
+    <integer name="config_accessibilityColorMode">2</integer>
+
+    <!-- Boolean indicating whether the HWC setColorTransform function can be performed efficiently
+         in hardware. -->
+    <bool name="config_setColorTransformAccelerated">true</bool>
+
+    <!-- Boolean indicating if restoring network selection should be skipped -->
+    <!-- The restoring is handled by modem if it is true -->
+    <bool translatable="false" name="skip_restoring_network_selection">true</bool>
+
+    <!-- If device has a sensor that can wake-up the lock screen -->
+    <bool name="config_dozeWakeLockScreenSensorAvailable">true</bool>
+
+    <!-- If device supports pickup/lift gesture -->
+    <bool name="config_dozePulsePickup">true</bool>
+
+    <!-- Set to true to add links to Cell Broadcast app from Settings and MMS app. -->
+    <bool name="config_cellBroadcastAppLinks">true</bool>
+
+    <!--  Whether Multiuser UI should be shown -->
+    <bool name="config_enableMultiUserUI">true</bool>
+
+    <!--  Maximum number of supported users -->
+    <integer name="config_multiuserMaximumUsers">4</integer>
+
+    <!-- Whether Hearing Aid profile is supported -->
+    <bool name="config_hearing_aid_profile_supported">true</bool>
+
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         USB interfaces.  If the device doesn't want to support tething over USB this should
+         be empty.  An example would be "usb.*" -->
+    <string-array translatable="false" name="config_tether_usb_regexs">
+        <item>"usb\\d"</item>
+        <item>"rndis\\d"</item>
+    </string-array>
+
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         Wifi interfaces.  If the device doesn't want to support tethering over Wifi this
+         should be empty.  An example would be "softap.*" -->
+    <string-array translatable="false" name="config_tether_wifi_regexs">
+        <item>"wlan\\d"</item>
+    </string-array>
+
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         bluetooth interfaces.  If the device doesn't want to support tethering over bluetooth this
+         should be empty. -->
+    <string-array translatable="false" name="config_tether_bluetooth_regexs">
+           <item>"bt-pan"</item>
+    </string-array>
+
+    <!-- Boolean indicating if current platform supports HFP inband ringing -->
+    <bool name="config_bluetooth_hfp_inband_ringing_support">true</bool>
+
+    <bool translatable="false" name="config_tether_upstream_automatic">true</bool>
+
+    <!-- This string array should be overridden by the device to present a list of network
+         attributes.  This is used by the connectivity manager to decide which networks can coexist
+         based on the hardware -->
+    <!-- An Array of "[Connection name],[ConnectivityManager.TYPE_xxxx],
+         [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet]  -->
+    <!-- the 5th element "resore-time" indicates the number of milliseconds to delay
+         before automatically restore the default connection.  Set -1 if the connection
+         does not require auto-restore. -->
+    <!-- the 6th element indicates boot-time dependency-met value. -->
+    <string-array translatable="false" name="networkAttributes">
+        <item>"wifi,1,1,1,-1,true"</item>
+        <item>"mobile,0,0,0,-1,true"</item>
+        <item>"mobile_mms,2,0,2,60000,true"</item>
+        <item>"mobile_supl,3,0,2,60000,true"</item>
+        <item>"mobile_dun,4,0,2,60000,true"</item>
+        <item>"mobile_hipri,5,0,3,60000,true"</item>
+        <item>"mobile_fota,10,0,2,60000,true"</item>
+        <item>"mobile_ims,11,0,2,60000,true"</item>
+        <item>"mobile_cbs,12,0,2,60000,true"</item>
+        <item>"mobile_ia,14,0,2,-1,true"</item>
+        <item>"bluetooth,7,7,2,-1,true"</item>
+        <item>"ethernet,9,9,9,-1,true"</item>
+        <item>"mobile_emergency,15,0,2,-1,true</item>
+    </string-array>
+
+    <!-- This string array should be overridden by the device to present a list of radio
+         attributes.  This is used by the connectivity manager to decide which networks can coexist
+         based on the hardware -->
+    <!-- An Array of "[ConnectivityManager connectionType],
+                      [# simultaneous connection types]"  -->
+    <string-array translatable="false" name="radioAttributes">
+        <item>"1,1"</item>
+        <item>"0,1"</item>
+        <item>"7,1"</item>
+        <item>"9,1"</item>
+    </string-array>
+
+    <!-- If the hardware supports specially marking packets that caused a wakeup of the
+         main CPU, set this value to the mark used. -->
+    <integer name="config_networkWakeupPacketMark">0x80000000</integer>
+
+    <!-- Mask to use when checking skb mark defined in config_networkWakeupPacketMark above. -->
+    <integer name="config_networkWakeupPacketMask">0x80000000</integer>
+
+    <!-- Boolean indicating whether the wifi chipset has dual frequency band support -->
+    <bool translatable="false" name="config_wifi_dual_band_support">true</bool>
+
+    <!-- Boolean indicating whether the wifi chipset requires the softap band be -->
+    <!-- converted from 5GHz to ANY due to hardware restrictions -->
+    <bool translatable="false" name="config_wifi_convert_apband_5ghz_to_any">true</bool>
+
+    <!-- Boolean indicating whether 802.11r Fast BSS Transition is enabled on this platform -->
+    <bool translatable="false" name="config_wifi_fast_bss_transition_enabled">true</bool>
+
+    <!-- Boolean indicating whether the wifi chipset has background scan support -->
+    <bool translatable="false" name="config_wifi_background_scan_support">true</bool>
+
+
+    <!-- Wifi driver supports batched scan -->
+    <bool translatable="false" name="config_wifi_batched_scan_supported">true</bool>
+
+    <!-- Boolean indicating whether or not to revert to default country code when cellular
+    radio is unable to find any MCC information to infer wifi country code from -->
+    <bool translatable="false" name="config_wifi_revert_country_code_on_cellular_loss">false</bool>
+
+    <!-- Boolean indicating whether or not wifi should turn off when emergency call is made -->
+    <bool translatable="false" name="config_wifi_turn_off_during_emergency_call">true</bool>
+
+    <!-- ImsService package name to bind to by default, if config_dynamic_bind_ims is true -->
+    <string name="config_ims_package">org.codeaurora.ims</string>
+
+    <!-- Flag specifying whether or not IMS will use the ImsResolver dynamically -->
+    <bool name="config_dynamic_bind_ims">true</bool>
+
+    <!-- Specifies whether to decouple the auto-suspend state of the device from the display on/off state. -->
+    <bool name="config_powerDecoupleAutoSuspendModeFromDisplay">true</bool>
+
+    <!-- Specifies whether to decouple the interactive state of the device from the display on/off state. -->
+    <bool name="config_powerDecoupleInteractiveModeFromDisplay">true</bool>
+
+    <!-- Is the device capable of hot swapping an UICC Card -->
+    <bool name="config_hotswapCapable">true</bool>
+
+    <!-- Flag specifying whether VoLTE is availasble on device -->
+    <bool name="config_device_volte_available">true</bool>
+
+    <!-- Flag specifying whether VoLTE is available on device -->
+    <bool name="config_device_vt_available">true</bool>
+
+    <!-- Enable video pause workaround when enabling/disabling the camera. -->
+    <bool name="config_useVideoPauseWorkaround">true</bool>
+
+    <!-- Flag specifying whether WFC over IMS is availasble on device -->
+    <bool name="config_device_wfc_ims_available">true</bool>
+
+    <!-- Configure mobile tcp buffer sizes in the form:
+         rat-name:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
+         If no value is found for the rat-name in use, the system default will be applied.
+    -->
+    <string-array name="config_mobile_tcp_buffers">
+        <item>umts:131072,262144,1452032,4096,16384,399360</item>
+        <item>hspa:131072,262144,2441216,4096,16384,399360</item>
+        <item>hsupa:131072,262144,2441216,4096,16384,399360</item>
+        <item>hsdpa:131072,262144,2441216,4096,16384,399360</item>
+        <item>hspap:131072,262144,2441216,4096,16384,399360</item>
+        <item>edge:16384,32768,131072,4096,16384,65536</item>
+        <item>gprs:4096,8192,24576,4096,8192,24576</item>
+        <item>1xrtt:16384,32768,131070,4096,16384,102400</item>
+        <item>evdo:131072,262144,1048576,4096,16384,524288</item>
+        <item>lte:524288,1048576,8388608,262144,524288,4194304</item>
+    </string-array>
+
+    <!-- Configure wifi tcp buffersizes in the form:
+         rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max -->
+    <string name="config_wifi_tcp_buffers" translatable="false">524288,2097152,8388608,262144,524288,4194304</string>
+
+    <!-- Idle Receive current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_idle_receive_cur_ma">1</integer>
+
+    <!-- Rx current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_active_rx_cur_ma">100</integer>
+
+    <!-- Tx current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_tx_cur_ma">250</integer>
+
+    <!-- Operating volatage for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_operating_voltage_mv">3800</integer>
+
+    <!-- Config SoftAP 2G channel list -->
+    <string  translatable="false" name="config_wifi_framework_sap_2G_channel_list">6</string>
+
+    <!-- Config determines whether to update phone object when voice registration
+         state changes. Voice radio tech change will always trigger an update of
+         phone object irrespective of this config -->
+    <bool name="config_switch_phone_on_voice_reg_state_change">false</bool>
+
+    <!-- Number of physical SIM slots on the device. This includes both eSIM and pSIM slots, and
+         is not necessarily the same as the number of phones/logical modems supported by the device.
+         For example, a multi-sim device can have 2 phones/logical modems, but 3 physical slots,
+         or a single SIM device can have 1 phones/logical modems, but 2 physical slots (one eSIM
+         and one pSIM) -->
+    <integer name="config_num_physical_slots">2</integer>
+
+    <!-- Disables compatibility WAL mode.
+    In this mode, only database journal mode will be changed, connection pool
+    size will still be limited to a single connection. -->
+    <bool name="db_compatibility_wal_supported">false</bool>
+
+    <!-- Use ERI text for network name on CDMA LTE -->
+        <bool name="config_LTE_eri_for_network_name">false</bool>
+
+    <!-- An array of device capabilities defined by GSMA SGP.22 v2.0, and their corresponding major
+         version. -->
+    <string-array translatable="false" name="config_telephonyEuiccDeviceCapabilities">
+        <item>"gsm,11"</item>
+        <item>"utran,11"</item>
+        <item>"cdma1x,1"</item>
+        <item>"hrpd,3"</item>
+        <item>"ehrpd,12"</item>
+        <item>"eutran,11"</item>
+    </string-array>
+
+    <!-- Whether the new Auto Selection Network UI should be shown -->
+    <bool name="config_enableNewAutoSelectNetworkUI">true</bool>
+
+    <!-- Enable ACS (auto channel selection) for Wifi hotspot (SAP) -->
+    <bool translatable="false" name="config_wifi_softap_acs_supported">true</bool>
+
+    <!-- Enable 802.11ac for Wifi hotspot (SAP) -->
+    <bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">true</bool>
+
+    <!-- Integer thresholds, do not connect to APs with RSSI lower than these values  -->
+    <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz">-77</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz">-80</integer>
+    <!-- Integer thresholds for low network score, should be somewhat less than the entry threshholds -->
+    <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-80</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-83</integer>
+
+    <!-- Enables or disables haptic effect when the text insertion/selection handle is moved
+          manually by the user. Off by default, since the expected haptic feedback may not be
+          available on some devices. -->
+    <bool name="config_enableHapticTextHandle">true</bool>
+    <!-- Enable Zram writeback feature to allow unused pages in zram be written to flash. -->
+    <bool name="config_zramWriteback">true</bool>
+
+</resources>
diff --git a/overlay/frameworks/base/core/res/res/values/strings.xml b/overlay/frameworks/base/core/res/res/values/strings.xml
new file mode 100644
index 0000000..e1daaad
--- /dev/null
+++ b/overlay/frameworks/base/core/res/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds.  Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Do not translate. Default access point SSID used for tethering -->
+    <string name="wifi_tether_configure_ssid_default" translatable="false">Pixel</string>
+</resources>
diff --git a/overlay/frameworks/base/packages/SystemUI/res/values-mcc440-mnc20/config.xml b/overlay/frameworks/base/packages/SystemUI/res/values-mcc440-mnc20/config.xml
new file mode 100644
index 0000000..f9741d7
--- /dev/null
+++ b/overlay/frameworks/base/packages/SystemUI/res/values-mcc440-mnc20/config.xml
@@ -0,0 +1,26 @@
+<?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 my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Control whether status bar should distinguish HSPA data icon from UMTS
+    data icon on devices -->
+    <bool name="config_hspa_data_distinguishable">false</bool>
+</resources>
diff --git a/overlay/packages/apps/Bluetooth/res/values/config.xml b/overlay/packages/apps/Bluetooth/res/values/config.xml
new file mode 100644
index 0000000..9b1b241
--- /dev/null
+++ b/overlay/packages/apps/Bluetooth/res/values/config.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<resources>
+    <bool name="profile_supported_sap">true</bool>
+</resources>
diff --git a/overlay/packages/apps/Settings/res/raw/face_enroll_introduction_animation.mp4 b/overlay/packages/apps/Settings/res/raw/face_enroll_introduction_animation.mp4
new file mode 100644
index 0000000..03aea2f
--- /dev/null
+++ b/overlay/packages/apps/Settings/res/raw/face_enroll_introduction_animation.mp4
Binary files differ
diff --git a/overlay/packages/apps/Settings/res/values-mcc262-mnc01/strings.xml b/overlay/packages/apps/Settings/res/values-mcc262-mnc01/strings.xml
new file mode 100644
index 0000000..cff4d80
--- /dev/null
+++ b/overlay/packages/apps/Settings/res/values-mcc262-mnc01/strings.xml
@@ -0,0 +1,22 @@
+<?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>
+    <string name="wifi_calling_settings_title">WLAN Call</string>
+</resources>
diff --git a/overlay/packages/apps/Settings/res/values/bools.xml b/overlay/packages/apps/Settings/res/values/bools.xml
new file mode 100755
index 0000000..bb93789
--- /dev/null
+++ b/overlay/packages/apps/Settings/res/values/bools.xml
@@ -0,0 +1,20 @@
+<?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>
+    <!-- Whether to show a preference item for mobile plan -->
+    <bool name="config_show_mobile_plan">false</bool>
+</resources>
diff --git a/overlay/packages/apps/Settings/res/values/config.xml b/overlay/packages/apps/Settings/res/values/config.xml
new file mode 100755
index 0000000..c2ac3b4
--- /dev/null
+++ b/overlay/packages/apps/Settings/res/values/config.xml
@@ -0,0 +1,23 @@
+<?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>
+    <!-- Whether or not the device is capable of multiple levels of vibration intensity.
+         Note that this is different from whether it can control the vibration amplitude as some
+         devices will be able to vary their amplitude but do not possess enough dynamic range to
+         have distinct intensity levels -->
+    <bool name="config_vibration_supports_multiple_intensities">true</bool>
+</resources>
diff --git a/overlay/packages/services/Telephony/res/values/config.xml b/overlay/packages/services/Telephony/res/values/config.xml
new file mode 100644
index 0000000..4072b9e
--- /dev/null
+++ b/overlay/packages/services/Telephony/res/values/config.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Phone app resources that may need to be customized
+     for different hardware or product builds. -->
+<resources>
+    <!-- Allow handover from telephony calls to another ConnectionService. -->
+    <bool name="config_support_handover_from">true</bool>
+
+    <!-- Flag indicating whether the device supports RTT (real-time text) -->
+    <bool name="config_support_rtt">true</bool>
+
+    <!-- This device supports the AudioManager Telephony audio device and output onto this
+         device using {@link AudioDeviceInfo#TYPE_TELEPHONY}.
+         This is used to support carriers which generate a recording tone to the remote party
+         when a call recording app is in use. -->
+    <bool name="config_support_telephony_audio_device">true</bool>
+</resources>
diff --git a/p2p_supplicant_overlay.conf b/p2p_supplicant_overlay.conf
new file mode 100644
index 0000000..d66504c
--- /dev/null
+++ b/p2p_supplicant_overlay.conf
@@ -0,0 +1,2 @@
+disable_scan_offload=1
+p2p_go_vht=1
diff --git a/pixelstats/Android.bp b/pixelstats/Android.bp
new file mode 100644
index 0000000..d6c8e01
--- /dev/null
+++ b/pixelstats/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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_binary {
+  name: "pixelstats-vendor",
+  init_rc: ["pixelstats-vendor.bramble.rc"],
+  srcs: [
+    "service.cpp",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "libcutils",
+    "libhidlbase",
+    "libhidltransport",
+    "liblog",
+    "libutils",
+    "libpixelstats",
+  ],
+  proprietary: true,
+  static_libs: ["chre_client"],
+  header_libs: ["chre_api"],
+}
+
diff --git a/pixelstats/pixelstats-vendor.bramble.rc b/pixelstats/pixelstats-vendor.bramble.rc
new file mode 100644
index 0000000..9410090
--- /dev/null
+++ b/pixelstats/pixelstats-vendor.bramble.rc
@@ -0,0 +1,4 @@
+service vendor.pixelstats_vendor /vendor/bin/pixelstats-vendor
+    class hal
+    user system
+    group system
diff --git a/pixelstats/service.cpp b/pixelstats/service.cpp
new file mode 100644
index 0000000..5e8abc5
--- /dev/null
+++ b/pixelstats/service.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "pixelstats"
+
+#include <android-base/logging.h>
+#include <utils/StrongPointer.h>
+
+#include <pixelstats/DropDetect.h>
+#include <pixelstats/SysfsCollector.h>
+#include <pixelstats/UeventListener.h>
+
+using android::sp;
+using android::hardware::google::pixel::DropDetect;
+using android::hardware::google::pixel::SysfsCollector;
+using android::hardware::google::pixel::UeventListener;
+
+#define UFSHC_PATH(filename) "/sys/devices/platform/soc/1d84000.ufshc/" #filename
+const struct SysfsCollector::SysfsPaths sysfs_paths = {
+    .SlowioReadCntPath = UFSHC_PATH(slowio_read_cnt),
+    .SlowioWriteCntPath = UFSHC_PATH(slowio_write_cnt),
+    .SlowioUnmapCntPath = UFSHC_PATH(slowio_unmap_cnt),
+    .SlowioSyncCntPath = UFSHC_PATH(slowio_sync_cnt),
+    .CycleCountBinsPath = "/sys/class/power_supply/maxfg/cycle_counts_bins",
+    .ImpedancePath = "/sys/class/misc/msm_cirrus_playback/resistance_left_right",
+    .CodecPath = "",  // b/117976641
+};
+
+const char *const kAudioUevent = "/kernel/q6audio/q6voice_uevent";
+
+int main() {
+    LOG(INFO) << "starting PixelStats";
+
+    // b/118713028 Expect failure until drop detect nanoapp is enabled
+    sp<DropDetect> dropDetector = DropDetect::start();
+    if (!dropDetector) {
+        LOG(ERROR) << "Unable to launch drop detection";
+        return 1;
+    }
+
+    UeventListener ueventListener(kAudioUevent);
+    std::thread listenThread(&UeventListener::ListenForever, &ueventListener);
+    listenThread.detach();
+
+    SysfsCollector collector(sysfs_paths);
+    collector.collect();  // This blocks forever.
+
+    return 0;
+}
diff --git a/power/hint-data.h b/power/hint-data.h
new file mode 100644
index 0000000..0cb54c2
--- /dev/null
+++ b/power/hint-data.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, 2013, 2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * *    * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Default use-case hint IDs */
+#define DEFAULT_VIDEO_ENCODE_HINT_ID    (0x0A00)
+#define DEFAULT_VIDEO_DECODE_HINT_ID    (0x0B00)
+#define DISPLAY_STATE_HINT_ID           (0x0C00)
+#define DISPLAY_STATE_HINT_ID_2         (0x0D00)
+#define CAM_PREVIEW_HINT_ID             (0x0E00)
+#define SUSTAINED_PERF_HINT_ID          (0x0F00)
+#define VR_MODE_HINT_ID                 (0x1000)
+#define VR_MODE_SUSTAINED_PERF_HINT_ID  (0x1001)
+
+#define AOSP_DELTA                      (0x1200)
+
+#define VSYNC_HINT                      AOSP_DELTA + POWER_HINT_VSYNC
+#define INTERACTION_HINT                AOSP_DELTA + POWER_HINT_INTERACTION
+#define VIDEO_DECODE_HINT               AOSP_DELTA + POWER_HINT_VIDEO_DECODE
+#define VIDEO_ENCODE_HINT               AOSP_DELTA + POWER_HINT_VIDEO_ENCODE
+#define LOW_POWER_HINT                  AOSP_DELTA + POWER_HINT_LOW_POWER
+#define SUSTAINED_PERF_HINT             AOSP_DELTA + POWER_HINT_SUSTAINED_PERFORMANCE
+#define VR_MODE_HINT                    AOSP_DELTA + POWER_HINT_VR_MODE
+#define LAUNCH_HINT                     AOSP_DELTA + POWER_HINT_LAUNCH
+#define DISABLE_TOUCH_HINT              AOSP_DELTA + POWER_HINT_DISABLE_TOUCH
+
+#define VR_MODE_SUSTAINED_PERF_HINT    (0x1301)
+
+
+struct hint_data {
+    unsigned long hint_id; /* This is our key. */
+    unsigned long perflock_handle;
+};
+
+int hint_compare(struct hint_data *first_hint,
+        struct hint_data *other_hint);
+void hint_dump(struct hint_data *hint);
diff --git a/power/list.h b/power/list.h
new file mode 100644
index 0000000..d68c3df
--- /dev/null
+++ b/power/list.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * *    * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct list_node {
+    struct list_node *next;
+    void *data;
+    int (*compare)(void *data1, void *data2);
+    void (*dump)(void *data);
+};
+
+int init_list_head(struct list_node *head);
+struct list_node * add_list_node(struct list_node *head, void *data);
+int remove_list_node(struct list_node *head, struct list_node *del_node);
+void dump_list(struct list_node *head);
+struct list_node *find_node(struct list_node *head, void *comparison_data);
diff --git a/power/metadata-defs.h b/power/metadata-defs.h
new file mode 100644
index 0000000..c464900
--- /dev/null
+++ b/power/metadata-defs.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define ATTRIBUTE_VALUE_DELIM ('=')
+#define ATTRIBUTE_STRING_DELIM (";")
+
+#define METADATA_PARSING_ERR (-1)
+#define METADATA_PARSING_CONTINUE (0)
+#define METADATA_PARSING_DONE (1)
+
+#define MIN(x,y) (((x)>(y))?(y):(x))
+
+struct video_encode_metadata_t {
+    int hint_id;
+    int state;
+};
+
+struct video_decode_metadata_t {
+    int hint_id;
+    int state;
+};
+
+int parse_metadata(char *metadata, char **metadata_saveptr,
+    char *attribute, int attribute_size, char *value, int value_size);
+int parse_video_encode_metadata(char *metadata,
+    struct video_encode_metadata_t *video_encode_metadata);
+int parse_video_decode_metadata(char *metadata,
+    struct video_decode_metadata_t *video_decode_metadata);
diff --git a/power/performance.h b/power/performance.h
new file mode 100644
index 0000000..b7bf34b
--- /dev/null
+++ b/power/performance.h
@@ -0,0 +1,265 @@
+/* Copyright (c) 2012, 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FAILED                  -1
+#define SUCCESS                 0
+#define INDEFINITE_DURATION     0
+
+/* Hints sent to perf HAL from power HAL
+ * These have to be kept in sync with Perf HAL side definitions
+ */
+#define VENDOR_HINT_DISPLAY_OFF      0x00001040
+#define VENDOR_HINT_DISPLAY_ON       0x00001041
+
+enum SCREEN_DISPLAY_TYPE {
+    DISPLAY_OFF = 0x00FF,
+};
+
+enum PWR_CLSP_TYPE {
+    ALL_CPUS_PWR_CLPS_DIS = 0x101,
+};
+
+/* For CPUx min freq, the leftmost byte
+ * represents the CPU and the
+ * rightmost byte represents the frequency
+ * All intermediate frequencies on the
+ * device are supported. The hex value
+ * passed into PerfLock will be multiplied
+ * by 10^5. This frequency or the next
+ * highest frequency available will be set
+ *
+ * For example, if 1.4 Ghz is required on
+ * CPU0, use 0x20E
+ *
+ * If the highest available frequency
+ * on the device is required, use
+ * CPUx_MIN_FREQ_TURBO_MAX
+ * where x represents the CPU
+ */
+enum CPU0_MIN_FREQ_LVL {
+    CPU0_MIN_FREQ_NONTURBO_MAX = 0x20A,
+    CPU0_MIN_FREQ_TURBO_MAX = 0x2FE,
+};
+
+enum CPU1_MIN_FREQ_LVL {
+    CPU1_MIN_FREQ_NONTURBO_MAX = 0x30A,
+    CPU1_MIN_FREQ_TURBO_MAX = 0x3FE,
+};
+
+enum CPU2_MIN_FREQ_LVL {
+    CPU2_MIN_FREQ_NONTURBO_MAX = 0x40A,
+    CPU2_MIN_FREQ_TURBO_MAX = 0x4FE,
+};
+
+enum CPU3_MIN_FREQ_LVL {
+    CPU3_MIN_FREQ_NONTURBO_MAX = 0x50A,
+    CPU3_MIN_FREQ_TURBO_MAX = 0x5FE,
+};
+
+enum CPU0_MAX_FREQ_LVL {
+    CPU0_MAX_FREQ_NONTURBO_MAX = 0x150A,
+};
+
+enum CPU1_MAX_FREQ_LVL {
+    CPU1_MAX_FREQ_NONTURBO_MAX = 0x160A,
+};
+
+enum CPU2_MAX_FREQ_LVL {
+    CPU2_MAX_FREQ_NONTURBO_MAX = 0x170A,
+};
+
+enum CPU3_MAX_FREQ_LVL {
+    CPU3_MAX_FREQ_NONTURBO_MAX = 0x180A,
+};
+
+enum MIN_CPUS_ONLINE_LVL {
+    CPUS_ONLINE_MIN_2 = 0x702,
+    CPUS_ONLINE_MIN_3 = 0x703,
+    CPUS_ONLINE_MIN_4 = 0x704,
+    CPUS_ONLINE_MPD_OVERRIDE = 0x777,
+    CPUS_ONLINE_MAX = 0x7FF,
+};
+
+enum MAX_CPUS_ONLINE_LVL {
+    CPUS_ONLINE_MAX_LIMIT_1 = 0x8FE,
+    CPUS_ONLINE_MAX_LIMIT_2 = 0x8FD,
+    CPUS_ONLINE_MAX_LIMIT_3 = 0x8FC,
+    CPUS_ONLINE_MAX_LIMIT_4 = 0x8FB,
+    CPUS_ONLINE_MAX_LIMIT_MAX = 0x8FB,
+};
+
+enum SAMPLING_RATE_LVL {
+    MS_500 = 0xBCD,
+    MS_50 = 0xBFA,
+    MS_20 = 0xBFD,
+};
+
+enum ONDEMAND_IO_BUSY_LVL {
+    IO_BUSY_OFF = 0xC00,
+    IO_BUSY_ON = 0xC01,
+};
+
+enum ONDEMAND_SAMPLING_DOWN_FACTOR_LVL {
+    SAMPLING_DOWN_FACTOR_1 = 0xD01,
+    SAMPLING_DOWN_FACTOR_4 = 0xD04,
+};
+
+enum INTERACTIVE_TIMER_RATE_LVL {
+    TR_MS_500 = 0xECD,
+    TR_MS_100 = 0xEF5,
+    TR_MS_50 = 0xEFA,
+    TR_MS_30 = 0xEFC,
+    TR_MS_20 = 0xEFD,
+};
+
+/* This timer rate applicable to cpu0
+    across 8939 series chipset */
+enum INTERACTIVE_TIMER_RATE_LVL_CPU0_8939 {
+    TR_MS_CPU0_500 = 0x30CD,
+    TR_MS_CPU0_100 = 0x30F5,
+    TR_MS_CPU0_50 = 0x30FA,
+    TR_MS_CPU0_30 = 0x30FC,
+    TR_MS_CPU0_20 = 0x30FD,
+};
+
+/* This timer rate applicable to cpu4
+    across 8939 series chipset */
+enum INTERACTIVE_TIMER_RATE_LVL_CPU4_8939 {
+    TR_MS_CPU4_500 = 0x3BCD,
+    TR_MS_CPU4_100 = 0x3BF5,
+    TR_MS_CPU4_50 = 0x3BFA,
+    TR_MS_CPU4_30 = 0x3BFC,
+    TR_MS_CPU4_20 = 0x3BFD,
+};
+
+/* This timer rate applicable to big.little arch */
+enum INTERACTIVE_TIMER_RATE_LVL_BIG_LITTLE {
+    BIG_LITTLE_TR_MS_100 = 0x64,
+    BIG_LITTLE_TR_MS_50 = 0x32,
+    BIG_LITTLE_TR_MS_40 = 0x28,
+    BIG_LITTLE_TR_MS_30 = 0x1E,
+    BIG_LITTLE_TR_MS_20 = 0x14,
+};
+
+/* INTERACTIVE opcodes */
+enum INTERACTIVE_OPCODES {
+    INT_OP_CLUSTER0_TIMER_RATE = 0x41424000,
+    INT_OP_CLUSTER1_TIMER_RATE = 0x41424100,
+    INT_OP_CLUSTER0_USE_SCHED_LOAD = 0x41430000,
+    INT_OP_CLUSTER1_USE_SCHED_LOAD = 0x41430100,
+    INT_OP_CLUSTER0_USE_MIGRATION_NOTIF = 0x41434000,
+    INT_OP_CLUSTER1_USE_MIGRATION_NOTIF = 0x41434100,
+    INT_OP_NOTIFY_ON_MIGRATE = 0x4241C000
+};
+
+enum INTERACTIVE_HISPEED_FREQ_LVL {
+    HS_FREQ_1026 = 0xF0A,
+};
+
+enum INTERACTIVE_HISPEED_LOAD_LVL {
+    HISPEED_LOAD_90 = 0x105A,
+};
+
+enum SYNC_FREQ_LVL {
+    SYNC_FREQ_300 = 0x1103,
+    SYNC_FREQ_600 = 0X1106,
+    SYNC_FREQ_384 = 0x1103,
+    SYNC_FREQ_NONTURBO_MAX = 0x110A,
+    SYNC_FREQ_TURBO = 0x110F,
+};
+
+enum OPTIMAL_FREQ_LVL {
+    OPTIMAL_FREQ_300 = 0x1203,
+    OPTIMAL_FREQ_600 = 0x1206,
+    OPTIMAL_FREQ_384 = 0x1203,
+    OPTIMAL_FREQ_NONTURBO_MAX = 0x120A,
+    OPTIMAL_FREQ_TURBO = 0x120F,
+};
+
+enum SCREEN_PWR_CLPS_LVL {
+    PWR_CLPS_DIS = 0x1300,
+    PWR_CLPS_ENA = 0x1301,
+};
+
+enum THREAD_MIGRATION_LVL {
+    THREAD_MIGRATION_SYNC_OFF = 0x1400,
+};
+
+enum INTERACTIVE_IO_BUSY_LVL {
+    INTERACTIVE_IO_BUSY_OFF = 0x1B00,
+    INTERACTIVE_IO_BUSY_ON = 0x1B01,
+};
+
+enum SCHED_BOOST_LVL {
+    SCHED_BOOST_ON = 0x1E01,
+};
+
+enum CPU4_MIN_FREQ_LVL {
+    CPU4_MIN_FREQ_NONTURBO_MAX = 0x1F0A,
+    CPU4_MIN_FREQ_TURBO_MAX = 0x1FFE,
+};
+
+enum CPU5_MIN_FREQ_LVL {
+    CPU5_MIN_FREQ_NONTURBO_MAX = 0x200A,
+    CPU5_MIN_FREQ_TURBO_MAX = 0x20FE,
+};
+
+enum CPU6_MIN_FREQ_LVL {
+    CPU6_MIN_FREQ_NONTURBO_MAX = 0x210A,
+    CPU6_MIN_FREQ_TURBO_MAX = 0x21FE,
+};
+
+enum CPU7_MIN_FREQ_LVL {
+    CPU7_MIN_FREQ_NONTURBO_MAX = 0x220A,
+    CPU7_MIN_FREQ_TURBO_MAX = 0x22FE,
+};
+
+enum CPU4_MAX_FREQ_LVL {
+    CPU4_MAX_FREQ_NONTURBO_MAX = 0x230A,
+};
+
+enum CPU5_MAX_FREQ_LVL {
+    CPU5_MAX_FREQ_NONTURBO_MAX = 0x240A,
+};
+
+enum CPU6_MAX_FREQ_LVL {
+    CPU6_MAX_FREQ_NONTURBO_MAX = 0x250A,
+};
+
+enum CPU7_MAX_FREQ_LVL {
+    CPU7_MAX_FREQ_NONTURBO_MAX = 0x260A,
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/power/power-common.h b/power/power-common.h
new file mode 100644
index 0000000..5ba5e81
--- /dev/null
+++ b/power/power-common.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * *    * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define NODE_MAX (64)
+
+#define SCALING_GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+#define DCVS_CPU0_SLACK_MAX_NODE "/sys/module/msm_dcvs/cores/cpu0/slack_time_max_us"
+#define DCVS_CPU0_SLACK_MIN_NODE "/sys/module/msm_dcvs/cores/cpu0/slack_time_min_us"
+#define MPDECISION_SLACK_MAX_NODE "/sys/module/msm_mpdecision/slack_time_max_us"
+#define MPDECISION_SLACK_MIN_NODE "/sys/module/msm_mpdecision/slack_time_min_us"
+#define SCALING_MIN_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+#define ONDEMAND_GOVERNOR "ondemand"
+#define INTERACTIVE_GOVERNOR "interactive"
+#define MSMDCVS_GOVERNOR "msm-dcvs"
+
+#define HINT_HANDLED (0)
+#define HINT_NONE (-1)
+
+enum CPU_GOV_CHECK {
+    CPU0 = 0,
+    CPU1 = 1,
+    CPU2 = 2,
+    CPU3 = 3
+};
diff --git a/power/powerhintparser.h b/power/powerhintparser.h
new file mode 100644
index 0000000..5f9cbe6
--- /dev/null
+++ b/power/powerhintparser.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __POWERHINTPARSER__
+#define __POWERHINTPARSER__
+
+#define POWERHINT_XML      "/vendor/etc/powerhint.xml"
+#define MAX_HINT 6
+#define MAX_PARAM 30
+
+typedef struct perflock_param_t {
+    int type;
+    int numParams;
+    int paramList[MAX_PARAM];//static limit on number of hints - 15
+}perflock_param_t;
+
+static perflock_param_t powerhint[MAX_HINT];
+
+int parsePowerhintXML();
+int *getPowerhint(int, int*);
+
+#endif /* __POWERHINTPARSER__ */
diff --git a/power/utils.h b/power/utils.h
new file mode 100644
index 0000000..4c3dc7f
--- /dev/null
+++ b/power/utils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012-2013,2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * *    * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cutils/properties.h>
+
+int sysfs_read(char *path, char *s, int num_bytes);
+int sysfs_write(char *path, char *s);
+int get_scaling_governor(char governor[], int size);
+int get_scaling_governor_check_cores(char governor[], int size,int core_num);
+int is_interactive_governor(char*);
+
+void vote_ondemand_io_busy_off();
+void unvote_ondemand_io_busy_off();
+void vote_ondemand_sdf_low();
+void unvote_ondemand_sdf_low();
+void perform_hint_action(int hint_id, int resource_values[],
+    int num_resources);
+void undo_hint_action(int hint_id);
+void release_request(int lock_handle);
+int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[]);
+int perf_hint_enable(int hint_id, int duration);
diff --git a/powerhint.json b/powerhint.json
new file mode 100644
index 0000000..1087869
--- /dev/null
+++ b/powerhint.json
@@ -0,0 +1,650 @@
+{
+  "Nodes": [
+    {
+      "Name": "CPULittleClusterMaxFreq",
+      "Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq",
+      "Values": [
+        "9999999",
+        "1267200",
+        "1171200",
+        "1113600"
+      ],
+      "DefaultIndex": 0,
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPULittleClusterMinFreq",
+      "Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq",
+      "Values": [
+        "9999999",
+        "1267200",
+        "1171200",
+        "1113600",
+        "300000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBigClusterMaxFreq",
+      "Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq",
+      "Values": [
+        "9999999",
+        "2016000",
+        "1497600",
+        "1401600"
+      ],
+      "DefaultIndex": 0,
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBigClusterMinFreq",
+      "Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq",
+      "Values": [
+        "9999999",
+        "1497600",
+        "1401600",
+        "1286400",
+        "0"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBigPlusClusterMaxFreq",
+      "Path": "/sys/devices/system/cpu/cpu7/cpufreq/scaling_max_freq",
+      "Values": [
+        "9999999",
+        "2016000",
+        "1497600",
+        "1401600"
+      ],
+      "DefaultIndex": 0,
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBigPlusClusterMinFreq",
+      "Path": "/sys/devices/system/cpu/cpu7/cpufreq/scaling_min_freq",
+      "Values": [
+        "9999999",
+        "1497600",
+        "1401600",
+        "1286400",
+        "0"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUMaxFreq",
+      "Path": "/sys/class/kgsl/kgsl-3d0/devfreq/max_freq",
+      "Values": [
+        "600000000",
+        "379650000"
+      ],
+      "DefaultIndex": 0,
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUMinFreq",
+      "Path": "/sys/class/kgsl/kgsl-3d0/devfreq/min_freq",
+      "Values": [
+        "553850000",
+        "379650000",
+        "309110000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUBusMinFreq",
+      "Path": "/sys/class/devfreq/soc:qcom,gpubw/min_freq",
+      "Values": [
+        "6881",
+        "5931",
+        "3879",
+        "0"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUForceRailOn",
+      "Path": "/sys/class/kgsl/kgsl-3d0/force_rail_on",
+      "Values": [
+        "1",
+        "0"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUForceClkOn",
+      "Path": "/sys/class/kgsl/kgsl-3d0/force_clk_on",
+      "Values": [
+        "1",
+        "0"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUIdleTimer",
+      "Path": "/sys/class/kgsl/kgsl-3d0/idle_timer",
+      "Values": [
+        "10000",
+        "80"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "TASchedtuneBoost",
+      "Path": "/dev/stune/top-app/schedtune.boost",
+      "Values": [
+        "50",
+        "10"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWHystTriggerCount",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/hyst_trigger_count",
+      "Values": [
+        "0",
+        "3"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWHistMemory",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/hist_memory",
+      "Values": [
+        "0",
+        "20"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWHystLength",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/hyst_length",
+      "Values": [
+        "0",
+        "10"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWSampleMs",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/sample_ms",
+      "Values": [
+        "10",
+        "4"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWIOPercent",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/bw_hwmon/io_percent",
+      "Values": [
+        "80",
+        "34"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWMinFreq",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/min_freq",
+      "Values": [
+        "11856",
+        "8132",
+        "6149",
+        "2288"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "LLCCBWMinFreq",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-llcc-ddr-bw/min_freq",
+      "Values": [
+        "6881",
+        "2597",
+        "762"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "LLCCBWSampleMs",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu-llcc-ddr-bw/bw_hwmon/sample_ms",
+      "Values": [
+        "10",
+        "4"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "L3LittleClusterMinFreq",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu0-cpu-l3-lat/min_freq",
+      "Values": [
+        "1440000000",
+        "300000000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "L3BigClusterMinFreq",
+      "Path": "/sys/class/devfreq/soc:qcom,cpu4-cpu-l3-lat/min_freq",
+      "Values": [
+        "1440000000",
+        "300000000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "PMQoSCpuDmaLatency",
+      "Path": "/dev/cpu_dma_latency",
+      "Values": [
+        "44",
+        "100"
+      ],
+      "HoldFd": true
+    },
+    {
+      "Name": "SchedFeatures",
+      "Path": "/sys/kernel/debug/sched_features",
+      "Values": [
+        "NO_ENERGY_AWARE",
+        "ENERGY_AWARE"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "PowerHALMainState",
+      "Path": "vendor.powerhal.state",
+      "Values": [
+        "CAMERA_STREAMING",
+        "SUSTAINED_PERFORMANCE",
+        ""
+      ],
+      "Type": "Property"
+    },
+    {
+      "Name": "PowerHALAudioState",
+      "Path": "vendor.powerhal.audio",
+      "Values": [
+        "AUDIO_LOW_LATENCY",
+        ""
+      ],
+      "Type": "Property"
+    },
+    {
+      "Name": "PowerHALRenderingState",
+      "Path": "vendor.powerhal.rendering",
+      "Values": [
+        "EXPENSIVE_RENDERING",
+        ""
+      ],
+      "Type": "Property"
+    }
+  ],
+  "Actions": [
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "PowerHALMainState",
+      "Duration": 0,
+      "Value": "SUSTAINED_PERFORMANCE"
+    },
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "CPUBigClusterMaxFreq",
+      "Duration": 0,
+      "Value": "1401600"
+    },
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "CPUBigPlusClusterMaxFreq",
+      "Duration": 0,
+      "Value": "1401600"
+    },
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "CPULittleClusterMaxFreq",
+      "Duration": 0,
+      "Value": "1113600"
+    },
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "GPUMaxFreq",
+      "Duration": 0,
+      "Value": "379650000"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBigPlusClusterMinFreq",
+      "Duration": 0,
+      "Value": "1286400"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPULittleClusterMinFreq",
+      "Duration": 0,
+      "Value": "1113600"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "TASchedtuneBoost",
+      "Duration": 0,
+      "Value": "50"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWHystTriggerCount",
+      "Duration": 0,
+      "Value": "0"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWHystLength",
+      "Duration": 0,
+      "Value": "0"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWHistMemory",
+      "Duration": 0,
+      "Value": "0"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWMinFreq",
+      "Duration": 0,
+      "Value": "8132"
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "LLCCBWMinFreq",
+      "Duration": 0,
+      "Value": "2597"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "SchedFeatures",
+      "Duration": 5000,
+      "Value": "NO_ENERGY_AWARE"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBigClusterMaxFreq",
+      "Duration": 5000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBigPlusClusterMaxFreq",
+      "Duration": 5000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBigClusterMinFreq",
+      "Duration": 5000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBigPlusClusterMinFreq",
+      "Duration": 5000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPULittleClusterMinFreq",
+      "Duration": 5000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "PMQoSCpuDmaLatency",
+      "Duration": 5000,
+      "Value": "44"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWHystTriggerCount",
+      "Duration": 5000,
+      "Value": "0"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWHystLength",
+      "Duration": 5000,
+      "Value": "0"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWHistMemory",
+      "Duration": 5000,
+      "Value": "0"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWMinFreq",
+      "Duration": 5000,
+      "Value": "11856"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "GPUForceClkOn",
+      "Duration": 5000,
+      "Value": "1"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "GPUForceRailOn",
+      "Duration": 5000,
+      "Value": "1"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "GPUIdleTimer",
+      "Duration": 5000,
+      "Value": "10000"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "LLCCBWMinFreq",
+      "Duration": 5000,
+      "Value": "6881"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "L3LittleClusterMinFreq",
+      "Duration": 5000,
+      "Value": "1440000000"
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "L3BigClusterMinFreq",
+      "Duration": 5000,
+      "Value": "1440000000"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "SchedFeatures",
+      "Duration": 1000,
+      "Value": "NO_ENERGY_AWARE"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPUBigClusterMaxFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPUBigPlusClusterMaxFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPUBigClusterMinFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPUBigPlusClusterMinFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPULittleClusterMaxFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPULittleClusterMinFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "PMQoSCpuDmaLatency",
+      "Duration": 1000,
+      "Value": "44"
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "PowerHALMainState",
+      "Duration": 0,
+      "Value": "CAMERA_STREAMING"
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "CPUBigClusterMaxFreq",
+      "Duration": 0,
+      "Value": "2016000"
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "CPUBigPlusClusterMaxFreq",
+      "Duration": 0,
+      "Value": "2016000"
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "CPUBWSampleMs",
+      "Duration": 0,
+      "Value": "10"
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "CPUBWIOPercent",
+      "Duration": 0,
+      "Value": "80"
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "LLCCBWSampleMs",
+      "Duration": 0,
+      "Value": "10"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "SchedFeatures",
+      "Duration": 1000,
+      "Value": "NO_ENERGY_AWARE"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBigClusterMaxFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBigPlusClusterMaxFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBigClusterMinFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBigPlusClusterMinFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPULittleClusterMaxFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPULittleClusterMinFreq",
+      "Duration": 1000,
+      "Value": "9999999"
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "PMQoSCpuDmaLatency",
+      "Duration": 1000,
+      "Value": "44"
+    },
+    {
+      "PowerHint": "AUDIO_STREAMING",
+      "Node": "CPUBigClusterMinFreq",
+      "Duration": 2000,
+      "Value": "1497600"
+    },
+    {
+      "PowerHint": "AUDIO_STREAMING",
+      "Node": "CPUBigPlusClusterMinFreq",
+      "Duration": 2000,
+      "Value": "1497600"
+    },
+    {
+      "PowerHint": "AUDIO_STREAMING",
+      "Node": "PMQoSCpuDmaLatency",
+      "Duration": 2000,
+      "Value": "44"
+    },
+    {
+      "PowerHint": "AUDIO_LOW_LATENCY",
+      "Node": "PowerHALAudioState",
+      "Duration": 0,
+      "Value": "AUDIO_LOW_LATENCY"
+    },
+    {
+      "PowerHint": "AUDIO_LOW_LATENCY",
+      "Node": "PMQoSCpuDmaLatency",
+      "Duration": 0,
+      "Value": "44"
+    },
+    {
+      "PowerHint": "EXPENSIVE_RENDERING",
+      "Node": "PowerHALRenderingState",
+      "Duration": 0,
+      "Value": "EXPENSIVE_RENDERING"
+    },
+    {
+      "PowerHint": "EXPENSIVE_RENDERING",
+      "Node": "GPUMinFreq",
+      "Duration": 0,
+      "Value": "553850000"
+    },
+    {
+      "PowerHint": "EXPENSIVE_RENDERING",
+      "Node": "GPUMaxFreq",
+      "Duration": 0,
+      "Value": "600000000"
+    },
+    {
+      "PowerHint": "TPU_BOOST",
+      "Node": "PMQoSCpuDmaLatency",
+      "Duration": 2000,
+      "Value": "44"
+    }
+  ]
+}
diff --git a/powerstats/Android.bp b/powerstats/Android.bp
new file mode 100644
index 0000000..9baf56d
--- /dev/null
+++ b/powerstats/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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_binary {
+    name: "android.hardware.power.stats@1.0-service.pixel",
+    include_dirs: ["hardware/knowles/athletico/sound_trigger_hal"],
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.power.stats@1.0-service.pixel.rc"],
+    srcs: [
+        "service.cpp",
+        "RailDataProvider.cpp",
+        "GpuStateResidencyDataProvider.cpp",
+        "OsloStateResidencyDataProvider.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "libpixelpowerstats",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.power.stats@1.0",
+        "pixelpowerstats_provider_aidl_interface-cpp",
+        "libbinder",
+    ],
+    vendor: true,
+}
diff --git a/powerstats/GpuStateResidencyDataProvider.cpp b/powerstats/GpuStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..558eafa
--- /dev/null
+++ b/powerstats/GpuStateResidencyDataProvider.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 "libpixelpowerstats"
+
+#include "GpuStateResidencyDataProvider.h"
+
+#include <android-base/logging.h>
+
+#include <fstream>
+#include <sstream>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+GpuStateResidencyDataProvider::GpuStateResidencyDataProvider(uint32_t id)
+    : mPowerEntityId(id), mActiveId(0) /* (TODO (b/117228832): enable this) , mSuspendId(1) */ {}
+
+bool GpuStateResidencyDataProvider::getTotalTime(const std::string &path, uint64_t &totalTimeMs) {
+    std::ifstream inFile(path, std::ifstream::in);
+    if (!inFile.is_open()) {
+        PLOG(ERROR) << __func__ << ":Failed to open file " << path;
+        return false;
+    }
+
+    std::string line;
+    std::getline(inFile, line);
+    std::istringstream lineStream(line, std::istringstream::in);
+
+    totalTimeMs = 0;
+    uint64_t curTimeMs = 0;
+    while (lineStream >> curTimeMs) {
+        totalTimeMs += curTimeMs;
+    }
+    return true;
+}
+
+bool GpuStateResidencyDataProvider::getResults(
+    std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
+    uint64_t totalActiveTimeUs = 0;
+    if (!getTotalTime("/sys/class/kgsl/kgsl-3d0/gpu_clock_stats", totalActiveTimeUs)) {
+        LOG(ERROR) << __func__ << "Failed to get results for GPU:Active";
+        return false;
+    }
+
+    /* (TODO (b/117228832): enable this)
+    uint64_t totalSuspendTimeMs = 0;
+    if (!getTotalTime("/sys/class/kgsl/kgsl-3d0/devfreq/suspend_time", totalSuspendTimeMs)) {
+        LOG(ERROR) << __func__ << "Failed to get results for GPU:Suspend";
+        return false;
+    }
+    */
+
+    PowerEntityStateResidencyResult result = {
+        .powerEntityId = mPowerEntityId,
+        .stateResidencyData = {
+            {.powerEntityStateId = mActiveId, .totalTimeInStateMs = totalActiveTimeUs / 1000},
+            /* (TODO (b/117228832): enable this)
+            {.powerEntityStateId = mSuspendId, .totalTimeInStateMs = totalSuspendTimeMs},
+            */
+        }};
+
+    results.emplace(std::make_pair(mPowerEntityId, result));
+    return true;
+}
+
+std::vector<PowerEntityStateSpace> GpuStateResidencyDataProvider::getStateSpaces() {
+    return {{.powerEntityId = mPowerEntityId,
+             .states = {
+                 {.powerEntityStateId = mActiveId, .powerEntityStateName = "Active"},
+                 /* (TODO (b/117228832): enable this)
+                 {.powerEntityStateId = mSuspendId, .powerEntityStateName = "Suspend"}
+                 */
+             }}};
+}
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/powerstats/GpuStateResidencyDataProvider.h b/powerstats/GpuStateResidencyDataProvider.h
new file mode 100644
index 0000000..a719272
--- /dev/null
+++ b/powerstats/GpuStateResidencyDataProvider.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+#ifndef HARDWARE_GOOGLE_PIXEL_POWERSTATS_GPUSTATERESIDENCYDATAPROVIDER_H
+#define HARDWARE_GOOGLE_PIXEL_POWERSTATS_GPUSTATERESIDENCYDATAPROVIDER_H
+
+#include <pixelpowerstats/PowerStats.h>
+
+using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+class GpuStateResidencyDataProvider : public IStateResidencyDataProvider {
+  public:
+    GpuStateResidencyDataProvider(uint32_t id);
+    ~GpuStateResidencyDataProvider() = default;
+    bool getResults(
+            std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) override;
+    std::vector<PowerEntityStateSpace> getStateSpaces() override;
+
+  private:
+    bool getTotalTime(const std::string &path, uint64_t &totalTimeMs);
+    const uint32_t mPowerEntityId;
+    const uint32_t mActiveId;
+    /* (TODO (b/117228832): enable this) const uint32_t mSuspendId; */
+};
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_GOOGLE_PIXEL_POWERSTATS_GPUSTATERESIDENCYDATAPROVIDER_H
diff --git a/powerstats/OsloStateResidencyDataProvider.cpp b/powerstats/OsloStateResidencyDataProvider.cpp
new file mode 100644
index 0000000..d19345f
--- /dev/null
+++ b/powerstats/OsloStateResidencyDataProvider.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 "libpixelpowerstats"
+
+#include "OsloStateResidencyDataProvider.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <utility>
+
+#include "iaxxx-module.h"
+#include "tests/oslo_iaxxx_sensor_control.h"
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+OsloStateResidencyDataProvider::OsloStateResidencyDataProvider(uint32_t id)
+    : mPath("/dev/iaxxx-module-celldrv"), mPowerEntityId(id) {}
+
+bool OsloStateResidencyDataProvider::getResults(
+    std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
+    android::base::unique_fd devNode(open(mPath.c_str(), O_RDWR));
+    if (devNode.get() < 0) {
+        PLOG(ERROR) << __func__ << ":Failed to open file " << mPath;
+        return false;
+    }
+
+    int err = 0;
+    struct iaxxx_sensor_param sp = {
+        .inst_id = 0, .block_id = 0, .param_id = SENSOR_PARAM_DUMP_STATS, .param_val = 1};
+
+    err = ioctl(devNode.get(), MODULE_SENSOR_SET_PARAM, (unsigned long)&sp);
+    if (err) {
+        PLOG(ERROR) << __func__ << ": MODULE_SENSOR_SET_PARAM IOCTL failed";
+        return false;
+    }
+
+    struct iaxxx_sensor_mode_stats stats[SENSOR_NUM_MODE];
+    err = ioctl(devNode.get(), IAXXX_SENSOR_MODE_STATS, (unsigned long)stats);
+    if (err) {
+        PLOG(ERROR) << __func__ << ": IAXXX_SENSOR_MODE_STATS IOCTL failed";
+        return false;
+    }
+
+    PowerEntityStateResidencyResult result = {
+        .powerEntityId = mPowerEntityId,
+        .stateResidencyData = {
+            {.powerEntityStateId = SENSOR_MODE_OFF,
+             .totalTimeInStateMs = stats[SENSOR_MODE_OFF].totalTimeSpentMs,
+             .totalStateEntryCount = stats[SENSOR_MODE_OFF].totalNumEntries,
+             .lastEntryTimestampMs = stats[SENSOR_MODE_OFF].lastEntryTimeStampMs},
+            {.powerEntityStateId = SENSOR_MODE_ENTRANCE,
+             .totalTimeInStateMs = stats[SENSOR_MODE_ENTRANCE].totalTimeSpentMs,
+             .totalStateEntryCount = stats[SENSOR_MODE_ENTRANCE].totalNumEntries,
+             .lastEntryTimestampMs = stats[SENSOR_MODE_ENTRANCE].lastEntryTimeStampMs},
+            {.powerEntityStateId = SENSOR_MODE_INTERACTIVE,
+             .totalTimeInStateMs = stats[SENSOR_MODE_INTERACTIVE].totalTimeSpentMs,
+             .totalStateEntryCount = stats[SENSOR_MODE_INTERACTIVE].totalNumEntries,
+             .lastEntryTimestampMs = stats[SENSOR_MODE_INTERACTIVE].lastEntryTimeStampMs}}};
+
+    results.insert(std::make_pair(mPowerEntityId, result));
+    return true;
+}
+
+std::vector<PowerEntityStateSpace> OsloStateResidencyDataProvider::getStateSpaces() {
+    return {{.powerEntityId = mPowerEntityId,
+             .states = {
+                 {.powerEntityStateId = SENSOR_MODE_OFF, .powerEntityStateName = "Off"},
+                 {.powerEntityStateId = SENSOR_MODE_ENTRANCE, .powerEntityStateName = "Entrance"},
+                 {.powerEntityStateId = SENSOR_MODE_INTERACTIVE,
+                  .powerEntityStateName = "Interactive"}}}};
+}
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
diff --git a/powerstats/OsloStateResidencyDataProvider.h b/powerstats/OsloStateResidencyDataProvider.h
new file mode 100644
index 0000000..a48693d
--- /dev/null
+++ b/powerstats/OsloStateResidencyDataProvider.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+#ifndef HARDWARE_GOOGLE_PIXEL_POWERSTATS_OSLOSTATERESIDENCYDATAPROVIDER_H
+#define HARDWARE_GOOGLE_PIXEL_POWERSTATS_OSLOSTATERESIDENCYDATAPROVIDER_H
+
+#include <pixelpowerstats/PowerStats.h>
+
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+class OsloStateResidencyDataProvider : public IStateResidencyDataProvider {
+  public:
+    OsloStateResidencyDataProvider(uint32_t id);
+    ~OsloStateResidencyDataProvider() = default;
+    bool getResults(std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) override;
+    std::vector<PowerEntityStateSpace> getStateSpaces() override;
+
+  private:
+    const std::string mPath;
+    const uint32_t mPowerEntityId;
+};
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_GOOGLE_PIXEL_POWERSTATS_OSLOSTATERESIDENCYDATAPROVIDER_H
\ No newline at end of file
diff --git a/powerstats/RailDataProvider.cpp b/powerstats/RailDataProvider.cpp
new file mode 100644
index 0000000..86bbeb6
--- /dev/null
+++ b/powerstats/RailDataProvider.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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 <algorithm>
+#include <thread>
+#include <exception>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
+#include "RailDataProvider.h"
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+#define MAX_FILE_PATH_LEN 128
+#define MAX_DEVICE_NAME_LEN 64
+#define MAX_QUEUE_SIZE 8192
+
+constexpr char kIioDirRoot[] = "/sys/bus/iio/devices/";
+constexpr char kDeviceName[] = "microchip,pac1934";
+constexpr char kDeviceType[] = "iio:device";
+constexpr uint32_t MAX_SAMPLING_RATE = 10;
+constexpr uint64_t WRITE_TIMEOUT_NS = 1000000000;
+
+void RailDataProvider::findIioPowerMonitorNodes() {
+  struct dirent *ent;
+  int fd;
+  char devName[MAX_DEVICE_NAME_LEN];
+  char filePath[MAX_FILE_PATH_LEN];
+  DIR *iioDir = opendir(kIioDirRoot);
+  if (!iioDir) {
+    ALOGE("Error opening directory: %s", kIioDirRoot);
+    return;
+  }
+  while (ent = readdir(iioDir), ent) {
+    if (strcmp(ent->d_name, ".") != 0 &&
+        strcmp(ent->d_name, "..") != 0 &&
+        strlen(ent->d_name) > strlen(kDeviceType) &&
+        strncmp(ent->d_name, kDeviceType, strlen(kDeviceType)) == 0) {
+
+      snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", ent->d_name, "name");
+      fd = openat(dirfd(iioDir), filePath, O_RDONLY);
+      if (fd < 0) {
+        ALOGW("Failed to open directory: %s", filePath);
+        continue;
+      }
+      if (read(fd, devName, MAX_DEVICE_NAME_LEN) < 0) {
+        ALOGW("Failed to read device name from file: %s(%d)",
+              filePath, fd);
+        close(fd);
+        continue;
+      }
+
+      if (strncmp(devName, kDeviceName, strlen(kDeviceName)) == 0) {
+        snprintf(filePath, MAX_FILE_PATH_LEN, "%s/%s", kIioDirRoot, ent->d_name);
+        mOdpm.devicePaths.push_back(filePath);
+      }
+      close(fd);
+    }
+  }
+  closedir(iioDir);
+  return;
+}
+
+size_t RailDataProvider::parsePowerRails() {
+  std::string data;
+  std::string railFileName;
+  std::string spsFileName;
+  uint32_t index = 0;
+  uint32_t samplingRate;
+  for (const auto &path : mOdpm.devicePaths) {
+    railFileName = path + "/enabled_rails";
+    spsFileName = path + "/sampling_rate";
+    if (!android::base::ReadFileToString(spsFileName, &data)) {
+      ALOGW("Error reading file: %s", spsFileName.c_str());
+      continue;
+    }
+    samplingRate = strtoul(data.c_str(), NULL, 10);
+    if (!samplingRate || samplingRate == ULONG_MAX) {
+      ALOGE("Error parsing: %s", spsFileName.c_str());
+      break;
+    }
+    if (!android::base::ReadFileToString(railFileName, &data)) {
+      ALOGW("Error reading file: %s", railFileName.c_str());
+      continue;
+    }
+    std::istringstream railNames(data);
+    std::string line;
+    while (std::getline(railNames, line)) {
+      std::vector<std::string> words = android::base::Split(line, ":");
+      if (words.size() == 2) {
+        mOdpm.railsInfo.emplace(words[0],
+                           RailData {
+                             .devicePath = path,
+                             .index = index,
+                             .subsysName = words[1],
+                             .samplingRate = samplingRate
+                           });
+        index++;
+      } else {
+        ALOGW("Unexpected format in file: %s", railFileName.c_str());
+      }
+    }
+  }
+  return index;
+}
+
+int RailDataProvider::parseIioEnergyNode(std::string devName) {
+   int ret = 0;
+   std::string data;
+   std::string fileName = devName + "/energy_value";
+   if (!android::base::ReadFileToString(fileName, &data)) {
+     ALOGE("Error reading file: %s", fileName.c_str());
+     return -1;
+   }
+
+   std::istringstream energyData(data);
+   std::string line;
+   uint64_t timestamp = 0;
+   bool timestampRead = false;
+   while (std::getline(energyData, line)) {
+     std::vector<std::string> words = android::base::Split(line, ",");
+     if (timestampRead == false) {
+       if (words.size() == 1) {
+         timestamp = strtoull(words[0].c_str(), NULL, 10);
+         if (timestamp == 0 || timestamp == ULLONG_MAX) {
+           ALOGW("Potentially wrong timestamp: %" PRIu64, timestamp);
+         }
+         timestampRead = true;
+       }
+     } else if (words.size() == 2) {
+         std::string railName = words[0];
+         if (mOdpm.railsInfo.count(railName) != 0) {
+           size_t index = mOdpm.railsInfo[railName].index;
+           mOdpm.reading[index].index = index;
+           mOdpm.reading[index].timestamp = timestamp;
+           mOdpm.reading[index].energy = strtoull(words[1].c_str(), NULL, 10);
+           if (mOdpm.reading[index].energy == ULLONG_MAX) {
+             ALOGW("Potentially wrong energy value: %" PRIu64,
+                   mOdpm.reading[index].energy);
+           }
+         }
+     } else {
+       ALOGW("Unexpected format in file: %s", fileName.c_str());
+       ret = -1;
+       break;
+     }
+   }
+   return ret;
+}
+
+Status RailDataProvider::parseIioEnergyNodes() {
+  Status ret = Status::SUCCESS;
+  if (mOdpm.hwEnabled == false) {
+    return Status::NOT_SUPPORTED;
+  }
+
+  for (const auto &devicePath : mOdpm.devicePaths) {
+    if(parseIioEnergyNode(devicePath) < 0) {
+      ALOGE("Error in parsing power stats");
+      ret = Status::FILESYSTEM_ERROR;
+      break;
+    }
+  }
+  return ret;
+}
+
+RailDataProvider::RailDataProvider() {
+    findIioPowerMonitorNodes();
+    size_t numRails = parsePowerRails();
+    if (mOdpm.devicePaths.empty() || numRails == 0) {
+      mOdpm.hwEnabled = false;
+    } else {
+      mOdpm.hwEnabled = true;
+      mOdpm.reading.resize(numRails);
+    }
+}
+
+Return<void> RailDataProvider::getRailInfo(IPowerStats::getRailInfo_cb _hidl_cb) {
+  hidl_vec<RailInfo> rInfo;
+  Status ret = Status::SUCCESS;
+  size_t index;
+  std::lock_guard<std::mutex> _lock(mOdpm.mLock);
+  if (mOdpm.hwEnabled == false) {
+    _hidl_cb(rInfo, Status::NOT_SUPPORTED);
+    return Void();
+  }
+  rInfo.resize(mOdpm.railsInfo.size());
+  for (const auto& railData : mOdpm.railsInfo) {
+    index = railData.second.index;
+    rInfo[index].railName = railData.first;
+    rInfo[index].subsysName = railData.second.subsysName;
+    rInfo[index].index = index;
+    rInfo[index].samplingRate = railData.second.samplingRate;
+  }
+  _hidl_cb(rInfo, ret);
+  return Void();
+}
+
+Return<void> RailDataProvider::getEnergyData(const hidl_vec<uint32_t>& railIndices, IPowerStats::getEnergyData_cb _hidl_cb) {
+  hidl_vec<EnergyData> eVal;
+  std::lock_guard<std::mutex> _lock(mOdpm.mLock);
+  Status ret = parseIioEnergyNodes();
+
+  if (ret != Status::SUCCESS) {
+    ALOGE("Failed to getEnergyData");
+    _hidl_cb(eVal, ret);
+    return Void();
+  }
+
+  if (railIndices.size() == 0) {
+    eVal.resize(mOdpm.railsInfo.size());
+    memcpy(&eVal[0], &mOdpm.reading[0], mOdpm.reading.size() * sizeof(EnergyData));
+  } else {
+    eVal.resize(railIndices.size());
+    int i = 0;
+    for (const auto &railIndex : railIndices) {
+      if (railIndex >= mOdpm.reading.size()) {
+        ret = Status::INVALID_INPUT;
+        eVal.resize(0);
+        break;
+      }
+      memcpy(&eVal[i], &mOdpm.reading[railIndex], sizeof(EnergyData));
+      i++;
+    }
+  }
+  _hidl_cb(eVal, ret);
+  return Void();
+}
+
+Return<void> RailDataProvider::streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
+                                IPowerStats::streamEnergyData_cb _hidl_cb) {
+  std::lock_guard<std::mutex> _lock(mOdpm.mLock);
+  if (mOdpm.fmqSynchronized != nullptr) {
+    _hidl_cb(MessageQueueSync::Descriptor(),
+             0, 0, Status::INSUFFICIENT_RESOURCES);
+    return Void();
+  }
+  uint32_t sps = std::min(samplingRate, MAX_SAMPLING_RATE);
+  uint32_t numSamples = timeMs * sps / 1000;
+  mOdpm.fmqSynchronized.reset(new (std::nothrow) MessageQueueSync(MAX_QUEUE_SIZE, true));
+  if (mOdpm.fmqSynchronized == nullptr || mOdpm.fmqSynchronized->isValid() == false) {
+    mOdpm.fmqSynchronized = nullptr;
+    _hidl_cb(MessageQueueSync::Descriptor(),
+             0, 0, Status::INSUFFICIENT_RESOURCES);
+    return Void();
+  }
+  std::thread pollThread = std::thread([this, sps, numSamples]() {
+    uint64_t sleepTimeUs = 1000000/sps;
+    uint32_t currSamples = 0;
+    while (currSamples < numSamples) {
+      mOdpm.mLock.lock();
+      if (parseIioEnergyNodes() == Status::SUCCESS) {
+        mOdpm.fmqSynchronized->writeBlocking(&mOdpm.reading[0],
+                                             mOdpm.reading.size(), WRITE_TIMEOUT_NS);
+        mOdpm.mLock.unlock();
+        currSamples++;
+        if (usleep(sleepTimeUs) < 0) {
+          ALOGW("Sleep interrupted");
+          break;
+        }
+      } else {
+        mOdpm.mLock.unlock();
+        break;
+      }
+    }
+    mOdpm.mLock.lock();
+    mOdpm.fmqSynchronized = nullptr;
+    mOdpm.mLock.unlock();
+    return;
+  });
+  pollThread.detach();
+  _hidl_cb(*(mOdpm.fmqSynchronized)->getDesc(), numSamples,
+           mOdpm.reading.size(), Status::SUCCESS);
+  return Void();
+}
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
diff --git a/powerstats/RailDataProvider.h b/powerstats/RailDataProvider.h
new file mode 100644
index 0000000..a11440b
--- /dev/null
+++ b/powerstats/RailDataProvider.h
@@ -0,0 +1,53 @@
+#ifndef ANDROID_HARDWARE_POWERSTATS_RAILDATAPROVIDER_H
+#define ANDROID_HARDWARE_POWERSTATS_RAILDATAPROVIDER_H
+
+#include <fmq/MessageQueue.h>
+#include <pixelpowerstats/PowerStats.h>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace powerstats {
+
+typedef MessageQueue<EnergyData, kSynchronizedReadWrite> MessageQueueSync;
+struct RailData {
+    std::string devicePath;
+    uint32_t index;
+    std::string subsysName;
+    uint32_t samplingRate;
+};
+
+struct OnDeviceMmt {
+    std::mutex mLock;
+    bool hwEnabled;
+    std::vector<std::string> devicePaths;
+    std::map<std::string, RailData> railsInfo;
+    std::vector<EnergyData> reading;
+    std::unique_ptr<MessageQueueSync> fmqSynchronized;
+};
+
+class RailDataProvider : public IRailDataProvider {
+public:
+    RailDataProvider();
+    // Methods from ::android::hardware::power::stats::V1_0::IPowerStats follow.
+    Return<void> getRailInfo(IPowerStats::getRailInfo_cb _hidl_cb) override;
+    Return<void> getEnergyData(const hidl_vec<uint32_t>& railIndices,
+                        IPowerStats::getEnergyData_cb _hidl_cb) override;
+    Return<void> streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
+                        IPowerStats::streamEnergyData_cb _hidl_cb) override;
+ private:
+     OnDeviceMmt mOdpm;
+     void findIioPowerMonitorNodes();
+     size_t parsePowerRails();
+     int parseIioEnergyNode(std::string devName);
+     Status parseIioEnergyNodes();
+};
+
+}  // namespace powerstats
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_POWERSTATS_RAILDATAPROVIDER_H
diff --git a/powerstats/android.hardware.power.stats@1.0-service.pixel.rc b/powerstats/android.hardware.power.stats@1.0-service.pixel.rc
new file mode 100644
index 0000000..6ba83c2
--- /dev/null
+++ b/powerstats/android.hardware.power.stats@1.0-service.pixel.rc
@@ -0,0 +1,4 @@
+service vendor.power.stats-hal-1-0 /vendor/bin/hw/android.hardware.power.stats@1.0-service.pixel
+    class hal
+    user system
+    group system
diff --git a/powerstats/service.cpp b/powerstats/service.cpp
new file mode 100644
index 0000000..229fadd
--- /dev/null
+++ b/powerstats/service.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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.power.stats@1.0-service.pixel"
+
+#include <android/log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <pixelpowerstats/AidlStateResidencyDataProvider.h>
+#include <pixelpowerstats/GenericStateResidencyDataProvider.h>
+#include <pixelpowerstats/PowerStats.h>
+#include <pixelpowerstats/WlanStateResidencyDataProvider.h>
+
+#include "GpuStateResidencyDataProvider.h"
+#include "OsloStateResidencyDataProvider.h"
+#include "RailDataProvider.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::stats::V1_0::IPowerStats;
+using android::hardware::power::stats::V1_0::PowerEntityType;
+using android::hardware::power::stats::V1_0::implementation::PowerStats;
+
+// Pixel specific
+using android::hardware::google::pixel::powerstats::AidlStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::generateGenericStateResidencyConfigs;
+using android::hardware::google::pixel::powerstats::GenericStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::GpuStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::OsloStateResidencyDataProvider;
+using android::hardware::google::pixel::powerstats::PowerEntityConfig;
+using android::hardware::google::pixel::powerstats::RailDataProvider;
+using android::hardware::google::pixel::powerstats::StateResidencyConfig;
+using android::hardware::google::pixel::powerstats::WlanStateResidencyDataProvider;
+
+int main(int /* argc */, char** /* argv */) {
+    ALOGI("power.stats service 1.0 is starting.");
+
+
+    PowerStats* service = new PowerStats();
+
+    // Add rail data provider
+    service->setRailDataProvider(std::make_unique<RailDataProvider>());
+
+    // Add power entities related to rpmh
+    const uint64_t RPM_CLK = 19200;  // RPM runs at 19.2Mhz. Divide by 19200 for msec
+    std::function<uint64_t(uint64_t)> rpmConvertToMs = [](uint64_t a) { return a / RPM_CLK; };
+    std::vector<StateResidencyConfig> rpmStateResidencyConfigs = {
+        {.name = "Sleep",
+         .entryCountSupported = true,
+         .entryCountPrefix = "Sleep Count:",
+         .totalTimeSupported = true,
+         .totalTimePrefix = "Sleep Accumulated Duration:",
+         .totalTimeTransform = rpmConvertToMs,
+         .lastEntrySupported = true,
+         .lastEntryPrefix = "Sleep Last Entered At:",
+         .lastEntryTransform = rpmConvertToMs}};
+
+    sp<GenericStateResidencyDataProvider> rpmSdp =
+            new GenericStateResidencyDataProvider("/sys/power/rpmh_stats/master_stats");
+
+    uint32_t apssId = service->addPowerEntity("APSS", PowerEntityType::SUBSYSTEM);
+    rpmSdp->addEntity(apssId, PowerEntityConfig("APSS", rpmStateResidencyConfigs));
+
+    uint32_t mpssId = service->addPowerEntity("MPSS", PowerEntityType::SUBSYSTEM);
+    rpmSdp->addEntity(mpssId, PowerEntityConfig("MPSS", rpmStateResidencyConfigs));
+
+    uint32_t adspId = service->addPowerEntity("ADSP", PowerEntityType::SUBSYSTEM);
+    rpmSdp->addEntity(adspId, PowerEntityConfig("ADSP", rpmStateResidencyConfigs));
+
+    uint32_t cdspId = service->addPowerEntity("CDSP", PowerEntityType::SUBSYSTEM);
+    rpmSdp->addEntity(cdspId, PowerEntityConfig("CDSP", rpmStateResidencyConfigs));
+
+    uint32_t slpiId = service->addPowerEntity("SLPI", PowerEntityType::SUBSYSTEM);
+    rpmSdp->addEntity(slpiId, PowerEntityConfig("SLPI", rpmStateResidencyConfigs));
+
+    uint32_t slpiIslandId = service->addPowerEntity("SLPI_ISLAND", PowerEntityType::SUBSYSTEM);
+    rpmSdp->addEntity(slpiIslandId, PowerEntityConfig("SLPI_ISLAND", {
+        {.name = "uImage",
+         .entryCountSupported = true,
+         .entryCountPrefix = "Sleep Count:",
+         .totalTimeSupported = true,
+         .totalTimePrefix = "Sleep Accumulated Duration:",
+         .totalTimeTransform = rpmConvertToMs,
+         .lastEntrySupported = true,
+         .lastEntryPrefix = "Sleep Last Entered At:",
+         .lastEntryTransform = rpmConvertToMs}}));
+
+    service->addStateResidencyDataProvider(rpmSdp);
+
+    // Add SoC power entity
+    StateResidencyConfig socStateConfig = {
+        .entryCountSupported = true,
+        .entryCountPrefix = "count:",
+        .totalTimeSupported = true,
+        .totalTimePrefix = "actual last sleep(msec):",
+        .lastEntrySupported = false
+    };
+    std::vector<std::pair<std::string, std::string>> socStateHeaders = {
+        std::make_pair("AOSD", "RPM Mode:aosd"),
+        std::make_pair("CXSD", "RPM Mode:cxsd"),
+        std::make_pair("DDR", "RPM Mode:ddr"),
+    };
+
+    sp<GenericStateResidencyDataProvider> socSdp =
+            new GenericStateResidencyDataProvider("/sys/power/system_sleep/stats");
+
+    uint32_t socId = service->addPowerEntity("SoC", PowerEntityType::POWER_DOMAIN);
+    socSdp->addEntity(socId,
+        PowerEntityConfig(generateGenericStateResidencyConfigs(socStateConfig, socStateHeaders)));
+
+    service->addStateResidencyDataProvider(socSdp);
+
+    // Add WLAN power entity
+    uint32_t wlanId = service->addPowerEntity("WLAN", PowerEntityType::SUBSYSTEM);
+    sp<WlanStateResidencyDataProvider> wlanSdp =
+            new WlanStateResidencyDataProvider(wlanId, "/sys/kernel/wlan/power_stats");
+    service->addStateResidencyDataProvider(wlanSdp);
+
+    // Add Airbrush power entity
+    StateResidencyConfig airStateConfig = {
+        .entryCountSupported = true,
+        .entryCountPrefix = "Cumulative count:",
+        .totalTimeSupported = true,
+        .totalTimePrefix = "Cumulative duration msec:",
+        .lastEntrySupported = true,
+        .lastEntryPrefix = "Last entry timestamp msec:",
+    };
+    std::vector<std::pair<std::string, std::string>> airStateHeaders = {
+        std::make_pair("Active", "ACTIVE"),
+        std::make_pair("Sleep", "SLEEP"),
+        std::make_pair("Deep-Sleep", "DEEP SLEEP"),
+        std::make_pair("Suspend", "SUSPEND"),
+        std::make_pair("Off", "OFF"),
+        std::make_pair("Unknown", "UNKNOWN"),
+    };
+
+    sp<GenericStateResidencyDataProvider> airSdp =
+            new GenericStateResidencyDataProvider(
+                    "/sys/devices/platform/soc/soc:abc-sm/state_stats");
+
+    uint32_t airId = service->addPowerEntity("Visual-Core", PowerEntityType::SUBSYSTEM);
+    airSdp->addEntity(airId, PowerEntityConfig("Pixel Visual Core Subsystem Power Stats",
+            generateGenericStateResidencyConfigs(airStateConfig, airStateHeaders)));
+
+    service->addStateResidencyDataProvider(airSdp);
+
+    // Add NFC power entity
+    StateResidencyConfig nfcStateConfig = {
+        .entryCountSupported = true,
+        .entryCountPrefix = "Cumulative count:",
+        .totalTimeSupported = true,
+        .totalTimePrefix = "Cumulative duration msec:",
+        .lastEntrySupported = true,
+        .lastEntryPrefix = "Last entry timestamp msec:"
+    };
+    std::vector<std::pair<std::string, std::string>> nfcStateHeaders = {
+        std::make_pair("Idle", "Idle mode:"),
+        std::make_pair("Active", "Active mode:"),
+        std::make_pair("Active-RW", "Active Reader/Writer mode:"),
+    };
+
+    sp<GenericStateResidencyDataProvider> nfcSdp =
+            new GenericStateResidencyDataProvider("/sys/class/misc/st21nfc/device/power_stats");
+
+    uint32_t nfcId = service->addPowerEntity("NFC", PowerEntityType::SUBSYSTEM);
+    nfcSdp->addEntity(nfcId,
+        PowerEntityConfig(generateGenericStateResidencyConfigs(nfcStateConfig, nfcStateHeaders)));
+
+    service->addStateResidencyDataProvider(nfcSdp);
+
+    // Add GPU power entity
+    uint32_t gpuId = service->addPowerEntity("GPU", PowerEntityType::SUBSYSTEM);
+    sp<GpuStateResidencyDataProvider> gpuSdp = new GpuStateResidencyDataProvider(gpuId);
+    service->addStateResidencyDataProvider(gpuSdp);
+
+    // Add Oslo power entity
+    uint32_t osloId = service->addPowerEntity("Oslo", PowerEntityType::SUBSYSTEM);
+    sp<OsloStateResidencyDataProvider> osloSdp = new OsloStateResidencyDataProvider(osloId);
+    service->addStateResidencyDataProvider(osloSdp);
+
+    // Add Power Entities that require the Aidl data provider
+    sp<AidlStateResidencyDataProvider> aidlSdp = new AidlStateResidencyDataProvider();
+    uint32_t citadelId = service->addPowerEntity("Citadel", PowerEntityType::SUBSYSTEM);
+    aidlSdp->addEntity(citadelId, "Citadel", {"Last-Reset", "Active", "Deep-Sleep"});
+
+    auto serviceStatus = android::defaultServiceManager()->addService(
+            android::String16("power.stats-vendor"), aidlSdp);
+    if (serviceStatus != android::OK) {
+        ALOGE("Unable to register power.stats-vendor service %d", serviceStatus);
+        return 1;
+    }
+    sp<android::ProcessState> ps{android::ProcessState::self()};  // Create non-HW binder threadpool
+    ps->startThreadPool();
+
+    service->addStateResidencyDataProvider(aidlSdp);
+
+    // Configure the threadpool
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    status_t status = service->registerAsService();
+    if (status != OK) {
+        ALOGE("Could not register service for power.stats HAL Iface (%d), exiting.", status);
+        return 1;
+    }
+
+    ALOGI("power.stats service is ready");
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("power.stats service is shutting down");
+    return 1;
+}
diff --git a/product.prop b/product.prop
new file mode 100644
index 0000000..9d1a473
--- /dev/null
+++ b/product.prop
@@ -0,0 +1,94 @@
+
+persist.rild.nitz_plmn=
+persist.rild.nitz_long_ons_0=
+persist.rild.nitz_long_ons_1=
+persist.rild.nitz_long_ons_2=
+persist.rild.nitz_long_ons_3=
+persist.rild.nitz_short_ons_0=
+persist.rild.nitz_short_ons_1=
+persist.rild.nitz_short_ons_2=
+persist.rild.nitz_short_ons_3=
+DEVICE_PROVISIONED=1
+
+# Set network mode to Global by default and no DSDS/DSDA
+ro.telephony.default_network=10
+
+debug.sf.hw=1
+debug.gralloc.enable_fb_ubwc=1
+
+# system props for the cne module
+persist.vendor.cne.feature=1
+
+# system props for the MM modules
+media.stagefright.enable-player=true
+media.stagefright.enable-http=true
+media.stagefright.enable-aac=true
+media.stagefright.enable-qcp=true
+media.stagefright.enable-scan=true
+mmp.enable.3g2=true
+media.aac_51_output_enabled=true
+mm.enable.smoothstreaming=true
+#13631487 is decimal sum of supported codecs in AAL
+#codecs:(PARSER_)AAC AC3 AMR_NB AMR_WB ASF AVI DTS FLV 3GP 3G2 MKV MP2PS MP2TS MP3 OGG QCP WAV FLAC AIFF APE DSD
+mm.enable.qcom_parser=13631487
+persist.mm.enable.prefetch=true
+
+# Additional buffers shared between Camera and Video
+vidc.enc.dcvs.extra-buff-count=2
+vidc.enc.disable.pq=1
+
+# system props for the data netmgrd
+persist.data.netmgrd.qos.enable=true
+persist.vendor.data.mode=concurrent
+
+# system props for time-services
+persist.timed.enable=true
+
+# system props for perfetto
+persist.traced.enable=1
+persist.heapprofd.enable=1
+
+# System prop to turn on CdmaLTEPhone always
+telephony.lteOnCdmaDevice=1
+
+# Simulate sdcard on /data/media
+persist.fuse_sdcard=true
+
+# settings to enable Device Orientation Sensors
+ro.qti.sensors.dev_ori=true
+
+# settings to disable sensors not needed
+# all secondary wakeup
+ro.qti.sensors.wu=false
+# unused algorithms
+ro.qti.sdk.sensors.gestures=false
+ro.qti.sensors.amd=false
+ro.qti.sensors.cmc=false
+ro.qti.sensors.facing=false
+ro.qti.sensors.pedometer=false
+ro.qti.sensors.rmd=false
+ro.qti.sensors.scrn_ortn=false
+# use SMGR supplied verison
+ro.qti.sensors.step_counter=false
+ro.qti.sensors.step_detector=false
+
+#system prop for RmNet Data
+persist.rmnet.data.enable=true
+persist.data.wda.enable=true
+persist.data.df.dl_mode=5
+persist.data.df.ul_mode=5
+persist.data.df.agg.dl_pkt=10
+persist.data.df.agg.dl_size=4096
+persist.data.df.mux_count=8
+persist.data.df.iwlan_mux=9
+persist.data.df.dev_name=rmnet_usb0
+
+#
+## system props for the data modules
+#
+#ro.use_data_netmgrd=true
+persist.data.netmgrd.qos.enable=true
+persist.data.mode=concurrent
+
+# Disable RescueParty / rescue mode
+persist.sys.disable_rescue=true
diff --git a/recovery.wipe b/recovery.wipe
new file mode 100644
index 0000000..f3b99e0
--- /dev/null
+++ b/recovery.wipe
@@ -0,0 +1,12 @@
+# All the partitions to be wiped (in order) under recovery.
+/dev/block/bootdevice/by-name/system_a
+/dev/block/bootdevice/by-name/system_b
+/dev/block/bootdevice/by-name/product_a
+/dev/block/bootdevice/by-name/product_b
+/dev/block/bootdevice/by-name/vendor_a
+/dev/block/bootdevice/by-name/vendor_b
+/dev/block/bootdevice/by-name/userdata
+# Wipe the boot partitions last so that all partitions will be wiped
+# correctly even if the wiping process gets interrupted by a force boot.
+/dev/block/bootdevice/by-name/boot_a
+/dev/block/bootdevice/by-name/boot_b
diff --git a/recovery/Android.bp b/recovery/Android.bp
new file mode 100644
index 0000000..37cf203
--- /dev/null
+++ b/recovery/Android.bp
@@ -0,0 +1,39 @@
+//
+// 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_static {
+    name: "librecovery_ui_bramble",
+    owner: "google",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-pedantic",
+    ],
+    srcs: [
+        "recovery_ui.cpp",
+    ],
+
+    static_libs: [
+        "libbase",
+        "libnos_for_recovery",
+        "libnos_citadel_for_recovery",
+    ],
+
+    shared_libs: [
+        "librecovery_ui",
+    ],
+}
diff --git a/recovery/recovery_ui.cpp b/recovery/recovery_ui.cpp
new file mode 100644
index 0000000..55e686d
--- /dev/null
+++ b/recovery/recovery_ui.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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 <android-base/endian.h>
+#include <android-base/logging.h>
+
+#include <app_nugget.h>
+#include <nos/debug.h>
+#include <nos/NuggetClient.h>
+
+#include <recovery_ui/device.h>
+#include <recovery_ui/screen_ui.h>
+
+namespace android {
+namespace device {
+namespace google {
+namespace bramble {
+
+namespace {
+
+/** Wipe user data from Titan M. */
+bool WipeTitanM() {
+    // Connect to Titan M
+    ::nos::NuggetClient client;
+    client.Open();
+    if (!client.IsOpen()) {
+        LOG(ERROR) << "Failed to connect to Titan M";
+        return false;
+    }
+
+    // Tell it to wipe user data
+    const uint32_t magicValue = htole32(ERASE_CONFIRMATION);
+    std::vector<uint8_t> magic(sizeof(magicValue));
+    memcpy(magic.data(), &magicValue, sizeof(magicValue));
+    const uint32_t status
+            = client.CallApp(APP_ID_NUGGET, NUGGET_PARAM_NUKE_FROM_ORBIT, magic, nullptr);
+    if (status != APP_SUCCESS) {
+        LOG(ERROR) << "Titan M user data wipe failed: " << ::nos::StatusCodeString(status)
+                   << " (" << status << ")";
+        return false;
+    }
+
+    LOG(INFO) << "Titan M wipe successful";
+    return true;
+}
+
+} // namespace
+
+class BrambleDevice : public ::Device
+{
+public:
+    BrambleDevice(::ScreenRecoveryUI* const ui) : ::Device(ui) {}
+
+    /** Hook to wipe user data not stored in /data */
+    bool PostWipeData() override {
+        // Try to do everything but report a failure if anything wasn't successful
+        bool totalSuccess = true;
+        ::RecoveryUI* const ui = GetUI();
+
+        ui->Print("Wiping Titan M...\n");
+        if (!WipeTitanM()) {
+            totalSuccess = false;
+        }
+
+        // Extendable to wipe other components
+
+        return totalSuccess;
+    }
+};
+
+} // namespace bramble
+} // namespace google
+} // namespace device
+} // namespace android
+
+Device *make_device()
+{
+    return new ::android::device::google::bramble::BrambleDevice(new ::ScreenRecoveryUI);
+}
diff --git a/sec_config b/sec_config
new file mode 100644
index 0000000..a33c89b
--- /dev/null
+++ b/sec_config
@@ -0,0 +1,330 @@
+/* IPC Security Config */
+/* <GPS QMI Service ID - 16>:<GPS QMI Instance ID - all instances>:<Client Group ID> */
+16:4294967295:1000:1021:1026
+/* <QDMA QMI Service ID - 75>:<QDMA QMI Instance ID - all instances>:<Client Group ID> */
+75:4294967295:1000:1001:3006
+/* <LOWI QMI Service ID - 38>:<LOWI QMI Instance ID - all instances>:<Client Group ID> */
+56:4294967295:1021
+/* Allow SS CTL service to be used by system and net_raw processes */
+43:4294967295:1000:3004
+/* <UIMHTTP QMI Service ID - 16>:<UIMHTTP QMI Instance ID - all instances>:<Client Group ID> */
+71:4294967295:1001
+/* <UIMRMT QMI Service ID - 16>:<UIMRMT QMI Instance ID - all instances>:<Client Group ID> */
+50:4294967295:1001
+/* QMI-SLIM service permitted to gps and net_raw */
+55:4294967295:1021
+/* Allow Sensor services to be used by sensor process */
+256:4294967295:1000:1006:1013:1021:1047:3011
+257:4294967295:1000:1006:1013:1021:1047:3011
+258:4294967295:1000:1006:1013:1021:1047:3011
+259:4294967295:1000:1006:1013:1021:1047:3011
+260:4294967295:1000:1006:1013:1021:1047:3011
+261:4294967295:1000:1006:1013:1021:1047:3011
+262:4294967295:1000:1006:1013:1021:1047:3011
+263:4294967295:1000:1006:1013:1021:1047:3011
+264:4294967295:1000:1006:1013:1021:1047:3011
+265:4294967295:1000:1006:1013:1021:1047:3011
+266:4294967295:1000:1006:1013:1021:1047:3011
+267:4294967295:1000:1006:1013:1021:1047:3011
+268:4294967295:1000:1006:1013:1021:1047:3011
+269:4294967295:1000:1006:1013:1021:1047:3011
+270:4294967295:1000:1006:1013:1021:1047:3011
+271:4294967295:1000:1006:1013:1021:1047:3011
+272:4294967295:1000:1006:1013:1021:1047:3011
+273:4294967295:1000:1006:1013:1021:1047:3011
+274:4294967295:1000:1006:1013:1021:1047:3011
+275:4294967295:1000:1006:1013:1021:1047:3011
+276:4294967295:1000:1006:1013:1021:1047:3011
+277:4294967295:1000:1006:1013:1021:1047:3011
+278:4294967295:1000:1006:1013:1021:1047:3011
+279:4294967295:1000:1006:1013:1021:1047:3011
+280:4294967295:1000:1006:1013:1021:1047:3011
+281:4294967295:1000:1006:1013:1021:1047:3011
+282:4294967295:1000:1006:1013:1021:1047:3011
+283:4294967295:1000:1006:1013:1021:1047:3011
+284:4294967295:1000:1006:1013:1021:1047:3011
+285:4294967295:1000:1006:1013:1021:1047:3011
+286:4294967295:1000:1006:1013:1021:1047:3011
+287:4294967295:1000:1006:1013:1021:1047:3011
+288:4294967295:1000:1006:1013:1021:1047:3011
+289:4294967295:1000:1006:1013:1021:1047:3011
+290:4294967295:1000:1006:1013:1021:1047:3011
+291:4294967295:1000:1006:1013:1021:1047:3011
+292:4294967295:1000:1006:1013:1021:1047:3011
+293:4294967295:1000:1006:1013:1021:1047:3011
+294:4294967295:1000:1006:1013:1021:1047:3011
+295:4294967295:1000:1006:1013:1021:1047:3011
+296:4294967295:1000:1006:1013:1021:1047:3011
+297:4294967295:1000:1006:1013:1021:1047:3011
+298:4294967295:1000:1006:1013:1021:1047:3011
+299:4294967295:1000:1006:1013:1021:1047:3011
+300:4294967295:1000:1006:1013:1021:1047:3011
+301:4294967295:1000:1006:1013:1021:1047:3011
+302:4294967295:1000:1006:1013:1021:1047:3011
+303:4294967295:1000:1006:1013:1021:1047:3011
+304:4294967295:1000:1006:1013:1021:1047:3011
+305:4294967295:1000:1006:1013:1021:1047:3011
+306:4294967295:1000:1006:1013:1021:1047:3011
+307:4294967295:1000:1006:1013:1021:1047:3011
+308:4294967295:1000:1006:1013:1021:1047:3011
+309:4294967295:1000:1006:1013:1021:1047:3011
+310:4294967295:1000:1006:1013:1021:1047:3011
+311:4294967295:1000:1006:1013:1021:1047:3011
+312:4294967295:1000:1006:1013:1021:1047:3011
+313:4294967295:1000:1006:1013:1021:1047:3011
+314:4294967295:1000:1006:1013:1021:1047:3011
+315:4294967295:1000:1006:1013:1021:1047:3011
+316:4294967295:1000:1006:1013:1021:1047:3011
+317:4294967295:1000:1006:1013:1021:1047:3011
+318:4294967295:1000:1006:1013:1021:1047:3011
+319:4294967295:1000:1006:1013:1021:1047:3011
+320:4294967295:1000:1006:1013:1021:1047:3011
+321:4294967295:1000:1006:1013:1021:1047:3011
+322:4294967295:1000:1006:1013:1021:1047:3011
+323:4294967295:1000:1006:1013:1021:1047:3011
+324:4294967295:1000:1006:1013:1021:1047:3011
+325:4294967295:1000:1006:1013:1021:1047:3011
+326:4294967295:1000:1006:1013:1021:1047:3011
+327:4294967295:1000:1006:1013:1021:1047:3011
+328:4294967295:1000:1006:1013:1021:1047:3011
+329:4294967295:1000:1006:1013:1021:1047:3011
+330:4294967295:1000:1006:1013:1021:1047:3011
+331:4294967295:1000:1006:1013:1021:1047:3011
+332:4294967295:1000:1006:1013:1021:1047:3011
+333:4294967295:1000:1006:1013:1021:1047:3011
+334:4294967295:1000:1006:1013:1021:1047:3011
+335:4294967295:1000:1006:1013:1021:1047:3011
+336:4294967295:1000:1006:1013:1021:1047:3011
+337:4294967295:1000:1006:1013:1021:1047:3011
+338:4294967295:1000:1006:1013:1021:1047:3011
+339:4294967295:1000:1006:1013:1021:1047:3011
+340:4294967295:1000:1006:1013:1021:1047:3011
+341:4294967295:1000:1006:1013:1021:1047:3011
+342:4294967295:1000:1006:1013:1021:1047:3011
+343:4294967295:1000:1006:1013:1021:1047:3011
+344:4294967295:1000:1006:1013:1021:1047:3011
+345:4294967295:1000:1006:1013:1021:1047:3011
+346:4294967295:1000:1006:1013:1021:1047:3011
+347:4294967295:1000:1006:1013:1021:1047:3011
+348:4294967295:1000:1006:1013:1021:1047:3011
+349:4294967295:1000:1006:1013:1021:1047:3011
+350:4294967295:1000:1006:1013:1021:1047:3011
+351:4294967295:1000:1006:1013:1021:1047:3011
+352:4294967295:1000:1006:1013:1021:1047:3011
+353:4294967295:1000:1006:1013:1021:1047:3011
+354:4294967295:1000:1006:1013:1021:1047:3011
+355:4294967295:1000:1006:1013:1021:1047:3011
+356:4294967295:1000:1006:1013:1021:1047:3011
+357:4294967295:1000:1006:1013:1021:1047:3011
+358:4294967295:1000:1006:1013:1021:1047:3011
+359:4294967295:1000:1006:1013:1021:1047:3011
+360:4294967295:1000:1006:1013:1021:1047:3011
+361:4294967295:1000:1006:1013:1021:1047:3011
+362:4294967295:1000:1006:1013:1021:1047:3011
+363:4294967295:1000:1006:1013:1021:1047:3011
+364:4294967295:1000:1006:1013:1021:1047:3011
+365:4294967295:1000:1006:1013:1021:1047:3011
+366:4294967295:1000:1006:1013:1021:1047:3011
+367:4294967295:1000:1006:1013:1021:1047:3011
+368:4294967295:1000:1006:1013:1021:1047:3011
+369:4294967295:1000:1006:1013:1021:1047:3011
+370:4294967295:1000:1006:1013:1021:1047:3011
+371:4294967295:1000:1006:1013:1021:1047:3011
+372:4294967295:1000:1006:1013:1021:1047:3011
+373:4294967295:1000:1006:1013:1021:1047:3011
+374:4294967295:1000:1006:1013:1021:1047:3011
+375:4294967295:1000:1006:1013:1021:1047:3011
+376:4294967295:1000:1006:1013:1021:1047:3011
+377:4294967295:1000:1006:1013:1021:1047:3011
+378:4294967295:1000:1006:1013:1021:1047:3011
+379:4294967295:1000:1006:1013:1021:1047:3011
+380:4294967295:1000:1006:1013:1021:1047:3011
+381:4294967295:1000:1006:1013:1021:1047:3011
+382:4294967295:1000:1006:1013:1021:1047:3011
+383:4294967295:1000:1006:1013:1021:1047:3011
+384:4294967295:1000:1006:1013:1021:1047:3011
+385:4294967295:1000:1006:1013:1021:1047:3011
+386:4294967295:1000:1006:1013:1021:1047:3011
+387:4294967295:1000:1006:1013:1021:1047:3011
+388:4294967295:1000:1006:1013:1021:1047:3011
+389:4294967295:1000:1006:1013:1021:1047:3011
+390:4294967295:1000:1006:1013:1021:1047:3011
+391:4294967295:1000:1006:1013:1021:1047:3011
+392:4294967295:1000:1006:1013:1021:1047:3011
+393:4294967295:1000:1006:1013:1021:1047:3011
+394:4294967295:1000:1006:1013:1021:1047:3011
+395:4294967295:1000:1006:1013:1021:1047:3011
+396:4294967295:1000:1006:1013:1021:1047:3011
+397:4294967295:1000:1006:1013:1021:1047:3011
+398:4294967295:1000:1006:1013:1021:1047:3011
+399:4294967295:1000:1006:1013:1021:1047:3011
+400:4294967295:1000:1006:1013:1021:1047:3011
+401:4294967295:1000:1006:1013:1021:1047:3011
+402:4294967295:1000:1006:1013:1021:1047:3011
+403:4294967295:1000:1006:1013:1021:1047:3011
+404:4294967295:1000:1006:1013:1021:1047:3011
+405:4294967295:1000:1006:1013:1021:1047:3011
+406:4294967295:1000:1006:1013:1021:1047:3011
+407:4294967295:1000:1006:1013:1021:1047:3011
+408:4294967295:1000:1006:1013:1021:1047:3011
+409:4294967295:1000:1006:1013:1021:1047:3011
+410:4294967295:1000:1006:1013:1021:1047:3011
+411:4294967295:1000:1006:1013:1021:1047:3011
+412:4294967295:1000:1006:1013:1021:1047:3011
+413:4294967295:1000:1006:1013:1021:1047:3011
+414:4294967295:1000:1006:1013:1021:1047:3011
+415:4294967295:1000:1006:1013:1021:1047:3011
+416:4294967295:1000:1006:1013:1021:1047:3011
+417:4294967295:1000:1006:1013:1021:1047:3011
+418:4294967295:1000:1006:1013:1021:1047:3011
+419:4294967295:1000:1006:1013:1021:1047:3011
+420:4294967295:1000:1006:1013:1021:1047:3011
+421:4294967295:1000:1006:1013:1021:1047:3011
+422:4294967295:1000:1006:1013:1021:1047:3011
+423:4294967295:1000:1006:1013:1021:1047:3011
+424:4294967295:1000:1006:1013:1021:1047:3011
+425:4294967295:1000:1006:1013:1021:1047:3011
+426:4294967295:1000:1006:1013:1021:1047:3011
+427:4294967295:1000:1006:1013:1021:1047:3011
+428:4294967295:1000:1006:1013:1021:1047:3011
+429:4294967295:1000:1006:1013:1021:1047:3011
+430:4294967295:1000:1006:1013:1021:1047:3011
+431:4294967295:1000:1006:1013:1021:1047:3011
+432:4294967295:1000:1006:1013:1021:1047:3011
+433:4294967295:1000:1006:1013:1021:1047:3011
+434:4294967295:1000:1006:1013:1021:1047:3011
+435:4294967295:1000:1006:1013:1021:1047:3011
+436:4294967295:1000:1006:1013:1021:1047:3011
+437:4294967295:1000:1006:1013:1021:1047:3011
+438:4294967295:1000:1006:1013:1021:1047:3011
+439:4294967295:1000:1006:1013:1021:1047:3011
+440:4294967295:1000:1006:1013:1021:1047:3011
+441:4294967295:1000:1006:1013:1021:1047:3011
+442:4294967295:1000:1006:1013:1021:1047:3011
+443:4294967295:1000:1006:1013:1021:1047:3011
+444:4294967295:1000:1006:1013:1021:1047:3011
+445:4294967295:1000:1006:1013:1021:1047:3011
+446:4294967295:1000:1006:1013:1021:1047:3011
+447:4294967295:1000:1006:1013:1021:1047:3011
+448:4294967295:1000:1006:1013:1021:1047:3011
+449:4294967295:1000:1006:1013:1021:1047:3011
+450:4294967295:1000:1006:1013:1021:1047:3011
+451:4294967295:1000:1006:1013:1021:1047:3011
+452:4294967295:1000:1006:1013:1021:1047:3011
+453:4294967295:1000:1006:1013:1021:1047:3011
+454:4294967295:1000:1006:1013:1021:1047:3011
+455:4294967295:1000:1006:1013:1021:1047:3011
+456:4294967295:1000:1006:1013:1021:1047:3011
+457:4294967295:1000:1006:1013:1021:1047:3011
+458:4294967295:1000:1006:1013:1021:1047:3011
+459:4294967295:1000:1006:1013:1021:1047:3011
+460:4294967295:1000:1006:1013:1021:1047:3011
+461:4294967295:1000:1006:1013:1021:1047:3011
+462:4294967295:1000:1006:1013:1021:1047:3011
+463:4294967295:1000:1006:1013:1021:1047:3011
+464:4294967295:1000:1006:1013:1021:1047:3011
+465:4294967295:1000:1006:1013:1021:1047:3011
+466:4294967295:1000:1006:1013:1021:1047:3011
+467:4294967295:1000:1006:1013:1021:1047:3011
+468:4294967295:1000:1006:1013:1021:1047:3011
+469:4294967295:1000:1006:1013:1021:1047:3011
+470:4294967295:1000:1006:1013:1021:1047:3011
+471:4294967295:1000:1006:1013:1021:1047:3011
+472:4294967295:1000:1006:1013:1021:1047:3011
+473:4294967295:1000:1006:1013:1021:1047:3011
+474:4294967295:1000:1006:1013:1021:1047:3011
+475:4294967295:1000:1006:1013:1021:1047:3011
+476:4294967295:1000:1006:1013:1021:1047:3011
+477:4294967295:1000:1006:1013:1021:1047:3011
+478:4294967295:1000:1006:1013:1021:1047:3011
+479:4294967295:1000:1006:1013:1021:1047:3011
+480:4294967295:1000:1006:1013:1021:1047:3011
+481:4294967295:1000:1006:1013:1021:1047:3011
+482:4294967295:1000:1006:1013:1021:1047:3011
+483:4294967295:1000:1006:1013:1021:1047:3011
+484:4294967295:1000:1006:1013:1021:1047:3011
+485:4294967295:1000:1006:1013:1021:1047:3011
+486:4294967295:1000:1006:1013:1021:1047:3011
+487:4294967295:1000:1006:1013:1021:1047:3011
+488:4294967295:1000:1006:1013:1021:1047:3011
+489:4294967295:1000:1006:1013:1021:1047:3011
+490:4294967295:1000:1006:1013:1021:1047:3011
+491:4294967295:1000:1006:1013:1021:1047:3011
+492:4294967295:1000:1006:1013:1021:1047:3011
+493:4294967295:1000:1006:1013:1021:1047:3011
+494:4294967295:1000:1006:1013:1021:1047:3011
+495:4294967295:1000:1006:1013:1021:1047:3011
+496:4294967295:1000:1006:1013:1021:1047:3011
+497:4294967295:1000:1006:1013:1021:1047:3011
+498:4294967295:1000:1006:1013:1021:1047:3011
+499:4294967295:1000:1006:1013:1021:1047:3011
+500:4294967295:1000:1006:1013:1021:1047:3011
+501:4294967295:1000:1006:1013:1021:1047:3011
+502:4294967295:1000:1006:1013:1021:1047:3011
+503:4294967295:1000:1006:1013:1021:1047:3011
+504:4294967295:1000:1006:1013:1021:1047:3011
+505:4294967295:1000:1006:1013:1021:1047:3011
+506:4294967295:1000:1006:1013:1021:1047:3011
+507:4294967295:1000:1006:1013:1021:1047:3011
+508:4294967295:1000:1006:1013:1021:1047:3011
+509:4294967295:1000:1006:1013:1021:1047:3011
+510:4294967295:1000:1006:1013:1021:1047:3011
+511:4294967295:1000:1006:1013:1021:1047:3011
+/* Allow RCS service to aquire net_raw permission */
+18:4294967295:1001:3004
+/* Allow RCS service to communicate to IMS QMI Priv Svc*/
+77:4294967295:1001:3003
+/* Allow cnd to accquire netbind */
+18:4294967295:1000:3003
+/* Allow QMID service to aquire net_raw permission */
+3:4294967295:1001:1021:3004
+2:4294967295:1000:1001:3004
+42:4294967295:1001:3004
+18:4294967295:1001:3004
+9:4294967295:1001:3004
+1:4294967295:1001:3004:1000
+4:4294967295:1001:3004
+7:4294967295:1001:3004
+8:4294967295:1001:3004:1000
+68:4294967295:1001:3004
+/* DPM */
+47:4294967295:1001:3004
+/* Allow communication to some QMI services with radio privilages */
+/* Format is <Service id>:<all instances>:<radio> */
+/* PBM */
+12:4294967295:1001
+/* WMS */
+5:4294967295:1001
+/* IMS VT */
+32:4294967295:1001
+/* IMSP */
+31:4294967295:1001
+/* PDC */
+36:4294967295:1001
+/* SAR */
+17:4294967295:1001
+/* RFRPE */
+41:4294967295:1001
+/*UIM*/
+11:4294967295:1001
+/*CAT*/
+10:4294967295:1001
+/*IMSA*/
+33:4294967295:1001
+/* CSVT */
+29:4294967295:1001
+/*SERVREG_NOTIF*/
+64:4294967295:1001
+66:4294967295:1001
+/*LTE*/
+70:4294967295:1001
+/* Allow Data dpmd to access QMI DFS */
+48:4294967295:1000:3004
+/* DIAG */
+4097:4294967295:2002:2950:3009:2901
+/* <WLFW QMI Service ID - 0x45>:<WLFW QMI Instance ID - all instances>:<Client Group ID> */
+69:4294967295:1000
+/* <WLPS QMI Service ID - 0x39>:<WLFW QMI Instance ID - all instances>:<Client Group ID> */
+57:4294967295:1000
+/* <MODEM_SVC QMI Service ID - 235>:<MODEM_SVC QMI Instance ID - all instances>:<Client Group ID> */
+235:4294967295:1000
diff --git a/seccomp_policy/mediacodec.policy b/seccomp_policy/mediacodec.policy
new file mode 100644
index 0000000..07b7bf7
--- /dev/null
+++ b/seccomp_policy/mediacodec.policy
@@ -0,0 +1,9 @@
+# device specific syscalls
+pselect6: 1
+eventfd2: 1
+sendto: 1
+recvfrom: 1
+_llseek: 1
+sysinfo: 1
+getcwd: 1
+getdents64: 1
diff --git a/sensors.hals.conf b/sensors.hals.conf
new file mode 100644
index 0000000..5f3a14b
--- /dev/null
+++ b/sensors.hals.conf
@@ -0,0 +1 @@
+sensors.ssc.so
diff --git a/thermal-engine-bramble.conf b/thermal-engine-bramble.conf
new file mode 100644
index 0000000..7dfbf68
--- /dev/null
+++ b/thermal-engine-bramble.conf
@@ -0,0 +1,58 @@
+[SS-SKIN-HIGH-CPU7]
+algo_type		ss
+sampling 		2000
+sensor 			sdm-therm
+device 			cpu7
+set_point 		50000
+set_point_clr 		49000
+device_max_limit 	2131200
+time_constant 		0
+
+[SS-SKIN-MID-CPU7]
+algo_type		ss
+sampling 		2000
+sensor 			sdm-therm
+device 			cpu7
+set_point 		52000
+set_point_clr 		51000
+device_max_limit 	1804800
+time_constant 		0
+
+[SS-SKIN-LOW-CPU7]
+algo_type		ss
+sampling 		2000
+sensor 			sdm-therm
+device 			cpu7
+set_point 		54000
+set_point_clr 		53000
+device_max_limit 	1401600
+time_constant 		0
+
+[HOT-SKIN-VIRTUAL]
+algo_type               virtual
+trip_sensor             sdm-therm
+sensors                 gpuss-0-usr cpuss-0-usr
+list_cnt                2
+weights                 1 -1
+set_point               51000
+set_point_clr           49000
+sampling                1000
+math                    0
+
+[VIRTUAL-SS-GPU-SKIN]
+algo_type               ss
+sensor                  HOT-SKIN-VIRTUAL
+device                  gpu
+sampling                1000
+set_point               8000
+set_point_clr           2000
+device_max_limit        427000000
+
+[SKIN-MONITOR]
+algo_type		monitor
+sampling		1000
+sensor			sdm-therm
+thresholds		56000				58000				100000
+thresholds_clr		54000				56000				99000
+actions			cpu0+cpu7+gpu			cpu0+cpu7+gpu			shutdown
+action_info		940800+1056000+427000000	672000+825600+257000000		1
diff --git a/thermal-engine/thermal_client.h b/thermal-engine/thermal_client.h
new file mode 100644
index 0000000..b41f139
--- /dev/null
+++ b/thermal-engine/thermal_client.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * *    * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cutils/properties.h>
+#ifndef __THERMAL_CLIENT_H__
+#define __THERMAL_CLIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_ACTIONS  (32)
+
+/* Enum for supported fields */
+enum supported_fields {
+	UNKNOWN_FIELD = 0x0,
+	DISABLE_FIELD = 0x1,
+	SAMPLING_FIELD = 0x2,
+	THRESHOLDS_FIELD = 0x4,
+	SET_POINT_FIELD = THRESHOLDS_FIELD,
+	THRESHOLDS_CLR_FIELD = 0x8,
+	SET_POINT_CLR_FIELD = THRESHOLDS_CLR_FIELD,
+	ACTION_INFO_FIELD = 0x10,
+	SUPPORTED_FIELD_MAX = 0x20,
+};
+
+enum field_data_type {
+	FIELD_INT = 0,
+	FIELD_STR,
+	FIELD_INT_ARR,
+	FIELD_ARR_STR,
+	FIELD_ARR_INT_ARR,
+	FIELD_MAX
+};
+
+struct action_info_data {
+	int info[MAX_ACTIONS];
+	uint32_t num_actions;
+};
+
+struct field_data {
+	char *field_name;
+	enum field_data_type data_type;
+	uint32_t num_data;
+	void *data;
+};
+
+struct config_instance {
+	char *cfg_desc;
+	char *algo_type;
+	unsigned int fields_mask;  /* mask set by client to request to adjust supported fields */
+	uint32_t num_fields;
+	struct field_data *fields;
+};
+
+int thermal_client_config_query(char *algo_type, struct config_instance **configs);
+void thermal_client_config_cleanup(struct config_instance *configs, unsigned int config_size);
+int thermal_client_config_set(struct config_instance *configs, unsigned int config_size);
+
+int thermal_client_register_callback(char *client_name, int (*callback)(int , void *, void *), void *data);
+int thermal_client_request(char *client_name, int req_data);
+void thermal_client_unregister_callback(int client_cb_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __THERMAL_CLIENT_H__ */
diff --git a/thermal_info_config_bramble.json b/thermal_info_config_bramble.json
new file mode 100644
index 0000000..59f2d99
--- /dev/null
+++ b/thermal_info_config_bramble.json
@@ -0,0 +1,346 @@
+{
+    "Sensors":[
+        {
+            "Name":"cpu-0-0-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"cpu-0-1-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"cpu-0-2-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"cpu-0-3-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"cpu-1-0-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"cpu-1-1-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"cpu-1-2-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"cpu-1-3-usr",
+            "Type":"CPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"gpuss-0-usr",
+            "Type":"GPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"gpuss-1-usr",
+            "Type":"GPU",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                95.0,
+                "NAN",
+                "NAN",
+                125.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"battery",
+            "Type":"BATTERY",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                60.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"usbc-therm-monitor",
+            "Type":"USB_PORT",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "60.0",
+                "NAN"
+            ],
+            "HotHysteresis":[
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                5.0,
+                0.0
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001,
+            "Monitor":true
+        },
+        {
+            "Name":"sdm-therm-monitor",
+            "Type":"SKIN",
+            "HotThreshold":[
+                "NAN",
+                40.0,
+                44.0,
+                46.0,
+                48.0,
+                61.0,
+                95.0
+            ],
+            "HotHysteresis":[
+                0.0,
+                1.9,
+                1.9,
+                1.9,
+                1.9,
+                1.9,
+                1.9
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001,
+            "Monitor":true
+        },
+        {
+            "Name":"abh-therm",
+            "Type":"UNKNOWN",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN"
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"xo-therm",
+            "Type":"UNKNOWN",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN"
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"rcam-therm",
+            "Type":"UNKNOWN",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN"
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"btn-therm",
+            "Type":"UNKNOWN",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN"
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"qtm-left-therm",
+            "Type":"POWER_AMPLIFIER",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN"
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"chg-therm",
+            "Type":"UNKNOWN",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN"
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        },
+        {
+            "Name":"disp-therm",
+            "Type":"UNKNOWN",
+            "HotThreshold":[
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN",
+                "NAN"
+            ],
+            "VrThreshold":"NAN",
+            "Multiplier":0.001
+        }
+    ],
+    "CoolingDevices":[
+        {
+            "Name":"thermal-cpufreq-0",
+            "Type":"CPU"
+        },
+        {
+            "Name":"thermal-cpufreq-4",
+            "Type":"CPU"
+        },
+        {
+            "Name":"thermal-devfreq-0",
+            "Type":"GPU"
+        },
+        {
+            "Name":"cx",
+            "Type":"COMPONENT"
+        },
+        {
+            "Name":"ebi",
+            "Type":"COMPONENT"
+        }
+    ]
+}
diff --git a/ueventd.rc b/ueventd.rc
new file mode 100644
index 0000000..7433212
--- /dev/null
+++ b/ueventd.rc
@@ -0,0 +1,139 @@
+#
+# 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.
+#
+
+# The modem image is mounted at /vendor/firmware_mnt
+firmware_directories /vendor/firmware_mnt/image/
+
+# the DIAG device node is not world writable/readable.
+/dev/diag                 0660   system     diag
+
+/dev/wlan                 0666   system     system
+/dev/kgsl-3d0             0666   system     system
+/dev/ion                  0664   system     system
+/dev/rtc0                 0660   system     system
+/dev/smd7                 0660   bluetooth  bluetooth
+/dev/ipa                  0660   system     radio
+/dev/wwan_ioctl           0660   system     radio
+/dev/ipaNatTable          0660   system     radio
+/dev/rmnet_ctrl           0660   usb        usb
+/dev/ipa_odl_ctl          0660   radio      radio
+/dev/ipa_adpl             0660   system     oem_2905
+
+#permissions for CSVT
+/dev/smd11                0660   radio      radio
+
+/dev/smdcntl8             0640   radio      radio
+/dev/at_usb0              0640   radio      radio
+/dev/at_mdm0              0640   radio      radio
+
+/dev/video*               0660   system     camera
+/dev/media*               0660   system     camera
+/dev/v4l-subdev*          0660   system     camera
+
+/dev/qseecom              0660   system     drmrpc
+/dev/qsee_ipc_irq_spss    0660   system     drmrpc
+/dev/seemplog             0660   system     system
+/dev/spcom                0660   system     system
+/dev/sp_kernel            0660   system     system
+/dev/sp_ssr               0660   system     system
+/dev/sp_keymaster         0660   system     system
+/dev/sec_nvm_*            0660   system     system
+
+/dev/jpeg0                0660   system     camera
+/dev/adsprpc-smd          0664   system     system
+/dev/adsprpc-smd-secure   0644   system     system
+
+/dev/hw_random            0600   root       root
+/dev/sdsprpc-smd          0660   system     system
+
+/dev/wcd-dsp-glink        0660   system     audio
+/dev/wcd_dsp0_control     0660   system     audio
+/dev/wcd-spi-ac-client    0660   system     audio
+/dev/iaxxx-odsp-celldrv   0660   system     audio
+/dev/tunnel0              0660   system     audio
+
+/dev/msm_qcelp            0660   system     audio
+/dev/msm_evrc             0660   system     audio
+/dev/msm_wma              0660   system     audio
+/dev/msm_wmapro           0660   system     audio
+/dev/msm_alac             0660   system     audio
+/dev/msm_ape              0660   system     audio
+/dev/msm_amrnb            0660   system     audio
+/dev/msm_amrwb            0660   system     audio
+/dev/msm_amrwbplus        0660   system     audio
+/dev/msm_aac              0660   system     audio
+/dev/msm_mp3*             0660   system     audio
+/dev/msm_multi_aac        0660   system     audio
+/dev/msm_aac_in           0660   system     audio
+/dev/msm_qcelp_in         0660   system     audio
+/dev/msm_evrc_in          0660   system     audio
+/dev/msm_amrnb_in         0640   system     audio
+/dev/msm_a2dp_in          0660   system     audio
+/dev/msm_ac3              0660   system     audio
+/dev/msm_audio_cal        0660   system     audio
+/dev/msm_hweffects        0660   system     audio
+/dev/msm_rtac             0660   system     audio
+/dev/msm_cirrus_playback  0660   system     audio
+
+/dev/i2c-5                0660   media      media
+/dev/avtimer              0660   system     audio
+
+/dev/uio0                 0660   system     system
+/dev/uio1                 0660   system     system
+
+# SSR devices
+/dev/subsys_*             0640   system     system
+
+# Ramdump devices
+/dev/ramdump_*            0640   system     system
+
+# Citadel
+/dev/citadel0             0660    hsm         hsm
+
+# Storage: for factory reset protection feature
+/dev/block/platform/soc/1d84000.ufshc/by-name/frp       0660   system     system
+
+# fuel gauge history
+/dev/maxfg_history        0644   system system
+
+# BT
+/dev/ttyMSM0              0600   bluetooth  bluetooth
+/dev/ttyHS0               0660   bluetooth  net_bt
+/dev/btpower              0660   bluetooth  net_bt
+
+# NFC
+/dev/st21nfc              0660   nfc    nfc
+
+#eSE device
+/dev/st54j_se             0660   secure_element secure_element
+
+# Airbrush
+/dev/ab_sm                0600   vendor_airbrush vendor_airbrush
+
+# TPU
+/dev/abc-pcie-tpu_0       0660   system system
+
+# Face Authentication
+/dev/faceauth             0660   system system
+
+# IPU
+/dev/ipu                  0666   cameraserver camera
+
+# AB DRAM
+/dev/ab-dram              0666   cameraserver camera
+
+# ABC PCIE DMA
+/dev/abc-pcie-dma         0666   cameraserver camera
diff --git a/usb/.clang-format b/usb/.clang-format
new file mode 100644
index 0000000..5d8d909
--- /dev/null
+++ b/usb/.clang-format
@@ -0,0 +1,14 @@
+BasedOnStyle: Google
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+ColumnLimit: 99
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Right
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
+AllowShortIfStatementsOnASingleLine: false
+SpacesBeforeTrailingComments: 2
+
diff --git a/usb/Android.bp b/usb/Android.bp
new file mode 100644
index 0000000..0122e0b
--- /dev/null
+++ b/usb/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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_binary {
+    name: "android.hardware.usb@1.2-service.bramble",
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.usb@1.2-service.bramble.rc"],
+    srcs: ["service.cpp", "Usb.cpp", "UsbGadget.cpp"],
+    shared_libs: [
+        "android.hardware.usb@1.0",
+        "android.hardware.usb@1.1",
+        "android.hardware.usb@1.2",
+        "android.hardware.usb.gadget@1.0",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: ["libpixelusb"],
+    proprietary: true,
+}
diff --git a/usb/Usb.cpp b/usb/Usb.cpp
new file mode 100644
index 0000000..f4a5629
--- /dev/null
+++ b/usb/Usb.cpp
@@ -0,0 +1,785 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.usb@1.2-service.bramble"
+
+#include <android-base/logging.h>
+#include <assert.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <chrono>
+#include <regex>
+#include <thread>
+#include <unordered_map>
+
+#include <cutils/uevent.h>
+#include <sys/epoll.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "Usb.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace V1_2 {
+namespace implementation {
+
+// Set by the signal handler to destroy the thread
+volatile bool destroyThread;
+
+constexpr char kEnabledPath[] = "/sys/class/power_supply/usb/moisture_detection_enabled";
+constexpr char kDetectedPath[] = "/sys/class/power_supply/usb/moisture_detected";
+
+void queryVersionHelper(android::hardware::usb::V1_2::implementation::Usb *usb,
+                        hidl_vec<PortStatus> *currentPortStatus_1_2);
+
+int32_t readFile(const std::string &filename, std::string *contents) {
+    FILE *fp;
+    ssize_t read = 0;
+    char *line = NULL;
+    size_t len = 0;
+
+    fp = fopen(filename.c_str(), "r");
+    if (fp != NULL) {
+        if ((read = getline(&line, &len, fp)) != -1) {
+            char *pos;
+            if ((pos = strchr(line, '\n')) != NULL)
+                *pos = '\0';
+            *contents = line;
+        }
+        free(line);
+        fclose(fp);
+        return 0;
+    } else {
+        ALOGE("fopen failed");
+    }
+
+    return -1;
+}
+
+int32_t writeFile(const std::string &filename, const std::string &contents) {
+    FILE *fp;
+    std::string written;
+
+    fp = fopen(filename.c_str(), "w");
+    if (fp != NULL) {
+        // FAILURE RETRY
+        int ret = fputs(contents.c_str(), fp);
+        fclose(fp);
+        if ((ret != EOF) && !readFile(filename, &written) && written == contents)
+            return 0;
+    }
+    return -1;
+}
+
+Status queryMoistureDetectionStatus(hidl_vec<PortStatus> *currentPortStatus_1_2) {
+    std::string enabled, status;
+
+    (*currentPortStatus_1_2)[0].supportedContaminantProtectionModes = 0;
+    (*currentPortStatus_1_2)[0].supportedContaminantProtectionModes |=
+        ContaminantProtectionMode::FORCE_SINK;
+    (*currentPortStatus_1_2)[0].contaminantProtectionStatus = ContaminantProtectionStatus::NONE;
+    (*currentPortStatus_1_2)[0].contaminantDetectionStatus = ContaminantDetectionStatus::DISABLED;
+    (*currentPortStatus_1_2)[0].supportsEnableContaminantPresenceDetection = true;
+    (*currentPortStatus_1_2)[0].supportsEnableContaminantPresenceProtection = false;
+
+    if (readFile(kEnabledPath, &enabled)) {
+        ALOGE("Failed to open moisture_detection_enabled");
+        return Status::ERROR;
+    }
+
+    if (enabled == "1") {
+        if (readFile(kDetectedPath, &status)) {
+            ALOGE("Failed to open moisture_detected");
+            return Status::ERROR;
+        }
+        if (status == "1") {
+            (*currentPortStatus_1_2)[0].contaminantDetectionStatus =
+                ContaminantDetectionStatus::DETECTED;
+            (*currentPortStatus_1_2)[0].contaminantProtectionStatus =
+                ContaminantProtectionStatus::FORCE_SINK;
+        } else
+            (*currentPortStatus_1_2)[0].contaminantDetectionStatus =
+                ContaminantDetectionStatus::NOT_DETECTED;
+    }
+
+     ALOGI("ContaminantDetectionStatus:%d ContaminantProtectionStatus:%d",
+	   (*currentPortStatus_1_2)[0].contaminantDetectionStatus,
+	   (*currentPortStatus_1_2)[0].contaminantProtectionStatus);
+
+    return Status::SUCCESS;
+}
+
+Return<void> Usb::enableContaminantPresenceDetection(const hidl_string & /*portName*/,
+                                                     bool enable) {
+    writeFile(kEnabledPath, enable ? "1" : "0");
+    hidl_vec<PortStatus> currentPortStatus_1_2;
+
+    queryVersionHelper(this, &currentPortStatus_1_2);
+    return Void();
+}
+
+Return<void> Usb::enableContaminantPresenceProtection(const hidl_string & /*portName*/,
+                                                      bool /*enable*/) {
+    hidl_vec<PortStatus> currentPortStatus_1_2;
+
+    queryVersionHelper(this, &currentPortStatus_1_2);
+    return Void();
+}
+
+std::string appendRoleNodeHelper(const std::string &portName, PortRoleType type) {
+    std::string node("/sys/class/typec/" + portName);
+
+    switch (type) {
+        case PortRoleType::DATA_ROLE:
+            return node + "/data_role";
+        case PortRoleType::POWER_ROLE:
+            return node + "/power_role";
+        case PortRoleType::MODE:
+            return node + "/port_type";
+        default:
+            return "";
+    }
+}
+
+std::string convertRoletoString(PortRole role) {
+    if (role.type == PortRoleType::POWER_ROLE) {
+        if (role.role == static_cast<uint32_t>(PortPowerRole::SOURCE))
+            return "source";
+        else if (role.role == static_cast<uint32_t>(PortPowerRole::SINK))
+            return "sink";
+    } else if (role.type == PortRoleType::DATA_ROLE) {
+        if (role.role == static_cast<uint32_t>(PortDataRole::HOST))
+            return "host";
+        if (role.role == static_cast<uint32_t>(PortDataRole::DEVICE))
+            return "device";
+    } else if (role.type == PortRoleType::MODE) {
+        if (role.role == static_cast<uint32_t>(PortMode_1_1::UFP))
+            return "sink";
+        if (role.role == static_cast<uint32_t>(PortMode_1_1::DFP))
+            return "source";
+    }
+    return "none";
+}
+
+void extractRole(std::string *roleName) {
+    std::size_t first, last;
+
+    first = roleName->find("[");
+    last = roleName->find("]");
+
+    if (first != std::string::npos && last != std::string::npos) {
+        *roleName = roleName->substr(first + 1, last - first - 1);
+    }
+}
+
+void switchToDrp(const std::string &portName) {
+    std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), PortRoleType::MODE);
+    FILE *fp;
+
+    if (filename != "") {
+        fp = fopen(filename.c_str(), "w");
+        if (fp != NULL) {
+            int ret = fputs("dual", fp);
+            fclose(fp);
+            if (ret == EOF)
+                ALOGE("Fatal: Error while switching back to drp");
+        } else {
+            ALOGE("Fatal: Cannot open file to switch back to drp");
+        }
+    } else {
+        ALOGE("Fatal: invalid node type");
+    }
+}
+
+bool switchMode(const hidl_string &portName, const PortRole &newRole, struct Usb *usb) {
+    std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
+    std::string written;
+    FILE *fp;
+    bool roleSwitch = false;
+
+    if (filename == "") {
+        ALOGE("Fatal: invalid node type");
+        return false;
+    }
+
+    fp = fopen(filename.c_str(), "w");
+    if (fp != NULL) {
+        // Hold the lock here to prevent loosing connected signals
+        // as once the file is written the partner added signal
+        // can arrive anytime.
+        pthread_mutex_lock(&usb->mPartnerLock);
+        usb->mPartnerUp = false;
+        int ret = fputs(convertRoletoString(newRole).c_str(), fp);
+        fclose(fp);
+
+        if (ret != EOF) {
+            struct timespec to;
+            struct timespec now;
+
+        wait_again:
+            clock_gettime(CLOCK_MONOTONIC, &now);
+            to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
+            to.tv_nsec = now.tv_nsec;
+
+            int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
+            // There are no uevent signals which implies role swap timed out.
+            if (err == ETIMEDOUT) {
+                ALOGI("uevents wait timedout");
+                // Sanity check.
+            } else if (!usb->mPartnerUp) {
+                goto wait_again;
+                // Role switch succeeded since usb->mPartnerUp is true.
+            } else {
+                roleSwitch = true;
+            }
+        } else {
+            ALOGI("Role switch failed while wrting to file");
+        }
+        pthread_mutex_unlock(&usb->mPartnerLock);
+    }
+
+    if (!roleSwitch)
+        switchToDrp(std::string(portName.c_str()));
+
+    return roleSwitch;
+}
+
+Usb::Usb()
+    : mLock(PTHREAD_MUTEX_INITIALIZER),
+      mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
+      mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
+      mPartnerUp(false) {
+    pthread_condattr_t attr;
+    if (pthread_condattr_init(&attr)) {
+        ALOGE("pthread_condattr_init failed: %s", strerror(errno));
+        abort();
+    }
+    if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
+        ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
+        abort();
+    }
+    if (pthread_cond_init(&mPartnerCV, &attr)) {
+        ALOGE("pthread_cond_init failed: %s", strerror(errno));
+        abort();
+    }
+    if (pthread_condattr_destroy(&attr)) {
+        ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
+        abort();
+    }
+}
+
+Return<void> Usb::switchRole(const hidl_string &portName, const V1_0::PortRole &newRole) {
+    std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
+    std::string written;
+    FILE *fp;
+    bool roleSwitch = false;
+
+    if (filename == "") {
+        ALOGE("Fatal: invalid node type");
+        return Void();
+    }
+
+    pthread_mutex_lock(&mRoleSwitchLock);
+
+    ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(newRole).c_str());
+
+    if (newRole.type == PortRoleType::MODE) {
+        roleSwitch = switchMode(portName, newRole, this);
+    } else {
+        fp = fopen(filename.c_str(), "w");
+        if (fp != NULL) {
+            int ret = fputs(convertRoletoString(newRole).c_str(), fp);
+            fclose(fp);
+            if ((ret != EOF) && !readFile(filename, &written)) {
+                extractRole(&written);
+                ALOGI("written: %s", written.c_str());
+                if (written == convertRoletoString(newRole)) {
+                    roleSwitch = true;
+                } else {
+                    ALOGE("Role switch failed");
+                }
+            } else {
+                ALOGE("failed to update the new role");
+            }
+        } else {
+            ALOGE("fopen failed");
+        }
+    }
+
+    pthread_mutex_lock(&mLock);
+    if (mCallback_1_0 != NULL) {
+        Return<void> ret = mCallback_1_0->notifyRoleSwitchStatus(
+            portName, newRole, roleSwitch ? Status::SUCCESS : Status::ERROR);
+        if (!ret.isOk())
+            ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
+    } else {
+        ALOGE("Not notifying the userspace. Callback is not set");
+    }
+    pthread_mutex_unlock(&mLock);
+    pthread_mutex_unlock(&mRoleSwitchLock);
+
+    return Void();
+}
+
+Status getAccessoryConnected(const std::string &portName, std::string *accessory) {
+    std::string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
+
+    if (readFile(filename, accessory)) {
+        ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
+        return Status::ERROR;
+    }
+
+    return Status::SUCCESS;
+}
+
+Status getCurrentRoleHelper(const std::string &portName, bool connected, PortRoleType type,
+                            uint32_t *currentRole) {
+    std::string filename;
+    std::string roleName;
+    std::string accessory;
+
+    // Mode
+
+    if (type == PortRoleType::POWER_ROLE) {
+        filename = "/sys/class/typec/" + portName + "/power_role";
+        *currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
+    } else if (type == PortRoleType::DATA_ROLE) {
+        filename = "/sys/class/typec/" + portName + "/data_role";
+        *currentRole = static_cast<uint32_t>(PortDataRole::NONE);
+    } else if (type == PortRoleType::MODE) {
+        filename = "/sys/class/typec/" + portName + "/data_role";
+        *currentRole = static_cast<uint32_t>(PortMode_1_1::NONE);
+    } else {
+        return Status::ERROR;
+    }
+
+    if (!connected)
+        return Status::SUCCESS;
+
+    if (type == PortRoleType::MODE) {
+        if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
+            return Status::ERROR;
+        }
+        if (accessory == "analog_audio") {
+            *currentRole = static_cast<uint32_t>(PortMode_1_1::AUDIO_ACCESSORY);
+            return Status::SUCCESS;
+        } else if (accessory == "debug") {
+            *currentRole = static_cast<uint32_t>(PortMode_1_1::DEBUG_ACCESSORY);
+            return Status::SUCCESS;
+        }
+    }
+
+    if (readFile(filename, &roleName)) {
+        ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
+        return Status::ERROR;
+    }
+
+    extractRole(&roleName);
+
+    if (roleName == "source") {
+        *currentRole = static_cast<uint32_t>(PortPowerRole::SOURCE);
+    } else if (roleName == "sink") {
+        *currentRole = static_cast<uint32_t>(PortPowerRole::SINK);
+    } else if (roleName == "host") {
+        if (type == PortRoleType::DATA_ROLE)
+            *currentRole = static_cast<uint32_t>(PortDataRole::HOST);
+        else
+            *currentRole = static_cast<uint32_t>(PortMode_1_1::DFP);
+    } else if (roleName == "device") {
+        if (type == PortRoleType::DATA_ROLE)
+            *currentRole = static_cast<uint32_t>(PortDataRole::DEVICE);
+        else
+            *currentRole = static_cast<uint32_t>(PortMode_1_1::UFP);
+    } else if (roleName != "none") {
+        /* case for none has already been addressed.
+         * so we check if the role isnt none.
+         */
+        return Status::UNRECOGNIZED_ROLE;
+    }
+
+    return Status::SUCCESS;
+}
+
+Status getTypeCPortNamesHelper(std::unordered_map<std::string, bool> *names) {
+    DIR *dp;
+
+    dp = opendir("/sys/class/typec");
+    if (dp != NULL) {
+        struct dirent *ep;
+
+        while ((ep = readdir(dp))) {
+            if (ep->d_type == DT_LNK) {
+                if (std::string::npos == std::string(ep->d_name).find("-partner")) {
+                    std::unordered_map<std::string, bool>::const_iterator portName =
+                        names->find(ep->d_name);
+                    if (portName == names->end()) {
+                        names->insert({ep->d_name, false});
+                    }
+                } else {
+                    (*names)[std::strtok(ep->d_name, "-")] = true;
+                }
+            }
+        }
+        closedir(dp);
+        return Status::SUCCESS;
+    }
+
+    ALOGE("Failed to open /sys/class/typec");
+    return Status::ERROR;
+}
+
+bool canSwitchRoleHelper(const std::string &portName, PortRoleType /*type*/) {
+    std::string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
+    std::string supportsPD;
+
+    if (!readFile(filename, &supportsPD)) {
+        if (supportsPD == "yes") {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/*
+ * Reuse the same method for both V1_0 and V1_1 callback objects.
+ * The caller of this method would reconstruct the V1_0::PortStatus
+ * object if required.
+ */
+Status getPortStatusHelper(hidl_vec<PortStatus> *currentPortStatus_1_2, HALVersion version) {
+    std::unordered_map<std::string, bool> names;
+    Status result = getTypeCPortNamesHelper(&names);
+    int i = -1;
+
+    if (result == Status::SUCCESS) {
+        currentPortStatus_1_2->resize(names.size());
+        for (std::pair<std::string, bool> port : names) {
+            i++;
+            ALOGI("%s", port.first.c_str());
+            (*currentPortStatus_1_2)[i].status_1_1.status.portName = port.first;
+
+            uint32_t currentRole;
+            if (getCurrentRoleHelper(port.first, port.second, PortRoleType::POWER_ROLE,
+                                     &currentRole) == Status::SUCCESS) {
+                (*currentPortStatus_1_2)[i].status_1_1.status.currentPowerRole =
+                    static_cast<PortPowerRole>(currentRole);
+            } else {
+                ALOGE("Error while retreiving portNames");
+                goto done;
+            }
+
+            if (getCurrentRoleHelper(port.first, port.second, PortRoleType::DATA_ROLE,
+                                     &currentRole) == Status::SUCCESS) {
+                (*currentPortStatus_1_2)[i].status_1_1.status.currentDataRole =
+                    static_cast<PortDataRole>(currentRole);
+            } else {
+                ALOGE("Error while retreiving current port role");
+                goto done;
+            }
+
+            if (getCurrentRoleHelper(port.first, port.second, PortRoleType::MODE, &currentRole) ==
+                Status::SUCCESS) {
+                (*currentPortStatus_1_2)[i].status_1_1.currentMode =
+                    static_cast<PortMode_1_1>(currentRole);
+                (*currentPortStatus_1_2)[i].status_1_1.status.currentMode =
+                    static_cast<V1_0::PortMode>(currentRole);
+            } else {
+                ALOGE("Error while retreiving current data role");
+                goto done;
+            }
+
+            (*currentPortStatus_1_2)[i].status_1_1.status.canChangeMode = true;
+            (*currentPortStatus_1_2)[i].status_1_1.status.canChangeDataRole =
+                port.second ? canSwitchRoleHelper(port.first, PortRoleType::DATA_ROLE) : false;
+            (*currentPortStatus_1_2)[i].status_1_1.status.canChangePowerRole =
+                port.second ? canSwitchRoleHelper(port.first, PortRoleType::POWER_ROLE) : false;
+
+            if (version == HALVersion::V1_0) {
+                ALOGI("HAL version V1_0");
+                (*currentPortStatus_1_2)[i].status_1_1.status.supportedModes = V1_0::PortMode::DRP;
+            } else {
+		if (version == HALVersion::V1_1)
+                    ALOGI("HAL version V1_1");
+		else
+                    ALOGI("HAL version V1_2");
+                (*currentPortStatus_1_2)[i].status_1_1.supportedModes = 0 | PortMode_1_1::DRP;
+                (*currentPortStatus_1_2)[i].status_1_1.status.supportedModes = V1_0::PortMode::NONE;
+                (*currentPortStatus_1_2)[i].status_1_1.status.currentMode = V1_0::PortMode::NONE;
+            }
+
+            ALOGI(
+                "%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
+                "supportedModes:%d",
+                i, port.first.c_str(), port.second,
+                (*currentPortStatus_1_2)[i].status_1_1.status.canChangeMode,
+                (*currentPortStatus_1_2)[i].status_1_1.status.canChangeDataRole,
+                (*currentPortStatus_1_2)[i].status_1_1.status.canChangePowerRole,
+                (*currentPortStatus_1_2)[i].status_1_1.supportedModes);
+        }
+        return Status::SUCCESS;
+    }
+done:
+    return Status::ERROR;
+}
+
+void queryVersionHelper(android::hardware::usb::V1_2::implementation::Usb *usb,
+                        hidl_vec<PortStatus> *currentPortStatus_1_2) {
+    hidl_vec<V1_1::PortStatus_1_1> currentPortStatus_1_1;
+    hidl_vec<V1_0::PortStatus> currentPortStatus;
+    Status status;
+    sp<V1_1::IUsbCallback> callback_V1_1 = V1_1::IUsbCallback::castFrom(usb->mCallback_1_0);
+    sp<IUsbCallback> callback_V1_2 = IUsbCallback::castFrom(usb->mCallback_1_0);
+
+    pthread_mutex_lock(&usb->mLock);
+    if (usb->mCallback_1_0 != NULL) {
+        if (callback_V1_2 != NULL) {
+            status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_2);
+            queryMoistureDetectionStatus(currentPortStatus_1_2);
+        } else if (callback_V1_1 != NULL) {
+            status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_1);
+            currentPortStatus_1_1.resize(currentPortStatus_1_2->size());
+            for (unsigned long i = 0; i < currentPortStatus_1_2->size(); i++)
+                currentPortStatus_1_1[i] = (*currentPortStatus_1_2)[i].status_1_1;
+        } else {
+            status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_0);
+            currentPortStatus.resize(currentPortStatus_1_2->size());
+            for (unsigned long i = 0; i < currentPortStatus_1_2->size(); i++)
+                currentPortStatus[i] = (*currentPortStatus_1_2)[i].status_1_1.status;
+        }
+
+        Return<void> ret;
+
+        if (callback_V1_2 != NULL)
+            ret = callback_V1_2->notifyPortStatusChange_1_2(*currentPortStatus_1_2, status);
+        else if (callback_V1_1 != NULL)
+            ret = callback_V1_1->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
+        else
+            ret = usb->mCallback_1_0->notifyPortStatusChange(currentPortStatus, status);
+
+        if (!ret.isOk())
+            ALOGE("queryPortStatus_1_2 error %s", ret.description().c_str());
+    } else {
+        ALOGI("Notifying userspace skipped. Callback is NULL");
+    }
+    pthread_mutex_unlock(&usb->mLock);
+}
+
+Return<void> Usb::queryPortStatus() {
+    hidl_vec<PortStatus> currentPortStatus_1_2;
+
+    queryVersionHelper(this, &currentPortStatus_1_2);
+    return Void();
+}
+
+struct data {
+    int uevent_fd;
+    android::hardware::usb::V1_2::implementation::Usb *usb;
+};
+
+static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
+    char msg[UEVENT_MSG_LEN + 2];
+    char *cp;
+    int n;
+
+    n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
+    if (n <= 0)
+        return;
+    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+        return;
+
+    msg[n] = '\0';
+    msg[n + 1] = '\0';
+    cp = msg;
+
+    while (*cp) {
+        if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
+            ALOGI("partner added");
+            pthread_mutex_lock(&payload->usb->mPartnerLock);
+            payload->usb->mPartnerUp = true;
+            pthread_cond_signal(&payload->usb->mPartnerCV);
+            pthread_mutex_unlock(&payload->usb->mPartnerLock);
+        } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
+                   !strncmp(cp, "POWER_SUPPLY_MOISTURE_DETECTED",
+                            strlen("POWER_SUPPLY_MOISTURE_DETECTED"))) {
+            hidl_vec<PortStatus> currentPortStatus_1_2;
+            queryVersionHelper(payload->usb, &currentPortStatus_1_2);
+
+            // Role switch is not in progress and port is in disconnected state
+            if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
+                for (unsigned long i = 0; i < currentPortStatus_1_2.size(); i++) {
+                    DIR *dp =
+                        opendir(std::string("/sys/class/typec/" +
+                                            std::string(currentPortStatus_1_2[i]
+                                                            .status_1_1.status.portName.c_str()) +
+                                            "-partner")
+                                    .c_str());
+                    if (dp == NULL) {
+                        // PortRole role = {.role = static_cast<uint32_t>(PortMode::UFP)};
+                        switchToDrp(currentPortStatus_1_2[i].status_1_1.status.portName);
+                    } else {
+                        closedir(dp);
+                    }
+                }
+                pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
+            }
+            break;
+        }
+        /* advance to after the next \0 */
+        while (*cp++) {
+        }
+    }
+}
+
+void *work(void *param) {
+    int epoll_fd, uevent_fd;
+    struct epoll_event ev;
+    int nevents = 0;
+    struct data payload;
+
+    ALOGE("creating thread");
+
+    uevent_fd = uevent_open_socket(64 * 1024, true);
+
+    if (uevent_fd < 0) {
+        ALOGE("uevent_init: uevent_open_socket failed\n");
+        return NULL;
+    }
+
+    payload.uevent_fd = uevent_fd;
+    payload.usb = (android::hardware::usb::V1_2::implementation::Usb *)param;
+
+    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+
+    ev.events = EPOLLIN;
+    ev.data.ptr = (void *)uevent_event;
+
+    epoll_fd = epoll_create(64);
+    if (epoll_fd == -1) {
+        ALOGE("epoll_create failed; errno=%d", errno);
+        goto error;
+    }
+
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
+        ALOGE("epoll_ctl failed; errno=%d", errno);
+        goto error;
+    }
+
+    while (!destroyThread) {
+        struct epoll_event events[64];
+
+        nevents = epoll_wait(epoll_fd, events, 64, -1);
+        if (nevents == -1) {
+            if (errno == EINTR)
+                continue;
+            ALOGE("usb epoll_wait failed; errno=%d", errno);
+            break;
+        }
+
+        for (int n = 0; n < nevents; ++n) {
+            if (events[n].data.ptr)
+                (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
+                                                                           &payload);
+        }
+    }
+
+    ALOGI("exiting worker thread");
+error:
+    close(uevent_fd);
+
+    if (epoll_fd >= 0)
+        close(epoll_fd);
+
+    return NULL;
+}
+
+void sighandler(int sig) {
+    if (sig == SIGUSR1) {
+        destroyThread = true;
+        ALOGI("destroy set");
+        return;
+    }
+    signal(SIGUSR1, sighandler);
+}
+
+Return<void> Usb::setCallback(const sp<V1_0::IUsbCallback> &callback) {
+    sp<V1_1::IUsbCallback> callback_V1_1 = V1_1::IUsbCallback::castFrom(callback);
+    sp<IUsbCallback> callback_V1_2 = IUsbCallback::castFrom(callback);
+
+    if (callback != NULL) {
+        if (callback_V1_2 != NULL)
+            ALOGI("Registering 1.2 callback");
+        else if (callback_V1_1 != NULL)
+            ALOGI("Registering 1.1 callback");
+    }
+
+    pthread_mutex_lock(&mLock);
+    /*
+     * When both the old callback and new callback values are NULL,
+     * there is no need to spin off the worker thread.
+     * When both the values are not NULL, we would already have a
+     * worker thread running, so updating the callback object would
+     * be suffice.
+     */
+    if ((mCallback_1_0 == NULL && callback == NULL) ||
+        (mCallback_1_0 != NULL && callback != NULL)) {
+        /*
+         * Always store as V1_0 callback object. Type cast to V1_1
+         * when the callback is actually invoked.
+         */
+        mCallback_1_0 = callback;
+        pthread_mutex_unlock(&mLock);
+        return Void();
+    }
+
+    mCallback_1_0 = callback;
+    ALOGI("registering callback");
+
+    // Kill the worker thread if the new callback is NULL.
+    if (mCallback_1_0 == NULL) {
+        pthread_mutex_unlock(&mLock);
+        if (!pthread_kill(mPoll, SIGUSR1)) {
+            pthread_join(mPoll, NULL);
+            ALOGI("pthread destroyed");
+        }
+        return Void();
+    }
+
+    destroyThread = false;
+    signal(SIGUSR1, sighandler);
+
+    /*
+     * Create a background thread if the old callback value is NULL
+     * and being updated with a new value.
+     */
+    if (pthread_create(&mPoll, NULL, work, this)) {
+        ALOGE("pthread creation failed %d", errno);
+        mCallback_1_0 = NULL;
+    }
+
+    pthread_mutex_unlock(&mLock);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
diff --git a/usb/Usb.h b/usb/Usb.h
new file mode 100644
index 0000000..65be180
--- /dev/null
+++ b/usb/Usb.h
@@ -0,0 +1,81 @@
+#ifndef ANDROID_HARDWARE_USB_V1_1_USB_H
+#define ANDROID_HARDWARE_USB_V1_1_USB_H
+
+#include <android/hardware/usb/1.2/IUsb.h>
+#include <android/hardware/usb/1.2/IUsbCallback.h>
+#include <android/hardware/usb/1.2/types.h>
+#include <hidl/Status.h>
+#include <utils/Log.h>
+
+#define UEVENT_MSG_LEN 2048
+// The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd.
+// The -partner directory would not be created until this is done.
+// Having a margin of ~3 secs for the directory and other related bookeeping
+// structures created and uvent fired.
+#define PORT_TYPE_TIMEOUT 8
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::usb::V1_0::PortDataRole;
+using ::android::hardware::usb::V1_0::PortPowerRole;
+using ::android::hardware::usb::V1_0::PortRole;
+using ::android::hardware::usb::V1_0::PortRoleType;
+using ::android::hardware::usb::V1_0::Status;
+using ::android::hardware::usb::V1_2::IUsb;
+using ::android::hardware::usb::V1_2::IUsbCallback;
+
+using ::android::hardware::usb::V1_1::PortMode_1_1;
+using ::android::hardware::usb::V1_1::PortStatus_1_1;
+using ::android::hardware::usb::V1_2::PortStatus;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
+
+enum class HALVersion{
+    V1_0,
+    V1_1,
+    V1_2
+};
+
+struct Usb : public IUsb {
+    Usb();
+
+    Return<void> switchRole(const hidl_string &portName, const V1_0::PortRole &role) override;
+    Return<void> setCallback(const sp<V1_0::IUsbCallback> &callback) override;
+    Return<void> queryPortStatus() override;
+    Return<void> enableContaminantPresenceDetection(const hidl_string& portName, bool enable);
+    Return<void> enableContaminantPresenceProtection(const hidl_string& portName, bool enable);
+
+    sp<V1_0::IUsbCallback> mCallback_1_0;
+    // Protects mCallback variable
+    pthread_mutex_t mLock;
+    // Protects roleSwitch operation
+    pthread_mutex_t mRoleSwitchLock;
+    // Threads waiting for the partner to come back wait here
+    pthread_cond_t mPartnerCV;
+    // lock protecting mPartnerCV
+    pthread_mutex_t mPartnerLock;
+    // Variable to signal partner coming back online after type switch
+    bool mPartnerUp;
+
+  private:
+    pthread_t mPoll;
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_USB_V1_2_USB_H
diff --git a/usb/UsbGadget.cpp b/usb/UsbGadget.cpp
new file mode 100644
index 0000000..a49e67d
--- /dev/null
+++ b/usb/UsbGadget.cpp
@@ -0,0 +1,344 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.usb.gadget@1.0-service.bramble"
+
+#include "UsbGadget.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_0 {
+namespace implementation {
+
+UsbGadget::UsbGadget() {
+    if (access(OS_DESC_PATH, R_OK) != 0) {
+        ALOGE("configfs setup not done yet");
+        abort();
+    }
+}
+
+void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
+    UsbGadget *gadget = (UsbGadget *)payload;
+    gadget->mCurrentUsbFunctionsApplied = functionsApplied;
+}
+
+Return<void> UsbGadget::getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback> &callback) {
+    Return<void> ret = callback->getCurrentUsbFunctionsCb(
+        mCurrentUsbFunctions,
+        mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED);
+    if (!ret.isOk())
+        ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str());
+
+    return Void();
+}
+
+V1_0::Status UsbGadget::tearDownGadget() {
+    if (resetGadget() != Status::SUCCESS)
+        return Status::ERROR;
+
+    if (monitorFfs.isMonitorRunning()) {
+        monitorFfs.reset();
+    } else {
+        ALOGI("mMonitor not running");
+    }
+    return Status::SUCCESS;
+}
+
+static V1_0::Status validateAndSetVidPid(uint64_t functions) {
+    V1_0::Status ret = Status::SUCCESS;
+    std::string vendorFunctions = getVendorFunctions();
+
+    switch (functions) {
+        case static_cast<uint64_t>(GadgetFunction::MTP):
+            if (vendorFunctions == "diag") {
+                ret = setVidPid("0x05C6", "0x901B");
+            } else {
+                if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                    ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                    ret = Status::CONFIGURATION_NOT_SUPPORTED;
+                } else {
+                    ret = setVidPid("0x18d1", "0x4ee1");
+                }
+            }
+            break;
+        case GadgetFunction::ADB | GadgetFunction::MTP:
+            if (vendorFunctions == "diag") {
+                ret = setVidPid("0x05C6", "0x903A");
+            } else {
+                if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                    ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                    ret = Status::CONFIGURATION_NOT_SUPPORTED;
+                } else {
+                    ret = setVidPid("0x18d1", "0x4ee2");
+                }
+            }
+            break;
+        case static_cast<uint64_t>(GadgetFunction::RNDIS):
+            if (vendorFunctions == "diag") {
+                ret = setVidPid("0x05C6", "0x902C");
+            } else if (vendorFunctions == "serial_cdev,diag") {
+                ret = setVidPid("0x05C6", "0x90B5");
+            } else if (vendorFunctions == "diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl_gsi") {
+                ret = setVidPid("0x05C6", "0x90E6");
+            } else {
+                if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                    ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                    ret = Status::CONFIGURATION_NOT_SUPPORTED;
+                } else {
+                    ret = setVidPid("0x18d1", "0x4ee3");
+                }
+            }
+            break;
+        case GadgetFunction::ADB | GadgetFunction::RNDIS:
+            if (vendorFunctions == "diag") {
+                ret = setVidPid("0x05C6", "0x902D");
+            } else if (vendorFunctions == "serial_cdev,diag") {
+                ret = setVidPid("0x05C6", "0x90B6");
+            } else if (vendorFunctions == "diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl_gsi") {
+                ret = setVidPid("0x05C6", "0x90E7");
+            } else {
+                if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                    ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                    ret = Status::CONFIGURATION_NOT_SUPPORTED;
+                } else {
+                    ret = setVidPid("0x18d1", "0x4ee4");
+                }
+            }
+            break;
+        case static_cast<uint64_t>(GadgetFunction::PTP):
+            if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                ret = Status::CONFIGURATION_NOT_SUPPORTED;
+            } else {
+                ret = setVidPid("0x18d1", "0x4ee5");
+            }
+            break;
+        case GadgetFunction::ADB | GadgetFunction::PTP:
+            if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                ret = Status::CONFIGURATION_NOT_SUPPORTED;
+            } else {
+                ret = setVidPid("0x18d1", "0x4ee6");
+            }
+            break;
+        case static_cast<uint64_t>(GadgetFunction::ADB):
+            if (vendorFunctions == "diag") {
+                ret = setVidPid("0x05C6", "0x901D");
+            } else if (vendorFunctions == "diag,serial_cdev,rmnet_gsi") {
+                ret = setVidPid("0x05C6", "0x9091");
+            } else if (vendorFunctions == "diag,serial_cdev") {
+                ret = setVidPid("0x05C6", "0x901F");
+            } else if (vendorFunctions ==
+                       "diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl_gsi,rmnet_gsi") {
+                ret = setVidPid("0x05C6", "0x90E5");
+            } else {
+                if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                    ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                    ret = Status::CONFIGURATION_NOT_SUPPORTED;
+                } else {
+                    ret = setVidPid("0x18d1", "0x4ee7");
+                }
+            }
+            break;
+        case static_cast<uint64_t>(GadgetFunction::MIDI):
+            if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                ret = Status::CONFIGURATION_NOT_SUPPORTED;
+            } else {
+                ret = setVidPid("0x18d1", "0x4ee8");
+            }
+            break;
+        case GadgetFunction::ADB | GadgetFunction::MIDI:
+            if (!(vendorFunctions == "user" || vendorFunctions == "")) {
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+                ret = Status::CONFIGURATION_NOT_SUPPORTED;
+            } else {
+                ret = setVidPid("0x18d1", "0x4ee9");
+            }
+            break;
+        case static_cast<uint64_t>(GadgetFunction::ACCESSORY):
+            if (!(vendorFunctions == "user" || vendorFunctions == ""))
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+            ret = setVidPid("0x18d1", "0x2d00");
+            break;
+        case GadgetFunction::ADB | GadgetFunction::ACCESSORY:
+            if (!(vendorFunctions == "user" || vendorFunctions == ""))
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+            ret = setVidPid("0x18d1", "0x2d01");
+            break;
+        case static_cast<uint64_t>(GadgetFunction::AUDIO_SOURCE):
+            if (!(vendorFunctions == "user" || vendorFunctions == ""))
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+            ret = setVidPid("0x18d1", "0x2d02");
+            break;
+        case GadgetFunction::ADB | GadgetFunction::AUDIO_SOURCE:
+            if (!(vendorFunctions == "user" || vendorFunctions == ""))
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+            ret = setVidPid("0x18d1", "0x2d03");
+            break;
+        case GadgetFunction::ACCESSORY | GadgetFunction::AUDIO_SOURCE:
+            if (!(vendorFunctions == "user" || vendorFunctions == ""))
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+            ret = setVidPid("0x18d1", "0x2d04");
+            break;
+        case GadgetFunction::ADB | GadgetFunction::ACCESSORY | GadgetFunction::AUDIO_SOURCE:
+            if (!(vendorFunctions == "user" || vendorFunctions == ""))
+                ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
+            ret = setVidPid("0x18d1", "0x2d05");
+            break;
+        default:
+            ALOGE("Combination not supported");
+            ret = Status::CONFIGURATION_NOT_SUPPORTED;
+    }
+    return ret;
+}
+
+V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
+                                       const sp<V1_0::IUsbGadgetCallback> &callback,
+                                       uint64_t timeout) {
+    bool ffsEnabled = false;
+    int i = 0;
+
+    if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) != Status::SUCCESS)
+        return Status::ERROR;
+
+    std::string vendorFunctions = getVendorFunctions();
+
+    if (vendorFunctions != "") {
+        ALOGI("enable usbradio debug functions");
+        char *function = strtok(const_cast<char *>(vendorFunctions.c_str()), ",");
+        while (function != NULL) {
+            if (string(function) == "diag" && linkFunction("diag.diag", i++))
+                return Status::ERROR;
+            if (string(function) == "diag_mdm" && linkFunction("diag.diag_mdm", i++))
+                return Status::ERROR;
+            if (string(function) == "qdss" && linkFunction("qdss.qdss", i++))
+                return Status::ERROR;
+            if (string(function) == "qdss_mdm" && linkFunction("qdss.qdss_mdm", i++))
+                return Status::ERROR;
+            if (string(function) == "serial_cdev" && linkFunction("cser.dun.0", i++))
+                return Status::ERROR;
+            if (string(function) == "dpl_gsi" && linkFunction("gsi.dpl", i++))
+                return Status::ERROR;
+            if (string(function) == "rmnet_gsi" && linkFunction("gsi.rmnet", i++))
+                return Status::ERROR;
+            function = strtok(NULL, ",");
+        }
+    }
+
+    if ((functions & GadgetFunction::ADB) != 0) {
+        ffsEnabled = true;
+        if (addAdb(&monitorFfs, &i) != Status::SUCCESS)
+            return Status::ERROR;
+    }
+
+    // Pull up the gadget right away when there are no ffs functions.
+    if (!ffsEnabled) {
+        if (!WriteStringToFile(kGadgetName, PULLUP_PATH))
+            return Status::ERROR;
+        mCurrentUsbFunctionsApplied = true;
+        if (callback)
+            callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS);
+        return Status::SUCCESS;
+    }
+
+    monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
+    // Monitors the ffs paths to pull up the gadget when descriptors are written.
+    // Also takes of the pulling up the gadget again if the userspace process
+    // dies and restarts.
+    monitorFfs.startMonitor();
+
+    if (kDebug)
+        ALOGI("Mainthread in Cv");
+
+    if (callback) {
+        bool pullup = monitorFfs.waitForPullUp(timeout);
+        Return<void> ret = callback->setCurrentUsbFunctionsCb(
+            functions, pullup ? Status::SUCCESS : Status::ERROR);
+        if (!ret.isOk())
+            ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
+    }
+
+    return Status::SUCCESS;
+}
+
+Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
+                                               const sp<V1_0::IUsbGadgetCallback> &callback,
+                                               uint64_t timeout) {
+    std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
+
+    mCurrentUsbFunctions = functions;
+    mCurrentUsbFunctionsApplied = false;
+
+    // Unlink the gadget and stop the monitor if running.
+    V1_0::Status status = tearDownGadget();
+    if (status != Status::SUCCESS) {
+        goto error;
+    }
+
+    ALOGI("Returned from tearDown gadget");
+
+    // Leave the gadget pulled down to give time for the host to sense disconnect.
+    usleep(kDisconnectWaitUs);
+
+    if (functions == static_cast<uint64_t>(GadgetFunction::NONE)) {
+        if (callback == NULL)
+            return Void();
+        Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS);
+        if (!ret.isOk())
+            ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+        return Void();
+    }
+
+    status = validateAndSetVidPid(functions);
+
+    if (status != Status::SUCCESS) {
+        goto error;
+    }
+
+    status = setupFunctions(functions, callback, timeout);
+    if (status != Status::SUCCESS) {
+        goto error;
+    }
+
+    ALOGI("Usb Gadget setcurrent functions called successfully");
+    return Void();
+
+error:
+    ALOGI("Usb Gadget setcurrent functions failed");
+    if (callback == NULL)
+        return Void();
+    Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
+    if (!ret.isOk())
+        ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+    return Void();
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
diff --git a/usb/UsbGadget.h b/usb/UsbGadget.h
new file mode 100644
index 0000000..1ffb188
--- /dev/null
+++ b/usb/UsbGadget.h
@@ -0,0 +1,95 @@
+/*
+ * 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 ANDROID_HARDWARE_USB_GADGET_V1_0_USBGADGET_H
+#define ANDROID_HARDWARE_USB_GADGET_V1_0_USBGADGET_H
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/usb/gadget/1.0/IUsbGadget.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <pixelusb/UsbGadgetCommon.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::google::pixel::usb::addAdb;
+using ::android::hardware::google::pixel::usb::addEpollFd;
+using ::android::hardware::google::pixel::usb::getVendorFunctions;
+using ::android::hardware::google::pixel::usb::kDebug;
+using ::android::hardware::google::pixel::usb::kDisconnectWaitUs;
+using ::android::hardware::google::pixel::usb::linkFunction;
+using ::android::hardware::google::pixel::usb::MonitorFfs;
+using ::android::hardware::google::pixel::usb::resetGadget;
+using ::android::hardware::google::pixel::usb::setVidPid;
+using ::android::hardware::google::pixel::usb::unlinkFunctions;
+using ::std::string;
+
+constexpr char kGadgetName[] = "a600000.dwc3";
+static MonitorFfs monitorFfs(kGadgetName);
+
+struct UsbGadget : public IUsbGadget {
+    UsbGadget();
+
+    // Makes sure that only one request is processed at a time.
+    std::mutex mLockSetCurrentFunction;
+    uint64_t mCurrentUsbFunctions;
+    bool mCurrentUsbFunctionsApplied;
+
+    Return<void> setCurrentUsbFunctions(uint64_t functions, const sp<IUsbGadgetCallback> &callback,
+                                        uint64_t timeout) override;
+
+    Return<void> getCurrentUsbFunctions(const sp<IUsbGadgetCallback> &callback) override;
+
+  private:
+    Status tearDownGadget();
+    Status setupFunctions(uint64_t functions, const sp<IUsbGadgetCallback> &callback,
+                          uint64_t timeout);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_USB_V1_2_USBGADGET_H
diff --git a/usb/android.hardware.usb@1.2-service.bramble.rc b/usb/android.hardware.usb@1.2-service.bramble.rc
new file mode 100644
index 0000000..52f4379
--- /dev/null
+++ b/usb/android.hardware.usb@1.2-service.bramble.rc
@@ -0,0 +1,12 @@
+service vendor.usb-hal-1-2 /vendor/bin/hw/android.hardware.usb@1.2-service.bramble
+    class hal
+    user root
+    group root system shell mtp
+
+on boot
+    chown root system /sys/class/typec/port0/power_role
+    chown root system /sys/class/typec/port0/data_role
+    chown root system /sys/class/typec/port0/port_type
+    chmod 664 /sys/class/typec/port0/power_role
+    chmod 664 /sys/class/typec/port0/data_role
+    chmod 664 /sys/class/typec/port0/port_type
diff --git a/usb/service.cpp b/usb/service.cpp
new file mode 100644
index 0000000..5a34979
--- /dev/null
+++ b/usb/service.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.usb@1.2-service.bramble"
+
+#include <hidl/HidlTransportSupport.h>
+#include "Usb.h"
+#include "UsbGadget.h"
+
+using android::sp;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::usb::gadget::V1_0::IUsbGadget;
+using android::hardware::usb::gadget::V1_0::implementation::UsbGadget;
+using android::hardware::usb::V1_2::IUsb;
+using android::hardware::usb::V1_2::implementation::Usb;
+
+using android::OK;
+using android::status_t;
+
+int main() {
+    android::sp<IUsb> service = new Usb();
+    android::sp<IUsbGadget> service2 = new UsbGadget();
+
+    configureRpcThreadpool(2, true /*callerWillJoin*/);
+    status_t status = service->registerAsService();
+
+    if (status != OK) {
+        ALOGE("Cannot register USB HAL service");
+        return 1;
+    }
+
+    status = service2->registerAsService();
+
+    if (status != OK) {
+        ALOGE("Cannot register USB Gadget HAL service");
+        return 1;
+    }
+
+    ALOGI("USB HAL Ready.");
+    joinRpcThreadpool();
+    // Under noraml cases, execution will not reach this line.
+    ALOGI("USB HAL failed to join thread pool.");
+    return 1;
+}
diff --git a/utils.mk b/utils.mk
new file mode 100644
index 0000000..510e263
--- /dev/null
+++ b/utils.mk
@@ -0,0 +1,201 @@
+# vars for use by utils
+__empty :=
+__space := $(__empty) $(__empty)
+__colon := $(__empty):$(__empty)
+__underscore := $(__empty)_$(__empty)
+
+# $(call match-word,w1,w2)
+# checks if w1 == w2
+# How it works
+#   if (w1-w2 not __empty or w2-w1 not __empty) then not_match else match
+#
+# returns true or __empty
+#$(warning :$(1): :$(2): :$(subst $(1),,$(2)):) \
+#$(warning :$(2): :$(1): :$(subst $(2),,$(1)):) \
+#
+define match-word
+$(strip \
+  $(if $(or $(subst $(1),$(__empty),$(2)),$(subst $(2),$(__empty),$(1))),,true) \
+)
+endef
+
+# $(call find-word-in-list,w,wlist)
+# finds an exact match of word w in word list wlist
+#
+# How it works
+#   fill wlist spaces with __colon
+#   wrap w with __colon
+#   search word w in list wl, if found match m, return stripped word w
+#
+# returns stripped word or __empty
+define find-word-in-list
+$(strip \
+  $(eval wl:= $(__colon)$(subst $(__space),$(__colon),$(strip $(2)))$(__colon)) \
+  $(eval w:= $(__colon)$(strip $(1))$(__colon)) \
+  $(eval m:= $(findstring $(w),$(wl))) \
+  $(if $(m),$(1),) \
+)
+endef
+
+# $(call match-word-in-list,w,wlist)
+# does an exact match of word w in word list wlist
+# How it works
+#   if the input word is not __empty
+#     return output of an exact match of word w in wordlist wlist
+#   else
+#     return __empty
+# returns true or __empty
+define match-word-in-list
+$(strip \
+  $(if $(strip $(1)), \
+    $(call match-word,$(call find-word-in-list,$(1),$(2)),$(strip $(1))), \
+  ) \
+)
+endef
+
+# $(call match-prefix,p,delim,w/wlist)
+# matches prefix p in wlist using delimiter delim
+#
+# How it works
+#   trim the words in wlist w
+#   if find-word-in-list returns not __empty
+#     return true
+#   else
+#     return __empty
+#
+define match-prefix
+$(strip \
+  $(eval w := $(strip $(1)$(strip $(2)))) \
+  $(eval text := $(patsubst $(w)%,$(1),$(3))) \
+  $(if $(call match-word-in-list,$(1),$(text)),true,) \
+)
+endef
+
+# ----
+# The following utilities are meant for board platform specific
+# featurisation
+
+# $(call get-vendor-board-platforms,v)
+# returns list of board platforms for vendor v
+define get-vendor-board-platforms
+$($(1)_BOARD_PLATFORMS)
+endef
+
+# $(call is-board-platform,bp)
+# returns true or __empty
+define is-board-platform
+$(call match-word,$(1),$(TARGET_BOARD_PLATFORM))
+endef
+
+# $(call is-not-board-platform,bp)
+# returns true or __empty
+define is-not-board-platform
+$(if $(call match-word,$(1),$(TARGET_BOARD_PLATFORM)),,true)
+endef
+
+# $(call is-board-platform-in-list,bpl)
+# returns true or __empty
+define is-board-platform-in-list
+$(call match-word-in-list,$(TARGET_BOARD_PLATFORM),$(1))
+endef
+
+# $(call is-vendor-board-platform,vendor)
+# returns true or __empty
+define is-vendor-board-platform
+$(strip \
+  $(call match-word-in-list,$(TARGET_BOARD_PLATFORM),\
+    $(call get-vendor-board-platforms,$(1)) \
+  ) \
+)
+endef
+
+# $(call is-chipset-in-board-platform,chipset)
+# does a prefix match of chipset in TARGET_BOARD_PLATFORM
+# uses underscore as a delimiter
+#
+# returns true or __empty
+define is-chipset-in-board-platform
+$(call match-prefix,$(1),$(__underscore),$(TARGET_BOARD_PLATFORM))
+endef
+
+# $(call is-chipset-prefix-in-board-platform,prefix)
+# does a chipset prefix match in TARGET_BOARD_PLATFORM
+# assumes '_' and 'a' as the delimiter to the chipset prefix
+#
+# How it works
+#   if ($(prefix)_ or $(prefix)a match in board platform)
+#     return true
+#   else
+#     return __empty
+#
+define is-chipset-prefix-in-board-platform
+$(strip \
+  $(eval delim_a := $(__empty)a$(__empty)) \
+  $(if \
+    $(or \
+      $(call match-prefix,$(1),$(delim_a),$(TARGET_BOARD_PLATFORM)), \
+      $(call match-prefix,$(1),$(__underscore),$(TARGET_BOARD_PLATFORM)), \
+    ), \
+    true, \
+  ) \
+)
+endef
+
+#----
+# The following utilities are meant for Android Code Name
+# specific featurisation
+#
+# refer http://source.android.com/source/build-numbers.html
+# for code names and associated sdk versions
+CUPCAKE_SDK_VERSIONS := 3
+DONUT_SDK_VERSIONS   := 4
+ECLAIR_SDK_VERSIONS  := 5 6 7
+FROYO_SDK_VERSIONS   := 8
+GINGERBREAD_SDK_VERSIONS := 9 10
+HONEYCOMB_SDK_VERSIONS := 11 12 13
+ICECREAM_SANDWICH_SDK_VERSIONS := 14 15
+JELLY_BEAN_SDK_VERSIONS := 16 17 18
+
+# $(call is-platform-sdk-version-at-least,version)
+# version is a numeric SDK_VERSION defined above
+define is-platform-sdk-version-at-least
+$(strip \
+  $(if $(filter 1,$(shell echo "$$(( $(PLATFORM_SDK_VERSION) >= $(1) ))" )), \
+    true, \
+  ) \
+)
+endef
+
+# $(call is-android-codename,codename)
+# codename is one of cupcake,donut,eclair,froyo,gingerbread,icecream
+# please refer the $(codename)_SDK_VERSIONS declared above
+define is-android-codename
+$(strip \
+  $(if \
+    $(call match-word-in-list,$(PLATFORM_SDK_VERSION),$($(1)_SDK_VERSIONS)), \
+    true, \
+  ) \
+)
+endef
+
+# $(call is-android-codename-in-list,cnlist)
+# cnlist is combination/list of android codenames
+define is-android-codename-in-list
+$(strip \
+  $(eval acn := $(__empty)) \
+    $(foreach \
+      i,$(1),\
+      $(eval acn += \
+        $(if \
+          $(call \
+            match-word-in-list,\
+            $(PLATFORM_SDK_VERSION),\
+            $($(i)_SDK_VERSIONS)\
+          ),\
+          true,\
+        )\
+      )\
+    ) \
+  $(if $(strip $(acn)),true,) \
+)
+endef
diff --git a/vibrator/Android.bp b/vibrator/Android.bp
new file mode 100644
index 0000000..79b4c87
--- /dev/null
+++ b/vibrator/Android.bp
@@ -0,0 +1,82 @@
+//
+// 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_defaults {
+    name: "android.hardware.vibrator@1.3-defaults.bramble",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    shared_libs: [
+        "libhidlbase",
+        "libcutils",
+        "libhidltransport",
+        "liblog",
+        "libhwbinder",
+        "libutils",
+        "libhardware",
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
+        "android.hardware.vibrator@1.3",
+    ],
+    proprietary: true,
+}
+
+cc_library {
+    name: "android.hardware.vibrator@1.3-impl.bramble",
+    defaults: ["android.hardware.vibrator@1.3-defaults.bramble"],
+    srcs: [
+        "Hardware.cpp",
+        "Vibrator.cpp",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.vibrator@1.3-service.bramble",
+    defaults: ["android.hardware.vibrator@1.3-defaults.bramble"],
+    init_rc: ["android.hardware.vibrator@1.3-service.bramble.rc"],
+    vintf_fragments: ["android.hardware.vibrator@1.3-service.bramble.xml"],
+    srcs: ["service.cpp"],
+    static_libs: ["android.hardware.vibrator@1.3-impl.bramble"],
+}
+
+cc_test {
+    name: "PtsVibratorHalBrambleTestSuite",
+    defaults: ["android.hardware.vibrator@1.3-defaults.bramble"],
+    srcs: [
+        "tests/main.cpp",
+        "tests/test-hwapi.cpp",
+        "tests/test-hwcal.cpp",
+        "tests/test-vibrator.cpp",
+    ],
+    static_libs: [
+        "android.hardware.vibrator@1.3-impl.bramble",
+        "libgmock",
+    ],
+    shared_libs: [
+        "libbase",
+    ],
+    test_suites: [
+        "general-tests",
+        "pts",
+    ],
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+}
diff --git a/vibrator/AndroidTest.xml b/vibrator/AndroidTest.xml
new file mode 100644
index 0000000..cf91ea7
--- /dev/null
+++ b/vibrator/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (c) 2019 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="Runs PtsVibratorHalBrambleTestSuite.">
+    <option name="test-suite-tag" value="pts" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="append-bitness" value="true" />
+        <option name="cleanup" value="true" />
+        <option name="push" value="PtsVibratorHalBrambleTestSuite->/data/local/tmp/PtsVibratorHalBrambleTestSuite" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="module-name" value="PtsVibratorHalBrambleTestSuite" />
+        <option name="native-test-device-path" value="/data/local/tmp" />
+    </test>
+</configuration>
diff --git a/vibrator/Hardware.cpp b/vibrator/Hardware.cpp
new file mode 100644
index 0000000..0e1d808
--- /dev/null
+++ b/vibrator/Hardware.cpp
@@ -0,0 +1,209 @@
+/*
+ * 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.vibrator@1.3-service.bramble"
+
+#include "Hardware.h"
+
+#include <log/log.h>
+
+#include <iostream>
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+template <typename T>
+static void fileFromEnv(const char *env, T *outStream, std::string *outName = nullptr) {
+    auto file = std::getenv(env);
+    auto mode = std::is_base_of_v<std::ostream, T> ? std::ios_base::out : std::ios_base::in;
+
+    if (file == nullptr) {
+        ALOGE("Failed get env %s", env);
+        return;
+    }
+
+    if (outName != nullptr) {
+        *outName = std::string(file);
+    }
+
+    // Force 'in' mode to prevent file creation
+    outStream->open(file, mode | std::ios_base::in);
+    if (!*outStream) {
+        ALOGE("Failed to open %s:%s (%d): %s", env, file, errno, strerror(errno));
+    }
+}
+
+static auto pathsFromEnv(const char *env) {
+    std::map<std::string, std::ifstream> ret;
+    auto value = std::getenv(env);
+
+    if (value == nullptr) {
+        return ret;
+    }
+
+    std::istringstream paths{value};
+    std::string path;
+
+    while (paths >> path) {
+        ret[path].open(path);
+    }
+
+    return ret;
+}
+
+static std::string trim(const std::string &str, const std::string &whitespace = " \t") {
+    const auto str_begin = str.find_first_not_of(whitespace);
+    if (str_begin == std::string::npos) {
+        return "";
+    }
+
+    const auto str_end = str.find_last_not_of(whitespace);
+    const auto str_range = str_end - str_begin + 1;
+
+    return str.substr(str_begin, str_range);
+}
+
+template <typename T>
+static Enable_If_Iterable<T, true> unpack(std::istream &stream, T *value) {
+    for (auto &entry : *value) {
+        stream >> entry;
+    }
+}
+
+template <typename T>
+static Enable_If_Iterable<T, false> unpack(std::istream &stream, T *value) {
+    stream >> *value;
+}
+
+HwApi::HwApi() {
+    // ostreams below are required
+    fileFromEnv("F0_FILEPATH", &mF0, &mNames[&mF0]);
+    fileFromEnv("REDC_FILEPATH", &mRedc, &mNames[&mRedc]);
+    fileFromEnv("Q_FILEPATH", &mQ, &mNames[&mQ]);
+    fileFromEnv("ACTIVATE_PATH", &mActivate, &mNames[&mActivate]);
+    fileFromEnv("DURATION_PATH", &mDuration, &mNames[&mDuration]);
+    fileFromEnv("STATE_PATH", &mState, &mNames[&mState]);
+    fileFromEnv("EFFECT_DURATION_PATH", &mEffectDuration, &mNames[&mEffectDuration]);
+    fileFromEnv("EFFECT_INDEX_PATH", &mEffectIndex, &mNames[&mEffectIndex]);
+    fileFromEnv("EFFECT_QUEUE_PATH", &mEffectQueue, &mNames[&mEffectQueue]);
+    fileFromEnv("EFFECT_SCALE_PATH", &mEffectScale, &mNames[&mEffectScale]);
+    fileFromEnv("GLOBAL_SCALE_PATH", &mGlobalScale, &mNames[&mGlobalScale]);
+    fileFromEnv("ASP_ENABLE_PATH", &mAspEnable, &mNames[&mAspEnable]);
+    fileFromEnv("GPIO_FALL_INDEX", &mGpioFallIndex, &mNames[&mGpioFallIndex]);
+    fileFromEnv("GPIO_FALL_SCALE", &mGpioFallScale, &mNames[&mGpioFallScale]);
+    fileFromEnv("GPIO_RISE_INDEX", &mGpioRiseIndex, &mNames[&mGpioRiseIndex]);
+    fileFromEnv("GPIO_RISE_SCALE", &mGpioRiseScale, &mNames[&mGpioRiseScale]);
+}
+
+template <typename T>
+bool HwApi::has(T &stream) {
+    return !!stream;
+}
+
+template <typename T, typename U>
+bool HwApi::get(T *value, U &stream) {
+    bool ret;
+    stream.seekg(0);
+    stream >> *value;
+    if (!(ret = !!stream)) {
+        ALOGE("Failed to read %s (%d): %s", mNames[&stream].c_str(), errno, strerror(errno));
+    }
+    stream.clear();
+    return ret;
+}
+
+template <typename T, typename U>
+bool HwApi::set(const T &value, U &stream) {
+    bool ret;
+    stream << value << std::endl;
+    if (!(ret = !!stream)) {
+        ALOGE("Failed to write %s (%d): %s", mNames[&stream].c_str(), errno, strerror(errno));
+        stream.clear();
+    }
+    return ret;
+}
+
+void HwApi::debug(int fd) {
+    dprintf(fd, "Kernel:\n");
+
+    for (auto &entry : pathsFromEnv("HWAPI_DEBUG_PATHS")) {
+        auto &path = entry.first;
+        auto &stream = entry.second;
+        std::string line;
+
+        dprintf(fd, "  %s:\n", path.c_str());
+        while (std::getline(stream, line)) {
+            dprintf(fd, "    %s\n", line.c_str());
+        }
+    }
+}
+
+HwCal::HwCal() {
+    std::ifstream calfile;
+
+    fileFromEnv("CALIBRATION_FILEPATH", &calfile);
+
+    for (std::string line; std::getline(calfile, line);) {
+        if (line.empty() || line[0] == '#') {
+            continue;
+        }
+        std::istringstream is_line(line);
+        std::string key, value;
+        if (std::getline(is_line, key, ':') && std::getline(is_line, value)) {
+            mCalData[trim(key)] = trim(value);
+        }
+    }
+}
+
+template <typename T>
+bool HwCal::get(const char *key, T *value) {
+    auto it = mCalData.find(key);
+    if (it == mCalData.end()) {
+        ALOGE("Missing %s config!", key);
+        return false;
+    }
+    std::stringstream stream{it->second};
+    unpack(stream, value);
+    if (!stream || !stream.eof()) {
+        ALOGE("Invalid %s config!", key);
+        return false;
+    }
+    return true;
+}
+
+void HwCal::debug(int fd) {
+    std::ifstream stream;
+    std::string path;
+    std::string line;
+
+    dprintf(fd, "Persist:\n");
+
+    fileFromEnv("CALIBRATION_FILEPATH", &stream, &path);
+
+    dprintf(fd, "  %s:\n", path.c_str());
+    while (std::getline(stream, line)) {
+        dprintf(fd, "    %s\n", line.c_str());
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/Hardware.h b/vibrator/Hardware.h
new file mode 100644
index 0000000..4b65f24
--- /dev/null
+++ b/vibrator/Hardware.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
+#define ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
+
+#include "Vibrator.h"
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+class HwApi : public Vibrator::HwApi {
+  public:
+    HwApi();
+    bool setF0(uint32_t value) override { return set(value, mF0); }
+    bool setRedc(uint32_t value) override { return set(value, mRedc); }
+    bool setQ(uint32_t value) override { return set(value, mQ); }
+    bool setActivate(bool value) override { return set(value, mActivate); }
+    bool setDuration(uint32_t value) override { return set(value, mDuration); }
+    bool getEffectDuration(uint32_t *value) override { return get(value, mEffectDuration); }
+    bool setEffectIndex(uint32_t value) override { return set(value, mEffectIndex); }
+    bool setEffectQueue(std::string value) override { return set(value, mEffectQueue); }
+    bool hasEffectScale() override { return has(mEffectScale); }
+    bool setEffectScale(uint32_t value) override { return set(value, mEffectScale); }
+    bool setGlobalScale(uint32_t value) override { return set(value, mGlobalScale); }
+    bool setState(bool value) override { return set(value, mState); }
+    bool hasAspEnable() override { return has(mAspEnable); }
+    bool getAspEnable(bool *value) override { return get(value, mAspEnable); }
+    bool setAspEnable(bool value) override { return set(value, mAspEnable); }
+    bool setGpioFallIndex(uint32_t value) override { return set(value, mGpioFallIndex); }
+    bool setGpioFallScale(uint32_t value) override { return set(value, mGpioFallScale); }
+    bool setGpioRiseIndex(uint32_t value) override { return set(value, mGpioRiseIndex); }
+    bool setGpioRiseScale(uint32_t value) override { return set(value, mGpioRiseScale); }
+    void debug(int fd) override;
+
+  private:
+    template <typename T>
+    bool has(T &stream);
+    template <typename T, typename U>
+    bool get(T *value, U &stream);
+    template <typename T, typename U>
+    bool set(const T &value, U &stream);
+
+  private:
+    std::map<void *, std::string> mNames;
+    std::ofstream mF0;
+    std::ofstream mRedc;
+    std::ofstream mQ;
+    std::ofstream mActivate;
+    std::ofstream mDuration;
+    std::ifstream mEffectDuration;
+    std::ofstream mEffectIndex;
+    std::ofstream mEffectQueue;
+    std::ofstream mEffectScale;
+    std::ofstream mGlobalScale;
+    std::ofstream mState;
+    std::fstream mAspEnable;
+    std::ofstream mGpioFallIndex;
+    std::ofstream mGpioFallScale;
+    std::ofstream mGpioRiseIndex;
+    std::ofstream mGpioRiseScale;
+};
+
+class HwCal : public Vibrator::HwCal {
+  private:
+    static constexpr char F0_CONFIG[] = "f0_measured";
+    static constexpr char REDC_CONFIG[] = "redc_measured";
+    static constexpr char Q_CONFIG[] = "q_measured";
+    static constexpr char Q_INDEX[] = "q_index";
+    static constexpr char VOLTAGES_CONFIG[] = "v_levels";
+
+    static constexpr uint32_t Q_FLOAT_TO_FIXED = 1 << 16;
+    static constexpr float Q_INDEX_TO_FLOAT = 1.5f;
+    static constexpr uint32_t Q_INDEX_TO_FIXED = Q_INDEX_TO_FLOAT * Q_FLOAT_TO_FIXED;
+    static constexpr uint32_t Q_INDEX_OFFSET = 2.0f * Q_FLOAT_TO_FIXED;
+
+    static constexpr uint32_t Q_DEFAULT = 15.5 * Q_FLOAT_TO_FIXED;
+    static constexpr std::array<uint32_t, 6> V_LEVELS_DEFAULT = {60, 70, 80, 90, 100, 76};
+
+  public:
+    HwCal();
+    bool getF0(uint32_t *value) override { return get(F0_CONFIG, value); }
+    bool getRedc(uint32_t *value) override { return get(REDC_CONFIG, value); }
+    bool getQ(uint32_t *value) override {
+        if (get(Q_CONFIG, value)) {
+            return true;
+        }
+        if (get(Q_INDEX, value)) {
+            *value = *value * Q_INDEX_TO_FIXED + Q_INDEX_OFFSET;
+            return true;
+        }
+        *value = Q_DEFAULT;
+        return true;
+    }
+    bool getVolLevels(std::array<uint32_t, 6> *value) override {
+        if (get(VOLTAGES_CONFIG, value)) {
+            return true;
+        }
+        *value = V_LEVELS_DEFAULT;
+        return true;
+    }
+    void debug(int fd) override;
+
+  private:
+    template <typename T>
+    bool get(const char *key, T *value);
+
+  private:
+    std::map<std::string, std::string> mCalData;
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
diff --git a/vibrator/OWNERS b/vibrator/OWNERS
new file mode 100644
index 0000000..928c9ff
--- /dev/null
+++ b/vibrator/OWNERS
@@ -0,0 +1,3 @@
+chasewu@google.com
+eliptus@google.com
+michaelwr@google.com
diff --git a/vibrator/Vibrator.cpp b/vibrator/Vibrator.cpp
new file mode 100644
index 0000000..36a1ea8
--- /dev/null
+++ b/vibrator/Vibrator.cpp
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.vibrator@1.3-service.bramble"
+
+#include <log/log.h>
+
+#include <cutils/properties.h>
+#include <hardware/hardware.h>
+#include <hardware/vibrator.h>
+
+#include "Vibrator.h"
+
+#include <cinttypes>
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
+#endif
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using Status = ::android::hardware::vibrator::V1_0::Status;
+using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
+
+static constexpr uint32_t WAVEFORM_SIMPLE_EFFECT_INDEX = 2;
+
+static constexpr uint32_t WAVEFORM_TEXTURE_TICK_EFFECT_LEVEL = 0;
+
+static constexpr uint32_t WAVEFORM_TICK_EFFECT_LEVEL = 1;
+
+static constexpr uint32_t WAVEFORM_CLICK_EFFECT_LEVEL = 2;
+
+static constexpr uint32_t WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL = 3;
+
+static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100;
+
+static constexpr uint32_t WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0;
+
+static constexpr uint32_t WAVEFORM_TRIGGER_QUEUE_INDEX = 65534;
+
+static constexpr uint32_t VOLTAGE_GLOBAL_SCALE_LEVEL = 5;
+static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
+
+static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby
+static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling
+
+static constexpr float AMP_ATTENUATE_STEP_SIZE = 0.125f;
+static constexpr float EFFECT_FREQUENCY_KHZ = 48.0f;
+
+static uint8_t amplitudeToScale(uint8_t amplitude, uint8_t maximum) {
+    return std::round((-20 * std::log10(amplitude / static_cast<float>(maximum))) /
+                      (AMP_ATTENUATE_STEP_SIZE));
+}
+
+Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
+    : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
+    uint32_t caldata;
+    uint32_t effectDuration;
+
+    if (!mHwApi->setState(true)) {
+        ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
+    }
+
+    if (mHwCal->getF0(&caldata)) {
+        mHwApi->setF0(caldata);
+    }
+    if (mHwCal->getRedc(&caldata)) {
+        mHwApi->setRedc(caldata);
+    }
+    if (mHwCal->getQ(&caldata)) {
+        mHwApi->setQ(caldata);
+    }
+    mHwCal->getVolLevels(&mVolLevels);
+
+    mHwApi->setEffectIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
+    mHwApi->getEffectDuration(&effectDuration);
+
+    mSimpleEffectDuration = std::ceil(effectDuration / EFFECT_FREQUENCY_KHZ);
+
+    const uint32_t scaleFall =
+        amplitudeToScale(mVolLevels[WAVEFORM_CLICK_EFFECT_LEVEL], VOLTAGE_SCALE_MAX);
+    const uint32_t scaleRise =
+        amplitudeToScale(mVolLevels[WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL], VOLTAGE_SCALE_MAX);
+
+    mHwApi->setGpioFallIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
+    mHwApi->setGpioFallScale(scaleFall);
+    mHwApi->setGpioRiseIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
+    mHwApi->setGpioRiseScale(scaleRise);
+}
+
+Return<Status> Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex) {
+    mHwApi->setEffectIndex(effectIndex);
+    mHwApi->setDuration(timeoutMs);
+    mHwApi->setActivate(1);
+
+    return Status::OK;
+}
+
+// Methods from ::android::hardware::vibrator::V1_1::IVibrator follow.
+Return<Status> Vibrator::on(uint32_t timeoutMs) {
+    if (MAX_COLD_START_LATENCY_MS <= UINT32_MAX - timeoutMs) {
+        timeoutMs += MAX_COLD_START_LATENCY_MS;
+    }
+    setGlobalAmplitude(true);
+    return on(timeoutMs, WAVEFORM_LONG_VIBRATION_EFFECT_INDEX);
+}
+
+Return<Status> Vibrator::off() {
+    setGlobalAmplitude(false);
+    if (!mHwApi->setActivate(0)) {
+        ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+    return Status::OK;
+}
+
+Return<bool> Vibrator::supportsAmplitudeControl() {
+    return !isUnderExternalControl() && mHwApi->hasEffectScale();
+}
+
+Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
+    if (!amplitude) {
+        return Status::BAD_VALUE;
+    }
+
+    if (!isUnderExternalControl()) {
+        return setEffectAmplitude(amplitude, UINT8_MAX);
+    } else {
+        return Status::UNSUPPORTED_OPERATION;
+    }
+}
+
+Return<Status> Vibrator::setEffectAmplitude(uint8_t amplitude, uint8_t maximum) {
+    int32_t scale = amplitudeToScale(amplitude, maximum);
+
+    if (!mHwApi->setEffectScale(scale)) {
+        ALOGE("Failed to set effect amplitude (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+
+    return Status::OK;
+}
+
+Return<Status> Vibrator::setGlobalAmplitude(bool set) {
+    uint8_t amplitude = set ? mVolLevels[VOLTAGE_GLOBAL_SCALE_LEVEL] : VOLTAGE_SCALE_MAX;
+    int32_t scale = amplitudeToScale(amplitude, VOLTAGE_SCALE_MAX);
+
+    if (!mHwApi->setGlobalScale(scale)) {
+        ALOGE("Failed to set global amplitude (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+
+    return Status::OK;
+}
+
+// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
+
+Return<bool> Vibrator::supportsExternalControl() {
+    return (mHwApi->hasAspEnable() ? true : false);
+}
+
+Return<Status> Vibrator::setExternalControl(bool enabled) {
+    setGlobalAmplitude(enabled);
+
+    if (!mHwApi->setAspEnable(enabled)) {
+        ALOGE("Failed to set external control (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+    return Status::OK;
+}
+
+bool Vibrator::isUnderExternalControl() {
+    bool isAspEnabled;
+    mHwApi->getAspEnable(&isAspEnabled);
+    return isAspEnabled;
+}
+
+// Methods from ::android.hidl.base::V1_0::IBase follow.
+
+Return<void> Vibrator::debug(const hidl_handle &handle,
+                             const hidl_vec<hidl_string> & /* options */) {
+    if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
+        ALOGE("Called debug() with invalid fd.");
+        return Void();
+    }
+
+    int fd = handle->data[0];
+
+    dprintf(fd, "HIDL:\n");
+
+    dprintf(fd, "  Voltage Levels:");
+    for (auto v : mVolLevels) {
+        dprintf(fd, " %" PRIu32, v);
+    }
+    dprintf(fd, "\n");
+
+    dprintf(fd, "  Effect Duration: %" PRIu32 "\n", mSimpleEffectDuration);
+
+    dprintf(fd, "\n");
+
+    mHwApi->debug(fd);
+
+    dprintf(fd, "\n");
+
+    mHwCal->debug(fd);
+
+    fsync(fd);
+    return Void();
+}
+
+template <typename T>
+Return<void> Vibrator::performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb) {
+    auto validRange = hidl_enum_range<T>();
+    if (effect < *validRange.begin() || effect > *std::prev(validRange.end())) {
+        _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+        return Void();
+    }
+    return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
+                                   perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength,
+                                   perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<Status> Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
+                                          uint32_t *outTimeMs, uint32_t *outVolLevel) {
+    uint32_t timeMs;
+    uint32_t volLevel;
+    uint32_t volIndex;
+    int8_t volOffset;
+
+    switch (strength) {
+        case EffectStrength::LIGHT:
+            volOffset = -1;
+            break;
+        case EffectStrength::MEDIUM:
+            volOffset = 0;
+            break;
+        case EffectStrength::STRONG:
+            volOffset = 1;
+            break;
+        default:
+            return Status::UNSUPPORTED_OPERATION;
+    }
+
+    switch (effect) {
+        case Effect::TEXTURE_TICK:
+            volIndex = WAVEFORM_TEXTURE_TICK_EFFECT_LEVEL;
+            volOffset = 0;
+            break;
+        case Effect::TICK:
+            volIndex = WAVEFORM_TICK_EFFECT_LEVEL;
+            volOffset = 0;
+            break;
+        case Effect::CLICK:
+            volIndex = WAVEFORM_CLICK_EFFECT_LEVEL;
+            break;
+        case Effect::HEAVY_CLICK:
+            volIndex = WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL;
+            break;
+        default:
+            return Status::UNSUPPORTED_OPERATION;
+    }
+
+    volLevel = mVolLevels[volIndex + volOffset];
+    timeMs = mSimpleEffectDuration + MAX_COLD_START_LATENCY_MS;
+
+    *outTimeMs = timeMs;
+    *outVolLevel = volLevel;
+
+    return Status::OK;
+}
+
+Return<Status> Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
+                                            uint32_t *outTimeMs, uint32_t * /*outVolLevel*/,
+                                            std::string *outEffectQueue) {
+    Status status;
+    uint32_t timeMs;
+    std::ostringstream effectBuilder;
+    uint32_t thisTimeMs;
+    uint32_t thisVolLevel;
+
+    switch (effect) {
+        case Effect::DOUBLE_CLICK:
+            timeMs = 0;
+
+            status = getSimpleDetails(Effect::CLICK, strength, &thisTimeMs, &thisVolLevel);
+            if (status != Status::OK) {
+                return status;
+            }
+            effectBuilder << WAVEFORM_SIMPLE_EFFECT_INDEX << "." << thisVolLevel;
+            timeMs += thisTimeMs;
+
+            effectBuilder << ",";
+
+            effectBuilder << WAVEFORM_DOUBLE_CLICK_SILENCE_MS;
+            timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
+
+            effectBuilder << ",";
+
+            status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisTimeMs, &thisVolLevel);
+            if (status != Status::OK) {
+                return status;
+            }
+            effectBuilder << WAVEFORM_SIMPLE_EFFECT_INDEX << "." << thisVolLevel;
+            timeMs += thisTimeMs;
+
+            break;
+        default:
+            return Status::UNSUPPORTED_OPERATION;
+    }
+
+    *outTimeMs = timeMs;
+    *outEffectQueue = effectBuilder.str();
+
+    return Status::OK;
+}
+
+Return<Status> Vibrator::setEffectQueue(const std::string &effectQueue) {
+    if (!mHwApi->setEffectQueue(effectQueue)) {
+        ALOGE("Failed to write \"%s\" to effect queue (%d): %s", effectQueue.c_str(), errno,
+              strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+
+    return Status::OK;
+}
+
+Return<void> Vibrator::performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+    Status status = Status::OK;
+    uint32_t timeMs = 0;
+    uint32_t effectIndex;
+    uint32_t volLevel;
+    std::string effectQueue;
+
+    switch (effect) {
+        case Effect::TEXTURE_TICK:
+            // fall-through
+        case Effect::TICK:
+            // fall-through
+        case Effect::CLICK:
+            // fall-through
+        case Effect::HEAVY_CLICK:
+            status = getSimpleDetails(effect, strength, &timeMs, &volLevel);
+            break;
+        case Effect::DOUBLE_CLICK:
+            status = getCompoundDetails(effect, strength, &timeMs, &volLevel, &effectQueue);
+            break;
+        default:
+            status = Status::UNSUPPORTED_OPERATION;
+            break;
+    }
+    if (status != Status::OK) {
+        goto exit;
+    }
+
+    if (!effectQueue.empty()) {
+        status = setEffectQueue(effectQueue);
+        if (status != Status::OK) {
+            goto exit;
+        }
+        effectIndex = WAVEFORM_TRIGGER_QUEUE_INDEX;
+    } else {
+        setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
+        effectIndex = WAVEFORM_SIMPLE_EFFECT_INDEX;
+    }
+
+    on(timeMs, effectIndex);
+
+exit:
+
+    _hidl_cb(status, timeMs);
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/Vibrator.h b/vibrator/Vibrator.h
new file mode 100644
index 0000000..b204dae
--- /dev/null
+++ b/vibrator/Vibrator.h
@@ -0,0 +1,166 @@
+/*
+ * 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 ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <hidl/Status.h>
+
+#include <fstream>
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+class Vibrator : public IVibrator {
+  public:
+    // APIs for interfacing with the kernel driver.
+    class HwApi {
+      public:
+        virtual ~HwApi() = default;
+        // Stores the LRA resonant frequency to be used for PWLE playback
+        // and click compensation.
+        virtual bool setF0(uint32_t value) = 0;
+        // Stores the LRA series resistance to be used for click
+        // compensation.
+        virtual bool setRedc(uint32_t value) = 0;
+        // Stores the LRA Q factor to be used for Q-dependent waveform
+        // selection.
+        virtual bool setQ(uint32_t value) = 0;
+        // Activates/deactivates the vibrator for durations specified by
+        // setDuration().
+        virtual bool setActivate(bool value) = 0;
+        // Specifies the vibration duration in milliseconds.
+        virtual bool setDuration(uint32_t value) = 0;
+        // Reports the duration of the waveform selected by
+        // setEffectIndex(), measured in 48-kHz periods.
+        virtual bool getEffectDuration(uint32_t *value) = 0;
+        // Selects the waveform associated with vibration calls from
+        // the Android vibrator HAL.
+        virtual bool setEffectIndex(uint32_t value) = 0;
+        // Specifies an array of waveforms, delays, and repetition markers to
+        // generate complex waveforms.
+        virtual bool setEffectQueue(std::string value) = 0;
+        // Reports whether setEffectScale() is supported.
+        virtual bool hasEffectScale() = 0;
+        // Indicates the number of 0.125-dB steps of attenuation to apply to
+        // waveforms triggered in response to vibration calls from the
+        // Android vibrator HAL.
+        virtual bool setEffectScale(uint32_t value) = 0;
+        // Indicates the number of 0.125-dB steps of attenuation to apply to
+        // any output waveform (additive to all other set*Scale()
+        // controls).
+        virtual bool setGlobalScale(uint32_t value) = 0;
+        // Specifies the active state of the vibrator
+        // (true = enabled, false= disabled).
+        virtual bool setState(bool value) = 0;
+        // Reports whether getAspEnable()/setAspEnable() is supported.
+        virtual bool hasAspEnable() = 0;
+        // Enables/disables ASP playback.
+        virtual bool getAspEnable(bool *value) = 0;
+        // Reports enabled/disabled state of ASP playback.
+        virtual bool setAspEnable(bool value) = 0;
+        // Selects the waveform associated with a GPIO1 falling edge.
+        virtual bool setGpioFallIndex(uint32_t value) = 0;
+        // Indicates the number of 0.125-dB steps of attenuation to apply to
+        // waveforms triggered in response to a GPIO1 falling edge.
+        virtual bool setGpioFallScale(uint32_t value) = 0;
+        // Selects the waveform associated with a GPIO1 rising edge.
+        virtual bool setGpioRiseIndex(uint32_t value) = 0;
+        // Indicates the number of 0.125-dB steps of attenuation to apply to
+        // waveforms triggered in response to a GPIO1 rising edge.
+        virtual bool setGpioRiseScale(uint32_t value) = 0;
+        // Emit diagnostic information to the given file.
+        virtual void debug(int fd) = 0;
+    };
+
+    // APIs for obtaining calibration/configuration data from persistent memory.
+    class HwCal {
+      public:
+        virtual ~HwCal() = default;
+        // Obtains the LRA resonant frequency to be used for PWLE playback
+        // and click compensation.
+        virtual bool getF0(uint32_t *value) = 0;
+        // Obtains the LRA series resistance to be used for click
+        // compensation.
+        virtual bool getRedc(uint32_t *value) = 0;
+        // Obtains the LRA Q factor to be used for Q-dependent waveform
+        // selection.
+        virtual bool getQ(uint32_t *value) = 0;
+        // Obtains the discreet voltage levels to be applied for the various
+        // waveforms, in units of 1%.
+        virtual bool getVolLevels(std::array<uint32_t, 6> *value) = 0;
+        // Emit diagnostic information to the given file.
+        virtual void debug(int fd) = 0;
+    };
+
+  public:
+    Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal);
+
+    // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
+    using Status = ::android::hardware::vibrator::V1_0::Status;
+    Return<Status> on(uint32_t timeoutMs) override;
+    Return<Status> off() override;
+    Return<bool> supportsAmplitudeControl() override;
+    Return<Status> setAmplitude(uint8_t amplitude) override;
+
+    // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
+    Return<bool> supportsExternalControl() override;
+    Return<Status> setExternalControl(bool enabled) override;
+
+    using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
+    Return<void> perform(V1_0::Effect effect, EffectStrength strength,
+                         perform_cb _hidl_cb) override;
+    Return<void> perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
+                             perform_cb _hidl_cb) override;
+    Return<void> perform_1_2(V1_2::Effect effect, EffectStrength strength,
+                             perform_cb _hidl_cb) override;
+    Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+
+    // Methods from ::android.hidl.base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle &handle, const hidl_vec<hidl_string> &options) override;
+
+  private:
+    Return<Status> on(uint32_t timeoutMs, uint32_t effectIndex);
+    template <typename T>
+    Return<void> performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb);
+    // set 'amplitude' based on an arbitrary scale determined by 'maximum'
+    Return<Status> setEffectAmplitude(uint8_t amplitude, uint8_t maximum);
+    Return<Status> setGlobalAmplitude(bool set);
+    // 'simple' effects are those precompiled and loaded into the controller
+    Return<Status> getSimpleDetails(Effect effect, EffectStrength strength, uint32_t *outTimeMs,
+                                    uint32_t *outVolLevel);
+    // 'compound' effects are those composed by stringing multiple 'simple' effects
+    Return<Status> getCompoundDetails(Effect effect, EffectStrength strength, uint32_t *outTimeMs,
+                                      uint32_t *outVolLevel, std::string *outEffectQueue);
+    Return<Status> setEffectQueue(const std::string &effectQueue);
+    Return<void> performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
+    bool isUnderExternalControl();
+    std::unique_ptr<HwApi> mHwApi;
+    std::unique_ptr<HwCal> mHwCal;
+    std::array<uint32_t, 6> mVolLevels;
+    uint32_t mSimpleEffectDuration;
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
diff --git a/vibrator/android.hardware.vibrator@1.3-service.bramble.rc b/vibrator/android.hardware.vibrator@1.3-service.bramble.rc
new file mode 100644
index 0000000..47c7e5e
--- /dev/null
+++ b/vibrator/android.hardware.vibrator@1.3-service.bramble.rc
@@ -0,0 +1,38 @@
+service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.bramble
+    class hal
+    user system
+    group system
+
+    setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l25a.cal
+
+    setenv F0_FILEPATH /sys/class/leds/vibrator/device/f0_stored
+    setenv REDC_FILEPATH /sys/class/leds/vibrator/device/redc_stored
+    setenv Q_FILEPATH /sys/class/leds/vibrator/device/q_stored
+    setenv ACTIVATE_PATH /sys/class/leds/vibrator/activate
+    setenv DURATION_PATH /sys/class/leds/vibrator/duration
+    setenv STATE_PATH /sys/class/leds/vibrator/state
+    setenv EFFECT_DURATION_PATH /sys/class/leds/vibrator/device/cp_trigger_duration
+    setenv EFFECT_INDEX_PATH /sys/class/leds/vibrator/device/cp_trigger_index
+    setenv EFFECT_QUEUE_PATH /sys/class/leds/vibrator/device/cp_trigger_queue
+    setenv EFFECT_SCALE_PATH /sys/class/leds/vibrator/device/cp_dig_scale
+    setenv GLOBAL_SCALE_PATH /sys/class/leds/vibrator/device/dig_scale
+    setenv ASP_ENABLE_PATH /sys/class/leds/vibrator/device/asp_enable
+    setenv GPIO_FALL_INDEX /sys/class/leds/vibrator/device/gpio1_fall_index
+    setenv GPIO_FALL_SCALE /sys/class/leds/vibrator/device/gpio1_fall_dig_scale
+    setenv GPIO_RISE_INDEX /sys/class/leds/vibrator/device/gpio1_rise_index
+    setenv GPIO_RISE_SCALE /sys/class/leds/vibrator/device/gpio1_rise_dig_scale
+
+    setenv HWAPI_DEBUG_PATHS "
+        /sys/class/leds/vibrator/device/asp_enable
+        /sys/class/leds/vibrator/device/f0_stored
+        /sys/class/leds/vibrator/device/fw_rev
+        /sys/class/leds/vibrator/device/gpio1_fall_dig_scale
+        /sys/class/leds/vibrator/device/gpio1_fall_index
+        /sys/class/leds/vibrator/device/gpio1_rise_dig_scale
+        /sys/class/leds/vibrator/device/gpio1_rise_index
+        /sys/class/leds/vibrator/device/heartbeat
+        /sys/class/leds/vibrator/device/num_waves
+        /sys/class/leds/vibrator/device/q_stored
+        /sys/class/leds/vibrator/device/redc_stored
+        /sys/class/leds/vibrator/state
+        "
diff --git a/vibrator/android.hardware.vibrator@1.3-service.bramble.xml b/vibrator/android.hardware.vibrator@1.3-service.bramble.xml
new file mode 100644
index 0000000..172aa21
--- /dev/null
+++ b/vibrator/android.hardware.vibrator@1.3-service.bramble.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.vibrator</name>
+        <transport>hwbinder</transport>
+        <version>1.3</version>
+        <interface>
+            <name>IVibrator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/vibrator/service.cpp b/vibrator/service.cpp
new file mode 100644
index 0000000..9a076f1
--- /dev/null
+++ b/vibrator/service.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "android.hardware.vibrator@1.3-service.bramble"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "Hardware.h"
+#include "Vibrator.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::vibrator::V1_3::implementation::HwApi;
+using android::hardware::vibrator::V1_3::implementation::HwCal;
+using android::hardware::vibrator::V1_3::implementation::Vibrator;
+using namespace android;
+
+status_t registerVibratorService() {
+    sp<Vibrator> vibrator = new Vibrator(std::make_unique<HwApi>(), std::make_unique<HwCal>());
+
+    return vibrator->registerAsService();
+}
+
+int main() {
+    configureRpcThreadpool(1, true);
+    status_t status = registerVibratorService();
+
+    if (status != OK) {
+        return status;
+    }
+
+    joinRpcThreadpool();
+}
diff --git a/vibrator/tests/main.cpp b/vibrator/tests/main.cpp
new file mode 100644
index 0000000..87b18a4
--- /dev/null
+++ b/vibrator/tests/main.cpp
@@ -0,0 +1,22 @@
+/*
+ * 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 <gmock/gmock.h>
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleMock(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/vibrator/tests/mocks.h b/vibrator/tests/mocks.h
new file mode 100644
index 0000000..4e0544d
--- /dev/null
+++ b/vibrator/tests/mocks.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
+#define ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
+
+#include "Vibrator.h"
+
+class MockApi : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwApi {
+  public:
+    MOCK_METHOD0(destructor, void());
+    MOCK_METHOD1(setF0, bool(uint32_t value));
+    MOCK_METHOD1(setRedc, bool(uint32_t value));
+    MOCK_METHOD1(setQ, bool(uint32_t value));
+    MOCK_METHOD1(setActivate, bool(bool value));
+    MOCK_METHOD1(setDuration, bool(uint32_t value));
+    MOCK_METHOD1(getEffectDuration, bool(uint32_t *value));
+    MOCK_METHOD1(setEffectIndex, bool(uint32_t value));
+    MOCK_METHOD1(setEffectQueue, bool(std::string value));
+    MOCK_METHOD0(hasEffectScale, bool());
+    MOCK_METHOD1(setEffectScale, bool(uint32_t value));
+    MOCK_METHOD1(setGlobalScale, bool(uint32_t value));
+    MOCK_METHOD1(setState, bool(bool value));
+    MOCK_METHOD0(hasAspEnable, bool());
+    MOCK_METHOD1(getAspEnable, bool(bool *value));
+    MOCK_METHOD1(setAspEnable, bool(bool value));
+    MOCK_METHOD1(setGpioFallIndex, bool(uint32_t value));
+    MOCK_METHOD1(setGpioFallScale, bool(uint32_t value));
+    MOCK_METHOD1(setGpioRiseIndex, bool(uint32_t value));
+    MOCK_METHOD1(setGpioRiseScale, bool(uint32_t value));
+    MOCK_METHOD1(debug, void(int fd));
+
+    ~MockApi() override { destructor(); };
+};
+
+class MockCal : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwCal {
+  public:
+    MOCK_METHOD0(destructor, void());
+    MOCK_METHOD1(getF0, bool(uint32_t *value));
+    MOCK_METHOD1(getRedc, bool(uint32_t *value));
+    MOCK_METHOD1(getQ, bool(uint32_t *value));
+    MOCK_METHOD1(getVolLevels, bool(std::array<uint32_t, 6> *value));
+    MOCK_METHOD1(debug, void(int fd));
+
+    ~MockCal() override { destructor(); };
+};
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
diff --git a/vibrator/tests/test-hwapi.cpp b/vibrator/tests/test-hwapi.cpp
new file mode 100644
index 0000000..e5a46a6
--- /dev/null
+++ b/vibrator/tests/test-hwapi.cpp
@@ -0,0 +1,322 @@
+/*
+ * 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.vibrator@1.3-tests.bramble"
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+
+#include <cstdlib>
+#include <fstream>
+
+#include "Hardware.h"
+
+using namespace ::testing;
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+class HwApiTest : public Test {
+  private:
+    static constexpr const char *FILE_NAMES[]{
+        "F0_FILEPATH",       "REDC_FILEPATH",     "Q_FILEPATH",           "ACTIVATE_PATH",
+        "DURATION_PATH",     "STATE_PATH",        "EFFECT_DURATION_PATH", "EFFECT_INDEX_PATH",
+        "EFFECT_QUEUE_PATH", "EFFECT_SCALE_PATH", "GLOBAL_SCALE_PATH",    "ASP_ENABLE_PATH",
+        "GPIO_FALL_INDEX",   "GPIO_FALL_SCALE",   "GPIO_RISE_INDEX",      "GPIO_RISE_SCALE",
+    };
+
+  public:
+    void SetUp() override {
+        for (auto n : FILE_NAMES) {
+            auto name = std::string(n);
+            auto path = std::string(mFilesDir.path) + "/" + name;
+            std::ofstream touch{path};
+            setenv(name.c_str(), path.c_str(), true);
+            mFileMap[name] = path;
+        }
+        mHwApi = std::make_unique<HwApi>();
+
+        for (auto n : FILE_NAMES) {
+            auto name = std::string(n);
+            auto path = std::string(mEmptyDir.path) + "/" + name;
+            setenv(name.c_str(), path.c_str(), true);
+        }
+        mNoApi = std::make_unique<HwApi>();
+    }
+
+    void TearDown() override { verifyContents(); }
+
+  protected:
+    // Set expected file content for a test.
+    template <typename T>
+    void expectContent(const std::string &name, const T &value) {
+        mExpectedContent[name] << value << std::endl;
+    }
+
+    // Set actual file content for an input test.
+    template <typename T>
+    void updateContent(const std::string &name, const T &value) {
+        std::ofstream(mFileMap[name]) << value << std::endl;
+    }
+
+    template <typename T>
+    void expectAndUpdateContent(const std::string &name, const T &value) {
+        expectContent(name, value);
+        updateContent(name, value);
+    }
+
+    // Compare all file contents against expected contents.
+    void verifyContents() {
+        for (auto &a : mFileMap) {
+            std::ifstream file{a.second};
+            std::string expect = mExpectedContent[a.first].str();
+            std::string actual = std::string(std::istreambuf_iterator<char>(file),
+                                             std::istreambuf_iterator<char>());
+            EXPECT_EQ(expect, actual) << a.first;
+        }
+    }
+
+  protected:
+    std::unique_ptr<Vibrator::HwApi> mHwApi;
+    std::unique_ptr<Vibrator::HwApi> mNoApi;
+    std::map<std::string, std::string> mFileMap;
+    TemporaryDir mFilesDir;
+    TemporaryDir mEmptyDir;
+    std::map<std::string, std::stringstream> mExpectedContent;
+};
+
+template <typename T>
+class HwApiTypedTest
+    : public HwApiTest,
+      public testing::WithParamInterface<std::tuple<std::string, std::function<T>>> {
+  public:
+    static auto PrintParam(const testing::TestParamInfo<typename HwApiTypedTest::ParamType> &info) {
+        return std::get<0>(info.param);
+    };
+    static auto MakeParam(std::string name, std::function<T> func) {
+        return std::make_tuple(name, func);
+    }
+};
+
+using HasTest = HwApiTypedTest<bool(Vibrator::HwApi &)>;
+
+TEST_P(HasTest, success_returnsTrue) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+
+    EXPECT_TRUE(func(*mHwApi));
+}
+
+TEST_P(HasTest, success_returnsFalse) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+
+    EXPECT_FALSE(func(*mNoApi));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, HasTest,
+                        ValuesIn({
+                            HasTest::MakeParam("EFFECT_SCALE_PATH",
+                                               &Vibrator::HwApi::hasEffectScale),
+                            HasTest::MakeParam("ASP_ENABLE_PATH", &Vibrator::HwApi::hasAspEnable),
+                        }),
+                        HasTest::PrintParam);
+
+using GetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool *)>;
+
+TEST_P(GetBoolTest, success_returnsTrue) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    bool expect = true;
+    bool actual = !expect;
+
+    expectAndUpdateContent(name, "1");
+
+    EXPECT_TRUE(func(*mHwApi, &actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_P(GetBoolTest, success_returnsFalse) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    bool expect = false;
+    bool actual = !expect;
+
+    expectAndUpdateContent(name, "0");
+
+    EXPECT_TRUE(func(*mHwApi, &actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_P(GetBoolTest, failure) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+    bool value;
+
+    EXPECT_FALSE(func(*mNoApi, &value));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, GetBoolTest,
+                        ValuesIn({
+                            GetBoolTest::MakeParam("ASP_ENABLE_PATH",
+                                                   &Vibrator::HwApi::getAspEnable),
+                        }),
+                        GetBoolTest::PrintParam);
+
+using GetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t *)>;
+
+TEST_P(GetUint32Test, success) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    expectAndUpdateContent(name, expect);
+
+    EXPECT_TRUE(func(*mHwApi, &actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_P(GetUint32Test, failure) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+    uint32_t value;
+
+    EXPECT_FALSE(func(*mNoApi, &value));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, GetUint32Test,
+                        ValuesIn({
+                            GetUint32Test::MakeParam("EFFECT_DURATION_PATH",
+                                                     &Vibrator::HwApi::getEffectDuration),
+                        }),
+                        GetUint32Test::PrintParam);
+
+using SetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool)>;
+
+TEST_P(SetBoolTest, success_returnsTrue) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+
+    expectContent(name, "1");
+
+    EXPECT_TRUE(func(*mHwApi, true));
+}
+
+TEST_P(SetBoolTest, success_returnsFalse) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+
+    expectContent(name, "0");
+
+    EXPECT_TRUE(func(*mHwApi, false));
+}
+
+TEST_P(SetBoolTest, failure) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+
+    EXPECT_FALSE(func(*mNoApi, true));
+    EXPECT_FALSE(func(*mNoApi, false));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetBoolTest,
+                        ValuesIn({
+                            SetBoolTest::MakeParam("ACTIVATE_PATH", &Vibrator::HwApi::setActivate),
+                            SetBoolTest::MakeParam("STATE_PATH", &Vibrator::HwApi::setState),
+                            SetBoolTest::MakeParam("ASP_ENABLE_PATH",
+                                                   &Vibrator::HwApi::setAspEnable),
+                        }),
+                        SetBoolTest::PrintParam);
+
+using SetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t)>;
+
+TEST_P(SetUint32Test, success) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    uint32_t value = std::rand();
+
+    expectContent(name, value);
+
+    EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetUint32Test, failure) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+    uint32_t value = std::rand();
+
+    EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    HwApiTests, SetUint32Test,
+    ValuesIn({
+        SetUint32Test::MakeParam("F0_FILEPATH", &Vibrator::HwApi::setF0),
+        SetUint32Test::MakeParam("REDC_FILEPATH", &Vibrator::HwApi::setRedc),
+        SetUint32Test::MakeParam("Q_FILEPATH", &Vibrator::HwApi::setQ),
+        SetUint32Test::MakeParam("DURATION_PATH", &Vibrator::HwApi::setDuration),
+        SetUint32Test::MakeParam("EFFECT_INDEX_PATH", &Vibrator::HwApi::setEffectIndex),
+        SetUint32Test::MakeParam("EFFECT_SCALE_PATH", &Vibrator::HwApi::setEffectScale),
+        SetUint32Test::MakeParam("GLOBAL_SCALE_PATH", &Vibrator::HwApi::setGlobalScale),
+        SetUint32Test::MakeParam("GPIO_FALL_INDEX", &Vibrator::HwApi::setGpioFallIndex),
+        SetUint32Test::MakeParam("GPIO_FALL_SCALE", &Vibrator::HwApi::setGpioFallScale),
+        SetUint32Test::MakeParam("GPIO_RISE_INDEX", &Vibrator::HwApi::setGpioRiseIndex),
+        SetUint32Test::MakeParam("GPIO_RISE_SCALE", &Vibrator::HwApi::setGpioRiseScale),
+    }),
+    SetUint32Test::PrintParam);
+
+using SetStringTest = HwApiTypedTest<bool(Vibrator::HwApi &, std::string)>;
+
+TEST_P(SetStringTest, success) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    std::string value = TemporaryFile().path;
+
+    expectContent(name, value);
+
+    EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetStringTest, failure) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+    std::string value = TemporaryFile().path;
+
+    EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetStringTest,
+                        ValuesIn({
+                            SetStringTest::MakeParam("EFFECT_QUEUE_PATH",
+                                                     &Vibrator::HwApi::setEffectQueue),
+                        }),
+                        SetStringTest::PrintParam);
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/tests/test-hwcal.cpp b/vibrator/tests/test-hwcal.cpp
new file mode 100644
index 0000000..d2d5043
--- /dev/null
+++ b/vibrator/tests/test-hwcal.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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.vibrator@1.3-tests.bramble"
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+#include "Hardware.h"
+
+using namespace ::testing;
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+class HwCalTest : public Test {
+  protected:
+    static constexpr uint32_t Q_DEFAULT = 15.5f * (1 << 16);
+    static constexpr std::array<uint32_t, 6> V_DEFAULT = {60, 70, 80, 90, 100, 76};
+
+  public:
+    void SetUp() override { setenv("CALIBRATION_FILEPATH", mCalFile.path, true); }
+
+  private:
+    static void pack(std::ostream &stream, const uint32_t &value, std::string lpad,
+                     std::string rpad) {
+        stream << lpad << value << rpad;
+    }
+
+    template <typename T, typename std::array<T, 0>::size_type N>
+    static void pack(std::ostream &stream, const std::array<T, N> &value, std::string lpad,
+                     std::string rpad) {
+        for (auto &entry : value) {
+            pack(stream, entry, lpad, rpad);
+        }
+    }
+
+  protected:
+    void createHwCal() { mHwCal = std::make_unique<HwCal>(); }
+
+    template <typename T>
+    void write(const std::string key, const T &value, std::string lpad = " ",
+               std::string rpad = "") {
+        std::ofstream calfile{mCalFile.path, std::ios_base::app};
+        calfile << key << ":";
+        pack(calfile, value, lpad, rpad);
+        calfile << std::endl;
+    }
+
+    void unlink() { ::unlink(mCalFile.path); }
+
+  protected:
+    std::unique_ptr<Vibrator::HwCal> mHwCal;
+    TemporaryFile mCalFile;
+};
+
+TEST_F(HwCalTest, f0_measured) {
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    write("f0_measured", expect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getF0(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, f0_missing) {
+    uint32_t actual;
+
+    createHwCal();
+
+    EXPECT_FALSE(mHwCal->getF0(&actual));
+}
+
+TEST_F(HwCalTest, redc_measured) {
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    write("redc_measured", expect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getRedc(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, redc_missing) {
+    uint32_t actual;
+
+    createHwCal();
+
+    EXPECT_FALSE(mHwCal->getRedc(&actual));
+}
+
+TEST_F(HwCalTest, q_measured) {
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    write("q_measured", expect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getQ(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, q_index) {
+    uint8_t value = std::rand();
+    uint32_t expect = value * 1.5f * (1 << 16) + 2.0f * (1 << 16);
+    uint32_t actual = ~expect;
+
+    write("q_index", value);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getQ(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, q_missing) {
+    uint32_t expect = Q_DEFAULT;
+    uint32_t actual = ~expect;
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getQ(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, q_nofile) {
+    uint32_t expect = Q_DEFAULT;
+    uint32_t actual = ~expect;
+
+    write("q_measured", actual);
+    unlink();
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getQ(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, v_levels) {
+    std::array<uint32_t, 6> expect;
+    std::array<uint32_t, 6> actual;
+
+    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) {
+        e = std::rand();
+        return ~e;
+    });
+
+    write("v_levels", expect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, v_missing) {
+    std::array<uint32_t, 6> expect = V_DEFAULT;
+    std::array<uint32_t, 6> actual;
+
+    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, v_short) {
+    std::array<uint32_t, 6> expect = V_DEFAULT;
+    std::array<uint32_t, 6> actual;
+
+    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
+
+    write("v_levels", std::array<uint32_t, expect.size() - 1>());
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, v_long) {
+    std::array<uint32_t, 6> expect = V_DEFAULT;
+    std::array<uint32_t, 6> actual;
+
+    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
+
+    write("v_levels", std::array<uint32_t, expect.size() + 1>());
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, v_nofile) {
+    std::array<uint32_t, 6> expect = V_DEFAULT;
+    std::array<uint32_t, 6> actual;
+
+    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
+
+    write("v_levels", actual);
+    unlink();
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, multiple) {
+    uint32_t f0Expect = std::rand();
+    uint32_t f0Actual = ~f0Expect;
+    uint32_t redcExpect = std::rand();
+    uint32_t redcActual = ~redcExpect;
+    uint32_t qExpect = std::rand();
+    uint32_t qActual = ~qExpect;
+    std::array<uint32_t, 6> volExpect;
+    std::array<uint32_t, 6> volActual;
+
+    std::transform(volExpect.begin(), volExpect.end(), volActual.begin(), [](uint32_t &e) {
+        e = std::rand();
+        return ~e;
+    });
+
+    write("f0_measured", f0Expect);
+    write("redc_measured", redcExpect);
+    write("q_measured", qExpect);
+    write("v_levels", volExpect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getF0(&f0Actual));
+    EXPECT_EQ(f0Expect, f0Actual);
+    EXPECT_TRUE(mHwCal->getRedc(&redcActual));
+    EXPECT_EQ(redcExpect, redcActual);
+    EXPECT_TRUE(mHwCal->getQ(&qActual));
+    EXPECT_EQ(qExpect, qActual);
+    EXPECT_TRUE(mHwCal->getVolLevels(&volActual));
+    EXPECT_EQ(volExpect, volActual);
+}
+
+TEST_F(HwCalTest, trimming) {
+    uint32_t f0Expect = std::rand();
+    uint32_t f0Actual = ~f0Expect;
+    uint32_t redcExpect = std::rand();
+    uint32_t redcActual = ~redcExpect;
+    uint32_t qExpect = std::rand();
+    uint32_t qActual = ~qExpect;
+    std::array<uint32_t, 6> volExpect;
+    std::array<uint32_t, 6> volActual;
+
+    std::transform(volExpect.begin(), volExpect.end(), volActual.begin(), [](uint32_t &e) {
+        e = std::rand();
+        return ~e;
+    });
+
+    write("f0_measured", f0Expect, " \t", "\t ");
+    write("redc_measured", redcExpect, " \t", "\t ");
+    write("q_measured", qExpect, " \t", "\t ");
+    write("v_levels", volExpect, " \t", "\t ");
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getF0(&f0Actual));
+    EXPECT_EQ(f0Expect, f0Actual);
+    EXPECT_TRUE(mHwCal->getRedc(&redcActual));
+    EXPECT_EQ(redcExpect, redcActual);
+    EXPECT_TRUE(mHwCal->getQ(&qActual));
+    EXPECT_EQ(qExpect, qActual);
+    EXPECT_TRUE(mHwCal->getVolLevels(&volActual));
+    EXPECT_EQ(volExpect, volActual);
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/tests/test-vibrator.cpp b/vibrator/tests/test-vibrator.cpp
new file mode 100644
index 0000000..bcf2654
--- /dev/null
+++ b/vibrator/tests/test-vibrator.cpp
@@ -0,0 +1,464 @@
+/*
+ * 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 "PtsVibratorHalBrambleTestSuite"
+
+#include <android-base/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "Vibrator.h"
+#include "mocks.h"
+#include "types.h"
+#include "utils.h"
+
+using namespace ::testing;
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_0::Status;
+
+// Forward Declarations
+
+static EffectQueue Queue(const QueueEffect &effect);
+static EffectQueue Queue(const QueueDelay &delay);
+template <typename T, typename U, typename... Args>
+static EffectQueue Queue(const T &first, const U &second, Args... rest);
+
+// Constants With Arbitrary Values
+
+static constexpr std::array<EffectLevel, 6> V_LEVELS{40, 50, 60, 70, 80, 90};
+static constexpr EffectDuration EFFECT_DURATION{15};
+
+// Constants With Prescribed Values
+
+static constexpr EffectIndex EFFECT_INDEX{2};
+static constexpr EffectIndex QUEUE_INDEX{65534};
+
+static constexpr EffectIndex GPIO_FALL_INDEX{EFFECT_INDEX};
+static const EffectScale GPIO_FALL_SCALE{levelToScale(V_LEVELS[2])};
+static constexpr EffectIndex GPIO_RISE_INDEX{EFFECT_INDEX};
+static const EffectScale GPIO_RISE_SCALE{levelToScale(V_LEVELS[3])};
+
+static const EffectScale ON_GLOBAL_SCALE{levelToScale(V_LEVELS[5])};
+static const EffectIndex ON_EFFECT_INDEX{0};
+
+static const std::map<EffectTuple, EffectScale> EFFECT_SCALE{
+    {{Effect::CLICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[1])},
+    {{Effect::CLICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[2])},
+    {{Effect::CLICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[3])},
+    {{Effect::TICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[1])},
+    {{Effect::TICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[1])},
+    {{Effect::TICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[1])},
+    {{Effect::HEAVY_CLICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[2])},
+    {{Effect::HEAVY_CLICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[3])},
+    {{Effect::HEAVY_CLICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[4])},
+    {{Effect::TEXTURE_TICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[0])},
+    {{Effect::TEXTURE_TICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[0])},
+    {{Effect::TEXTURE_TICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[0])},
+};
+
+static const std::map<EffectTuple, EffectQueue> EFFECT_QUEUE{
+    {{Effect::DOUBLE_CLICK, EffectStrength::LIGHT},
+     Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[1]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[2]})},
+    {{Effect::DOUBLE_CLICK, EffectStrength::MEDIUM},
+     Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[2]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[3]})},
+    {{Effect::DOUBLE_CLICK, EffectStrength::STRONG},
+     Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[3]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[4]})},
+};
+
+EffectQueue Queue(const QueueEffect &effect) {
+    auto index = std::get<0>(effect);
+    auto level = std::get<1>(effect);
+    auto string = std::to_string(index) + "." + std::to_string(level);
+    auto duration = EFFECT_DURATION;
+    return {string, duration};
+}
+
+EffectQueue Queue(const QueueDelay &delay) {
+    auto string = std::to_string(delay);
+    return {string, delay};
+}
+
+template <typename T, typename U, typename... Args>
+EffectQueue Queue(const T &first, const U &second, Args... rest) {
+    auto head = Queue(first);
+    auto tail = Queue(second, rest...);
+    auto string = std::get<0>(head) + "," + std::get<0>(tail);
+    auto duration = std::get<1>(head) + std::get<1>(tail);
+    return {string, duration};
+}
+
+class VibratorTest : public Test, public WithParamInterface<EffectTuple> {
+  public:
+    void SetUp() override {
+        std::unique_ptr<MockApi> mockapi;
+        std::unique_ptr<MockCal> mockcal;
+
+        createMock(&mockapi, &mockcal);
+        createVibrator(std::move(mockapi), std::move(mockcal));
+    }
+
+    void TearDown() override { deleteVibrator(); }
+
+  protected:
+    void createMock(std::unique_ptr<MockApi> *mockapi, std::unique_ptr<MockCal> *mockcal) {
+        *mockapi = std::make_unique<MockApi>();
+        *mockcal = std::make_unique<MockCal>();
+
+        mMockApi = mockapi->get();
+        mMockCal = mockcal->get();
+
+        ON_CALL(*mMockApi, destructor()).WillByDefault(Assign(&mMockApi, nullptr));
+
+        ON_CALL(*mMockApi, getEffectDuration(_))
+            .WillByDefault(
+                DoAll(SetArgPointee<0>(msToCycles(EFFECT_DURATION)), ::testing::Return(true)));
+
+        ON_CALL(*mMockCal, destructor()).WillByDefault(Assign(&mMockCal, nullptr));
+
+        ON_CALL(*mMockCal, getVolLevels(_))
+            .WillByDefault(DoAll(SetArgPointee<0>(V_LEVELS), ::testing::Return(true)));
+
+        relaxMock(false);
+    }
+
+    void createVibrator(std::unique_ptr<MockApi> mockapi, std::unique_ptr<MockCal> mockcal,
+                        bool relaxed = true) {
+        std::vector<uint32_t> vlevels{std::begin(V_LEVELS), std::end(V_LEVELS)};
+        if (relaxed) {
+            relaxMock(true);
+        }
+        mVibrator = new Vibrator(std::move(mockapi), std::move(mockcal));
+        if (relaxed) {
+            relaxMock(false);
+        }
+    }
+
+    void deleteVibrator(bool relaxed = true) {
+        if (relaxed) {
+            relaxMock(true);
+        }
+        mVibrator.clear();
+    }
+
+  private:
+    void relaxMock(bool relax) {
+        auto times = relax ? AnyNumber() : Exactly(0);
+
+        Mock::VerifyAndClearExpectations(mMockApi);
+        Mock::VerifyAndClearExpectations(mMockCal);
+
+        EXPECT_CALL(*mMockApi, destructor()).Times(times);
+        EXPECT_CALL(*mMockApi, setF0(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setRedc(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setQ(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setActivate(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setDuration(_)).Times(times);
+        EXPECT_CALL(*mMockApi, getEffectDuration(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setEffectIndex(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setEffectQueue(_)).Times(times);
+        EXPECT_CALL(*mMockApi, hasEffectScale()).Times(times);
+        EXPECT_CALL(*mMockApi, setEffectScale(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setGlobalScale(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setState(_)).Times(times);
+        EXPECT_CALL(*mMockApi, hasAspEnable()).Times(times);
+        EXPECT_CALL(*mMockApi, getAspEnable(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setAspEnable(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setGpioFallIndex(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setGpioFallScale(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setGpioRiseIndex(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setGpioRiseScale(_)).Times(times);
+        EXPECT_CALL(*mMockApi, debug(_)).Times(times);
+
+        EXPECT_CALL(*mMockCal, destructor()).Times(times);
+        EXPECT_CALL(*mMockCal, getF0(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getRedc(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getQ(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getVolLevels(_)).Times(times);
+        EXPECT_CALL(*mMockApi, debug(_)).Times(times);
+    }
+
+  protected:
+    MockApi *mMockApi;
+    MockCal *mMockCal;
+    sp<IVibrator> mVibrator;
+};
+
+TEST_F(VibratorTest, HwApi) {
+    std::unique_ptr<MockApi> mockapi;
+    std::unique_ptr<MockCal> mockcal;
+    uint32_t f0Val = std::rand();
+    uint32_t redcVal = std::rand();
+    uint32_t qVal = std::rand();
+    Expectation volGet;
+    Sequence f0Seq, redcSeq, qSeq, volSeq, durSeq;
+
+    EXPECT_CALL(*mMockApi, destructor()).WillOnce(DoDefault());
+    EXPECT_CALL(*mMockCal, destructor()).WillOnce(DoDefault());
+
+    deleteVibrator(false);
+
+    createMock(&mockapi, &mockcal);
+
+    EXPECT_CALL(*mMockCal, getF0(_))
+        .InSequence(f0Seq)
+        .WillOnce(DoAll(SetArgPointee<0>(f0Val), ::testing::Return(true)));
+    EXPECT_CALL(*mMockApi, setF0(f0Val)).InSequence(f0Seq).WillOnce(::testing::Return(true));
+
+    EXPECT_CALL(*mMockCal, getRedc(_))
+        .InSequence(redcSeq)
+        .WillOnce(DoAll(SetArgPointee<0>(redcVal), ::testing::Return(true)));
+    EXPECT_CALL(*mMockApi, setRedc(redcVal)).InSequence(redcSeq).WillOnce(::testing::Return(true));
+
+    EXPECT_CALL(*mMockCal, getQ(_))
+        .InSequence(qSeq)
+        .WillOnce(DoAll(SetArgPointee<0>(qVal), ::testing::Return(true)));
+    EXPECT_CALL(*mMockApi, setQ(qVal)).InSequence(qSeq).WillOnce(::testing::Return(true));
+
+    volGet = EXPECT_CALL(*mMockCal, getVolLevels(_)).WillOnce(DoDefault());
+
+    EXPECT_CALL(*mMockApi, setState(true)).WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setEffectIndex(EFFECT_INDEX))
+        .InSequence(durSeq)
+        .WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, getEffectDuration(_)).InSequence(durSeq).WillOnce(DoDefault());
+
+    EXPECT_CALL(*mMockApi, setGpioFallIndex(GPIO_FALL_INDEX)).WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setGpioFallScale(GPIO_FALL_SCALE))
+        .After(volGet)
+        .WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setGpioRiseIndex(GPIO_RISE_INDEX)).WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setGpioRiseScale(GPIO_RISE_SCALE))
+        .After(volGet)
+        .WillOnce(::testing::Return(true));
+
+    createVibrator(std::move(mockapi), std::move(mockcal), false);
+}
+
+TEST_F(VibratorTest, on) {
+    Sequence s1, s2, s3;
+    uint16_t duration = std::rand() + 1;
+
+    EXPECT_CALL(*mMockApi, setGlobalScale(ON_GLOBAL_SCALE))
+        .InSequence(s1)
+        .WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setEffectIndex(ON_EFFECT_INDEX))
+        .InSequence(s2)
+        .WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
+        .InSequence(s3)
+        .WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setActivate(true))
+        .InSequence(s1, s2, s3)
+        .WillOnce(::testing::Return(true));
+
+    EXPECT_EQ(Status::OK, mVibrator->on(duration));
+}
+
+TEST_F(VibratorTest, off) {
+    EXPECT_CALL(*mMockApi, setActivate(false)).WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setGlobalScale(0)).WillOnce(::testing::Return(true));
+
+    EXPECT_EQ(Status::OK, mVibrator->off());
+}
+
+TEST_F(VibratorTest, supportsAmplitudeControl_supported) {
+    EXPECT_CALL(*mMockApi, hasEffectScale()).WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, getAspEnable(_))
+        .WillOnce(DoAll(SetArgPointee<0>(false), ::testing::Return(true)));
+
+    EXPECT_EQ(true, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_F(VibratorTest, supportsAmplitudeControl_unsupported1) {
+    MockFunction<void()> either;
+
+    EXPECT_CALL(*mMockApi, hasEffectScale())
+        .Times(AtMost(1))
+        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
+                        ::testing::Return(false)));
+    EXPECT_CALL(*mMockApi, getAspEnable(_))
+        .Times(AtMost(1))
+        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
+                        SetArgPointee<0>(false), ::testing::Return(true)));
+    EXPECT_CALL(either, Call()).Times(AtLeast(1));
+
+    EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_F(VibratorTest, supportsAmplitudeControl_unsupported2) {
+    MockFunction<void()> either;
+
+    EXPECT_CALL(*mMockApi, hasEffectScale())
+        .Times(AtMost(1))
+        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
+                        ::testing::Return(false)));
+    EXPECT_CALL(*mMockApi, getAspEnable(_))
+        .Times(AtMost(1))
+        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
+                        SetArgPointee<0>(true), ::testing::Return(true)));
+    EXPECT_CALL(either, Call()).Times(AtLeast(1));
+
+    EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_F(VibratorTest, supportsAmplitudeControl_unsupported3) {
+    MockFunction<void()> either;
+
+    EXPECT_CALL(*mMockApi, hasEffectScale())
+        .Times(AtMost(1))
+        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
+                        ::testing::Return(true)));
+    EXPECT_CALL(*mMockApi, getAspEnable(_))
+        .Times(AtMost(1))
+        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
+                        SetArgPointee<0>(true), ::testing::Return(true)));
+    EXPECT_CALL(either, Call()).Times(AtLeast(1));
+
+    EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_F(VibratorTest, setAmplitude_supported) {
+    Sequence s;
+    EffectAmplitude amplitude = std::rand() + 1;
+
+    EXPECT_CALL(*mMockApi, getAspEnable(_))
+        .InSequence(s)
+        .WillOnce(DoAll(SetArgPointee<0>(false), ::testing::Return(true)));
+    EXPECT_CALL(*mMockApi, setEffectScale(amplitudeToScale(amplitude)))
+        .InSequence(s)
+        .WillOnce(::testing::Return(true));
+
+    EXPECT_EQ(Status::OK, mVibrator->setAmplitude(amplitude));
+}
+
+TEST_F(VibratorTest, setAmplitude_unsupported) {
+    EXPECT_CALL(*mMockApi, getAspEnable(_))
+        .WillOnce(DoAll(SetArgPointee<0>(true), ::testing::Return(true)));
+
+    EXPECT_EQ(Status::UNSUPPORTED_OPERATION, mVibrator->setAmplitude(1));
+}
+
+TEST_F(VibratorTest, supportsExternalControl_supported) {
+    EXPECT_CALL(*mMockApi, hasAspEnable()).WillOnce(::testing::Return(true));
+
+    EXPECT_EQ(true, mVibrator->supportsExternalControl());
+}
+
+TEST_F(VibratorTest, supportsExternalControl_unsupported) {
+    EXPECT_CALL(*mMockApi, hasAspEnable()).WillOnce(::testing::Return(false));
+
+    EXPECT_EQ(false, mVibrator->supportsExternalControl());
+}
+
+TEST_F(VibratorTest, setExternalControl_enable) {
+    Sequence s;
+
+    EXPECT_CALL(*mMockApi, setGlobalScale(ON_GLOBAL_SCALE))
+        .InSequence(s)
+        .WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setAspEnable(true)).InSequence(s).WillOnce(::testing::Return(true));
+
+    EXPECT_EQ(Status::OK, mVibrator->setExternalControl(true));
+}
+
+TEST_F(VibratorTest, setExternalControl_disable) {
+    EXPECT_CALL(*mMockApi, setAspEnable(false)).WillOnce(::testing::Return(true));
+    EXPECT_CALL(*mMockApi, setGlobalScale(0)).WillOnce(::testing::Return(true));
+
+    EXPECT_EQ(Status::OK, mVibrator->setExternalControl(false));
+}
+
+TEST_P(VibratorTest, perform) {
+    auto param = GetParam();
+    auto effect = std::get<0>(param);
+    auto strength = std::get<1>(param);
+    auto scale = EFFECT_SCALE.find(param);
+    auto queue = EFFECT_QUEUE.find(param);
+    EffectDuration duration;
+
+    if (scale != EFFECT_SCALE.end()) {
+        Sequence s1, s2, s3;
+
+        duration = EFFECT_DURATION;
+
+        EXPECT_CALL(*mMockApi, setEffectIndex(EFFECT_INDEX))
+            .InSequence(s1)
+            .WillOnce(::testing::Return(true));
+        EXPECT_CALL(*mMockApi, setEffectScale(scale->second))
+            .InSequence(s2)
+            .WillOnce(::testing::Return(true));
+        EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
+            .InSequence(s3)
+            .WillOnce(::testing::Return(true));
+
+        EXPECT_CALL(*mMockApi, setActivate(true))
+            .InSequence(s1, s2, s3)
+            .WillOnce(::testing::Return(true));
+    } else if (queue != EFFECT_QUEUE.end()) {
+        Sequence s1, s2, s3;
+
+        duration = std::get<1>(queue->second);
+
+        EXPECT_CALL(*mMockApi, setEffectIndex(QUEUE_INDEX))
+            .InSequence(s1)
+            .WillOnce(::testing::Return(true));
+        EXPECT_CALL(*mMockApi, setEffectQueue(std::get<0>(queue->second)))
+            .InSequence(s2)
+            .WillOnce(::testing::Return(true));
+        EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
+            .InSequence(s3)
+            .WillOnce(::testing::Return(true));
+
+        EXPECT_CALL(*mMockApi, setActivate(true))
+            .InSequence(s1, s2, s3)
+            .WillOnce(::testing::Return(true));
+    } else {
+        duration = 0;
+    }
+
+    mVibrator->perform_1_3(effect, strength, [&](Status status, uint32_t lengthMs) {
+        if (duration) {
+            EXPECT_EQ(Status::OK, status);
+            EXPECT_LE(duration, lengthMs);
+        } else {
+            EXPECT_EQ(Status::UNSUPPORTED_OPERATION, status);
+            EXPECT_EQ(0, lengthMs);
+        }
+    });
+}
+
+INSTANTIATE_TEST_CASE_P(VibratorEffects, VibratorTest,
+                        Combine(ValuesIn(hidl_enum_range<Effect>().begin(),
+                                         hidl_enum_range<Effect>().end()),
+                                ValuesIn(hidl_enum_range<EffectStrength>().begin(),
+                                         hidl_enum_range<EffectStrength>().end())),
+                        [](const testing::TestParamInfo<VibratorTest::ParamType> &info) {
+                            auto effect = std::get<0>(info.param);
+                            auto strength = std::get<1>(info.param);
+                            return toString(effect) + "_" + toString(strength);
+                        });
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/tests/types.h b/vibrator/tests/types.h
new file mode 100644
index 0000000..94535c2
--- /dev/null
+++ b/vibrator/tests/types.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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H
+#define ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+
+using EffectIndex = uint16_t;
+using EffectLevel = uint32_t;
+using EffectAmplitude = uint8_t;
+using EffectScale = uint16_t;
+using EffectDuration = uint32_t;
+using EffectQueue = std::tuple<std::string, EffectDuration>;
+using EffectTuple = std::tuple<::android::hardware::vibrator::V1_3::Effect,
+                               ::android::hardware::vibrator::V1_0::EffectStrength>;
+
+using QueueEffect = std::tuple<EffectIndex, EffectLevel>;
+using QueueDelay = uint32_t;
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H
diff --git a/vibrator/tests/utils.h b/vibrator/tests/utils.h
new file mode 100644
index 0000000..86cb944
--- /dev/null
+++ b/vibrator/tests/utils.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
+#define ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
+
+#include <cmath>
+
+#include "types.h"
+
+static inline EffectScale toScale(uint8_t target, uint8_t maximum) {
+    return std::round((-20 * std::log10(target / static_cast<float>(maximum))) / 0.125f);
+}
+
+static inline EffectScale levelToScale(EffectLevel level) {
+    return toScale(level, 100);
+}
+
+static inline EffectScale amplitudeToScale(EffectAmplitude amplitude) {
+    return toScale(amplitude, UINT8_MAX);
+}
+
+static inline uint32_t msToCycles(EffectDuration ms) {
+    return ms * 48;
+}
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
diff --git a/vibrator/utils.h b/vibrator/utils.h
new file mode 100644
index 0000000..078310e
--- /dev/null
+++ b/vibrator/utils.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_UTILS_H
+#define ANDROID_HARDWARE_VIBRATOR_UTILS_H
+
+template <typename T>
+class Is_Iterable {
+  private:
+    template <typename U>
+    static std::true_type test(typename U::iterator *u);
+
+    template <typename U>
+    static std::false_type test(U *u);
+
+  public:
+    static const bool value = decltype(test<T>(0))::value;
+};
+
+template <typename T, bool B>
+using Enable_If_Iterable = std::enable_if_t<Is_Iterable<T>::value == B>;
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_UTILS_H
diff --git a/voice_processing/Android.mk b/voice_processing/Android.mk
new file mode 100644
index 0000000..674881f
--- /dev/null
+++ b/voice_processing/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := voice_processing_descriptors.c
+LOCAL_C_INCLUDES += $(call include-path-for, audio-effects)
+LOCAL_HEADER_LIBRARIES := libhardware_headers
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+LOCAL_MODULE := libqcomvoiceprocessingdescriptors
+LOCAL_MODULE_RELATIVE_PATH := soundfx
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := qcom
+LOCAL_PROPRIETARY_MODULE := true
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/voice_processing/voice_processing_descriptors.c b/voice_processing/voice_processing_descriptors.c
new file mode 100644
index 0000000..3d3746d
--- /dev/null
+++ b/voice_processing/voice_processing_descriptors.c
@@ -0,0 +1,47 @@
+/*
+ * 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 <hardware/audio_effect.h>
+//------------------------------------------------------------------------------
+// Effect descriptors
+//------------------------------------------------------------------------------
+
+// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
+// as the pre processing effects are not defined by OpenSL ES
+
+// Acoustic Echo Cancellation 27dab416-23f8-11e8-b467-0ed5f89f718b
+const effect_descriptor_t qcom_product_aec_descriptor = {
+        { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+        { 0x27dab416, 0x23f8, 0x11e8, 0xb467, { 0x0e, 0xd5, 0xf8, 0x9f, 0x71, 0x8b } }, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND|EFFECT_FLAG_HW_ACC_TUNNEL),
+        0,
+        0,
+        "Acoustic Echo Canceler",
+        "Qualcomm AEC for Bramble"
+};
+
+// Noise suppression 27dab6d2-23f8-11e8-b467-0ed5f89f718b
+const effect_descriptor_t qcom_product_ns_descriptor = {
+        { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+        { 0x27dab6d2, 0x23f8, 0x11e8, 0xb467, { 0x0e, 0xd5, 0xf8, 0x9f, 0x71, 0x8b } }, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND|EFFECT_FLAG_HW_ACC_TUNNEL),
+        0,
+        0,
+        "Noise Suppression",
+        "Qualcomm NS for Bramble"
+};
diff --git a/wifi_concurrency_cfg.txt b/wifi_concurrency_cfg.txt
new file mode 100644
index 0000000..fa2764c
--- /dev/null
+++ b/wifi_concurrency_cfg.txt
@@ -0,0 +1,3 @@
+ENABLE_STA_SAP_CONCURRENCY:1
+SAP_INTERFACE_NAME:softap0
+SAP_CHANNEL:6
diff --git a/wpa_supplicant_overlay.conf b/wpa_supplicant_overlay.conf
new file mode 100644
index 0000000..532638b
--- /dev/null
+++ b/wpa_supplicant_overlay.conf
@@ -0,0 +1,8 @@
+disable_scan_offload=1
+p2p_disabled=1
+tdls_external_control=1
+wowlan_triggers=magic_pkt
+bss_max_count=512
+interworking=1
+hs20=1
+auto_interworking=0
diff --git a/wpa_supplicant_wcn.conf b/wpa_supplicant_wcn.conf
new file mode 100644
index 0000000..287954e
--- /dev/null
+++ b/wpa_supplicant_wcn.conf
@@ -0,0 +1,830 @@
+##### Example wpa_supplicant configuration file ###############################
+#
+# This file describes configuration file format and lists all available option.
+# Please also take a look at simpler configuration examples in 'examples'
+# subdirectory.
+#
+# Empty lines and lines starting with # are ignored
+
+# NOTE! This file may contain password information and should probably be made
+# readable only by root user on multiuser systems.
+
+# Note: All file paths in this configuration file should use full (absolute,
+# not relative to working directory) path in order to allow working directory
+# to be changed. This can happen if wpa_supplicant is run in the background.
+
+# Whether to allow wpa_supplicant to update (overwrite) configuration
+#
+# This option can be used to allow wpa_supplicant to overwrite configuration
+# file whenever configuration is changed (e.g., new network block is added with
+# wpa_cli or wpa_gui, or a password is changed). This is required for
+# wpa_cli/wpa_gui to be able to store the configuration changes permanently.
+# Please note that overwriting configuration file will remove the comments from
+# it.
+update_config=1
+
+# global configuration (shared by all network blocks)
+#
+# Parameters for the control interface. If this is specified, wpa_supplicant
+# will open a control interface that is available for external programs to
+# manage wpa_supplicant. The meaning of this string depends on which control
+# interface mechanism is used. For all cases, the existance of this parameter
+# in configuration is used to determine whether the control interface is
+# enabled.
+#
+# For UNIX domain sockets (default on Linux and BSD): This is a directory that
+# will be created for UNIX domain sockets for listening to requests from
+# external programs (CLI/GUI, etc.) for status information and configuration.
+# The socket file will be named based on the interface name, so multiple
+# wpa_supplicant processes can be run at the same time if more than one
+# interface is used.
+# /var/run/wpa_supplicant is the recommended directory for sockets and by
+# default, wpa_cli will use it when trying to connect with wpa_supplicant.
+#
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run wpa_supplicant as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, wpa_supplicant is configured to use gid 0 (root). If you
+# want to allow non-root users to use the control interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group. If this variable is commented out or
+# not included in the configuration file, group will not be changed from the
+# value it got by default when the directory or socket was created.
+#
+# When configuring both the directory and group, use following format:
+# DIR=/var/run/wpa_supplicant GROUP=wheel
+# DIR=/var/run/wpa_supplicant GROUP=0
+# (group can be either group name or gid)
+ctrl_interface=wlan0
+
+# IEEE 802.1X/EAPOL version
+# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
+# EAPOL version 2. However, there are many APs that do not handle the new
+# version number correctly (they seem to drop the frames completely). In order
+# to make wpa_supplicant interoperate with these APs, the version number is set
+# to 1 by default. This configuration value can be used to set it to the new
+# version (2).
+eapol_version=1
+
+# AP scanning/selection
+# By default, wpa_supplicant requests driver to perform AP scanning and then
+# uses the scan results to select a suitable AP. Another alternative is to
+# allow the driver to take care of AP scanning and selection and use
+# wpa_supplicant just to process EAPOL frames based on IEEE 802.11 association
+# information from the driver.
+# 1: wpa_supplicant initiates scanning and AP selection
+# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
+#    parameters (e.g., WPA IE generation); this mode can also be used with
+#    non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
+#    APs (i.e., external program needs to control association). This mode must
+#    also be used when using wired Ethernet drivers.
+# 2: like 0, but associate with APs using security policy and SSID (but not
+#    BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
+#    enable operation with hidden SSIDs and optimized roaming; in this mode,
+#    the network blocks in the configuration file are tried one by one until
+#    the driver reports successful association; each network block should have
+#    explicit security policy (i.e., only one option in the lists) for
+#    key_mgmt, pairwise, group, proto variables
+ap_scan=1
+
+# EAP fast re-authentication
+# By default, fast re-authentication is enabled for all EAP methods that
+# support it. This variable can be used to disable fast re-authentication.
+# Normally, there is no need to disable this.
+fast_reauth=1
+
+#Disable the default behavior of adding a separate interface for the P2P
+#group when driver support for concurrent interfaces is available.
+p2p_no_group_iface=1
+
+# OpenSSL Engine support
+# These options can be used to load OpenSSL engines.
+# The two engines that are supported currently are shown below:
+# They are both from the opensc project (http://www.opensc.org/)
+# By default no engines are loaded.
+# make the opensc engine available
+#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
+# make the pkcs11 engine available
+#pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so
+# configure the path to the pkcs11 module required by the pkcs11 engine
+#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
+
+# Dynamic EAP methods
+# If EAP methods were built dynamically as shared object files, they need to be
+# loaded here before being used in the network blocks. By default, EAP methods
+# are included statically in the build, so these lines are not needed
+#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so
+#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
+
+# Driver interface parameters
+# This field can be used to configure arbitrary driver interace parameters. The
+# format is specific to the selected driver interface. This field is not used
+# in most cases.
+#driver_param="field=value"
+
+# Country code
+# The ISO/IEC alpha2 country code for the country in which this device is
+# currently operating.
+#country=US
+
+# Maximum lifetime for PMKSA in seconds; default 43200
+#dot11RSNAConfigPMKLifetime=43200
+# Threshold for reauthentication (percentage of PMK lifetime); default 70
+#dot11RSNAConfigPMKReauthThreshold=70
+# Timeout for security association negotiation in seconds; default 60
+#dot11RSNAConfigSATimeout=60
+
+# Wi-Fi Protected Setup (WPS) parameters
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless Client
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=cmodel
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+#       default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+#   1-0050F204-1 (Computer / PC)
+#   1-0050F204-2 (Computer / Server)
+#   5-0050F204-1 (Storage / NAS)
+#   6-0050F204-1 (Network Infrastructure / AP)
+#device_type=1-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Credential processing
+#   0 = process received credentials internally (default)
+#   1 = do not process received credentials; just pass them over ctrl_iface to
+#	external program(s)
+#   2 = process received credentials internally and pass them over ctrl_iface
+#	to external program(s)
+#wps_cred_processing=0
+
+# network block
+#
+# Each network (usually AP's sharing the same SSID) is configured as a separate
+# block in this configuration file. The network blocks are in preference order
+# (the first match is used).
+#
+# network block fields:
+#
+# disabled:
+#	0 = this network can be used (default)
+#	1 = this network block is disabled (can be enabled through ctrl_iface,
+#	    e.g., with wpa_cli or wpa_gui)
+#
+# id_str: Network identifier string for external scripts. This value is passed
+#	to external action script through wpa_cli as WPA_ID_STR environment
+#	variable to make it easier to do network specific configuration.
+#
+# ssid: SSID (mandatory); either as an ASCII string with double quotation or
+#	as hex string; network name
+#
+# scan_ssid:
+#	0 = do not scan this SSID with specific Probe Request frames (default)
+#	1 = scan with SSID-specific Probe Request frames (this can be used to
+#	    find APs that do not accept broadcast SSID or use multiple SSIDs;
+#	    this will add latency to scanning, so enable this only when needed)
+#
+# bssid: BSSID (optional); if set, this network block is used only when
+#	associating with the AP using the configured BSSID
+#
+# priority: priority group (integer)
+# By default, all networks will get same priority group (0). If some of the
+# networks are more desirable, this field can be used to change the order in
+# which wpa_supplicant goes through the networks when selecting a BSS. The
+# priority groups will be iterated in decreasing priority (i.e., the larger the
+# priority value, the sooner the network is matched against the scan results).
+# Within each priority group, networks will be selected based on security
+# policy, signal strength, etc.
+# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not
+# using this priority to select the order for scanning. Instead, they try the
+# networks in the order that used in the configuration file.
+#
+# mode: IEEE 802.11 operation mode
+# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
+# 1 = IBSS (ad-hoc, peer-to-peer)
+# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
+# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In addition, ap_scan has
+# to be set to 2 for IBSS. WPA-None requires following network block options:
+# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
+# both), and psk must also be set.
+#
+# frequency: Channel frequency in megahertz (MHz) for IBSS, e.g.,
+# 2412 = IEEE 802.11b/g channel 1. This value is used to configure the initial
+# channel for IBSS (adhoc) networks. It is ignored in the infrastructure mode.
+# In addition, this value is only used by the station that creates the IBSS. If
+# an IBSS network with the configured SSID is already present, the frequency of
+# the network will be used instead of this configured value.
+#
+# proto: list of accepted protocols
+# WPA = WPA/IEEE 802.11i/D3.0
+# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
+# If not set, this defaults to: WPA RSN
+#
+# key_mgmt: list of accepted authenticated key management protocols
+# WPA-PSK = WPA pre-shared key (this requires 'psk' field)
+# WPA-EAP = WPA using EAP authentication
+# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
+#	generated WEP keys
+# NONE = WPA is not used; plaintext or static WEP could be used
+# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
+# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
+# If not set, this defaults to: WPA-PSK WPA-EAP
+#
+# auth_alg: list of allowed IEEE 802.11 authentication algorithms
+# OPEN = Open System authentication (required for WPA/WPA2)
+# SHARED = Shared Key authentication (requires static WEP keys)
+# LEAP = LEAP/Network EAP (only used with LEAP)
+# If not set, automatic selection is used (Open System with LEAP enabled if
+# LEAP is allowed as one of the EAP methods).
+#
+# pairwise: list of accepted pairwise (unicast) ciphers for WPA
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# NONE = Use only Group Keys (deprecated, should not be included if APs support
+#	pairwise keys)
+# If not set, this defaults to: CCMP TKIP
+#
+# group: list of accepted group (broadcast/multicast) ciphers for WPA
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
+# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11]
+# If not set, this defaults to: CCMP TKIP WEP104 WEP40
+#
+# psk: WPA preshared key; 256-bit pre-shared key
+# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
+# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
+# generated using the passphrase and SSID). ASCII passphrase must be between
+# 8 and 63 characters (inclusive).
+# This field is not needed, if WPA-EAP is used.
+# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
+# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
+# startup and reconfiguration time can be optimized by generating the PSK only
+# only when the passphrase or SSID has actually changed.
+#
+# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
+# Dynamic WEP key required for non-WPA mode
+# bit0 (1): require dynamically generated unicast WEP key
+# bit1 (2): require dynamically generated broadcast WEP key
+# 	(3 = require both keys; default)
+# Note: When using wired authentication, eapol_flags must be set to 0 for the
+# authentication to be completed successfully.
+#
+# mixed_cell: This option can be used to configure whether so called mixed
+# cells, i.e., networks that use both plaintext and encryption in the same
+# SSID, are allowed when selecting a BSS form scan results.
+# 0 = disabled (default)
+# 1 = enabled
+#
+# proactive_key_caching:
+# Enable/disable opportunistic PMKSA caching for WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#
+# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
+# hex without quotation, e.g., 0102030405)
+# wep_tx_keyidx: Default WEP key index (TX) (0..3)
+#
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+#
+# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
+# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
+#
+# Following fields are only used with internal EAP implementation.
+# eap: space-separated list of accepted EAP methods
+#	MD5 = EAP-MD5 (unsecure and does not generate keying material ->
+#			cannot be used with WPA; to be used as a Phase 2 method
+#			with EAP-PEAP or EAP-TTLS)
+#       MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used
+#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#       OTP = EAP-OTP (cannot be used separately with WPA; to be used
+#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#       GTC = EAP-GTC (cannot be used separately with WPA; to be used
+#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#	TLS = EAP-TLS (client and server certificate)
+#	PEAP = EAP-PEAP (with tunnelled EAP authentication)
+#	TTLS = EAP-TTLS (with tunnelled EAP or PAP/CHAP/MSCHAP/MSCHAPV2
+#			 authentication)
+#	If not set, all compiled in methods are allowed.
+#
+# identity: Identity string for EAP
+#	This field is also used to configure user NAI for
+#	EAP-PSK/PAX/SAKE/GPSK.
+# anonymous_identity: Anonymous identity string for EAP (to be used as the
+#	unencrypted identity with EAP types that support different tunnelled
+#	identity, e.g., EAP-TTLS)
+# password: Password string for EAP. This field can include either the
+#	plaintext password (using ASCII or hex string) or a NtPasswordHash
+#	(16-byte MD4 hash of password) in hash:<32 hex digits> format.
+#	NtPasswordHash can only be used when the password is for MSCHAPv2 or
+#	MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
+#	EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
+#	PSK) is also configured using this field. For EAP-GPSK, this is a
+#	variable length PSK.
+# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
+#	or more trusted CA certificates. If ca_cert and ca_path are not
+#	included, server certificate will not be verified. This is insecure and
+#	a trusted CA certificate should always be configured when using
+#	EAP-TLS/TTLS/PEAP. Full path should be used since working directory may
+#	change when wpa_supplicant is run in the background.
+#	On Windows, trusted CA certificates can be loaded from the system
+#	certificate store by setting this to cert_store://<name>, e.g.,
+#	ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
+#	Note that when running wpa_supplicant as an application, the user
+#	certificate store (My user account) is used, whereas computer store
+#	(Computer account) is used when running wpasvc as a service.
+# ca_path: Directory path for CA certificate files (PEM). This path may
+#	contain multiple CA certificates in OpenSSL format. Common use for this
+#	is to point to system trusted CA list which is often installed into
+#	directory like /etc/ssl/certs. If configured, these certificates are
+#	added to the list of trusted CAs. ca_cert may also be included in that
+#	case, but it is not required.
+# client_cert: File path to client certificate file (PEM/DER)
+#	Full path should be used since working directory may change when
+#	wpa_supplicant is run in the background.
+#	Alternatively, a named configuration blob can be used by setting this
+#	to blob://<blob name>.
+# private_key: File path to client private key file (PEM/DER/PFX)
+#	When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+#	commented out. Both the private key and certificate will be read from
+#	the PKCS#12 file in this case. Full path should be used since working
+#	directory may change when wpa_supplicant is run in the background.
+#	Windows certificate store can be used by leaving client_cert out and
+#	configuring private_key in one of the following formats:
+#	cert://substring_to_match
+#	hash://certificate_thumbprint_in_hex
+#	for example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+#	Note that when running wpa_supplicant as an application, the user
+#	certificate store (My user account) is used, whereas computer store
+#	(Computer account) is used when running wpasvc as a service.
+#	Alternatively, a named configuration blob can be used by setting this
+#	to blob://<blob name>.
+# private_key_passwd: Password for private key file (if left out, this will be
+#	asked through control interface)
+# dh_file: File path to DH/DSA parameters file (in PEM format)
+#	This is an optional configuration file for setting parameters for an
+#	ephemeral DH key exchange. In most cases, the default RSA
+#	authentication does not use this configuration. However, it is possible
+#	setup RSA to use ephemeral DH key exchange. In addition, ciphers with
+#	DSA keys always use ephemeral DH keys. This can be used to achieve
+#	forward secrecy. If the file is in DSA parameters format, it will be
+#	automatically converted into DH params.
+# subject_match: Substring to be matched against the subject of the
+#	authentication server certificate. If this string is set, the server
+#	sertificate is only accepted if it contains this string in the subject.
+#	The subject string is in following format:
+#	/C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
+# altsubject_match: Semicolon separated string of entries to be matched against
+#	the alternative subject name of the authentication server certificate.
+#	If this string is set, the server sertificate is only accepted if it
+#	contains one of the entries in an alternative subject name extension.
+#	altSubjectName string is in following format: TYPE:VALUE
+#	Example: EMAIL:server@example.com
+#	Example: DNS:server.example.com;DNS:server2.example.com
+#	Following types are supported: EMAIL, DNS, URI
+# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
+#	(string with field-value pairs, e.g., "peapver=0" or
+#	"peapver=1 peaplabel=1")
+#	'peapver' can be used to force which PEAP version (0 or 1) is used.
+#	'peaplabel=1' can be used to force new label, "client PEAP encryption",
+#	to be used during key derivation when PEAPv1 or newer. Most existing
+#	PEAPv1 implementation seem to be using the old label, "client EAP
+#	encryption", and wpa_supplicant is now using that as the default value.
+#	Some servers, e.g., Radiator, may require peaplabel=1 configuration to
+#	interoperate with PEAPv1; see eap_testing.txt for more details.
+#	'peap_outer_success=0' can be used to terminate PEAP authentication on
+#	tunneled EAP-Success. This is required with some RADIUS servers that
+#	implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
+#	Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode)
+#	include_tls_length=1 can be used to force wpa_supplicant to include
+#	TLS Message Length field in all TLS messages even if they are not
+#	fragmented.
+#	sim_min_num_chal=3 can be used to configure EAP-SIM to require three
+#	challenges (by default, it accepts 2 or 3)
+#	result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use
+#	protected result indication.
+#	'crypto_binding' option can be used to control PEAPv0 cryptobinding
+#	behavior:
+#	 * 0 = do not use cryptobinding (default)
+#	 * 1 = use cryptobinding if server supports it
+#	 * 2 = require cryptobinding
+#	EAP-WSC (WPS) uses following options: pin=<Device Password> or
+#	pbc=1.
+# phase2: Phase2 (inner authentication with TLS tunnel) parameters
+#	(string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
+#	"autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
+# Following certificate/private key fields are used in inner Phase2
+# authentication when using EAP-TTLS or EAP-PEAP.
+# ca_cert2: File path to CA certificate file. This file can have one or more
+#	trusted CA certificates. If ca_cert2 and ca_path2 are not included,
+#	server certificate will not be verified. This is insecure and a trusted
+#	CA certificate should always be configured.
+# ca_path2: Directory path for CA certificate files (PEM)
+# client_cert2: File path to client certificate file
+# private_key2: File path to client private key file
+# private_key2_passwd: Password for private key file
+# dh_file2: File path to DH/DSA parameters file (in PEM format)
+# subject_match2: Substring to be matched against the subject of the
+#	authentication server certificate.
+# altsubject_match2: Substring to be matched against the alternative subject
+#	name of the authentication server certificate.
+#
+# fragment_size: Maximum EAP fragment size in bytes (default 1398).
+#	This value limits the fragment size for EAP methods that support
+#	fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set
+#	small enough to make the EAP messages fit in MTU of the network
+#	interface used for EAPOL. The default value is suitable for most
+#	cases.
+#
+# EAP-FAST variables:
+# pac_file: File path for the PAC entries. wpa_supplicant will need to be able
+#	to create this file and write updates to it when PAC is being
+#	provisioned or refreshed. Full path to the file should be used since
+#	working directory may change when wpa_supplicant is run in the
+#	background. Alternatively, a named configuration blob can be used by
+#	setting this to blob://<blob name>
+# phase1: fast_provisioning option can be used to enable in-line provisioning
+#         of EAP-FAST credentials (PAC):
+#         0 = disabled,
+#         1 = allow unauthenticated provisioning,
+#         2 = allow authenticated provisioning,
+#         3 = allow both unauthenticated and authenticated provisioning
+#	fast_max_pac_list_len=<num> option can be used to set the maximum
+#		number of PAC entries to store in a PAC list (default: 10)
+#	fast_pac_format=binary option can be used to select binary format for
+#		storing PAC entries in order to save some space (the default
+#		text format uses about 2.5 times the size of minimal binary
+#		format)
+#
+# wpa_supplicant supports number of "EAP workarounds" to work around
+# interoperability issues with incorrectly behaving authentication servers.
+# These are enabled by default because some of the issues are present in large
+# number of authentication servers. Strict EAP conformance mode can be
+# configured by disabling workarounds with eap_workaround=0.
+
+# Example blocks:
+
+# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
+#network={
+#	ssid="simple"
+#	psk="very secret passphrase"
+#	priority=5
+#}
+#
+## Same as previous, but request SSID-specific scanning (for APs that reject
+## broadcast SSID)
+#network={
+#	ssid="second ssid"
+#	scan_ssid=1
+#	psk="very secret passphrase"
+#	priority=2
+#}
+#
+## Only WPA-PSK is used. Any valid cipher combination is accepted.
+#network={
+#	ssid="example"
+#	proto=WPA
+#	key_mgmt=WPA-PSK
+#	pairwise=CCMP TKIP
+#	group=CCMP TKIP WEP104 WEP40
+#	psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
+#	priority=2
+#}
+#
+## WPA-Personal(PSK) with TKIP and enforcement for frequent PTK rekeying
+#network={
+#	ssid="example"
+#	proto=WPA
+#	key_mgmt=WPA-PSK
+#	pairwise=TKIP
+#	group=TKIP
+#	psk="not so secure passphrase"
+#	wpa_ptk_rekey=600
+#}
+#
+## Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104
+## or WEP40 as the group cipher will not be accepted.
+#network={
+#	ssid="example"
+#	proto=RSN
+#	key_mgmt=WPA-EAP
+#	pairwise=CCMP TKIP
+#	group=CCMP TKIP
+#	eap=TLS
+#	identity="user@example.com"
+#	ca_cert="/etc/cert/ca.pem"
+#	client_cert="/etc/cert/user.pem"
+#	private_key="/etc/cert/user.prv"
+#	private_key_passwd="password"
+#	priority=1
+#}
+#
+## EAP-PEAP/MSCHAPv2 configuration for RADIUS servers that use the new peaplabel
+## (e.g., Radiator)
+#network={
+#	ssid="example"
+#	key_mgmt=WPA-EAP
+#	eap=PEAP
+#	identity="user@example.com"
+#	password="foobar"
+#	ca_cert="/etc/cert/ca.pem"
+#	phase1="peaplabel=1"
+#	phase2="auth=MSCHAPV2"
+#	priority=10
+#}
+#
+## EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
+## unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
+#network={
+#	ssid="example"
+#	key_mgmt=WPA-EAP
+#	eap=TTLS
+#	identity="user@example.com"
+#	anonymous_identity="anonymous@example.com"
+#	password="foobar"
+#	ca_cert="/etc/cert/ca.pem"
+#	priority=2
+#}
+#
+## EAP-TTLS/MSCHAPv2 configuration with anonymous identity for the unencrypted
+## use. Real identity is sent only within an encrypted TLS tunnel.
+#network={
+#	ssid="example"
+#	key_mgmt=WPA-EAP
+#	eap=TTLS
+#	identity="user@example.com"
+#	anonymous_identity="anonymous@example.com"
+#	password="foobar"
+#	ca_cert="/etc/cert/ca.pem"
+#	phase2="auth=MSCHAPV2"
+#}
+#
+## WPA-EAP, EAP-TTLS with different CA certificate used for outer and inner
+## authentication.
+#network={
+#	ssid="example"
+#	key_mgmt=WPA-EAP
+#	eap=TTLS
+#	# Phase1 / outer authentication
+#	anonymous_identity="anonymous@example.com"
+#	ca_cert="/etc/cert/ca.pem"
+#	# Phase 2 / inner authentication
+#	phase2="autheap=TLS"
+#	ca_cert2="/etc/cert/ca2.pem"
+#	client_cert2="/etc/cer/user.pem"
+#	private_key2="/etc/cer/user.prv"
+#	private_key2_passwd="password"
+#	priority=2
+#}
+#
+## Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and
+## group cipher.
+#network={
+#	ssid="example"
+#	bssid=00:11:22:33:44:55
+#	proto=WPA RSN
+#	key_mgmt=WPA-PSK WPA-EAP
+#	pairwise=CCMP
+#	group=CCMP
+#	psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
+#}
+#
+## Special characters in SSID, so use hex string. Default to WPA-PSK, WPA-EAP
+## and all valid ciphers.
+#network={
+#	ssid=00010203
+#	psk=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+#}
+#
+#
+## EAP-SIM with a GSM SIM or USIM
+#network={
+#	ssid="eap-sim-test"
+#	key_mgmt=WPA-EAP
+#	eap=SIM
+#	pin="1234"
+#	pcsc=""
+#}
+#
+#
+## EAP-PSK
+#network={
+#	ssid="eap-psk-test"
+#	key_mgmt=WPA-EAP
+#	eap=PSK
+#	anonymous_identity="eap_psk_user"
+#	password=06b4be19da289f475aa46a33cb793029
+#	identity="eap_psk_user@example.com"
+#}
+#
+#
+## IEEE 802.1X/EAPOL with dynamically generated WEP keys (i.e., no WPA) using
+## EAP-TLS for authentication and key generation; require both unicast and
+## broadcast WEP keys.
+#network={
+#	ssid="1x-test"
+#	key_mgmt=IEEE8021X
+#	eap=TLS
+#	identity="user@example.com"
+#	ca_cert="/etc/cert/ca.pem"
+#	client_cert="/etc/cert/user.pem"
+#	private_key="/etc/cert/user.prv"
+#	private_key_passwd="password"
+#	eapol_flags=3
+#}
+#
+#
+## LEAP with dynamic WEP keys
+#network={
+#	ssid="leap-example"
+#	key_mgmt=IEEE8021X
+#	eap=LEAP
+#	identity="user"
+#	password="foobar"
+#}
+#
+## EAP-IKEv2 using shared secrets for both server and peer authentication
+#network={
+#	ssid="ikev2-example"
+#	key_mgmt=WPA-EAP
+#	eap=IKEV2
+#	identity="user"
+#	password="foobar"
+#}
+#
+## EAP-FAST with WPA (WPA or WPA2)
+#network={
+#	ssid="eap-fast-test"
+#	key_mgmt=WPA-EAP
+#	eap=FAST
+#	anonymous_identity="FAST-000102030405"
+#	identity="username"
+#	password="password"
+#	phase1="fast_provisioning=1"
+#	pac_file="/etc/wpa_supplicant.eap-fast-pac"
+#}
+#
+#network={
+#	ssid="eap-fast-test"
+#	key_mgmt=WPA-EAP
+#	eap=FAST
+#	anonymous_identity="FAST-000102030405"
+#	identity="username"
+#	password="password"
+#	phase1="fast_provisioning=1"
+#	pac_file="blob://eap-fast-pac"
+#}
+#
+## Plaintext connection (no WPA, no IEEE 802.1X)
+#network={
+#	ssid="plaintext-test"
+#	key_mgmt=NONE
+#}
+#
+#
+## Shared WEP key connection (no WPA, no IEEE 802.1X)
+#network={
+#	ssid="static-wep-test"
+#	key_mgmt=NONE
+#	wep_key0="abcde"
+#	wep_key1=0102030405
+#	wep_key2="1234567890123"
+#	wep_tx_keyidx=0
+#	priority=5
+#}
+#
+#
+## Shared WEP key connection (no WPA, no IEEE 802.1X) using Shared Key
+## IEEE 802.11 authentication
+#network={
+#	ssid="static-wep-test2"
+#	key_mgmt=NONE
+#	wep_key0="abcde"
+#	wep_key1=0102030405
+#	wep_key2="1234567890123"
+#	wep_tx_keyidx=0
+#	priority=5
+#	auth_alg=SHARED
+#}
+#
+#
+## IBSS/ad-hoc network with WPA-None/TKIP.
+#network={
+#	ssid="test adhoc"
+#	mode=1
+#	frequency=2412
+#	proto=WPA
+#	key_mgmt=WPA-NONE
+#	pairwise=NONE
+#	group=TKIP
+#	psk="secret passphrase"
+#}
+#
+#
+## Catch all example that allows more or less all configuration modes
+#network={
+#	ssid="example"
+#	scan_ssid=1
+#	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+#	pairwise=CCMP TKIP
+#	group=CCMP TKIP WEP104 WEP40
+#	psk="very secret passphrase"
+#	eap=TTLS PEAP TLS
+#	identity="user@example.com"
+#	password="foobar"
+#	ca_cert="/etc/cert/ca.pem"
+#	client_cert="/etc/cert/user.pem"
+#	private_key="/etc/cert/user.prv"
+#	private_key_passwd="password"
+#	phase1="peaplabel=0"
+#}
+#
+## Example of EAP-TLS with smartcard (openssl engine)
+#network={
+#	ssid="example"
+#	key_mgmt=WPA-EAP
+#	eap=TLS
+#	proto=RSN
+#	pairwise=CCMP TKIP
+#	group=CCMP TKIP
+#	identity="user@example.com"
+#	ca_cert="/etc/cert/ca.pem"
+#	client_cert="/etc/cert/user.pem"
+#
+#	engine=1
+#
+#	# The engine configured here must be available. Look at
+#	# OpenSSL engine support in the global section.
+#	# The key available through the engine must be the private key
+#	# matching the client certificate configured above.
+#
+#	# use the opensc engine
+#	#engine_id="opensc"
+#	#key_id="45"
+#
+#	# use the pkcs11 engine
+#	engine_id="pkcs11"
+#	key_id="id_45"
+#
+#	# Optional PIN configuration; this can be left out and PIN will be
+#	# asked through the control interface
+#	pin="1234"
+#}
+#
+## Example configuration showing how to use an inlined blob as a CA certificate
+## data instead of using external file
+#network={
+#	ssid="example"
+#	key_mgmt=WPA-EAP
+#	eap=TTLS
+#	identity="user@example.com"
+#	anonymous_identity="anonymous@example.com"
+#	password="foobar"
+#	ca_cert="blob://exampleblob"
+#	priority=20
+#}
+#
+#blob-base64-exampleblob={
+#SGVsbG8gV29ybGQhCg==
+#}
+
+
+# Wildcard match for SSID (plaintext APs only). This example select any
+# open AP regardless of its SSID.
+#network={
+#	key_mgmt=NONE
+#}