Merge "Implements HidlSensorHalWrapper"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 8da1352..34ccb21 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -11,286 +11,6 @@
 
 # Grant unix world read/write permissions to kernel tracepoints.
 # Access control to these files is now entirely in selinux policy.
-    chmod 0755 /sys/kernel/debug/tracing/events
-    chmod 0755 /sys/kernel/debug/tracing/events/binder
-    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_lock
-    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_locked
-    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_set_priority
-    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction
-    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_alloc_buf
-    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_received
-    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_unlock
-    chmod 0755 /sys/kernel/debug/tracing/events/block
-    chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_complete
-    chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_issue
-    chmod 0755 /sys/kernel/debug/tracing/events/cgroup
-    chmod 0755 /sys/kernel/debug/tracing/events/clk
-    chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_disable
-    chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_enable
-    chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_set_rate
-    chmod 0755 /sys/kernel/debug/tracing/events/cpufreq_interactive
-    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp
-    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_enter
-    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_pause
-    chmod 0755 /sys/kernel/debug/tracing/events/dma_fence
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_enter
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_load_inode
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter
-    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/f2fs
-    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_get_data_block
-    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_iget
-    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter
-    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin
-    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end
-    chmod 0755 /sys/kernel/debug/tracing/events/fence
-    chmod 0755 /sys/kernel/debug/tracing/events/filemap
-    chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache
-    chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache
-    chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem
-    chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_read
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_reply
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_result
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_write
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_read
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_reply
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_result
-    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_write
-    chmod 0755 /sys/kernel/debug/tracing/events/ion
-    chmod 0755 /sys/kernel/debug/tracing/events/ion/ion_stat
-    chmod 0755 /sys/kernel/debug/tracing/events/ipi
-    chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_entry
-    chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_raise
-    chmod 0755 /sys/kernel/debug/tracing/events/irq
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_entry
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_entry
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_raise
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_entry
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_entry
-    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/kmem
-    chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow
-    chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink
-    chmod 0755 /sys/kernel/debug/tracing/events/kmem/rss_stat
-    chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller
-    chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill
-    chmod 0755 /sys/kernel/debug/tracing/events/mm_event
-    chmod 0755 /sys/kernel/debug/tracing/events/mm_event/mm_event_record
-    chmod 0755 /sys/kernel/debug/tracing/events/oom
-    chmod 0755 /sys/kernel/debug/tracing/events/oom/mark_victim
-    chmod 0755 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update
-    chmod 0755 /sys/kernel/debug/tracing/events/power
-    chmod 0755 /sys/kernel/debug/tracing/events/power/clock_disable
-    chmod 0755 /sys/kernel/debug/tracing/events/power/clock_enable
-    chmod 0755 /sys/kernel/debug/tracing/events/power/clock_set_rate
-    chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency
-    chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits
-    chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_idle
-    chmod 0755 /sys/kernel/debug/tracing/events/power/gpu_frequency
-    chmod 0755 /sys/kernel/debug/tracing/events/power/suspend_resume
-    chmod 0755 /sys/kernel/debug/tracing/events/sched
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_exit
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_free
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_switch
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new
-    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_waking
-    chmod 0755 /sys/kernel/debug/tracing/events/signal
-    chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_deliver
-    chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_generate
-    chmod 0755 /sys/kernel/debug/tracing/events/sync
-    chmod 0755 /sys/kernel/debug/tracing/events/task
-    chmod 0755 /sys/kernel/debug/tracing/events/task/task_newtask
-    chmod 0755 /sys/kernel/debug/tracing/events/task/task_rename
-    chmod 0755 /sys/kernel/debug/tracing/events/thermal
-    chmod 0755 /sys/kernel/debug/tracing/events/thermal/cdev_update
-    chmod 0755 /sys/kernel/debug/tracing/events/thermal/thermal_temperature
-    chmod 0755 /sys/kernel/debug/tracing/events/vmscan
-    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
-    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
-    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep
-    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake
-    chmod 0755 /sys/kernel/debug/tracing/options
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu0
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu1
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu2
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu3
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu4
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu5
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu6
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu7
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu8
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu9
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu10
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu11
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu12
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu13
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu14
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu15
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu16
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu17
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu18
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu19
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu20
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu21
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu22
-    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu23
-    chmod 0755 /sys/kernel/tracing/events
-    chmod 0755 /sys/kernel/tracing/events/binder
-    chmod 0755 /sys/kernel/tracing/events/binder/binder_lock
-    chmod 0755 /sys/kernel/tracing/events/binder/binder_locked
-    chmod 0755 /sys/kernel/tracing/events/binder/binder_set_priority
-    chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction
-    chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf
-    chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_received
-    chmod 0755 /sys/kernel/tracing/events/binder/binder_unlock
-    chmod 0755 /sys/kernel/tracing/events/block
-    chmod 0755 /sys/kernel/tracing/events/block/block_rq_complete
-    chmod 0755 /sys/kernel/tracing/events/block/block_rq_issue
-    chmod 0755 /sys/kernel/tracing/events/cgroup
-    chmod 0755 /sys/kernel/tracing/events/clk
-    chmod 0755 /sys/kernel/tracing/events/clk/clk_disable
-    chmod 0755 /sys/kernel/tracing/events/clk/clk_enable
-    chmod 0755 /sys/kernel/tracing/events/clk/clk_set_rate
-    chmod 0755 /sys/kernel/tracing/events/cpufreq_interactive
-    chmod 0755 /sys/kernel/tracing/events/cpuhp
-    chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_enter
-    chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_exit
-    chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_pause
-    chmod 0755 /sys/kernel/tracing/events/dma_fence
-    chmod 0755 /sys/kernel/tracing/events/ext4
-    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_begin
-    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_end
-    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_enter
-    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_exit
-    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_load_inode
-    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter
-    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit
-    chmod 0755 /sys/kernel/tracing/events/f2fs
-    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block
-    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_iget
-    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter
-    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit
-    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_begin
-    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_end
-    chmod 0755 /sys/kernel/tracing/events/fence
-    chmod 0755 /sys/kernel/tracing/events/filemap
-    chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache
-    chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache
-    chmod 0755 /sys/kernel/tracing/events/gpu_mem
-    chmod 0755 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total
-    chmod 0755 /sys/kernel/tracing/events/i2c
-    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_read
-    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_reply
-    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_result
-    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_write
-    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_read
-    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_reply
-    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_result
-    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_write
-    chmod 0755 /sys/kernel/tracing/events/ion
-    chmod 0755 /sys/kernel/tracing/events/ion/ion_stat
-    chmod 0755 /sys/kernel/tracing/events/ipi
-    chmod 0755 /sys/kernel/tracing/events/ipi/ipi_entry
-    chmod 0755 /sys/kernel/tracing/events/ipi/ipi_exit
-    chmod 0755 /sys/kernel/tracing/events/ipi/ipi_raise
-    chmod 0755 /sys/kernel/tracing/events/irq
-    chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_entry
-    chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_exit
-    chmod 0755 /sys/kernel/tracing/events/irq/softirq_entry
-    chmod 0755 /sys/kernel/tracing/events/irq/softirq_exit
-    chmod 0755 /sys/kernel/tracing/events/irq/softirq_raise
-    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_entry
-    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_exit
-    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_entry
-    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_exit
-    chmod 0755 /sys/kernel/tracing/events/kmem
-    chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_grow
-    chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_shrink
-    chmod 0755 /sys/kernel/tracing/events/kmem/rss_stat
-    chmod 0755 /sys/kernel/tracing/events/lowmemorykiller
-    chmod 0755 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill
-    chmod 0755 /sys/kernel/tracing/events/mm_event
-    chmod 0755 /sys/kernel/tracing/events/mm_event/mm_event_record
-    chmod 0755 /sys/kernel/tracing/events/oom
-    chmod 0755 /sys/kernel/tracing/events/oom/mark_victim
-    chmod 0755 /sys/kernel/tracing/events/oom/oom_score_adj_update
-    chmod 0755 /sys/kernel/tracing/events/power
-    chmod 0755 /sys/kernel/tracing/events/power/clock_disable
-    chmod 0755 /sys/kernel/tracing/events/power/clock_enable
-    chmod 0755 /sys/kernel/tracing/events/power/clock_set_rate
-    chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency
-    chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency_limits
-    chmod 0755 /sys/kernel/tracing/events/power/cpu_idle
-    chmod 0755 /sys/kernel/tracing/events/power/gpu_frequency
-    chmod 0755 /sys/kernel/tracing/events/power/suspend_resume
-    chmod 0755 /sys/kernel/tracing/events/sched
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_blocked_reason
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_cpu_hotplug
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_pi_setprio
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_process_exit
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_process_free
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_switch
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup_new
-    chmod 0755 /sys/kernel/tracing/events/sched/sched_waking
-    chmod 0755 /sys/kernel/tracing/events/signal
-    chmod 0755 /sys/kernel/tracing/events/signal/signal_deliver
-    chmod 0755 /sys/kernel/tracing/events/signal/signal_generate
-    chmod 0755 /sys/kernel/tracing/events/sync
-    chmod 0755 /sys/kernel/tracing/events/task
-    chmod 0755 /sys/kernel/tracing/events/task/task_newtask
-    chmod 0755 /sys/kernel/tracing/events/task/task_rename
-    chmod 0755 /sys/kernel/tracing/events/thermal
-    chmod 0755 /sys/kernel/tracing/events/thermal/cdev_update
-    chmod 0755 /sys/kernel/tracing/events/thermal/thermal_temperature
-    chmod 0755 /sys/kernel/tracing/events/vmscan
-    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
-    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
-    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep
-    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake
-    chmod 0755 /sys/kernel/tracing/options
-    chmod 0755 /sys/kernel/tracing/per_cpu
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu0
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu1
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu2
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu3
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu4
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu5
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu6
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu7
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu8
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu9
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu10
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu11
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu12
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu13
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu14
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu15
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu16
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu17
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu18
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu19
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu20
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu21
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu22
-    chmod 0755 /sys/kernel/tracing/per_cpu/cpu23
     chmod 0666 /sys/kernel/debug/tracing/trace_clock
     chmod 0666 /sys/kernel/tracing/trace_clock
     chmod 0666 /sys/kernel/debug/tracing/buffer_size_kb
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index faa8485..00babc3 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -28,6 +28,7 @@
         "dexopt.cpp",
         "execv_helper.cpp",
         "globals.cpp",
+        "restorable_file.cpp",
         "run_dex2oat.cpp",
         "unique_file.cpp",
         "utils.cpp",
@@ -80,7 +81,7 @@
         "-cert-err58-cpp",
     ],
     tidy_flags: [
-        "-warnings-as-errors=clang-analyzer-security*,cert-*"
+        "-warnings-as-errors=clang-analyzer-security*,cert-*",
     ],
 }
 
@@ -132,7 +133,10 @@
         "unique_file.cpp",
         "execv_helper.cpp",
     ],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "libbase",
         "server_configurable_flags",
@@ -170,7 +174,7 @@
 
     // Needs to be wherever installd is as it's execed by
     // installd.
-    required: [ "migrate_legacy_obb_data.sh" ],
+    required: ["migrate_legacy_obb_data.sh"],
 }
 
 // OTA chroot tool
@@ -194,7 +198,7 @@
         "libutils",
     ],
     required: [
-      "apexd"
+        "apexd",
     ],
 }
 
@@ -213,7 +217,7 @@
     name: "libotapreoptparameters",
     cflags: [
         "-Wall",
-        "-Werror"
+        "-Werror",
     ],
 
     srcs: ["otapreopt_parameters.cpp"],
@@ -237,7 +241,7 @@
     name: "otapreopt",
     cflags: [
         "-Wall",
-        "-Werror"
+        "-Werror",
     ],
 
     srcs: [
@@ -246,6 +250,7 @@
         "globals.cpp",
         "otapreopt.cpp",
         "otapreopt_utils.cpp",
+        "restorable_file.cpp",
         "run_dex2oat.cpp",
         "unique_file.cpp",
         "utils.cpp",
@@ -296,5 +301,5 @@
 // Script to migrate legacy obb data.
 sh_binary {
     name: "migrate_legacy_obb_data.sh",
-    src: "migrate_legacy_obb_data.sh"
+    src: "migrate_legacy_obb_data.sh",
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 2bcf2d4..b6f42ad 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -58,9 +58,10 @@
 #include "dexopt_return_codes.h"
 #include "execv_helper.h"
 #include "globals.h"
-#include "installd_deps.h"
 #include "installd_constants.h"
+#include "installd_deps.h"
 #include "otapreopt_utils.h"
+#include "restorable_file.h"
 #include "run_dex2oat.h"
 #include "unique_file.h"
 #include "utils.h"
@@ -309,12 +310,6 @@
     return profile_boot_class_path == "true";
 }
 
-static void UnlinkIgnoreResult(const std::string& path) {
-    if (unlink(path.c_str()) < 0) {
-        PLOG(ERROR) << "Failed to unlink " << path;
-    }
-}
-
 /*
  * Whether dexopt should use a swap file when compiling an APK.
  *
@@ -988,42 +983,34 @@
 }
 
 // (re)Creates the app image if needed.
-UniqueFile maybe_open_app_image(const std::string& out_oat_path,
-        bool generate_app_image, bool is_public, int uid, bool is_secondary_dex) {
-
+RestorableFile maybe_open_app_image(const std::string& out_oat_path, bool generate_app_image,
+                                    bool is_public, int uid, bool is_secondary_dex) {
     const std::string image_path = create_image_filename(out_oat_path);
     if (image_path.empty()) {
         // Happens when the out_oat_path has an unknown extension.
-        return UniqueFile();
+        return RestorableFile();
     }
 
-    // In case there is a stale image, remove it now. Ignore any error.
-    unlink(image_path.c_str());
-
     // Not enabled, exit.
     if (!generate_app_image) {
-        return UniqueFile();
+        RestorableFile::RemoveAllFiles(image_path);
+        return RestorableFile();
     }
     std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
     if (app_image_format.empty()) {
-        return UniqueFile();
+        RestorableFile::RemoveAllFiles(image_path);
+        return RestorableFile();
     }
-    // Recreate is true since we do not want to modify a mapped image. If the app is
-    // already running and we modify the image file, it can cause crashes (b/27493510).
-    UniqueFile image_file(
-            open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
-            image_path,
-            UnlinkIgnoreResult);
+    // If the app is already running and we modify the image file, it can cause crashes
+    // (b/27493510).
+    RestorableFile image_file = RestorableFile::CreateWritableFile(image_path,
+                                                                   /*permissions*/ 0600);
     if (image_file.fd() < 0) {
         // Could not create application image file. Go on since we can compile without it.
         LOG(ERROR) << "installd could not create '" << image_path
                 << "' for image file during dexopt";
-         // If we have a valid image file path but no image fd, explicitly erase the image file.
-        if (unlink(image_path.c_str()) < 0) {
-            if (errno != ENOENT) {
-                PLOG(ERROR) << "Couldn't unlink image file " << image_path;
-            }
-        }
+        // If we have a valid image file path but cannot create tmp file, reset it.
+        image_file.reset();
     } else if (!set_permissions_and_ownership(
                 image_file.fd(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
@@ -1097,9 +1084,9 @@
 // Opens the vdex files and assigns the input fd to in_vdex_wrapper and the output fd to
 // out_vdex_wrapper. Returns true for success or false in case of errors.
 bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path, int dexopt_needed,
-        const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
-        bool profile_guided, UniqueFile* in_vdex_wrapper,
-        UniqueFile* out_vdex_wrapper) {
+                                 const char* instruction_set, bool is_public, int uid,
+                                 bool is_secondary_dex, bool profile_guided,
+                                 UniqueFile* in_vdex_wrapper, RestorableFile* out_vdex_wrapper) {
     CHECK(in_vdex_wrapper != nullptr);
     CHECK(out_vdex_wrapper != nullptr);
     // Open the existing VDEX. We do this before creating the new output VDEX, which will
@@ -1114,6 +1101,14 @@
         return false;
     }
 
+    // Create work file first. All files will be deleted when it fails.
+    *out_vdex_wrapper = RestorableFile::CreateWritableFile(out_vdex_path_str,
+                                                           /*permissions*/ 0644);
+    if (out_vdex_wrapper->fd() < 0) {
+        ALOGE("installd cannot open vdex '%s' during dexopt\n", out_vdex_path_str.c_str());
+        return false;
+    }
+
     bool update_vdex_in_place = false;
     if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
         // Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
@@ -1145,41 +1140,19 @@
             (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) &&
             !profile_guided;
         if (update_vdex_in_place) {
+            // dex2oat marks it invalid anyway. So delete it and set work file fd.
+            unlink(in_vdex_path_str.c_str());
             // Open the file read-write to be able to update it.
-            in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0),
-                                   in_vdex_path_str);
-            if (in_vdex_wrapper->fd() == -1) {
-                // If we failed to open the file, we cannot update it in place.
-                update_vdex_in_place = false;
-            }
+            in_vdex_wrapper->reset(out_vdex_wrapper->fd(), in_vdex_path_str);
+            // Disable auto close for the in wrapper fd (it will be done when destructing the out
+            // wrapper).
+            in_vdex_wrapper->DisableAutoClose();
         } else {
             in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0),
                                    in_vdex_path_str);
         }
     }
 
-    // If we are updating the vdex in place, we do not need to recreate a vdex,
-    // and can use the same existing one.
-    if (update_vdex_in_place) {
-        // We unlink the file in case the invocation of dex2oat fails, to ensure we don't
-        // have bogus stale vdex files.
-        out_vdex_wrapper->reset(
-              in_vdex_wrapper->fd(),
-              out_vdex_path_str,
-              UnlinkIgnoreResult);
-        // Disable auto close for the in wrapper fd (it will be done when destructing the out
-        // wrapper).
-        in_vdex_wrapper->DisableAutoClose();
-    } else {
-        out_vdex_wrapper->reset(
-              open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
-              out_vdex_path_str,
-              UnlinkIgnoreResult);
-        if (out_vdex_wrapper->fd() < 0) {
-            ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
-            return false;
-        }
-    }
     if (!set_permissions_and_ownership(out_vdex_wrapper->fd(), is_public, uid,
             out_vdex_path_str.c_str(), is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
@@ -1191,16 +1164,13 @@
 }
 
 // Opens the output oat file for the given apk.
-UniqueFile open_oat_out_file(const char* apk_path, const char* oat_dir,
-        bool is_public, int uid, const char* instruction_set, bool is_secondary_dex) {
+RestorableFile open_oat_out_file(const char* apk_path, const char* oat_dir, bool is_public, int uid,
+                                 const char* instruction_set, bool is_secondary_dex) {
     char out_oat_path[PKG_PATH_MAX];
     if (!create_oat_out_path(apk_path, instruction_set, oat_dir, is_secondary_dex, out_oat_path)) {
-        return UniqueFile();
+        return RestorableFile();
     }
-    UniqueFile oat(
-            open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
-            out_oat_path,
-            UnlinkIgnoreResult);
+    RestorableFile oat = RestorableFile::CreateWritableFile(out_oat_path, /*permissions*/ 0644);
     if (oat.fd() < 0) {
         PLOG(ERROR) << "installd cannot open output during dexopt" <<  out_oat_path;
     } else if (!set_permissions_and_ownership(
@@ -1839,6 +1809,7 @@
         if (sec_dex_result == kSecondaryDexOptProcessOk) {
             oat_dir = oat_dir_str.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
+                *completed = true;
                 return 0;  // Nothing to do, report success.
             }
         } else if (sec_dex_result == kSecondaryDexOptProcessCancelled) {
@@ -1874,8 +1845,8 @@
     }
 
     // Create the output OAT file.
-    UniqueFile out_oat = open_oat_out_file(dex_path, oat_dir, is_public, uid,
-            instruction_set, is_secondary_dex);
+    RestorableFile out_oat =
+            open_oat_out_file(dex_path, oat_dir, is_public, uid, instruction_set, is_secondary_dex);
     if (out_oat.fd() < 0) {
         *error_msg = "Could not open out oat file.";
         return -1;
@@ -1883,7 +1854,7 @@
 
     // Open vdex files.
     UniqueFile in_vdex;
-    UniqueFile out_vdex;
+    RestorableFile out_vdex;
     if (!open_vdex_files_for_dex2oat(dex_path, out_oat.path().c_str(), dexopt_needed,
             instruction_set, is_public, uid, is_secondary_dex, profile_guided, &in_vdex,
             &out_vdex)) {
@@ -1919,8 +1890,8 @@
     }
 
     // Create the app image file if needed.
-    UniqueFile out_image = maybe_open_app_image(
-            out_oat.path(), generate_app_image, is_public, uid, is_secondary_dex);
+    RestorableFile out_image = maybe_open_app_image(out_oat.path(), generate_app_image, is_public,
+                                                    uid, is_secondary_dex);
 
     UniqueFile dex_metadata;
     if (dex_metadata_path != nullptr) {
@@ -1953,30 +1924,18 @@
     LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
     RunDex2Oat runner(dex2oat_bin, execv_helper.get());
-    runner.Initialize(out_oat,
-                      out_vdex,
-                      out_image,
-                      in_dex,
-                      in_vdex,
-                      dex_metadata,
-                      reference_profile,
-                      class_loader_context,
-                      join_fds(context_input_fds),
-                      swap_fd.get(),
-                      instruction_set,
-                      compiler_filter,
-                      debuggable,
-                      boot_complete,
-                      for_restore,
-                      target_sdk_version,
-                      enable_hidden_api_checks,
-                      generate_compact_dex,
-                      use_jitzygote_image,
+    runner.Initialize(out_oat.GetUniqueFile(), out_vdex.GetUniqueFile(), out_image.GetUniqueFile(),
+                      in_dex, in_vdex, dex_metadata, reference_profile, class_loader_context,
+                      join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter,
+                      debuggable, boot_complete, for_restore, target_sdk_version,
+                      enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image,
                       compilation_reason);
 
     bool cancelled = false;
     pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
     if (cancelled) {
+        *completed = false;
+        reference_profile.DisableCleanup();
         return 0;
     }
     if (pid == 0) {
@@ -2004,6 +1963,7 @@
                 LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- cancelled";
                 // cancelled, not an error
                 *completed = false;
+                reference_profile.DisableCleanup();
                 return 0;
             }
             LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
@@ -2013,13 +1973,42 @@
         }
     }
 
-    // TODO(b/156537504) Implement SWAP of completed files
-    // We've been successful, don't delete output.
-    out_oat.DisableCleanup();
-    out_vdex.DisableCleanup();
-    out_image.DisableCleanup();
+    // dex2oat ran successfully, so profile is safe to keep.
     reference_profile.DisableCleanup();
 
+    // We've been successful, commit work files.
+    // If committing (=renaming tmp to regular) fails, try to restore backup files.
+    // If restoring fails as well, as a last resort, remove all files.
+    if (!out_oat.CreateBackupFile() || !out_vdex.CreateBackupFile() ||
+        !out_image.CreateBackupFile()) {
+        // Renaming failure can mean that the original file may not be accessible from installd.
+        LOG(ERROR) << "Cannot create backup file from existing file, file in wrong state?"
+                   << ", out_oat:" << out_oat.path() << " ,out_vdex:" << out_vdex.path()
+                   << " ,out_image:" << out_image.path();
+        out_oat.ResetAndRemoveAllFiles();
+        out_vdex.ResetAndRemoveAllFiles();
+        out_image.ResetAndRemoveAllFiles();
+        return -1;
+    }
+    if (!out_oat.CommitWorkFile() || !out_vdex.CommitWorkFile() || !out_image.CommitWorkFile()) {
+        LOG(ERROR) << "Cannot commit, out_oat:" << out_oat.path()
+                   << " ,out_vdex:" << out_vdex.path() << " ,out_image:" << out_image.path();
+        if (!out_oat.RestoreBackupFile() || !out_vdex.RestoreBackupFile() ||
+            !out_image.RestoreBackupFile()) {
+            LOG(ERROR) << "Cannot cancel commit, out_oat:" << out_oat.path()
+                       << " ,out_vdex:" << out_vdex.path() << " ,out_image:" << out_image.path();
+            // Restoring failed.
+            out_oat.ResetAndRemoveAllFiles();
+            out_vdex.ResetAndRemoveAllFiles();
+            out_image.ResetAndRemoveAllFiles();
+        }
+        return -1;
+    }
+    // Now remove remaining backup files.
+    out_oat.RemoveBackupFile();
+    out_vdex.RemoveBackupFile();
+    out_image.RemoveBackupFile();
+
     *completed = true;
     return 0;
 }
diff --git a/cmds/installd/restorable_file.cpp b/cmds/installd/restorable_file.cpp
new file mode 100644
index 0000000..fd54a23
--- /dev/null
+++ b/cmds/installd/restorable_file.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "restorable_file.h"
+
+#include <string>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+namespace {
+
+constexpr char kTmpFileSuffix[] = ".tmp";
+constexpr char kBackupFileSuffix[] = ".backup";
+
+std::string GetTmpFilePath(const std::string& path) {
+    return android::base::StringPrintf("%s%s", path.c_str(), kTmpFileSuffix);
+}
+
+std::string GetBackupFilePath(const std::string& path) {
+    return android::base::StringPrintf("%s%s", path.c_str(), kBackupFileSuffix);
+}
+
+void UnlinkPossiblyNonExistingFile(const std::string& path) {
+    if (unlink(path.c_str()) < 0) {
+        if (errno != ENOENT && errno != EROFS) { // EROFS reported even if it does not exist.
+            PLOG(ERROR) << "Cannot unlink: " << path;
+        }
+    }
+}
+
+// Check if file for the given path exists
+bool FileExists(const std::string& path) {
+    struct stat st;
+    return ::stat(path.c_str(), &st) == 0;
+}
+
+} // namespace
+
+namespace android {
+namespace installd {
+
+RestorableFile::RestorableFile() : RestorableFile(-1, "") {}
+
+RestorableFile::RestorableFile(int value, const std::string& path) : unique_file_(value, path) {
+    // As cleanup is null, this does not make much difference but use unique_file_ only for closing
+    // tmp file.
+    unique_file_.DisableCleanup();
+}
+
+RestorableFile::~RestorableFile() {
+    reset();
+}
+
+void RestorableFile::reset() {
+    // need to copy before reset clears it.
+    std::string path(unique_file_.path());
+    unique_file_.reset();
+    if (!path.empty()) {
+        UnlinkPossiblyNonExistingFile(GetTmpFilePath(path));
+    }
+}
+
+bool RestorableFile::CreateBackupFile() {
+    if (path().empty() || !FileExists(path())) {
+        return true;
+    }
+    std::string backup = GetBackupFilePath(path());
+    UnlinkPossiblyNonExistingFile(backup);
+    if (rename(path().c_str(), backup.c_str()) < 0) {
+        PLOG(ERROR) << "Cannot rename " << path() << " to " << backup;
+        return false;
+    }
+    return true;
+}
+
+bool RestorableFile::CommitWorkFile() {
+    std::string path(unique_file_.path());
+    // Keep the path with Commit for debugging purpose.
+    unique_file_.reset(-1, path);
+    if (!path.empty()) {
+        if (rename(GetTmpFilePath(path).c_str(), path.c_str()) < 0) {
+            PLOG(ERROR) << "Cannot rename " << GetTmpFilePath(path) << " to " << path;
+            // Remove both files as renaming can fail due to the original file as well.
+            UnlinkPossiblyNonExistingFile(path);
+            UnlinkPossiblyNonExistingFile(GetTmpFilePath(path));
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool RestorableFile::RestoreBackupFile() {
+    std::string backup = GetBackupFilePath(path());
+    if (path().empty() || !FileExists(backup)) {
+        return true;
+    }
+    UnlinkPossiblyNonExistingFile(path());
+    if (rename(backup.c_str(), path().c_str()) < 0) {
+        PLOG(ERROR) << "Cannot rename " << backup << " to " << path();
+        return false;
+    }
+    return true;
+}
+
+void RestorableFile::RemoveBackupFile() {
+    UnlinkPossiblyNonExistingFile(GetBackupFilePath(path()));
+}
+
+const UniqueFile& RestorableFile::GetUniqueFile() const {
+    return unique_file_;
+}
+
+void RestorableFile::ResetAndRemoveAllFiles() {
+    std::string path(unique_file_.path());
+    reset();
+    RemoveAllFiles(path);
+}
+
+RestorableFile RestorableFile::CreateWritableFile(const std::string& path, int permissions) {
+    std::string tmp_file_path = GetTmpFilePath(path);
+    // If old tmp file exists, delete it.
+    UnlinkPossiblyNonExistingFile(tmp_file_path);
+    int fd = -1;
+    if (!path.empty()) {
+        fd = open(tmp_file_path.c_str(), O_RDWR | O_CREAT, permissions);
+        if (fd < 0) {
+            PLOG(ERROR) << "Cannot create file: " << tmp_file_path;
+        }
+    }
+    RestorableFile rf(fd, path);
+    return rf;
+}
+
+void RestorableFile::RemoveAllFiles(const std::string& path) {
+    UnlinkPossiblyNonExistingFile(GetTmpFilePath(path));
+    UnlinkPossiblyNonExistingFile(GetBackupFilePath(path));
+    UnlinkPossiblyNonExistingFile(path);
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/restorable_file.h b/cmds/installd/restorable_file.h
new file mode 100644
index 0000000..eda2292
--- /dev/null
+++ b/cmds/installd/restorable_file.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_RESTORABLE_FILE_H
+#define ANDROID_INSTALLD_RESTORABLE_FILE_H
+
+#include <functional>
+#include <string>
+
+#include "unique_file.h"
+
+namespace android {
+namespace installd {
+
+// This is a file abstraction which allows restoring to the original file while temporary work
+// file is updated.
+//
+// Typical flow for this API will be:
+// RestorableFile rf =  RestorableFile::CreateWritableFile(...)
+// write to file using file descriptor acquired from: rf.fd()
+// Make work file into a regular file with: rf.CommitWorkFile()
+// Or throw away the work file by destroying the instance without calling CommitWorkFile().
+// The temporary work file is closed / removed when an instance is destroyed without calling
+// CommitWorkFile(). The original file, if CommitWorkFile() is not called, will be kept.
+//
+// For safer restoration of original file when commit fails, following 3 steps can be taken:
+// 1. CreateBackupFile(): This renames an existing regular file into a separate backup file.
+// 2. CommitWorkFile(): Rename the work file into the regular file.
+// 3. RemoveBackupFile(): Removes the backup file
+// If CommitWorkFile fails, client can call RestoreBackupFile() which will restore regular file from
+// the backup.
+class RestorableFile {
+public:
+    // Creates invalid instance with no fd (=-1) and empty path.
+    RestorableFile();
+    RestorableFile(RestorableFile&& other) = default;
+    ~RestorableFile();
+
+    // Passes all contents of other file into the current file.
+    // Files kept for the current file will be either deleted or committed depending on
+    // CommitWorkFile() and DisableCleanUp() calls made before this.
+    RestorableFile& operator=(RestorableFile&& other) = default;
+
+    // Gets file descriptor for backing work (=temporary) file. If work file does not exist, it will
+    // return -1.
+    int fd() const { return unique_file_.fd(); }
+
+    // Gets the path name for the regular file (not temporary file).
+    const std::string& path() const { return unique_file_.path(); }
+
+    // Closes work file, deletes it and resets all internal states into default states.
+    void reset();
+
+    // Closes work file and closes all files including work file, backup file and regular file.
+    void ResetAndRemoveAllFiles();
+
+    // Creates a backup file by renaming existing regular file. This will return false if renaming
+    // fails. If regular file for renaming does not exist, it will return true.
+    bool CreateBackupFile();
+
+    // Closes existing work file and makes it a regular file.
+    // Note that the work file is closed and fd() will return -1 after this. path() will still
+    // return the original path.
+    // This will return false when committing fails (=cannot rename). Both the regular file and tmp
+    // file will be deleted when it fails.
+    bool CommitWorkFile();
+
+    // Cancels the commit and restores the backup file into the regular one. If renaming fails,
+    // it will return false. This returns true if the backup file does not exist.
+    bool RestoreBackupFile();
+
+    // Removes the backup file.
+    void RemoveBackupFile();
+
+    // Gets UniqueFile with the same path and fd() pointing to the work file.
+    const UniqueFile& GetUniqueFile() const;
+
+    // Creates writable RestorableFile. This involves creating tmp file for writing.
+    static RestorableFile CreateWritableFile(const std::string& path, int permissions);
+
+    // Removes the specified file together with tmp file generated as RestorableFile.
+    static void RemoveAllFiles(const std::string& path);
+
+private:
+    RestorableFile(int value, const std::string& path);
+
+    // Used as a storage for work file fd and path string.
+    UniqueFile unique_file_;
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_RESTORABLE_FILE_H
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 4cde7e3..51f7716 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -188,3 +188,23 @@
         "libotapreoptparameters",
     ],
 }
+
+cc_test {
+    name: "installd_file_test",
+    test_suites: ["device-tests"],
+    clang: true,
+    srcs: ["installd_file_test.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libutils",
+    ],
+    static_libs: [
+        "libinstalld",
+        "liblog",
+    ],
+}
diff --git a/cmds/installd/tests/installd_file_test.cpp b/cmds/installd/tests/installd_file_test.cpp
new file mode 100644
index 0000000..00fb308
--- /dev/null
+++ b/cmds/installd/tests/installd_file_test.cpp
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "restorable_file.h"
+#include "unique_file.h"
+#include "utils.h"
+
+#undef LOG_TAG
+#define LOG_TAG "installd_file_test"
+
+namespace {
+
+constexpr char kFileTestDir[] = "/data/local/tmp/installd_file_test_data";
+constexpr char kTmpFileSuffix[] = ".tmp";
+constexpr char kBackupFileSuffix[] = ".backup";
+
+void UnlinkWithAssert(const std::string& path) {
+    ASSERT_EQ(0, unlink(path.c_str()));
+}
+
+} // namespace
+
+namespace android {
+namespace installd {
+
+// Add these as macros as functions make it hard to tell where the failure has happened.
+#define ASSERT_FILE_NOT_EXISTING(path)           \
+    {                                            \
+        struct stat st;                          \
+        ASSERT_NE(0, ::stat(path.c_str(), &st)); \
+    }
+#define ASSERT_FILE_EXISTING(path)               \
+    {                                            \
+        struct stat st;                          \
+        ASSERT_EQ(0, ::stat(path.c_str(), &st)); \
+    }
+#define ASSERT_FILE_CONTENT(path, expectedContent) ASSERT_EQ(expectedContent, ReadTestFile(path))
+#define ASSERT_FILE_OPEN(path, fd)       \
+    {                                    \
+        fd = open(path.c_str(), O_RDWR); \
+        ASSERT_TRUE(fd >= 0);            \
+    }
+#define ASSERT_WRITE_TO_FD(fd, content) \
+    ASSERT_TRUE(android::base::WriteStringToFd(content, android::base::borrowed_fd(fd)))
+
+class FileTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+
+        ASSERT_EQ(0, create_dir_if_needed(kFileTestDir, 0777));
+    }
+
+    virtual void TearDown() {
+        system(android::base::StringPrintf("rm -rf %s", kFileTestDir).c_str());
+    }
+
+    std::string GetTestFilePath(const std::string& fileName) {
+        return android::base::StringPrintf("%s/%s", kFileTestDir, fileName.c_str());
+    }
+
+    void CreateTestFileWithContents(const std::string& path, const std::string& content) {
+        ALOGI("CreateTestFileWithContents:%s", path.c_str());
+        ASSERT_TRUE(android::base::WriteStringToFile(content, path));
+    }
+
+    std::string GetTestName() {
+        std::string name(testing::UnitTest::GetInstance()->current_test_info()->name());
+        return name;
+    }
+
+    std::string ReadTestFile(const std::string& path) {
+        std::string content;
+        bool r = android::base::ReadFileToString(path, &content);
+        if (!r) {
+            PLOG(ERROR) << "Cannot read file:" << path;
+        }
+        return content;
+    }
+};
+
+TEST_F(FileTest, TestUniqueFileMoveConstruction) {
+    const int fd = 101;
+    std::string testFile = GetTestFilePath(GetTestName());
+    UniqueFile uf1(fd, testFile);
+    uf1.DisableAutoClose();
+
+    UniqueFile uf2(std::move(uf1));
+
+    ASSERT_EQ(fd, uf2.fd());
+    ASSERT_EQ(testFile, uf2.path());
+}
+
+TEST_F(FileTest, TestUniqueFileAssignment) {
+    const int fd1 = 101;
+    const int fd2 = 102;
+    std::string testFile1 = GetTestFilePath(GetTestName());
+    std::string testFile2 = GetTestFilePath(GetTestName() + "2");
+
+    UniqueFile uf1(fd1, testFile1);
+    uf1.DisableAutoClose();
+
+    UniqueFile uf2(fd2, testFile2);
+    uf2.DisableAutoClose();
+
+    ASSERT_EQ(fd2, uf2.fd());
+    ASSERT_EQ(testFile2, uf2.path());
+
+    uf2 = std::move(uf1);
+
+    ASSERT_EQ(fd1, uf2.fd());
+    ASSERT_EQ(testFile1, uf2.path());
+}
+
+TEST_F(FileTest, TestUniqueFileCleanup) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    int fd;
+    ASSERT_FILE_OPEN(testFile, fd);
+
+    { UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert); }
+
+    ASSERT_FILE_NOT_EXISTING(testFile);
+}
+
+TEST_F(FileTest, TestUniqueFileNoCleanup) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    int fd;
+    ASSERT_FILE_OPEN(testFile, fd);
+
+    {
+        UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert);
+        uf.DisableCleanup();
+    }
+
+    ASSERT_FILE_CONTENT(testFile, "OriginalContent");
+}
+
+TEST_F(FileTest, TestUniqueFileFd) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    int fd;
+    ASSERT_FILE_OPEN(testFile, fd);
+
+    UniqueFile uf(fd, testFile, UnlinkWithAssert);
+
+    ASSERT_EQ(fd, uf.fd());
+
+    uf.reset();
+
+    ASSERT_EQ(-1, uf.fd());
+}
+
+TEST_F(FileTest, TestRestorableFileMoveConstruction) {
+    std::string testFile = GetTestFilePath(GetTestName());
+
+    RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile, 0600);
+    int fd = rf1.fd();
+
+    RestorableFile rf2(std::move(rf1));
+
+    ASSERT_EQ(fd, rf2.fd());
+    ASSERT_EQ(testFile, rf2.path());
+}
+
+TEST_F(FileTest, TestRestorableFileAssignment) {
+    std::string testFile1 = GetTestFilePath(GetTestName());
+    std::string testFile2 = GetTestFilePath(GetTestName() + "2");
+
+    RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile1, 0600);
+    int fd1 = rf1.fd();
+
+    RestorableFile rf2 = RestorableFile::CreateWritableFile(testFile2, 0600);
+    int fd2 = rf2.fd();
+
+    ASSERT_EQ(fd2, rf2.fd());
+    ASSERT_EQ(testFile2, rf2.path());
+
+    rf2 = std::move(rf1);
+
+    ASSERT_EQ(fd1, rf2.fd());
+    ASSERT_EQ(testFile1, rf2.path());
+}
+
+TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithReset) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+        ASSERT_FILE_EXISTING(tmpFile);
+
+        const UniqueFile& uf = rf.GetUniqueFile();
+
+        ASSERT_EQ(rf.fd(), uf.fd());
+        ASSERT_EQ(rf.path(), uf.path());
+
+        rf.reset();
+
+        ASSERT_EQ(rf.fd(), uf.fd());
+        ASSERT_EQ(rf.path(), uf.path());
+        ASSERT_EQ(-1, rf.fd());
+        ASSERT_TRUE(rf.path().empty());
+    }
+}
+
+TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithCommit) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+        ASSERT_FILE_EXISTING(tmpFile);
+
+        const UniqueFile& uf = rf.GetUniqueFile();
+
+        ASSERT_EQ(rf.fd(), uf.fd());
+        ASSERT_EQ(rf.path(), uf.path());
+
+        ASSERT_TRUE(rf.CreateBackupFile());
+
+        ASSERT_FILE_NOT_EXISTING(backupFile);
+
+        rf.CommitWorkFile();
+
+        ASSERT_EQ(rf.fd(), uf.fd());
+        ASSERT_EQ(rf.path(), uf.path());
+        ASSERT_EQ(-1, rf.fd());
+        ASSERT_EQ(testFile, rf.path());
+    }
+}
+
+TEST_F(FileTest, TestRestorableFileNewFileNotCommitted) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+        ASSERT_FILE_EXISTING(tmpFile);
+        ASSERT_FILE_NOT_EXISTING(testFile);
+
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+        ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+    }
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_NOT_EXISTING(testFile);
+}
+
+TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginal) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+        ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+        ASSERT_FILE_EXISTING(testFile);
+    }
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_CONTENT(testFile, "OriginalContent");
+}
+
+TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginalAndOldTmp) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+    CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+        ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+        ASSERT_FILE_EXISTING(testFile);
+    }
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_CONTENT(testFile, "OriginalContent");
+}
+
+TEST_F(FileTest, TestRestorableFileNewFileCommitted) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+        ASSERT_FILE_EXISTING(tmpFile);
+        ASSERT_FILE_NOT_EXISTING(testFile);
+
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+        ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+
+        ASSERT_TRUE(rf.CreateBackupFile());
+
+        ASSERT_FILE_NOT_EXISTING(backupFile);
+
+        ASSERT_TRUE(rf.CommitWorkFile());
+        rf.RemoveBackupFile();
+
+        ASSERT_FILE_CONTENT(testFile, "NewContent");
+    }
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_NOT_EXISTING(backupFile);
+    ASSERT_FILE_CONTENT(testFile, "NewContent");
+}
+
+TEST_F(FileTest, TestRestorableFileCommittedWithOriginal) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+        ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+
+        ASSERT_TRUE(rf.CreateBackupFile());
+
+        ASSERT_FILE_NOT_EXISTING(testFile);
+        ASSERT_FILE_EXISTING(backupFile);
+
+        ASSERT_TRUE(rf.CommitWorkFile());
+
+        ASSERT_FILE_EXISTING(backupFile);
+        ASSERT_FILE_CONTENT(testFile, "NewContent");
+
+        rf.RemoveBackupFile();
+
+        ASSERT_FILE_NOT_EXISTING(backupFile);
+    }
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_CONTENT(testFile, "NewContent");
+}
+
+TEST_F(FileTest, TestRestorableFileCommittedWithOriginalAndOldTmp) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+    CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+        ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+
+        ASSERT_TRUE(rf.CommitWorkFile());
+
+        ASSERT_FILE_CONTENT(testFile, "NewContent");
+    }
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_CONTENT(testFile, "NewContent");
+}
+
+TEST_F(FileTest, TestRestorableFileCommitFailureNoOriginal) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+        ASSERT_TRUE(rf.CreateBackupFile());
+
+        ASSERT_FILE_NOT_EXISTING(testFile);
+        ASSERT_FILE_NOT_EXISTING(backupFile);
+
+        // Now remove tmp file to force commit failure.
+        close(rf.fd());
+        ASSERT_EQ(0, unlink(tmpFile.c_str()));
+        ASSERT_FILE_NOT_EXISTING(tmpFile);
+
+        ASSERT_FALSE(rf.CommitWorkFile());
+
+        ASSERT_EQ(-1, rf.fd());
+        ASSERT_EQ(testFile, rf.path());
+        ASSERT_FILE_NOT_EXISTING(testFile);
+        ASSERT_FILE_NOT_EXISTING(tmpFile);
+
+        ASSERT_TRUE(rf.RestoreBackupFile());
+    }
+
+    ASSERT_FILE_NOT_EXISTING(testFile);
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileCommitFailureAndRollback) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+        ASSERT_TRUE(rf.CreateBackupFile());
+
+        ASSERT_FILE_NOT_EXISTING(testFile);
+        ASSERT_FILE_EXISTING(backupFile);
+
+        // Now remove tmp file to force commit failure.
+        close(rf.fd());
+        ASSERT_EQ(0, unlink(tmpFile.c_str()));
+        ASSERT_FILE_NOT_EXISTING(tmpFile);
+
+        ASSERT_FALSE(rf.CommitWorkFile());
+
+        ASSERT_EQ(-1, rf.fd());
+        ASSERT_EQ(testFile, rf.path());
+        ASSERT_FILE_NOT_EXISTING(testFile);
+        ASSERT_FILE_NOT_EXISTING(tmpFile);
+        ASSERT_FILE_EXISTING(backupFile);
+
+        ASSERT_TRUE(rf.RestoreBackupFile());
+    }
+
+    ASSERT_FILE_EXISTING(testFile);
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileResetAndRemoveAllFiles) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    {
+        RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+        ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+        ASSERT_TRUE(rf.CreateBackupFile());
+
+        ASSERT_FILE_NOT_EXISTING(testFile);
+        ASSERT_FILE_EXISTING(backupFile);
+
+        rf.ResetAndRemoveAllFiles();
+
+        ASSERT_EQ(-1, rf.fd());
+        ASSERT_FILE_NOT_EXISTING(tmpFile);
+        ASSERT_FILE_NOT_EXISTING(testFile);
+        ASSERT_FILE_NOT_EXISTING(backupFile);
+    }
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_NOT_EXISTING(testFile);
+    ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentFile) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+
+    RestorableFile::RemoveAllFiles(testFile);
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_NOT_EXISTING(testFile);
+    ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentAndTmpFile) {
+    std::string testFile = GetTestFilePath(GetTestName());
+    std::string tmpFile = testFile + kTmpFileSuffix;
+    std::string backupFile = testFile + kBackupFileSuffix;
+    CreateTestFileWithContents(testFile, "OriginalContent");
+    CreateTestFileWithContents(testFile + kTmpFileSuffix, "TmpContent");
+
+    RestorableFile::RemoveAllFiles(testFile);
+
+    ASSERT_FILE_NOT_EXISTING(tmpFile);
+    ASSERT_FILE_NOT_EXISTING(testFile);
+    ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/tests/installd_file_test.xml b/cmds/installd/tests/installd_file_test.xml
new file mode 100644
index 0000000..5ec6e3f
--- /dev/null
+++ b/cmds/installd/tests/installd_file_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_file_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push"
+                value="installd_file_test->/data/local/tmp/installd_file_test" />
+    </target_preparer>
+
+    <!-- The test requires root for file access (rollback. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_file_test" />
+    </test>
+</configuration>
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 0dd29e0..e5d689f 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -6,8 +6,8 @@
     onrestart restart apexd
     onrestart restart audioserver
     onrestart restart gatekeeperd
-    onrestart class_restart main
-    onrestart class_restart hal
-    onrestart class_restart early_hal
+    onrestart class_restart --only-enabled main
+    onrestart class_restart --only-enabled hal
+    onrestart class_restart --only-enabled early_hal
     task_profiles ServiceCapacityLow
     shutdown critical
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 9670d7b..8dbdc1d 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <array>
 #include <map> // for legacy reasons
 #include <string>
 #include <type_traits>
@@ -224,6 +225,15 @@
         return writeData(val);
     }
 
+    template <typename T, size_t N>
+    status_t writeFixedArray(const std::array<T, N>& val) {
+        return writeData(val);
+    }
+    template <typename T, size_t N>
+    status_t writeFixedArray(const std::optional<std::array<T, N>>& val) {
+        return writeData(val);
+    }
+
     // Write an Enum vector with underlying type int8_t.
     // Does not use padding; each byte is contiguous.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
@@ -487,6 +497,15 @@
                             std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const;
 
+    template <typename T, size_t N>
+    status_t readFixedArray(std::array<T, N>* val) const {
+        return readData(val);
+    }
+    template <typename T, size_t N>
+    status_t readFixedArray(std::optional<std::array<T, N>>* val) const {
+        return readData(val);
+    }
+
     template<typename T>
     status_t            read(Flattenable<T>& val) const;
 
@@ -818,6 +837,16 @@
             || is_specialization_v<T, std::unique_ptr>
             || is_specialization_v<T, std::shared_ptr>;
 
+    // Tells if T is a fixed-size array.
+    template <typename T>
+    struct is_fixed_array : std::false_type {};
+
+    template <typename T, size_t N>
+    struct is_fixed_array<std::array<T, N>> : std::true_type {};
+
+    template <typename T>
+    static inline constexpr bool is_fixed_array_v = is_fixed_array<T>::value;
+
     // special int32 value to indicate NonNull or Null parcelables
     // This is fixed to be only 0 or 1 by contract, do not change.
     static constexpr int32_t kNonNullParcelableFlag = 1;
@@ -922,7 +951,9 @@
             if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
         } else if constexpr (std::is_base_of_v<Parcelable, T>) {
             if (!c) return writeData(static_cast<int32_t>(kNullParcelableFlag));
-        } else /* constexpr */ {  // could define this, but raise as error.
+        } else if constexpr (is_fixed_array_v<T>) {
+            if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
+        } else /* constexpr */ { // could define this, but raise as error.
             static_assert(dependent_false_v<CT>);
         }
         return writeData(*c);
@@ -961,6 +992,23 @@
         return OK;
     }
 
+    template <typename T, size_t N>
+    status_t writeData(const std::array<T, N>& val) {
+        static_assert(N <= std::numeric_limits<int32_t>::max());
+        status_t status = writeData(static_cast<int32_t>(N));
+        if (status != OK) return status;
+        if constexpr (is_pointer_equivalent_array_v<T>) {
+            static_assert(N <= std::numeric_limits<size_t>::max() / sizeof(T));
+            return write(val.data(), val.size() * sizeof(T));
+        } else /* constexpr */ {
+            for (const auto& t : val) {
+                status = writeData(t);
+                if (status != OK) return status;
+            }
+            return OK;
+        }
+    }
+
     // readData function overloads.
     // Implementation detail: Function overloading improves code readability over
     // template overloading, but prevents readData<T> from being used for those types.
@@ -1053,9 +1101,8 @@
         int32_t peek;
         status_t status = readData(&peek);
         if (status != OK) return status;
-        if constexpr (is_specialization_v<T, std::vector>
-                || std::is_same_v<T, String16>
-                || std::is_same_v<T, std::string>) {
+        if constexpr (is_specialization_v<T, std::vector> || is_fixed_array_v<T> ||
+                      std::is_same_v<T, String16> || std::is_same_v<T, std::string>) {
             if (peek == kNullVectorSize) {
                 c->reset();
                 return OK;
@@ -1065,12 +1112,15 @@
                 c->reset();
                 return OK;
             }
-        } else /* constexpr */ {  // could define this, but raise as error.
+        } else /* constexpr */ { // could define this, but raise as error.
             static_assert(dependent_false_v<CT>);
         }
         // create a new object.
         if constexpr (is_specialization_v<CT, std::optional>) {
-            c->emplace();
+            // Call default constructor explicitly
+            // - Clang bug: https://bugs.llvm.org/show_bug.cgi?id=35748
+            //   std::optional::emplace() doesn't work with nested types.
+            c->emplace(T());
         } else /* constexpr */ {
             T* const t = new (std::nothrow) T;  // contents read from Parcel below.
             if (t == nullptr) return NO_MEMORY;
@@ -1079,7 +1129,7 @@
         // rewind data ptr to reread (this is pretty quick), otherwise we could
         // pass an optional argument to readData to indicate a peeked value.
         setDataPosition(startPos);
-        if constexpr (is_specialization_v<T, std::vector>) {
+        if constexpr (is_specialization_v<T, std::vector> || is_fixed_array_v<T>) {
             return readData(&**c, READ_FLAG_SP_NULLABLE);  // nullable sp<> allowed now
         } else {
             return readData(&**c);
@@ -1142,6 +1192,41 @@
         return OK;
     }
 
+    template <typename T, size_t N>
+    status_t readData(std::array<T, N>* val, ReadFlags readFlags = READ_FLAG_NONE) const {
+        static_assert(N <= std::numeric_limits<int32_t>::max());
+        int32_t size;
+        status_t status = readInt32(&size);
+        if (status != OK) return status;
+        if (size < 0) return UNEXPECTED_NULL;
+        if (size != static_cast<int32_t>(N)) return BAD_VALUE;
+        if constexpr (is_pointer_equivalent_array_v<T>) {
+            auto data = reinterpret_cast<const T*>(readInplace(N * sizeof(T)));
+            if (data == nullptr) return BAD_VALUE;
+            memcpy(val->data(), data, N * sizeof(T));
+        } else if constexpr (is_specialization_v<T, sp>) {
+            for (auto& t : *val) {
+                if (readFlags & READ_FLAG_SP_NULLABLE) {
+                    status = readNullableStrongBinder(&t); // allow nullable
+                } else {
+                    status = readStrongBinder(&t);
+                }
+                if (status != OK) return status;
+            }
+        } else if constexpr (is_fixed_array_v<T>) { // pass readFlags down to nested arrays
+            for (auto& t : *val) {
+                status = readData(&t, readFlags);
+                if (status != OK) return status;
+            }
+        } else /* constexpr */ {
+            for (auto& t : *val) {
+                status = readData(&t);
+                if (status != OK) return status;
+            }
+        }
+        return OK;
+    }
+
     //-----------------------------------------------------------------------------
     private:
 
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index aa3b978..972eca7 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -46,6 +46,18 @@
     AParcelableHolder() = delete;
     explicit AParcelableHolder(parcelable_stability_t stability)
         : mParcel(AParcel_create()), mStability(stability) {}
+
+#if __ANDROID_API__ >= 31
+    AParcelableHolder(const AParcelableHolder& other)
+        : mParcel(AParcel_create()), mStability(other.mStability) {
+        // AParcelableHolder has been introduced in 31.
+        if (__builtin_available(android 31, *)) {
+            AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
+                               AParcel_getDataSize(other.mParcel.get()));
+        }
+    }
+#endif
+
     AParcelableHolder(AParcelableHolder&& other) = default;
     virtual ~AParcelableHolder() = default;
 
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 32406e5..077d915 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -233,6 +233,32 @@
     PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<std::string>>>, readUtf8VectorFromUtf16Vector),
     PARCEL_READ_WITH_STATUS(std::vector<std::string>, readUtf8VectorFromUtf16Vector),
 
+#define COMMA ,
+    PARCEL_READ_WITH_STATUS(std::array<uint8_t COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<uint8_t COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<char16_t COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<char16_t COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<std::string COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<std::optional<std::string> COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<android::String16 COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<std::optional<android::String16> COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<android::sp<android::IBinder> COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<android::sp<android::IBinder> COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<ExampleParcelable COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<std::optional<ExampleParcelable> COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<ByteEnum COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<ByteEnum COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<IntEnum COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<IntEnum COMMA 3>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<LongEnum COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<LongEnum COMMA 3>>, readFixedArray),
+    // nested arrays
+    PARCEL_READ_WITH_STATUS(std::array<std::array<uint8_t COMMA 3> COMMA 4>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<std::array<uint8_t COMMA 3> COMMA 4>>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::array<ExampleParcelable COMMA 3>, readFixedArray),
+    PARCEL_READ_WITH_STATUS(std::optional<std::array<std::array<std::optional<ExampleParcelable> COMMA 3> COMMA 4>>, readFixedArray),
+#undef COMMA
+
     [] (const android::Parcel& p, uint8_t /*len*/) {
         FUZZ_LOG() << "about to read flattenable";
         ExampleFlattenable f;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index a7b5900..936e653 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -138,6 +138,7 @@
         "HdrCapabilities.cpp",
         "PixelFormat.cpp",
         "PublicFormat.cpp",
+        "StaticAsserts.cpp",
         "StaticDisplayInfo.cpp",
     ],
 
diff --git a/libs/ui/StaticAsserts.cpp b/libs/ui/StaticAsserts.cpp
new file mode 100644
index 0000000..85da64f
--- /dev/null
+++ b/libs/ui/StaticAsserts.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/PixelFormat.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+
+// Ideally, PIXEL_FORMAT_R_8 would simply be defined to match the aidl PixelFormat, but
+// PixelFormat.h (where PIXEL_FORMAT_R_8 is defined) is pulled in by builds for
+// which there is no aidl build (e.g. Windows).
+static_assert(android::PIXEL_FORMAT_R_8 ==static_cast<int32_t>(
+                                  aidl::android::hardware::graphics::common::PixelFormat::R_8));
diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc
index 65a5c27..0da8bd3 100644
--- a/services/gpuservice/gpuservice.rc
+++ b/services/gpuservice/gpuservice.rc
@@ -1,4 +1,4 @@
 service gpu /system/bin/gpuservice
     class core
     user gpu_service
-    group graphics
+    group graphics readtracefs
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e6bcec8..94ad6c3 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -539,6 +539,7 @@
             break;
         case Composition::CURSOR:
         case Composition::DEVICE:
+        case Composition::DISPLAY_DECORATION:
             writeBufferStateToHWC(hwcLayer, outputIndependentState, skipLayer);
             break;
         case Composition::INVALID:
@@ -684,6 +685,7 @@
 
         case Composition::DEVICE:
         case Composition::SOLID_COLOR:
+        case Composition::DISPLAY_DECORATION:
             result = (to == Composition::CLIENT);
             break;
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
index 074673e..2d53583 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
@@ -114,6 +114,10 @@
                 plan.addLayerType(
                         aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR);
                 continue;
+            case 'A':
+                plan.addLayerType(aidl::android::hardware::graphics::composer3::Composition::
+                                          DISPLAY_DECORATION);
+                continue;
             default:
                 return std::nullopt;
         }
@@ -143,6 +147,10 @@
             case aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR:
                 result.append("S");
                 break;
+            case aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION:
+                // A for "Alpha", since the decoration is an alpha layer.
+                result.append("A");
+                break;
         }
     }
     return result;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index c9b6144..3bed796 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -253,6 +253,13 @@
 
 AidlComposer::~AidlComposer() = default;
 
+bool AidlComposer::isSupported(OptionalFeature feature) const {
+    switch (feature) {
+        case OptionalFeature::RefreshRateSwitching:
+            return true;
+    }
+}
+
 std::vector<IComposer::Capability> AidlComposer::getCapabilities() {
     std::vector<Capability> capabilities;
     const auto status = mAidlComposer->getCapabilities(&capabilities);
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 057ba89..076b898 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -56,6 +56,8 @@
     explicit AidlComposer(const std::string& serviceName);
     ~AidlComposer() override;
 
+    bool isSupported(OptionalFeature) const;
+
     std::vector<IComposer::Capability> getCapabilities() override;
     std::string dumpDebugInfo() override;
 
@@ -178,7 +180,6 @@
     Error setDisplayBrightness(Display display, float brightness) override;
 
     // Composer HAL 2.4
-    bool isVsyncPeriodSwitchSupported() override { return true; }
     Error getDisplayCapabilities(Display display,
                                  std::vector<DisplayCapability>* outCapabilities) override;
     V2_4::Error getDisplayConnectionType(Display display,
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index b4ba8ab..6f2aa78 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -75,6 +75,12 @@
 
     virtual ~Composer() = 0;
 
+    enum class OptionalFeature {
+        RefreshRateSwitching,
+    };
+
+    virtual bool isSupported(OptionalFeature) const = 0;
+
     virtual std::vector<IComposer::Capability> getCapabilities() = 0;
     virtual std::string dumpDebugInfo() = 0;
 
@@ -200,7 +206,6 @@
     virtual Error setDisplayBrightness(Display display, float brightness) = 0;
 
     // Composer HAL 2.4
-    virtual bool isVsyncPeriodSwitchSupported() = 0;
     virtual Error getDisplayCapabilities(Display display,
                                          std::vector<DisplayCapability>* outCapabilities) = 0;
     virtual V2_4::Error getDisplayConnectionType(
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 82f463e..5dbec05 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -144,7 +144,7 @@
 bool Display::isVsyncPeriodSwitchSupported() const {
     ALOGV("[%" PRIu64 "] isVsyncPeriodSwitchSupported()", mId);
 
-    return mComposer.isVsyncPeriodSwitchSupported();
+    return mComposer.isSupported(android::Hwc2::Composer::OptionalFeature::RefreshRateSwitching);
 }
 
 Error Display::getChangedCompositionTypes(std::unordered_map<HWC2::Layer*, Composition>* outTypes) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d851e22..514c879 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -159,8 +159,10 @@
     }
     mRegisteredCallback = true;
 
+    const bool vsyncSwitchingSupported =
+            mComposer->isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching);
     mComposer->registerCallback(
-            sp<ComposerCallbackBridge>::make(callback, mComposer->isVsyncPeriodSwitchSupported()));
+            sp<ComposerCallbackBridge>::make(callback, vsyncSwitchingSupported));
 }
 
 bool HWComposer::getDisplayIdentificationData(hal::HWDisplayId hwcDisplayId, uint8_t* outPort,
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 77e704f..7236868 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -111,6 +111,8 @@
             return "Cursor";
         case aidl::android::hardware::graphics::composer3::Composition::SIDEBAND:
             return "Sideband";
+        case aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION:
+            return "DisplayDecoration";
         default:
             return "Unknown";
     }
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 18f24c1..ab16027 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -30,6 +30,7 @@
 #include <hidl/HidlTransportUtils.h>
 #include <log/log.h>
 #include <utils/Trace.h>
+#include "Hal.h"
 
 #include <algorithm>
 #include <cinttypes>
@@ -153,6 +154,13 @@
     }
 }
 
+bool HidlComposer::isSupported(OptionalFeature feature) const {
+    switch (feature) {
+        case OptionalFeature::RefreshRateSwitching:
+            return mClient_2_4 != nullptr;
+    }
+}
+
 std::vector<IComposer::Capability> HidlComposer::getCapabilities() {
     std::vector<IComposer::Capability> capabilities;
     mComposer->getCapabilities(
@@ -620,6 +628,11 @@
 
 static IComposerClient::Composition to_hidl_type(
         aidl::android::hardware::graphics::composer3::Composition type) {
+    LOG_ALWAYS_FATAL_IF(static_cast<int32_t>(type) >
+                                static_cast<int32_t>(IComposerClient::Composition::SIDEBAND),
+                        "Trying to use %s, which is not supported by HidlComposer!",
+                        android::to_string(type).c_str());
+
     return static_cast<IComposerClient::Composition>(type);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 5b2219e..d60d12c 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -168,6 +168,8 @@
     explicit HidlComposer(const std::string& serviceName);
     ~HidlComposer() override;
 
+    bool isSupported(OptionalFeature) const;
+
     std::vector<IComposer::Capability> getCapabilities() override;
     std::string dumpDebugInfo() override;
 
@@ -290,7 +292,6 @@
     Error setDisplayBrightness(Display display, float brightness) override;
 
     // Composer HAL 2.4
-    bool isVsyncPeriodSwitchSupported() override { return mClient_2_4 != nullptr; }
     Error getDisplayCapabilities(Display display,
                                  std::vector<DisplayCapability>* outCapabilities) override;
     V2_4::Error getDisplayConnectionType(Display display,
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 655baf8..01724dc 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -86,7 +86,8 @@
                             }),
                             Return(hardware::graphics::composer::V2_4::Error::NONE)));
     EXPECT_CALL(*mHal, registerCallback(_));
-    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+    EXPECT_CALL(*mHal, isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching))
+            .WillOnce(Return(false));
 
     impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
     hwc.setCallback(&mCallback);
@@ -104,7 +105,8 @@
     EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
             .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
     EXPECT_CALL(*mHal, registerCallback(_));
-    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+    EXPECT_CALL(*mHal, isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching))
+            .WillOnce(Return(false));
 
     impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
     hwc.setCallback(&mCallback);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 9796a70..56a0506 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -52,7 +52,8 @@
 
         // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy
         // will call setActiveConfig instead of setActiveConfigWithConstraints.
-        ON_CALL(*mComposer, isVsyncPeriodSwitchSupported()).WillByDefault(Return(true));
+        ON_CALL(*mComposer, isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching))
+                .WillByDefault(Return(true));
     }
 
 protected:
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index c3250d5..5cf8278 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -48,6 +48,7 @@
     Composer();
     ~Composer() override;
 
+    MOCK_METHOD(bool, isSupported, (OptionalFeature), (const, override));
     MOCK_METHOD0(getCapabilities, std::vector<IComposer::Capability>());
     MOCK_METHOD0(dumpDebugInfo, std::string());
     MOCK_METHOD1(registerCallback, void(const sp<IComposerCallback>&));
@@ -119,7 +120,6 @@
     MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
                  Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
     MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
-    MOCK_METHOD0(isVsyncPeriodSwitchSupported, bool());
     MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
     MOCK_METHOD2(getDisplayConnectionType,
                  V2_4::Error(Display, IComposerClient::DisplayConnectionType*));
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index eb4befd..e6717d7 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1222,12 +1222,14 @@
         swap_interval ? create_info->minImageCount : mailbox_num_images;
     uint32_t num_images = requested_images - 1 + min_undequeued_buffers;
 
-    // Lower layer insists that we have at least two buffers. This is wasteful
-    // and we'd like to relax it in the shared case, but not all the pieces are
-    // in place for that to work yet. Note we only lie to the lower layer-- we
-    // don't want to give the app back a swapchain with extra images (which they
-    // can't actually use!).
-    err = native_window_set_buffer_count(window, std::max(2u, num_images));
+    // Lower layer insists that we have at least min_undequeued_buffers + 1
+    // buffers.  This is wasteful and we'd like to relax it in the shared case,
+    // but not all the pieces are in place for that to work yet.  Note we only
+    // lie to the lower layer--we don't want to give the app back a swapchain
+    // with extra images (which they can't actually use!).
+    uint32_t min_buffer_count = min_undequeued_buffers + 1;
+    err = native_window_set_buffer_count(
+        window, std::max(min_buffer_count, num_images));
     if (err != android::OK) {
         ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
               strerror(-err), err);