Merge "SF: rename CommandWriterBase and CommandReaderBase"
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/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2935c6a..d4c17fe 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -419,10 +419,17 @@
int res = 0;
char* before = nullptr;
char* after = nullptr;
+ if (!existing) {
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
+ SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
+ PLOG(ERROR) << "Failed recursive restorecon for " << path;
+ goto fail;
+ }
+ return res;
+ }
// Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
// libselinux. Not needed here.
-
if (lgetfilecon(path.c_str(), &before) < 0) {
PLOG(ERROR) << "Failed before getfilecon for " << path;
goto fail;
@@ -459,12 +466,6 @@
return res;
}
-static int restorecon_app_data_lazy(const std::string& parent, const char* name,
- const std::string& seInfo, uid_t uid, bool existing) {
- return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seInfo, uid,
- existing);
-}
-
static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
PLOG(ERROR) << "Failed to prepare " << path;
@@ -610,8 +611,14 @@
int32_t uid, int32_t* previousUid, int32_t cacheGid,
const std::string& seInfo, mode_t targetMode) {
struct stat st{};
- bool existing = (stat(path.c_str(), &st) == 0);
- if (existing) {
+ bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
+
+ auto cache_path = StringPrintf("%s/%s", path.c_str(), "cache");
+ auto code_cache_path = StringPrintf("%s/%s", path.c_str(), "code_cache");
+ bool cache_exists = (access(cache_path.c_str(), F_OK) == 0);
+ bool code_cache_exists = (access(code_cache_path.c_str(), F_OK) == 0);
+
+ if (parent_dir_exists) {
if (*previousUid < 0) {
// If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
// of the directory as previousUid. This is required because it is not always possible
@@ -625,6 +632,7 @@
}
}
+ // Prepare only the parent app directory
if (prepare_app_dir(path, targetMode, uid) ||
prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
@@ -632,12 +640,23 @@
}
// Consider restorecon over contents if label changed
- if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
+ if (restorecon_app_data_lazy(path, seInfo, uid, parent_dir_exists)) {
return error("Failed to restorecon " + path);
}
+ // If the parent dir exists, the restorecon would already have been done
+ // as a part of the recursive restorecon above
+ if (parent_dir_exists && !cache_exists
+ && restorecon_app_data_lazy(cache_path, seInfo, uid, false)) {
+ return error("Failed to restorecon " + cache_path);
+ }
+
+ // If the parent dir exists, the restorecon would already have been done
+ // as a part of the recursive restorecon above
+ if (parent_dir_exists && !code_cache_exists
+ && restorecon_app_data_lazy(code_cache_path, seInfo, uid, false)) {
+ return error("Failed to restorecon " + code_cache_path);
+ }
return ok();
}
@@ -2863,7 +2882,6 @@
binder::Status InstalldNativeService::rmPackageDir(const std::string& packageName,
const std::string& packageDir) {
ENFORCE_UID(AID_SYSTEM);
- CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(packageDir);
LOCK_PACKAGE();
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/include/android/input.h b/include/android/input.h
index 27587ce..447f8fa 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -1391,7 +1391,7 @@
*
* Available since API level 33.
*/
-AInputQueue* AInputQueue_fromJava(jobject inputQueue) __INTRODUCED_IN(33);
+AInputQueue* AInputQueue_fromJava(JNIEnv* env, jobject inputQueue) __INTRODUCED_IN(33);
#ifdef __cplusplus
}
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 059bc41..3a13104 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -595,6 +595,15 @@
bool enableBackPressure)
__INTRODUCED_IN(31);
+/**
+ * Sets the frame timeline to use.
+ *
+ * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to
+ * the corresponding expected present time and deadline from the frame to be rendered.
+ */
+void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
+ int64_t vsyncId) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 2c6eacb..dfb0ff5 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -201,10 +201,8 @@
std::array<std::atomic<HalSupport>,
static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1>
mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN};
- // Android framework only sends mode upto DISPLAY_INACTIVE.
- // Need to increase the array if more mode supported.
std::array<std::atomic<HalSupport>,
- static_cast<int32_t>(hardware::power::Mode::DISPLAY_INACTIVE) + 1>
+ static_cast<int32_t>(*(android::enum_range<hardware::power::Mode>().end() - 1)) + 1>
mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN};
};
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_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index e5560f8..0bf1e3d 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -31,6 +31,7 @@
#include <android/binder_internal_logging.h>
#include <android/binder_parcel.h>
+#include <array>
#include <optional>
#include <string>
#include <type_traits>
@@ -86,9 +87,87 @@
(is_specialization_v<T, std::optional> ||
is_specialization_v<T, std::unique_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;
+
+template <typename T>
+static inline constexpr bool dependent_false_v = false;
} // namespace
/**
+ * This checks the length against the array size and retrieves the buffer. No allocation required.
+ */
+template <typename T, size_t N>
+static inline bool AParcel_stdArrayAllocator(void* arrayData, int32_t length, T** outBuffer) {
+ if (length < 0) return false;
+
+ if (length != static_cast<int32_t>(N)) {
+ return false;
+ }
+
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
+ *outBuffer = arr->data();
+ return true;
+}
+
+/**
+ * This checks the length against the array size and retrieves the buffer. No allocation required.
+ */
+template <typename T, size_t N>
+static inline bool AParcel_nullableStdArrayAllocator(void* arrayData, int32_t length,
+ T** outBuffer) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
+ if (length < 0) {
+ *arr = std::nullopt;
+ return true;
+ }
+
+ if (length != static_cast<int32_t>(N)) {
+ return false;
+ }
+
+ arr->emplace();
+ *outBuffer = (*arr)->data();
+ return true;
+}
+
+/**
+ * This checks the length against the array size. No allocation required.
+ */
+template <size_t N>
+static inline bool AParcel_stdArrayExternalAllocator(void* arrayData, int32_t length) {
+ (void)arrayData;
+ return length == static_cast<int32_t>(N);
+}
+
+/**
+ * This checks the length against the array size. No allocation required.
+ */
+template <typename T, size_t N>
+static inline bool AParcel_nullableStdArrayExternalAllocator(void* arrayData, int32_t length) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
+
+ if (length < 0) {
+ *arr = std::nullopt;
+ return true;
+ }
+
+ if (length != static_cast<int32_t>(N)) {
+ return false;
+ }
+
+ arr->emplace();
+ return true;
+}
+
+/**
* This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
*/
template <typename T>
@@ -397,6 +476,118 @@
}
/**
+ * This retrieves the underlying value in a std::array which may not be contiguous at index from a
+ * corresponding arrData.
+ */
+template <typename T, size_t N>
+static inline T AParcel_stdArrayGetter(const void* arrData, size_t index) {
+ const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrData);
+ return (*arr)[index];
+}
+
+/**
+ * This sets the underlying value in a corresponding arrData which may not be contiguous at
+ * index.
+ */
+template <typename T, size_t N>
+static inline void AParcel_stdArraySetter(void* arrData, size_t index, T value) {
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrData);
+ (*arr)[index] = value;
+}
+
+/**
+ * This retrieves the underlying value in a std::array which may not be contiguous at index from a
+ * corresponding arrData.
+ */
+template <typename T, size_t N>
+static inline T AParcel_nullableStdArrayGetter(const void* arrData, size_t index) {
+ const std::optional<std::array<T, N>>* arr =
+ static_cast<const std::optional<std::array<T, N>>*>(arrData);
+ return (*arr)[index];
+}
+
+/**
+ * This sets the underlying value in a corresponding arrData which may not be contiguous at
+ * index.
+ */
+template <typename T, size_t N>
+static inline void AParcel_nullableStdArraySetter(void* arrData, size_t index, T value) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrData);
+ (*arr)->at(index) = value;
+}
+
+/**
+ * Allocates a std::string inside of std::array<std::string, N> at index 'index' to size 'length'.
+ */
+template <size_t N>
+static inline bool AParcel_stdArrayStringElementAllocator(void* arrData, size_t index,
+ int32_t length, char** buffer) {
+ std::array<std::string, N>* arr = static_cast<std::array<std::string, N>*>(arrData);
+ std::string& element = arr->at(index);
+ return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::string inside of a std::array<std::string, N> at index
+ * 'index'.
+ */
+template <size_t N>
+static const char* AParcel_stdArrayStringElementGetter(const void* arrData, size_t index,
+ int32_t* outLength) {
+ const std::array<std::string, N>* arr = static_cast<const std::array<std::string, N>*>(arrData);
+ const std::string& element = arr->at(index);
+
+ *outLength = static_cast<int32_t>(element.size());
+ return element.c_str();
+}
+
+/**
+ * Allocates a std::string inside of std::array<std::optional<std::string>, N> at index 'index' to
+ * size 'length'.
+ */
+template <size_t N>
+static inline bool AParcel_stdArrayNullableStringElementAllocator(void* arrData, size_t index,
+ int32_t length, char** buffer) {
+ std::array<std::optional<std::string>, N>* arr =
+ static_cast<std::array<std::optional<std::string>, N>*>(arrData);
+ std::optional<std::string>& element = arr->at(index);
+ return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::string inside of a
+ * std::array<std::optional<std::string>, N> at index 'index'.
+ */
+template <size_t N>
+static const char* AParcel_stdArrayNullableStringElementGetter(const void* arrData, size_t index,
+ int32_t* outLength) {
+ const std::array<std::optional<std::string>, N>* arr =
+ static_cast<const std::array<std::optional<std::string>, N>*>(arrData);
+ const std::optional<std::string>& element = arr->at(index);
+
+ if (!element) {
+ *outLength = -1;
+ return nullptr;
+ }
+
+ *outLength = static_cast<int32_t>(element->size());
+ return element->c_str();
+}
+
+/**
+ * Allocates a std::string inside of std::optional<std::array<std::optional<std::string>, N>> at
+ * index 'index' to size 'length'.
+ */
+template <size_t N>
+static inline bool AParcel_nullableStdArrayStringElementAllocator(void* arrData, size_t index,
+ int32_t length, char** buffer) {
+ std::optional<std::array<std::optional<std::string>, N>>* arr =
+ static_cast<std::optional<std::array<std::optional<std::string>, N>>*>(arrData);
+ std::optional<std::string>& element = (*arr)->at(index);
+ return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
* Convenience API for writing a std::string.
*/
static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
@@ -571,6 +762,64 @@
}
}
+// Forward decls
+template <typename T>
+static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value);
+template <typename T>
+static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value);
+template <typename T>
+static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value);
+template <typename T>
+static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value);
+
+/**
+ * Reads an object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_readStdArrayData(const AParcel* parcel, void* arrayData, size_t index) {
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
+ return AParcel_readData(parcel, &arr->at(index));
+}
+
+/**
+ * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_readStdArrayNullableData(const AParcel* parcel, void* arrayData,
+ size_t index) {
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
+ return AParcel_readNullableData(parcel, &arr->at(index));
+}
+
+/**
+ * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_readNullableStdArrayNullableData(const AParcel* parcel, void* arrayData,
+ size_t index) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
+ return AParcel_readNullableData(parcel, &(*arr)->at(index));
+}
+
+/**
+ * Writes an object of type T inside a std::array<T, N> at index 'index' to 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_writeStdArrayData(AParcel* parcel, const void* arrayData, size_t index) {
+ const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData);
+ return AParcel_writeData(parcel, arr->at(index));
+}
+
+/**
+ * Writes a nullable object of type T inside a std::array<T, N> at index 'index' to 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_writeStdArrayNullableData(AParcel* parcel, const void* arrayData,
+ size_t index) {
+ const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData);
+ return AParcel_writeNullableData(parcel, arr->at(index));
+}
+
/**
* Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
*/
@@ -714,9 +963,25 @@
*/
template <typename P>
static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
- const void* vectorData = static_cast<const void*>(&vec);
- return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
- AParcel_writeStdVectorParcelableElement<P>);
+ if constexpr (std::is_enum_v<P>) {
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()),
+ static_cast<int32_t>(vec.size()));
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_writeInt32Array(parcel, reinterpret_cast<const int32_t*>(vec.data()),
+ static_cast<int32_t>(vec.size()));
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_writeInt64Array(parcel, reinterpret_cast<const int64_t*>(vec.data()),
+ static_cast<int32_t>(vec.size()));
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::string>, "specialization should be used");
+ const void* vectorData = static_cast<const void*>(&vec);
+ return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
+ AParcel_writeStdVectorParcelableElement<P>);
+ }
}
/**
@@ -724,9 +989,24 @@
*/
template <typename P>
static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readParcelableArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<P>,
- AParcel_readStdVectorParcelableElement<P>);
+ if constexpr (std::is_enum_v<P>) {
+ void* vectorData = static_cast<void*>(vec);
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::string>, "specialization should be used");
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readParcelableArray(parcel, vectorData,
+ AParcel_stdVectorExternalAllocator<P>,
+ AParcel_readStdVectorParcelableElement<P>);
+ }
}
/**
@@ -735,10 +1015,30 @@
template <typename P>
static inline binder_status_t AParcel_writeVector(AParcel* parcel,
const std::optional<std::vector<P>>& vec) {
- if (!vec) return AParcel_writeInt32(parcel, -1);
- const void* vectorData = static_cast<const void*>(&vec);
- return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec->size()),
- AParcel_writeNullableStdVectorParcelableElement<P>);
+ if constexpr (std::is_enum_v<P>) {
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_writeByteArray(
+ parcel, vec ? reinterpret_cast<const int8_t*>(vec->data()) : nullptr,
+ vec ? static_cast<int32_t>(vec->size()) : -1);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_writeInt32Array(
+ parcel, vec ? reinterpret_cast<const int32_t*>(vec->data()) : nullptr,
+ vec ? static_cast<int32_t>(vec->size()) : -1);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_writeInt64Array(
+ parcel, vec ? reinterpret_cast<const int64_t*>(vec->data()) : nullptr,
+ vec ? static_cast<int32_t>(vec->size()) : -1);
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::optional<std::string>>,
+ "specialization should be used");
+ if (!vec) return AParcel_writeInt32(parcel, -1);
+ const void* vectorData = static_cast<const void*>(&vec);
+ return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec->size()),
+ AParcel_writeNullableStdVectorParcelableElement<P>);
+ }
}
/**
@@ -747,10 +1047,28 @@
template <typename P>
static inline binder_status_t AParcel_readVector(const AParcel* parcel,
std::optional<std::vector<P>>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readParcelableArray(parcel, vectorData,
- AParcel_nullableStdVectorExternalAllocator<P>,
- AParcel_readNullableStdVectorParcelableElement<P>);
+ if constexpr (std::is_enum_v<P>) {
+ void* vectorData = static_cast<void*>(vec);
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_readByteArray(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<int8_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_readInt32Array(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<int32_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_readInt64Array(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<int64_t>);
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::optional<std::string>>,
+ "specialization should be used");
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readParcelableArray(parcel, vectorData,
+ AParcel_nullableStdVectorExternalAllocator<P>,
+ AParcel_readNullableStdVectorParcelableElement<P>);
+ }
}
// @START
@@ -1132,6 +1450,294 @@
return STATUS_OK;
}
+/**
+ * Writes a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_writeFixedArray(AParcel* parcel,
+ const std::array<T, N>& arr) {
+ if constexpr (std::is_same_v<T, bool>) {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeBoolArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_stdArrayGetter<T, N>);
+ } else if constexpr (std::is_same_v<T, uint8_t>) {
+ return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(arr.data()),
+ static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, char16_t>) {
+ return AParcel_writeCharArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ return AParcel_writeInt32Array(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return AParcel_writeInt64Array(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, float>) {
+ return AParcel_writeFloatArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, double>) {
+ return AParcel_writeDoubleArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_stdArrayStringElementGetter<N>);
+ } else {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_writeStdArrayData<T, N>);
+ }
+}
+
+/**
+ * Writes a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_writeFixedArrayWithNullableData(AParcel* parcel,
+ const std::array<T, N>& arr) {
+ if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> ||
+ std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> ||
+ std::is_same_v<T, int64_t> || std::is_same_v<T, float> ||
+ std::is_same_v<T, double> || std::is_same_v<T, std::string>) {
+ return AParcel_writeFixedArray(parcel, arr);
+ } else if constexpr (std::is_same_v<T, std::optional<std::string>>) {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_stdArrayNullableStringElementGetter<N>);
+ } else {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_writeStdArrayNullableData<T, N>);
+ }
+}
+
+/**
+ * Writes a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_writeNullableFixedArrayWithNullableData(
+ AParcel* parcel, const std::optional<std::array<T, N>>& arr) {
+ if (!arr) return AParcel_writeInt32(parcel, -1);
+ return AParcel_writeFixedArrayWithNullableData(parcel, arr.value());
+}
+
+/**
+ * Reads a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_readFixedArray(const AParcel* parcel, std::array<T, N>* arr) {
+ void* arrayData = static_cast<void*>(arr);
+ if constexpr (std::is_same_v<T, bool>) {
+ return AParcel_readBoolArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_stdArraySetter<T, N>);
+ } else if constexpr (std::is_same_v<T, uint8_t>) {
+ return AParcel_readByteArray(parcel, arrayData, &AParcel_stdArrayAllocator<int8_t, N>);
+ } else if constexpr (std::is_same_v<T, char16_t>) {
+ return AParcel_readCharArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ return AParcel_readInt32Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return AParcel_readInt64Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, float>) {
+ return AParcel_readFloatArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, double>) {
+ return AParcel_readDoubleArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_stdArrayStringElementAllocator<N>);
+ } else {
+ return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_readStdArrayData<T, N>);
+ }
+}
+
+/**
+ * Reads a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_readFixedArrayWithNullableData(const AParcel* parcel,
+ std::array<T, N>* arr) {
+ void* arrayData = static_cast<void*>(arr);
+ if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> ||
+ std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> ||
+ std::is_same_v<T, int64_t> || std::is_same_v<T, float> ||
+ std::is_same_v<T, double> || std::is_same_v<T, std::string>) {
+ return AParcel_readFixedArray(parcel, arr);
+ } else if constexpr (std::is_same_v<T, std::optional<std::string>>) {
+ return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_stdArrayNullableStringElementAllocator<N>);
+ } else {
+ return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_readStdArrayNullableData<T, N>);
+ }
+}
+
+/**
+ * Reads a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_readNullableFixedArrayWithNullableData(
+ const AParcel* parcel, std::optional<std::array<T, N>>* arr) {
+ void* arrayData = static_cast<void*>(arr);
+ if constexpr (std::is_same_v<T, bool>) {
+ return AParcel_readBoolArray(parcel, arrayData,
+ &AParcel_nullableStdArrayExternalAllocator<T, N>,
+ &AParcel_nullableStdArraySetter<T, N>);
+ } else if constexpr (std::is_same_v<T, uint8_t>) {
+ return AParcel_readByteArray(parcel, arrayData,
+ &AParcel_nullableStdArrayAllocator<int8_t, N>);
+ } else if constexpr (std::is_same_v<T, char16_t>) {
+ return AParcel_readCharArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ return AParcel_readInt32Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return AParcel_readInt64Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, float>) {
+ return AParcel_readFloatArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, double>) {
+ return AParcel_readDoubleArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ return AParcel_readStringArray(parcel, arrayData,
+ &AParcel_nullableStdArrayExternalAllocator<N>,
+ &AParcel_nullableStdArrayStringElementAllocator<N>);
+ } else {
+ return AParcel_readParcelableArray(parcel, arrayData,
+ &AParcel_nullableStdArrayExternalAllocator<T, N>,
+ &AParcel_readStdArrayNullableData<T, N>);
+ }
+}
+
+/**
+ * Convenience API for writing a value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value) {
+ if constexpr (is_specialization_v<T, std::vector>) {
+ return AParcel_writeVector(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) {
+ return AParcel_writeFixedArray(parcel, value);
+ } else if constexpr (std::is_same_v<std::string, T>) {
+ return AParcel_writeString(parcel, value);
+ } else if constexpr (std::is_same_v<bool, T>) {
+ return AParcel_writeBool(parcel, value);
+ } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) {
+ return AParcel_writeByte(parcel, value);
+ } else if constexpr (std::is_same_v<char16_t, T>) {
+ return AParcel_writeChar(parcel, value);
+ } else if constexpr (std::is_same_v<int32_t, T>) {
+ return AParcel_writeInt32(parcel, value);
+ } else if constexpr (std::is_same_v<int64_t, T>) {
+ return AParcel_writeInt64(parcel, value);
+ } else if constexpr (std::is_same_v<float, T>) {
+ return AParcel_writeFloat(parcel, value);
+ } else if constexpr (std::is_same_v<double, T>) {
+ return AParcel_writeDouble(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_writeRequiredParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_writeRequiredStrongBinder(parcel, value);
+ } else if constexpr (std::is_enum_v<T>) {
+ return AParcel_writeData(parcel, static_cast<std::underlying_type_t<T>>(value));
+ } else if constexpr (is_interface_v<T>) {
+ return AParcel_writeParcelable(parcel, value);
+ } else if constexpr (is_parcelable_v<T>) {
+ return AParcel_writeParcelable(parcel, value);
+ } else {
+ static_assert(dependent_false_v<T>, "unrecognized type");
+ return STATUS_OK;
+ }
+}
+
+/**
+ * Convenience API for writing a nullable value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value) {
+ if constexpr (is_specialization_v<T, std::optional> &&
+ is_specialization_v<first_template_type_t<T>, std::vector>) {
+ return AParcel_writeVector(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ is_fixed_array_v<first_template_type_t<T>>) {
+ return AParcel_writeNullableFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) { // happens with a nullable multi-dimensional array.
+ return AParcel_writeFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ std::is_same_v<first_template_type_t<T>, std::string>) {
+ return AParcel_writeString(parcel, value);
+ } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) {
+ return AParcel_writeNullableParcelable(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_writeNullableParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_writeNullableStrongBinder(parcel, value);
+ } else {
+ return AParcel_writeData(parcel, value);
+ }
+}
+
+/**
+ * Convenience API for reading a value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value) {
+ if constexpr (is_specialization_v<T, std::vector>) {
+ return AParcel_readVector(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) {
+ return AParcel_readFixedArray(parcel, value);
+ } else if constexpr (std::is_same_v<std::string, T>) {
+ return AParcel_readString(parcel, value);
+ } else if constexpr (std::is_same_v<bool, T>) {
+ return AParcel_readBool(parcel, value);
+ } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) {
+ return AParcel_readByte(parcel, value);
+ } else if constexpr (std::is_same_v<char16_t, T>) {
+ return AParcel_readChar(parcel, value);
+ } else if constexpr (std::is_same_v<int32_t, T>) {
+ return AParcel_readInt32(parcel, value);
+ } else if constexpr (std::is_same_v<int64_t, T>) {
+ return AParcel_readInt64(parcel, value);
+ } else if constexpr (std::is_same_v<float, T>) {
+ return AParcel_readFloat(parcel, value);
+ } else if constexpr (std::is_same_v<double, T>) {
+ return AParcel_readDouble(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_readRequiredParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_readRequiredStrongBinder(parcel, value);
+ } else if constexpr (std::is_enum_v<T>) {
+ return AParcel_readData(parcel, reinterpret_cast<std::underlying_type_t<T>*>(value));
+ } else if constexpr (is_interface_v<T>) {
+ return AParcel_readParcelable(parcel, value);
+ } else if constexpr (is_parcelable_v<T>) {
+ return AParcel_readParcelable(parcel, value);
+ } else {
+ static_assert(dependent_false_v<T>, "unrecognized type");
+ return STATUS_OK;
+ }
+}
+
+/**
+ * Convenience API for reading a nullable value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value) {
+ if constexpr (is_specialization_v<T, std::optional> &&
+ is_specialization_v<first_template_type_t<T>, std::vector>) {
+ return AParcel_readVector(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ is_fixed_array_v<first_template_type_t<T>>) {
+ return AParcel_readNullableFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) { // happens with a nullable multi-dimensional array.
+ return AParcel_readFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ std::is_same_v<first_template_type_t<T>, std::string>) {
+ return AParcel_readString(parcel, value);
+ } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) {
+ return AParcel_readNullableParcelable(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_readNullableParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_readNullableStrongBinder(parcel, value);
+ } else {
+ return AParcel_readData(parcel, value);
+ }
+}
+
} // namespace ndk
/** @} */
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/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index b0dea94..4d3d59a 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -60,6 +60,16 @@
}
}
+impl PartialEq for ParcelFileDescriptor {
+ // Since ParcelFileDescriptors own the FD, if this function ever returns true (and it is used to
+ // compare two different objects), then it would imply that an FD is double-owned.
+ fn eq(&self, other: &Self) -> bool {
+ self.as_raw_fd() == other.as_raw_fd()
+ }
+}
+
+impl Eq for ParcelFileDescriptor {}
+
impl Serialize for ParcelFileDescriptor {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let fd = self.0.as_raw_fd();
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 9007cba..61f88b6 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -652,6 +652,39 @@
}
}
+impl<T: SerializeArray, const N: usize> Serialize for [T; N] {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // forwards to T::serialize_array.
+ SerializeArray::serialize_array(self, parcel)
+ }
+}
+
+impl<T: SerializeArray, const N: usize> SerializeOption for [T; N] {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ SerializeOption::serialize_option(this.map(|arr| &arr[..]), parcel)
+ }
+}
+
+impl<T: SerializeArray, const N: usize> SerializeArray for [T; N] {}
+
+impl<T: DeserializeArray, const N: usize> Deserialize for [T; N] {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+ let vec = DeserializeArray::deserialize_array(parcel)
+ .transpose()
+ .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))?;
+ vec.try_into().or(Err(StatusCode::BAD_VALUE))
+ }
+}
+
+impl<T: DeserializeArray, const N: usize> DeserializeOption for [T; N] {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
+ let vec = DeserializeArray::deserialize_array(parcel)?;
+ vec.map(|v| v.try_into().or(Err(StatusCode::BAD_VALUE))).transpose()
+ }
+}
+
+impl<T: DeserializeArray, const N: usize> DeserializeArray for [T; N] {}
+
impl Serialize for Stability {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
i32::from(*self).serialize(parcel)
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/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 752fcbb..5aeb5cc 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -156,5 +156,21 @@
PARCEL_READ(std::optional<std::vector<char16_t>>, ndk::AParcel_readVector),
PARCEL_READ(std::vector<int32_t>, ndk::AParcel_resizeVector),
PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_resizeVector),
+
+ // methods for std::array<T,N>
+#define COMMA ,
+ PARCEL_READ(std::array<bool COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<uint8_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<char16_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<int32_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<int64_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<float COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<double COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<std::string COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<SomeParcelable COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<ndk::SpAIBinder COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<ndk::ScopedFileDescriptor COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<std::shared_ptr<ISomeInterface> COMMA 3>, ndk::AParcel_readData),
+#undef COMMA
};
// clang-format on
diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp
index 9231a57..3800b88 100644
--- a/libs/gui/FrameTimelineInfo.cpp
+++ b/libs/gui/FrameTimelineInfo.cpp
@@ -33,12 +33,14 @@
status_t FrameTimelineInfo::write(Parcel& output) const {
SAFE_PARCEL(output.writeInt64, vsyncId);
SAFE_PARCEL(output.writeInt32, inputEventId);
+ SAFE_PARCEL(output.writeInt64, startTimeNanos);
return NO_ERROR;
}
status_t FrameTimelineInfo::read(const Parcel& input) {
SAFE_PARCEL(input.readInt64, &vsyncId);
SAFE_PARCEL(input.readInt32, &inputEventId);
+ SAFE_PARCEL(input.readInt64, &startTimeNanos);
return NO_ERROR;
}
@@ -48,16 +50,19 @@
if (other.vsyncId > vsyncId) {
vsyncId = other.vsyncId;
inputEventId = other.inputEventId;
+ startTimeNanos = other.startTimeNanos;
}
} else if (vsyncId == INVALID_VSYNC_ID) {
vsyncId = other.vsyncId;
inputEventId = other.inputEventId;
+ startTimeNanos = other.startTimeNanos;
}
}
void FrameTimelineInfo::clear() {
vsyncId = INVALID_VSYNC_ID;
inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID;
+ startTimeNanos = 0;
}
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 353a91d..20c4146 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1846,9 +1846,10 @@
ATRACE_CALL();
auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t));
auto inputEventId = static_cast<int32_t>(va_arg(args, int32_t));
+ auto startTimeNanos = static_cast<int64_t>(va_arg(args, int64_t));
ALOGV("Surface::%s", __func__);
- return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId});
+ return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos});
}
bool Surface::transformToDisplayInverse() const {
diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h
index a23c202..255ce56 100644
--- a/libs/gui/include/gui/FrameTimelineInfo.h
+++ b/libs/gui/include/gui/FrameTimelineInfo.h
@@ -36,6 +36,9 @@
// not directly vendor available.
int32_t inputEventId = 0;
+ // The current time in nanoseconds the application started to render the frame.
+ int64_t startTimeNanos = 0;
+
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 0bc2b5d..a319769 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1025,10 +1025,11 @@
}
static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window,
- int64_t frameTimelineVsyncId,
- int32_t inputEventId) {
- return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO,
- frameTimelineVsyncId, inputEventId);
+ int64_t frameTimelineVsyncId,
+ int32_t inputEventId,
+ int64_t startTimeNanos) {
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameTimelineVsyncId,
+ inputEventId, startTimeNanos);
}
// ------------------------------------------------------------------------------------------------
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/powermanager/Android.bp b/services/powermanager/Android.bp
index d828aa9..6fbba3f 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -24,11 +24,11 @@
],
aidl: {
- local_include_dirs: ["include"],
- include_dirs: [
- "frameworks/base/core/java/android/os",
- ],
- export_aidl_headers: true
+ local_include_dirs: ["include"],
+ include_dirs: [
+ "frameworks/base/core/java/android/os",
+ ],
+ export_aidl_headers: true,
},
shared_libs: [
@@ -38,7 +38,7 @@
"libutils",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
- "android.hardware.power-V2-cpp",
+ "android.hardware.power-V3-cpp",
],
cflags: [
@@ -50,6 +50,6 @@
local_include_dirs: ["include"],
export_include_dirs: [
- "include",
+ "include",
],
}
diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp
index 3997929..fcb012f 100644
--- a/services/powermanager/benchmarks/Android.bp
+++ b/services/powermanager/benchmarks/Android.bp
@@ -38,7 +38,7 @@
"libutils",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
- "android.hardware.power-V2-cpp",
+ "android.hardware.power-V3-cpp",
],
static_libs: [
"libtestUtil",
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index 659b2d2..2d1558a 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -46,7 +46,7 @@
"libutils",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
- "android.hardware.power-V2-cpp",
+ "android.hardware.power-V3-cpp",
],
static_libs: [
"libgmock",
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
index d890f5c..cb1a77a 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -183,6 +183,10 @@
auto result = mWrapper->setMode(Mode::LAUNCH, true);
ASSERT_TRUE(result.isUnsupported());
+
+ EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::CAMERA_STREAMING_HIGH), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
ASSERT_TRUE(result.isUnsupported());
}
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index b596708..dccbeb0 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -15,6 +15,7 @@
"CorrectedGyroSensor.cpp",
"Fusion.cpp",
"GravitySensor.cpp",
+ "HidlSensorHalWrapper.cpp",
"LinearAccelerationSensor.cpp",
"OrientationSensor.cpp",
"RecentEventLogger.cpp",
diff --git a/services/sensorservice/HidlSensorHalWrapper.cpp b/services/sensorservice/HidlSensorHalWrapper.cpp
new file mode 100644
index 0000000..dbb3da1
--- /dev/null
+++ b/services/sensorservice/HidlSensorHalWrapper.cpp
@@ -0,0 +1,562 @@
+/*
+ * 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 "HidlSensorHalWrapper.h"
+#include "android/hardware/sensors/2.0/types.h"
+#include "android/hardware/sensors/2.1/ISensorsCallback.h"
+#include "android/hardware/sensors/2.1/types.h"
+#include "convertV2_1.h"
+
+#include <android-base/logging.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::sensors::V1_0::RateLevel;
+using android::hardware::sensors::V1_0::Result;
+using android::hardware::sensors::V1_0::SharedMemFormat;
+using android::hardware::sensors::V1_0::SharedMemInfo;
+using android::hardware::sensors::V1_0::SharedMemType;
+using android::hardware::sensors::V2_0::EventQueueFlagBits;
+using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using android::hardware::sensors::V2_1::Event;
+using android::hardware::sensors::V2_1::ISensorsCallback;
+using android::hardware::sensors::V2_1::implementation::convertFromSensorEvent;
+using android::hardware::sensors::V2_1::implementation::convertToNewEvents;
+using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos;
+using android::hardware::sensors::V2_1::implementation::convertToSensor;
+using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV1_0;
+using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_0;
+using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_1;
+
+namespace android {
+
+namespace {
+
+status_t statusFromResult(Result result) {
+ switch (result) {
+ case Result::OK:
+ return OK;
+ case Result::BAD_VALUE:
+ return BAD_VALUE;
+ case Result::PERMISSION_DENIED:
+ return PERMISSION_DENIED;
+ case Result::INVALID_OPERATION:
+ return INVALID_OPERATION;
+ case Result::NO_MEMORY:
+ return NO_MEMORY;
+ }
+}
+
+template <typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+ return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+enum EventQueueFlagBitsInternal : uint32_t {
+ INTERNAL_WAKE = 1 << 16,
+};
+
+} // anonymous namespace
+
+void SensorsHalDeathReceiver::serviceDied(
+ uint64_t /* cookie */, const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
+ ALOGW("Sensors HAL died, attempting to reconnect.");
+ mHidlSensorHalWrapper->prepareForReconnect();
+}
+
+struct SensorsCallback : public ISensorsCallback {
+ using Result = ::android::hardware::sensors::V1_0::Result;
+ using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
+
+ SensorsCallback(ISensorHalWrapper::SensorDeviceCallback* sensorDeviceCallback) {
+ mSensorDeviceCallback = sensorDeviceCallback;
+ }
+
+ Return<void> onDynamicSensorsConnected_2_1(
+ const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+ std::vector<sensor_t> sensors;
+ for (const android::hardware::sensors::V2_1::SensorInfo& info : dynamicSensorsAdded) {
+ sensor_t sensor;
+ convertToSensor(info, &sensor);
+ sensors.push_back(sensor);
+ }
+
+ mSensorDeviceCallback->onDynamicSensorsConnected(sensors);
+ return Return<void>();
+ }
+
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<android::hardware::sensors::V1_0::SensorInfo>& dynamicSensorsAdded)
+ override {
+ return onDynamicSensorsConnected_2_1(convertToNewSensorInfos(dynamicSensorsAdded));
+ }
+
+ Return<void> onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+ mSensorDeviceCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved);
+ return Return<void>();
+ }
+
+private:
+ ISensorHalWrapper::SensorDeviceCallback* mSensorDeviceCallback;
+};
+
+bool HidlSensorHalWrapper::supportsPolling() {
+ return mSensors->supportsPolling();
+}
+
+bool HidlSensorHalWrapper::supportsMessageQueues() {
+ return mSensors->supportsMessageQueues();
+}
+
+bool HidlSensorHalWrapper::connect(SensorDeviceCallback* callback) {
+ mSensorDeviceCallback = callback;
+ bool ret = connectHidlService();
+ if (mEventQueueFlag != nullptr) {
+ mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+ }
+ return ret;
+}
+
+void HidlSensorHalWrapper::prepareForReconnect() {
+ mReconnecting = true;
+ if (mEventQueueFlag != nullptr) {
+ mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+ }
+}
+
+ssize_t HidlSensorHalWrapper::poll(sensors_event_t* buffer, size_t count) {
+ ssize_t err;
+ int numHidlTransportErrors = 0;
+ bool hidlTransportError = false;
+
+ do {
+ auto ret = mSensors->poll(
+ count, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
+ if (result == Result::OK) {
+ convertToSensorEventsAndQuantize(convertToNewEvents(events),
+ convertToNewSensorInfos(
+ dynamicSensorsAdded),
+ buffer);
+ err = (ssize_t)events.size();
+ } else {
+ err = statusFromResult(result);
+ }
+ });
+
+ if (ret.isOk()) {
+ hidlTransportError = false;
+ } else {
+ hidlTransportError = true;
+ numHidlTransportErrors++;
+ if (numHidlTransportErrors > 50) {
+ // Log error and bail
+ ALOGE("Max Hidl transport errors this cycle : %d", numHidlTransportErrors);
+ handleHidlDeath(ret.description());
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ } while (hidlTransportError);
+
+ if (numHidlTransportErrors > 0) {
+ ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors);
+ HidlTransportErrorLog errLog(time(nullptr), numHidlTransportErrors);
+ mHidlTransportErrors.add(errLog);
+ mTotalHidlTransportErrors++;
+ }
+
+ return err;
+}
+
+ssize_t HidlSensorHalWrapper::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead) {
+ ssize_t eventsRead = 0;
+ size_t availableEvents = mSensors->getEventQueue()->availableToRead();
+
+ if (availableEvents == 0) {
+ uint32_t eventFlagState = 0;
+
+ // Wait for events to become available. This is necessary so that the Event FMQ's read() is
+ // able to be called with the correct number of events to read. If the specified number of
+ // events is not available, then read() would return no events, possibly introducing
+ // additional latency in delivering events to applications.
+ if (mEventQueueFlag != nullptr) {
+ mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) |
+ asBaseType(INTERNAL_WAKE),
+ &eventFlagState);
+ }
+ availableEvents = mSensors->getEventQueue()->availableToRead();
+
+ if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
+ ALOGD("Event FMQ internal wake, returning from poll with no events");
+ return DEAD_OBJECT;
+ }
+ }
+
+ size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()});
+ if (eventsToRead > 0) {
+ if (mSensors->getEventQueue()->read(mEventBuffer.data(), eventsToRead)) {
+ // Notify the Sensors HAL that sensor events have been read. This is required to support
+ // the use of writeBlocking by the Sensors HAL.
+ if (mEventQueueFlag != nullptr) {
+ mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ));
+ }
+
+ for (size_t i = 0; i < eventsToRead; i++) {
+ convertToSensorEvent(mEventBuffer[i], &buffer[i]);
+ android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i],
+ getResolutionForSensor(
+ buffer[i].sensor));
+ }
+ eventsRead = eventsToRead;
+ } else {
+ ALOGW("Failed to read %zu events, currently %zu events available", eventsToRead,
+ availableEvents);
+ }
+ }
+
+ return eventsRead;
+}
+
+std::vector<sensor_t> HidlSensorHalWrapper::getSensorsList() {
+ std::vector<sensor_t> sensorsFound;
+ if (mSensors != nullptr) {
+ checkReturn(mSensors->getSensorsList([&](const auto& list) {
+ for (size_t i = 0; i < list.size(); i++) {
+ sensor_t sensor;
+ convertToSensor(list[i], &sensor);
+ sensorsFound.push_back(sensor);
+
+ // Only disable all sensors on HAL 1.0 since HAL 2.0
+ // handles this in its initialize method
+ if (!mSensors->supportsMessageQueues()) {
+ checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+ }
+ }
+ }));
+ }
+
+ return sensorsFound;
+}
+
+status_t HidlSensorHalWrapper::setOperationMode(SensorService::Mode mode) {
+ if (mSensors == nullptr) return NO_INIT;
+ return checkReturnAndGetStatus(
+ mSensors->setOperationMode(static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
+}
+
+status_t HidlSensorHalWrapper::activate(int32_t sensorHandle, bool enabled) {
+ if (mSensors == nullptr) return NO_INIT;
+ return checkReturnAndGetStatus(mSensors->activate(sensorHandle, enabled));
+}
+
+status_t HidlSensorHalWrapper::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) {
+ if (mSensors == nullptr) return NO_INIT;
+ return checkReturnAndGetStatus(
+ mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs));
+}
+
+status_t HidlSensorHalWrapper::flush(int32_t sensorHandle) {
+ if (mSensors == nullptr) return NO_INIT;
+ return checkReturnAndGetStatus(mSensors->flush(sensorHandle));
+}
+
+status_t HidlSensorHalWrapper::injectSensorData(const sensors_event_t* event) {
+ if (mSensors == nullptr) return NO_INIT;
+
+ Event ev;
+ convertFromSensorEvent(*event, &ev);
+ return checkReturnAndGetStatus(mSensors->injectSensorData(ev));
+}
+
+status_t HidlSensorHalWrapper::registerDirectChannel(const sensors_direct_mem_t* memory,
+ int32_t* /*channelHandle*/) {
+ if (mSensors == nullptr) return NO_INIT;
+
+ SharedMemType type;
+ switch (memory->type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ type = SharedMemType::ASHMEM;
+ break;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ type = SharedMemType::GRALLOC;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ SharedMemFormat format;
+ if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ return BAD_VALUE;
+ }
+ format = SharedMemFormat::SENSORS_EVENT;
+
+ SharedMemInfo mem = {
+ .type = type,
+ .format = format,
+ .size = static_cast<uint32_t>(memory->size),
+ .memoryHandle = memory->handle,
+ };
+
+ status_t ret;
+ checkReturn(mSensors->registerDirectChannel(mem, [&ret](auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ ret = channelHandle;
+ } else {
+ ret = statusFromResult(result);
+ }
+ }));
+ return ret;
+}
+
+status_t HidlSensorHalWrapper::unregisterDirectChannel(int32_t channelHandle) {
+ if (mSensors == nullptr) return NO_INIT;
+ return checkReturnAndGetStatus(mSensors->unregisterDirectChannel(channelHandle));
+}
+
+status_t HidlSensorHalWrapper::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+ const struct sensors_direct_cfg_t* config) {
+ if (mSensors == nullptr) return NO_INIT;
+
+ RateLevel rate;
+ switch (config->rate_level) {
+ case SENSOR_DIRECT_RATE_STOP:
+ rate = RateLevel::STOP;
+ break;
+ case SENSOR_DIRECT_RATE_NORMAL:
+ rate = RateLevel::NORMAL;
+ break;
+ case SENSOR_DIRECT_RATE_FAST:
+ rate = RateLevel::FAST;
+ break;
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ rate = RateLevel::VERY_FAST;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ status_t ret;
+ checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
+ [&ret, rate](auto result, auto token) {
+ if (rate == RateLevel::STOP) {
+ ret = statusFromResult(result);
+ } else {
+ if (result == Result::OK) {
+ ret = token;
+ } else {
+ ret = statusFromResult(result);
+ }
+ }
+ }));
+
+ return ret;
+}
+
+void HidlSensorHalWrapper::writeWakeLockHandled(uint32_t count) {
+ if (mWakeLockQueue->write(&count)) {
+ mWakeLockQueueFlag->wake(asBaseType(WakeLockQueueFlagBits::DATA_WRITTEN));
+ } else {
+ ALOGW("Failed to write wake lock handled");
+ }
+}
+
+status_t HidlSensorHalWrapper::checkReturnAndGetStatus(const hardware::Return<Result>& ret) {
+ checkReturn(ret);
+ return (!ret.isOk()) ? DEAD_OBJECT : statusFromResult(ret);
+}
+
+void HidlSensorHalWrapper::handleHidlDeath(const std::string& detail) {
+ if (!mSensors->supportsMessageQueues()) {
+ // restart is the only option at present.
+ LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
+ } else {
+ ALOGD("ISensors HAL died, death recipient will attempt reconnect");
+ }
+}
+
+bool HidlSensorHalWrapper::connectHidlService() {
+ HalConnectionStatus status = connectHidlServiceV2_1();
+ if (status == HalConnectionStatus::DOES_NOT_EXIST) {
+ status = connectHidlServiceV2_0();
+ }
+
+ if (status == HalConnectionStatus::DOES_NOT_EXIST) {
+ status = connectHidlServiceV1_0();
+ }
+ return (status == HalConnectionStatus::CONNECTED);
+}
+
+ISensorHalWrapper::HalConnectionStatus HidlSensorHalWrapper::connectHidlServiceV1_0() {
+ // SensorDevice will wait for HAL service to start if HAL is declared in device manifest.
+ size_t retry = 10;
+ HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
+
+ while (retry-- > 0) {
+ sp<android::hardware::sensors::V1_0::ISensors> sensors =
+ android::hardware::sensors::V1_0::ISensors::getService();
+ if (sensors == nullptr) {
+ // no sensor hidl service found
+ connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
+ break;
+ }
+
+ mSensors = new ISensorsWrapperV1_0(sensors);
+ mRestartWaiter->reset();
+ // Poke ISensor service. If it has lingering connection from previous generation of
+ // system server, it will kill itself. There is no intention to handle the poll result,
+ // which will be done since the size is 0.
+ if (mSensors->poll(0, [](auto, const auto&, const auto&) {}).isOk()) {
+ // ok to continue
+ connectionStatus = HalConnectionStatus::CONNECTED;
+ break;
+ }
+
+ // hidl service is restarting, pointer is invalid.
+ mSensors = nullptr;
+ connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
+ ALOGI("%s unsuccessful, remaining retry %zu.", __FUNCTION__, retry);
+ mRestartWaiter->wait();
+ }
+
+ return connectionStatus;
+}
+
+ISensorHalWrapper::HalConnectionStatus HidlSensorHalWrapper::connectHidlServiceV2_0() {
+ HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
+ sp<android::hardware::sensors::V2_0::ISensors> sensors =
+ android::hardware::sensors::V2_0::ISensors::getService();
+
+ if (sensors == nullptr) {
+ connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
+ } else {
+ mSensors = new ISensorsWrapperV2_0(sensors);
+ connectionStatus = initializeHidlServiceV2_X();
+ }
+
+ return connectionStatus;
+}
+
+ISensorHalWrapper::HalConnectionStatus HidlSensorHalWrapper::connectHidlServiceV2_1() {
+ HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
+ sp<android::hardware::sensors::V2_1::ISensors> sensors =
+ android::hardware::sensors::V2_1::ISensors::getService();
+
+ if (sensors == nullptr) {
+ connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
+ } else {
+ mSensors = new ISensorsWrapperV2_1(sensors);
+ connectionStatus = initializeHidlServiceV2_X();
+ }
+
+ return connectionStatus;
+}
+
+ISensorHalWrapper::HalConnectionStatus HidlSensorHalWrapper::initializeHidlServiceV2_X() {
+ HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
+
+ mWakeLockQueue =
+ std::make_unique<WakeLockQueue>(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
+ true /* configureEventFlagWord */);
+
+ hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
+ hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(),
+ &mEventQueueFlag);
+
+ hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+ hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakeLockQueueFlag);
+
+ CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
+ mWakeLockQueueFlag != nullptr);
+
+ mCallback = new SensorsCallback(mSensorDeviceCallback);
+ status_t status =
+ checkReturnAndGetStatus(mSensors->initialize(*mWakeLockQueue->getDesc(), mCallback));
+
+ if (status != NO_ERROR) {
+ connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
+ ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status));
+ } else {
+ connectionStatus = HalConnectionStatus::CONNECTED;
+ mSensorsHalDeathReceiver = new SensorsHalDeathReceiver(this);
+ mSensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */);
+ }
+
+ return connectionStatus;
+}
+
+void HidlSensorHalWrapper::convertToSensorEvent(const Event& src, sensors_event_t* dst) {
+ android::hardware::sensors::V2_1::implementation::convertToSensorEvent(src, dst);
+
+ if (src.sensorType == android::hardware::sensors::V2_1::SensorType::DYNAMIC_SENSOR_META) {
+ const hardware::sensors::V1_0::DynamicSensorInfo& dyn = src.u.dynamic;
+
+ dst->dynamic_sensor_meta.connected = dyn.connected;
+ dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
+ if (dyn.connected) {
+ std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
+ // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked since it
+ // can be received out of order from this event due to a bug in the HIDL spec that
+ // marks it as oneway.
+ auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
+ if (it == mConnectedDynamicSensors.end()) {
+ mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] {
+ return mConnectedDynamicSensors.find(dyn.sensorHandle) !=
+ mConnectedDynamicSensors.end();
+ });
+ it = mConnectedDynamicSensors.find(dyn.sensorHandle);
+ CHECK(it != mConnectedDynamicSensors.end());
+ }
+
+ dst->dynamic_sensor_meta.sensor = &it->second;
+
+ memcpy(dst->dynamic_sensor_meta.uuid, dyn.uuid.data(),
+ sizeof(dst->dynamic_sensor_meta.uuid));
+ }
+ }
+}
+
+void HidlSensorHalWrapper::convertToSensorEventsAndQuantize(
+ const hidl_vec<Event>& src, const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ sensors_event_t* dst) {
+ if (dynamicSensorsAdded.size() > 0 && mCallback != nullptr) {
+ mCallback->onDynamicSensorsConnected_2_1(dynamicSensorsAdded);
+ }
+
+ for (size_t i = 0; i < src.size(); ++i) {
+ android::hardware::sensors::V2_1::implementation::convertToSensorEvent(src[i], &dst[i]);
+ android::SensorDeviceUtils::quantizeSensorEventValues(&dst[i],
+ getResolutionForSensor(
+ dst[i].sensor));
+ }
+}
+
+float HidlSensorHalWrapper::getResolutionForSensor(int sensorHandle) {
+ for (size_t i = 0; i < mSensorList.size(); i++) {
+ if (sensorHandle == mSensorList[i].handle) {
+ return mSensorList[i].resolution;
+ }
+ }
+
+ auto it = mConnectedDynamicSensors.find(sensorHandle);
+ if (it != mConnectedDynamicSensors.end()) {
+ return it->second.resolution;
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/sensorservice/HidlSensorHalWrapper.h b/services/sensorservice/HidlSensorHalWrapper.h
new file mode 100644
index 0000000..030247f
--- /dev/null
+++ b/services/sensorservice/HidlSensorHalWrapper.h
@@ -0,0 +1,182 @@
+/*
+ * 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_HIDL_SENSOR_HAL_WRAPPER_H
+#define ANDROID_HIDL_SENSOR_HAL_WRAPPER_H
+
+#include <sensor/SensorEventQueue.h>
+#include <utils/Singleton.h>
+
+#include "ISensorHalWrapper.h"
+
+#include "ISensorsWrapper.h"
+#include "SensorDeviceUtils.h"
+
+namespace android {
+
+using android::hardware::sensors::V1_0::Result;
+using android::hardware::sensors::V2_1::Event;
+using android::hardware::sensors::V2_1::SensorInfo;
+
+class HidlTransportErrorLog {
+public:
+ HidlTransportErrorLog() {
+ mTs = 0;
+ mCount = 0;
+ }
+
+ HidlTransportErrorLog(time_t ts, int count) {
+ mTs = ts;
+ mCount = count;
+ }
+
+ String8 toString() const {
+ String8 result;
+ struct tm* timeInfo = localtime(&mTs);
+ result.appendFormat("%02d:%02d:%02d :: %d", timeInfo->tm_hour, timeInfo->tm_min,
+ timeInfo->tm_sec, mCount);
+ return result;
+ }
+
+private:
+ time_t mTs; // timestamp of the error
+ int mCount; // number of transport errors observed
+};
+
+class SensorsHalDeathReceiver : public android::hardware::hidl_death_recipient {
+public:
+ SensorsHalDeathReceiver(ISensorHalWrapper* wrapper) : mHidlSensorHalWrapper(wrapper) {}
+
+ virtual void serviceDied(uint64_t cookie,
+ const wp<::android::hidl::base::V1_0::IBase>& service) override;
+
+private:
+ ISensorHalWrapper* mHidlSensorHalWrapper;
+};
+
+class HidlSensorHalWrapper : public ISensorHalWrapper {
+public:
+ HidlSensorHalWrapper()
+ : mHidlTransportErrors(20),
+ mTotalHidlTransportErrors(0),
+ mRestartWaiter(new SensorDeviceUtils::HidlServiceRegistrationWaiter()),
+ mEventQueueFlag(nullptr),
+ mWakeLockQueueFlag(nullptr) {}
+
+ ~HidlSensorHalWrapper() override {
+ if (mEventQueueFlag != nullptr) {
+ hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
+ mEventQueueFlag = nullptr;
+ }
+ if (mWakeLockQueueFlag != nullptr) {
+ hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+ mWakeLockQueueFlag = nullptr;
+ }
+ }
+ virtual bool connect(SensorDeviceCallback* callback) override;
+
+ virtual void prepareForReconnect() override;
+
+ virtual bool supportsPolling() override;
+
+ virtual bool supportsMessageQueues() override;
+
+ virtual ssize_t poll(sensors_event_t* buffer, size_t count) override;
+
+ virtual ssize_t pollFmq(sensors_event_t* buffer, size_t count) override;
+
+ virtual std::vector<sensor_t> getSensorsList() override;
+
+ virtual status_t setOperationMode(SensorService::Mode mode) override;
+
+ virtual status_t activate(int32_t sensorHandle, bool enabled) override;
+
+ virtual status_t batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override;
+
+ virtual status_t flush(int32_t sensorHandle) override;
+
+ virtual status_t injectSensorData(const sensors_event_t* event) override;
+
+ virtual status_t registerDirectChannel(const sensors_direct_mem_t* memory,
+ int32_t* channelHandle) override;
+
+ virtual status_t unregisterDirectChannel(int32_t channelHandle) override;
+
+ virtual status_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+ const struct sensors_direct_cfg_t* config) override;
+
+ virtual void writeWakeLockHandled(uint32_t count) override;
+
+private:
+ sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors;
+ sp<::android::hardware::sensors::V2_1::ISensorsCallback> mCallback;
+ std::vector<sensor_t> mSensorList;
+ std::unordered_map<int32_t, sensor_t> mConnectedDynamicSensors;
+
+ std::mutex mDynamicSensorsMutex;
+ std::condition_variable mDynamicSensorsCv;
+ static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5};
+
+ // Keep track of any hidl transport failures
+ SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors;
+ int mTotalHidlTransportErrors;
+
+ SensorDeviceCallback* mSensorDeviceCallback = nullptr;
+
+ // TODO(b/67425500): remove waiter after bug is resolved.
+ sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
+
+ template <typename T>
+ void checkReturn(const hardware::Return<T>& ret) {
+ if (!ret.isOk()) {
+ handleHidlDeath(ret.description());
+ }
+ }
+
+ status_t checkReturnAndGetStatus(const hardware::Return<Result>& ret);
+
+ void handleHidlDeath(const std::string& detail);
+
+ void convertToSensorEvent(const Event& src, sensors_event_t* dst);
+
+ void convertToSensorEventsAndQuantize(const hardware::hidl_vec<Event>& src,
+ const hardware::hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ sensors_event_t* dst);
+
+ bool connectHidlService();
+
+ HalConnectionStatus connectHidlServiceV1_0();
+ HalConnectionStatus connectHidlServiceV2_0();
+ HalConnectionStatus connectHidlServiceV2_1();
+ HalConnectionStatus initializeHidlServiceV2_X();
+
+ typedef hardware::MessageQueue<uint32_t, hardware::kSynchronizedReadWrite> WakeLockQueue;
+ std::unique_ptr<WakeLockQueue> mWakeLockQueue;
+
+ float getResolutionForSensor(int sensorHandle);
+
+ hardware::EventFlag* mEventQueueFlag;
+ hardware::EventFlag* mWakeLockQueueFlag;
+
+ std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+
+ sp<SensorsHalDeathReceiver> mSensorsHalDeathReceiver;
+};
+
+} // namespace android
+
+#endif // ANDROID_HIDL_SENSOR_HAL_WRAPPER_H
diff --git a/services/sensorservice/ISensorHalWrapper.h b/services/sensorservice/ISensorHalWrapper.h
index c9e089e..3d33540 100644
--- a/services/sensorservice/ISensorHalWrapper.h
+++ b/services/sensorservice/ISensorHalWrapper.h
@@ -30,26 +30,45 @@
*/
class ISensorHalWrapper {
public:
- class ICallback : public ISensorsCallback {
-
- void onDynamicSensorsConnected(
+ class SensorDeviceCallback {
+ public:
+ virtual void onDynamicSensorsConnected(
const std::vector<sensor_t> &dynamicSensorsAdded) = 0;
- void onDynamicSensorsDisconnected(
+ virtual void onDynamicSensorsDisconnected(
const std::vector<int32_t> &dynamicSensorHandlesRemoved) = 0;
+
+ virtual ~SensorDeviceCallback(){};
};
+ enum HalConnectionStatus {
+ CONNECTED, // Successfully connected to the HAL
+ DOES_NOT_EXIST, // Could not find the HAL
+ FAILED_TO_CONNECT, // Found the HAL but failed to connect/initialize
+ UNKNOWN,
+ };
+
+ virtual ~ISensorHalWrapper(){};
+
/**
* Connects to the underlying sensors HAL. This should also be used for any reconnections
* due to HAL resets.
*/
- virtual bool connect(ICallback *callback) = 0;
+ virtual bool connect(SensorDeviceCallback *callback) = 0;
+
+ virtual void prepareForReconnect() = 0;
+
+ virtual bool supportsPolling() = 0;
+
+ virtual bool supportsMessageQueues() = 0;
/**
* Polls for available sensor events. This could be using the traditional sensors
* polling or from a FMQ.
*/
- virtual ssize_t poll(sensors_event_t* buffer, size_t count) = 0;
+ virtual ssize_t poll(sensors_event_t *buffer, size_t count) = 0;
+
+ virtual ssize_t pollFmq(sensors_event_t *buffer, size_t maxNumEventsToRead) = 0;
/**
* The below functions directly mirrors the sensors HAL definitions.
@@ -70,11 +89,15 @@
virtual status_t registerDirectChannel(const sensors_direct_mem_t *memory,
int32_t *channelHandle) = 0;
- virtual void unregisterDirectChannel(int32_t channelHandle) = 0;
+ virtual status_t unregisterDirectChannel(int32_t channelHandle) = 0;
virtual status_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
const struct sensors_direct_cfg_t *config) = 0;
-}
+
+ virtual void writeWakeLockHandled(uint32_t count) = 0;
+
+ std::atomic_bool mReconnecting = false;
+};
} // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index c67acbf..84a1076 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -17,7 +17,6 @@
#include "SensorDevice.h"
#include "android/hardware/sensors/2.0/types.h"
-#include "android/hardware/sensors/2.1/ISensorsCallback.h"
#include "android/hardware/sensors/2.1/types.h"
#include "convertV2_1.h"
@@ -35,21 +34,7 @@
#include <thread>
using namespace android::hardware::sensors;
-using namespace android::hardware::sensors::V1_0;
-using namespace android::hardware::sensors::V1_0::implementation;
-using android::hardware::hidl_vec;
using android::hardware::Return;
-using android::hardware::sensors::V2_0::EventQueueFlagBits;
-using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
-using android::hardware::sensors::V2_1::ISensorsCallback;
-using android::hardware::sensors::V2_1::implementation::convertToNewEvents;
-using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos;
-using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo;
-using android::hardware::sensors::V2_1::implementation::convertToSensor;
-using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV1_0;
-using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_0;
-using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_1;
-using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
using android::util::ProtoOutputStream;
namespace android {
@@ -59,21 +44,6 @@
namespace {
-status_t statusFromResult(Result result) {
- switch (result) {
- case Result::OK:
- return OK;
- case Result::BAD_VALUE:
- return BAD_VALUE;
- case Result::PERMISSION_DENIED:
- return PERMISSION_DENIED;
- case Result::INVALID_OPERATION:
- return INVALID_OPERATION;
- case Result::NO_MEMORY:
- return NO_MEMORY;
- }
-}
-
template <typename EnumType>
constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
return static_cast<typename std::underlying_type<EnumType>::type>(value);
@@ -85,245 +55,98 @@
INTERNAL_WAKE = 1 << 16,
};
-} // anonymous namespace
-
-void SensorsHalDeathReceivier::serviceDied(
- uint64_t /* cookie */, const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
- ALOGW("Sensors HAL died, attempting to reconnect.");
- SensorDevice::getInstance().prepareForReconnect();
-}
-
-struct SensorsCallback : public ISensorsCallback {
- using Result = ::android::hardware::sensors::V1_0::Result;
- using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
-
- Return<void> onDynamicSensorsConnected_2_1(
- const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
- std::vector<sensor_t> sensors;
- for (const V2_1::SensorInfo& info : dynamicSensorsAdded) {
- sensor_t sensor;
- convertToSensor(info, &sensor);
- sensors.push_back(sensor);
- }
-
- SensorDevice::getInstance().onDynamicSensorsConnected(sensors);
- return Return<void>();
- }
-
- Return<void> onDynamicSensorsConnected(
- const hidl_vec<V1_0::SensorInfo>& dynamicSensorsAdded) override {
- return onDynamicSensorsConnected_2_1(convertToNewSensorInfos(dynamicSensorsAdded));
- }
-
- Return<void> onDynamicSensorsDisconnected(
- const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
- SensorDevice::getInstance().onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved);
- return Return<void>();
- }
+enum DevicePrivateBase : int32_t {
+ DEVICE_PRIVATE_BASE = 65536,
};
-SensorDevice::SensorDevice()
- : mHidlTransportErrors(20),
- mRestartWaiter(new HidlServiceRegistrationWaiter()),
- mEventQueueFlag(nullptr),
- mWakeLockQueueFlag(nullptr),
- mReconnecting(false) {
- if (!connectHidlService()) {
+} // anonymous namespace
+
+SensorDevice::SensorDevice() {
+ if (!connectHalService()) {
return;
}
initializeSensorList();
- mIsDirectReportSupported =
- (checkReturnAndGetStatus(mSensors->unregisterDirectChannel(-1)) != INVALID_OPERATION);
+ mIsDirectReportSupported = (mHalWrapper->unregisterDirectChannel(-1) != INVALID_OPERATION);
}
void SensorDevice::initializeSensorList() {
- checkReturn(mSensors->getSensorsList([&](const auto& list) {
- const size_t count = list.size();
+ if (mHalWrapper == nullptr) {
+ return;
+ }
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i = 0; i < count; i++) {
- sensor_t sensor;
- convertToSensor(list[i], &sensor);
+ auto list = mHalWrapper->getSensorsList();
+ const size_t count = list.size();
- if (sensor.type < static_cast<int>(SensorType::DEVICE_PRIVATE_BASE)) {
- sensor.resolution = SensorDeviceUtils::resolutionForSensor(sensor);
+ mActivationCount.setCapacity(count);
+ Info model;
+ for (size_t i = 0; i < count; i++) {
+ sensor_t sensor = list[i];
- // Some sensors don't have a default resolution and will be left at 0.
- // Don't crash in this case since CTS will verify that devices don't go to
- // production with a resolution of 0.
- if (sensor.resolution != 0) {
- float quantizedRange = sensor.maxRange;
- SensorDeviceUtils::quantizeValue(&quantizedRange, sensor.resolution,
- /*factor=*/1);
- // Only rewrite maxRange if the requantization produced a "significant"
- // change, which is fairly arbitrarily defined as resolution / 8.
- // Smaller deltas are permitted, as they may simply be due to floating
- // point representation error, etc.
- if (fabsf(sensor.maxRange - quantizedRange) > sensor.resolution / 8) {
- ALOGW("%s's max range %.12f is not a multiple of the resolution "
- "%.12f - updated to %.12f",
- sensor.name, sensor.maxRange, sensor.resolution, quantizedRange);
- sensor.maxRange = quantizedRange;
- }
- } else {
- // Don't crash here or the device will go into a crashloop.
- ALOGW("%s should have a non-zero resolution", sensor.name);
+ if (sensor.type < DEVICE_PRIVATE_BASE) {
+ sensor.resolution = SensorDeviceUtils::resolutionForSensor(sensor);
+
+ // Some sensors don't have a default resolution and will be left at 0.
+ // Don't crash in this case since CTS will verify that devices don't go to
+ // production with a resolution of 0.
+ if (sensor.resolution != 0) {
+ float quantizedRange = sensor.maxRange;
+ SensorDeviceUtils::quantizeValue(&quantizedRange, sensor.resolution,
+ /*factor=*/1);
+ // Only rewrite maxRange if the requantization produced a "significant"
+ // change, which is fairly arbitrarily defined as resolution / 8.
+ // Smaller deltas are permitted, as they may simply be due to floating
+ // point representation error, etc.
+ if (fabsf(sensor.maxRange - quantizedRange) > sensor.resolution / 8) {
+ ALOGW("%s's max range %.12f is not a multiple of the resolution "
+ "%.12f - updated to %.12f",
+ sensor.name, sensor.maxRange, sensor.resolution, quantizedRange);
+ sensor.maxRange = quantizedRange;
}
- }
-
- // Check and clamp power if it is 0 (or close)
- constexpr float MIN_POWER_MA = 0.001; // 1 microAmp
- if (sensor.power < MIN_POWER_MA) {
- ALOGI("%s's reported power %f invalid, clamped to %f", sensor.name, sensor.power,
- MIN_POWER_MA);
- sensor.power = MIN_POWER_MA;
- }
- mSensorList.push_back(sensor);
-
- mActivationCount.add(list[i].sensorHandle, model);
-
- // Only disable all sensors on HAL 1.0 since HAL 2.0
- // handles this in its initialize method
- if (!mSensors->supportsMessageQueues()) {
- checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+ } else {
+ // Don't crash here or the device will go into a crashloop.
+ ALOGW("%s should have a non-zero resolution", sensor.name);
}
}
- }));
-}
-SensorDevice::~SensorDevice() {
- if (mEventQueueFlag != nullptr) {
- hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
- mEventQueueFlag = nullptr;
- }
-
- if (mWakeLockQueueFlag != nullptr) {
- hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
- mWakeLockQueueFlag = nullptr;
- }
-}
-
-bool SensorDevice::connectHidlService() {
- HalConnectionStatus status = connectHidlServiceV2_1();
- if (status == HalConnectionStatus::DOES_NOT_EXIST) {
- status = connectHidlServiceV2_0();
- }
-
- if (status == HalConnectionStatus::DOES_NOT_EXIST) {
- status = connectHidlServiceV1_0();
- }
- return (status == HalConnectionStatus::CONNECTED);
-}
-
-SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV1_0() {
- // SensorDevice will wait for HAL service to start if HAL is declared in device manifest.
- size_t retry = 10;
- HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
-
- while (retry-- > 0) {
- sp<V1_0::ISensors> sensors = V1_0::ISensors::getService();
- if (sensors == nullptr) {
- // no sensor hidl service found
- connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
- break;
+ // Check and clamp power if it is 0 (or close)
+ constexpr float MIN_POWER_MA = 0.001; // 1 microAmp
+ if (sensor.power < MIN_POWER_MA) {
+ ALOGI("%s's reported power %f invalid, clamped to %f", sensor.name, sensor.power,
+ MIN_POWER_MA);
+ sensor.power = MIN_POWER_MA;
}
+ mSensorList.push_back(sensor);
- mSensors = new ISensorsWrapperV1_0(sensors);
- mRestartWaiter->reset();
- // Poke ISensor service. If it has lingering connection from previous generation of
- // system server, it will kill itself. There is no intention to handle the poll result,
- // which will be done since the size is 0.
- if (mSensors->poll(0, [](auto, const auto&, const auto&) {}).isOk()) {
- // ok to continue
- connectionStatus = HalConnectionStatus::CONNECTED;
- break;
+ mActivationCount.add(list[i].handle, model);
+
+ // Only disable all sensors on HAL 1.0 since HAL 2.0
+ // handles this in its initialize method
+ if (!mHalWrapper->supportsMessageQueues()) {
+ mHalWrapper->activate(list[i].handle, 0 /* enabled */);
}
-
- // hidl service is restarting, pointer is invalid.
- mSensors = nullptr;
- connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
- ALOGI("%s unsuccessful, remaining retry %zu.", __FUNCTION__, retry);
- mRestartWaiter->wait();
}
-
- return connectionStatus;
}
-SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_0() {
- HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
- sp<V2_0::ISensors> sensors = V2_0::ISensors::getService();
+SensorDevice::~SensorDevice() {}
- if (sensors == nullptr) {
- connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
- } else {
- mSensors = new ISensorsWrapperV2_0(sensors);
- connectionStatus = initializeHidlServiceV2_X();
+bool SensorDevice::connectHalService() {
+ std::unique_ptr<ISensorHalWrapper> hidl_wrapper = std::make_unique<HidlSensorHalWrapper>();
+ if (hidl_wrapper->connect(this)) {
+ mHalWrapper = std::move(hidl_wrapper);
+ return true;
}
-
- return connectionStatus;
-}
-
-SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_1() {
- HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
- sp<V2_1::ISensors> sensors = V2_1::ISensors::getService();
-
- if (sensors == nullptr) {
- connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
- } else {
- mSensors = new ISensorsWrapperV2_1(sensors);
- connectionStatus = initializeHidlServiceV2_X();
- }
-
- return connectionStatus;
-}
-
-SensorDevice::HalConnectionStatus SensorDevice::initializeHidlServiceV2_X() {
- HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
-
- mWakeLockQueue =
- std::make_unique<WakeLockQueue>(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
- true /* configureEventFlagWord */);
-
- hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
- hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(),
- &mEventQueueFlag);
-
- hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
- hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakeLockQueueFlag);
-
- CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
- mWakeLockQueueFlag != nullptr);
-
- mCallback = new SensorsCallback();
- status_t status =
- checkReturnAndGetStatus(mSensors->initialize(*mWakeLockQueue->getDesc(), mCallback));
-
- if (status != NO_ERROR) {
- connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
- ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status));
- } else {
- connectionStatus = HalConnectionStatus::CONNECTED;
- mSensorsHalDeathReceiver = new SensorsHalDeathReceivier();
- mSensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */);
- }
-
- return connectionStatus;
+ // TODO: check aidl connection;
+ return false;
}
void SensorDevice::prepareForReconnect() {
- mReconnecting = true;
-
- // Wake up the polling thread so it returns and allows the SensorService to initiate
- // a reconnect.
- mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+ mHalWrapper->prepareForReconnect();
}
void SensorDevice::reconnect() {
Mutex::Autolock _l(mLock);
- mSensors = nullptr;
auto previousActivations = mActivationCount;
auto previousSensorList = mSensorList;
@@ -331,7 +154,7 @@
mActivationCount.clear();
mSensorList.clear();
- if (connectHidlService()) {
+ if (mHalWrapper->connect(this)) {
initializeSensorList();
if (sensorHandlesChanged(previousSensorList, mSensorList)) {
@@ -340,7 +163,7 @@
reactivateSensors(previousActivations);
}
}
- mReconnecting = false;
+ mHalWrapper->mReconnecting = false;
}
bool SensorDevice::sensorHandlesChanged(const std::vector<sensor_t>& oldSensorList,
@@ -422,14 +245,14 @@
if (connected) {
Info model;
mActivationCount.add(handle, model);
- checkReturn(mSensors->activate(handle, 0 /* enabled */));
+ mHalWrapper->activate(handle, 0 /* enabled */);
} else {
mActivationCount.removeItem(handle);
}
}
std::string SensorDevice::dump() const {
- if (mSensors == nullptr) return "HAL not initialized\n";
+ if (mHalWrapper == nullptr) return "HAL not initialized\n";
String8 result;
result.appendFormat("Total %zu h/w sensors, %zu running %zu disabled clients:\n",
@@ -476,7 +299,7 @@
*/
void SensorDevice::dump(ProtoOutputStream* proto) const {
using namespace service::SensorDeviceProto;
- if (mSensors == nullptr) {
+ if (mHalWrapper == nullptr) {
proto->write(INITIALIZED, false);
return;
}
@@ -511,17 +334,17 @@
}
status_t SensorDevice::initCheck() const {
- return mSensors != nullptr ? NO_ERROR : NO_INIT;
+ return mHalWrapper != nullptr ? NO_ERROR : NO_INIT;
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
- if (mSensors == nullptr) return NO_INIT;
+ if (mHalWrapper == nullptr) return NO_INIT;
ssize_t eventsRead = 0;
- if (mSensors->supportsMessageQueues()) {
- eventsRead = pollFmq(buffer, count);
- } else if (mSensors->supportsPolling()) {
- eventsRead = pollHal(buffer, count);
+ if (mHalWrapper->supportsMessageQueues()) {
+ eventsRead = mHalWrapper->pollFmq(buffer, count);
+ } else if (mHalWrapper->supportsPolling()) {
+ eventsRead = mHalWrapper->poll(buffer, count);
} else {
ALOGE("Must support polling or FMQ");
eventsRead = -1;
@@ -529,95 +352,6 @@
return eventsRead;
}
-ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) {
- ssize_t err;
- int numHidlTransportErrors = 0;
- bool hidlTransportError = false;
-
- do {
- auto ret = mSensors->poll(
- count, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
- if (result == Result::OK) {
- convertToSensorEventsAndQuantize(convertToNewEvents(events),
- convertToNewSensorInfos(
- dynamicSensorsAdded),
- buffer);
- err = (ssize_t)events.size();
- } else {
- err = statusFromResult(result);
- }
- });
-
- if (ret.isOk()) {
- hidlTransportError = false;
- } else {
- hidlTransportError = true;
- numHidlTransportErrors++;
- if (numHidlTransportErrors > 50) {
- // Log error and bail
- ALOGE("Max Hidl transport errors this cycle : %d", numHidlTransportErrors);
- handleHidlDeath(ret.description());
- } else {
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- }
- } while (hidlTransportError);
-
- if (numHidlTransportErrors > 0) {
- ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors);
- HidlTransportErrorLog errLog(time(nullptr), numHidlTransportErrors);
- mHidlTransportErrors.add(errLog);
- mTotalHidlTransportErrors++;
- }
-
- return err;
-}
-
-ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead) {
- ssize_t eventsRead = 0;
- size_t availableEvents = mSensors->getEventQueue()->availableToRead();
-
- if (availableEvents == 0) {
- uint32_t eventFlagState = 0;
-
- // Wait for events to become available. This is necessary so that the Event FMQ's read() is
- // able to be called with the correct number of events to read. If the specified number of
- // events is not available, then read() would return no events, possibly introducing
- // additional latency in delivering events to applications.
- mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) |
- asBaseType(INTERNAL_WAKE),
- &eventFlagState);
- availableEvents = mSensors->getEventQueue()->availableToRead();
-
- if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
- ALOGD("Event FMQ internal wake, returning from poll with no events");
- return DEAD_OBJECT;
- }
- }
-
- size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()});
- if (eventsToRead > 0) {
- if (mSensors->getEventQueue()->read(mEventBuffer.data(), eventsToRead)) {
- // Notify the Sensors HAL that sensor events have been read. This is required to support
- // the use of writeBlocking by the Sensors HAL.
- mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ));
-
- for (size_t i = 0; i < eventsToRead; i++) {
- convertToSensorEvent(mEventBuffer[i], &buffer[i]);
- android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i],
- getResolutionForSensor(
- buffer[i].sensor));
- }
- eventsRead = eventsToRead;
- } else {
- ALOGW("Failed to read %zu events, currently %zu events available", eventsToRead,
- availableEvents);
- }
- }
-
- return eventsRead;
-}
-
void SensorDevice::onDynamicSensorsConnected(const std::vector<sensor_t>& dynamicSensorsAdded) {
std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
@@ -641,12 +375,8 @@
}
void SensorDevice::writeWakeLockHandled(uint32_t count) {
- if (mSensors != nullptr && mSensors->supportsMessageQueues()) {
- if (mWakeLockQueue->write(&count)) {
- mWakeLockQueueFlag->wake(asBaseType(WakeLockQueueFlagBits::DATA_WRITTEN));
- } else {
- ALOGW("Failed to write wake lock handled");
- }
+ if (mHalWrapper != nullptr && mHalWrapper->supportsMessageQueues()) {
+ mHalWrapper->writeWakeLockHandled(count);
}
}
@@ -665,7 +395,7 @@
}
status_t SensorDevice::activate(void* ident, int handle, int enabled) {
- if (mSensors == nullptr) return NO_INIT;
+ if (mHalWrapper == nullptr) return NO_INIT;
Mutex::Autolock _l(mLock);
return activateLocked(ident, handle, enabled);
@@ -724,8 +454,8 @@
// events, and the best effort batch parameters might have changed.
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w batch 0x%08x %" PRId64 " %" PRId64,
handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
- checkReturn(mSensors->batch(handle, info.bestBatchParams.mTSample,
- info.bestBatchParams.mTBatch));
+ mHalWrapper->batch(handle, info.bestBatchParams.mTSample,
+ info.bestBatchParams.mTBatch);
}
} else {
// sensor wasn't enabled for this ident
@@ -756,7 +486,7 @@
status_t SensorDevice::doActivateHardwareLocked(int handle, bool enabled) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
enabled);
- status_t err = checkReturnAndGetStatus(mSensors->activate(handle, enabled));
+ status_t err = mHalWrapper->activate(handle, enabled);
ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
strerror(-err));
return err;
@@ -764,7 +494,7 @@
status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
- if (mSensors == nullptr) return NO_INIT;
+ if (mHalWrapper == nullptr) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
@@ -801,8 +531,8 @@
status_t err = updateBatchParamsLocked(handle, info);
if (err != NO_ERROR) {
- ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s", mSensors.get(),
- handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch, strerror(-err));
+ ALOGE("sensor batch failed 0x%08x %" PRId64 " %" PRId64 " err=%s", handle,
+ info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch, strerror(-err));
info.removeBatchParamsForIdent(ident);
}
@@ -825,8 +555,8 @@
if (prevBestBatchParams != info.bestBatchParams && info.numActiveClients() > 0) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH 0x%08x %" PRId64 " %" PRId64, handle,
info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
- err = checkReturnAndGetStatus(mSensors->batch(handle, info.bestBatchParams.mTSample,
- info.bestBatchParams.mTBatch));
+ err = mHalWrapper->batch(handle, info.bestBatchParams.mTSample,
+ info.bestBatchParams.mTBatch);
}
return err;
@@ -837,15 +567,12 @@
}
int SensorDevice::getHalDeviceVersion() const {
- if (mSensors == nullptr) return -1;
+ if (mHalWrapper == nullptr) return -1;
return SENSORS_DEVICE_API_VERSION_1_4;
}
-status_t SensorDevice::flush(void* ident, int handle) {
- if (mSensors == nullptr) return NO_INIT;
- if (isClientDisabled(ident)) return INVALID_OPERATION;
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
- return checkReturnAndGetStatus(mSensors->flush(handle));
+status_t SensorDevice::flush(void* /*ident*/, int handle) {
+ return mHalWrapper->flush(handle);
}
bool SensorDevice::isClientDisabled(void* ident) const {
@@ -928,7 +655,7 @@
}
void SensorDevice::enableAllSensors() {
- if (mSensors == nullptr) return;
+ if (mHalWrapper == nullptr) return;
Mutex::Autolock _l(mLock);
for (void* client : getDisabledClientsLocked()) {
@@ -943,13 +670,12 @@
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
sensor_handle);
- status_t err = checkReturnAndGetStatus(mSensors->batch(sensor_handle,
- info.bestBatchParams.mTSample,
- info.bestBatchParams.mTBatch));
+ status_t err = mHalWrapper->batch(sensor_handle, info.bestBatchParams.mTSample,
+ info.bestBatchParams.mTBatch);
ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
if (err == NO_ERROR) {
- err = checkReturnAndGetStatus(mSensors->activate(sensor_handle, 1 /* enabled */));
+ err = mHalWrapper->activate(sensor_handle, 1 /* enabled */);
ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
}
@@ -960,7 +686,7 @@
}
void SensorDevice::disableAllSensors() {
- if (mSensors == nullptr) return;
+ if (mHalWrapper == nullptr) return;
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mActivationCount.size(); ++i) {
Info& info = mActivationCount.editValueAt(i);
@@ -969,7 +695,7 @@
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
sensor_handle);
- checkReturn(mSensors->activate(sensor_handle, 0 /* enabled */));
+ mHalWrapper->activate(sensor_handle, 0 /* enabled */);
// Add all the connections that were registered for this sensor to the disabled
// clients list.
@@ -985,110 +711,29 @@
}
status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
- if (mSensors == nullptr) return NO_INIT;
- ALOGD_IF(DEBUG_CONNECTIONS,
- "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
- injected_sensor_event->sensor, injected_sensor_event->timestamp,
- injected_sensor_event->data[0], injected_sensor_event->data[1],
- injected_sensor_event->data[2], injected_sensor_event->data[3],
- injected_sensor_event->data[4], injected_sensor_event->data[5]);
-
- Event ev;
- V2_1::implementation::convertFromSensorEvent(*injected_sensor_event, &ev);
-
- return checkReturnAndGetStatus(mSensors->injectSensorData(ev));
+ return mHalWrapper->injectSensorData(injected_sensor_event);
}
status_t SensorDevice::setMode(uint32_t mode) {
- if (mSensors == nullptr) return NO_INIT;
- return checkReturnAndGetStatus(
- mSensors->setOperationMode(static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
+ if (mHalWrapper == nullptr) return NO_INIT;
+ return mHalWrapper->setOperationMode(static_cast<SensorService::Mode>(mode));
}
int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
- if (mSensors == nullptr) return NO_INIT;
Mutex::Autolock _l(mLock);
- SharedMemType type;
- switch (memory->type) {
- case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
- type = SharedMemType::ASHMEM;
- break;
- case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
- type = SharedMemType::GRALLOC;
- break;
- default:
- return BAD_VALUE;
- }
-
- SharedMemFormat format;
- if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
- return BAD_VALUE;
- }
- format = SharedMemFormat::SENSORS_EVENT;
-
- SharedMemInfo mem = {
- .type = type,
- .format = format,
- .size = static_cast<uint32_t>(memory->size),
- .memoryHandle = memory->handle,
- };
-
- int32_t ret;
- checkReturn(mSensors->registerDirectChannel(mem, [&ret](auto result, auto channelHandle) {
- if (result == Result::OK) {
- ret = channelHandle;
- } else {
- ret = statusFromResult(result);
- }
- }));
- return ret;
+ return mHalWrapper->registerDirectChannel(memory, nullptr);
}
void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
- if (mSensors == nullptr) return;
- Mutex::Autolock _l(mLock);
- checkReturn(mSensors->unregisterDirectChannel(channelHandle));
+ mHalWrapper->unregisterDirectChannel(channelHandle);
}
int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
const struct sensors_direct_cfg_t* config) {
- if (mSensors == nullptr) return NO_INIT;
Mutex::Autolock _l(mLock);
- RateLevel rate;
- switch (config->rate_level) {
- case SENSOR_DIRECT_RATE_STOP:
- rate = RateLevel::STOP;
- break;
- case SENSOR_DIRECT_RATE_NORMAL:
- rate = RateLevel::NORMAL;
- break;
- case SENSOR_DIRECT_RATE_FAST:
- rate = RateLevel::FAST;
- break;
- case SENSOR_DIRECT_RATE_VERY_FAST:
- rate = RateLevel::VERY_FAST;
- break;
- default:
- return BAD_VALUE;
- }
-
- int32_t ret;
- checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
- [&ret, rate](auto result, auto token) {
- if (rate == RateLevel::STOP) {
- ret = statusFromResult(result);
- } else {
- if (result == Result::OK) {
- ret = token;
- } else {
- ret = statusFromResult(result);
- }
- }
- }));
-
- return ret;
+ return mHalWrapper->configureDirectChannel(sensorHandle, channelHandle, config);
}
// ---------------------------------------------------------------------------
@@ -1153,52 +798,6 @@
return mIsDirectReportSupported;
}
-void SensorDevice::convertToSensorEvent(const Event& src, sensors_event_t* dst) {
- V2_1::implementation::convertToSensorEvent(src, dst);
-
- if (src.sensorType == V2_1::SensorType::DYNAMIC_SENSOR_META) {
- const DynamicSensorInfo& dyn = src.u.dynamic;
-
- dst->dynamic_sensor_meta.connected = dyn.connected;
- dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
- if (dyn.connected) {
- std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
- // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked since it
- // can be received out of order from this event due to a bug in the HIDL spec that
- // marks it as oneway.
- auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
- if (it == mConnectedDynamicSensors.end()) {
- mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] {
- return mConnectedDynamicSensors.find(dyn.sensorHandle) !=
- mConnectedDynamicSensors.end();
- });
- it = mConnectedDynamicSensors.find(dyn.sensorHandle);
- CHECK(it != mConnectedDynamicSensors.end());
- }
-
- dst->dynamic_sensor_meta.sensor = &it->second;
-
- memcpy(dst->dynamic_sensor_meta.uuid, dyn.uuid.data(),
- sizeof(dst->dynamic_sensor_meta.uuid));
- }
- }
-}
-
-void SensorDevice::convertToSensorEventsAndQuantize(const hidl_vec<Event>& src,
- const hidl_vec<SensorInfo>& dynamicSensorsAdded,
- sensors_event_t* dst) {
- if (dynamicSensorsAdded.size() > 0 && mCallback != nullptr) {
- mCallback->onDynamicSensorsConnected_2_1(dynamicSensorsAdded);
- }
-
- for (size_t i = 0; i < src.size(); ++i) {
- V2_1::implementation::convertToSensorEvent(src[i], &dst[i]);
- android::SensorDeviceUtils::quantizeSensorEventValues(&dst[i],
- getResolutionForSensor(
- dst[i].sensor));
- }
-}
-
float SensorDevice::getResolutionForSensor(int sensorHandle) {
for (size_t i = 0; i < mSensorList.size(); i++) {
if (sensorHandle == mSensorList[i].handle) {
@@ -1214,19 +813,5 @@
return 0;
}
-void SensorDevice::handleHidlDeath(const std::string& detail) {
- if (!mSensors->supportsMessageQueues()) {
- // restart is the only option at present.
- LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
- } else {
- ALOGD("ISensors HAL died, death recipient will attempt reconnect");
- }
-}
-
-status_t SensorDevice::checkReturnAndGetStatus(const Return<Result>& ret) {
- checkReturn(ret);
- return (!ret.isOk()) ? DEAD_OBJECT : statusFromResult(ret);
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 314ddb8..80e77d9 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_SENSOR_DEVICE_H
#define ANDROID_SENSOR_DEVICE_H
+#include "HidlSensorHalWrapper.h"
+#include "ISensorHalWrapper.h"
+
#include "ISensorsWrapper.h"
#include "SensorDeviceUtils.h"
#include "SensorService.h"
#include "SensorServiceUtils.h"
-#include <fmq/MessageQueue.h>
#include <sensor/Sensor.h>
#include <sensor/SensorEventQueue.h>
#include <stdint.h>
@@ -43,41 +45,12 @@
namespace android {
-using Result = ::android::hardware::sensors::V1_0::Result;
-
// ---------------------------------------------------------------------------
-class SensorsHalDeathReceivier : public android::hardware::hidl_death_recipient {
- virtual void serviceDied(uint64_t cookie,
- const wp<::android::hidl::base::V1_0::IBase>& service) override;
-};
-class SensorDevice : public Singleton<SensorDevice>, public SensorServiceUtil::Dumpable {
+class SensorDevice : public Singleton<SensorDevice>,
+ public SensorServiceUtil::Dumpable,
+ public ISensorHalWrapper::SensorDeviceCallback {
public:
- class HidlTransportErrorLog {
- public:
- HidlTransportErrorLog() {
- mTs = 0;
- mCount = 0;
- }
-
- HidlTransportErrorLog(time_t ts, int count) {
- mTs = ts;
- mCount = count;
- }
-
- String8 toString() const {
- String8 result;
- struct tm* timeInfo = localtime(&mTs);
- result.appendFormat("%02d:%02d:%02d :: %d", timeInfo->tm_hour, timeInfo->tm_min,
- timeInfo->tm_sec, mCount);
- return result;
- }
-
- private:
- time_t mTs; // timestamp of the error
- int mCount; // number of transport errors observed
- };
-
~SensorDevice();
void prepareForReconnect();
void reconnect();
@@ -112,12 +85,15 @@
status_t injectSensorData(const sensors_event_t* event);
void notifyConnectionDestroyed(void* ident);
- void onDynamicSensorsConnected(const std::vector<sensor_t>& dynamicSensorsAdded);
- void onDynamicSensorsDisconnected(const std::vector<int32_t>& dynamicSensorHandlesRemoved);
+ // SensorDeviceCallback
+ virtual void onDynamicSensorsConnected(
+ const std::vector<sensor_t>& dynamicSensorsAdded) override;
+ virtual void onDynamicSensorsDisconnected(
+ const std::vector<int32_t>& dynamicSensorHandlesRemoved) override;
void setUidStateForConnection(void* ident, SensorService::UidState state);
- bool isReconnecting() const { return mReconnecting; }
+ bool isReconnecting() const { return mHalWrapper->mReconnecting; }
bool isSensorActive(int handle) const;
@@ -132,8 +108,8 @@
private:
friend class Singleton<SensorDevice>;
- sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors;
- sp<::android::hardware::sensors::V2_1::ISensorsCallback> mCallback;
+ std::unique_ptr<ISensorHalWrapper> mHalWrapper;
+
std::vector<sensor_t> mSensorList;
std::unordered_map<int32_t, sensor_t> mConnectedDynamicSensors;
@@ -143,7 +119,6 @@
// HAL implementations.
std::mutex mDynamicSensorsMutex;
std::condition_variable mDynamicSensorsCv;
- static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5};
static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
mutable Mutex mLock; // protect mActivationCount[].batchParams
@@ -203,8 +178,6 @@
};
DefaultKeyedVector<int, Info> mActivationCount;
- // Keep track of any hidl transport failures
- SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors;
int mTotalHidlTransportErrors;
/**
@@ -228,26 +201,13 @@
void removeDisabledReasonForIdentLocked(void* ident, DisabledReason reason);
SensorDevice();
- bool connectHidlService();
+ bool connectHalService();
void initializeSensorList();
void reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations);
static bool sensorHandlesChanged(const std::vector<sensor_t>& oldSensorList,
const std::vector<sensor_t>& newSensorList);
static bool sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor);
- enum HalConnectionStatus {
- CONNECTED, // Successfully connected to the HAL
- DOES_NOT_EXIST, // Could not find the HAL
- FAILED_TO_CONNECT, // Found the HAL but failed to connect/initialize
- UNKNOWN,
- };
- HalConnectionStatus connectHidlServiceV1_0();
- HalConnectionStatus connectHidlServiceV2_0();
- HalConnectionStatus connectHidlServiceV2_1();
- HalConnectionStatus initializeHidlServiceV2_X();
-
- ssize_t pollHal(sensors_event_t* buffer, size_t count);
- ssize_t pollFmq(sensors_event_t* buffer, size_t count);
status_t activateLocked(void* ident, int handle, int enabled);
status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs);
@@ -255,47 +215,15 @@
status_t updateBatchParamsLocked(int handle, Info& info);
status_t doActivateHardwareLocked(int handle, bool enable);
- void handleHidlDeath(const std::string& detail);
- template <typename T>
- void checkReturn(const Return<T>& ret) {
- if (!ret.isOk()) {
- handleHidlDeath(ret.description());
- }
- }
-
- status_t checkReturnAndGetStatus(const Return<Result>& ret);
- // TODO(b/67425500): remove waiter after bug is resolved.
- sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
-
bool isClientDisabled(void* ident) const;
bool isClientDisabledLocked(void* ident) const;
std::vector<void*> getDisabledClientsLocked() const;
bool clientHasNoAccessLocked(void* ident) const;
- using Event = hardware::sensors::V2_1::Event;
- using SensorInfo = hardware::sensors::V2_1::SensorInfo;
-
- void convertToSensorEvent(const Event& src, sensors_event_t* dst);
-
- void convertToSensorEventsAndQuantize(const hardware::hidl_vec<Event>& src,
- const hardware::hidl_vec<SensorInfo>& dynamicSensorsAdded,
- sensors_event_t* dst);
-
float getResolutionForSensor(int sensorHandle);
bool mIsDirectReportSupported;
-
- typedef hardware::MessageQueue<uint32_t, hardware::kSynchronizedReadWrite> WakeLockQueue;
- std::unique_ptr<WakeLockQueue> mWakeLockQueue;
-
- hardware::EventFlag* mEventQueueFlag;
- hardware::EventFlag* mWakeLockQueueFlag;
-
- std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
-
- sp<SensorsHalDeathReceivier> mSensorsHalDeathReceiver;
- std::atomic_bool mReconnecting;
};
// ---------------------------------------------------------------------------
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/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 5f8e434..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>
@@ -627,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/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 0c4e112..86e96d7 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -667,7 +667,8 @@
packet->set_timestamp(
static_cast<uint64_t>(endTime - kPredictionExpiredStartTimeDelta));
} else {
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+ packet->set_timestamp(static_cast<uint64_t>(
+ mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime));
}
auto* event = packet->set_frame_timeline_event();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6e9138c..5948a78 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1263,6 +1263,7 @@
getSequence(), mName,
mTransactionName,
/*isBuffer*/ false, getGameMode());
+ surfaceFrame->setActualStartTime(info.startTimeNanos);
// For Transactions, the post time is considered to be both queue and acquire fence time.
surfaceFrame->setActualQueueTime(postTime);
surfaceFrame->setAcquireFenceTime(postTime);
@@ -1280,6 +1281,7 @@
mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid,
getSequence(), mName, debugName,
/*isBuffer*/ true, getGameMode());
+ surfaceFrame->setActualStartTime(info.startTimeNanos);
// For buffers, acquire fence time will set during latch.
surfaceFrame->setActualQueueTime(queueTime);
const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
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);