summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-15 21:50:53 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-15 21:50:53 +0000
commit9d32f7da95b0dc23e4329411b7d0d76f751f1912 (patch)
tree0fe5012e262a64b731e9ad784daacb6ba3c72761
parent1c0caadb38b0eff21d119b27ffa45886bb3b128b (diff)
parente39516d84d785435a1b61f81234143df10d69a5c (diff)
downloadcore-aml_tz3_314012010.tar.gz
Change-Id: Iee871fe28ebb919b6082e1715f36ffc64403ee98
-rw-r--r--PREUPLOAD.cfg2
-rw-r--r--TEST_MAPPING66
-rw-r--r--bootstat/bootstat.cpp24
-rw-r--r--debuggerd/Android.bp66
-rw-r--r--debuggerd/OWNERS1
-rw-r--r--debuggerd/TEST_MAPPING15
-rw-r--r--debuggerd/client/debuggerd_client.cpp187
-rw-r--r--debuggerd/crash_dump.cpp24
-rw-r--r--debuggerd/crash_test.cpp9
-rw-r--r--debuggerd/crash_test.h38
-rw-r--r--debuggerd/crasher/Android.bp2
-rw-r--r--debuggerd/crasher/crasher.cpp10
-rw-r--r--debuggerd/debuggerd.cpp22
-rw-r--r--debuggerd/debuggerd_test.cpp712
-rw-r--r--debuggerd/handler/debuggerd_fallback.cpp100
-rw-r--r--debuggerd/handler/debuggerd_fallback_nop.cpp34
-rw-r--r--debuggerd/handler/debuggerd_handler.cpp65
-rw-r--r--debuggerd/libdebuggerd/gwp_asan.cpp120
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h20
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/scudo.h4
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h4
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/types.h1
-rw-r--r--debuggerd/libdebuggerd/include/libdebuggerd/utility.h40
-rw-r--r--debuggerd/libdebuggerd/scudo.cpp88
-rw-r--r--debuggerd/libdebuggerd/test/UnwinderMock.h4
-rw-r--r--debuggerd/libdebuggerd/test/tombstone_test.cpp486
-rw-r--r--debuggerd/libdebuggerd/test/utility_test.cpp42
-rw-r--r--debuggerd/libdebuggerd/tombstone.cpp598
-rw-r--r--debuggerd/libdebuggerd/tombstone_proto.cpp274
-rw-r--r--debuggerd/libdebuggerd/tombstone_proto_to_text.cpp60
-rw-r--r--debuggerd/libdebuggerd/utility.cpp65
-rw-r--r--debuggerd/proto/tombstone.proto4
-rw-r--r--debuggerd/rust/tombstoned_client/Android.bp59
-rw-r--r--debuggerd/rust/tombstoned_client/src/lib.rs153
-rw-r--r--debuggerd/rust/tombstoned_client/wrapper.cpp38
-rw-r--r--debuggerd/rust/tombstoned_client/wrapper.hpp23
-rw-r--r--debuggerd/seccomp_policy/crash_dump.arm.policy1
-rw-r--r--debuggerd/seccomp_policy/crash_dump.arm64.policy3
-rw-r--r--debuggerd/seccomp_policy/crash_dump.policy.def11
-rw-r--r--debuggerd/seccomp_policy/crash_dump.x86.policy1
-rw-r--r--debuggerd/seccomp_policy/crash_dump.x86_64.policy1
-rw-r--r--debuggerd/tombstoned/tombstoned.cpp2
-rw-r--r--debuggerd/tombstoned/tombstoned.rc2
-rw-r--r--debuggerd/util.cpp22
-rw-r--r--debuggerd/util.h2
-rw-r--r--diagnose_usb/Android.bp1
-rw-r--r--diagnose_usb/OWNERS1
-rw-r--r--diagnose_usb/diagnose_usb.cpp24
-rw-r--r--fastboot/Android.bp18
-rw-r--r--fastboot/Android.mk12
-rw-r--r--fastboot/LICENSE23
-rw-r--r--fastboot/OWNERS3
-rw-r--r--fastboot/README.md12
-rw-r--r--fastboot/device/commands.cpp10
-rw-r--r--fastboot/device/fastboot_device.cpp29
-rw-r--r--fastboot/device/fastboot_device.h6
-rw-r--r--fastboot/device/flashing.cpp88
-rw-r--r--fastboot/device/utility.cpp12
-rw-r--r--fastboot/device/utility.h50
-rw-r--r--fastboot/device/variables.cpp21
-rw-r--r--fastboot/fastboot.bash2
-rw-r--r--fastboot/fastboot.cpp125
-rw-r--r--fastboot/fs.cpp7
-rw-r--r--fastboot/fuzzer/Android.bp62
-rw-r--r--fastboot/fuzzer/README.md51
-rw-r--r--fastboot/fuzzer/fastboot_fuzzer.cpp276
-rw-r--r--fastboot/fuzzer/socket_mock_fuzz.cpp126
-rw-r--r--fastboot/fuzzer/socket_mock_fuzz.h73
-rw-r--r--fastboot/fuzzy_fastboot/README.md2
-rw-r--r--fastboot/fuzzy_fastboot/main.cpp119
-rw-r--r--fastboot/socket.cpp4
-rw-r--r--fs_mgr/Android.bp54
-rw-r--r--fs_mgr/NOTICE21
-rw-r--r--fs_mgr/OWNERS2
-rw-r--r--fs_mgr/TEST_MAPPING6
-rw-r--r--fs_mgr/blockdev.cpp17
-rw-r--r--fs_mgr/clean_scratch_files.cpp (renamed from libusbhost/include/usbhost/usbhost_jni.h)17
-rw-r--r--fs_mgr/file_wait.cpp3
-rw-r--r--fs_mgr/fs_mgr.cpp304
-rw-r--r--fs_mgr/fs_mgr_format.cpp24
-rw-r--r--fs_mgr/fs_mgr_fstab.cpp260
-rw-r--r--fs_mgr/fs_mgr_overlayfs.cpp145
-rw-r--r--fs_mgr/fs_mgr_remount.cpp20
-rw-r--r--fs_mgr/fs_mgr_roots.cpp50
-rw-r--r--fs_mgr/fs_mgr_verity.cpp557
-rw-r--r--fs_mgr/fuzz/Android.bp40
-rw-r--r--fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp26
-rw-r--r--fs_mgr/fuzz/fstab.dict70
-rw-r--r--fs_mgr/include/fs_mgr.h19
-rw-r--r--fs_mgr/include/fs_mgr/file_wait.h3
-rw-r--r--fs_mgr/include_fstab/fstab/fstab.h17
-rw-r--r--fs_mgr/libdm/Android.bp4
-rw-r--r--fs_mgr/libdm/dm.cpp88
-rw-r--r--fs_mgr/libdm/dm_target.cpp4
-rw-r--r--fs_mgr/libdm/dm_test.cpp11
-rw-r--r--fs_mgr/libdm/include/libdm/dm.h73
-rw-r--r--fs_mgr/libdm/include/libdm/dm_target.h1
-rw-r--r--fs_mgr/libdm/include/libdm/loop_control.h3
-rw-r--r--fs_mgr/libdm/loop_control.cpp10
-rw-r--r--fs_mgr/libfiemap/Android.bp6
-rw-r--r--fs_mgr/libfiemap/binder.cpp12
-rw-r--r--fs_mgr/libfiemap/fiemap_writer.cpp56
-rw-r--r--fs_mgr/libfiemap/fiemap_writer_test.cpp29
-rw-r--r--fs_mgr/libfiemap/image_manager.cpp139
-rw-r--r--fs_mgr/libfiemap/image_test.cpp1
-rw-r--r--fs_mgr/libfiemap/include/libfiemap/image_manager.h7
-rw-r--r--fs_mgr/libfiemap/metadata.h5
-rw-r--r--fs_mgr/libfiemap/split_fiemap_writer.cpp4
-rw-r--r--fs_mgr/libfs_avb/Android.bp3
-rw-r--r--fs_mgr/libfs_avb/avb_util.cpp75
-rw-r--r--fs_mgr/libfs_avb/avb_util.h6
-rw-r--r--fs_mgr/libfs_avb/fs_avb.cpp1
-rw-r--r--fs_mgr/libfs_avb/fs_avb_util.cpp71
-rw-r--r--fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h6
-rwxr-xr-xfs_mgr/libfs_avb/run_tests.sh9
-rw-r--r--fs_mgr/libfs_avb/tests/avb_util_test.cpp11
-rw-r--r--fs_mgr/liblp/Android.bp6
-rw-r--r--fs_mgr/liblp/OWNERS2
-rw-r--r--fs_mgr/liblp/TEST_MAPPING5
-rw-r--r--fs_mgr/liblp/builder_test.cpp2
-rw-r--r--fs_mgr/liblp/io_test.cpp4
-rw-r--r--fs_mgr/libsnapshot/Android.bp162
-rw-r--r--fs_mgr/libsnapshot/OWNERS2
-rw-r--r--fs_mgr/libsnapshot/android/snapshot/snapshot.proto9
-rw-r--r--fs_mgr/libsnapshot/cow_api_test.cpp312
-rw-r--r--fs_mgr/libsnapshot/cow_format.cpp22
-rw-r--r--fs_mgr/libsnapshot/cow_reader.cpp512
-rw-r--r--fs_mgr/libsnapshot/cow_snapuserd_test.cpp (renamed from fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp)164
-rw-r--r--fs_mgr/libsnapshot/cow_writer.cpp64
-rw-r--r--fs_mgr/libsnapshot/device_info.cpp4
-rw-r--r--fs_mgr/libsnapshot/device_info.h1
-rw-r--r--fs_mgr/libsnapshot/dm_snapshot_internals.h59
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/cow_format.h11
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h71
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h18
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h1
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h55
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/snapshot.h63
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h1
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h17
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h (renamed from fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h)16
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h (renamed from fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h)2
-rw-r--r--fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h47
-rw-r--r--fs_mgr/libsnapshot/inspect_cow.cpp126
-rw-r--r--fs_mgr/libsnapshot/run_snapshot_tests.sh35
-rw-r--r--fs_mgr/libsnapshot/scripts/Android.bp31
-rw-r--r--fs_mgr/libsnapshot/scripts/dump_snapshot_proto.py39
-rw-r--r--fs_mgr/libsnapshot/snapshot.cpp843
-rw-r--r--fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp4
-rw-r--r--fs_mgr/libsnapshot/snapshot_fuzz_utils.h6
-rw-r--r--fs_mgr/libsnapshot/snapshot_reader.cpp25
-rw-r--r--fs_mgr/libsnapshot/snapshot_reader_test.cpp21
-rw-r--r--fs_mgr/libsnapshot/snapshot_stub.cpp5
-rw-r--r--fs_mgr/libsnapshot/snapshot_test.cpp532
-rw-r--r--fs_mgr/libsnapshot/snapshot_writer.cpp35
-rw-r--r--fs_mgr/libsnapshot/snapshotctl.cpp4
-rw-r--r--fs_mgr/libsnapshot/snapuserd.cpp (renamed from fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp)217
-rw-r--r--fs_mgr/libsnapshot/snapuserd.h (renamed from fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h)45
-rw-r--r--fs_mgr/libsnapshot/snapuserd.rc7
-rw-r--r--fs_mgr/libsnapshot/snapuserd/Android.bp200
-rw-r--r--fs_mgr/libsnapshot/snapuserd/OWNERS3
-rw-r--r--fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h62
-rw-r--r--fs_mgr/libsnapshot/snapuserd/snapuserd.rc19
-rw-r--r--fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp96
-rw-r--r--fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp245
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp701
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h419
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp645
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp570
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp816
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp691
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h148
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp885
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp653
-rw-r--r--fs_mgr/libsnapshot/snapuserd_client.cpp (renamed from fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp)68
-rw-r--r--fs_mgr/libsnapshot/snapuserd_daemon.cpp132
-rw-r--r--fs_mgr/libsnapshot/snapuserd_daemon.h (renamed from fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.h)12
-rw-r--r--fs_mgr/libsnapshot/snapuserd_readahead.cpp (renamed from fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp)90
-rw-r--r--fs_mgr/libsnapshot/snapuserd_server.cpp (renamed from fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp)157
-rw-r--r--fs_mgr/libsnapshot/snapuserd_server.h (renamed from fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.h)9
-rw-r--r--fs_mgr/libsnapshot/snapuserd_worker.cpp (renamed from fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp)128
-rw-r--r--fs_mgr/libsnapshot/test_helpers.cpp4
-rw-r--r--fs_mgr/libsnapshot/utility.cpp13
-rw-r--r--fs_mgr/libsnapshot/utility.h11
-rw-r--r--fs_mgr/libsnapshot/vts_ota_config_test.cpp23
-rw-r--r--fs_mgr/libstorage_literals/Android.bp2
-rw-r--r--fs_mgr/tests/Android.bp29
-rw-r--r--fs_mgr/tests/fs_mgr_test.cpp176
-rw-r--r--fs_mgr/tests/vts_fs_test.cpp119
-rw-r--r--gatekeeperd/Android.bp7
-rw-r--r--gatekeeperd/gatekeeperd.rc2
-rw-r--r--healthd/Android.bp122
-rw-r--r--healthd/BatteryMonitor.cpp279
-rw-r--r--healthd/OWNERS1
-rw-r--r--healthd/TEST_MAPPING5
-rw-r--r--healthd/charger.cpp4
-rw-r--r--healthd/charger_test.cpp4
-rw-r--r--healthd/healthd_draw.cpp44
-rw-r--r--healthd/healthd_draw.h14
-rw-r--r--healthd/healthd_mode_charger.cpp220
-rw-r--r--healthd/healthd_mode_charger.h (renamed from healthd/include_charger/charger/healthd_mode_charger.h)77
-rw-r--r--healthd/healthd_mode_charger_hidl.cpp81
-rw-r--r--healthd/healthd_mode_charger_hidl.h55
-rw-r--r--healthd/healthd_mode_charger_test.cpp9
-rw-r--r--healthd/include/healthd/BatteryMonitor.h22
-rw-r--r--init/Android.bp138
-rw-r--r--init/Android.mk151
-rw-r--r--init/OWNERS1
-rw-r--r--init/README.md110
-rw-r--r--init/README.ueventd.md21
-rw-r--r--init/TEST_MAPPING24
-rw-r--r--init/block_dev_initializer.cpp8
-rw-r--r--init/bootchart.cpp14
-rw-r--r--init/builtins.cpp166
-rw-r--r--init/devices.cpp50
-rw-r--r--init/devices.h6
-rw-r--r--init/epoll.cpp19
-rw-r--r--init/epoll.h7
-rwxr-xr-xinit/extra_free_kbytes.sh136
-rw-r--r--init/firmware_handler.cpp22
-rw-r--r--init/firmware_handler.h5
-rw-r--r--init/first_stage_console.cpp3
-rw-r--r--init/first_stage_init.cpp71
-rw-r--r--init/first_stage_mount.cpp77
-rwxr-xr-xinit/host_builtin_map.py9
-rw-r--r--init/init.cpp124
-rw-r--r--init/main.cpp6
-rw-r--r--init/mount_handler.cpp86
-rw-r--r--init/mount_namespace.cpp114
-rw-r--r--init/parser.cpp54
-rw-r--r--init/parser.h6
-rwxr-xr-xinit/perfboot.py40
-rw-r--r--init/property_service.cpp51
-rw-r--r--init/property_service_test.cpp2
-rw-r--r--init/reboot.cpp42
-rw-r--r--init/selinux.cpp302
-rw-r--r--init/service.cpp287
-rw-r--r--init/service.h19
-rw-r--r--init/service_parser.cpp42
-rw-r--r--init/service_utils.cpp13
-rw-r--r--init/service_utils.h1
-rw-r--r--init/sigchld_handler.cpp5
-rw-r--r--init/snapuserd_transition.cpp110
-rw-r--r--init/snapuserd_transition.h11
-rw-r--r--init/subcontext.cpp10
-rw-r--r--init/switch_root.cpp3
-rw-r--r--init/ueventd.cpp75
-rw-r--r--init/ueventd_parser.cpp32
-rw-r--r--init/ueventd_parser.h1
-rw-r--r--init/ueventd_parser_test.cpp69
-rw-r--r--init/ueventd_test.cpp2
-rw-r--r--init/util.cpp5
-rw-r--r--init/util.h2
-rw-r--r--libasyncio/Android.bp1
-rw-r--r--libcrypto_utils/Android.bp3
-rw-r--r--libcutils/Android.bp15
-rw-r--r--libcutils/TEST_MAPPING12
-rw-r--r--libcutils/fs_config.cpp1
-rw-r--r--libcutils/include/cutils/list.h14
-rw-r--r--libcutils/include/cutils/multiuser.h2
-rw-r--r--libcutils/include/cutils/qtaguid.h18
-rw-r--r--libcutils/include/cutils/trace.h68
-rw-r--r--libcutils/include/private/android_filesystem_config.h15
-rw-r--r--libcutils/include/private/android_projectid_config.h10
-rw-r--r--libcutils/multiuser.cpp19
-rw-r--r--libcutils/multiuser_test.cpp35
-rw-r--r--libcutils/qtaguid.cpp31
-rw-r--r--libcutils/rust/cutils.h4
-rw-r--r--libcutils/trace-container.cpp104
-rw-r--r--libcutils/trace-dev.cpp28
-rw-r--r--libcutils/trace-dev.inc33
-rw-r--r--libcutils/trace-dev_test.cpp377
-rw-r--r--libcutils/trace-host.cpp6
-rw-r--r--libdiskconfig/Android.bp6
-rw-r--r--libgrallocusage/Android.bp5
-rw-r--r--libkeyutils/Android.bp8
-rw-r--r--libkeyutils/NOTICE25
-rw-r--r--libmodprobe/Android.bp1
-rw-r--r--libmodprobe/TEST_MAPPING12
-rw-r--r--libmodprobe/include/modprobe/modprobe.h6
-rw-r--r--libmodprobe/libmodprobe.cpp93
-rw-r--r--libmodprobe/libmodprobe_ext.cpp5
-rw-r--r--libmodprobe/libmodprobe_test.cpp9
-rw-r--r--libnetutils/Android.bp20
-rw-r--r--libnetutils/checksum.c145
-rw-r--r--libnetutils/include/netutils/checksum.h34
-rw-r--r--libpackagelistparser/TEST_MAPPING12
-rw-r--r--libprocessgroup/Android.bp26
-rw-r--r--libprocessgroup/cgroup_map.cpp40
-rw-r--r--libprocessgroup/cgroup_map.h2
-rw-r--r--libprocessgroup/cgrouprc/include/android/cgrouprc.h1
-rw-r--r--libprocessgroup/include/processgroup/processgroup.h4
-rw-r--r--libprocessgroup/processgroup.cpp142
-rw-r--r--libprocessgroup/profiles/cgroups.json9
-rw-r--r--libprocessgroup/profiles/task_profiles.json56
-rw-r--r--libprocessgroup/profiles/task_profiles.proto4
-rw-r--r--libprocessgroup/profiles/task_profiles_28.json27
-rw-r--r--libprocessgroup/profiles/task_profiles_29.json27
-rw-r--r--libprocessgroup/profiles/task_profiles_30.json27
-rw-r--r--libprocessgroup/sched_policy.cpp51
-rw-r--r--libprocessgroup/setup/cgroup_map_write.cpp23
-rw-r--r--libprocessgroup/task_profiles.cpp449
-rw-r--r--libprocessgroup/task_profiles.h144
-rw-r--r--libprocessgroup/task_profiles_test.cpp209
-rw-r--r--libprocessgroup/tools/Android.bp30
-rw-r--r--libprocessgroup/tools/settaskprofile.cpp53
-rw-r--r--libqtaguid/Android.bp60
-rw-r--r--libqtaguid/include/qtaguid/qtaguid.h62
-rw-r--r--libqtaguid/qtaguid.c143
-rw-r--r--libsparse/Android.bp10
-rw-r--r--libsparse/img2simg.cpp2
-rw-r--r--libsparse/include/sparse/sparse.h49
-rw-r--r--libsparse/output_file.cpp34
-rwxr-xr-xlibsparse/simg_dump.py9
-rw-r--r--libsparse/sparse_fuzzer.cpp27
-rw-r--r--libsparse/sparse_read.cpp198
-rw-r--r--libstats/bootstrap/Android.bp49
-rw-r--r--libstats/bootstrap/BootstrapClientInternal.cpp57
-rw-r--r--libstats/bootstrap/BootstrapClientInternal.h41
-rw-r--r--libstats/bootstrap/StatsBootstrapAtomClient.cpp37
-rw-r--r--libstats/bootstrap/include/StatsBootstrapAtomClient.h32
-rw-r--r--libstats/pull_lazy/TEST_MAPPING5
-rw-r--r--libstats/pull_rust/Android.bp15
-rw-r--r--libstats/pull_rust/stats_pull.rs2
-rw-r--r--libstats/socket_lazy/TEST_MAPPING5
-rw-r--r--libsuspend/Android.bp1
-rw-r--r--libsync/OWNERS1
-rw-r--r--libsystem/include/system/graphics.h10
-rw-r--r--libsysutils/src/NetlinkEvent.cpp164
-rw-r--r--libusbhost/Android.bp6
-rw-r--r--libusbhost/include/usbhost/usbhost.h1
-rw-r--r--libusbhost/usbhost.c30
-rw-r--r--libusbhost/usbhost_jni.cpp41
-rw-r--r--libusbhost/usbhost_private.h25
-rw-r--r--libutils/Android.bp32
-rw-r--r--libutils/Errors_test.cpp172
-rw-r--r--libutils/Looper.cpp191
-rw-r--r--libutils/Looper_test.cpp122
-rw-r--r--libutils/LruCache_test.cpp6
-rw-r--r--libutils/NativeHandle.cpp2
-rw-r--r--libutils/RefBase.cpp27
-rw-r--r--libutils/String16.cpp13
-rw-r--r--libutils/String16_test.cpp31
-rw-r--r--libutils/String8.cpp23
-rw-r--r--libutils/String8_fuzz.cpp4
-rw-r--r--libutils/TEST_MAPPING7
-rw-r--r--libutils/Threads.cpp24
-rw-r--r--libutils/Timers.cpp26
-rw-r--r--libutils/Timers_test.cpp9
-rw-r--r--libutils/Unicode_test.cpp5
-rw-r--r--libutils/VectorImpl.cpp14
-rw-r--r--libutils/Vector_test.cpp9
-rw-r--r--libutils/include/utils/Compat.h20
-rw-r--r--libutils/include/utils/Errors.h16
-rw-r--r--libutils/include/utils/ErrorsMacros.h186
-rw-r--r--libutils/include/utils/Looper.h39
-rw-r--r--libutils/include/utils/NativeHandle.h2
-rw-r--r--libutils/include/utils/String16.h6
-rw-r--r--libutils/include/utils/String8.h8
-rw-r--r--libvndksupport/TEST_MAPPING7
-rw-r--r--libvndksupport/linker.cpp2
-rw-r--r--libvndksupport/tests/Android.bp2
-rw-r--r--llkd/libllkd.cpp3
-rw-r--r--llkd/llkd-debuggable.rc4
-rw-r--r--llkd/llkd.rc2
-rw-r--r--llkd/tests/llkd_test.cpp10
-rw-r--r--mini_keyctl/Android.bp1
-rw-r--r--mini_keyctl/OWNERS5
-rw-r--r--property_service/TEST_MAPPING12
-rw-r--r--property_service/libpropertyinfoparser/Android.bp8
-rw-r--r--property_service/libpropertyinfoserializer/property_info_serializer_test.cpp1
-rw-r--r--rootdir/Android.bp9
-rw-r--r--rootdir/Android.mk34
-rw-r--r--rootdir/avb/Android.bp31
-rw-r--r--rootdir/avb/Android.mk52
-rw-r--r--rootdir/avb/q-gsi.avbpubkeybin0 -> 1032 bytes
-rw-r--r--rootdir/avb/qcar-gsi.avbpubkeybin0 -> 1032 bytes
-rw-r--r--rootdir/avb/r-gsi.avbpubkeybin0 -> 1032 bytes
-rw-r--r--rootdir/avb/s-gsi.avbpubkeybin0 -> 1032 bytes
-rw-r--r--rootdir/etc/TEST_MAPPING5
-rw-r--r--rootdir/etc/linker.config.json9
-rw-r--r--rootdir/init.no_zygote.rc2
-rw-r--r--rootdir/init.rc179
-rw-r--r--rootdir/init.zygote32.rc3
-rw-r--r--rootdir/init.zygote64.rc3
-rw-r--r--rootdir/init.zygote64_32.rc1
-rw-r--r--rootdir/ueventd.rc5
l---------rustfmt.toml1
-rw-r--r--set-verity-state/set-verity-state.cpp19
-rw-r--r--shell_and_utilities/Android.bp3
-rw-r--r--shell_and_utilities/README.md355
-rw-r--r--storaged/Android.bp16
-rw-r--r--storaged/include/storaged.h31
-rw-r--r--storaged/include/storaged_diskstats.h17
-rw-r--r--storaged/include/storaged_info.h14
-rw-r--r--storaged/storaged.cpp124
-rw-r--r--storaged/storaged.rc2
-rw-r--r--storaged/storaged_diskstats.cpp44
-rw-r--r--storaged/storaged_info.cpp34
-rw-r--r--storaged/tests/storaged_test.cpp39
-rwxr-xr-xtoolbox/generate-input.h-labels.py4
-rw-r--r--trusty/Android.bp26
-rw-r--r--trusty/apploader/apploader.cpp8
-rw-r--r--trusty/apploader/apploader_ipc.h3
-rw-r--r--trusty/apploader/fuzz/Android.bp8
-rw-r--r--trusty/confirmationui/fuzz/Android.bp6
-rw-r--r--trusty/confirmationui/fuzz/msg_fuzzer.cpp2
-rw-r--r--trusty/fuzz/counters.cpp2
-rw-r--r--trusty/gatekeeper/fuzz/Android.bp3
-rw-r--r--trusty/keymaster/3.0/TrustyKeymaster3Device.cpp3
-rw-r--r--trusty/keymaster/4.0/TrustyKeymaster4Device.cpp3
-rw-r--r--trusty/keymaster/Android.bp11
-rw-r--r--trusty/keymaster/TrustyKeymaster.cpp6
-rw-r--r--trusty/keymaster/fuzz/Android.bp3
-rw-r--r--trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h10
-rw-r--r--trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h1
-rw-r--r--trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h1
-rw-r--r--trusty/keymaster/ipc/trusty_keymaster_ipc.cpp67
-rw-r--r--trusty/keymaster/keymint/TEST_MAPPING12
-rw-r--r--trusty/keymaster/keymint/TrustyKeyMintDevice.cpp28
-rw-r--r--trusty/keymaster/keymint/TrustyKeyMintOperation.cpp6
-rw-r--r--trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp3
-rw-r--r--trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml2
-rw-r--r--trusty/keymaster/keymint/service.cpp4
-rw-r--r--trusty/keymaster/set_attestation_key/set_attestation_key.cpp31
-rw-r--r--trusty/libtrusty-rs/Android.bp39
-rw-r--r--trusty/libtrusty-rs/src/lib.rs224
-rw-r--r--trusty/libtrusty-rs/src/sys.rs31
-rw-r--r--trusty/libtrusty-rs/tests/test.rs86
-rw-r--r--trusty/libtrusty/include/trusty/ipc.h23
-rw-r--r--trusty/libtrusty/tipc-test/tipc_test.c1518
-rw-r--r--trusty/storage/interface/include/trusty/interface/storage.h40
-rw-r--r--trusty/storage/proxy/Android.bp8
-rw-r--r--trusty/storage/proxy/checkpoint_handling.cpp92
-rw-r--r--trusty/storage/proxy/checkpoint_handling.h39
-rw-r--r--trusty/storage/proxy/proxy.c23
-rw-r--r--trusty/storage/proxy/storage.c109
-rw-r--r--trusty/test/driver/Android.bp32
-rw-r--r--trusty/test/driver/trusty_driver_test.py81
-rw-r--r--trusty/trusty-base.mk4
-rw-r--r--trusty/trusty-test.mk4
-rw-r--r--trusty/utils/acvp/acvp_ipc.h2
-rw-r--r--trusty/utils/rpmb_dev/Android.bp8
-rw-r--r--trusty/utils/rpmb_dev/rpmb_dev.c26
-rw-r--r--usbd/Android.bp1
445 files changed, 7764 insertions, 21762 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9b96f3691..dcf92be1e 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,10 +1,8 @@
[Builtin Hooks]
clang_format = true
-rustfmt = true
[Builtin Hooks Options]
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
-rustfmt = --config-path=rustfmt.toml
[Hook Scripts]
aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "."
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 000000000..da7fca1e7
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,66 @@
+{
+ "presubmit": [
+ {
+ "name": "adbd_test"
+ },
+ {
+ "name": "adb_crypto_test"
+ },
+ {
+ "name": "adb_pairing_auth_test"
+ },
+ {
+ "name": "adb_pairing_connection_test"
+ },
+ {
+ "name": "adb_tls_connection_test"
+ },
+ {
+ "name": "CtsFsMgrTestCases"
+ },
+ {
+ "name": "CtsInitTestCases"
+ },
+ {
+ "name": "debuggerd_test"
+ },
+ {
+ "name": "fs_mgr_vendor_overlay_test"
+ },
+ {
+ "name": "init_kill_services_test"
+ },
+ {
+ "name": "libpackagelistparser_test"
+ },
+ {
+ "name": "libcutils_test"
+ },
+ {
+ "name": "libmodprobe_tests"
+ },
+ {
+ "name": "libprocinfo_test"
+ },
+ {
+ "name": "libutils_test"
+ },
+ {
+ "name": "memunreachable_test"
+ },
+ {
+ "name": "memunreachable_unit_test"
+ },
+ {
+ "name": "memunreachable_binder_test"
+ },
+ {
+ "name": "propertyinfoserializer_tests"
+ }
+ ],
+ "imports": [
+ {
+ "path": "frameworks/base/tests/StagedInstallTest"
+ }
+ ]
+}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 2c878f024..d6ebb0d54 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -439,30 +439,6 @@ const std::map<std::string, int32_t> kBootReasonMap = {
{"reboot,forcedsilent", 191},
{"reboot,forcednonsilent", 192},
{"reboot,thermal,tj", 193},
- {"reboot,emergency", 194},
- {"reboot,factory", 195},
- {"reboot,fastboot", 196},
- {"reboot,gsa,hard", 197},
- {"reboot,gsa,soft", 198},
- {"reboot,master_dc,fault_n", 199},
- {"reboot,master_dc,reset", 200},
- {"reboot,ocp", 201},
- {"reboot,pin", 202},
- {"reboot,rom_recovery", 203},
- {"reboot,uvlo", 204},
- {"reboot,uvlo,pmic,if", 205},
- {"reboot,uvlo,pmic,main", 206},
- {"reboot,uvlo,pmic,sub", 207},
- {"reboot,warm", 208},
- {"watchdog,aoc", 209},
- {"watchdog,apc", 210},
- {"watchdog,apc,bl,debug,early", 211},
- {"watchdog,apc,bl,early", 212},
- {"watchdog,apc,early", 213},
- {"watchdog,apm", 214},
- {"watchdog,gsa,hard", 215},
- {"watchdog,gsa,soft", 216},
- {"watchdog,pmucal", 217},
};
// Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ad0231d8d..198e4defb 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -1,5 +1,29 @@
package {
- default_applicable_licenses: ["Android-Apache-2.0"],
+ default_applicable_licenses: ["system_core_debuggerd_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+ name: "system_core_debuggerd_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-BSD",
+ ],
+ // large-scale-change unable to identify any license_text files
}
cc_defaults {
@@ -8,12 +32,10 @@ cc_defaults {
"-Wall",
"-Wextra",
"-Werror",
- "-Wno-gcc-compat",
"-Wno-unused-argument",
"-Wno-unused-function",
"-Wno-nullability-completeness",
"-Os",
- "-fno-finite-loops",
],
local_include_dirs: ["include"],
@@ -24,10 +46,6 @@ cc_library_headers {
export_include_dirs: ["common/include"],
recovery_available: true,
vendor_ramdisk_available: true,
- apex_available: [
- "com.android.virt",
- "//apex_available:platform",
- ],
}
cc_library_shared {
@@ -48,10 +66,6 @@ cc_library_shared {
"libbase",
"libcutils",
],
- apex_available: [
- "com.android.virt",
- "//apex_available:platform",
- ],
export_header_lib_headers: ["libdebuggerd_common_headers"],
export_include_dirs: ["tombstoned/include"],
@@ -188,6 +202,7 @@ cc_library_static {
"libdebuggerd/backtrace.cpp",
"libdebuggerd/gwp_asan.cpp",
"libdebuggerd/open_files_list.cpp",
+ "libdebuggerd/scudo.cpp",
"libdebuggerd/tombstone.cpp",
"libdebuggerd/tombstone_proto.cpp",
"libdebuggerd/tombstone_proto_to_text.cpp",
@@ -200,6 +215,9 @@ cc_library_static {
include_dirs: [
// Needed for private/bionic_fdsan.h
"bionic/libc",
+
+ // Needed for scudo/interface.h
+ "external/scudo/standalone/include",
],
header_libs: [
"bionic_libc_platform_headers",
@@ -214,13 +232,11 @@ cc_library_static {
"libcutils",
"liblog",
],
- runtime_libs: [
- "libdexfile", // libdexfile_support dependency
- ],
whole_static_libs: [
"libasync_safe",
"gwp_asan_crash_handler",
+ "libscudo",
"libtombstone_proto",
"libprocinfo",
"libprotobuf-cpp-lite",
@@ -231,17 +247,11 @@ cc_library_static {
exclude_static_libs: [
"libdexfile_support",
],
- exclude_runtime_libs: [
- "libdexfile",
- ],
},
vendor_ramdisk: {
exclude_static_libs: [
"libdexfile_support",
],
- exclude_runtime_libs: [
- "libdexfile",
- ],
},
},
@@ -249,13 +259,6 @@ cc_library_static {
debuggable: {
cflags: ["-DROOT_POSSIBLE"],
},
-
- malloc_not_svelte: {
- cflags: ["-DUSE_SCUDO"],
- whole_static_libs: ["libscudo"],
- srcs: ["libdebuggerd/scudo.cpp"],
- header_libs: ["scudo_headers"],
- },
},
}
@@ -290,7 +293,7 @@ cc_test {
"libdebuggerd/test/elf_fake.cpp",
"libdebuggerd/test/log_fake.cpp",
"libdebuggerd/test/open_files_list_test.cpp",
- "libdebuggerd/test/utility_test.cpp",
+ "libdebuggerd/test/tombstone_test.cpp",
],
target: {
@@ -326,6 +329,10 @@ cc_test {
"gwp_asan_headers",
],
+ include_dirs: [
+ "external/scudo/standalone/include",
+ ],
+
local_include_dirs: [
"libdebuggerd",
],
@@ -398,9 +405,6 @@ cc_binary {
apex_available: [
"com.android.runtime",
],
-
- // Required for tests.
- required: ["crash_dump.policy"],
}
cc_binary {
diff --git a/debuggerd/OWNERS b/debuggerd/OWNERS
index 6f7e4a3c4..bfeedca0e 100644
--- a/debuggerd/OWNERS
+++ b/debuggerd/OWNERS
@@ -1 +1,2 @@
cferris@google.com
+jmgao@google.com
diff --git a/debuggerd/TEST_MAPPING b/debuggerd/TEST_MAPPING
deleted file mode 100644
index 394447bc3..000000000
--- a/debuggerd/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "presubmit": [
- {
- "name": "debuggerd_test"
- },
- {
- "name": "libtombstoned_client_rust_test"
- }
- ],
- "hwasan-presubmit": [
- {
- "name": "debuggerd_test"
- }
- ]
-}
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index b302918fb..530e0e88f 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -47,30 +47,19 @@ using namespace std::chrono_literals;
using android::base::ReadFileToString;
using android::base::SendFileDescriptors;
-using android::base::StringAppendV;
using android::base::unique_fd;
using android::base::WriteStringToFd;
-#define TAG "libdebuggerd_client: "
-
-// Log an error both to the log (via LOG(ERROR)) and to the given fd.
-static void log_error(int fd, int errno_value, const char* format, ...) __printflike(3, 4) {
- std::string message(TAG);
-
- va_list ap;
- va_start(ap, format);
- StringAppendV(&message, format, ap);
- va_end(ap);
-
- if (errno_value != 0) {
- message = message + ": " + strerror(errno_value);
- }
+static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) {
+ const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : BIONIC_SIGNAL_DEBUGGER;
+ sigval val;
+ val.sival_int = (dump_type == kDebuggerdNativeBacktrace) ? 1 : 0;
- if (fd != -1) {
- dprintf(fd, "%s\n", message.c_str());
+ if (sigqueue(pid, signal, val) != 0) {
+ PLOG(ERROR) << "libdebuggerd_client: failed to send signal to pid " << pid;
+ return false;
}
-
- LOG(ERROR) << message;
+ return true;
}
template <typename Duration>
@@ -85,11 +74,13 @@ static void populate_timeval(struct timeval* tv, const Duration& duration) {
* Returns the wchan data for each thread in the process,
* or empty string if unable to obtain any data.
*/
-static std::string get_wchan_data(int fd, pid_t pid) {
+static std::string get_wchan_data(pid_t pid) {
+ std::stringstream buffer;
std::vector<pid_t> tids;
+
if (!android::procinfo::GetProcessTids(pid, &tids)) {
- log_error(fd, 0, "failed to get process tids");
- return "";
+ LOG(WARNING) << "libdebuggerd_client: Failed to get process tids";
+ return buffer.str();
}
std::stringstream data;
@@ -97,13 +88,12 @@ static std::string get_wchan_data(int fd, pid_t pid) {
std::string path = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/wchan";
std::string wchan_str;
if (!ReadFileToString(path, &wchan_str, true)) {
- log_error(fd, errno, "failed to read \"%s\"", path.c_str());
+ PLOG(WARNING) << "libdebuggerd_client: Failed to read \"" << path << "\"";
continue;
}
data << "sysTid=" << std::left << std::setw(10) << tid << wchan_str << "\n";
}
- std::stringstream buffer;
if (std::string str = data.str(); !str.empty()) {
buffer << "\n----- Waiting Channels: pid " << pid << " at " << get_timestamp() << " -----\n"
<< "Cmd line: " << android::base::Join(get_command_line(pid), " ") << "\n";
@@ -111,9 +101,16 @@ static std::string get_wchan_data(int fd, pid_t pid) {
buffer << "----- end " << std::to_string(pid) << " -----\n";
buffer << "\n";
}
+
return buffer.str();
}
+static void dump_wchan_data(const std::string& data, int fd, pid_t pid) {
+ if (!WriteStringToFd(data, fd)) {
+ LOG(WARNING) << "libdebuggerd_client: Failed to dump wchan data for pid: " << pid;
+ }
+}
+
bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
unique_fd output_fd) {
pid_t pid = tid;
@@ -122,51 +119,51 @@ bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int
android::procinfo::ProcessInfo procinfo;
std::string error;
if (!android::procinfo::GetProcessInfo(tid, &procinfo, &error)) {
- log_error(output_fd, 0, "failed to get process info: %s", error.c_str());
+ LOG(ERROR) << "libdebugged_client: failed to get process info: " << error;
return false;
}
pid = procinfo.pid;
}
- LOG(INFO) << TAG "started dumping process " << pid;
-
- // Rather than try to deal with poll() all the way through the flow, we update
- // the socket timeout between each step (and only use poll() during the final
- // copy loop).
+ LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
+ unique_fd sockfd;
const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
- auto update_timeout = [timeout_ms, &output_fd](int sockfd, auto end) {
- if (timeout_ms <= 0) return true;
+ auto time_left = [&end]() { return end - std::chrono::steady_clock::now(); };
+ auto set_timeout = [timeout_ms, &time_left](int sockfd) {
+ if (timeout_ms <= 0) {
+ return sockfd;
+ }
- auto remaining = end - std::chrono::steady_clock::now();
+ auto remaining = time_left();
if (remaining < decltype(remaining)::zero()) {
- log_error(output_fd, 0, "timeout expired");
- return false;
+ LOG(ERROR) << "libdebuggerd_client: timeout expired";
+ return -1;
}
struct timeval timeout;
populate_timeval(&timeout, remaining);
+
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) {
- log_error(output_fd, errno, "failed to set receive timeout");
- return false;
+ PLOG(ERROR) << "libdebuggerd_client: failed to set receive timeout";
+ return -1;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0) {
- log_error(output_fd, errno, "failed to set send timeout");
- return false;
+ PLOG(ERROR) << "libdebuggerd_client: failed to set send timeout";
+ return -1;
}
- return true;
+
+ return sockfd;
};
- unique_fd sockfd(socket(AF_LOCAL, SOCK_SEQPACKET, 0));
+ sockfd.reset(socket(AF_LOCAL, SOCK_SEQPACKET, 0));
if (sockfd == -1) {
- log_error(output_fd, errno, "failed to create socket");
+ PLOG(ERROR) << "libdebugger_client: failed to create socket";
return false;
}
- if (!update_timeout(sockfd, end)) return false;
-
- if (socket_local_client_connect(sockfd.get(), kTombstonedInterceptSocketName,
+ if (socket_local_client_connect(set_timeout(sockfd.get()), kTombstonedInterceptSocketName,
ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET) == -1) {
- log_error(output_fd, errno, "failed to connect to tombstoned");
+ PLOG(ERROR) << "libdebuggerd_client: failed to connect to tombstoned";
return false;
}
@@ -174,11 +171,15 @@ bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int
.dump_type = dump_type,
.pid = pid,
};
+ if (!set_timeout(sockfd)) {
+ PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+ return false;
+ }
// Create an intermediate pipe to pass to the other end.
unique_fd pipe_read, pipe_write;
if (!Pipe(&pipe_read, &pipe_write)) {
- log_error(output_fd, errno, "failed to create pipe");
+ PLOG(ERROR) << "libdebuggerd_client: failed to create pipe";
return false;
}
@@ -193,69 +194,71 @@ bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int
}
if (fcntl(pipe_read.get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
- log_error(output_fd, errno, "failed to set pipe buffer size");
+ PLOG(ERROR) << "failed to set pipe buffer size";
}
- if (!update_timeout(sockfd, end)) return false;
- ssize_t rc = SendFileDescriptors(sockfd, &req, sizeof(req), pipe_write.get());
+ ssize_t rc = SendFileDescriptors(set_timeout(sockfd), &req, sizeof(req), pipe_write.get());
pipe_write.reset();
if (rc != sizeof(req)) {
- log_error(output_fd, errno, "failed to send output fd to tombstoned");
+ PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
return false;
}
- auto get_response = [&output_fd](const char* kind, int sockfd, InterceptResponse* response) {
- ssize_t rc = TEMP_FAILURE_RETRY(recv(sockfd, response, sizeof(*response), MSG_TRUNC));
- if (rc == 0) {
- log_error(output_fd, 0, "failed to read %s response from tombstoned: timeout reached?", kind);
- return false;
- } else if (rc == -1) {
- log_error(output_fd, errno, "failed to read %s response from tombstoned", kind);
- return false;
- } else if (rc != sizeof(*response)) {
- log_error(output_fd, 0,
- "received packet of unexpected length from tombstoned while reading %s response: "
- "expected %zd, received %zd",
- kind, sizeof(response), rc);
- return false;
- }
- return true;
- };
-
// Check to make sure we've successfully registered.
InterceptResponse response;
- if (!update_timeout(sockfd, end)) return false;
- if (!get_response("initial", sockfd, &response)) return false;
+ rc = TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
+ if (rc == 0) {
+ LOG(ERROR) << "libdebuggerd_client: failed to read initial response from tombstoned: "
+ << "timeout reached?";
+ return false;
+ } else if (rc == -1) {
+ PLOG(ERROR) << "libdebuggerd_client: failed to read initial response from tombstoned";
+ return false;
+ } else if (rc != sizeof(response)) {
+ LOG(ERROR) << "libdebuggerd_client: received packet of unexpected length from tombstoned while "
+ "reading initial response: expected "
+ << sizeof(response) << ", received " << rc;
+ return false;
+ }
+
if (response.status != InterceptStatus::kRegistered) {
- log_error(output_fd, 0, "unexpected registration response: %d",
- static_cast<int>(response.status));
+ LOG(ERROR) << "libdebuggerd_client: unexpected registration response: "
+ << static_cast<int>(response.status);
return false;
}
- // Send the signal.
- const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : BIONIC_SIGNAL_DEBUGGER;
- sigval val = {.sival_int = (dump_type == kDebuggerdNativeBacktrace) ? 1 : 0};
- if (sigqueue(pid, signal, val) != 0) {
- log_error(output_fd, errno, "failed to send signal to pid %d", pid);
+ if (!send_signal(tid, dump_type)) {
+ return false;
+ }
+
+ rc = TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
+ if (rc == 0) {
+ LOG(ERROR) << "libdebuggerd_client: failed to read status response from tombstoned: "
+ "timeout reached?";
+ return false;
+ } else if (rc == -1) {
+ PLOG(ERROR) << "libdebuggerd_client: failed to read status response from tombstoned";
+ return false;
+ } else if (rc != sizeof(response)) {
+ LOG(ERROR) << "libdebuggerd_client: received packet of unexpected length from tombstoned while "
+ "reading confirmation response: expected "
+ << sizeof(response) << ", received " << rc;
return false;
}
- if (!update_timeout(sockfd, end)) return false;
- if (!get_response("status", sockfd, &response)) return false;
if (response.status != InterceptStatus::kStarted) {
response.error_message[sizeof(response.error_message) - 1] = '\0';
- log_error(output_fd, 0, "tombstoned reported failure: %s", response.error_message);
+ LOG(ERROR) << "libdebuggerd_client: tombstoned reported failure: " << response.error_message;
return false;
}
// Forward output from the pipe to the output fd.
while (true) {
- auto remaining = end - std::chrono::steady_clock::now();
- auto remaining_ms = std::chrono::duration_cast<std::chrono::milliseconds>(remaining).count();
+ auto remaining_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_left()).count();
if (timeout_ms <= 0) {
remaining_ms = -1;
} else if (remaining_ms < 0) {
- log_error(output_fd, 0, "timeout expired");
+ LOG(ERROR) << "libdebuggerd_client: timeout expired";
return false;
}
@@ -268,11 +271,11 @@ bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int
if (errno == EINTR) {
continue;
} else {
- log_error(output_fd, errno, "error while polling");
+ PLOG(ERROR) << "libdebuggerd_client: error while polling";
return false;
}
} else if (rc == 0) {
- log_error(output_fd, 0, "timeout expired");
+ LOG(ERROR) << "libdebuggerd_client: timeout expired";
return false;
}
@@ -282,17 +285,17 @@ bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int
// Done.
break;
} else if (rc == -1) {
- log_error(output_fd, errno, "error while reading");
+ PLOG(ERROR) << "libdebuggerd_client: error while reading";
return false;
}
if (!android::base::WriteFully(output_fd.get(), buf, rc)) {
- log_error(output_fd, errno, "error while writing");
+ PLOG(ERROR) << "libdebuggerd_client: error while writing";
return false;
}
}
- LOG(INFO) << TAG "done dumping process " << pid;
+ LOG(INFO) << "libdebuggerd_client: done dumping process " << pid;
return true;
}
@@ -310,16 +313,14 @@ int dump_backtrace_to_file_timeout(pid_t tid, DebuggerdDumpType dump_type, int t
// debuggerd_trigger_dump results in every thread in the process being interrupted
// by a signal, so we need to fetch the wchan data before calling that.
- std::string wchan_data = get_wchan_data(fd, tid);
+ std::string wchan_data = get_wchan_data(tid);
int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0;
int ret = debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1;
// Dump wchan data, since only privileged processes (CAP_SYS_ADMIN) can read
// kernel stack traces (/proc/*/stack).
- if (!WriteStringToFd(wchan_data, fd)) {
- LOG(WARNING) << TAG "Failed to dump wchan data for pid: " << tid;
- }
+ dump_wchan_data(wchan_data, fd, tid);
return ret;
}
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 967b9422c..a15274019 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -32,7 +32,6 @@
#include <set>
#include <vector>
-#include <android-base/errno_restorer.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -68,9 +67,8 @@
#include "protocol.h"
#include "util.h"
-using android::base::ErrnoRestorer;
-using android::base::StringPrintf;
using android::base::unique_fd;
+using android::base::StringPrintf;
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
struct stat st;
@@ -91,11 +89,10 @@ static pid_t get_tracer(pid_t tracee) {
static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error, int flags = 0) {
if (ptrace(PTRACE_SEIZE, tid, 0, flags) != 0) {
if (errno == EPERM) {
- ErrnoRestorer errno_restorer; // In case get_tracer() fails and we fall through.
- pid_t tracer_pid = get_tracer(tid);
- if (tracer_pid > 0) {
+ pid_t tracer = get_tracer(tid);
+ if (tracer != -1) {
*error = StringPrintf("failed to attach to thread %d, already traced by %d (%s)", tid,
- tracer_pid, get_process_name(tracer_pid).c_str());
+ tracer, get_process_name(tracer).c_str());
return false;
}
}
@@ -502,24 +499,15 @@ int main(int argc, char** argv) {
continue;
}
- struct iovec tagged_addr_iov = {
+ struct iovec iov = {
&info.tagged_addr_ctrl,
sizeof(info.tagged_addr_ctrl),
};
if (ptrace(PTRACE_GETREGSET, thread, NT_ARM_TAGGED_ADDR_CTRL,
- reinterpret_cast<void*>(&tagged_addr_iov)) == -1) {
+ reinterpret_cast<void*>(&iov)) == -1) {
info.tagged_addr_ctrl = -1;
}
- struct iovec pac_enabled_keys_iov = {
- &info.pac_enabled_keys,
- sizeof(info.pac_enabled_keys),
- };
- if (ptrace(PTRACE_GETREGSET, thread, NT_ARM_PAC_ENABLED_KEYS,
- reinterpret_cast<void*>(&pac_enabled_keys_iov)) == -1) {
- info.pac_enabled_keys = -1;
- }
-
if (thread == g_target_thread) {
// Read the thread's registers along with the rest of the crash info out of the pipe.
ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info);
diff --git a/debuggerd/crash_test.cpp b/debuggerd/crash_test.cpp
index ce0f91fd1..c15145f61 100644
--- a/debuggerd/crash_test.cpp
+++ b/debuggerd/crash_test.cpp
@@ -16,13 +16,6 @@
#include <stdint.h>
-#include "crash_test.h"
-
-extern "C" {
-
-JITDescriptor __dex_debug_descriptor = {.version = 1};
-
-void crash() {
+extern "C" void crash() {
*reinterpret_cast<volatile char*>(0xdead) = '1';
}
-}
diff --git a/debuggerd/crash_test.h b/debuggerd/crash_test.h
deleted file mode 100644
index 2a8bea33d..000000000
--- a/debuggerd/crash_test.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdint.h>
-
-// Only support V1 of these structures.
-// See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
-// for information on the JIT Compilation Interface.
-// Also, see libunwindstack/GlobalDebugImpl.h for the full definition of
-// these structures.
-struct JITCodeEntry {
- uintptr_t next;
- uintptr_t prev;
- uintptr_t symfile_addr;
- uint64_t symfile_size;
-};
-
-struct JITDescriptor {
- uint32_t version;
- uint32_t action_flag;
- uintptr_t relevant_entry;
- uintptr_t first_entry;
-};
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index 799163e31..23b106ea4 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -45,8 +45,6 @@ cc_binary {
shared_libs: [
"libbase",
"liblog",
- ],
- static_libs: [
"libseccomp_policy",
],
multilib: {
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 55490b5d0..db30b8f07 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -39,8 +39,6 @@
#include "debuggerd/handler.h"
#endif
-extern "C" void android_set_abort_message(const char* msg);
-
#if defined(__arm__)
// See https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt for details.
#define __kuser_helper_version (*(int32_t*) 0xffff0ffc)
@@ -184,8 +182,6 @@ static int usage() {
fprintf(stderr, " leak leak memory until we get OOM-killed\n");
fprintf(stderr, "\n");
fprintf(stderr, " abort call abort()\n");
- fprintf(stderr, " abort_with_msg call abort() setting an abort message\n");
- fprintf(stderr, " abort_with_null_msg call abort() setting a null abort message\n");
fprintf(stderr, " assert call assert() without a function\n");
fprintf(stderr, " assert2 call assert() with a function\n");
fprintf(stderr, " exit call exit(1)\n");
@@ -263,12 +259,6 @@ noinline int do_action(const char* arg) {
return crash(42);
} else if (!strcasecmp(arg, "abort")) {
maybe_abort();
- } else if (!strcasecmp(arg, "abort_with_msg")) {
- android_set_abort_message("Aborting due to crasher");
- maybe_abort();
- } else if (!strcasecmp(arg, "abort_with_null")) {
- android_set_abort_message(nullptr);
- maybe_abort();
} else if (!strcasecmp(arg, "assert")) {
__assert("some_file.c", 123, "false");
} else if (!strcasecmp(arg, "assert2")) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index e20e8d9e1..360ea95b3 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -93,18 +93,8 @@ int main(int argc, char* argv[]) {
errx(1, "process %d is a zombie", pid);
}
- // Send a signal to the main thread pid, not a side thread. The signal
- // handler always sets the crashing tid to the main thread pid when sent this
- // signal. This is to avoid a problem where the signal is sent to a process,
- // but happens on a side thread and the intercept mismatches since it
- // is looking for the main thread pid, not the tid of this random thread.
- // See b/194346289 for extra details.
- if (kill(proc_info.pid, 0) != 0) {
- if (pid == proc_info.pid) {
- err(1, "cannot send signal to process %d", pid);
- } else {
- err(1, "cannot send signal to main thread %d (requested thread %d)", proc_info.pid, pid);
- }
+ if (kill(pid, 0) != 0) {
+ err(1, "cannot send signal to process %d", pid);
}
unique_fd piperead, pipewrite;
@@ -113,13 +103,9 @@ int main(int argc, char* argv[]) {
}
std::thread redirect_thread = spawn_redirect_thread(std::move(piperead));
- if (!debuggerd_trigger_dump(proc_info.pid, dump_type, 0, std::move(pipewrite))) {
+ if (!debuggerd_trigger_dump(pid, dump_type, 0, std::move(pipewrite))) {
redirect_thread.join();
- if (pid == proc_info.pid) {
- errx(1, "failed to dump process %d", pid);
- } else {
- errx(1, "failed to dump main thread %d (requested thread %d)", proc_info.pid, pid);
- }
+ errx(1, "failed to dump process %d", pid);
}
redirect_thread.join();
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index e11330819..abda0713a 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -18,7 +18,6 @@
#include <dlfcn.h>
#include <err.h>
#include <fcntl.h>
-#include <linux/prctl.h>
#include <malloc.h>
#include <stdlib.h>
#include <sys/capability.h>
@@ -32,7 +31,6 @@
#include <chrono>
#include <regex>
-#include <set>
#include <string>
#include <thread>
@@ -56,13 +54,9 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/Memory.h>
-
#include <libminijail.h>
#include <scoped_minijail.h>
-#include "crash_test.h"
#include "debuggerd/handler.h"
#include "libdebuggerd/utility.h"
#include "protocol.h"
@@ -88,7 +82,7 @@ constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
struct sigaction old_sigaction; \
struct sigaction new_sigaction = {}; \
new_sigaction.sa_handler = [](int) {}; \
- if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
+ if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
err(1, "sigaction failed"); \
} \
alarm(seconds); \
@@ -113,14 +107,8 @@ constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
// process sampling, so we need to ensure we force GWP-ASan on.
__attribute__((constructor)) static void enable_gwp_asan() {
- android_mallopt_gwp_asan_options_t opts;
- // No, we're not an app, but let's turn ourselves on without sampling.
- // Technically, if someone's using the *.default_app sysprops, they'll adjust
- // our settings, but I don't think this will be common on a device that's
- // running debuggerd_tests.
- opts.desire = android_mallopt_gwp_asan_options_t::Action::TURN_ON_FOR_APP;
- opts.program_name = "";
- android_mallopt(M_INITIALIZE_GWP_ASAN, &opts, sizeof(android_mallopt_gwp_asan_options_t));
+ bool force = true;
+ android_mallopt(M_INITIALIZE_GWP_ASAN, &force, sizeof(force));
}
static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
@@ -179,14 +167,6 @@ static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, uniq
*status = response.status;
}
-static bool pac_supported() {
-#if defined(__aarch64__)
- return getauxval(AT_HWCAP) & HWCAP_PACA;
-#else
- return false;
-#endif
-}
-
class CrasherTest : public ::testing::Test {
public:
pid_t crasher_pid = -1;
@@ -359,23 +339,11 @@ TEST_F(CrasherTest, smoke) {
std::string result;
ConsumeFd(std::move(output_fd), &result);
-#ifdef __LP64__
- ASSERT_MATCH(result,
- R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
-#else
- ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
-#endif
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
if (mte_supported()) {
// Test that the default TAGGED_ADDR_CTRL value is set.
- ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
- R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
- }
-
- if (pac_supported()) {
- // Test that the default PAC_ENABLED_KEYS value is set.
- ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
- R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
+ ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)");
}
}
@@ -383,8 +351,6 @@ TEST_F(CrasherTest, tagged_fault_addr) {
#if !defined(__aarch64__)
GTEST_SKIP() << "Requires aarch64";
#endif
- // HWASan crashes with SIGABRT on tag mismatch.
- SKIP_WITH_HWASAN;
int intercept_result;
unique_fd output_fd;
StartProcess([]() {
@@ -403,7 +369,8 @@ TEST_F(CrasherTest, tagged_fault_addr) {
// The address can either be tagged (new kernels) or untagged (old kernels).
ASSERT_MATCH(
- result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
+ result,
+ R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
}
// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
@@ -416,10 +383,6 @@ TEST_F(CrasherTest, heap_addr_in_register) {
#if defined(__i386__)
GTEST_SKIP() << "architecture does not pass arguments in registers";
#endif
- // The memory dump in HWASan crashes sadly shows the memory near the registers
- // in the HWASan dump function, rather the faulting context. This is a known
- // issue.
- SKIP_WITH_HWASAN;
int intercept_result;
unique_fd output_fd;
StartProcess([]() {
@@ -458,12 +421,6 @@ static void SetTagCheckingLevelSync() {
abort();
}
}
-
-static void SetTagCheckingLevelAsync() {
- if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
- abort();
- }
-}
#endif
// Number of iterations required to reliably guarantee a GWP-ASan crash.
@@ -498,8 +455,6 @@ TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
// instead of GWP-ASan.
GTEST_SKIP() << "Skipped on MTE.";
}
- // Skip this test on HWASan, which will reliably catch test errors as well.
- SKIP_WITH_HWASAN;
GwpAsanTestParameters params = GetParam();
LogcatCollector logcat_collector;
@@ -697,36 +652,6 @@ TEST_P(SizeParamCrasherTest, mte_underflow) {
#endif
}
-TEST_F(CrasherTest, mte_async) {
-#if defined(__aarch64__)
- if (!mte_supported()) {
- GTEST_SKIP() << "Requires MTE";
- }
-
- int intercept_result;
- unique_fd output_fd;
- StartProcess([&]() {
- SetTagCheckingLevelAsync();
- volatile int* p = (volatile int*)malloc(16);
- p[-1] = 42;
- });
-
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGSEGV);
- FinishIntercept(&intercept_result);
-
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
-#else
- GTEST_SKIP() << "Requires aarch64";
-#endif
-}
-
TEST_F(CrasherTest, mte_multiple_causes) {
#if defined(__aarch64__)
if (!mte_supported()) {
@@ -777,7 +702,7 @@ TEST_F(CrasherTest, mte_multiple_causes) {
for (const auto& result : log_sources) {
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
- "listing them in decreasing order of likelihood."));
+ "listing them in decreasing order of probability."));
// Adjacent untracked allocations may cause us to see the wrong underflow here (or only
// overflows), so we can't match explicitly for an underflow message.
ASSERT_MATCH(result,
@@ -964,7 +889,7 @@ TEST_F(CrasherTest, LD_PRELOAD) {
std::string result;
ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
}
TEST_F(CrasherTest, abort) {
@@ -1036,44 +961,6 @@ TEST_F(CrasherTest, abort_message) {
ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
}
-TEST_F(CrasherTest, abort_message_newline_trimmed) {
- int intercept_result;
- unique_fd output_fd;
- StartProcess([]() {
- android_set_abort_message("Message with a newline.\n");
- abort();
- });
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGABRT);
- FinishIntercept(&intercept_result);
-
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
-}
-
-TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
- int intercept_result;
- unique_fd output_fd;
- StartProcess([]() {
- android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
- abort();
- });
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGABRT);
- FinishIntercept(&intercept_result);
-
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
-}
-
TEST_F(CrasherTest, abort_message_backtrace) {
int intercept_result;
unique_fd output_fd;
@@ -1423,16 +1310,6 @@ __attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpTyp
return true;
}
-extern "C" void foo() {
- LOG(INFO) << "foo";
- std::this_thread::sleep_for(1s);
-}
-
-extern "C" void bar() {
- LOG(INFO) << "bar";
- std::this_thread::sleep_for(1s);
-}
-
TEST_F(CrasherTest, seccomp_tombstone) {
int intercept_result;
unique_fd output_fd;
@@ -1440,11 +1317,6 @@ TEST_F(CrasherTest, seccomp_tombstone) {
static const auto dump_type = kDebuggerdTombstone;
StartProcess(
[]() {
- std::thread a(foo);
- std::thread b(bar);
-
- std::this_thread::sleep_for(100ms);
-
raise_debugger_signal(dump_type);
_exit(0);
},
@@ -1459,31 +1331,16 @@ TEST_F(CrasherTest, seccomp_tombstone) {
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
- ASSERT_BACKTRACE_FRAME(result, "foo");
- ASSERT_BACKTRACE_FRAME(result, "bar");
}
-TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
- int intercept_result;
- unique_fd output_fd;
-
- static const auto dump_type = kDebuggerdTombstone;
- StartProcess(
- []() {
- std::thread abort_thread([] { abort(); });
- abort_thread.join();
- },
- &seccomp_fork);
-
- StartIntercept(&output_fd, dump_type);
- FinishCrasher();
- AssertDeath(SIGABRT);
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+extern "C" void foo() {
+ LOG(INFO) << "foo";
+ std::this_thread::sleep_for(1s);
+}
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
- ASSERT_BACKTRACE_FRAME(result, "abort");
+extern "C" void bar() {
+ LOG(INFO) << "bar";
+ std::this_thread::sleep_for(1s);
}
TEST_F(CrasherTest, seccomp_backtrace) {
@@ -1862,9 +1719,9 @@ static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
TEST_F(CrasherTest, unreadable_elf) {
int intercept_result;
unique_fd output_fd;
- std::string tmp_so_name;
- StartProcess([&tmp_so_name]() {
+ StartProcess([]() {
TemporaryDir td;
+ std::string tmp_so_name;
if (!CopySharedLibrary(td.path, &tmp_so_name)) {
_exit(1);
}
@@ -1894,8 +1751,6 @@ TEST_F(CrasherTest, unreadable_elf) {
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
- std::string match_str = "NOTE: " + tmp_so_name;
- ASSERT_MATCH(result, match_str);
}
TEST(tombstoned, proto) {
@@ -1970,534 +1825,3 @@ TEST(tombstoned, proto_intercept) {
ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
ASSERT_EQ("foo", output);
}
-
-// Verify that when an intercept is present for the main thread, and the signal
-// is received on a different thread, the intercept still works.
-TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
- StartProcess([]() {
- std::thread thread([]() {
- // Raise the signal on the side thread.
- raise_debugger_signal(kDebuggerdNativeBacktrace);
- });
- thread.join();
- _exit(0);
- });
-
- unique_fd output_fd;
- StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
- FinishCrasher();
- AssertDeath(0);
-
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
- ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
-}
-
-static std::string format_pointer(uintptr_t ptr) {
-#if defined(__LP64__)
- return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
- static_cast<uint32_t>(ptr & 0xffffffff));
-#else
- return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
-#endif
-}
-
-static std::string format_pointer(void* ptr) {
- return format_pointer(reinterpret_cast<uintptr_t>(ptr));
-}
-
-static std::string format_full_pointer(uintptr_t ptr) {
-#if defined(__LP64__)
- return android::base::StringPrintf("%016" PRIx64, ptr);
-#else
- return android::base::StringPrintf("%08x", ptr);
-#endif
-}
-
-static std::string format_full_pointer(void* ptr) {
- return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
-}
-
-__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
- int* crash_ptr = reinterpret_cast<int*>(ptr);
- *crash_ptr = 1;
- return *crash_ptr;
-}
-
-// Verify that a fault address before the first map is properly handled.
-TEST_F(CrasherTest, fault_address_before_first_map) {
- StartProcess([]() {
- ASSERT_EQ(0, crash_call(0x1024));
- _exit(0);
- });
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGSEGV);
-
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
-
- ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
-
- std::string match_str = android::base::StringPrintf(
- R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
- format_pointer(0x1024).c_str());
- ASSERT_MATCH(result, match_str);
-}
-
-// Verify that a fault address after the last map is properly handled.
-TEST_F(CrasherTest, fault_address_after_last_map) {
- // This makes assumptions about the memory layout that are not true in HWASan
- // processes.
- SKIP_WITH_HWASAN;
- uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
- StartProcess([crash_uptr]() {
- ASSERT_EQ(0, crash_call(crash_uptr));
- _exit(0);
- });
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGSEGV);
-
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
- match_str += format_full_pointer(crash_uptr);
- ASSERT_MATCH(result, match_str);
-
- ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
-
- // Assumes that the open files section comes after the map section.
- // If that assumption changes, the regex below needs to change.
- match_str = android::base::StringPrintf(
- R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
- format_pointer(crash_uptr).c_str());
- ASSERT_MATCH(result, match_str);
-}
-
-// Verify that a fault address between maps is properly handled.
-TEST_F(CrasherTest, fault_address_between_maps) {
- // Create a map before the fork so it will be present in the child.
- void* start_ptr =
- mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, start_ptr);
- // Unmap the page in the middle.
- void* middle_ptr =
- reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
- ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
-
- StartProcess([middle_ptr]() {
- ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
- _exit(0);
- });
-
- // Unmap the two maps.
- ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
- void* end_ptr =
- reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
- ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGSEGV);
-
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
- match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
- ASSERT_MATCH(result, match_str);
-
- ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
-
- match_str = android::base::StringPrintf(
- R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
- format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
- format_pointer(end_ptr).c_str());
- ASSERT_MATCH(result, match_str);
-}
-
-// Verify that a fault address happens in the correct map.
-TEST_F(CrasherTest, fault_address_in_map) {
- // Create a map before the fork so it will be present in the child.
- void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, ptr);
-
- StartProcess([ptr]() {
- ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
- _exit(0);
- });
-
- ASSERT_EQ(0, munmap(ptr, getpagesize()));
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGSEGV);
-
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
- match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
- ASSERT_MATCH(result, match_str);
-
- ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
-
- match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
- ASSERT_MATCH(result, match_str);
-}
-
-static constexpr uint32_t kDexData[] = {
- 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
- 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
- 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
- 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
- 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
- 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
- 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
- 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
- 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
- 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
- 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
- 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
- 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
- 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
- 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
- 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
- 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
-};
-
-TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
- StartProcess([]() {
- TemporaryDir td;
- std::string tmp_so_name;
- if (!CopySharedLibrary(td.path, &tmp_so_name)) {
- _exit(1);
- }
-
- // In order to cause libunwindstack to look for this __dex_debug_descriptor
- // move the library to which has a basename of libart.so.
- std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
- ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
- void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
- if (handle == nullptr) {
- _exit(1);
- }
-
- void* ptr =
- mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_TRUE(ptr != MAP_FAILED);
- memcpy(ptr, kDexData, sizeof(kDexData));
- prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
-
- JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
- .symfile_size = sizeof(kDexData)};
-
- JITDescriptor* dex_debug =
- reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
- ASSERT_TRUE(dex_debug != nullptr);
- dex_debug->version = 1;
- dex_debug->action_flag = 0;
- dex_debug->relevant_entry = 0;
- dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
-
- // This sets the magic dex pc value for register 0, using the value
- // of register 1 + 0x102.
- asm(".cfi_escape "
- "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
- "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
- "0x13 /* DW_OP_drop */,"
- "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
-
- // For each different architecture, set register one to the dex ptr mmap
- // created above. Then do a nullptr dereference to force a crash.
-#if defined(__arm__)
- asm volatile(
- "mov r1, %[base]\n"
- "mov r2, 0\n"
- "str r3, [r2]\n"
- : [base] "+r"(ptr)
- :
- : "r1", "r2", "r3", "memory");
-#elif defined(__aarch64__)
- asm volatile(
- "mov x1, %[base]\n"
- "mov x2, 0\n"
- "str x3, [x2]\n"
- : [base] "+r"(ptr)
- :
- : "x1", "x2", "x3", "memory");
-#elif defined(__i386__)
- asm volatile(
- "mov %[base], %%ecx\n"
- "movl $0, %%edi\n"
- "movl 0(%%edi), %%edx\n"
- : [base] "+r"(ptr)
- :
- : "edi", "ecx", "edx", "memory");
-#elif defined(__x86_64__)
- asm volatile(
- "mov %[base], %%rdx\n"
- "movq 0, %%rdi\n"
- "movq 0(%%rdi), %%rcx\n"
- : [base] "+r"(ptr)
- :
- : "rcx", "rdx", "rdi", "memory");
-#else
-#error "Unsupported architecture"
-#endif
- _exit(0);
- });
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGSEGV);
-
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- // Verify the process crashed properly.
- ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
-
- // Now verify that the dex_pc frame includes a proper function name.
- ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
-}
-
-static std::string format_map_pointer(uintptr_t ptr) {
-#if defined(__LP64__)
- return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
- static_cast<uint32_t>(ptr & 0xffffffff));
-#else
- return android::base::StringPrintf("%08x", ptr);
-#endif
-}
-
-// Verify that map data is properly formatted.
-TEST_F(CrasherTest, verify_map_format) {
- // Create multiple maps to make sure that the map data is formatted properly.
- void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, none_map);
- void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, r_map);
- void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, w_map);
- void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, x_map);
-
- TemporaryFile tf;
- ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
- char c = 'f';
- ASSERT_EQ(1, write(tf.fd, &c, 1));
- ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
- ASSERT_EQ(1, write(tf.fd, &c, 1));
- ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
- void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
- ASSERT_NE(MAP_FAILED, file_map);
-
- StartProcess([]() { abort(); });
-
- ASSERT_EQ(0, munmap(none_map, getpagesize()));
- ASSERT_EQ(0, munmap(r_map, getpagesize()));
- ASSERT_EQ(0, munmap(w_map, getpagesize()));
- ASSERT_EQ(0, munmap(x_map, getpagesize()));
- ASSERT_EQ(0, munmap(file_map, 0x3001));
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGABRT);
- int intercept_result;
- FinishIntercept(&intercept_result);
-
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- std::string match_str;
- // Verify none.
- match_str = android::base::StringPrintf(
- " %s-%s --- 0 1000\\n",
- format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
- ASSERT_MATCH(result, match_str);
-
- // Verify read-only.
- match_str = android::base::StringPrintf(
- " %s-%s r-- 0 1000\\n",
- format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
- ASSERT_MATCH(result, match_str);
-
- // Verify write-only.
- match_str = android::base::StringPrintf(
- " %s-%s -w- 0 1000\\n",
- format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
- ASSERT_MATCH(result, match_str);
-
- // Verify exec-only.
- match_str = android::base::StringPrintf(
- " %s-%s --x 0 1000\\n",
- format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
- ASSERT_MATCH(result, match_str);
-
- // Verify file map with non-zero offset and a name.
- match_str = android::base::StringPrintf(
- " %s-%s r-- 2000 4000 %s\\n",
- format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
- ASSERT_MATCH(result, match_str);
-}
-
-// Verify that the tombstone map data is correct.
-TEST_F(CrasherTest, verify_header) {
- StartProcess([]() { abort(); });
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGABRT);
- int intercept_result;
- FinishIntercept(&intercept_result);
-
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- std::string match_str = android::base::StringPrintf(
- "Build fingerprint: '%s'\\nRevision: '%s'\\n",
- android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
- android::base::GetProperty("ro.revision", "unknown").c_str());
- match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
- ASSERT_MATCH(result, match_str);
-}
-
-// Verify that the thread header is formatted properly.
-TEST_F(CrasherTest, verify_thread_header) {
- void* shared_map =
- mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- ASSERT_NE(MAP_FAILED, shared_map);
- memset(shared_map, 0, sizeof(pid_t));
-
- StartProcess([&shared_map]() {
- std::atomic_bool tid_written;
- std::thread thread([&tid_written, &shared_map]() {
- pid_t tid = gettid();
- memcpy(shared_map, &tid, sizeof(pid_t));
- tid_written = true;
- volatile bool done = false;
- while (!done)
- ;
- });
- thread.detach();
- while (!tid_written.load(std::memory_order_acquire))
- ;
- abort();
- });
-
- pid_t primary_pid = crasher_pid;
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGABRT);
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- // Read the tid data out.
- pid_t tid;
- memcpy(&tid, shared_map, sizeof(pid_t));
- ASSERT_NE(0, tid);
-
- ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- // Verify that there are two headers, one where the tid is "primary_pid"
- // and the other where the tid is "tid".
- std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
- primary_pid, primary_pid);
- ASSERT_MATCH(result, match_str);
-
- match_str =
- android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
- ASSERT_MATCH(result, match_str);
-}
-
-// Verify that there is a BuildID present in the map section and set properly.
-TEST_F(CrasherTest, verify_build_id) {
- StartProcess([]() { abort(); });
-
- unique_fd output_fd;
- StartIntercept(&output_fd);
- FinishCrasher();
- AssertDeath(SIGABRT);
- int intercept_result;
- FinishIntercept(&intercept_result);
- ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
-
- std::string result;
- ConsumeFd(std::move(output_fd), &result);
-
- // Find every /system or /apex lib and verify the BuildID is displayed
- // properly.
- bool found_valid_elf = false;
- std::smatch match;
- std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
- for (std::string prev_file; std::regex_search(result, match, build_id_regex);
- result = match.suffix()) {
- if (prev_file == match[1]) {
- // Already checked this file.
- continue;
- }
-
- prev_file = match[1];
- unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
- if (!elf.Init() || !elf.valid()) {
- // Skipping invalid elf files.
- continue;
- }
- ASSERT_EQ(match[3], elf.GetPrintableBuildID());
-
- found_valid_elf = true;
- }
- ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
-}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index c8b25ae2b..f61578068 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -1,17 +1,29 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
#include <dirent.h>
@@ -73,13 +85,14 @@ static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
thread.registers.reset(
unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
+ // TODO: Create this once and store it in a global?
+ unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
// Do not use the thread cache here because it will call pthread_key_create
// which doesn't work in linker code. See b/189803009.
// Use a normal cached object because the process is stopped, and there
// is no chance of data changing between reads.
auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
- // TODO: Create this once and store it in a global?
- unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid(), process_memory);
+ unwinder.SetProcessMemory(process_memory);
dump_backtrace_thread(output_fd, &unwinder, thread);
}
__linker_disable_fallback_allocator();
@@ -97,6 +110,32 @@ static void debuggerd_fallback_tombstone(int output_fd, int proto_fd, ucontext_t
__linker_disable_fallback_allocator();
}
+static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) {
+ pid_t current_tid = gettid();
+ char buf[BUFSIZ];
+ snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid);
+ DIR* dir = opendir(buf);
+
+ if (!dir) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
+ return;
+ }
+
+ struct dirent* ent;
+ while ((ent = readdir(dir))) {
+ char* end;
+ long tid = strtol(ent->d_name, &end, 10);
+ if (end == ent->d_name || *end != '\0') {
+ continue;
+ }
+
+ if (tid != current_tid) {
+ callback(tid, output_fd);
+ }
+ }
+ closedir(dir);
+}
+
static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) {
// Make sure the thread actually got the signal.
struct pollfd pfd = {
@@ -189,21 +228,21 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
}
// Only allow one thread to perform a trace at a time.
- static std::mutex trace_mutex;
- if (!trace_mutex.try_lock()) {
- async_safe_format_log(ANDROID_LOG_INFO, "libc", "trace lock failed");
+ static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
+ int ret = pthread_mutex_trylock(&trace_mutex);
+ if (ret != 0) {
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s",
+ strerror(ret));
return;
}
- std::lock_guard<std::mutex> scoped_lock(trace_mutex, std::adopt_lock);
-
// Fetch output fd from tombstoned.
unique_fd tombstone_socket, output_fd;
if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, nullptr,
kDebuggerdNativeBacktrace)) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc",
"missing crash_dump_fallback() in selinux policy?");
- return;
+ goto exit;
}
dump_backtrace_header(output_fd.get());
@@ -212,15 +251,15 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
debuggerd_fallback_trace(output_fd.get(), ucontext);
// Send a signal to all of our siblings, asking them to dump their stack.
- pid_t current_tid = gettid();
- if (!iterate_tids(current_tid, [&output_fd](pid_t tid) {
+ iterate_siblings(
+ [](pid_t tid, int output_fd) {
// Use a pipe, to be able to detect situations where the thread gracefully exits before
// receiving our signal.
unique_fd pipe_read, pipe_write;
if (!Pipe(&pipe_read, &pipe_write)) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s",
strerror(errno));
- return;
+ return false;
}
uint64_t expected = pack_thread_fd(-1, -1);
@@ -230,7 +269,7 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc",
"thread %d is already outputting to fd %d?", tid, fd);
close(sent_fd);
- return;
+ return false;
}
siginfo_t siginfo = {};
@@ -242,10 +281,10 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
tid, strerror(errno));
- return;
+ return false;
}
- bool success = forward_output(pipe_read.get(), output_fd.get(), tid);
+ bool success = forward_output(pipe_read.get(), output_fd, tid);
if (!success) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc",
"timeout expired while waiting for thread %d to dump", tid);
@@ -261,14 +300,15 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
}
}
- return;
- })) {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/%d/task: %s",
- current_tid, strerror(errno));
- }
+ return true;
+ },
+ output_fd.get());
dump_backtrace_footer(output_fd.get());
tombstoned_notify_completion(tombstone_socket.get());
+
+exit:
+ pthread_mutex_unlock(&trace_mutex);
}
static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
diff --git a/debuggerd/handler/debuggerd_fallback_nop.cpp b/debuggerd/handler/debuggerd_fallback_nop.cpp
index 5666d9899..331301f8f 100644
--- a/debuggerd/handler/debuggerd_fallback_nop.cpp
+++ b/debuggerd/handler/debuggerd_fallback_nop.cpp
@@ -1,17 +1,29 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
extern "C" void debuggerd_fallback_handler(struct siginfo_t*, struct ucontext_t*, void*) {
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 35be2bf31..b60739794 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -1,17 +1,29 @@
/*
- * Copyright 2008 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
#include "debuggerd/handler.h"
@@ -155,14 +167,18 @@ static bool get_main_thread_name(char* buf, size_t len) {
* could allocate memory or hold a lock.
*/
static void log_signal_summary(const siginfo_t* info) {
- char main_thread_name[MAX_TASK_NAME_LEN + 1];
- if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
- strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
+ char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
+ if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
+ strcpy(thread_name, "<name unknown>");
+ } else {
+ // short names are null terminated by prctl, but the man page
+ // implies that 16 byte names are not.
+ thread_name[MAX_TASK_NAME_LEN] = 0;
}
if (info->si_signo == BIONIC_SIGNAL_DEBUGGER) {
- async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for pid %d (%s)", __getpid(),
- main_thread_name);
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(),
+ thread_name);
return;
}
@@ -177,13 +193,9 @@ static void log_signal_summary(const siginfo_t* info) {
get_signal_sender(sender_desc, sizeof(sender_desc), info);
}
- char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
- if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
- strcpy(thread_name, "<name unknown>");
- } else {
- // short names are null terminated by prctl, but the man page
- // implies that 16 byte names are not.
- thread_name[MAX_TASK_NAME_LEN] = 0;
+ char main_thread_name[MAX_TASK_NAME_LEN + 1];
+ if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
+ strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
}
async_safe_format_log(ANDROID_LOG_FATAL, "libc",
@@ -532,13 +544,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
log_signal_summary(info);
- // If we got here due to the signal BIONIC_SIGNAL_DEBUGGER, it's possible
- // this is not the main thread, which can cause the intercept logic to fail
- // since the intercept is only looking for the main thread. In this case,
- // setting crashing_tid to pid instead of the current thread's tid avoids
- // the problem.
debugger_thread_info thread_info = {
- .crashing_tid = (signal_number == BIONIC_SIGNAL_DEBUGGER) ? __getpid() : __gettid(),
+ .crashing_tid = __gettid(),
.pseudothread_tid = -1,
.siginfo = info,
.ucontext = context,
diff --git a/debuggerd/libdebuggerd/gwp_asan.cpp b/debuggerd/libdebuggerd/gwp_asan.cpp
index 3d9662793..3ee309fc5 100644
--- a/debuggerd/libdebuggerd/gwp_asan.cpp
+++ b/debuggerd/libdebuggerd/gwp_asan.cpp
@@ -43,13 +43,10 @@ static bool retrieve_gwp_asan_state(unwindstack::Memory* process_memory, uintptr
static const gwp_asan::AllocationMetadata* retrieve_gwp_asan_metadata(
unwindstack::Memory* process_memory, const gwp_asan::AllocatorState& state,
uintptr_t metadata_addr) {
- // 1 million GWP-ASan slots would take 4.1GiB of space. Thankfully, copying
- // the metadata for that amount of slots is only 532MiB, and this really will
- // only be used with some ridiculous torture-tests.
- if (state.MaxSimultaneousAllocations > 1000000) {
+ if (state.MaxSimultaneousAllocations > 1024) {
ALOGE(
"Error when retrieving GWP-ASan metadata, MSA from state (%zu) "
- "exceeds maximum allowed (1,000,000).",
+ "exceeds maximum allowed (1024).",
state.MaxSimultaneousAllocations);
return nullptr;
}
@@ -150,7 +147,7 @@ void GwpAsanCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinde
for (size_t i = 0; i != num_frames; ++i) {
unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
BacktraceFrame* f = heap_object->add_allocation_backtrace();
- fill_in_backtrace_frame(f, frame_data);
+ fill_in_backtrace_frame(f, frame_data, unwinder->GetMaps());
}
heap_object->set_deallocation_tid(__gwp_asan_get_deallocation_thread_id(responsible_allocation_));
@@ -159,8 +156,117 @@ void GwpAsanCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinde
for (size_t i = 0; i != num_frames; ++i) {
unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
BacktraceFrame* f = heap_object->add_deallocation_backtrace();
- fill_in_backtrace_frame(f, frame_data);
+ fill_in_backtrace_frame(f, frame_data, unwinder->GetMaps());
}
set_human_readable_cause(cause, crash_address_);
}
+
+void GwpAsanCrashData::DumpCause(log_t* log) const {
+ if (!CrashIsMine()) {
+ ALOGE("Internal Error: DumpCause() on a non-GWP-ASan crash.");
+ return;
+ }
+
+ if (error_ == gwp_asan::Error::UNKNOWN) {
+ _LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: Unknown error occurred at 0x%" PRIxPTR ".\n",
+ crash_address_);
+ return;
+ }
+
+ if (!responsible_allocation_) {
+ _LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: %s at 0x%" PRIxPTR ".\n", error_string_,
+ crash_address_);
+ return;
+ }
+
+ uintptr_t alloc_address = __gwp_asan_get_allocation_address(responsible_allocation_);
+ size_t alloc_size = __gwp_asan_get_allocation_size(responsible_allocation_);
+
+ uintptr_t diff;
+ const char* location_str;
+
+ if (crash_address_ < alloc_address) {
+ // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
+ location_str = "left of";
+ diff = alloc_address - crash_address_;
+ } else if (crash_address_ - alloc_address < alloc_size) {
+ // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
+ location_str = "into";
+ diff = crash_address_ - alloc_address;
+ } else {
+ // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef, or
+ // Invalid Free, 47 bytes right of a 41-byte allocation at 0xdeadbeef.
+ location_str = "right of";
+ diff = crash_address_ - alloc_address;
+ if (error_ == gwp_asan::Error::BUFFER_OVERFLOW) {
+ diff -= alloc_size;
+ }
+ }
+
+ // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
+ const char* byte_suffix = "s";
+ if (diff == 1) {
+ byte_suffix = "";
+ }
+ _LOG(log, logtype::HEADER,
+ "Cause: [GWP-ASan]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
+ error_string_, diff, byte_suffix, location_str, alloc_size, alloc_address);
+}
+
+bool GwpAsanCrashData::HasDeallocationTrace() const {
+ assert(CrashIsMine() && "HasDeallocationTrace(): Crash is not mine!");
+ if (!responsible_allocation_ || !__gwp_asan_is_deallocated(responsible_allocation_)) {
+ return false;
+ }
+ return true;
+}
+
+void GwpAsanCrashData::DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
+ assert(HasDeallocationTrace() && "DumpDeallocationTrace(): No dealloc trace!");
+ uint64_t thread_id = __gwp_asan_get_deallocation_thread_id(responsible_allocation_);
+
+ std::unique_ptr<uintptr_t[]> frames(new uintptr_t[kMaxTraceLength]);
+ size_t num_frames =
+ __gwp_asan_get_deallocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
+
+ if (thread_id == gwp_asan::kInvalidThreadID) {
+ _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread <unknown>:\n");
+ } else {
+ _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %" PRIu64 ":\n", thread_id);
+ }
+
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < num_frames; ++i) {
+ unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
+ frame_data.num = i;
+ _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
+ }
+}
+
+bool GwpAsanCrashData::HasAllocationTrace() const {
+ assert(CrashIsMine() && "HasAllocationTrace(): Crash is not mine!");
+ return responsible_allocation_ != nullptr;
+}
+
+void GwpAsanCrashData::DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
+ assert(HasAllocationTrace() && "DumpAllocationTrace(): No dealloc trace!");
+ uint64_t thread_id = __gwp_asan_get_allocation_thread_id(responsible_allocation_);
+
+ std::unique_ptr<uintptr_t[]> frames(new uintptr_t[kMaxTraceLength]);
+ size_t num_frames =
+ __gwp_asan_get_allocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
+
+ if (thread_id == gwp_asan::kInvalidThreadID) {
+ _LOG(log, logtype::BACKTRACE, "\nallocated by thread <unknown>:\n");
+ } else {
+ _LOG(log, logtype::BACKTRACE, "\nallocated by thread %" PRIu64 ":\n", thread_id);
+ }
+
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < num_frames; ++i) {
+ unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames[i]);
+ frame_data.num = i;
+ _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
+ }
+}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
index a97937005..f9c2481a9 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
@@ -52,6 +52,26 @@ class GwpAsanCrashData {
// allocator crash state.
uintptr_t GetFaultAddress() const;
+ // Dump the GWP-ASan stringified cause of this crash. May only be called if
+ // CrashIsMine() returns true.
+ void DumpCause(log_t* log) const;
+
+ // Returns whether this crash has a deallocation trace. May only be called if
+ // CrashIsMine() returns true.
+ bool HasDeallocationTrace() const;
+
+ // Dump the GWP-ASan deallocation trace for this crash. May only be called if
+ // HasDeallocationTrace() returns true.
+ void DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
+
+ // Returns whether this crash has a allocation trace. May only be called if
+ // CrashIsMine() returns true.
+ bool HasAllocationTrace() const;
+
+ // Dump the GWP-ASan allocation trace for this crash. May only be called if
+ // HasAllocationTrace() returns true.
+ void DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
+
void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
protected:
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
index 172ffe961..c3b95d608 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
@@ -34,12 +34,16 @@ class ScudoCrashData {
bool CrashIsMine() const;
+ void DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const;
void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
private:
scudo_error_info error_info_ = {};
uintptr_t untagged_fault_addr_;
+ void DumpReport(const scudo_error_report* report, log_t* log,
+ unwindstack::Unwinder* unwinder) const;
+
void FillInCause(Cause* cause, const scudo_error_report* report,
unwindstack::Unwinder* unwinder) const;
};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 7bf1688c0..2331f1e6e 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -37,6 +37,7 @@ class Tombstone;
namespace unwindstack {
struct FrameData;
+class Maps;
class Unwinder;
}
@@ -67,7 +68,8 @@ bool tombstone_proto_to_text(
const Tombstone& tombstone,
std::function<void(const std::string& line, bool should_log)> callback);
-void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& frame);
+void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& frame,
+ unwindstack::Maps* maps);
void set_human_readable_cause(Cause* cause, uint64_t fault_addr);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index a51e2769c..086dc97da 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -25,7 +25,6 @@
struct ThreadInfo {
std::unique_ptr<unwindstack::Regs> registers;
long tagged_addr_ctrl = -1;
- long pac_enabled_keys = -1;
pid_t uid;
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 63e142f2c..24ae16949 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -1,20 +1,22 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
+/* system/debuggerd/utility.h
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef _DEBUGGERD_UTILITY_H
+#define _DEBUGGERD_UTILITY_H
#include <inttypes.h>
#include <signal.h>
@@ -90,8 +92,6 @@ bool signal_has_si_addr(const siginfo_t*);
void get_signal_sender(char* buf, size_t n, const siginfo_t*);
const char* get_signame(const siginfo_t*);
const char* get_sigcode(const siginfo_t*);
-std::string describe_tagged_addr_ctrl(long ctrl);
-std::string describe_pac_enabled_keys(long keys);
// Number of bytes per MTE granule.
constexpr size_t kTagGranuleSize = 16;
@@ -99,3 +99,5 @@ constexpr size_t kTagGranuleSize = 16;
// Number of rows and columns to display in an MTE tag dump.
constexpr size_t kNumTagColumns = 16;
constexpr size_t kNumTagRows = 16;
+
+#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp
index a4836d753..f4690bac3 100644
--- a/debuggerd/libdebuggerd/scudo.cpp
+++ b/debuggerd/libdebuggerd/scudo.cpp
@@ -108,7 +108,7 @@ void ScudoCrashData::FillInCause(Cause* cause, const scudo_error_report* report,
for (size_t i = 0; i < arraysize(report->allocation_trace) && report->allocation_trace[i]; ++i) {
unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
BacktraceFrame* f = heap_object->add_allocation_backtrace();
- fill_in_backtrace_frame(f, frame_data);
+ fill_in_backtrace_frame(f, frame_data, unwinder->GetMaps());
}
heap_object->set_deallocation_tid(report->deallocation_tid);
@@ -117,7 +117,7 @@ void ScudoCrashData::FillInCause(Cause* cause, const scudo_error_report* report,
unwindstack::FrameData frame_data =
unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
BacktraceFrame* f = heap_object->add_deallocation_backtrace();
- fill_in_backtrace_frame(f, frame_data);
+ fill_in_backtrace_frame(f, frame_data, unwinder->GetMaps());
}
set_human_readable_cause(cause, untagged_fault_addr_);
@@ -130,3 +130,87 @@ void ScudoCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder*
FillInCause(tombstone->add_causes(), &error_info_.reports[report_num++], unwinder);
}
}
+
+void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const {
+ if (error_info_.reports[1].error_type != UNKNOWN) {
+ _LOG(log, logtype::HEADER,
+ "\nNote: multiple potential causes for this crash were detected, listing them in "
+ "decreasing order of probability.\n");
+ }
+
+ size_t report_num = 0;
+ while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
+ error_info_.reports[report_num].error_type != UNKNOWN) {
+ DumpReport(&error_info_.reports[report_num++], log, unwinder);
+ }
+}
+
+void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log,
+ unwindstack::Unwinder* unwinder) const {
+ const char *error_type_str;
+ switch (report->error_type) {
+ case USE_AFTER_FREE:
+ error_type_str = "Use After Free";
+ break;
+ case BUFFER_OVERFLOW:
+ error_type_str = "Buffer Overflow";
+ break;
+ case BUFFER_UNDERFLOW:
+ error_type_str = "Buffer Underflow";
+ break;
+ default:
+ error_type_str = "Unknown";
+ break;
+ }
+
+ uintptr_t diff;
+ const char* location_str;
+
+ if (untagged_fault_addr_ < report->allocation_address) {
+ // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
+ location_str = "left of";
+ diff = report->allocation_address - untagged_fault_addr_;
+ } else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) {
+ // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
+ location_str = "into";
+ diff = untagged_fault_addr_ - report->allocation_address;
+ } else {
+ // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef.
+ location_str = "right of";
+ diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size;
+ }
+
+ // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
+ const char* byte_suffix = "s";
+ if (diff == 1) {
+ byte_suffix = "";
+ }
+ _LOG(log, logtype::HEADER,
+ "\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
+ error_type_str, diff, byte_suffix, location_str, report->allocation_size,
+ report->allocation_address);
+
+ if (report->allocation_trace[0]) {
+ _LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid);
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < arraysize(report->allocation_trace) && report->allocation_trace[i];
+ ++i) {
+ unwindstack::FrameData frame_data =
+ unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
+ frame_data.num = i;
+ _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
+ }
+ }
+
+ if (report->deallocation_trace[0]) {
+ _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid);
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < arraysize(report->deallocation_trace) && report->deallocation_trace[i];
+ ++i) {
+ unwindstack::FrameData frame_data =
+ unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
+ frame_data.num = i;
+ _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str());
+ }
+ }
+}
diff --git a/debuggerd/libdebuggerd/test/UnwinderMock.h b/debuggerd/libdebuggerd/test/UnwinderMock.h
index 1e3c55952..8f84346af 100644
--- a/debuggerd/libdebuggerd/test/UnwinderMock.h
+++ b/debuggerd/libdebuggerd/test/UnwinderMock.h
@@ -16,8 +16,6 @@
#pragma once
-#include <memory>
-
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Unwinder.h>
@@ -33,7 +31,7 @@ class UnwinderMock : public unwindstack::Unwinder {
}
void MockSetBuildID(uint64_t offset, const std::string& build_id) {
- std::shared_ptr<unwindstack::MapInfo> map_info = GetMaps()->Find(offset);
+ unwindstack::MapInfo* map_info = GetMaps()->Find(offset);
if (map_info != nullptr) {
map_info->SetBuildID(std::string(build_id));
}
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
new file mode 100644
index 000000000..a14dcb0e7
--- /dev/null
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <time.h>
+
+#include <memory>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "libdebuggerd/utility.h"
+
+#include "UnwinderMock.h"
+#include "host_signal_fixup.h"
+#include "log_fake.h"
+
+// Include tombstone.cpp to define log_tag before GWP-ASan includes log.
+#include "tombstone.cpp"
+
+#include "gwp_asan.cpp"
+
+using ::testing::MatchesRegex;
+
+class TombstoneTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ unwinder_mock_.reset(new UnwinderMock());
+
+ char tmp_file[256];
+ const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, data_template, sizeof(data_template));
+ int tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, tmp_template, sizeof(tmp_template));
+ tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ abort();
+ }
+ }
+ if (unlink(tmp_file) == -1) {
+ abort();
+ }
+
+ log_.tfd = tombstone_fd;
+ amfd_data_.clear();
+ log_.amfd_data = &amfd_data_;
+ log_.crashed_tid = 12;
+ log_.current_tid = 12;
+ log_.should_retrieve_logcat = false;
+
+ resetLogs();
+ }
+
+ virtual void TearDown() {
+ if (log_.tfd >= 0) {
+ close(log_.tfd);
+ }
+ }
+
+ std::unique_ptr<UnwinderMock> unwinder_mock_;
+
+ log_t log_;
+ std::string amfd_data_;
+};
+
+TEST_F(TombstoneTest, single_map) {
+#if defined(__LP64__)
+ unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0);
+#else
+ unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0);
+#endif
+
+ dump_all_maps(&log_, unwinder_mock_.get(), 0);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map (1 entry):\n"
+#if defined(__LP64__)
+" 12345678'9abcd000-12345678'9abdefff --- 0 12000\n";
+#else
+" 01234000-01234fff --- 0 1000\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, single_map_elf_build_id) {
+ uint64_t build_id_offset;
+#if defined(__LP64__)
+ build_id_offset = 0x123456789abcd000UL;
+ unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ,
+ "/system/lib/libfake.so", 0);
+#else
+ build_id_offset = 0x1234000;
+ unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0);
+#endif
+
+ unwinder_mock_->MockSetBuildID(
+ build_id_offset,
+ std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef),
+ static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56),
+ static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab),
+ static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12),
+ static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78),
+ static_cast<char>(0x90)});
+ dump_all_maps(&log_, unwinder_mock_.get(), 0);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map (1 entry):\n"
+#if defined(__LP64__)
+" 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
+#else
+" 01234000-01234fff r-- 0 1000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, multiple_maps) {
+ unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0);
+ unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0);
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
+
+ dump_all_maps(&log_, unwinder_mock_.get(), 0);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump =
+ "\nmemory map (5 entries):\n"
+#if defined(__LP64__)
+ " 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
+ " 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+ " 0a234000-0a234fff --- 0 1000\n"
+ " 0a334000-0a334fff r-- f000 1000\n"
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
+
+ dump_all_maps(&log_, unwinder_mock_.get(), 0x1000);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump =
+ "\nmemory map (3 entries):\n"
+#if defined(__LP64__)
+ "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+ "--->Fault address falls at 00001000 before any mapped regions\n"
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
+
+ dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump =
+ "\nmemory map (3 entries): (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->Fault address falls at 00000000'0a533000 between mapped regions\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->Fault address falls at 0a533000 between mapped regions\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
+
+ dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump =
+ "\nmemory map (3 entries): (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
+
+#if defined(__LP64__)
+ uint64_t addr = 0x12345a534040UL;
+#else
+ uint64_t addr = 0xf534040UL;
+#endif
+ dump_all_maps(&log_, unwinder_mock_.get(), addr);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump =
+ "\nmemory map (3 entries): (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n"
+ "--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
+#else
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n"
+ "--->Fault address falls at 0f534040 after any mapped regions\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, dump_log_file_error) {
+ log_.should_retrieve_logcat = true;
+ dump_log_file(&log_, 123, "/fake/filename", 10);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ("", tombstone_contents.c_str());
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
+ getFakeLogPrint().c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+}
+
+TEST_F(TombstoneTest, dump_header_info) {
+ dump_header_info(&log_);
+
+ std::string expected = android::base::StringPrintf(
+ "Build fingerprint: '%s'\nRevision: '%s'\n",
+ android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
+ android::base::GetProperty("ro.revision", "unknown").c_str());
+ expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
+ ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
+}
+
+TEST_F(TombstoneTest, dump_thread_info_uid) {
+ std::vector<std::string> cmdline = {"some_process"};
+ dump_thread_info(
+ &log_,
+ ThreadInfo{
+ .uid = 1, .tid = 3, .thread_name = "some_thread", .pid = 2, .command_line = cmdline});
+ std::string expected = "pid: 2, tid: 3, name: some_thread >>> some_process <<<\nuid: 1\n";
+ ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
+}
+
+class GwpAsanCrashDataTest : public GwpAsanCrashData {
+public:
+ GwpAsanCrashDataTest(
+ gwp_asan::Error error,
+ const gwp_asan::AllocationMetadata *responsible_allocation) :
+ GwpAsanCrashData(nullptr, ProcessInfo{}, ThreadInfo{}) {
+ is_gwp_asan_responsible_ = true;
+ error_ = error;
+ responsible_allocation_ = responsible_allocation;
+ error_string_ = gwp_asan::ErrorToString(error_);
+ }
+
+ void SetCrashAddress(uintptr_t crash_address) {
+ crash_address_ = crash_address;
+ }
+};
+
+TEST_F(TombstoneTest, gwp_asan_cause_uaf_exact) {
+ gwp_asan::AllocationMetadata meta;
+ meta.Addr = 0x1000;
+ meta.RequestedSize = 32;
+
+ GwpAsanCrashDataTest crash_data(gwp_asan::Error::USE_AFTER_FREE, &meta);
+ crash_data.SetCrashAddress(0x1000);
+
+ crash_data.DumpCause(&log_);
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ std::string tombstone_contents;
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Use After Free, 0 bytes "
+ "into a 32-byte allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_double_free) {
+ gwp_asan::AllocationMetadata meta;
+ meta.Addr = 0x1000;
+ meta.RequestedSize = 32;
+
+ GwpAsanCrashDataTest crash_data(gwp_asan::Error::DOUBLE_FREE, &meta);
+ crash_data.SetCrashAddress(0x1000);
+
+ crash_data.DumpCause(&log_);
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ std::string tombstone_contents;
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Double Free, 0 bytes into a "
+ "32-byte allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_overflow) {
+ gwp_asan::AllocationMetadata meta;
+ meta.Addr = 0x1000;
+ meta.RequestedSize = 32;
+
+ GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_OVERFLOW, &meta);
+ crash_data.SetCrashAddress(0x1025);
+
+ crash_data.DumpCause(&log_);
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ std::string tombstone_contents;
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_THAT(
+ tombstone_contents,
+ MatchesRegex(
+ "Cause: \\[GWP-ASan\\]: Buffer Overflow, 5 bytes right of a 32-byte "
+ "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_underflow) {
+ gwp_asan::AllocationMetadata meta;
+ meta.Addr = 0x1000;
+ meta.RequestedSize = 32;
+
+ GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_UNDERFLOW, &meta);
+ crash_data.SetCrashAddress(0xffe);
+
+ crash_data.DumpCause(&log_);
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ std::string tombstone_contents;
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_THAT(
+ tombstone_contents,
+ MatchesRegex(
+ "Cause: \\[GWP-ASan\\]: Buffer Underflow, 2 bytes left of a 32-byte "
+ "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_inside) {
+ gwp_asan::AllocationMetadata meta;
+ meta.Addr = 0x1000;
+ meta.RequestedSize = 32;
+
+ GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
+ crash_data.SetCrashAddress(0x1001);
+
+ crash_data.DumpCause(&log_);
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ std::string tombstone_contents;
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_THAT(
+ tombstone_contents,
+ MatchesRegex(
+ "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 1 byte into a 32-byte "
+ "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_outside) {
+ gwp_asan::AllocationMetadata meta;
+ meta.Addr = 0x1000;
+ meta.RequestedSize = 32;
+
+ GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
+ crash_data.SetCrashAddress(0x1021);
+
+ crash_data.DumpCause(&log_);
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ std::string tombstone_contents;
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_THAT(
+ tombstone_contents,
+ MatchesRegex(
+ "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 33 bytes right of a 32-byte "
+ "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
diff --git a/debuggerd/libdebuggerd/test/utility_test.cpp b/debuggerd/libdebuggerd/test/utility_test.cpp
deleted file mode 100644
index dad338054..000000000
--- a/debuggerd/libdebuggerd/test/utility_test.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 <gtest/gtest.h>
-#include <sys/prctl.h>
-
-#include "libdebuggerd/utility.h"
-
-TEST(UtilityTest, describe_tagged_addr_ctrl) {
- EXPECT_EQ("", describe_tagged_addr_ctrl(0));
- EXPECT_EQ(" (PR_TAGGED_ADDR_ENABLE)", describe_tagged_addr_ctrl(PR_TAGGED_ADDR_ENABLE));
- EXPECT_EQ(" (PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe)",
- describe_tagged_addr_ctrl(PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC |
- (0xfffe << PR_MTE_TAG_SHIFT)));
- EXPECT_EQ(
- " (PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, PR_MTE_TCF_ASYNC, mask 0xfffe, unknown "
- "0xf0000000)",
- describe_tagged_addr_ctrl(0xf0000000 | PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC |
- PR_MTE_TCF_ASYNC | (0xfffe << PR_MTE_TAG_SHIFT)));
-}
-
-TEST(UtilityTest, describe_pac_enabled_keys) {
- EXPECT_EQ("", describe_pac_enabled_keys(0));
- EXPECT_EQ(" (PR_PAC_APIAKEY)", describe_pac_enabled_keys(PR_PAC_APIAKEY));
- EXPECT_EQ(" (PR_PAC_APIAKEY, PR_PAC_APDBKEY)",
- describe_pac_enabled_keys(PR_PAC_APIAKEY | PR_PAC_APDBKEY));
- EXPECT_EQ(" (PR_PAC_APIAKEY, PR_PAC_APDBKEY, unknown 0x1000)",
- describe_pac_enabled_keys(PR_PAC_APIAKEY | PR_PAC_APDBKEY | 0x1000));
-}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index eda718206..9c01f15eb 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -18,39 +18,547 @@
#include "libdebuggerd/tombstone.h"
+#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/prctl.h>
-#include <sys/types.h>
-#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <time.h>
#include <memory>
#include <string>
#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/log.h>
#include <async_safe/log.h>
+#include <bionic/macros.h>
#include <log/log.h>
+#include <log/log_read.h>
+#include <log/logprint.h>
#include <private/android_filesystem_config.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/Unwinder.h>
#include "libdebuggerd/backtrace.h"
+#include "libdebuggerd/gwp_asan.h"
#include "libdebuggerd/open_files_list.h"
+#include "libdebuggerd/scudo.h"
#include "libdebuggerd/utility.h"
#include "util.h"
+#include "gwp_asan/common.h"
+#include "gwp_asan/crash_handler.h"
+
#include "tombstone.pb.h"
+using android::base::GetBoolProperty;
+using android::base::GetProperty;
+using android::base::StringPrintf;
using android::base::unique_fd;
using namespace std::literals::string_literals;
+#define STACK_WORDS 16
+
+static void dump_header_info(log_t* log) {
+ auto fingerprint = GetProperty("ro.build.fingerprint", "unknown");
+ auto revision = GetProperty("ro.revision", "unknown");
+
+ _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint.c_str());
+ _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision.c_str());
+ _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
+}
+
+static std::string get_stack_overflow_cause(uint64_t fault_addr, uint64_t sp,
+ unwindstack::Maps* maps) {
+ static constexpr uint64_t kMaxDifferenceBytes = 256;
+ uint64_t difference;
+ if (sp >= fault_addr) {
+ difference = sp - fault_addr;
+ } else {
+ difference = fault_addr - sp;
+ }
+ if (difference <= kMaxDifferenceBytes) {
+ // The faulting address is close to the current sp, check if the sp
+ // indicates a stack overflow.
+ // On arm, the sp does not get updated when the instruction faults.
+ // In this case, the sp will still be in a valid map, which is the
+ // last case below.
+ // On aarch64, the sp does get updated when the instruction faults.
+ // In this case, the sp will be in either an invalid map if triggered
+ // on the main thread, or in a guard map if in another thread, which
+ // will be the first case or second case from below.
+ unwindstack::MapInfo* map_info = maps->Find(sp);
+ if (map_info == nullptr) {
+ return "stack pointer is in a non-existent map; likely due to stack overflow.";
+ } else if ((map_info->flags() & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
+ return "stack pointer is not in a rw map; likely due to stack overflow.";
+ } else if ((sp - map_info->start()) <= kMaxDifferenceBytes) {
+ return "stack pointer is close to top of stack; likely stack overflow.";
+ }
+ }
+ return "";
+}
+
+static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps,
+ unwindstack::Regs* regs) {
+ std::string cause;
+ if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
+ if (si->si_addr < reinterpret_cast<void*>(4096)) {
+ cause = StringPrintf("null pointer dereference");
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0ffc)) {
+ cause = "call to kuser_helper_version";
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fe0)) {
+ cause = "call to kuser_get_tls";
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fc0)) {
+ cause = "call to kuser_cmpxchg";
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0fa0)) {
+ cause = "call to kuser_memory_barrier";
+ } else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
+ cause = "call to kuser_cmpxchg64";
+ } else {
+ cause = get_stack_overflow_cause(reinterpret_cast<uint64_t>(si->si_addr), regs->sp(), maps);
+ }
+ } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
+ uint64_t fault_addr = reinterpret_cast<uint64_t>(si->si_addr);
+ unwindstack::MapInfo* map_info = maps->Find(fault_addr);
+ if (map_info != nullptr && map_info->flags() == PROT_EXEC) {
+ cause = "execute-only (no-read) memory access error; likely due to data in .text.";
+ } else {
+ cause = get_stack_overflow_cause(fault_addr, regs->sp(), maps);
+ }
+ } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
+ cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
+ si->si_syscall);
+ }
+
+ if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
+}
+
+static void dump_signal_info(log_t* log, const ThreadInfo& thread_info,
+ const ProcessInfo& process_info, unwindstack::Memory* process_memory) {
+ char addr_desc[64]; // ", fault addr 0x1234"
+ if (process_info.has_fault_address) {
+ // SIGILL faults will never have tagged addresses, so okay to
+ // indiscriminately use the tagged address here.
+ size_t addr = process_info.maybe_tagged_fault_address;
+ if (thread_info.siginfo->si_signo == SIGILL) {
+ uint32_t instruction = {};
+ process_memory->Read(addr, &instruction, sizeof(instruction));
+ snprintf(addr_desc, sizeof(addr_desc), "0x%zx (*pc=%#08x)", addr, instruction);
+ } else {
+ snprintf(addr_desc, sizeof(addr_desc), "0x%zx", addr);
+ }
+ } else {
+ snprintf(addr_desc, sizeof(addr_desc), "--------");
+ }
+
+ char sender_desc[32] = {}; // " from pid 1234, uid 666"
+ if (signal_has_sender(thread_info.siginfo, thread_info.pid)) {
+ get_signal_sender(sender_desc, sizeof(sender_desc), thread_info.siginfo);
+ }
+
+ _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
+ thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
+ thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
+}
+
+static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
+ // Don't try to collect logs from the threads that implement the logging system itself.
+ if (thread_info.uid == AID_LOGD) log->should_retrieve_logcat = false;
+
+ const char* process_name = "<unknown>";
+ if (!thread_info.command_line.empty()) {
+ process_name = thread_info.command_line[0].c_str();
+ }
+
+ _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", thread_info.pid,
+ thread_info.tid, thread_info.thread_name.c_str(), process_name);
+ _LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid);
+ if (thread_info.tagged_addr_ctrl != -1) {
+ _LOG(log, logtype::HEADER, "tagged_addr_ctrl: %016lx\n", thread_info.tagged_addr_ctrl);
+ }
+}
+
+static std::string get_addr_string(uint64_t addr) {
+ std::string addr_str;
+#if defined(__LP64__)
+ addr_str = StringPrintf("%08x'%08x", static_cast<uint32_t>(addr >> 32),
+ static_cast<uint32_t>(addr & 0xffffffff));
+#else
+ addr_str = StringPrintf("%08x", static_cast<uint32_t>(addr));
+#endif
+ return addr_str;
+}
+
+static void dump_abort_message(log_t* log, unwindstack::Memory* process_memory, uint64_t address) {
+ if (address == 0) {
+ return;
+ }
+
+ size_t length;
+ if (!process_memory->ReadFully(address, &length, sizeof(length))) {
+ _LOG(log, logtype::HEADER, "Failed to read abort message header: %s\n", strerror(errno));
+ return;
+ }
+
+ // The length field includes the length of the length field itself.
+ if (length < sizeof(size_t)) {
+ _LOG(log, logtype::HEADER, "Abort message header malformed: claimed length = %zd\n", length);
+ return;
+ }
+
+ length -= sizeof(size_t);
+
+ // The abort message should be null terminated already, but reserve a spot for NUL just in case.
+ std::vector<char> msg(length + 1);
+ if (!process_memory->ReadFully(address + sizeof(length), &msg[0], length)) {
+ _LOG(log, logtype::HEADER, "Failed to read abort message: %s\n", strerror(errno));
+ return;
+ }
+
+ _LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]);
+}
+
+static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t addr) {
+ bool print_fault_address_marker = addr;
+
+ unwindstack::Maps* maps = unwinder->GetMaps();
+ _LOG(log, logtype::MAPS,
+ "\n"
+ "memory map (%zu entr%s):",
+ maps->Total(), maps->Total() == 1 ? "y" : "ies");
+ if (print_fault_address_marker) {
+ if (maps->Total() != 0 && addr < maps->Get(0)->start()) {
+ _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
+ get_addr_string(addr).c_str());
+ print_fault_address_marker = false;
+ } else {
+ _LOG(log, logtype::MAPS, " (fault address prefixed with --->)\n");
+ }
+ } else {
+ _LOG(log, logtype::MAPS, "\n");
+ }
+
+ std::shared_ptr<unwindstack::Memory>& process_memory = unwinder->GetProcessMemory();
+
+ std::string line;
+ for (auto const& map_info : *maps) {
+ line = " ";
+ if (print_fault_address_marker) {
+ if (addr < map_info->start()) {
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
+ get_addr_string(addr).c_str());
+ print_fault_address_marker = false;
+ } else if (addr >= map_info->start() && addr < map_info->end()) {
+ line = "--->";
+ print_fault_address_marker = false;
+ }
+ }
+ line += get_addr_string(map_info->start()) + '-' + get_addr_string(map_info->end() - 1) + ' ';
+ if (map_info->flags() & PROT_READ) {
+ line += 'r';
+ } else {
+ line += '-';
+ }
+ if (map_info->flags() & PROT_WRITE) {
+ line += 'w';
+ } else {
+ line += '-';
+ }
+ if (map_info->flags() & PROT_EXEC) {
+ line += 'x';
+ } else {
+ line += '-';
+ }
+ line += StringPrintf(" %8" PRIx64 " %8" PRIx64, map_info->offset(),
+ map_info->end() - map_info->start());
+ bool space_needed = true;
+ if (!map_info->name().empty()) {
+ space_needed = false;
+ line += " " + map_info->name();
+ std::string build_id = map_info->GetPrintableBuildID();
+ if (!build_id.empty()) {
+ line += " (BuildId: " + build_id + ")";
+ }
+ }
+ uint64_t load_bias = map_info->GetLoadBias(process_memory);
+ if (load_bias != 0) {
+ if (space_needed) {
+ line += ' ';
+ }
+ line += StringPrintf(" (load bias 0x%" PRIx64 ")", load_bias);
+ }
+ _LOG(log, logtype::MAPS, "%s\n", line.c_str());
+ }
+ if (print_fault_address_marker) {
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %s after any mapped regions\n",
+ get_addr_string(addr).c_str());
+ }
+}
+
+static void print_register_row(log_t* log,
+ const std::vector<std::pair<std::string, uint64_t>>& registers) {
+ std::string output;
+ for (auto& [name, value] : registers) {
+ output += android::base::StringPrintf(" %-3s %0*" PRIx64, name.c_str(),
+ static_cast<int>(2 * sizeof(void*)),
+ static_cast<uint64_t>(value));
+ }
+
+ _LOG(log, logtype::REGISTERS, " %s\n", output.c_str());
+}
+
+void dump_registers(log_t* log, unwindstack::Regs* regs) {
+ // Split lr/sp/pc into their own special row.
+ static constexpr size_t column_count = 4;
+ std::vector<std::pair<std::string, uint64_t>> current_row;
+ std::vector<std::pair<std::string, uint64_t>> special_row;
+
+#if defined(__arm__) || defined(__aarch64__)
+ static constexpr const char* special_registers[] = {"ip", "lr", "sp", "pc", "pst"};
+#elif defined(__i386__)
+ static constexpr const char* special_registers[] = {"ebp", "esp", "eip"};
+#elif defined(__x86_64__)
+ static constexpr const char* special_registers[] = {"rbp", "rsp", "rip"};
+#else
+ static constexpr const char* special_registers[] = {};
+#endif
+
+ regs->IterateRegisters([log, &current_row, &special_row](const char* name, uint64_t value) {
+ auto row = &current_row;
+ for (const char* special_name : special_registers) {
+ if (strcmp(special_name, name) == 0) {
+ row = &special_row;
+ break;
+ }
+ }
+
+ row->emplace_back(name, value);
+ if (current_row.size() == column_count) {
+ print_register_row(log, current_row);
+ current_row.clear();
+ }
+ });
+
+ if (!current_row.empty()) {
+ print_register_row(log, current_row);
+ }
+
+ print_register_row(log, special_row);
+}
+
+void dump_memory_and_code(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
+ unwindstack::Regs* regs) {
+ regs->IterateRegisters([log, maps, memory](const char* reg_name, uint64_t reg_value) {
+ std::string label{"memory near "s + reg_name};
+ if (maps) {
+ unwindstack::MapInfo* map_info = maps->Find(untag_address(reg_value));
+ if (map_info != nullptr && !map_info->name().empty()) {
+ label += " (" + map_info->name() + ")";
+ }
+ }
+ dump_memory(log, memory, reg_value, label);
+ });
+}
+
+static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info,
+ const ProcessInfo& process_info, bool primary_thread) {
+ log->current_tid = thread_info.tid;
+ if (!primary_thread) {
+ _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+ }
+ dump_thread_info(log, thread_info);
+
+ if (thread_info.siginfo) {
+ dump_signal_info(log, thread_info, process_info, unwinder->GetProcessMemory().get());
+ }
+
+ std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
+ std::unique_ptr<ScudoCrashData> scudo_crash_data;
+ if (primary_thread) {
+ gwp_asan_crash_data = std::make_unique<GwpAsanCrashData>(unwinder->GetProcessMemory().get(),
+ process_info, thread_info);
+ scudo_crash_data =
+ std::make_unique<ScudoCrashData>(unwinder->GetProcessMemory().get(), process_info);
+ }
+
+ if (primary_thread && gwp_asan_crash_data->CrashIsMine()) {
+ gwp_asan_crash_data->DumpCause(log);
+ } else if (thread_info.siginfo && !(primary_thread && scudo_crash_data->CrashIsMine())) {
+ dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(), thread_info.registers.get());
+ }
+
+ if (primary_thread) {
+ dump_abort_message(log, unwinder->GetProcessMemory().get(), process_info.abort_msg_address);
+ }
+
+ dump_registers(log, thread_info.registers.get());
+
+ // Unwind will mutate the registers, so make a copy first.
+ std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
+ unwinder->SetRegs(regs_copy.get());
+ unwinder->Unwind();
+ if (unwinder->NumFrames() == 0) {
+ _LOG(log, logtype::THREAD, "Failed to unwind\n");
+ if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
+ _LOG(log, logtype::THREAD, " Error code: %s\n", unwinder->LastErrorCodeString());
+ _LOG(log, logtype::THREAD, " Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
+ }
+ } else {
+ _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
+ log_backtrace(log, unwinder, " ");
+ }
+
+ if (primary_thread) {
+ if (gwp_asan_crash_data->HasDeallocationTrace()) {
+ gwp_asan_crash_data->DumpDeallocationTrace(log, unwinder);
+ }
+
+ if (gwp_asan_crash_data->HasAllocationTrace()) {
+ gwp_asan_crash_data->DumpAllocationTrace(log, unwinder);
+ }
+
+ scudo_crash_data->DumpCause(log, unwinder);
+
+ unwindstack::Maps* maps = unwinder->GetMaps();
+ dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
+ thread_info.registers.get());
+ if (maps != nullptr) {
+ uint64_t addr = 0;
+ if (process_info.has_fault_address) {
+ addr = process_info.untagged_fault_address;
+ }
+ dump_all_maps(log, unwinder, addr);
+ }
+ }
+
+ log->current_tid = log->crashed_tid;
+ return true;
+}
+
+// Reads the contents of the specified log device, filters out the entries
+// that don't match the specified pid, and writes them to the tombstone file.
+//
+// If "tail" is non-zero, log the last "tail" number of lines.
+static void dump_log_file(log_t* log, pid_t pid, const char* filename, unsigned int tail) {
+ bool first = true;
+ logger_list* logger_list;
+
+ if (!log->should_retrieve_logcat) {
+ return;
+ }
+
+ logger_list =
+ android_logger_list_open(android_name_to_log_id(filename), ANDROID_LOG_NONBLOCK, tail, pid);
+
+ if (!logger_list) {
+ ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
+ return;
+ }
+
+ while (true) {
+ log_msg log_entry;
+ ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+
+ if (actual < 0) {
+ if (actual == -EINTR) {
+ // interrupted by signal, retry
+ continue;
+ } else if (actual == -EAGAIN) {
+ // non-blocking EOF; we're done
+ break;
+ } else {
+ ALOGE("Error while reading log: %s\n", strerror(-actual));
+ break;
+ }
+ } else if (actual == 0) {
+ ALOGE("Got zero bytes while reading log: %s\n", strerror(errno));
+ break;
+ }
+
+ // NOTE: if you ALOGV something here, this will spin forever,
+ // because you will be writing as fast as you're reading. Any
+ // high-frequency debug diagnostics should just be written to
+ // the tombstone file.
+
+ if (first) {
+ _LOG(log, logtype::LOGS, "--------- %slog %s\n", tail ? "tail end of " : "", filename);
+ first = false;
+ }
+
+ // Msg format is: <priority:1><tag:N>\0<message:N>\0
+ //
+ // We want to display it in the same format as "logcat -v threadtime"
+ // (although in this case the pid is redundant).
+ char timeBuf[32];
+ time_t sec = static_cast<time_t>(log_entry.entry.sec);
+ tm tm;
+ localtime_r(&sec, &tm);
+ strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", &tm);
+
+ char* msg = log_entry.msg();
+ if (msg == nullptr) {
+ continue;
+ }
+ unsigned char prio = msg[0];
+ char* tag = msg + 1;
+ msg = tag + strlen(tag) + 1;
+
+ // consume any trailing newlines
+ char* nl = msg + strlen(msg) - 1;
+ while (nl >= msg && *nl == '\n') {
+ *nl-- = '\0';
+ }
+
+ static const char* kPrioChars = "!.VDIWEFS";
+ char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+
+ // Look for line breaks ('\n') and display each text line
+ // on a separate line, prefixed with the header, like logcat does.
+ do {
+ nl = strchr(msg, '\n');
+ if (nl != nullptr) {
+ *nl = '\0';
+ ++nl;
+ }
+
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n", timeBuf,
+ log_entry.entry.nsec / 1000000, log_entry.entry.pid, log_entry.entry.tid, prioChar, tag,
+ msg);
+ } while ((msg = nl));
+ }
+
+ android_logger_list_free(logger_list);
+}
+
+// Dumps the logs generated by the specified pid to the tombstone, from both
+// "system" and "main" log devices. Ideally we'd interleave the output.
+static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
+ if (pid == getpid()) {
+ // Cowardly refuse to dump logs while we're running in-process.
+ return;
+ }
+
+ dump_log_file(log, pid, "system", tail);
+ dump_log_file(log, pid, "main", tail);
+}
+
void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_msg_address,
siginfo_t* siginfo, ucontext_t* ucontext) {
pid_t uid = getuid();
@@ -74,40 +582,22 @@ void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_m
std::map<pid_t, ThreadInfo> threads;
threads[tid] = ThreadInfo{
- .registers = std::move(regs), .uid = uid, .tid = tid, .thread_name = std::move(thread_name),
- .pid = pid, .command_line = std::move(command_line), .selinux_label = std::move(selinux_label),
- .siginfo = siginfo,
-#if defined(__aarch64__)
- // Only supported on aarch64 for now.
- .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
- .pac_enabled_keys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0),
-#endif
+ .registers = std::move(regs),
+ .uid = uid,
+ .tid = tid,
+ .thread_name = std::move(thread_name),
+ .pid = pid,
+ .command_line = std::move(command_line),
+ .selinux_label = std::move(selinux_label),
+ .siginfo = siginfo,
};
- if (pid == tid) {
- const ThreadInfo& thread = threads[pid];
- if (!iterate_tids(pid, [&threads, &thread](pid_t tid) {
- threads[tid] = ThreadInfo{
- .uid = thread.uid,
- .tid = tid,
- .pid = thread.pid,
- .command_line = thread.command_line,
- .thread_name = get_thread_name(tid),
- .tagged_addr_ctrl = thread.tagged_addr_ctrl,
- .pac_enabled_keys = thread.pac_enabled_keys,
- };
- })) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to open /proc/%d/task: %s", pid,
- strerror(errno));
- }
- }
+ unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
auto process_memory =
unwindstack::Memory::CreateProcessMemoryCached(getpid());
- unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch(), nullptr,
- process_memory);
+ unwinder.SetProcessMemory(process_memory);
if (!unwinder.Init()) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to init unwinder object");
- return;
+ async_safe_fatal("failed to init unwinder object");
}
ProcessInfo process_info;
@@ -137,7 +627,45 @@ void engrave_tombstone(unique_fd output_fd, unique_fd proto_fd, unwindstack::Unw
log.tfd = output_fd.get();
log.amfd_data = amfd_data;
- tombstone_proto_to_text(tombstone, [&log](const std::string& line, bool should_log) {
- _LOG(&log, should_log ? logtype::HEADER : logtype::LOGS, "%s\n", line.c_str());
- });
+ bool translate_proto = GetBoolProperty("debug.debuggerd.translate_proto_to_text", true);
+ if (translate_proto) {
+ tombstone_proto_to_text(tombstone, [&log](const std::string& line, bool should_log) {
+ _LOG(&log, should_log ? logtype::HEADER : logtype::LOGS, "%s\n", line.c_str());
+ });
+ } else {
+ bool want_logs = GetBoolProperty("ro.debuggable", false);
+
+ _LOG(&log, logtype::HEADER,
+ "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
+ dump_header_info(&log);
+ _LOG(&log, logtype::HEADER, "Timestamp: %s\n", get_timestamp().c_str());
+
+ auto it = threads.find(target_thread);
+ if (it == threads.end()) {
+ async_safe_fatal("failed to find target thread");
+ }
+
+ dump_thread(&log, unwinder, it->second, process_info, true);
+
+ if (want_logs) {
+ dump_logs(&log, it->second.pid, 50);
+ }
+
+ for (auto& [tid, thread_info] : threads) {
+ if (tid == target_thread) {
+ continue;
+ }
+
+ dump_thread(&log, unwinder, thread_info, process_info, false);
+ }
+
+ if (open_files) {
+ _LOG(&log, logtype::OPEN_FILES, "\nopen files:\n");
+ dump_open_files_list(&log, *open_files, " ");
+ }
+
+ if (want_logs) {
+ dump_logs(&log, it->second.pid, 0);
+ }
+ }
}
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index bd05837a5..ff12017f7 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -18,9 +18,7 @@
#include "libdebuggerd/tombstone.h"
#include "libdebuggerd/gwp_asan.h"
-#if defined(USE_SCUDO)
#include "libdebuggerd/scudo.h"
-#endif
#include <errno.h>
#include <fcntl.h>
@@ -30,18 +28,15 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
-#include <sys/sysinfo.h>
#include <time.h>
#include <memory>
#include <optional>
-#include <set>
#include <string>
#include <async_safe/log.h>
#include <android-base/file.h>
-#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -49,7 +44,6 @@
#include <android/log.h>
#include <bionic/macros.h>
-#include <bionic/reserved_signals.h>
#include <log/log.h>
#include <log/log_read.h>
#include <log/logprint.h>
@@ -105,7 +99,7 @@ static std::optional<std::string> get_stack_overflow_cause(uint64_t fault_addr,
// In this case, the sp will be in either an invalid map if triggered
// on the main thread, or in a guard map if in another thread, which
// will be the first case or second case from below.
- std::shared_ptr<unwindstack::MapInfo> map_info = maps->Find(sp);
+ unwindstack::MapInfo* map_info = maps->Find(sp);
if (map_info == nullptr) {
return "stack pointer is in a non-existent map; likely due to stack overflow.";
} else if ((map_info->flags() & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
@@ -191,13 +185,11 @@ void set_human_readable_cause(Cause* cause, uint64_t fault_addr) {
static void dump_probable_cause(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
const ProcessInfo& process_info, const ThreadInfo& main_thread) {
-#if defined(USE_SCUDO)
ScudoCrashData scudo_crash_data(unwinder->GetProcessMemory().get(), process_info);
if (scudo_crash_data.CrashIsMine()) {
scudo_crash_data.AddCauseProtos(tombstone, unwinder);
return;
}
-#endif
GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(), process_info,
main_thread);
@@ -228,7 +220,7 @@ static void dump_probable_cause(Tombstone* tombstone, unwindstack::Unwinder* unw
cause = get_stack_overflow_cause(fault_addr, main_thread.registers->sp(), maps);
}
} else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
- auto map_info = maps->Find(fault_addr);
+ unwindstack::MapInfo* map_info = maps->Find(fault_addr);
if (map_info != nullptr && map_info->flags() == PROT_EXEC) {
cause = "execute-only (no-read) memory access error; likely due to data in .text.";
} else {
@@ -279,13 +271,6 @@ static void dump_abort_message(Tombstone* tombstone, unwindstack::Unwinder* unwi
return;
}
- // Remove any trailing newlines.
- size_t index = msg.size();
- while (index > 0 && (msg[index - 1] == '\0' || msg[index - 1] == '\n')) {
- --index;
- }
- msg.resize(index);
-
tombstone->set_abort_message(msg);
}
@@ -314,7 +299,8 @@ static void dump_open_fds(Tombstone* tombstone, const OpenFilesList* open_files)
}
}
-void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& frame) {
+void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& frame,
+ unwindstack::Maps* maps) {
f->set_rel_pc(frame.rel_pc);
f->set_pc(frame.pc);
f->set_sp(frame.sp);
@@ -332,155 +318,122 @@ void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& fr
f->set_function_offset(frame.function_offset);
- if (frame.map_info == nullptr) {
+ if (frame.map_start == frame.map_end) {
// No valid map associated with this frame.
f->set_file_name("<unknown>");
- return;
- }
-
- if (!frame.map_info->name().empty()) {
- f->set_file_name(frame.map_info->GetFullName());
+ } else if (!frame.map_name.empty()) {
+ f->set_file_name(frame.map_name);
} else {
- f->set_file_name(StringPrintf("<anonymous:%" PRIx64 ">", frame.map_info->start()));
+ f->set_file_name(StringPrintf("<anonymous:%" PRIx64 ">", frame.map_start));
}
- f->set_file_map_offset(frame.map_info->elf_start_offset());
- f->set_build_id(frame.map_info->GetPrintableBuildID());
-}
+ f->set_file_map_offset(frame.map_elf_start_offset);
-static void dump_registers(unwindstack::Unwinder* unwinder,
- const std::unique_ptr<unwindstack::Regs>& regs, Thread& thread,
- bool memory_dump) {
- if (regs == nullptr) {
- return;
+ unwindstack::MapInfo* map_info = maps->Find(frame.map_start);
+ if (map_info) {
+ f->set_build_id(map_info->GetPrintableBuildID());
}
+}
- unwindstack::Maps* maps = unwinder->GetMaps();
- unwindstack::Memory* memory = unwinder->GetProcessMemory().get();
-
- regs->IterateRegisters([&thread, memory_dump, maps, memory](const char* name, uint64_t value) {
- Register r;
- r.set_name(name);
- r.set_u64(value);
- *thread.add_registers() = r;
-
- if (memory_dump) {
- MemoryDump dump;
+static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
+ const ThreadInfo& thread_info, bool memory_dump = false) {
+ Thread thread;
- dump.set_register_name(name);
- std::shared_ptr<unwindstack::MapInfo> map_info = maps->Find(untag_address(value));
- if (map_info) {
- dump.set_mapping_name(map_info->name());
- }
+ thread.set_id(thread_info.tid);
+ thread.set_name(thread_info.thread_name);
+ thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl);
- constexpr size_t kNumBytesAroundRegister = 256;
- constexpr size_t kNumTagsAroundRegister = kNumBytesAroundRegister / kTagGranuleSize;
- char buf[kNumBytesAroundRegister];
- uint8_t tags[kNumTagsAroundRegister];
- ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory);
- if (bytes == -1) {
- return;
- }
- dump.set_begin_address(value);
- dump.set_memory(buf, bytes);
+ unwindstack::Maps* maps = unwinder->GetMaps();
+ unwindstack::Memory* memory = unwinder->GetProcessMemory().get();
- bool has_tags = false;
+ thread_info.registers->IterateRegisters(
+ [&thread, memory_dump, maps, memory](const char* name, uint64_t value) {
+ Register r;
+ r.set_name(name);
+ r.set_u64(value);
+ *thread.add_registers() = r;
+
+ if (memory_dump) {
+ MemoryDump dump;
+
+ dump.set_register_name(name);
+ unwindstack::MapInfo* map_info = maps->Find(untag_address(value));
+ if (map_info) {
+ dump.set_mapping_name(map_info->name());
+ }
+
+ constexpr size_t kNumBytesAroundRegister = 256;
+ constexpr size_t kNumTagsAroundRegister = kNumBytesAroundRegister / kTagGranuleSize;
+ char buf[kNumBytesAroundRegister];
+ uint8_t tags[kNumTagsAroundRegister];
+ size_t start_offset = 0;
+ ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory);
+ if (bytes == -1) {
+ return;
+ }
+ dump.set_begin_address(value);
+
+ if (start_offset + bytes > sizeof(buf)) {
+ async_safe_fatal("dump_memory overflowed? start offset = %zu, bytes read = %zd",
+ start_offset, bytes);
+ }
+
+ dump.set_memory(buf, bytes);
+
+ bool has_tags = false;
#if defined(__aarch64__)
- for (size_t i = 0; i < kNumTagsAroundRegister; ++i) {
- if (tags[i] != 0) {
- has_tags = true;
- }
- }
+ for (size_t i = 0; i < kNumTagsAroundRegister; ++i) {
+ if (tags[i] != 0) {
+ has_tags = true;
+ }
+ }
#endif // defined(__aarch64__)
- if (has_tags) {
- dump.mutable_arm_mte_metadata()->set_memory_tags(tags, kNumTagsAroundRegister);
- }
-
- *thread.add_memory_dump() = std::move(dump);
- }
- });
-}
+ if (has_tags) {
+ dump.mutable_arm_mte_metadata()->set_memory_tags(tags, kNumTagsAroundRegister);
+ }
-static void log_unwinder_error(unwindstack::Unwinder* unwinder) {
- if (unwinder->LastErrorCode() == unwindstack::ERROR_NONE) {
- return;
- }
-
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error code: %s",
- unwinder->LastErrorCodeString());
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error address: 0x%" PRIx64,
- unwinder->LastErrorAddress());
-}
+ *thread.add_memory_dump() = std::move(dump);
+ }
+ });
-static void dump_thread_backtrace(unwindstack::Unwinder* unwinder, Thread& thread) {
+ std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
+ unwinder->SetRegs(regs_copy.get());
+ unwinder->Unwind();
if (unwinder->NumFrames() == 0) {
async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind");
- log_unwinder_error(unwinder);
- return;
- }
-
- unwinder->SetDisplayBuildID(true);
- std::set<std::string> unreadable_elf_files;
- for (const auto& frame : unwinder->frames()) {
- BacktraceFrame* f = thread.add_current_backtrace();
- fill_in_backtrace_frame(f, frame);
- if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
- unreadable_elf_files.emplace(frame.map_info->name());
+ if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error code: %s",
+ unwinder->LastErrorCodeString());
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error address: 0x%" PRIx64,
+ unwinder->LastErrorAddress());
}
- }
-
- if (!unreadable_elf_files.empty()) {
- auto unreadable_elf_files_proto = thread.mutable_unreadable_elf_files();
- auto backtrace_note = thread.mutable_backtrace_note();
- *backtrace_note->Add() =
- "Function names and BuildId information is missing for some frames due";
- *backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries";
- *backtrace_note->Add() = "found under the lib/ directory are readable.";
- *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable.";
- *backtrace_note->Add() = "Unreadable libraries:";
- for (auto& name : unreadable_elf_files) {
- *backtrace_note->Add() = " " + name;
- *unreadable_elf_files_proto->Add() = name;
+ } else {
+ if (unwinder->elf_from_memory_not_file()) {
+ auto backtrace_note = thread.mutable_backtrace_note();
+ *backtrace_note->Add() =
+ "Function names and BuildId information is missing for some frames due";
+ *backtrace_note->Add() =
+ "to unreadable libraries. For unwinds of apps, only shared libraries";
+ *backtrace_note->Add() = "found under the lib/ directory are readable.";
+ *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable.";
}
- }
-}
-
-static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
- const ThreadInfo& thread_info, bool memory_dump = false) {
- Thread thread;
-
- thread.set_id(thread_info.tid);
- thread.set_name(thread_info.thread_name);
- thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl);
- thread.set_pac_enabled_keys(thread_info.pac_enabled_keys);
-
- if (thread_info.registers == nullptr) {
- // Fallback path for non-main thread, doing unwind from running process.
- unwindstack::ThreadUnwinder thread_unwinder(kMaxFrames, unwinder->GetMaps());
- if (!thread_unwinder.Init()) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
- "Unable to initialize ThreadUnwinder object.");
- log_unwinder_error(&thread_unwinder);
- return;
+ unwinder->SetDisplayBuildID(true);
+ for (const auto& frame : unwinder->frames()) {
+ BacktraceFrame* f = thread.add_current_backtrace();
+ fill_in_backtrace_frame(f, frame, maps);
}
-
- std::unique_ptr<unwindstack::Regs> initial_regs;
- thread_unwinder.UnwindWithSignal(BIONIC_SIGNAL_BACKTRACE, thread_info.tid, &initial_regs);
- dump_registers(&thread_unwinder, initial_regs, thread, memory_dump);
- dump_thread_backtrace(&thread_unwinder, thread);
- } else {
- dump_registers(unwinder, thread_info.registers, thread, memory_dump);
- std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
- unwinder->SetRegs(regs_copy.get());
- unwinder->Unwind();
- dump_thread_backtrace(unwinder, thread);
}
auto& threads = *tombstone->mutable_threads();
threads[thread_info.tid] = thread;
}
+static void dump_main_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
+ const ThreadInfo& thread_info) {
+ dump_thread(tombstone, unwinder, thread_info, true);
+}
+
static void dump_mappings(Tombstone* tombstone, unwindstack::Unwinder* unwinder) {
unwindstack::Maps* maps = unwinder->GetMaps();
std::shared_ptr<unwindstack::Memory> process_memory = unwinder->GetProcessMemory();
@@ -636,6 +589,14 @@ static void dump_tags_around_fault_addr(Signal* signal, const Tombstone& tombsto
}
}
+static std::optional<uint64_t> read_uptime_secs() {
+ std::string uptime;
+ if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
+ return {};
+ }
+ return strtoll(uptime.c_str(), nullptr, 10);
+}
+
void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
const ProcessInfo& process_info, const OpenFilesList* open_files) {
@@ -646,25 +607,27 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind
result.set_revision(android::base::GetProperty("ro.revision", "unknown"));
result.set_timestamp(get_timestamp());
+ std::optional<uint64_t> system_uptime = read_uptime_secs();
+ if (system_uptime) {
+ android::procinfo::ProcessInfo proc_info;
+ std::string error;
+ if (android::procinfo::GetProcessInfo(target_thread, &proc_info, &error)) {
+ uint64_t starttime = proc_info.starttime / sysconf(_SC_CLK_TCK);
+ result.set_process_uptime(*system_uptime - starttime);
+ } else {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to read process info: %s",
+ error.c_str());
+ }
+ } else {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to read /proc/uptime: %s",
+ strerror(errno));
+ }
+
const ThreadInfo& main_thread = threads.at(target_thread);
result.set_pid(main_thread.pid);
result.set_tid(main_thread.tid);
result.set_uid(main_thread.uid);
result.set_selinux_label(main_thread.selinux_label);
- // The main thread must have a valid siginfo.
- CHECK(main_thread.siginfo != nullptr);
-
- struct sysinfo si;
- sysinfo(&si);
- android::procinfo::ProcessInfo proc_info;
- std::string error;
- if (android::procinfo::GetProcessInfo(main_thread.pid, &proc_info, &error)) {
- uint64_t starttime = proc_info.starttime / sysconf(_SC_CLK_TCK);
- result.set_process_uptime(si.uptime - starttime);
- } else {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to read process info: %s",
- error.c_str());
- }
auto cmd_line = result.mutable_command_line();
for (const auto& arg : main_thread.command_line) {
@@ -698,8 +661,7 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind
dump_abort_message(&result, unwinder, process_info);
- // Dump the main thread, but save the memory around the registers.
- dump_thread(&result, unwinder, main_thread, /* memory_dump */ true);
+ dump_main_thread(&result, unwinder, main_thread);
for (const auto& [tid, thread_info] : threads) {
if (tid != target_thread) {
diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
index 026564112..053299a81 100644
--- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
@@ -82,12 +82,7 @@ static void print_thread_header(CallbackType callback, const Tombstone& tombston
thread.name().c_str(), process_name);
CB(should_log, "uid: %d", tombstone.uid());
if (thread.tagged_addr_ctrl() != -1) {
- CB(should_log, "tagged_addr_ctrl: %016" PRIx64 "%s", thread.tagged_addr_ctrl(),
- describe_tagged_addr_ctrl(thread.tagged_addr_ctrl()).c_str());
- }
- if (thread.pac_enabled_keys() != -1) {
- CB(should_log, "pac_enabled_keys: %016" PRIx64 "%s", thread.pac_enabled_keys(),
- describe_pac_enabled_keys(thread.pac_enabled_keys()).c_str());
+ CB(should_log, "tagged_addr_ctrl: %016" PRIx64, thread.tagged_addr_ctrl());
}
}
@@ -297,7 +292,6 @@ static void print_tag_dump(CallbackType callback, const Tombstone& tombstone) {
static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
const Thread& thread) {
- int word_size = pointer_width(tombstone);
print_thread_header(callback, tombstone, thread, true);
const Signal& signal_info = tombstone.signal_info();
@@ -313,7 +307,7 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
} else {
std::string fault_addr_desc;
if (signal_info.has_fault_address()) {
- fault_addr_desc = StringPrintf("0x%0*" PRIx64, 2 * word_size, signal_info.fault_address());
+ fault_addr_desc = StringPrintf("0x%" PRIx64, signal_info.fault_address());
} else {
fault_addr_desc = "--------";
}
@@ -337,7 +331,7 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
if (tombstone.causes_size() > 1) {
CBS("");
CBL("Note: multiple potential causes for this crash were detected, listing them in decreasing "
- "order of likelihood.");
+ "order of probability.");
}
for (const Cause& cause : tombstone.causes()) {
@@ -368,13 +362,9 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
print_thread_memory_dump(callback, tombstone, thread);
CBS("");
-
- // No memory maps to print.
- if (tombstone.memory_mappings().empty()) {
- CBS("No memory maps found");
- return;
- }
-
+ CBS("memory map (%d %s):", tombstone.memory_mappings().size(),
+ tombstone.memory_mappings().size() == 1 ? "entry" : "entries");
+ int word_size = pointer_width(tombstone);
const auto format_pointer = [word_size](uint64_t ptr) -> std::string {
if (word_size == 8) {
uint64_t top = ptr >> 32;
@@ -385,41 +375,8 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
return StringPrintf("%0*" PRIx64, word_size * 2, ptr);
};
- std::string memory_map_header =
- StringPrintf("memory map (%d %s):", tombstone.memory_mappings().size(),
- tombstone.memory_mappings().size() == 1 ? "entry" : "entries");
-
- bool has_fault_address = signal_info.has_fault_address();
- uint64_t fault_address = untag_address(signal_info.fault_address());
- bool preamble_printed = false;
- bool printed_fault_address_marker = false;
for (const auto& map : tombstone.memory_mappings()) {
- if (!preamble_printed) {
- preamble_printed = true;
- if (has_fault_address) {
- if (fault_address < map.begin_address()) {
- memory_map_header +=
- StringPrintf("\n--->Fault address falls at %s before any mapped regions",
- format_pointer(fault_address).c_str());
- printed_fault_address_marker = true;
- } else {
- memory_map_header += " (fault address prefixed with --->)";
- }
- }
- CBS("%s", memory_map_header.c_str());
- }
-
std::string line = " ";
- if (has_fault_address && !printed_fault_address_marker) {
- if (fault_address < map.begin_address()) {
- printed_fault_address_marker = true;
- CBS("--->Fault address falls at %s between mapped regions",
- format_pointer(fault_address).c_str());
- } else if (fault_address >= map.begin_address() && fault_address < map.end_address()) {
- printed_fault_address_marker = true;
- line = "--->";
- }
- }
StringAppendF(&line, "%s-%s", format_pointer(map.begin_address()).c_str(),
format_pointer(map.end_address() - 1).c_str());
StringAppendF(&line, " %s%s%s", map.read() ? "r" : "-", map.write() ? "w" : "-",
@@ -441,11 +398,6 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
CBS("%s", line.c_str());
}
-
- if (has_fault_address && !printed_fault_address_marker) {
- CBS("--->Fault address falls at %s after any mapped regions",
- format_pointer(fault_address).c_str());
- }
}
void print_logs(CallbackType callback, const Tombstone& tombstone, int tail) {
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index ecd98a4c5..2c645b542 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -28,7 +28,6 @@
#include <sys/wait.h>
#include <unistd.h>
-#include <set>
#include <string>
#include <android-base/properties.h>
@@ -42,7 +41,6 @@
#include <unwindstack/Memory.h>
#include <unwindstack/Unwinder.h>
-using android::base::StringPrintf;
using android::base::unique_fd;
bool is_allowed_in_logcat(enum logtype ltype) {
@@ -277,10 +275,9 @@ bool signal_has_si_addr(const siginfo_t* si) {
case SIGBUS:
case SIGFPE:
case SIGILL:
+ case SIGSEGV:
case SIGTRAP:
return true;
- case SIGSEGV:
- return si->si_code != SEGV_MTEAERR;
default:
return false;
}
@@ -405,8 +402,6 @@ const char* get_sigcode(const siginfo_t* si) {
case TRAP_HWBKPT: return "TRAP_HWBKPT";
case TRAP_UNK:
return "TRAP_UNDIAGNOSED";
- case TRAP_PERF:
- return "TRAP_PERF";
}
if ((si->si_code & 0xff) == SIGTRAP) {
switch ((si->si_code >> 8) & 0xff) {
@@ -428,7 +423,7 @@ const char* get_sigcode(const siginfo_t* si) {
return "PTRACE_EVENT_STOP";
}
}
- static_assert(NSIGTRAP == TRAP_PERF, "missing TRAP_* si_code");
+ static_assert(NSIGTRAP == TRAP_UNK, "missing TRAP_* si_code");
break;
}
// Then the other codes...
@@ -447,53 +442,8 @@ const char* get_sigcode(const siginfo_t* si) {
return "?";
}
-#define DESCRIBE_FLAG(flag) \
- if (value & flag) { \
- desc += ", "; \
- desc += #flag; \
- value &= ~flag; \
- }
-
-static std::string describe_end(long value, std::string& desc) {
- if (value) {
- desc += StringPrintf(", unknown 0x%lx", value);
- }
- return desc.empty() ? "" : " (" + desc.substr(2) + ")";
-}
-
-std::string describe_tagged_addr_ctrl(long value) {
- std::string desc;
- DESCRIBE_FLAG(PR_TAGGED_ADDR_ENABLE);
- DESCRIBE_FLAG(PR_MTE_TCF_SYNC);
- DESCRIBE_FLAG(PR_MTE_TCF_ASYNC);
- if (value & PR_MTE_TAG_MASK) {
- desc += StringPrintf(", mask 0x%04lx", (value & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT);
- value &= ~PR_MTE_TAG_MASK;
- }
- return describe_end(value, desc);
-}
-
-std::string describe_pac_enabled_keys(long value) {
- std::string desc;
- DESCRIBE_FLAG(PR_PAC_APIAKEY);
- DESCRIBE_FLAG(PR_PAC_APIBKEY);
- DESCRIBE_FLAG(PR_PAC_APDAKEY);
- DESCRIBE_FLAG(PR_PAC_APDBKEY);
- DESCRIBE_FLAG(PR_PAC_APGAKEY);
- return describe_end(value, desc);
-}
-
void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
- std::set<std::string> unreadable_elf_files;
- unwinder->SetDisplayBuildID(true);
- for (const auto& frame : unwinder->frames()) {
- if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
- unreadable_elf_files.emplace(frame.map_info->name());
- }
- }
-
- // Put the preamble ahead of the backtrace.
- if (!unreadable_elf_files.empty()) {
+ if (unwinder->elf_from_memory_not_file()) {
_LOG(log, logtype::BACKTRACE,
"%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
_LOG(log, logtype::BACKTRACE,
@@ -503,13 +453,10 @@ void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* pref
_LOG(log, logtype::BACKTRACE,
"%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
#endif
- _LOG(log, logtype::BACKTRACE, "%sNOTE: Unreadable libraries:\n", prefix);
- for (auto& name : unreadable_elf_files) {
- _LOG(log, logtype::BACKTRACE, "%sNOTE: %s\n", prefix, name.c_str());
- }
}
- for (const auto& frame : unwinder->frames()) {
- _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(frame).c_str());
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+ _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
}
}
diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto
index a0f2f82c6..a701212d8 100644
--- a/debuggerd/proto/tombstone.proto
+++ b/debuggerd/proto/tombstone.proto
@@ -123,13 +123,11 @@ message Thread {
string name = 2;
repeated Register registers = 3;
repeated string backtrace_note = 7;
- repeated string unreadable_elf_files = 9;
repeated BacktraceFrame current_backtrace = 4;
repeated MemoryDump memory_dump = 5;
int64 tagged_addr_ctrl = 6;
- int64 pac_enabled_keys = 8;
- reserved 10 to 999;
+ reserved 8 to 999;
}
message BacktraceFrame {
diff --git a/debuggerd/rust/tombstoned_client/Android.bp b/debuggerd/rust/tombstoned_client/Android.bp
deleted file mode 100644
index 2007f3934..000000000
--- a/debuggerd/rust/tombstoned_client/Android.bp
+++ /dev/null
@@ -1,59 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_library_static {
- name: "libtombstoned_client_wrapper",
- srcs: [
- "wrapper.cpp",
- ],
- generated_sources: [
- "libtombstoned_client_rust_bridge_code"
- ],
- header_libs: [
- "libbase_headers",
- "libdebuggerd_common_headers",
- ],
- shared_libs: [
- "libtombstoned_client",
- ],
- apex_available: ["com.android.virt"],
-}
-
-rust_defaults {
- name: "libtombstoned_client_rust_defaults",
- crate_name: "tombstoned_client",
- srcs: ["src/lib.rs"],
- edition: "2021",
- rustlibs: [
- "libcxx",
- "libthiserror",
- ],
- static_libs: [
- "libtombstoned_client_wrapper",
- ],
- shared_libs: [
- "libtombstoned_client",
- ],
-}
-
-rust_library {
- name: "libtombstoned_client_rust",
- defaults: ["libtombstoned_client_rust_defaults"],
- apex_available: ["com.android.virt"],
-}
-
-rust_test {
- name: "libtombstoned_client_rust_test",
- defaults: ["libtombstoned_client_rust_defaults"],
- require_root: true,
- test_suites: ["device-tests"],
-}
-
-genrule {
- name: "libtombstoned_client_rust_bridge_code",
- tools: ["cxxbridge"],
- cmd: "$(location cxxbridge) $(in) >> $(out)",
- srcs: ["src/lib.rs"],
- out: ["libtombstoned_client_cxx_generated.cc"],
-}
diff --git a/debuggerd/rust/tombstoned_client/src/lib.rs b/debuggerd/rust/tombstoned_client/src/lib.rs
deleted file mode 100644
index 5c8abef2c..000000000
--- a/debuggerd/rust/tombstoned_client/src/lib.rs
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2022, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Rust wrapper for tombstoned client.
-
-pub use ffi::DebuggerdDumpType;
-use std::fs::File;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
-use thiserror::Error;
-
-/// Error communicating with tombstoned.
-#[derive(Clone, Debug, Error, Eq, PartialEq)]
-#[error("Error communicating with tombstoned")]
-pub struct Error;
-
-/// File descriptors for communicating with tombstoned.
-pub struct TombstonedConnection {
- /// The socket connection to tombstoned.
- ///
- /// This is actually a Unix SOCK_SEQPACKET socket not a file, but the Rust standard library
- /// doesn't have an appropriate type and it's not really worth bringing in a dependency on `uds`
- /// or something when all we do is pass it back to C++ or close it.
- tombstoned_socket: File,
- /// The file descriptor for text output.
- pub text_output: Option<File>,
- /// The file descriptor for proto output.
- pub proto_output: Option<File>,
-}
-
-impl TombstonedConnection {
- unsafe fn from_raw_fds(
- tombstoned_socket: RawFd,
- text_output_fd: RawFd,
- proto_output_fd: RawFd,
- ) -> Self {
- Self {
- tombstoned_socket: File::from_raw_fd(tombstoned_socket),
- text_output: if text_output_fd >= 0 {
- Some(File::from_raw_fd(text_output_fd))
- } else {
- None
- },
- proto_output: if proto_output_fd >= 0 {
- Some(File::from_raw_fd(proto_output_fd))
- } else {
- None
- },
- }
- }
-
- /// Connects to tombstoned.
- pub fn connect(pid: i32, dump_type: DebuggerdDumpType) -> Result<Self, Error> {
- let mut tombstoned_socket = -1;
- let mut text_output_fd = -1;
- let mut proto_output_fd = -1;
- if ffi::tombstoned_connect_files(
- pid,
- &mut tombstoned_socket,
- &mut text_output_fd,
- &mut proto_output_fd,
- dump_type,
- ) {
- Ok(unsafe { Self::from_raw_fds(tombstoned_socket, text_output_fd, proto_output_fd) })
- } else {
- Err(Error)
- }
- }
-
- /// Notifies tombstoned that the dump is complete.
- pub fn notify_completion(&self) -> Result<(), Error> {
- if ffi::tombstoned_notify_completion(self.tombstoned_socket.as_raw_fd()) {
- Ok(())
- } else {
- Err(Error)
- }
- }
-}
-
-#[cxx::bridge]
-mod ffi {
- /// The type of dump.
- enum DebuggerdDumpType {
- /// A native backtrace.
- #[cxx_name = "kDebuggerdNativeBacktrace"]
- NativeBacktrace,
- /// A tombstone.
- #[cxx_name = "kDebuggerdTombstone"]
- Tombstone,
- /// A Java backtrace.
- #[cxx_name = "kDebuggerdJavaBacktrace"]
- JavaBacktrace,
- /// Any intercept.
- #[cxx_name = "kDebuggerdAnyIntercept"]
- AnyIntercept,
- /// A tombstone proto.
- #[cxx_name = "kDebuggerdTombstoneProto"]
- TombstoneProto,
- }
-
- unsafe extern "C++" {
- include!("wrapper.hpp");
-
- type DebuggerdDumpType;
-
- fn tombstoned_connect_files(
- pid: i32,
- tombstoned_socket: &mut i32,
- text_output_fd: &mut i32,
- proto_output_fd: &mut i32,
- dump_type: DebuggerdDumpType,
- ) -> bool;
-
- fn tombstoned_notify_completion(tombstoned_socket: i32) -> bool;
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::{io::Write, process};
-
- // Verify that we can connect to tombstoned, write something to the file descriptor it returns,
- // and notify completion, without any errors.
- #[test]
- fn test() {
- let connection =
- TombstonedConnection::connect(process::id() as i32, DebuggerdDumpType::Tombstone)
- .expect("Failed to connect to tombstoned.");
-
- assert!(connection.proto_output.is_none());
- connection
- .text_output
- .as_ref()
- .expect("No text output FD returned.")
- .write_all(b"test data")
- .expect("Failed to write to text output FD.");
-
- connection
- .notify_completion()
- .expect("Failed to notify completion.");
- }
-}
diff --git a/debuggerd/rust/tombstoned_client/wrapper.cpp b/debuggerd/rust/tombstoned_client/wrapper.cpp
deleted file mode 100644
index 749232973..000000000
--- a/debuggerd/rust/tombstoned_client/wrapper.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2022, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "wrapper.hpp"
-
-#include <android-base/unique_fd.h>
-
-#include "tombstoned/tombstoned.h"
-
-using android::base::unique_fd;
-
-bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd,
- int& proto_output_fd, DebuggerdDumpType dump_type) {
- unique_fd tombstoned_socket_unique, text_output_unique, proto_output_unique;
-
- bool result = tombstoned_connect(pid, &tombstoned_socket_unique, &text_output_unique,
- &proto_output_unique, dump_type);
- if (result) {
- tombstoned_socket = tombstoned_socket_unique.release();
- text_output_fd = text_output_unique.release();
- proto_output_fd = proto_output_unique.release();
- }
-
- return result;
-}
diff --git a/debuggerd/rust/tombstoned_client/wrapper.hpp b/debuggerd/rust/tombstoned_client/wrapper.hpp
deleted file mode 100644
index 95d386549..000000000
--- a/debuggerd/rust/tombstoned_client/wrapper.hpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2022, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <sys/types.h>
-#include "tombstoned/tombstoned.h"
-
-bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd,
- int& proto_output_fd, DebuggerdDumpType dump_type);
diff --git a/debuggerd/seccomp_policy/crash_dump.arm.policy b/debuggerd/seccomp_policy/crash_dump.arm.policy
index 8fd03c427..4eac0e92a 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm.policy
@@ -20,7 +20,6 @@ getdents64: 1
faccessat: 1
recvmsg: 1
recvfrom: 1
-sysinfo: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy
index 8241f0ee4..21887abe0 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -19,13 +19,12 @@ getdents64: 1
faccessat: 1
recvmsg: 1
recvfrom: 1
-sysinfo: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_sigaction: 1
rt_tgsigqueueinfo: 1
-prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS || arg0 == 56 || arg0 == 61
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS
madvise: 1
mprotect: arg2 in 0x1|0x2
munmap: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
index 0cb8e081d..90843fcba 100644
--- a/debuggerd/seccomp_policy/crash_dump.policy.def
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -25,7 +25,6 @@ getdents64: 1
faccessat: 1
recvmsg: 1
recvfrom: 1
-sysinfo: 1
process_vm_readv: 1
@@ -34,18 +33,10 @@ rt_sigprocmask: 1
rt_sigaction: 1
rt_tgsigqueueinfo: 1
-// this is referenced from mainline modules running on Q devices, where not all
-// of the constants used here are defined in headers, so minijail rejects them.
-// we define them here to avoid those errors.
- // constants introduced in R
#define PR_SET_VMA 0x53564d41
-#define PR_GET_TAGGED_ADDR_CTRL 56
- // constants introduced in S
-#define PR_PAC_GET_ENABLED_KEYS 61
-
#if defined(__aarch64__)
// PR_PAC_RESET_KEYS happens on aarch64 in pthread_create path.
-prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA || arg0 == PR_PAC_RESET_KEYS || arg0 == PR_GET_TAGGED_ADDR_CTRL || arg0 == PR_PAC_GET_ENABLED_KEYS
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA || arg0 == PR_PAC_RESET_KEYS
#else
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA
#endif
diff --git a/debuggerd/seccomp_policy/crash_dump.x86.policy b/debuggerd/seccomp_policy/crash_dump.x86.policy
index 8fd03c427..4eac0e92a 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86.policy
@@ -20,7 +20,6 @@ getdents64: 1
faccessat: 1
recvmsg: 1
recvfrom: 1
-sysinfo: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.x86_64.policy b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
index 281e231b0..1585cc6ee 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86_64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
@@ -19,7 +19,6 @@ getdents64: 1
faccessat: 1
recvmsg: 1
recvfrom: 1
-sysinfo: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 50558f7a3..05d805097 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -449,7 +449,7 @@ static void crash_completed(borrowed_fd sockfd, std::unique_ptr<Crash> crash) {
}
if (crash->output.text.fd == -1) {
- LOG(WARNING) << "skipping tombstone file creation due to intercept";
+ LOG(WARNING) << "missing output fd";
return;
}
diff --git a/debuggerd/tombstoned/tombstoned.rc b/debuggerd/tombstoned/tombstoned.rc
index fc43f4e5d..c39f4e4f2 100644
--- a/debuggerd/tombstoned/tombstoned.rc
+++ b/debuggerd/tombstoned/tombstoned.rc
@@ -5,4 +5,4 @@ service tombstoned /system/bin/tombstoned
socket tombstoned_crash seqpacket 0666 system system
socket tombstoned_intercept seqpacket 0666 system system
socket tombstoned_java_trace seqpacket 0666 system system
- task_profiles ServiceCapacityLow
+ writepid /dev/cpuset/system-background/tasks
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index 5c6abc94b..ce0fd30f7 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -18,7 +18,6 @@
#include <time.h>
-#include <functional>
#include <string>
#include <utility>
@@ -75,24 +74,3 @@ std::string get_timestamp() {
n = strftime(s, sz, "%z", &tm), s += n, sz -= n;
return buf;
}
-
-bool iterate_tids(pid_t pid, std::function<void(pid_t)> callback) {
- char buf[BUFSIZ];
- snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(buf), closedir);
- if (dir == nullptr) {
- return false;
- }
-
- struct dirent* entry;
- while ((entry = readdir(dir.get())) != nullptr) {
- pid_t tid = atoi(entry->d_name);
- if (tid == 0) {
- continue;
- }
- if (pid != tid) {
- callback(tid);
- }
- }
- return true;
-}
diff --git a/debuggerd/util.h b/debuggerd/util.h
index 43758702f..ec2862a2a 100644
--- a/debuggerd/util.h
+++ b/debuggerd/util.h
@@ -16,7 +16,6 @@
#pragma once
-#include <functional>
#include <string>
#include <vector>
@@ -28,4 +27,3 @@ std::string get_process_name(pid_t pid);
std::string get_thread_name(pid_t tid);
std::string get_timestamp();
-bool iterate_tids(pid_t, std::function<void(pid_t)>);
diff --git a/diagnose_usb/Android.bp b/diagnose_usb/Android.bp
index d7d87b502..cb79ffe91 100644
--- a/diagnose_usb/Android.bp
+++ b/diagnose_usb/Android.bp
@@ -7,7 +7,6 @@ cc_library_static {
cflags: ["-Wall", "-Wextra", "-Werror"],
host_supported: true,
recovery_available: true,
- min_sdk_version: "apex_inherit",
apex_available: [
"com.android.adbd",
// TODO(b/151398197) remove the below
diff --git a/diagnose_usb/OWNERS b/diagnose_usb/OWNERS
index fcd77573a..643b4489f 100644
--- a/diagnose_usb/OWNERS
+++ b/diagnose_usb/OWNERS
@@ -1 +1,2 @@
+jmgao@google.com
yabinc@google.com
diff --git a/diagnose_usb/diagnose_usb.cpp b/diagnose_usb/diagnose_usb.cpp
index 5716323ce..35edb5e05 100644
--- a/diagnose_usb/diagnose_usb.cpp
+++ b/diagnose_usb/diagnose_usb.cpp
@@ -19,9 +19,7 @@
#include <errno.h>
#include <unistd.h>
-#include <algorithm>
#include <string>
-#include <vector>
#include <android-base/stringprintf.h>
@@ -47,25 +45,9 @@ static std::string GetUdevProblem() {
return "";
}
- int ngroups = getgroups(0, nullptr);
- if (ngroups < 0) {
- perror("failed to get groups list size");
- return "";
- }
-
- std::vector<gid_t> groups(ngroups);
- ngroups = getgroups(groups.size(), groups.data());
- if (ngroups < 0) {
- perror("failed to get groups list");
- return "";
- }
-
- groups.resize(ngroups);
-
- // getgroups(2) indicates that the egid may not be included so we check it additionally just
- // to be sure.
- if (std::find(groups.begin(), groups.end(), plugdev_group->gr_gid) != groups.end() ||
- getegid() == plugdev_group->gr_gid) {
+ // getgroups(2) indicates that the GNU group_member(3) may not check the egid so we check it
+ // additionally just to be sure.
+ if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
// The user is in plugdev so the problem is likely with the udev rules.
return "missing udev rules? user is in the plugdev group";
}
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 9ae2c3782..2c70778ae 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -15,10 +15,7 @@
// This is required because no Android.bp can include a library defined in an
// Android.mk. Eventually should kill libfastboot (defined in Android.mk)
package {
- default_applicable_licenses: [
- "system_core_fastboot_license",
- "Android-Apache-2.0",
- ],
+ default_applicable_licenses: ["system_core_fastboot_license"],
}
// Added automatically by a large-scale-change that took the approach of
@@ -39,9 +36,10 @@ license {
name: "system_core_fastboot_license",
visibility: [":__subpackages__"],
license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
"SPDX-license-identifier-BSD",
],
- license_text: ["LICENSE"],
+ // large-scale-change unable to identify any license_text files
}
cc_library_host_static {
@@ -168,10 +166,8 @@ cc_binary {
"android.hardware.boot@1.1",
"android.hardware.fastboot@1.1",
"android.hardware.health@2.0",
- "android.hardware.health-V1-ndk",
"libasyncio",
"libbase",
- "libbinder_ndk",
"libbootloader_message",
"libcutils",
"libext2_uuid",
@@ -187,10 +183,8 @@ cc_binary {
],
static_libs: [
- "android.hardware.health-translate-ndk",
"libc++fs",
"libhealthhalutils",
- "libhealthshim",
"libsnapshot_cow",
"libsnapshot_nobinder",
"update_metadata-protos",
@@ -414,9 +408,3 @@ cc_test_host {
":fastboot_test_vendor_boot_v4_with_frag"
],
}
-
-cc_library_headers {
- name: "fastboot_headers",
- host_supported: true,
- export_include_dirs: ["."],
-}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 10bed6da9..0e918a35a 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,10 +18,10 @@ LOCAL_PATH:= $(call my-dir)
# Package fastboot-related executables.
#
-my_dist_files := $(HOST_OUT_EXECUTABLES)/mke2fs
-my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
-my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
-my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs_casefold
-my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
-$(call dist-for-goals,dist_files sdk,$(my_dist_files))
+my_dist_files := $(SOONG_HOST_OUT_EXECUTABLES)/mke2fs
+my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/e2fsdroid
+my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/make_f2fs
+my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/make_f2fs_casefold
+my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/sload_f2fs
+$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
my_dist_files :=
diff --git a/fastboot/LICENSE b/fastboot/LICENSE
deleted file mode 100644
index f0a0e52d6..000000000
--- a/fastboot/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
index 17b34668c..a72ee070f 100644
--- a/fastboot/OWNERS
+++ b/fastboot/OWNERS
@@ -1,3 +1,4 @@
dvander@google.com
-elsk@google.com
+hridya@google.com
enh@google.com
+jmgao@google.com
diff --git a/fastboot/README.md b/fastboot/README.md
index d3b6c1ae7..c22444803 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -27,16 +27,16 @@ Linux, macOS, or Windows.
1. Host sends a command, which is an ascii string in a single
packet no greater than 64 bytes.
-2. Client response with a single packet no greater than 256 bytes.
+2. Client response with a single packet no greater than 64 bytes.
The first four bytes of the response are "OKAY", "FAIL", "DATA",
or "INFO". Additional bytes may contain an (ascii) informative
message.
- a. INFO -> the remaining 252 bytes are an informative message
+ a. INFO -> the remaining 60 bytes are an informative message
(providing progress or diagnostic messages). They should
be displayed and then step #2 repeats
- b. FAIL -> the requested command failed. The remaining 252 bytes
+ b. FAIL -> the requested command failed. The remaining 60 bytes
of the response (if present) provide a textual failure message
to present to the user. Stop.
@@ -53,13 +53,13 @@ Linux, macOS, or Windows.
until the client has sent or received the number of bytes indicated
in the "DATA" response above.
-4. Client responds with a single packet no greater than 256 bytes.
+4. Client responds with a single packet no greater than 64 bytes.
The first four bytes of the response are "OKAY", "FAIL", or "INFO".
Similar to #2:
- a. INFO -> display the remaining 252 bytes and return to #4
+ a. INFO -> display the remaining 60 bytes and return to #4
- b. FAIL -> display the remaining 252 bytes (if present) as a failure
+ b. FAIL -> display the remaining 60 bytes (if present) as a failure
reason and consider the command failed. Stop.
c. OKAY -> success. Go to #5
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index b9f6c973c..0a72812c2 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -268,18 +268,10 @@ bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& arg
}
// arg[0] is the command name, arg[1] contains size of data to be downloaded
- // which should always be 8 bytes
- if (args[1].length() != 8) {
- return device->WriteStatus(FastbootResult::FAIL,
- "Invalid size (length of size != 8)");
- }
unsigned int size;
if (!android::base::ParseUint("0x" + args[1], &size, kMaxDownloadSizeDefault)) {
return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
}
- if (size == 0) {
- return device->WriteStatus(FastbootResult::FAIL, "Invalid size (0)");
- }
device->download_data().resize(size);
if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
return false;
@@ -733,7 +725,7 @@ class PartitionFetcher {
return false;
}
- if (!OpenPartition(device_, partition_name_, &handle_, O_RDONLY)) {
+ if (!OpenPartition(device_, partition_name_, &handle_, true /* read */)) {
ret_ = device_->WriteFail(
android::base::StringPrintf("Cannot open %s", partition_name_.c_str()));
return false;
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index ae225debc..64a934ddb 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -21,12 +21,10 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <android/binder_manager.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/fastboot/1.1/IFastboot.h>
#include <fs_mgr.h>
#include <fs_mgr/roots.h>
-#include <health-shim/shim.h>
#include <healthhalutils/HealthHalUtils.h>
#include "constants.h"
@@ -34,36 +32,16 @@
#include "tcp_client.h"
#include "usb_client.h"
-using std::string_literals::operator""s;
using android::fs_mgr::EnsurePathUnmounted;
using android::fs_mgr::Fstab;
using ::android::hardware::hidl_string;
using ::android::hardware::boot::V1_0::IBootControl;
using ::android::hardware::boot::V1_0::Slot;
using ::android::hardware::fastboot::V1_1::IFastboot;
+using ::android::hardware::health::V2_0::get_health_service;
namespace sph = std::placeholders;
-std::shared_ptr<aidl::android::hardware::health::IHealth> get_health_service() {
- using aidl::android::hardware::health::IHealth;
- using HidlHealth = android::hardware::health::V2_0::IHealth;
- using aidl::android::hardware::health::HealthShim;
- auto service_name = IHealth::descriptor + "/default"s;
- if (AServiceManager_isDeclared(service_name.c_str())) {
- ndk::SpAIBinder binder(AServiceManager_waitForService(service_name.c_str()));
- std::shared_ptr<IHealth> health = IHealth::fromBinder(binder);
- if (health != nullptr) return health;
- LOG(WARNING) << "AIDL health service is declared, but it cannot be retrieved.";
- }
- LOG(INFO) << "Unable to get AIDL health service, trying HIDL...";
- android::sp<HidlHealth> hidl_health = android::hardware::health::V2_0::get_health_service();
- if (hidl_health != nullptr) {
- return ndk::SharedRefBase::make<HealthShim>(hidl_health);
- }
- LOG(WARNING) << "No health implementation is found.";
- return nullptr;
-}
-
FastbootDevice::FastbootDevice()
: kCommandMap({
{FB_CMD_SET_ACTIVE, SetActiveHandler},
@@ -186,11 +164,6 @@ void FastbootDevice::ExecuteCommands() {
PLOG(ERROR) << "Couldn't read command";
return;
}
- if (std::count_if(command, command + bytes_read, iscntrl) != 0) {
- WriteStatus(FastbootResult::FAIL,
- "Command contains control character");
- continue;
- }
command[bytes_read] = '\0';
LOG(INFO) << "Fastboot command: " << command;
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index 91ffce3d9..35361365c 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -22,10 +22,10 @@
#include <utility>
#include <vector>
-#include <aidl/android/hardware/health/IHealth.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/boot/1.1/IBootControl.h>
#include <android/hardware/fastboot/1.1/IFastboot.h>
+#include <android/hardware/health/2.0/IHealth.h>
#include "commands.h"
#include "transport.h"
@@ -57,7 +57,7 @@ class FastbootDevice {
android::sp<android::hardware::fastboot::V1_1::IFastboot> fastboot_hal() {
return fastboot_hal_;
}
- std::shared_ptr<aidl::android::hardware::health::IHealth> health_hal() { return health_hal_; }
+ android::sp<android::hardware::health::V2_0::IHealth> health_hal() { return health_hal_; }
void set_active_slot(const std::string& active_slot) { active_slot_ = active_slot; }
@@ -67,7 +67,7 @@ class FastbootDevice {
std::unique_ptr<Transport> transport_;
android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1_;
- std::shared_ptr<aidl::android::hardware::health::IHealth> health_hal_;
+ android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
android::sp<android::hardware::fastboot::V1_1::IFastboot> fastboot_hal_;
std::vector<char> download_data_;
std::string active_slot_;
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 06ffe0f68..ee0aa582b 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -16,7 +16,6 @@
#include "flashing.h"
#include <fcntl.h>
-#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -76,30 +75,11 @@ void WipeOverlayfsForPartition(FastbootDevice* device, const std::string& partit
} // namespace
-int FlashRawDataChunk(PartitionHandle* handle, const char* data, size_t len) {
+int FlashRawDataChunk(int fd, const char* data, size_t len) {
size_t ret = 0;
- const size_t max_write_size = 1048576;
- void* aligned_buffer;
-
- if (posix_memalign(&aligned_buffer, 4096, max_write_size)) {
- PLOG(ERROR) << "Failed to allocate write buffer";
- return -ENOMEM;
- }
-
- auto aligned_buffer_unique_ptr = std::unique_ptr<void, decltype(&free)>{aligned_buffer, free};
-
while (ret < len) {
- int this_len = std::min(max_write_size, len - ret);
- memcpy(aligned_buffer_unique_ptr.get(), data, this_len);
- // In case of non 4KB aligned writes, reopen without O_DIRECT flag
- if (this_len & 0xFFF) {
- if (handle->Reset(O_WRONLY) != true) {
- PLOG(ERROR) << "Failed to reset file descriptor";
- return -1;
- }
- }
-
- int this_ret = write(handle->fd(), aligned_buffer_unique_ptr.get(), this_len);
+ int this_len = std::min(static_cast<size_t>(1048576UL * 8), len - ret);
+ int this_ret = write(fd, data, this_len);
if (this_ret < 0) {
PLOG(ERROR) << "Failed to flash data of len " << len;
return -1;
@@ -110,8 +90,8 @@ int FlashRawDataChunk(PartitionHandle* handle, const char* data, size_t len) {
return 0;
}
-int FlashRawData(PartitionHandle* handle, const std::vector<char>& downloaded_data) {
- int ret = FlashRawDataChunk(handle, downloaded_data.data(), downloaded_data.size());
+int FlashRawData(int fd, const std::vector<char>& downloaded_data) {
+ int ret = FlashRawDataChunk(fd, downloaded_data.data(), downloaded_data.size());
if (ret < 0) {
return -errno;
}
@@ -119,30 +99,28 @@ int FlashRawData(PartitionHandle* handle, const std::vector<char>& downloaded_da
}
int WriteCallback(void* priv, const void* data, size_t len) {
- PartitionHandle* handle = reinterpret_cast<PartitionHandle*>(priv);
+ int fd = reinterpret_cast<long long>(priv);
if (!data) {
- return lseek64(handle->fd(), len, SEEK_CUR) >= 0 ? 0 : -errno;
+ return lseek64(fd, len, SEEK_CUR) >= 0 ? 0 : -errno;
}
- return FlashRawDataChunk(handle, reinterpret_cast<const char*>(data), len);
+ return FlashRawDataChunk(fd, reinterpret_cast<const char*>(data), len);
}
-int FlashSparseData(PartitionHandle* handle, std::vector<char>& downloaded_data) {
- struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(),
- downloaded_data.size(), true, false);
+int FlashSparseData(int fd, std::vector<char>& downloaded_data) {
+ struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(), true, false);
if (!file) {
- // Invalid sparse format
- return -EINVAL;
+ return -ENOENT;
}
- return sparse_file_callback(file, false, false, WriteCallback, reinterpret_cast<void*>(handle));
+ return sparse_file_callback(file, false, false, WriteCallback, reinterpret_cast<void*>(fd));
}
-int FlashBlockDevice(PartitionHandle* handle, std::vector<char>& downloaded_data) {
- lseek64(handle->fd(), 0, SEEK_SET);
+int FlashBlockDevice(int fd, std::vector<char>& downloaded_data) {
+ lseek64(fd, 0, SEEK_SET);
if (downloaded_data.size() >= sizeof(SPARSE_HEADER_MAGIC) &&
*reinterpret_cast<uint32_t*>(downloaded_data.data()) == SPARSE_HEADER_MAGIC) {
- return FlashSparseData(handle, downloaded_data);
+ return FlashSparseData(fd, downloaded_data);
} else {
- return FlashRawData(handle, downloaded_data);
+ return FlashRawData(fd, downloaded_data);
}
}
@@ -169,7 +147,7 @@ static void CopyAVBFooter(std::vector<char>* data, const uint64_t block_device_s
int Flash(FastbootDevice* device, const std::string& partition_name) {
PartitionHandle handle;
- if (!OpenPartition(device, partition_name, &handle, O_WRONLY | O_DIRECT)) {
+ if (!OpenPartition(device, partition_name, &handle)) {
return -ENOENT;
}
@@ -182,23 +160,17 @@ int Flash(FastbootDevice* device, const std::string& partition_name) {
return -EOVERFLOW;
} else if (data.size() < block_device_size &&
(partition_name == "boot" || partition_name == "boot_a" ||
- partition_name == "boot_b" || partition_name == "init_boot" ||
- partition_name == "init_boot_a" || partition_name == "init_boot_b")) {
+ partition_name == "boot_b")) {
CopyAVBFooter(&data, block_device_size);
}
if (android::base::GetProperty("ro.system.build.type", "") != "user") {
WipeOverlayfsForPartition(device, partition_name);
}
- int result = FlashBlockDevice(&handle, data);
+ int result = FlashBlockDevice(handle.fd(), data);
sync();
return result;
}
-static void RemoveScratchPartition() {
- AutoMountMetadata mount_metadata;
- android::fs_mgr::TeardownAllOverlayForMountPoint();
-}
-
bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wipe) {
std::vector<char> data = std::move(device->download_data());
if (data.empty()) {
@@ -215,37 +187,27 @@ bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wip
", build may be missing broken or missing boot_devices");
}
- std::string slot_suffix = device->GetCurrentSlot();
- uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
-
- std::string other_slot_suffix;
- if (!slot_suffix.empty()) {
- other_slot_suffix = (slot_suffix == "_a") ? "_b" : "_a";
- }
-
// If we are unable to read the existing metadata, then the super partition
// is corrupt. In this case we reflash the whole thing using the provided
// image.
+ std::string slot_suffix = device->GetCurrentSlot();
+ uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
std::unique_ptr<LpMetadata> old_metadata = ReadMetadata(super_name, slot_number);
if (wipe || !old_metadata) {
if (!FlashPartitionTable(super_name, *new_metadata.get())) {
return device->WriteFail("Unable to flash new partition table");
}
- RemoveScratchPartition();
+ android::fs_mgr::TeardownAllOverlayForMountPoint();
sync();
return device->WriteOkay("Successfully flashed partition table");
}
std::set<std::string> partitions_to_keep;
- bool virtual_ab = android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
for (const auto& partition : old_metadata->partitions) {
// Preserve partitions in the other slot, but not the current slot.
std::string partition_name = GetPartitionName(partition);
- if (!slot_suffix.empty()) {
- auto part_suffix = GetPartitionSlotSuffix(partition_name);
- if (part_suffix == slot_suffix || (part_suffix == other_slot_suffix && virtual_ab)) {
- continue;
- }
+ if (!slot_suffix.empty() && GetPartitionSlotSuffix(partition_name) == slot_suffix) {
+ continue;
}
std::string group_name = GetPartitionGroupName(old_metadata->groups[partition.group_index]);
// Skip partitions in the COW group
@@ -275,7 +237,7 @@ bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wip
if (!UpdateAllPartitionMetadata(device, super_name, *new_metadata.get())) {
return device->WriteFail("Unable to write new partition table");
}
- RemoveScratchPartition();
+ android::fs_mgr::TeardownAllOverlayForMountPoint();
sync();
return device->WriteOkay("Successfully updated partition table");
}
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 3302c4310..07ad9028c 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -78,7 +78,7 @@ bool OpenLogicalPartition(FastbootDevice* device, const std::string& partition_n
} // namespace
bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle,
- int flags) {
+ bool read) {
// We prioritize logical partitions over physical ones, and do this
// consistently for other partition operations (like getvar:partition-size).
if (LogicalPartitionExists(device, name)) {
@@ -90,7 +90,15 @@ bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHan
return false;
}
- return handle->Open(flags);
+ int flags = (read ? O_RDONLY : O_WRONLY);
+ flags |= (O_EXCL | O_CLOEXEC | O_BINARY);
+ unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), flags)));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open block device: " << handle->path();
+ return false;
+ }
+ handle->set_fd(std::move(fd));
+ return true;
}
std::optional<std::string> FindPhysicalPartition(const std::string& name) {
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
index 6e1453f83..c2646d718 100644
--- a/fastboot/device/utility.h
+++ b/fastboot/device/utility.h
@@ -18,8 +18,6 @@
#include <optional>
#include <string>
-#include <android-base/file.h>
-#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <fstab/fstab.h>
@@ -46,51 +44,11 @@ class PartitionHandle {
}
const std::string& path() const { return path_; }
int fd() const { return fd_.get(); }
- bool Open(int flags) {
- flags |= (O_EXCL | O_CLOEXEC | O_BINARY);
+ void set_fd(android::base::unique_fd&& fd) { fd_ = std::move(fd); }
- // Attempts to open a second device can fail with EBUSY if the device is already open.
- // Explicitly close any previously opened devices as unique_fd won't close them until
- // after the attempt to open.
- fd_.reset();
-
- fd_ = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path_.c_str(), flags)));
- if (fd_ < 0) {
- PLOG(ERROR) << "Failed to open block device: " << path_;
- return false;
- }
- flags_ = flags;
-
- return true;
- }
- bool Reset(int flags) {
- if (fd_.ok() && (flags | O_EXCL | O_CLOEXEC | O_BINARY) == flags_) {
- return true;
- }
-
- off_t offset = fd_.ok() ? lseek(fd_.get(), 0, SEEK_CUR) : 0;
- if (offset < 0) {
- PLOG(ERROR) << "Failed lseek on block device: " << path_;
- return false;
- }
-
- sync();
-
- if (Open(flags) == false) {
- return false;
- }
-
- if (lseek(fd_.get(), offset, SEEK_SET) != offset) {
- PLOG(ERROR) << "Failed lseek on block device: " << path_;
- return false;
- }
-
- return true;
- }
private:
std::string path_;
android::base::unique_fd fd_;
- int flags_;
std::function<void()> closer_;
};
@@ -118,11 +76,9 @@ std::optional<std::string> FindPhysicalPartition(const std::string& name);
bool LogicalPartitionExists(FastbootDevice* device, const std::string& name,
bool* is_zero_length = nullptr);
-// Partition is O_WRONLY by default, caller should pass O_RDONLY for reading.
-// Caller may pass additional flags if needed. (O_EXCL | O_CLOEXEC | O_BINARY)
-// will be logically ORed internally.
+// If read, partition is readonly. Else it is write only.
bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle,
- int flags = O_WRONLY);
+ bool read = false);
bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number);
std::vector<std::string> ListPartitions(FastbootDevice* device);
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 0cf4699aa..ee1eed876 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -26,6 +26,7 @@
#include <android/hardware/boot/1.1/IBootControl.h>
#include <ext4_utils/ext4_utils.h>
#include <fs_mgr.h>
+#include <healthhalutils/HealthHalUtils.h>
#include <liblp/liblp.h>
#include "fastboot_device.h"
@@ -119,17 +120,23 @@ bool GetVariant(FastbootDevice* device, const std::vector<std::string>& /* args
}
bool GetBatteryVoltageHelper(FastbootDevice* device, int32_t* battery_voltage) {
- using aidl::android::hardware::health::HealthInfo;
+ using android::hardware::health::V2_0::HealthInfo;
+ using android::hardware::health::V2_0::Result;
auto health_hal = device->health_hal();
if (!health_hal) {
return false;
}
- HealthInfo health_info;
- auto res = health_hal->getHealthInfo(&health_info);
- if (!res.isOk()) return false;
- *battery_voltage = health_info.batteryVoltageMillivolts;
+ Result ret;
+ auto ret_val = health_hal->getHealthInfo([&](Result result, HealthInfo info) {
+ *battery_voltage = info.legacy.batteryVoltage;
+ ret = result;
+ });
+ if (!ret_val.isOk() || (ret != Result::SUCCESS)) {
+ return false;
+ }
+
return true;
}
@@ -332,8 +339,8 @@ bool GetPartitionType(FastbootDevice* device, const std::vector<std::string>& ar
auto fastboot_hal = device->fastboot_hal();
if (!fastboot_hal) {
- *message = "raw";
- return true;
+ *message = "Fastboot HAL not found";
+ return false;
}
FileSystemType type;
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
index e9bf9e940..f5a3384cf 100644
--- a/fastboot/fastboot.bash
+++ b/fastboot/fastboot.bash
@@ -109,7 +109,7 @@ _fastboot_cmd_flash() {
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ $i -eq $COMP_CWORD ]]; then
- partitions="boot bootloader dtbo init_boot modem odm odm_dlkm oem product pvmfw radio recovery system system_dlkm vbmeta vendor vendor_dlkm"
+ partitions="boot bootloader dtbo modem odm odm_dlkm oem product pvmfw radio recovery system vbmeta vendor vendor_dlkm"
COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
else
_fastboot_util_complete_local_file "${cur}" '!*.img'
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 39d86f9b3..6a49fdf34 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -104,6 +104,8 @@ static std::string g_dtb_path;
static bool g_disable_verity = false;
static bool g_disable_verification = false;
+static const std::string convert_fbe_marker_filename("convert_fbe");
+
fastboot::FastBootDriver* fb = nullptr;
enum fb_buffer_type {
@@ -141,10 +143,6 @@ struct Image {
static Image images[] = {
// clang-format off
{ "boot", "boot.img", "boot.sig", "boot", false, ImageType::BootCritical },
- { "init_boot",
- "init_boot.img", "init_boot.sig",
- "init_boot",
- true, ImageType::BootCritical },
{ nullptr, "boot_other.img", "boot.sig", "boot", true, ImageType::Normal },
{ "cache", "cache.img", "cache.sig", "cache", true, ImageType::Extra },
{ "dtbo", "dtbo.img", "dtbo.sig", "dtbo", true, ImageType::BootCritical },
@@ -156,10 +154,6 @@ static Image images[] = {
{ "recovery", "recovery.img", "recovery.sig", "recovery", true, ImageType::BootCritical },
{ "super", "super.img", "super.sig", "super", true, ImageType::Extra },
{ "system", "system.img", "system.sig", "system", false, ImageType::Normal },
- { "system_dlkm",
- "system_dlkm.img", "system_dlkm.sig",
- "system_dlkm",
- true, ImageType::Normal },
{ "system_ext",
"system_ext.img", "system_ext.sig",
"system_ext",
@@ -435,7 +429,7 @@ static int show_help() {
" snapshot-update merge On devices that support snapshot-based updates, finish\n"
" an in-progress update if it is in the \"merging\"\n"
" phase.\n"
- " fetch PARTITION OUT_FILE Fetch a partition image from the device."
+ " fetch PARTITION Fetch a partition image from the device."
"\n"
"boot image:\n"
" boot KERNEL [RAMDISK [SECOND]]\n"
@@ -479,6 +473,9 @@ static int show_help() {
" --disable-verification Sets disable-verification when flashing vbmeta.\n"
" --fs-options=OPTION[,OPTION]\n"
" Enable filesystem features. OPTION supports casefold, projid, compress\n"
+#if !defined(_WIN32)
+ " --wipe-and-use-fbe Enable file-based encryption, wiping userdata.\n"
+#endif
// TODO: remove --unbuffered?
" --unbuffered Don't buffer input or output.\n"
" --verbose, -v Verbose output.\n"
@@ -596,6 +593,10 @@ static FILE* win32_tmpfile() {
#define tmpfile win32_tmpfile
+static std::string make_temporary_directory() {
+ die("make_temporary_directory not supported under Windows, sorry!");
+}
+
static int make_temporary_fd(const char* /*what*/) {
// TODO: reimplement to avoid leaking a FILE*.
return fileno(tmpfile());
@@ -609,6 +610,15 @@ static std::string make_temporary_template() {
return std::string(tmpdir) + "/fastboot_userdata_XXXXXX";
}
+static std::string make_temporary_directory() {
+ std::string result(make_temporary_template());
+ if (mkdtemp(&result[0]) == nullptr) {
+ die("unable to create temporary directory with template %s: %s",
+ result.c_str(), strerror(errno));
+ }
+ return result;
+}
+
static int make_temporary_fd(const char* what) {
std::string path_template(make_temporary_template());
int fd = mkstemp(&path_template[0]);
@@ -622,6 +632,32 @@ static int make_temporary_fd(const char* what) {
#endif
+static std::string create_fbemarker_tmpdir() {
+ std::string dir = make_temporary_directory();
+ std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+ int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
+ if (fd == -1) {
+ die("unable to create FBE marker file %s locally: %s",
+ marker_file.c_str(), strerror(errno));
+ }
+ close(fd);
+ return dir;
+}
+
+static void delete_fbemarker_tmpdir(const std::string& dir) {
+ std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+ if (unlink(marker_file.c_str()) == -1) {
+ fprintf(stderr, "Unable to delete FBE marker file %s locally: %d, %s\n",
+ marker_file.c_str(), errno, strerror(errno));
+ return;
+ }
+ if (rmdir(dir.c_str()) == -1) {
+ fprintf(stderr, "Unable to delete FBE marker directory %s locally: %d, %s\n",
+ dir.c_str(), errno, strerror(errno));
+ return;
+ }
+}
+
static unique_fd unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
unique_fd fd(make_temporary_fd(entry_name));
@@ -949,8 +985,7 @@ static void rewrite_vbmeta_buffer(struct fastboot_buffer* buf, bool vbmeta_in_bo
// Tries to locate top-level vbmeta from boot.img footer.
uint64_t footer_offset = buf->sz - AVB_FOOTER_SIZE;
if (0 != data.compare(footer_offset, AVB_FOOTER_MAGIC_LEN, AVB_FOOTER_MAGIC)) {
- die("Failed to find AVB_FOOTER at offset: %" PRId64 ", is BOARD_AVB_ENABLE true?",
- footer_offset);
+ die("Failed to find AVB_FOOTER at offset: %" PRId64, footer_offset);
}
const AvbFooter* footer = reinterpret_cast<const AvbFooter*>(data.c_str() + footer_offset);
vbmeta_offset = be64toh(footer->vbmeta_offset);
@@ -1025,48 +1060,37 @@ static uint64_t get_partition_size(const std::string& partition) {
return partition_size;
}
-static void copy_avb_footer(const std::string& partition, struct fastboot_buffer* buf) {
+static void copy_boot_avb_footer(const std::string& partition, struct fastboot_buffer* buf) {
if (buf->sz < AVB_FOOTER_SIZE) {
return;
}
- // If overflows and negative, it should be < buf->sz.
- int64_t partition_size = static_cast<int64_t>(get_partition_size(partition));
-
- if (partition_size == buf->sz) {
- return;
- }
- // Some device bootloaders might not implement `fastboot getvar partition-size:boot[_a|_b]`.
- // In this case, partition_size will be zero.
- if (partition_size < buf->sz) {
- fprintf(stderr,
- "Warning: skip copying %s image avb footer"
- " (%s partition size: %" PRId64 ", %s image size: %" PRId64 ").\n",
- partition.c_str(), partition.c_str(), partition_size, partition.c_str(), buf->sz);
- return;
- }
-
- // IMPORTANT: after the following read, we need to reset buf->fd before return (if not die).
- // Because buf->fd will still be used afterwards.
std::string data;
if (!android::base::ReadFdToString(buf->fd, &data)) {
- die("Failed reading from %s", partition.c_str());
+ die("Failed reading from boot");
}
uint64_t footer_offset = buf->sz - AVB_FOOTER_SIZE;
if (0 != data.compare(footer_offset, AVB_FOOTER_MAGIC_LEN, AVB_FOOTER_MAGIC)) {
- lseek(buf->fd.get(), 0, SEEK_SET); // IMPORTANT: resets buf->fd before return.
return;
}
+ // If overflows and negative, it should be < buf->sz.
+ int64_t partition_size = static_cast<int64_t>(get_partition_size(partition));
- const std::string tmp_fd_template = partition + " rewriting";
- unique_fd fd(make_temporary_fd(tmp_fd_template.c_str()));
+ if (partition_size == buf->sz) {
+ return;
+ }
+ if (partition_size < buf->sz) {
+ die("boot partition is smaller than boot image");
+ }
+
+ unique_fd fd(make_temporary_fd("boot rewriting"));
if (!android::base::WriteStringToFd(data, fd)) {
- die("Failed writing to modified %s", partition.c_str());
+ die("Failed writing to modified boot");
}
lseek(fd.get(), partition_size - AVB_FOOTER_SIZE, SEEK_SET);
if (!android::base::WriteStringToFd(data.substr(footer_offset), fd)) {
- die("Failed copying AVB footer in %s", partition.c_str());
+ die("Failed copying AVB footer in boot");
}
buf->fd = std::move(fd);
buf->sz = partition_size;
@@ -1077,18 +1101,13 @@ static void flash_buf(const std::string& partition, struct fastboot_buffer *buf)
{
sparse_file** s;
- if (partition == "boot" || partition == "boot_a" || partition == "boot_b" ||
- partition == "init_boot" || partition == "init_boot_a" || partition == "init_boot_b") {
- copy_avb_footer(partition, buf);
+ if (partition == "boot" || partition == "boot_a" || partition == "boot_b") {
+ copy_boot_avb_footer(partition, buf);
}
// Rewrite vbmeta if that's what we're flashing and modification has been requested.
if (g_disable_verity || g_disable_verification) {
- // The vbmeta partition might have additional prefix if running in virtual machine
- // e.g., guest_vbmeta_a.
- if (android::base::EndsWith(partition, "vbmeta") ||
- android::base::EndsWith(partition, "vbmeta_a") ||
- android::base::EndsWith(partition, "vbmeta_b")) {
+ if (partition == "vbmeta" || partition == "vbmeta_a" || partition == "vbmeta_b") {
rewrite_vbmeta_buffer(buf, false /* vbmeta_in_boot */);
} else if (!has_vbmeta_partition() &&
(partition == "boot" || partition == "boot_a" || partition == "boot_b")) {
@@ -1876,6 +1895,7 @@ int FastBootTool::Main(int argc, char* argv[]) {
bool skip_reboot = false;
bool wants_set_active = false;
bool skip_secondary = false;
+ bool set_fbe_marker = false;
bool force_flash = false;
unsigned fs_options = 0;
int longindex;
@@ -1913,6 +1933,9 @@ int FastBootTool::Main(int argc, char* argv[]) {
{"unbuffered", no_argument, 0, 0},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 0},
+#if !defined(_WIN32)
+ {"wipe-and-use-fbe", no_argument, 0, 0},
+#endif
{0, 0, 0, 0}
};
@@ -1966,6 +1989,11 @@ int FastBootTool::Main(int argc, char* argv[]) {
fprintf(stdout, "fastboot version %s-%s\n", PLATFORM_TOOLS_VERSION, android::build::GetBuildNumber().c_str());
fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
return 0;
+#if !defined(_WIN32)
+ } else if (name == "wipe-and-use-fbe") {
+ wants_wipe = true;
+ set_fbe_marker = true;
+#endif
} else {
die("unknown option %s", longopts[longindex].name);
}
@@ -2277,7 +2305,14 @@ int FastBootTool::Main(int argc, char* argv[]) {
}
if (partition_type.empty()) continue;
fb->Erase(partition);
- fb_perform_format(partition, 1, partition_type, "", "", fs_options);
+ if (partition == "userdata" && set_fbe_marker) {
+ fprintf(stderr, "setting FBE marker on initial userdata...\n");
+ std::string initial_userdata_dir = create_fbemarker_tmpdir();
+ fb_perform_format(partition, 1, partition_type, "", initial_userdata_dir, fs_options);
+ delete_fbemarker_tmpdir(initial_userdata_dir);
+ } else {
+ fb_perform_format(partition, 1, partition_type, "", "", fs_options);
+ }
}
}
if (wants_set_active) {
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index d268a502c..458a7a184 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -143,13 +143,6 @@ static int generate_ext4_image(const char* fileName, long long partSize,
mke2fs_args.push_back("512");
}
- if (fsOptions & (1 << FS_OPT_CASEFOLD)) {
- mke2fs_args.push_back("-O");
- mke2fs_args.push_back("casefold");
- mke2fs_args.push_back("-E");
- mke2fs_args.push_back("encoding=utf8");
- }
-
mke2fs_args.push_back(fileName);
std::string size_str = std::to_string(partSize / block_size);
diff --git a/fastboot/fuzzer/Android.bp b/fastboot/fuzzer/Android.bp
deleted file mode 100644
index 1b59e4a6e..000000000
--- a/fastboot/fuzzer/Android.bp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_fuzz {
- name: "fastboot_fuzzer",
- host_supported: true,
- device_supported: false,
- srcs: [
- "fastboot_fuzzer.cpp",
- "socket_mock_fuzz.cpp",
- ],
- header_libs: [
- "bootimg_headers",
- "fastboot_headers",
- ],
- static_libs: [
- "libext4_utils",
- "libcrypto",
- "libfastboot",
- "libbuildversion",
- "libbase",
- "libziparchive",
- "libsparse",
- "libutils",
- "liblog",
- "libz",
- "libdiagnose_usb",
- "libbase",
- "libcutils",
- "libgtest",
- "libgtest_main",
- "libbase",
- "libadb_host",
- "liblp",
- "liblog",
- ],
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 533764,
- },
-}
diff --git a/fastboot/fuzzer/README.md b/fastboot/fuzzer/README.md
deleted file mode 100644
index 10b06ea78..000000000
--- a/fastboot/fuzzer/README.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# Fuzzer for libfastboot
-
-## Plugin Design Considerations
-The fuzzer plugin for libfastboot is designed based on the understanding of the
-source code and tries to achieve the following:
-
-##### Maximize code coverage
-The configuration parameters are not hardcoded, but instead selected based on
-incoming data. This ensures more code paths are reached by the fuzzer.
-
-libfastboot supports the following parameters:
-1. Year (parameter name: `year`)
-2. Month (parameter name: `month`)
-3. Day (parameter name: `day`)
-4. Version (parameter name: `version`)
-5. Fs Option (parameter name: `fsOption`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-| `year` | `2000` to `2127` | Value obtained from FuzzedDataProvider|
-| `month` | `1` to `12` | Value obtained from FuzzedDataProvider|
-| `day` | `1` to `31` | Value obtained from FuzzedDataProvider|
-| `version` | `0` to `127` | Value obtained from FuzzedDataProvider|
-| `fsOption` | 0. `casefold` 1. `projid` 2. `compress` | Value obtained from FuzzedDataProvider|
-
-##### Maximize utilization of input data
-The plugin feeds the entire input data to the module.
-This ensures that the plugin tolerates any kind of input (empty, huge,
-malformed, etc) and doesnt `exit()` on any input and thereby increasing the
-chance of identifying vulnerabilities.
-
-## Build
-
-This describes steps to build fastboot_fuzzer binary.
-
-### Android
-
-#### Steps to build
-Build the fuzzer
-```
- $ mm -j$(nproc) fastboot_fuzzer_fuzzer
-```
-#### Steps to run
-To run on host
-```
- $ $ANDROID_HOST_OUT/fuzz/${TARGET_ARCH}/fastboot_fuzzer/fastboot_fuzzer CORPUS_DIR
-```
-
-## References:
- * http://llvm.org/docs/LibFuzzer.html
- * https://github.com/google/oss-fuzz
diff --git a/fastboot/fuzzer/fastboot_fuzzer.cpp b/fastboot/fuzzer/fastboot_fuzzer.cpp
deleted file mode 100644
index 60940fe3d..000000000
--- a/fastboot/fuzzer/fastboot_fuzzer.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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 "fastboot.h"
-#include "socket.h"
-#include "socket_mock_fuzz.h"
-#include "tcp.h"
-#include "udp.h"
-#include "vendor_boot_img_utils.h"
-
-#include <fuzzer/FuzzedDataProvider.h>
-
-using namespace std;
-
-const size_t kYearMin = 2000;
-const size_t kYearMax = 2127;
-const size_t kMonthMin = 1;
-const size_t kMonthMax = 12;
-const size_t kDayMin = 1;
-const size_t kDayMax = 31;
-const size_t kVersionMin = 0;
-const size_t kVersionMax = 127;
-const size_t kMaxStringSize = 100;
-const size_t kMinTimeout = 10;
-const size_t kMaxTimeout = 3000;
-const uint16_t kValidUdpPacketSize = 512;
-const uint16_t kMinUdpPackets = 1;
-const uint16_t kMaxUdpPackets = 10;
-
-const string kValidTcpHandshakeString = "FB01";
-const string kInvalidTcpHandshakeString = "FB00";
-const string kValidRamdiskName = "default";
-const string kVendorBootFile = "/tmp/vendorBootFile";
-const string kRamdiskFile = "/tmp/ramdiskFile";
-const char* kFsOptionsArray[] = {"casefold", "projid", "compress"};
-
-class FastbootFuzzer {
- public:
- void Process(const uint8_t* data, size_t size);
-
- private:
- void InvokeParseApi();
- void InvokeSocket();
- void InvokeTcp();
- void InvokeUdp();
- void InvokeVendorBootImgUtils(const uint8_t* data, size_t size);
- bool MakeConnectedSockets(Socket::Protocol protocol, unique_ptr<Socket>* server,
- unique_ptr<Socket>* client, const string& hostname);
- unique_ptr<FuzzedDataProvider> fdp_ = nullptr;
-};
-
-void FastbootFuzzer::InvokeParseApi() {
- boot_img_hdr_v1 hdr = {};
- FastBootTool fastBoot;
-
- int32_t year = fdp_->ConsumeIntegralInRange<int32_t>(kYearMin, kYearMax);
- int32_t month = fdp_->ConsumeIntegralInRange<int32_t>(kMonthMin, kMonthMax);
- int32_t day = fdp_->ConsumeIntegralInRange<int32_t>(kDayMin, kDayMax);
- string date = to_string(year) + "-" + to_string(month) + "-" + to_string(day);
- fastBoot.ParseOsPatchLevel(&hdr, date.c_str());
-
- int32_t major = fdp_->ConsumeIntegralInRange<int32_t>(kVersionMin, kVersionMax);
- int32_t minor = fdp_->ConsumeIntegralInRange<int32_t>(kVersionMin, kVersionMax);
- int32_t patch = fdp_->ConsumeIntegralInRange<int32_t>(kVersionMin, kVersionMax);
- string version = to_string(major) + "." + to_string(minor) + "." + to_string(patch);
- fastBoot.ParseOsVersion(&hdr, version.c_str());
-
- fastBoot.ParseFsOption(fdp_->PickValueInArray(kFsOptionsArray));
-}
-
-bool FastbootFuzzer::MakeConnectedSockets(Socket::Protocol protocol, unique_ptr<Socket>* server,
- unique_ptr<Socket>* client,
- const string& hostname = "localhost") {
- *server = Socket::NewServer(protocol, 0);
- if (*server == nullptr) {
- return false;
- }
- *client = Socket::NewClient(protocol, hostname, (*server)->GetLocalPort(), nullptr);
- if (*client == nullptr) {
- return false;
- }
- if (protocol == Socket::Protocol::kTcp) {
- *server = (*server)->Accept();
- if (*server == nullptr) {
- return false;
- }
- }
- return true;
-}
-
-void FastbootFuzzer::InvokeSocket() {
- unique_ptr<Socket> server, client;
-
- for (Socket::Protocol protocol : {Socket::Protocol::kUdp, Socket::Protocol::kTcp}) {
- if (MakeConnectedSockets(protocol, &server, &client)) {
- string message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
- client->Send(message.c_str(), message.length());
- string received(message.length(), '\0');
- if (fdp_->ConsumeBool()) {
- client->Close();
- }
- if (fdp_->ConsumeBool()) {
- server->Close();
- }
- server->ReceiveAll(&received[0], received.length(),
- /* timeout_ms */
- fdp_->ConsumeIntegralInRange<size_t>(kMinTimeout, kMaxTimeout));
- server->Close();
- client->Close();
- }
- }
-}
-
-void FastbootFuzzer::InvokeTcp() {
- /* Using a raw SocketMockFuzz* here because ownership shall be passed to the Transport object */
- SocketMockFuzz* tcp_mock = new SocketMockFuzz;
- tcp_mock->ExpectSend(fdp_->ConsumeBool() ? kValidTcpHandshakeString
- : kInvalidTcpHandshakeString);
- tcp_mock->AddReceive(fdp_->ConsumeBool() ? kValidTcpHandshakeString
- : kInvalidTcpHandshakeString);
-
- string error;
- unique_ptr<Transport> transport = tcp::internal::Connect(unique_ptr<Socket>(tcp_mock), &error);
-
- if (transport.get()) {
- string write_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
- if (fdp_->ConsumeBool()) {
- tcp_mock->ExpectSend(write_message);
- } else {
- tcp_mock->ExpectSendFailure(write_message);
- }
- string read_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
- if (fdp_->ConsumeBool()) {
- tcp_mock->AddReceive(read_message);
- } else {
- tcp_mock->AddReceiveFailure();
- }
-
- transport->Write(write_message.data(), write_message.length());
-
- string buffer(read_message.length(), '\0');
- transport->Read(&buffer[0], buffer.length());
-
- transport->Close();
- }
-}
-
-static string PacketValue(uint16_t value) {
- return string{static_cast<char>(value >> 8), static_cast<char>(value)};
-}
-
-static string ErrorPacket(uint16_t sequence, const string& message = "",
- char flags = udp::internal::kFlagNone) {
- return string{udp::internal::kIdError, flags} + PacketValue(sequence) + message;
-}
-
-static string InitPacket(uint16_t sequence, uint16_t version, uint16_t max_packet_size) {
- return string{udp::internal::kIdInitialization, udp::internal::kFlagNone} +
- PacketValue(sequence) + PacketValue(version) + PacketValue(max_packet_size);
-}
-
-static string QueryPacket(uint16_t sequence, uint16_t new_sequence) {
- return string{udp::internal::kIdDeviceQuery, udp::internal::kFlagNone} + PacketValue(sequence) +
- PacketValue(new_sequence);
-}
-
-static string QueryPacket(uint16_t sequence) {
- return string{udp::internal::kIdDeviceQuery, udp::internal::kFlagNone} + PacketValue(sequence);
-}
-
-static string FastbootPacket(uint16_t sequence, const string& data = "",
- char flags = udp::internal::kFlagNone) {
- return string{udp::internal::kIdFastboot, flags} + PacketValue(sequence) + data;
-}
-
-void FastbootFuzzer::InvokeUdp() {
- /* Using a raw SocketMockFuzz* here because ownership shall be passed to the Transport object */
- SocketMockFuzz* udp_mock = new SocketMockFuzz;
- uint16_t starting_sequence = fdp_->ConsumeIntegral<uint16_t>();
- int32_t device_max_packet_size = fdp_->ConsumeBool() ? kValidUdpPacketSize
- : fdp_->ConsumeIntegralInRange<uint16_t>(
- 0, kValidUdpPacketSize - 1);
- udp_mock->ExpectSend(QueryPacket(0));
- udp_mock->AddReceive(QueryPacket(0, starting_sequence));
- udp_mock->ExpectSend(InitPacket(starting_sequence, udp::internal::kProtocolVersion,
- udp::internal::kHostMaxPacketSize));
- udp_mock->AddReceive(
- InitPacket(starting_sequence, udp::internal::kProtocolVersion, device_max_packet_size));
-
- string error;
- unique_ptr<Transport> transport = udp::internal::Connect(unique_ptr<Socket>(udp_mock), &error);
- bool is_transport_initialized = transport != nullptr && error.empty();
-
- if (is_transport_initialized) {
- uint16_t num_packets =
- fdp_->ConsumeIntegralInRange<uint16_t>(kMinUdpPackets, kMaxUdpPackets);
-
- for (uint16_t i = 0; i < num_packets; ++i) {
- string write_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
- string read_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
- if (fdp_->ConsumeBool()) {
- udp_mock->ExpectSend(FastbootPacket(i, write_message));
- } else {
- udp_mock->ExpectSend(ErrorPacket(i, write_message));
- }
-
- if (fdp_->ConsumeBool()) {
- udp_mock->AddReceive(FastbootPacket(i, read_message));
- } else {
- udp_mock->AddReceive(ErrorPacket(i, read_message));
- }
- transport->Write(write_message.data(), write_message.length());
- string buffer(read_message.length(), '\0');
- transport->Read(&buffer[0], buffer.length());
- }
- transport->Close();
- }
-}
-
-void FastbootFuzzer::InvokeVendorBootImgUtils(const uint8_t* data, size_t size) {
- int32_t vendor_boot_fd = open(kVendorBootFile.c_str(), O_CREAT | O_RDWR, 0644);
- if (vendor_boot_fd < 0) {
- return;
- }
- int32_t ramdisk_fd = open(kRamdiskFile.c_str(), O_CREAT | O_RDWR, 0644);
- if (ramdisk_fd < 0) {
- return;
- }
- write(vendor_boot_fd, data, size);
- write(ramdisk_fd, data, size);
- string ramdisk_name = fdp_->ConsumeBool() ? kValidRamdiskName
- : fdp_->ConsumeRandomLengthString(kMaxStringSize);
- string content_vendor_boot_fd = {};
- string content_ramdisk_fd = {};
- lseek(vendor_boot_fd, 0, SEEK_SET);
- lseek(ramdisk_fd, 0, SEEK_SET);
- android::base::ReadFdToString(vendor_boot_fd, &content_vendor_boot_fd);
- android::base::ReadFdToString(ramdisk_fd, &content_ramdisk_fd);
- uint64_t vendor_boot_size =
- fdp_->ConsumeBool() ? content_vendor_boot_fd.size() : fdp_->ConsumeIntegral<uint64_t>();
- uint64_t ramdisk_size =
- fdp_->ConsumeBool() ? content_ramdisk_fd.size() : fdp_->ConsumeIntegral<uint64_t>();
- (void)replace_vendor_ramdisk(vendor_boot_fd, vendor_boot_size, ramdisk_name, ramdisk_fd,
- ramdisk_size);
- close(vendor_boot_fd);
- close(ramdisk_fd);
-}
-
-void FastbootFuzzer::Process(const uint8_t* data, size_t size) {
- fdp_ = make_unique<FuzzedDataProvider>(data, size);
- InvokeParseApi();
- InvokeSocket();
- InvokeTcp();
- InvokeUdp();
- InvokeVendorBootImgUtils(data, size);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FastbootFuzzer fastbootFuzzer;
- fastbootFuzzer.Process(data, size);
- return 0;
-}
diff --git a/fastboot/fuzzer/socket_mock_fuzz.cpp b/fastboot/fuzzer/socket_mock_fuzz.cpp
deleted file mode 100644
index df96eb005..000000000
--- a/fastboot/fuzzer/socket_mock_fuzz.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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 "socket_mock_fuzz.h"
-
-SocketMockFuzz::SocketMockFuzz() : Socket(INVALID_SOCKET) {}
-
-SocketMockFuzz::~SocketMockFuzz() {}
-
-bool SocketMockFuzz::Send(const void* data, size_t length) {
- if (events_.empty()) {
- return false;
- }
-
- if (events_.front().type != EventType::kSend) {
- return false;
- }
-
- std::string message(reinterpret_cast<const char*>(data), length);
- if (events_.front().message != message) {
- return false;
- }
-
- bool return_value = events_.front().status;
- events_.pop();
- return return_value;
-}
-
-// Mock out multi-buffer send to be one large send, since that's what it should looks like from
-// the user's perspective.
-bool SocketMockFuzz::Send(std::vector<cutils_socket_buffer_t> buffers) {
- std::string data;
- for (const auto& buffer : buffers) {
- data.append(reinterpret_cast<const char*>(buffer.data), buffer.length);
- }
- return Send(data.data(), data.size());
-}
-
-ssize_t SocketMockFuzz::Receive(void* data, size_t length, int /*timeout_ms*/) {
- if (events_.empty()) {
- return -1;
- }
-
- const Event& event = events_.front();
- if (event.type != EventType::kReceive) {
- return -1;
- }
-
- const std::string& message = event.message;
- if (message.length() > length) {
- return -1;
- }
-
- receive_timed_out_ = event.status;
- ssize_t return_value = message.length();
-
- // Empty message indicates failure.
- if (message.empty()) {
- return_value = -1;
- } else {
- memcpy(data, message.data(), message.length());
- }
-
- events_.pop();
- return return_value;
-}
-
-int SocketMockFuzz::Close() {
- return 0;
-}
-
-std::unique_ptr<Socket> SocketMockFuzz::Accept() {
- if (events_.empty()) {
- return nullptr;
- }
-
- if (events_.front().type != EventType::kAccept) {
- return nullptr;
- }
-
- std::unique_ptr<Socket> sock = std::move(events_.front().sock);
- events_.pop();
- return sock;
-}
-
-void SocketMockFuzz::ExpectSend(std::string message) {
- events_.push(Event(EventType::kSend, std::move(message), true, nullptr));
-}
-
-void SocketMockFuzz::ExpectSendFailure(std::string message) {
- events_.push(Event(EventType::kSend, std::move(message), false, nullptr));
-}
-
-void SocketMockFuzz::AddReceive(std::string message) {
- events_.push(Event(EventType::kReceive, std::move(message), false, nullptr));
-}
-
-void SocketMockFuzz::AddReceiveTimeout() {
- events_.push(Event(EventType::kReceive, "", true, nullptr));
-}
-
-void SocketMockFuzz::AddReceiveFailure() {
- events_.push(Event(EventType::kReceive, "", false, nullptr));
-}
-
-void SocketMockFuzz::AddAccept(std::unique_ptr<Socket> sock) {
- events_.push(Event(EventType::kAccept, "", false, std::move(sock)));
-}
-
-SocketMockFuzz::Event::Event(EventType _type, std::string _message, ssize_t _status,
- std::unique_ptr<Socket> _sock)
- : type(_type), message(_message), status(_status), sock(std::move(_sock)) {}
diff --git a/fastboot/fuzzer/socket_mock_fuzz.h b/fastboot/fuzzer/socket_mock_fuzz.h
deleted file mode 100644
index 67bd0d6ae..000000000
--- a/fastboot/fuzzer/socket_mock_fuzz.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#pragma once
-
-#include <memory>
-#include <queue>
-#include <string>
-
-#include <android-base/macros.h>
-
-#include "socket.h"
-
-class SocketMockFuzz : public Socket {
- public:
- SocketMockFuzz();
- ~SocketMockFuzz() override;
-
- bool Send(const void* data, size_t length) override;
- bool Send(std::vector<cutils_socket_buffer_t> buffers) override;
- ssize_t Receive(void* data, size_t length, int timeout_ms) override;
- int Close() override;
- virtual std::unique_ptr<Socket> Accept();
-
- // Adds an expectation for Send().
- void ExpectSend(std::string message);
-
- // Adds an expectation for Send() that returns false.
- void ExpectSendFailure(std::string message);
-
- // Adds data to provide for Receive().
- void AddReceive(std::string message);
-
- // Adds a Receive() timeout after which ReceiveTimedOut() will return true.
- void AddReceiveTimeout();
-
- // Adds a Receive() failure after which ReceiveTimedOut() will return false.
- void AddReceiveFailure();
-
- // Adds a Socket to return from Accept().
- void AddAccept(std::unique_ptr<Socket> sock);
-
- private:
- enum class EventType { kSend, kReceive, kAccept };
-
- struct Event {
- Event(EventType _type, std::string _message, ssize_t _status,
- std::unique_ptr<Socket> _sock);
-
- EventType type;
- std::string message;
- bool status; // Return value for Send() or timeout status for Receive().
- std::unique_ptr<Socket> sock;
- };
-
- std::queue<Event> events_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketMockFuzz);
-};
diff --git a/fastboot/fuzzy_fastboot/README.md b/fastboot/fuzzy_fastboot/README.md
index a5b64c746..72967c5fe 100644
--- a/fastboot/fuzzy_fastboot/README.md
+++ b/fastboot/fuzzy_fastboot/README.md
@@ -293,7 +293,7 @@ The following is the recommended workflow for using Fuzzy Fastboot on a new devi
Begin with just the generic tests (i.e. no XML file). In particular, make sure all
the conformance tests are passing before you move on. All other tests require that
the basic generic conformance tests all pass for them to be valid. The conformance
-tests can be run with `./fuzzy_fastboot --gtest_filter=Conformance.*`.
+tests can be run with `./fuzzy_fastboot --gtests_filter=Conformance.*`.
#### Understanding and Fixing Failed Tests
Whenever a test fails, it will print out to the console the reason for failure
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 074306b32..b6beaf93a 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -874,12 +874,6 @@ TEST_F(Fuzz, DownloadInvalid8) {
<< "Device did not respond with FAIL for malformed download command '" << cmd << "'";
}
-TEST_F(Fuzz, DownloadInvalid9) {
- std::string cmd("download:2PPPPPPPPPPPPPPPPPPPPPPPPPPPPPP");
- EXPECT_EQ(fb->RawCommand(cmd), DEVICE_FAIL)
- << "Device did not respond with FAIL for malformed download command '" << cmd << "'";
-}
-
TEST_F(Fuzz, GetVarAllSpam) {
auto start = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed;
@@ -896,51 +890,28 @@ TEST_F(Fuzz, GetVarAllSpam) {
TEST_F(Fuzz, BadCommandTooLarge) {
std::string s = RandomString(FB_COMMAND_SZ + 1, rand_legal);
- RetCode ret = fb->RawCommand(s);
- EXPECT_TRUE(ret == DEVICE_FAIL || ret == IO_ERROR)
+ EXPECT_EQ(fb->RawCommand(s), DEVICE_FAIL)
<< "Device did not respond with failure after sending length " << s.size()
<< " string of random ASCII chars";
- if (ret == IO_ERROR) EXPECT_EQ(transport->Reset(), 0) << "USB reset failed";
std::string s1 = RandomString(1000, rand_legal);
- ret = fb->RawCommand(s1);
- EXPECT_TRUE(ret == DEVICE_FAIL || ret == IO_ERROR)
+ EXPECT_EQ(fb->RawCommand(s1), DEVICE_FAIL)
<< "Device did not respond with failure after sending length " << s1.size()
<< " string of random ASCII chars";
- if (ret == IO_ERROR) EXPECT_EQ(transport->Reset(), 0) << "USB reset failed";
std::string s2 = RandomString(1000, rand_illegal);
- ret = fb->RawCommand(s2);
- EXPECT_TRUE(ret == DEVICE_FAIL || ret == IO_ERROR)
- << "Device did not respond with failure after sending length " << s2.size()
+ EXPECT_EQ(fb->RawCommand(s2), DEVICE_FAIL)
+ << "Device did not respond with failure after sending length " << s1.size()
<< " string of random non-ASCII chars";
- if (ret == IO_ERROR) EXPECT_EQ(transport->Reset(), 0) << "USB reset failed";
std::string s3 = RandomString(1000, rand_char);
- ret = fb->RawCommand(s3);
- EXPECT_TRUE(ret == DEVICE_FAIL || ret == IO_ERROR)
- << "Device did not respond with failure after sending length " << s3.size()
+ EXPECT_EQ(fb->RawCommand(s3), DEVICE_FAIL)
+ << "Device did not respond with failure after sending length " << s1.size()
<< " string of random chars";
- if (ret == IO_ERROR) EXPECT_EQ(transport->Reset(), 0) << "USB reset failed";
-
- std::string s4 = RandomString(10 * 1024 * 1024, rand_legal);
- ret = fb->RawCommand(s);
- EXPECT_TRUE(ret == DEVICE_FAIL || ret == IO_ERROR)
- << "Device did not respond with failure after sending length " << s4.size()
- << " string of random ASCII chars ";
- if (ret == IO_ERROR) EXPECT_EQ(transport->Reset(), 0) << "USB reset failed";
-
- ASSERT_TRUE(UsbStillAvailible()) << USB_PORT_GONE;
- std::string resp;
- EXPECT_EQ(fb->GetVar("product", &resp), SUCCESS)
- << "Device is unresponsive to getvar command";
}
TEST_F(Fuzz, CommandTooLarge) {
for (const std::string& s : CMDS) {
std::string rs = RandomString(1000, rand_char);
- RetCode ret;
- ret = fb->RawCommand(s + rs);
- EXPECT_TRUE(ret == DEVICE_FAIL || ret == IO_ERROR)
- << "Device did not respond with failure " << ret << "after '" << s + rs << "'";
- if (ret == IO_ERROR) EXPECT_EQ(transport->Reset(), 0) << "USB reset failed";
+ EXPECT_EQ(fb->RawCommand(s + rs), DEVICE_FAIL)
+ << "Device did not respond with failure after '" << s + rs << "'";
ASSERT_TRUE(UsbStillAvailible()) << USB_PORT_GONE;
std::string resp;
EXPECT_EQ(fb->GetVar("product", &resp), SUCCESS)
@@ -983,80 +954,6 @@ TEST_F(Fuzz, SparseZeroLength) {
}
}
-TEST_F(Fuzz, SparseZeroBlkSize) {
- // handcrafted malform sparse file with zero as block size
- const std::vector<char> buf = {
- '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', '\x00',
- '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00',
- '\x00', '\x00', '\x00', '\x00', '\xc2', '\xca', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00',
- '\x10', '\x00', '\x00', '\x00', '\x11', '\x22', '\x33', '\x44'
- };
-
- ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command";
- ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed";
-
- // It can either reject this download or reject it during flash
- if (HandleResponse() != DEVICE_FAIL) {
- EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
- << "Flashing a zero block size in sparse file should fail";
- }
-}
-
-TEST_F(Fuzz, SparseVeryLargeBlkSize) {
- // handcrafted sparse file with block size of ~4GB and divisible 4
- const std::vector<char> buf = {
- '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00',
- '\x1c', '\x00', '\x0c', '\x00', '\xF0', '\xFF', '\xFF', '\xFF',
- '\x01', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00',
- '\x00', '\x00', '\x00', '\x00', '\xc3', '\xca', '\x00', '\x00',
- '\x01', '\x00', '\x00', '\x00', '\x0c', '\x00', '\x00', '\x00',
- '\x11', '\x22', '\x33', '\x44'
- };
-
- ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command";
- ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed";
- ASSERT_EQ(HandleResponse(), SUCCESS) << "Not receive okay";
- ASSERT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed";
-}
-
-TEST_F(Fuzz, SparseTrimmed) {
- // handcrafted malform sparse file which is trimmed
- const std::vector<char> buf = {
- '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', '\x00',
- '\x00', '\x10', '\x00', '\x00', '\x00', '\x00', '\x08', '\x00', '\x01', '\x00', '\x00', '\x00',
- '\x00', '\x00', '\x00', '\x00', '\xc1', '\xca', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00',
- '\x00', '\x00', '\x00', '\x80', '\x11', '\x22', '\x33', '\x44'
- };
-
- ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command";
- ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed";
-
- // It can either reject this download or reject it during flash
- if (HandleResponse() != DEVICE_FAIL) {
- EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
- << "Flashing a trimmed sparse file should fail";
- }
-}
-
-TEST_F(Fuzz, SparseInvalidChurk) {
- // handcrafted malform sparse file with invalid churk
- const std::vector<char> buf = {
- '\x3a', '\xff', '\x26', '\xed', '\x01', '\x00', '\x00', '\x00', '\x1c', '\x00', '\x0c', '\x00',
- '\x00', '\x10', '\x00', '\x00', '\x00', '\x00', '\x08', '\x00', '\x01', '\x00', '\x00', '\x00',
- '\x00', '\x00', '\x00', '\x00', '\xc1', '\xca', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00',
- '\x10', '\x00', '\x00', '\x00', '\x11', '\x22', '\x33', '\x44'
- };
-
- ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command";
- ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed";
-
- // It can either reject this download or reject it during flash
- if (HandleResponse() != DEVICE_FAIL) {
- EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
- << "Flashing a sparse file with invalid churk should fail";
- }
-}
-
TEST_F(Fuzz, SparseTooManyChunks) {
SparseWrapper sparse(4096, 4096); // 1 block, but we send two chunks that will use 2 blocks
ASSERT_TRUE(*sparse) << "Sparse image creation failed";
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index 3096905a1..5a14b6377 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -28,10 +28,6 @@
#include "socket.h"
-#ifndef _WIN32
-#include <sys/select.h>
-#endif
-
#include <android-base/errors.h>
#include <android-base/stringprintf.h>
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 49761ac30..3c83aabba 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -15,10 +15,7 @@
//
package {
- default_applicable_licenses: [
- "Android-Apache-2.0",
- "system_core_fs_mgr_license",
- ],
+ default_applicable_licenses: ["system_core_fs_mgr_license"],
}
// Added automatically by a large-scale-change that took the approach of
@@ -39,9 +36,10 @@ license {
name: "system_core_fs_mgr_license",
visibility: [":__subpackages__"],
license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
"SPDX-license-identifier-MIT",
],
- license_text: ["NOTICE"],
+ // large-scale-change unable to identify any license_text files
}
cc_defaults {
@@ -69,6 +67,7 @@ cc_defaults {
"file_wait.cpp",
"fs_mgr.cpp",
"fs_mgr_format.cpp",
+ "fs_mgr_verity.cpp",
"fs_mgr_dm_linear.cpp",
"fs_mgr_overlayfs.cpp",
"fs_mgr_roots.cpp",
@@ -126,19 +125,10 @@ cc_defaults {
export_header_lib_headers: [
"libfiemap_headers",
],
- target: {
- platform: {
- required: [
- "e2freefrag",
- "e2fsdroid",
- ],
- },
- recovery: {
- required: [
- "e2fsdroid.recovery",
- ],
- },
- },
+ required: [
+ "e2freefrag",
+ "e2fsdroid",
+ ],
}
// Two variants of libfs_mgr are provided: libfs_mgr and libfs_mgr_binder.
@@ -152,8 +142,6 @@ cc_library {
// Do not ever allow this library to be vendor_available as a shared library.
// It does not have a stable interface.
name: "libfs_mgr",
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
defaults: [
"libfs_mgr_defaults",
@@ -178,8 +166,6 @@ cc_library_static {
// It does not have a stable interface.
name: "libfstab",
vendor_available: true,
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
host_supported: true,
defaults: ["fs_mgr_defaults"],
@@ -214,6 +200,7 @@ cc_binary {
static_libs: [
"libavb_user",
"libgsid",
+ "libutils",
"libvold_binder",
],
shared_libs: [
@@ -228,7 +215,6 @@ cc_binary {
"liblog",
"liblp",
"libselinux",
- "libutils",
],
header_libs: [
"libcutils_headers",
@@ -245,12 +231,28 @@ cc_binary {
"-UALLOW_ADBD_DISABLE_VERITY",
"-DALLOW_ADBD_DISABLE_VERITY=1",
],
+ },
+ },
+ required: [
+ "clean_scratch_files",
+ ],
+}
+
+cc_binary {
+ name: "clean_scratch_files",
+ defaults: ["fs_mgr_defaults"],
+ shared_libs: [
+ "libbase",
+ "libfs_mgr_binder",
+ ],
+ srcs: [
+ "clean_scratch_files.cpp",
+ ],
+ product_variables: {
+ debuggable: {
init_rc: [
"clean_scratch_files.rc",
],
},
},
- symlinks: [
- "clean_scratch_files",
- ],
}
diff --git a/fs_mgr/NOTICE b/fs_mgr/NOTICE
deleted file mode 100644
index 3972a4036..000000000
--- a/fs_mgr/NOTICE
+++ /dev/null
@@ -1,21 +0,0 @@
-Copyright (C) 2016 The Android Open Source Project
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use, copy,
-modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/fs_mgr/OWNERS b/fs_mgr/OWNERS
index c6f9054fa..cf353a1ed 100644
--- a/fs_mgr/OWNERS
+++ b/fs_mgr/OWNERS
@@ -1,4 +1,2 @@
-# Bug component: 30545
bowgotsai@google.com
dvander@google.com
-elsk@google.com
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 432aa4ff5..84709b6a8 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -1,9 +1,6 @@
{
"presubmit": [
{
- "name": "CtsFsMgrTestCases"
- },
- {
"name": "libdm_test"
},
{
@@ -16,9 +13,6 @@
"name": "fiemap_writer_test"
},
{
- "name": "fs_mgr_vendor_overlay_test"
- },
- {
"name": "vts_libsnapshot_test"
},
{
diff --git a/fs_mgr/blockdev.cpp b/fs_mgr/blockdev.cpp
index 388dadc64..14b217ca8 100644
--- a/fs_mgr/blockdev.cpp
+++ b/fs_mgr/blockdev.cpp
@@ -30,6 +30,7 @@ using android::base::Basename;
using android::base::ErrnoError;
using android::base::Error;
using android::base::Result;
+using android::base::ResultError;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -93,8 +94,10 @@ static Result<uint32_t> BlockDeviceQueueDepth(const std::string& file_path) {
std::string blockdev = "/dev/block/" + BlockdevName(statbuf.st_dev);
LOG(DEBUG) << __func__ << ": " << file_path << " -> " << blockdev;
if (blockdev.empty()) {
- return Errorf("Failed to convert {}:{} (path {})", major(statbuf.st_dev),
- minor(statbuf.st_dev), file_path.c_str());
+ const std::string err_msg =
+ StringPrintf("Failed to convert %u:%u (path %s)", major(statbuf.st_dev),
+ minor(statbuf.st_dev), file_path.c_str());
+ return ResultError(err_msg, 0);
}
auto& dm = DeviceMapper::Instance();
for (;;) {
@@ -107,7 +110,7 @@ static Result<uint32_t> BlockDeviceQueueDepth(const std::string& file_path) {
}
std::optional<std::string> maybe_blockdev = android::dm::ExtractBlockDeviceName(blockdev);
if (!maybe_blockdev) {
- return Errorf("Failed to remove /dev/block/ prefix from {}", blockdev);
+ return ResultError("Failed to remove /dev/block/ prefix from " + blockdev, 0);
}
blockdev = PartitionParent(*maybe_blockdev);
LOG(DEBUG) << __func__ << ": "
@@ -116,7 +119,7 @@ static Result<uint32_t> BlockDeviceQueueDepth(const std::string& file_path) {
StringPrintf("/sys/class/block/%s/mq/0/nr_tags", blockdev.c_str());
std::string nr_tags;
if (!android::base::ReadFileToString(nr_tags_path, &nr_tags)) {
- return Errorf("Failed to read {}", nr_tags_path);
+ return ResultError("Failed to read " + nr_tags_path, 0);
}
rtrim(nr_tags);
LOG(DEBUG) << __func__ << ": " << file_path << " is backed by /dev/" << blockdev
@@ -134,9 +137,11 @@ Result<void> ConfigureQueueDepth(const std::string& loop_device_path,
const std::string loop_device_name = Basename(loop_device_path);
- const auto qd = BlockDeviceQueueDepth(file_path);
+ const Result<uint32_t> qd = BlockDeviceQueueDepth(file_path);
if (!qd.ok()) {
- return qd.error();
+ LOG(DEBUG) << __func__ << ": "
+ << "BlockDeviceQueueDepth() returned " << qd.error();
+ return ResultError(qd.error());
}
const std::string nr_requests = StringPrintf("%u", *qd);
const std::string sysfs_path =
diff --git a/libusbhost/include/usbhost/usbhost_jni.h b/fs_mgr/clean_scratch_files.cpp
index 4885d457e..42fe35a59 100644
--- a/libusbhost/include/usbhost/usbhost_jni.h
+++ b/fs_mgr/clean_scratch_files.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,9 @@
* limitations under the License.
*/
-#pragma once
+#include <fs_mgr_overlayfs.h>
-#include <jni.h>
-
-/**
- * Reads USB descriptors from `fd`.
- *
- * Returns a byte[] on success,
- * or returns NULL and logs an appropriate error on failure.
- */
-jbyteArray usb_jni_read_descriptors(JNIEnv* env, int fd);
+int main() {
+ android::fs_mgr::CleanupOldScratchFiles();
+ return 0;
+}
diff --git a/fs_mgr/file_wait.cpp b/fs_mgr/file_wait.cpp
index af0699b7b..cbf68456d 100644
--- a/fs_mgr/file_wait.cpp
+++ b/fs_mgr/file_wait.cpp
@@ -206,9 +206,6 @@ bool OneShotInotify::ConsumeEvents() {
}
int64_t OneShotInotify::RemainingMs() const {
- if (relative_timeout_ == std::chrono::milliseconds::max()) {
- return std::chrono::milliseconds::max().count();
- }
auto remaining = (std::chrono::steady_clock::now() - start_time_);
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(remaining);
return (relative_timeout_ - elapsed).count();
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 686389495..21df8af8c 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -34,13 +34,11 @@
#include <time.h>
#include <unistd.h>
-#include <array>
#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <string>
-#include <string_view>
#include <thread>
#include <utility>
#include <vector>
@@ -75,6 +73,9 @@
#include "blockdev.h"
#include "fs_mgr_priv.h"
+#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
+#define KEY_IN_FOOTER "footer"
+
#define E2FSCK_BIN "/system/bin/e2fsck"
#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
#define MKSWAP_BIN "/system/bin/mkswap"
@@ -101,7 +102,6 @@ using android::base::GetUintProperty;
using android::base::Realpath;
using android::base::SetProperty;
using android::base::StartsWith;
-using android::base::StringPrintf;
using android::base::Timer;
using android::base::unique_fd;
using android::dm::DeviceMapper;
@@ -170,22 +170,6 @@ static bool should_force_check(int fs_stat) {
FS_STAT_SET_RESERVED_BLOCKS_FAILED | FS_STAT_ENABLE_ENCRYPTION_FAILED);
}
-static bool umount_retry(const std::string& mount_point) {
- int retry_count = 5;
- bool umounted = false;
-
- while (retry_count-- > 0) {
- umounted = umount(mount_point.c_str()) == 0;
- if (umounted) {
- LINFO << __FUNCTION__ << "(): unmount(" << mount_point << ") succeeded";
- break;
- }
- PERROR << __FUNCTION__ << "(): umount(" << mount_point << ") failed";
- if (retry_count) sleep(1);
- }
- return umounted;
-}
-
static void check_fs(const std::string& blk_device, const std::string& fs_type,
const std::string& target, int* fs_stat) {
int status;
@@ -225,12 +209,25 @@ static void check_fs(const std::string& blk_device, const std::string& fs_type,
tmpmnt_opts.c_str());
PINFO << __FUNCTION__ << "(): mount(" << blk_device << "," << target << "," << fs_type
<< ")=" << ret;
- if (ret) {
+ if (!ret) {
+ bool umounted = false;
+ int retry_count = 5;
+ while (retry_count-- > 0) {
+ umounted = umount(target.c_str()) == 0;
+ if (umounted) {
+ LINFO << __FUNCTION__ << "(): unmount(" << target << ") succeeded";
+ break;
+ }
+ PERROR << __FUNCTION__ << "(): umount(" << target << ") failed";
+ if (retry_count) sleep(1);
+ }
+ if (!umounted) {
+ // boot may fail but continue and leave it to later stage for now.
+ PERROR << __FUNCTION__ << "(): umount(" << target << ") timed out";
+ *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
+ }
+ } else {
*fs_stat |= FS_STAT_RO_MOUNT_FAILED;
- } else if (!umount_retry(target)) {
- // boot may fail but continue and leave it to later stage for now.
- PERROR << __FUNCTION__ << "(): umount(" << target << ") timed out";
- *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
}
}
@@ -271,12 +268,12 @@ static void check_fs(const std::string& blk_device, const std::string& fs_type,
LINFO << "Running " << F2FS_FSCK_BIN << " -f -c 10000 --debug-cache "
<< realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
- &status, false, LOG_KLOG | LOG_FILE, false, nullptr);
+ &status, false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
} else {
LINFO << "Running " << F2FS_FSCK_BIN << " -a -c 10000 --debug-cache "
<< realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, false,
- LOG_KLOG | LOG_FILE, false, nullptr);
+ LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
}
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
@@ -364,8 +361,8 @@ static void tune_quota(const std::string& blk_device, const FstabEntry& entry,
const struct ext4_super_block* sb, int* fs_stat) {
bool has_quota = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
bool want_quota = entry.fs_mgr_flags.quota;
- // Enable projid support by default
- bool want_projid = true;
+ bool want_projid = android::base::GetBoolProperty("external_storage.projid.enabled", false);
+
if (has_quota == want_quota) {
return;
}
@@ -794,26 +791,20 @@ static int __mount(const std::string& source, const std::string& target, const F
int save_errno = 0;
int gc_allowance = 0;
std::string opts;
- std::string checkpoint_opts;
bool try_f2fs_gc_allowance = is_f2fs(entry.fs_type) && entry.fs_checkpoint_opts.length() > 0;
- bool try_f2fs_fallback = false;
Timer t;
do {
- if (save_errno == EINVAL && (try_f2fs_gc_allowance || try_f2fs_fallback)) {
- PINFO << "Kernel does not support " << checkpoint_opts << ", trying without.";
+ if (save_errno == EINVAL && try_f2fs_gc_allowance) {
+ PINFO << "Kernel does not support checkpoint=disable:[n]%, trying without.";
try_f2fs_gc_allowance = false;
- // Attempt without gc allowance before dropping.
- try_f2fs_fallback = !try_f2fs_fallback;
}
if (try_f2fs_gc_allowance) {
- checkpoint_opts = entry.fs_checkpoint_opts + ":" + std::to_string(gc_allowance) + "%";
- } else if (try_f2fs_fallback) {
- checkpoint_opts = entry.fs_checkpoint_opts;
+ opts = entry.fs_options + entry.fs_checkpoint_opts + ":" +
+ std::to_string(gc_allowance) + "%";
} else {
- checkpoint_opts = "";
+ opts = entry.fs_options;
}
- opts = entry.fs_options + checkpoint_opts;
if (save_errno == EAGAIN) {
PINFO << "Retrying mount (source=" << source << ",target=" << target
<< ",type=" << entry.fs_type << ", gc_allowance=" << gc_allowance << "%)=" << ret
@@ -824,7 +815,7 @@ static int __mount(const std::string& source, const std::string& target, const F
save_errno = errno;
if (try_f2fs_gc_allowance) gc_allowance += 10;
} while ((ret && save_errno == EAGAIN && gc_allowance <= 100) ||
- (ret && save_errno == EINVAL && (try_f2fs_gc_allowance || try_f2fs_fallback)));
+ (ret && save_errno == EINVAL && try_f2fs_gc_allowance));
const char* target_missing = "";
const char* source_missing = "";
if (save_errno == ENOENT) {
@@ -907,7 +898,7 @@ static bool mount_with_alternatives(const Fstab& fstab, int start_idx, int* end_
<< "(): skipping mount due to invalid magic, mountpoint=" << fstab[i].mount_point
<< " blk_dev=" << realpath(fstab[i].blk_device) << " rec[" << i
<< "].fs_type=" << fstab[i].fs_type;
- mount_errno = EINVAL; // continue bootup for metadata encryption
+ mount_errno = EINVAL; // continue bootup for FDE
continue;
}
@@ -1005,21 +996,50 @@ static bool TranslateExtLabels(FstabEntry* entry) {
return false;
}
+static bool needs_block_encryption(const FstabEntry& entry) {
+ if (android::base::GetBoolProperty("ro.vold.forceencryption", false) && entry.is_encryptable())
+ return true;
+ if (entry.fs_mgr_flags.force_crypt) return true;
+ if (entry.fs_mgr_flags.crypt) {
+ // Check for existence of convert_fde breadcrumb file.
+ auto convert_fde_name = entry.mount_point + "/misc/vold/convert_fde";
+ if (access(convert_fde_name.c_str(), F_OK) == 0) return true;
+ }
+ if (entry.fs_mgr_flags.force_fde_or_fbe) {
+ // Check for absence of convert_fbe breadcrumb file.
+ auto convert_fbe_name = entry.mount_point + "/convert_fbe";
+ if (access(convert_fbe_name.c_str(), F_OK) != 0) return true;
+ }
+ return false;
+}
+
static bool should_use_metadata_encryption(const FstabEntry& entry) {
- return !entry.metadata_key_dir.empty() && entry.fs_mgr_flags.file_encryption;
+ return !entry.metadata_key_dir.empty() &&
+ (entry.fs_mgr_flags.file_encryption || entry.fs_mgr_flags.force_fde_or_fbe);
}
// Check to see if a mountable volume has encryption requirements
static int handle_encryptable(const FstabEntry& entry) {
- if (should_use_metadata_encryption(entry)) {
- if (umount_retry(entry.mount_point)) {
+ // If this is block encryptable, need to trigger encryption.
+ if (needs_block_encryption(entry)) {
+ if (umount(entry.mount_point.c_str()) == 0) {
+ return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
+ } else {
+ PWARNING << "Could not umount " << entry.mount_point << " - allow continue unencrypted";
+ return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+ }
+ } else if (should_use_metadata_encryption(entry)) {
+ if (umount(entry.mount_point.c_str()) == 0) {
return FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION;
+ } else {
+ PERROR << "Could not umount " << entry.mount_point << " - fail since can't encrypt";
+ return FS_MGR_MNTALL_FAIL;
}
- PERROR << "Could not umount " << entry.mount_point << " - fail since can't encrypt";
- return FS_MGR_MNTALL_FAIL;
- } else if (entry.fs_mgr_flags.file_encryption) {
+ } else if (entry.fs_mgr_flags.file_encryption || entry.fs_mgr_flags.force_fde_or_fbe) {
LINFO << entry.mount_point << " is file encrypted";
return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
+ } else if (entry.is_encryptable()) {
+ return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
} else {
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
}
@@ -1027,6 +1047,9 @@ static int handle_encryptable(const FstabEntry& entry) {
static void set_type_property(int status) {
switch (status) {
+ case FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED:
+ SetProperty("ro.crypto.type", "block");
+ break;
case FS_MGR_MNTALL_DEV_FILE_ENCRYPTED:
case FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED:
case FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION:
@@ -1445,6 +1468,14 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
// Skips mounting the device.
continue;
}
+ } else if ((current_entry.fs_mgr_flags.verify)) {
+ int rc = fs_mgr_setup_verity(&current_entry, true);
+ if (rc == FS_MGR_SETUP_VERITY_DISABLED || rc == FS_MGR_SETUP_VERITY_SKIPPED) {
+ LINFO << "Verity disabled";
+ } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
+ LERROR << "Could not set up verified partition, skipping!";
+ continue;
+ }
}
int last_idx_inspected;
@@ -1492,6 +1523,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
// Mounting failed, understand why and retry.
wiped = partition_wiped(current_entry.blk_device.c_str());
+ bool crypt_footer = false;
if (mount_errno != EBUSY && mount_errno != EACCES &&
current_entry.fs_mgr_flags.formattable && wiped) {
// current_entry and attempted_entry point at the same partition, but sometimes
@@ -1503,6 +1535,19 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
checkpoint_manager.Revert(&current_entry);
+ if (current_entry.is_encryptable() && current_entry.key_loc != KEY_IN_FOOTER) {
+ unique_fd fd(TEMP_FAILURE_RETRY(
+ open(current_entry.key_loc.c_str(), O_WRONLY | O_CLOEXEC)));
+ if (fd >= 0) {
+ LINFO << __FUNCTION__ << "(): also wipe " << current_entry.key_loc;
+ wipe_block_device(fd, get_file_size(fd));
+ } else {
+ PERROR << __FUNCTION__ << "(): " << current_entry.key_loc << " wouldn't open";
+ }
+ } else if (current_entry.is_encryptable() && current_entry.key_loc == KEY_IN_FOOTER) {
+ crypt_footer = true;
+ }
+
// EncryptInplace will be used when vdc gives an error or needs to format partitions
// other than /data
if (should_use_metadata_encryption(current_entry) &&
@@ -1523,7 +1568,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
}
}
- if (fs_mgr_do_format(current_entry) == 0) {
+ if (fs_mgr_do_format(current_entry, crypt_footer) == 0) {
// Let's replay the mount actions.
i = top_idx - 1;
continue;
@@ -1536,8 +1581,27 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
}
// mount(2) returned an error, handle the encryptable/formattable case.
- if (mount_errno != EBUSY && mount_errno != EACCES &&
- should_use_metadata_encryption(attempted_entry)) {
+ if (mount_errno != EBUSY && mount_errno != EACCES && attempted_entry.is_encryptable()) {
+ if (wiped) {
+ LERROR << __FUNCTION__ << "(): " << attempted_entry.blk_device << " is wiped and "
+ << attempted_entry.mount_point << " " << attempted_entry.fs_type
+ << " is encryptable. Suggest recovery...";
+ encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
+ continue;
+ } else {
+ // Need to mount a tmpfs at this mountpoint for now, and set
+ // properties that vold will query later for decrypting
+ LERROR << __FUNCTION__ << "(): possibly an encryptable blkdev "
+ << attempted_entry.blk_device << " for mount " << attempted_entry.mount_point
+ << " type " << attempted_entry.fs_type;
+ if (fs_mgr_do_tmpfs_mount(attempted_entry.mount_point.c_str()) < 0) {
+ ++error_count;
+ continue;
+ }
+ }
+ encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
+ } else if (mount_errno != EBUSY && mount_errno != EACCES &&
+ should_use_metadata_encryption(attempted_entry)) {
if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.blk_device,
attempted_entry.mount_point},
nullptr)) {
@@ -1609,6 +1673,13 @@ int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) {
ret |= FsMgrUmountStatus::ERROR_VERITY;
continue;
}
+ } else if ((current_entry.fs_mgr_flags.verify)) {
+ if (!fs_mgr_teardown_verity(&current_entry)) {
+ LERROR << "Failed to tear down verified partition on mount point: "
+ << current_entry.mount_point;
+ ret |= FsMgrUmountStatus::ERROR_VERITY;
+ continue;
+ }
}
}
return ret;
@@ -1809,13 +1880,9 @@ int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& alt_mount_po
auto& mount_point = alt_mount_point.empty() ? entry.mount_point : alt_mount_point;
// Run fsck if needed
- int ret = prepare_fs_for_mount(entry.blk_device, entry, mount_point);
- // Wiped case doesn't require to try __mount below.
- if (ret & FS_STAT_INVALID_MAGIC) {
- return FS_MGR_DOMNT_FAILED;
- }
+ prepare_fs_for_mount(entry.blk_device, entry, mount_point);
- ret = __mount(entry.blk_device, mount_point, entry);
+ int ret = __mount(entry.blk_device, mount_point, entry);
if (ret) {
ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
}
@@ -1905,6 +1972,14 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name,
// Skips mounting the device.
continue;
}
+ } else if (fstab_entry.fs_mgr_flags.verify) {
+ int rc = fs_mgr_setup_verity(&fstab_entry, true);
+ if (rc == FS_MGR_SETUP_VERITY_DISABLED || rc == FS_MGR_SETUP_VERITY_SKIPPED) {
+ LINFO << "Verity disabled";
+ } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
+ LERROR << "Could not set up verified partition, skipping!";
+ continue;
+ }
}
int retry_count = 2;
@@ -1964,35 +2039,6 @@ int fs_mgr_do_tmpfs_mount(const char *n_name)
return 0;
}
-static bool ConfigureIoScheduler(const std::string& device_path) {
- if (!StartsWith(device_path, "/dev/")) {
- LERROR << __func__ << ": invalid argument " << device_path;
- return false;
- }
-
- const std::string iosched_path =
- StringPrintf("/sys/block/%s/queue/scheduler", Basename(device_path).c_str());
- unique_fd iosched_fd(open(iosched_path.c_str(), O_RDWR | O_CLOEXEC));
- if (iosched_fd.get() == -1) {
- PERROR << __func__ << ": failed to open " << iosched_path;
- return false;
- }
-
- // Kernels before v4.1 only support 'noop'. Kernels [v4.1, v5.0) support
- // 'noop' and 'none'. Kernels v5.0 and later only support 'none'.
- static constexpr const std::array<std::string_view, 2> kNoScheduler = {"none", "noop"};
-
- for (const std::string_view& scheduler : kNoScheduler) {
- int ret = write(iosched_fd.get(), scheduler.data(), scheduler.size());
- if (ret > 0) {
- return true;
- }
- }
-
- PERROR << __func__ << ": failed to write to " << iosched_path;
- return false;
-}
-
static bool InstallZramDevice(const std::string& device) {
if (!android::base::WriteStringToFile(device, ZRAM_BACK_DEV)) {
PERROR << "Cannot write " << device << " in: " << ZRAM_BACK_DEV;
@@ -2025,11 +2071,7 @@ static bool PrepareZramBackingDevice(off64_t size) {
return false;
}
- ConfigureIoScheduler(loop_device);
-
- if (auto ret = ConfigureQueueDepth(loop_device, "/"); !ret.ok()) {
- LOG(DEBUG) << "Failed to config queue depth: " << ret.error().message();
- }
+ ConfigureQueueDepth(loop_device, "/");
// set block size & direct IO
unique_fd loop_fd(TEMP_FAILURE_RETRY(open(loop_device.c_str(), O_RDWR | O_CLOEXEC)));
@@ -2037,9 +2079,6 @@ static bool PrepareZramBackingDevice(off64_t size) {
PERROR << "Cannot open " << loop_device;
return false;
}
- if (!LoopControl::SetAutoClearStatus(loop_fd.get())) {
- PERROR << "Failed set LO_FLAGS_AUTOCLEAR for " << loop_device;
- }
if (!LoopControl::EnableDirectIo(loop_fd.get())) {
return false;
}
@@ -2056,7 +2095,7 @@ bool fs_mgr_swapon_all(const Fstab& fstab) {
}
if (entry.zram_size > 0) {
- if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
+ if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
LERROR << "Failure of zram backing device file for '" << entry.blk_device << "'";
}
// A zram_size was specified, so we need to configure the
@@ -2123,7 +2162,7 @@ bool fs_mgr_swapon_all(const Fstab& fstab) {
}
bool fs_mgr_is_verity_enabled(const FstabEntry& entry) {
- if (!entry.fs_mgr_flags.avb) {
+ if (!entry.fs_mgr_flags.verify && !entry.fs_mgr_flags.avb) {
return false;
}
@@ -2134,12 +2173,17 @@ bool fs_mgr_is_verity_enabled(const FstabEntry& entry) {
return false;
}
+ const char* status;
std::vector<DeviceMapper::TargetInfo> table;
if (!dm.GetTableStatus(mount_point, &table) || table.empty() || table[0].data.empty()) {
- return false;
+ if (!entry.fs_mgr_flags.verify_at_boot) {
+ return false;
+ }
+ status = "V";
+ } else {
+ status = table[0].data.c_str();
}
- auto status = table[0].data.c_str();
if (*status == 'C' || *status == 'V') {
return true;
}
@@ -2147,16 +2191,16 @@ bool fs_mgr_is_verity_enabled(const FstabEntry& entry) {
return false;
}
-std::optional<HashtreeInfo> fs_mgr_get_hashtree_info(const android::fs_mgr::FstabEntry& entry) {
- if (!entry.fs_mgr_flags.avb) {
- return {};
+std::string fs_mgr_get_hashtree_algorithm(const android::fs_mgr::FstabEntry& entry) {
+ if (!entry.fs_mgr_flags.verify && !entry.fs_mgr_flags.avb) {
+ return "";
}
DeviceMapper& dm = DeviceMapper::Instance();
std::string device = GetVerityDeviceName(entry);
std::vector<DeviceMapper::TargetInfo> table;
if (dm.GetState(device) == DmDeviceState::INVALID || !dm.GetTableInfo(device, &table)) {
- return {};
+ return "";
}
for (const auto& target : table) {
if (strcmp(target.spec.target_type, "verity") != 0) {
@@ -2172,19 +2216,18 @@ std::optional<HashtreeInfo> fs_mgr_get_hashtree_info(const android::fs_mgr::Fsta
std::vector<std::string> tokens = android::base::Split(target.data, " \t\r\n");
if (tokens[0] != "0" && tokens[0] != "1") {
LOG(WARNING) << "Unrecognized device mapper version in " << target.data;
- return {};
+ return "";
}
- // Hashtree algorithm & root digest are the 8th & 9th token in the output.
- return HashtreeInfo{.algorithm = android::base::Trim(tokens[7]),
- .root_digest = android::base::Trim(tokens[8])};
+ // Hashtree algorithm is the 8th token in the output
+ return android::base::Trim(tokens[7]);
}
- return {};
+ return "";
}
bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry) {
- if (!entry.fs_mgr_flags.avb) {
+ if (!entry.fs_mgr_flags.verify && !entry.fs_mgr_flags.avb) {
return false;
}
@@ -2208,10 +2251,8 @@ std::string fs_mgr_get_super_partition_name(int slot) {
// Devices upgrading to dynamic partitions are allowed to specify a super
// partition name. This includes cuttlefish, which is a non-A/B device.
std::string super_partition;
- if (fs_mgr_get_boot_config("force_super_partition", &super_partition)) {
- return super_partition;
- }
- if (fs_mgr_get_boot_config("super_partition", &super_partition)) {
+ if (fs_mgr_get_boot_config_from_bootconfig_source("super_partition", &super_partition) ||
+ fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) {
if (fs_mgr_get_slot_suffix().empty()) {
return super_partition;
}
@@ -2258,8 +2299,7 @@ bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) {
#if ALLOW_ADBD_DISABLE_VERITY == 0
// Allowlist the mount point if user build.
static const std::vector<const std::string> kAllowedPaths = {
- "/odm", "/odm_dlkm", "/oem", "/product",
- "/system_dlkm", "/system_ext", "/vendor", "/vendor_dlkm",
+ "/odm", "/odm_dlkm", "/oem", "/product", "/system_ext", "/vendor", "/vendor_dlkm",
};
static const std::vector<const std::string> kAllowedPrefixes = {
"/mnt/product/",
@@ -2285,24 +2325,7 @@ bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) {
return false;
}
- auto lowerdir = entry.lowerdir;
- if (entry.fs_mgr_flags.overlayfs_remove_missing_lowerdir) {
- bool removed_any = false;
- std::vector<std::string> lowerdirs;
- for (const auto& dir : android::base::Split(entry.lowerdir, ":")) {
- if (access(dir.c_str(), F_OK)) {
- PWARNING << __FUNCTION__ << "(): remove missing lowerdir '" << dir << "'";
- removed_any = true;
- } else {
- lowerdirs.push_back(dir);
- }
- }
- if (removed_any) {
- lowerdir = android::base::Join(lowerdirs, ":");
- }
- }
-
- auto options = "lowerdir=" + lowerdir;
+ auto options = "lowerdir=" + entry.lowerdir;
if (overlayfs_valid_result == OverlayfsValidResult::kOverrideCredsRequired) {
options += ",override_creds=off";
}
@@ -2323,22 +2346,3 @@ bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) {
LINFO << report << ret;
return true;
}
-
-bool fs_mgr_load_verity_state(int* mode) {
- // unless otherwise specified, use EIO mode.
- *mode = VERITY_MODE_EIO;
-
- // The bootloader communicates verity mode via the kernel commandline
- std::string verity_mode;
- if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
- return false;
- }
-
- if (verity_mode == "enforcing") {
- *mode = VERITY_MODE_DEFAULT;
- } else if (verity_mode == "logging") {
- *mode = VERITY_MODE_LOGGING;
- }
-
- return true;
-}
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 6f59ed36e..301c90755 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -34,6 +34,7 @@
#include <selinux/selinux.h>
#include "fs_mgr_priv.h"
+#include "cryptfs.h"
using android::base::unique_fd;
@@ -57,7 +58,7 @@ static int get_dev_sz(const std::string& fs_blkdev, uint64_t* dev_sz) {
}
static int format_ext4(const std::string& fs_blkdev, const std::string& fs_mnt_point,
- bool needs_projid, bool needs_metadata_csum) {
+ bool crypt_footer, bool needs_projid, bool needs_metadata_csum) {
uint64_t dev_sz;
int rc = 0;
@@ -67,6 +68,9 @@ static int format_ext4(const std::string& fs_blkdev, const std::string& fs_mnt_p
}
/* Format the partition using the calculated length */
+ if (crypt_footer) {
+ dev_sz -= CRYPT_FOOTER_OFFSET;
+ }
std::string size_str = std::to_string(dev_sz / 4096);
@@ -116,8 +120,8 @@ static int format_ext4(const std::string& fs_blkdev, const std::string& fs_mnt_p
return rc;
}
-static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs_projid,
- bool needs_casefold, bool fs_compress) {
+static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool crypt_footer,
+ bool needs_projid, bool needs_casefold, bool fs_compress) {
if (!dev_sz) {
int rc = get_dev_sz(fs_blkdev, &dev_sz);
if (rc) {
@@ -126,6 +130,9 @@ static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs
}
/* Format the partition using the calculated length */
+ if (crypt_footer) {
+ dev_sz -= CRYPT_FOOTER_OFFSET;
+ }
std::string size_str = std::to_string(dev_sz / 4096);
@@ -152,21 +159,22 @@ static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs
return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, false, nullptr);
}
-int fs_mgr_do_format(const FstabEntry& entry) {
+int fs_mgr_do_format(const FstabEntry& entry, bool crypt_footer) {
LERROR << __FUNCTION__ << ": Format " << entry.blk_device << " as '" << entry.fs_type << "'";
bool needs_casefold = false;
- bool needs_projid = true;
+ bool needs_projid = false;
if (entry.mount_point == "/data") {
needs_casefold = android::base::GetBoolProperty("external_storage.casefold.enabled", false);
+ needs_projid = android::base::GetBoolProperty("external_storage.projid.enabled", false);
}
if (entry.fs_type == "f2fs") {
- return format_f2fs(entry.blk_device, entry.length, needs_projid, needs_casefold,
- entry.fs_mgr_flags.fs_compress);
+ return format_f2fs(entry.blk_device, entry.length, crypt_footer, needs_projid,
+ needs_casefold, entry.fs_mgr_flags.fs_compress);
} else if (entry.fs_type == "ext4") {
- return format_ext4(entry.blk_device, entry.mount_point, needs_projid,
+ return format_ext4(entry.blk_device, entry.mount_point, crypt_footer, needs_projid,
entry.fs_mgr_flags.ext_meta_csum);
} else {
LERROR << "File system type '" << entry.fs_type << "' is not supported";
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 8c719c868..d0c89b909 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -130,15 +130,13 @@ void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
const auto arg = flag.substr(equal_sign + 1);
if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
- off64_t size_in_4k_blocks;
- if (!ParseInt(arg, &size_in_4k_blocks, static_cast<off64_t>(0),
- std::numeric_limits<off64_t>::max() >> 12)) {
+ if (!ParseInt(arg, &entry->reserved_size)) {
LWARNING << "Warning: reserve_root= flag malformed: " << arg;
} else {
- entry->reserved_size = size_in_4k_blocks << 12;
+ entry->reserved_size <<= 12;
}
} else if (StartsWith(flag, "lowerdir=")) {
- entry->lowerdir = arg;
+ entry->lowerdir = std::move(arg);
}
}
}
@@ -146,7 +144,7 @@ void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
entry->fs_options = std::move(fs_options);
}
-bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
+void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
for (const auto& flag : Split(flags, ",")) {
if (flag.empty() || flag == "defaults") continue;
std::string arg;
@@ -167,10 +165,12 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
CheckFlag("recoveryonly", recovery_only);
CheckFlag("noemulatedsd", no_emulated_sd);
CheckFlag("notrim", no_trim);
+ CheckFlag("verify", verify);
CheckFlag("formattable", formattable);
CheckFlag("slotselect", slot_select);
CheckFlag("latemount", late_mount);
CheckFlag("nofail", no_fail);
+ CheckFlag("verifyatboot", verify_at_boot);
CheckFlag("quota", quota);
CheckFlag("avb", avb);
CheckFlag("logical", logical);
@@ -181,24 +181,14 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
CheckFlag("fsverity", fs_verity);
CheckFlag("metadata_csum", ext_meta_csum);
CheckFlag("fscompress", fs_compress);
- CheckFlag("overlayfs_remove_missing_lowerdir", overlayfs_remove_missing_lowerdir);
#undef CheckFlag
// Then handle flags that take an argument.
if (StartsWith(flag, "encryptable=")) {
- // The "encryptable" flag identifies adoptable storage volumes. The
- // argument to this flag is ignored, but it should be "userdata".
- //
- // Historical note: this flag was originally meant just for /data,
- // to indicate that FDE (full disk encryption) can be enabled.
- // Unfortunately, it was also overloaded to identify adoptable
- // storage volumes. Today, FDE is no longer supported, leaving only
- // the adoptable storage volume meaning for this flag.
+ // The encryptable flag is followed by an = and the location of the keys.
entry->fs_mgr_flags.crypt = true;
- } else if (StartsWith(flag, "forceencrypt=") || StartsWith(flag, "forcefdeorfbe=")) {
- LERROR << "flag no longer supported: " << flag;
- return false;
+ entry->key_loc = arg;
} else if (StartsWith(flag, "voldmanaged=")) {
// The voldmanaged flag is followed by an = and the label, a colon and the partition
// number or the word "auto", e.g. voldmanaged=sdcard:3
@@ -242,8 +232,18 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
LWARNING << "Warning: zramsize= flag malformed: " << arg;
}
}
+ } else if (StartsWith(flag, "forceencrypt=")) {
+ // The forceencrypt flag is followed by an = and the location of the keys.
+ entry->fs_mgr_flags.force_crypt = true;
+ entry->key_loc = arg;
} else if (StartsWith(flag, "fileencryption=")) {
ParseFileEncryption(arg, entry);
+ } else if (StartsWith(flag, "forcefdeorfbe=")) {
+ // The forcefdeorfbe flag is followed by an = and the location of the keys. Get it and
+ // return it.
+ entry->fs_mgr_flags.force_fde_or_fbe = true;
+ entry->key_loc = arg;
+ entry->encryption_options = "aes-256-xts:aes-256-cts";
} else if (StartsWith(flag, "max_comp_streams=")) {
if (!ParseInt(arg, &entry->max_comp_streams)) {
LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
@@ -287,16 +287,11 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
entry->fs_mgr_flags.avb = true;
entry->vbmeta_partition = arg;
} else if (StartsWith(flag, "keydirectory=")) {
- // The keydirectory flag enables metadata encryption. It is
- // followed by an = and the directory containing the metadata
- // encryption key.
+ // The metadata flag is followed by an = and the directory for the keys.
entry->metadata_key_dir = arg;
} else if (StartsWith(flag, "metadata_encryption=")) {
- // The metadata_encryption flag specifies the cipher and flags to
- // use for metadata encryption, if the defaults aren't sufficient.
- // It doesn't actually enable metadata encryption; that is done by
- // "keydirectory".
- entry->metadata_encryption_options = arg;
+ // Specify the cipher and flags to use for metadata encryption
+ entry->metadata_encryption = arg;
} else if (StartsWith(flag, "sysfs_path=")) {
// The path to trigger device gc by idle-maint of vold.
entry->sysfs_path = arg;
@@ -308,19 +303,6 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
LWARNING << "Warning: unknown flag: " << flag;
}
}
-
- // FDE is no longer supported, so reject "encryptable" when used without
- // "vold_managed". For now skip this check when in recovery mode, since
- // some recovery fstabs still contain the FDE options since they didn't do
- // anything in recovery mode anyway (except possibly to cause the
- // reservation of a crypto footer) and thus never got removed.
- if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed &&
- access("/system/bin/recovery", F_OK) != 0) {
- LERROR << "FDE is no longer supported; 'encryptable' can only be used for adoptable "
- "storage";
- return false;
- }
- return true;
}
std::string InitAndroidDtDir() {
@@ -431,24 +413,17 @@ std::string ReadFstabFromDt() {
return fstab_result;
}
-// Return the path to the fstab file. There may be multiple fstab files; the
-// one that is returned will be the first that exists of fstab.<fstab_suffix>,
-// fstab.<hardware>, and fstab.<hardware.platform>. The fstab is searched for
-// in /odm/etc/ and /vendor/etc/, as well as in the locations where it may be in
-// the first stage ramdisk during early boot. Previously, the first stage
-// ramdisk's copy of the fstab had to be located in the root directory, but now
-// the system/etc directory is supported too and is the preferred location.
+// Identify path to fstab file. Lookup is based on pattern
+// fstab.<fstab_suffix>, fstab.<hardware>, fstab.<hardware.platform> in
+// folders /odm/etc, vendor/etc, or /.
std::string GetFstabPath() {
for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
std::string suffix;
if (!fs_mgr_get_boot_config(prop, &suffix)) continue;
- for (const char* prefix : {// late-boot/post-boot locations
- "/odm/etc/fstab.", "/vendor/etc/fstab.",
- // early boot locations
- "/system/etc/fstab.", "/first_stage_ramdisk/system/etc/fstab.",
- "/fstab.", "/first_stage_ramdisk/fstab."}) {
+ for (const char* prefix :
+ {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab.", "/first_stage_ramdisk/fstab."}) {
std::string fstab_path = prefix + suffix;
if (access(fstab_path.c_str(), F_OK) == 0) {
return fstab_path;
@@ -459,6 +434,92 @@ std::string GetFstabPath() {
return "";
}
+bool ReadFstabFile(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
+ ssize_t len;
+ size_t alloc_len = 0;
+ char *line = NULL;
+ const char *delim = " \t";
+ char *save_ptr, *p;
+ Fstab fstab;
+
+ while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
+ /* if the last character is a newline, shorten the string by 1 byte */
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
+
+ /* Skip any leading whitespace */
+ p = line;
+ while (isspace(*p)) {
+ p++;
+ }
+ /* ignore comments or empty lines */
+ if (*p == '#' || *p == '\0')
+ continue;
+
+ FstabEntry entry;
+
+ if (!(p = strtok_r(line, delim, &save_ptr))) {
+ LERROR << "Error parsing mount source";
+ goto err;
+ }
+ entry.blk_device = p;
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing mount_point";
+ goto err;
+ }
+ entry.mount_point = p;
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing fs_type";
+ goto err;
+ }
+ entry.fs_type = p;
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing mount_flags";
+ goto err;
+ }
+
+ ParseMountFlags(p, &entry);
+
+ // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
+ if (proc_mounts) {
+ p += strlen(p);
+ } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing fs_mgr_options";
+ goto err;
+ }
+
+ ParseFsMgrFlags(p, &entry);
+
+ if (entry.fs_mgr_flags.logical) {
+ entry.logical_partition_name = entry.blk_device;
+ }
+
+ fstab.emplace_back(std::move(entry));
+ }
+
+ if (fstab.empty()) {
+ LERROR << "No entries found in fstab";
+ goto err;
+ }
+
+ /* If an A/B partition, modify block device to be the real block device */
+ if (!fs_mgr_update_for_slotselect(&fstab)) {
+ LERROR << "Error updating for slotselect";
+ goto err;
+ }
+ free(line);
+ *fstab_out = std::move(fstab);
+ return true;
+
+err:
+ free(line);
+ return false;
+}
+
/* Extracts <device>s from the by-name symlinks specified in a fstab:
* /dev/block/<type>/<device>/by-name/<partition>
*
@@ -533,61 +594,6 @@ bool EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
} // namespace
-bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out) {
- const int expected_fields = proc_mounts ? 4 : 5;
-
- Fstab fstab;
-
- for (const auto& line : android::base::Split(fstab_str, "\n")) {
- auto fields = android::base::Tokenize(line, " \t");
-
- // Ignore empty lines and comments.
- if (fields.empty() || android::base::StartsWith(fields.front(), '#')) {
- continue;
- }
-
- if (fields.size() < expected_fields) {
- LERROR << "Error parsing fstab: expected " << expected_fields << " fields, got "
- << fields.size();
- return false;
- }
-
- FstabEntry entry;
- auto it = fields.begin();
-
- entry.blk_device = std::move(*it++);
- entry.mount_point = std::move(*it++);
- entry.fs_type = std::move(*it++);
- ParseMountFlags(std::move(*it++), &entry);
-
- // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
- if (!proc_mounts && !ParseFsMgrFlags(std::move(*it++), &entry)) {
- LERROR << "Error parsing fs_mgr_flags";
- return false;
- }
-
- if (entry.fs_mgr_flags.logical) {
- entry.logical_partition_name = entry.blk_device;
- }
-
- fstab.emplace_back(std::move(entry));
- }
-
- if (fstab.empty()) {
- LERROR << "No entries found in fstab";
- return false;
- }
-
- /* If an A/B partition, modify block device to be the real block device */
- if (!fs_mgr_update_for_slotselect(&fstab)) {
- LERROR << "Error updating for slotselect";
- return false;
- }
-
- *fstab_out = std::move(fstab);
- return true;
-}
-
void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
const std::vector<std::string>& dsu_partitions) {
static constexpr char kDsuKeysDir[] = "/avb";
@@ -653,7 +659,6 @@ void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
entry->blk_device = partition;
// AVB keys for DSU should always be under kDsuKeysDir.
entry->avb_keys = kDsuKeysDir;
- entry->fs_mgr_flags.logical = true;
}
// Make sure the ext4 is included to support GSI.
auto partition_ext4 =
@@ -663,23 +668,16 @@ void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
if (partition_ext4 == fstab->end()) {
auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
new_entry.fs_type = "ext4";
- auto it = std::find_if(fstab->rbegin(), fstab->rend(),
- [&mount_point](const auto& entry) {
- return entry.mount_point == mount_point;
- });
- auto end_of_mount_point_group = fstab->begin() + std::distance(it, fstab->rend());
- fstab->insert(end_of_mount_point_group, new_entry);
+ fstab->emplace_back(new_entry);
}
}
}
}
void EnableMandatoryFlags(Fstab* fstab) {
- // Devices launched in R and after must support fs_verity. Set flag to cause tune2fs
- // to enable the feature on userdata and metadata partitions.
+ // Devices launched in R and after should enable fs_verity on userdata. The flag causes tune2fs
+ // to enable the feature. A better alternative would be to enable on mkfs at the beginning.
if (android::base::GetIntProperty("ro.product.first_api_level", 0) >= 30) {
- // Devices launched in R and after should enable fs_verity on userdata.
- // A better alternative would be to enable on mkfs at the beginning.
std::vector<FstabEntry*> data_entries = GetEntriesForMountPoint(fstab, "/data");
for (auto&& entry : data_entries) {
// Besides ext4, f2fs is also supported. But the image is already created with verity
@@ -688,26 +686,20 @@ void EnableMandatoryFlags(Fstab* fstab) {
entry->fs_mgr_flags.fs_verity = true;
}
}
- // Devices shipping with S and earlier likely do not already have fs_verity enabled via
- // mkfs, so enable it here.
- std::vector<FstabEntry*> metadata_entries = GetEntriesForMountPoint(fstab, "/metadata");
- for (auto&& entry : metadata_entries) {
- entry->fs_mgr_flags.fs_verity = true;
- }
}
}
bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) {
- const bool is_proc_mounts = (path == "/proc/mounts");
-
- std::string fstab_str;
- if (!android::base::ReadFileToString(path, &fstab_str, /* follow_symlinks = */ true)) {
- PERROR << __FUNCTION__ << "(): failed to read file: '" << path << "'";
+ auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+ if (!fstab_file) {
+ PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
return false;
}
+ bool is_proc_mounts = path == "/proc/mounts";
+
Fstab fstab;
- if (!ParseFstabFromString(fstab_str, is_proc_mounts, &fstab)) {
+ if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, &fstab)) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
return false;
}
@@ -754,7 +746,15 @@ bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
return false;
}
- if (!ParseFstabFromString(fstab_buf, /* proc_mounts = */ false, fstab)) {
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
+ fstab_buf.length(), "r"), fclose);
+ if (!fstab_file) {
+ if (verbose) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+ return false;
+ }
+
+ if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
if (verbose) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
<< fstab_buf;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 82b5275a3..4d32bda80 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -33,7 +33,6 @@
#include <algorithm>
#include <memory>
-#include <optional>
#include <string>
#include <vector>
@@ -126,12 +125,8 @@ namespace {
bool fs_mgr_in_recovery() {
// Check the existence of recovery binary instead of using the compile time
- // __ANDROID_RECOVERY__ macro.
- // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot
- // mode would use the same init binary, which would mean during normal boot
- // the '/init' binary is actually a symlink pointing to
- // init_second_stage.recovery, which would be compiled with
- // __ANDROID_RECOVERY__ defined.
+ // macro, because first-stage-init is compiled with __ANDROID_RECOVERY__
+ // defined, albeit not in recovery. More details: system/core/init/README.md
return fs_mgr_access("/system/bin/recovery");
}
@@ -327,17 +322,6 @@ std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
const auto kLowerdirOption = "lowerdir="s;
const auto kUpperdirOption = "upperdir="s;
-static inline bool KernelSupportsUserXattrs() {
- struct utsname uts;
- uname(&uts);
-
- int major, minor;
- if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
- return false;
- }
- return major > 5 || (major == 5 && minor >= 15);
-}
-
// default options for mount_point, returns empty string for none available.
std::string fs_mgr_get_overlayfs_options(const std::string& mount_point) {
auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
@@ -347,9 +331,6 @@ std::string fs_mgr_get_overlayfs_options(const std::string& mount_point) {
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
ret += ",override_creds=off";
}
- if (KernelSupportsUserXattrs()) {
- ret += ",userxattr";
- }
return ret;
}
@@ -885,14 +866,9 @@ bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::s
errno = save_errno;
}
entry.flags &= ~MS_RDONLY;
- entry.flags |= MS_SYNCHRONOUS;
- entry.fs_options = "nodiscard";
fs_mgr_set_blk_ro(device_path, false);
}
- // check_fs requires apex runtime library
- if (fs_mgr_overlayfs_already_mounted("/data", false)) {
- entry.fs_mgr_flags.check = true;
- }
+ entry.fs_mgr_flags.check = true;
auto save_errno = errno;
if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0;
if (!mounted) {
@@ -1126,23 +1102,6 @@ static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_ex
return true;
}
-static inline uint64_t GetIdealDataScratchSize() {
- BlockDeviceInfo super_info;
- PartitionOpener opener;
- if (!opener.GetInfo(fs_mgr_get_super_partition_name(), &super_info)) {
- LERROR << "could not get block device info for super";
- return 0;
- }
-
- struct statvfs s;
- if (statvfs("/data", &s) < 0) {
- PERROR << "could not statfs /data";
- return 0;
- }
-
- return std::min(super_info.size, (uint64_t(s.f_frsize) * s.f_bfree) / 2);
-}
-
static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exists, bool* change) {
*partition_exists = false;
if (change) *change = false;
@@ -1158,6 +1117,13 @@ static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exi
return true;
}
+ BlockDeviceInfo info;
+ PartitionOpener opener;
+ if (!opener.GetInfo(fs_mgr_get_super_partition_name(), &info)) {
+ LERROR << "could not get block device info for super";
+ return false;
+ }
+
if (change) *change = true;
// Note: calling RemoveDisabledImages here ensures that we do not race with
@@ -1167,11 +1133,10 @@ static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exi
return false;
}
if (!images->BackingImageExists(partition_name)) {
- uint64_t size = GetIdealDataScratchSize();
- if (!size) {
- size = 2_GiB;
- }
+ static constexpr uint64_t kMinimumSize = 16_MiB;
+ static constexpr uint64_t kMaximumSize = 2_GiB;
+ uint64_t size = std::clamp(info.size / 2, kMinimumSize, kMaximumSize);
auto flags = IImageManager::CREATE_IMAGE_DEFAULT;
if (!images->CreateBackingImage(partition_name, size, flags)) {
@@ -1412,35 +1377,18 @@ bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool*
return ret;
}
-struct MapInfo {
- // If set, partition is owned by ImageManager.
- std::unique_ptr<IImageManager> images;
- // If set, and images is null, this is a DAP partition.
- std::string name;
- // If set, and images and name are empty, this is a non-dynamic partition.
- std::string device;
-
- MapInfo() = default;
- MapInfo(MapInfo&&) = default;
- ~MapInfo() {
- if (images) {
- images->UnmapImageDevice(name);
- } else if (!name.empty()) {
- DestroyLogicalPartition(name);
- }
- }
-};
-
// Note: This function never returns the DSU scratch device in recovery or fastbootd,
// because the DSU scratch is created in the first-stage-mount, which is not run in recovery.
-static std::optional<MapInfo> EnsureScratchMapped() {
- MapInfo info;
- info.device = GetBootScratchDevice();
- if (!info.device.empty()) {
- return {std::move(info)};
+static bool EnsureScratchMapped(std::string* device, bool* mapped) {
+ *mapped = false;
+ *device = GetBootScratchDevice();
+ if (!device->empty()) {
+ return true;
}
+
if (!fs_mgr_in_recovery()) {
- return {};
+ errno = EINVAL;
+ return false;
}
auto partition_name = android::base::Basename(kScratchMountPoint);
@@ -1450,15 +1398,11 @@ static std::optional<MapInfo> EnsureScratchMapped() {
// would otherwise always be mapped.
auto images = IImageManager::Open("remount", 10s);
if (images && images->BackingImageExists(partition_name)) {
- if (images->IsImageDisabled(partition_name)) {
- return {};
- }
- if (!images->MapImageDevice(partition_name, 10s, &info.device)) {
- return {};
+ if (!images->MapImageDevice(partition_name, 10s, device)) {
+ return false;
}
- info.name = partition_name;
- info.images = std::move(images);
- return {std::move(info)};
+ *mapped = true;
+ return true;
}
// Avoid uart spam by first checking for a scratch partition.
@@ -1466,12 +1410,12 @@ static std::optional<MapInfo> EnsureScratchMapped() {
auto super_device = fs_mgr_overlayfs_super_device(metadata_slot);
auto metadata = ReadCurrentMetadata(super_device);
if (!metadata) {
- return {};
+ return false;
}
auto partition = FindPartition(*metadata.get(), partition_name);
if (!partition) {
- return {};
+ return false;
}
CreateLogicalPartitionParams params = {
@@ -1481,11 +1425,11 @@ static std::optional<MapInfo> EnsureScratchMapped() {
.force_writable = true,
.timeout_ms = 10s,
};
- if (!CreateLogicalPartition(params, &info.device)) {
- return {};
+ if (!CreateLogicalPartition(params, device)) {
+ return false;
}
- info.name = partition_name;
- return {std::move(info)};
+ *mapped = true;
+ return true;
}
// This should only be reachable in recovery, where DSU scratch is not
@@ -1639,35 +1583,26 @@ void TeardownAllOverlayForMountPoint(const std::string& mount_point) {
fs_mgr_overlayfs_teardown_one(overlay_mount_point, teardown_dir, ignore_change);
}
- if (mount_point.empty()) {
- // Throw away the entire partition.
- auto partition_name = android::base::Basename(kScratchMountPoint);
- auto images = IImageManager::Open("remount", 10s);
- if (images && images->BackingImageExists(partition_name)) {
- if (images->DisableImage(partition_name)) {
- LOG(INFO) << "Disabled scratch partition for: " << kScratchMountPoint;
- } else {
- LOG(ERROR) << "Unable to disable scratch partition for " << kScratchMountPoint;
- }
- }
- }
-
- if (auto info = EnsureScratchMapped(); info.has_value()) {
- // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
+ // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
+ bool mapped = false;
+ std::string scratch_device;
+ if (EnsureScratchMapped(&scratch_device, &mapped)) {
fs_mgr_overlayfs_umount_scratch();
- if (fs_mgr_overlayfs_mount_scratch(info->device, fs_mgr_overlayfs_scratch_mount_type())) {
+ if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {
bool should_destroy_scratch = false;
fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change,
&should_destroy_scratch);
- fs_mgr_overlayfs_umount_scratch();
if (should_destroy_scratch) {
fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, nullptr);
}
+ fs_mgr_overlayfs_umount_scratch();
+ }
+ if (mapped) {
+ DestroyLogicalPartition(android::base::Basename(kScratchMountPoint));
}
}
// Teardown DSU overlay if present.
- std::string scratch_device;
if (MapDsuScratchDevice(&scratch_device)) {
fs_mgr_overlayfs_umount_scratch();
if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index deaf5f72d..e685070a8 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -42,8 +42,6 @@
#include <libavb_user/libavb_user.h>
#include <libgsi/libgsid.h>
-using namespace std::literals;
-
namespace {
[[noreturn]] void usage(int exit_status) {
@@ -144,7 +142,6 @@ enum RemountStatus {
BINDER_ERROR,
CHECKPOINTING,
GSID_ERROR,
- CLEAN_SCRATCH_FILES,
};
static int do_remount(int argc, char* argv[]) {
@@ -166,7 +163,6 @@ static int do_remount(int argc, char* argv[]) {
{"help", no_argument, nullptr, 'h'},
{"reboot", no_argument, nullptr, 'R'},
{"verbose", no_argument, nullptr, 'v'},
- {"clean_scratch_files", no_argument, nullptr, 'C'},
{0, 0, nullptr, 0},
};
for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
@@ -187,8 +183,6 @@ static int do_remount(int argc, char* argv[]) {
case 'v':
verbose = true;
break;
- case 'C':
- return CLEAN_SCRATCH_FILES;
default:
LOG(ERROR) << "Bad Argument -" << char(opt);
usage(BADARG);
@@ -426,8 +420,7 @@ static int do_remount(int argc, char* argv[]) {
break;
}
// Find overlayfs mount point?
- if ((mount_point == "/" && rentry.mount_point == "/system") ||
- (mount_point == "/system" && rentry.mount_point == "/")) {
+ if ((mount_point == "/") && (rentry.mount_point == "/system")) {
blk_device = rentry.blk_device;
mount_point = "/system";
found = true;
@@ -482,24 +475,13 @@ static int do_remount(int argc, char* argv[]) {
return retval;
}
-static int do_clean_scratch_files() {
- android::fs_mgr::CleanupOldScratchFiles();
- return 0;
-}
-
int main(int argc, char* argv[]) {
android::base::InitLogging(argv, MyLogger);
- if (argc > 0 && android::base::Basename(argv[0]) == "clean_scratch_files"s) {
- return do_clean_scratch_files();
- }
int result = do_remount(argc, argv);
if (result == MUST_REBOOT) {
LOG(INFO) << "Now reboot your device for settings to take effect";
- result = 0;
} else if (result == REMOUNT_SUCCESS) {
printf("remount succeeded\n");
- } else if (result == CLEAN_SCRATCH_FILES) {
- return do_clean_scratch_files();
} else {
printf("remount failed\n");
}
diff --git a/fs_mgr/fs_mgr_roots.cpp b/fs_mgr/fs_mgr_roots.cpp
index 2ad8125e7..fdaffbeb0 100644
--- a/fs_mgr/fs_mgr_roots.cpp
+++ b/fs_mgr/fs_mgr_roots.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "android-base/file.h"
#include "fs_mgr/roots.h"
#include <sys/mount.h>
@@ -40,26 +39,18 @@ FstabEntry* GetEntryForPath(Fstab* fstab, const std::string& path) {
while (true) {
auto entry = GetEntryForMountPoint(fstab, str);
if (entry != nullptr) return entry;
- str = android::base::Dirname(str);
- if (!str.compare(".") || !str.compare("/")) break;
+ if (str == "/") break;
+ auto slash = str.find_last_of('/');
+ if (slash == std::string::npos) break;
+ if (slash == 0) {
+ str = "/";
+ } else {
+ str = str.substr(0, slash);
+ }
}
return nullptr;
}
-std::vector<FstabEntry*> GetEntriesForPath(Fstab* fstab, const std::string& path) {
- std::vector<FstabEntry*> entries;
- if (path.empty()) return entries;
-
- std::string str(path);
- while (true) {
- entries = GetEntriesForMountPoint(fstab, str);
- if (!entries.empty()) return entries;
- str = android::base::Dirname(str);
- if (!str.compare(".") || !str.compare("/")) break;
- }
- return entries;
-}
-
enum class MountState {
ERROR = -1,
NOT_MOUNTED = 0,
@@ -80,7 +71,12 @@ static MountState GetMountState(const std::string& mount_point) {
return MountState::NOT_MOUNTED;
}
-bool TryPathMount(FstabEntry* rec, const std::string& mount_pt) {
+bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_pt) {
+ auto rec = GetEntryForPath(fstab, path);
+ if (rec == nullptr) {
+ LERROR << "unknown volume for path [" << path << "]";
+ return false;
+ }
if (rec->fs_type == "ramdisk") {
// The ramdisk is always mounted.
return true;
@@ -125,7 +121,8 @@ bool TryPathMount(FstabEntry* rec, const std::string& mount_pt) {
int result = fs_mgr_do_mount_one(*rec, mount_point);
if (result == -1 && rec->fs_mgr_flags.formattable) {
PERROR << "Failed to mount " << mount_point << "; formatting";
- if (fs_mgr_do_format(*rec) != 0) {
+ bool crypt_footer = rec->is_encryptable() && rec->key_loc == "footer";
+ if (fs_mgr_do_format(*rec, crypt_footer) != 0) {
PERROR << "Failed to format " << mount_point;
return false;
}
@@ -139,21 +136,6 @@ bool TryPathMount(FstabEntry* rec, const std::string& mount_pt) {
return true;
}
-bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_point) {
- auto entries = GetEntriesForPath(fstab, path);
- if (entries.empty()) {
- LERROR << "unknown volume for path [" << path << "]";
- return false;
- }
-
- for (auto entry : entries) {
- if (TryPathMount(entry, mount_point)) return true;
- }
-
- LERROR << "Failed to mount for path [" << path << "]";
- return false;
-}
-
bool EnsurePathUnmounted(Fstab* fstab, const std::string& path) {
auto rec = GetEntryForPath(fstab, path);
if (rec == nullptr) {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
new file mode 100644
index 000000000..efa218078
--- /dev/null
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <crypto_utils/android_pubkey.h>
+#include <cutils/properties.h>
+#include <fs_mgr/file_wait.h>
+#include <libdm/dm.h>
+#include <logwrap/logwrap.h>
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+#include "fec/io.h"
+
+#include "fs_mgr.h"
+#include "fs_mgr_dm_linear.h"
+#include "fs_mgr_priv.h"
+
+// Realistically, this file should be part of the android::fs_mgr namespace;
+using namespace android::fs_mgr;
+
+#define VERITY_TABLE_RSA_KEY "/verity_key"
+#define VERITY_TABLE_HASH_IDX 8
+#define VERITY_TABLE_SALT_IDX 9
+
+#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
+#define VERITY_TABLE_OPT_LOGGING "ignore_corruption"
+#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
+
+#define VERITY_TABLE_OPT_FEC_FORMAT \
+ "use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 \
+ " fec_roots %u " VERITY_TABLE_OPT_IGNZERO
+#define VERITY_TABLE_OPT_FEC_ARGS 9
+
+#define METADATA_MAGIC 0x01564c54
+#define METADATA_TAG_MAX_LENGTH 63
+#define METADATA_EOD "eod"
+
+#define VERITY_LASTSIG_TAG "verity_lastsig"
+
+#define VERITY_STATE_TAG "verity_state"
+#define VERITY_STATE_HEADER 0x83c0ae9d
+#define VERITY_STATE_VERSION 1
+
+#define VERITY_KMSG_RESTART "dm-verity device corrupted"
+#define VERITY_KMSG_BUFSIZE 1024
+
+#define READ_BUF_SIZE 4096
+
+#define __STRINGIFY(x) #x
+#define STRINGIFY(x) __STRINGIFY(x)
+
+struct verity_state {
+ uint32_t header;
+ uint32_t version;
+ int32_t mode;
+};
+
+extern struct fs_info info;
+
+static RSA *load_key(const char *path)
+{
+ uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+
+ auto f = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path, "re"), fclose};
+ if (!f) {
+ LERROR << "Can't open " << path;
+ return nullptr;
+ }
+
+ if (!fread(key_data, sizeof(key_data), 1, f.get())) {
+ LERROR << "Could not read key!";
+ return nullptr;
+ }
+
+ RSA* key = nullptr;
+ if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
+ LERROR << "Could not parse key!";
+ return nullptr;
+ }
+
+ return key;
+}
+
+static int verify_table(const uint8_t *signature, size_t signature_size,
+ const char *table, uint32_t table_length)
+{
+ RSA *key;
+ uint8_t hash_buf[SHA256_DIGEST_LENGTH];
+ int retval = -1;
+
+ // Hash the table
+ SHA256((uint8_t*)table, table_length, hash_buf);
+
+ // Now get the public key from the keyfile
+ key = load_key(VERITY_TABLE_RSA_KEY);
+ if (!key) {
+ LERROR << "Couldn't load verity keys";
+ goto out;
+ }
+
+ // verify the result
+ if (!RSA_verify(NID_sha256, hash_buf, sizeof(hash_buf), signature,
+ signature_size, key)) {
+ LERROR << "Couldn't verify table";
+ goto out;
+ }
+
+ retval = 0;
+
+out:
+ RSA_free(key);
+ return retval;
+}
+
+static int verify_verity_signature(const struct fec_verity_metadata& verity)
+{
+ if (verify_table(verity.signature, sizeof(verity.signature),
+ verity.table, verity.table_length) == 0 ||
+ verify_table(verity.ecc_signature, sizeof(verity.ecc_signature),
+ verity.table, verity.table_length) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static int invalidate_table(char *table, size_t table_length)
+{
+ size_t n = 0;
+ size_t idx = 0;
+ size_t cleared = 0;
+
+ while (n < table_length) {
+ if (table[n++] == ' ') {
+ ++idx;
+ }
+
+ if (idx != VERITY_TABLE_HASH_IDX && idx != VERITY_TABLE_SALT_IDX) {
+ continue;
+ }
+
+ while (n < table_length && table[n] != ' ') {
+ table[n++] = '0';
+ }
+
+ if (++cleared == 2) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+struct verity_table_params {
+ char *table;
+ int mode;
+ struct fec_ecc_metadata ecc;
+ const char *ecc_dev;
+};
+
+typedef bool (*format_verity_table_func)(char *buf, const size_t bufsize,
+ const struct verity_table_params *params);
+
+static bool format_verity_table(char *buf, const size_t bufsize,
+ const struct verity_table_params *params)
+{
+ const char *mode_flag = NULL;
+ int res = -1;
+
+ if (params->mode == VERITY_MODE_RESTART) {
+ mode_flag = VERITY_TABLE_OPT_RESTART;
+ } else if (params->mode == VERITY_MODE_LOGGING) {
+ mode_flag = VERITY_TABLE_OPT_LOGGING;
+ }
+
+ if (params->ecc.valid) {
+ if (mode_flag) {
+ res = snprintf(buf, bufsize,
+ "%s %u %s " VERITY_TABLE_OPT_FEC_FORMAT,
+ params->table, 1 + VERITY_TABLE_OPT_FEC_ARGS, mode_flag, params->ecc_dev,
+ params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
+ } else {
+ res = snprintf(buf, bufsize,
+ "%s %u " VERITY_TABLE_OPT_FEC_FORMAT,
+ params->table, VERITY_TABLE_OPT_FEC_ARGS, params->ecc_dev,
+ params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
+ }
+ } else if (mode_flag) {
+ res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
+ mode_flag);
+ } else {
+ res = snprintf(buf, bufsize, "%s 1 " VERITY_TABLE_OPT_IGNZERO, params->table);
+ }
+
+ if (res < 0 || (size_t)res >= bufsize) {
+ LERROR << "Error building verity table; insufficient buffer size?";
+ return false;
+ }
+
+ return true;
+}
+
+static bool format_legacy_verity_table(char *buf, const size_t bufsize,
+ const struct verity_table_params *params)
+{
+ int res;
+
+ if (params->mode == VERITY_MODE_EIO) {
+ res = strlcpy(buf, params->table, bufsize);
+ } else {
+ res = snprintf(buf, bufsize, "%s %d", params->table, params->mode);
+ }
+
+ if (res < 0 || (size_t)res >= bufsize) {
+ LERROR << "Error building verity table; insufficient buffer size?";
+ return false;
+ }
+
+ return true;
+}
+
+static int load_verity_table(android::dm::DeviceMapper& dm, const std::string& name,
+ uint64_t device_size, const struct verity_table_params* params,
+ format_verity_table_func format) {
+ android::dm::DmTable table;
+ table.set_readonly(true);
+
+ char buffer[DM_BUF_SIZE];
+ if (!format(buffer, sizeof(buffer), params)) {
+ LERROR << "Failed to format verity parameters";
+ return -1;
+ }
+
+ android::dm::DmTargetVerityString target(0, device_size / 512, buffer);
+ if (!table.AddTarget(std::make_unique<decltype(target)>(target))) {
+ LERROR << "Failed to add verity target";
+ return -1;
+ }
+ if (!dm.CreateDevice(name, table)) {
+ LERROR << "Failed to create verity device \"" << name << "\"";
+ return -1;
+ }
+ return 0;
+}
+
+static int read_partition(const char *path, uint64_t size)
+{
+ char buf[READ_BUF_SIZE];
+ ssize_t size_read;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)));
+
+ if (fd == -1) {
+ PERROR << "Failed to open " << path;
+ return -errno;
+ }
+
+ while (size) {
+ size_read = TEMP_FAILURE_RETRY(read(fd, buf, READ_BUF_SIZE));
+ if (size_read == -1) {
+ PERROR << "Error in reading partition " << path;
+ return -errno;
+ }
+ size -= size_read;
+ }
+
+ return 0;
+}
+
+bool fs_mgr_load_verity_state(int* mode) {
+ // unless otherwise specified, use EIO mode.
+ *mode = VERITY_MODE_EIO;
+
+ // The bootloader communicates verity mode via the kernel commandline
+ std::string verity_mode;
+ if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
+ return false;
+ }
+
+ if (verity_mode == "enforcing") {
+ *mode = VERITY_MODE_DEFAULT;
+ } else if (verity_mode == "logging") {
+ *mode = VERITY_MODE_LOGGING;
+ }
+
+ return true;
+}
+
+// Update the verity table using the actual block device path.
+// Two cases:
+// Case-1: verity table is shared for devices with different by-name prefix.
+// Example:
+// verity table token: /dev/block/bootdevice/by-name/vendor
+// blk_device-1 (non-A/B): /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
+// blk_device-2 (A/B): /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor_a
+//
+// Case-2: append A/B suffix in the verity table.
+// Example:
+// verity table token: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
+// blk_device: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor_a
+static void update_verity_table_blk_device(const std::string& blk_device, char** table,
+ bool slot_select) {
+ bool updated = false;
+ std::string result, ab_suffix;
+ auto tokens = android::base::Split(*table, " ");
+
+ // If slot_select is set, it means blk_device is already updated with ab_suffix.
+ if (slot_select) ab_suffix = fs_mgr_get_slot_suffix();
+
+ for (const auto& token : tokens) {
+ std::string new_token;
+ if (android::base::StartsWith(token, "/dev/block/")) {
+ if (token == blk_device) return; // no need to update if they're already the same.
+ std::size_t found1 = blk_device.find("by-name");
+ std::size_t found2 = token.find("by-name");
+ if (found1 != std::string::npos && found2 != std::string::npos &&
+ blk_device.substr(found1) == token.substr(found2) + ab_suffix) {
+ new_token = blk_device;
+ }
+ }
+
+ if (!new_token.empty()) {
+ updated = true;
+ LINFO << "Verity table: updated block device from '" << token << "' to '" << new_token
+ << "'";
+ } else {
+ new_token = token;
+ }
+
+ if (result.empty()) {
+ result = new_token;
+ } else {
+ result += " " + new_token;
+ }
+ }
+
+ if (!updated) {
+ return;
+ }
+
+ free(*table);
+ *table = strdup(result.c_str());
+}
+
+// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
+// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
+// verity device to get created before return
+int fs_mgr_setup_verity(FstabEntry* entry, bool wait_for_verity_dev) {
+ int retval = FS_MGR_SETUP_VERITY_FAIL;
+ int fd = -1;
+ std::string verity_blk_name;
+ struct fec_handle *f = NULL;
+ struct fec_verity_metadata verity;
+ struct verity_table_params params = { .table = NULL };
+
+ const std::string mount_point(basename(entry->mount_point.c_str()));
+ bool verified_at_boot = false;
+
+ android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
+
+ if (fec_open(&f, entry->blk_device.c_str(), O_RDONLY, FEC_VERITY_DISABLE, FEC_DEFAULT_ROOTS) <
+ 0) {
+ PERROR << "Failed to open '" << entry->blk_device << "'";
+ return retval;
+ }
+
+ // read verity metadata
+ if (fec_verity_get_metadata(f, &verity) < 0) {
+ PERROR << "Failed to get verity metadata '" << entry->blk_device << "'";
+ // Allow verity disabled when the device is unlocked without metadata
+ if (fs_mgr_is_device_unlocked()) {
+ retval = FS_MGR_SETUP_VERITY_SKIPPED;
+ LWARNING << "Allow invalid metadata when the device is unlocked";
+ }
+ goto out;
+ }
+
+#ifdef ALLOW_ADBD_DISABLE_VERITY
+ if (verity.disabled) {
+ retval = FS_MGR_SETUP_VERITY_DISABLED;
+ LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG/ENG";
+ goto out;
+ }
+#endif
+
+ // read ecc metadata
+ if (fec_ecc_get_metadata(f, &params.ecc) < 0) {
+ params.ecc.valid = false;
+ }
+
+ params.ecc_dev = entry->blk_device.c_str();
+
+ if (!fs_mgr_load_verity_state(&params.mode)) {
+ /* if accessing or updating the state failed, switch to the default
+ * safe mode. This makes sure the device won't end up in an endless
+ * restart loop, and no corrupted data will be exposed to userspace
+ * without a warning. */
+ params.mode = VERITY_MODE_EIO;
+ }
+
+ if (!verity.table) {
+ goto out;
+ }
+
+ params.table = strdup(verity.table);
+ if (!params.table) {
+ goto out;
+ }
+
+ // verify the signature on the table
+ if (verify_verity_signature(verity) < 0) {
+ // Allow signature verification error when the device is unlocked
+ if (fs_mgr_is_device_unlocked()) {
+ retval = FS_MGR_SETUP_VERITY_SKIPPED;
+ LWARNING << "Allow signature verification error when the device is unlocked";
+ goto out;
+ }
+ if (params.mode == VERITY_MODE_LOGGING) {
+ // the user has been warned, allow mounting without dm-verity
+ retval = FS_MGR_SETUP_VERITY_SKIPPED;
+ goto out;
+ }
+
+ // invalidate root hash and salt to trigger device-specific recovery
+ if (invalidate_table(params.table, verity.table_length) < 0) {
+ goto out;
+ }
+ }
+
+ LINFO << "Enabling dm-verity for " << mount_point.c_str()
+ << " (mode " << params.mode << ")";
+
+ // Update the verity params using the actual block device path
+ update_verity_table_blk_device(entry->blk_device, &params.table,
+ entry->fs_mgr_flags.slot_select);
+
+ // load the verity mapping table
+ if (load_verity_table(dm, mount_point, verity.data_size, &params, format_verity_table) == 0) {
+ goto loaded;
+ }
+
+ if (params.ecc.valid) {
+ // kernel may not support error correction, try without
+ LINFO << "Disabling error correction for " << mount_point.c_str();
+ params.ecc.valid = false;
+
+ if (load_verity_table(dm, mount_point, verity.data_size, &params, format_verity_table) == 0) {
+ goto loaded;
+ }
+ }
+
+ // try the legacy format for backwards compatibility
+ if (load_verity_table(dm, mount_point, verity.data_size, &params, format_legacy_verity_table) ==
+ 0) {
+ goto loaded;
+ }
+
+ if (params.mode != VERITY_MODE_EIO) {
+ // as a last resort, EIO mode should always be supported
+ LINFO << "Falling back to EIO mode for " << mount_point.c_str();
+ params.mode = VERITY_MODE_EIO;
+
+ if (load_verity_table(dm, mount_point, verity.data_size, &params,
+ format_legacy_verity_table) == 0) {
+ goto loaded;
+ }
+ }
+
+ LERROR << "Failed to load verity table for " << mount_point.c_str();
+ goto out;
+
+loaded:
+ if (!dm.GetDmDevicePathByName(mount_point, &verity_blk_name)) {
+ LERROR << "Couldn't get verity device number!";
+ goto out;
+ }
+
+ // mark the underlying block device as read-only
+ fs_mgr_set_blk_ro(entry->blk_device);
+
+ // Verify the entire partition in one go
+ // If there is an error, allow it to mount as a normal verity partition.
+ if (entry->fs_mgr_flags.verify_at_boot) {
+ LINFO << "Verifying partition " << entry->blk_device << " at boot";
+ int err = read_partition(verity_blk_name.c_str(), verity.data_size);
+ if (!err) {
+ LINFO << "Verified verity partition " << entry->blk_device << " at boot";
+ verified_at_boot = true;
+ }
+ }
+
+ // assign the new verity block device as the block device
+ if (!verified_at_boot) {
+ entry->blk_device = verity_blk_name;
+ } else if (!dm.DeleteDevice(mount_point)) {
+ LERROR << "Failed to remove verity device " << mount_point.c_str();
+ goto out;
+ }
+
+ // make sure we've set everything up properly
+ if (wait_for_verity_dev && !WaitForFile(entry->blk_device, 1s)) {
+ goto out;
+ }
+
+ retval = FS_MGR_SETUP_VERITY_SUCCESS;
+
+out:
+ if (fd != -1) {
+ close(fd);
+ }
+
+ fec_close(f);
+ free(params.table);
+
+ return retval;
+}
+
+bool fs_mgr_teardown_verity(FstabEntry* entry) {
+ const std::string mount_point(basename(entry->mount_point.c_str()));
+ if (!android::fs_mgr::UnmapDevice(mount_point)) {
+ return false;
+ }
+ LINFO << "Unmapped verity device " << mount_point;
+ return true;
+}
diff --git a/fs_mgr/fuzz/Android.bp b/fs_mgr/fuzz/Android.bp
deleted file mode 100644
index b2b9be8bf..000000000
--- a/fs_mgr/fuzz/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_fuzz {
- name: "libfstab_fuzzer",
- srcs: [
- "fs_mgr_fstab_fuzzer.cpp",
- ],
- static_libs: [
- "libfstab",
- ],
- shared_libs: [
- "libbase",
- ],
-
- dictionary: "fstab.dict",
- fuzz_config: {
- cc: [
- "yochiang@google.com",
- ],
- },
-}
diff --git a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp b/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
deleted file mode 100644
index 6a8a19176..000000000
--- a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// 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 <cstdio>
-
-#include <fstab/fstab.h>
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- std::string make_fstab_str(reinterpret_cast<const char*>(data), size);
- android::fs_mgr::Fstab fstab;
- android::fs_mgr::ParseFstabFromString(make_fstab_str, /* proc_mounts = */ false, &fstab);
- return 0;
-}
diff --git a/fs_mgr/fuzz/fstab.dict b/fs_mgr/fuzz/fstab.dict
deleted file mode 100644
index 84dddf740..000000000
--- a/fs_mgr/fuzz/fstab.dict
+++ /dev/null
@@ -1,70 +0,0 @@
-"#"
-"="
-","
-"f2fs"
-
-# mount flags
-"noatime"
-"noexec"
-"nosuid"
-"nodev"
-"nodiratime"
-"ro"
-"rw"
-"sync"
-"remount"
-"bind"
-"rec"
-"unbindable"
-"private"
-"slave"
-"shared"
-"defaults"
-
-# fs_mgr flags
-"wait"
-"check"
-"nonremovable"
-"recoveryonly"
-"noemulatedsd"
-"notrim"
-"verify"
-"formattable"
-"slotselect"
-"latemount"
-"nofail"
-"verifyatboot"
-"quota"
-"avb"
-"logical"
-"checkpoint=block"
-"checkpoint=fs"
-"first_stage_mount"
-"slotselect_other"
-"fsverity"
-"metadata_csum"
-"fscompress"
-"overlayfs_remove_missing_lowerdir"
-
-# fs_mgr flags that expect an argument
-"reserve_root="
-"lowerdir="
-"encryptable="
-"voldmanaged="
-"length="
-"swapprio="
-"zramsize="
-"forceencrypt="
-"fileencryption="
-"forcefdeorfbe="
-"max_comp_streams="
-"reservedsize="
-"readahead_size_kb="
-"eraseblk="
-"logicalblk="
-"avb_keys="
-"avb="
-"keydirectory="
-"metadata_encryption="
-"sysfs_path="
-"zram_backingdev_size="
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 29a5e60e6..4d3ecc9dc 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -22,7 +22,6 @@
#include <linux/dm-ioctl.h>
#include <functional>
-#include <optional>
#include <string>
#include <fstab/fstab.h>
@@ -56,6 +55,9 @@ enum mount_mode {
#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
+#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
+#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 2
+#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
@@ -66,13 +68,6 @@ struct MountAllResult {
bool userdata_mounted;
};
-struct HashtreeInfo {
- // The hash algorithm used to build the merkle tree.
- std::string algorithm;
- // The root digest of the merkle tree.
- std::string root_digest;
-};
-
// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
// Returns a |MountAllResult|. The first element is one of the FS_MNG_MNTALL_* return codes
// defined above, and the second element tells whether this call to fs_mgr_mount_all was responsible
@@ -93,9 +88,9 @@ int fs_mgr_do_tmpfs_mount(const char *n_name);
bool fs_mgr_load_verity_state(int* mode);
// Returns true if verity is enabled on this particular FstabEntry.
bool fs_mgr_is_verity_enabled(const android::fs_mgr::FstabEntry& entry);
-// Returns the verity hashtree information of this particular FstabEntry. Returns std::nullopt
-// if the input isn't a dm-verity entry, or if there is an error.
-std::optional<HashtreeInfo> fs_mgr_get_hashtree_info(const android::fs_mgr::FstabEntry& entry);
+// Returns the hash algorithm used to build the hashtree of this particular FstabEntry. Returns an
+// empty string if the input isn't a dm-verity entry, or if there is an error.
+std::string fs_mgr_get_hashtree_algorithm(const android::fs_mgr::FstabEntry& entry);
bool fs_mgr_swapon_all(const android::fs_mgr::Fstab& fstab);
bool fs_mgr_update_logical_partition(android::fs_mgr::FstabEntry* entry);
@@ -104,7 +99,7 @@ bool fs_mgr_update_logical_partition(android::fs_mgr::FstabEntry* entry);
// device is in "check_at_most_once" mode.
bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry);
-int fs_mgr_do_format(const android::fs_mgr::FstabEntry& entry);
+int fs_mgr_do_format(const android::fs_mgr::FstabEntry& entry, bool reserve_footer);
#define FS_MGR_SETUP_VERITY_SKIPPED (-3)
#define FS_MGR_SETUP_VERITY_DISABLED (-2)
diff --git a/fs_mgr/include/fs_mgr/file_wait.h b/fs_mgr/include/fs_mgr/file_wait.h
index 294e72723..74d160ed1 100644
--- a/fs_mgr/include/fs_mgr/file_wait.h
+++ b/fs_mgr/include/fs_mgr/file_wait.h
@@ -23,9 +23,6 @@ namespace fs_mgr {
// Wait at most |relative_timeout| milliseconds for |path| to exist. dirname(path)
// must already exist. For example, to wait on /dev/block/dm-6, /dev/block must
// be a valid directory.
-//
-// If relative_timeout is std::chrono::milliseconds::max(), then the wait will
-// block indefinitely.
bool WaitForFile(const std::string& path, const std::chrono::milliseconds relative_timeout);
// Wait at most |relative_timeout| milliseconds for |path| to stop existing.
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index f26fb245a..f33768b9d 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -37,8 +37,9 @@ struct FstabEntry {
unsigned long flags = 0;
std::string fs_options;
std::string fs_checkpoint_opts;
+ std::string key_loc;
std::string metadata_key_dir;
- std::string metadata_encryption_options;
+ std::string metadata_encryption;
off64_t length = 0;
std::string label;
int partnum = -1;
@@ -59,18 +60,22 @@ struct FstabEntry {
struct FsMgrFlags {
bool wait : 1;
bool check : 1;
- bool crypt : 1; // Now only used to identify adoptable storage volumes
+ bool crypt : 1;
bool nonremovable : 1;
bool vold_managed : 1;
bool recovery_only : 1;
+ bool verify : 1;
+ bool force_crypt : 1;
bool no_emulated_sd : 1; // No emulated sdcard daemon; sd card is the only external
// storage.
bool no_trim : 1;
bool file_encryption : 1;
bool formattable : 1;
bool slot_select : 1;
+ bool force_fde_or_fbe : 1;
bool late_mount : 1;
bool no_fail : 1;
+ bool verify_at_boot : 1;
bool quota : 1;
bool avb : 1;
bool logical : 1;
@@ -81,10 +86,11 @@ struct FstabEntry {
bool fs_verity : 1;
bool ext_meta_csum : 1;
bool fs_compress : 1;
- bool overlayfs_remove_missing_lowerdir : 1;
} fs_mgr_flags = {};
- bool is_encryptable() const { return fs_mgr_flags.crypt; }
+ bool is_encryptable() const {
+ return fs_mgr_flags.crypt || fs_mgr_flags.force_crypt || fs_mgr_flags.force_fde_or_fbe;
+ }
};
// An Fstab is a collection of FstabEntry structs.
@@ -92,9 +98,6 @@ struct FstabEntry {
// Unless explicitly requested, a lookup on mount point should always return the 1st one.
using Fstab = std::vector<FstabEntry>;
-// Exported for testability. Regular users should use ReadFstabFromFile().
-bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out);
-
bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
bool ReadFstabFromDt(Fstab* fstab, bool verbose = true);
bool ReadDefaultFstab(Fstab* fstab);
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 2bb90356b..428a7f4ec 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -86,9 +86,7 @@ cc_test {
name: "vts_libdm_test",
defaults: ["libdm_test_defaults"],
test_suites: ["vts"],
- test_options: {
- min_shipping_api_level: 29,
- },
+ test_min_api_level: 29,
}
cc_fuzz {
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 4034e30ab..e43c00b44 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -170,18 +170,19 @@ static bool IsRecovery() {
return access("/system/bin/recovery", F_OK) == 0;
}
-bool DeviceMapper::CreateEmptyDevice(const std::string& name) {
+bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+ const std::chrono::milliseconds& timeout_ms) {
std::string uuid = GenerateUuid();
- return CreateDevice(name, uuid);
-}
+ if (!CreateDevice(name, uuid)) {
+ return false;
+ }
-bool DeviceMapper::WaitForDevice(const std::string& name,
- const std::chrono::milliseconds& timeout_ms, std::string* path) {
// We use the unique path for testing whether the device is ready. After
// that, it's safe to use the dm-N path which is compatible with callers
// that expect it to be formatted as such.
std::string unique_path;
- if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) {
+ if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
+ !GetDmDevicePathByName(name, path)) {
DeleteDevice(name);
return false;
}
@@ -207,25 +208,6 @@ bool DeviceMapper::WaitForDevice(const std::string& name,
return true;
}
-bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
- const std::chrono::milliseconds& timeout_ms) {
- if (!CreateEmptyDevice(name)) {
- return false;
- }
-
- if (!LoadTableAndActivate(name, table)) {
- DeleteDevice(name);
- return false;
- }
-
- if (!WaitForDevice(name, timeout_ms, path)) {
- DeleteDevice(name);
- return false;
- }
-
- return true;
-}
-
bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
struct dm_ioctl io;
InitIo(&io, name);
@@ -647,61 +629,5 @@ bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const {
return spec.target_type == "snapshot"s && data == "Overflow"s;
}
-// Find directories in format of "/sys/block/dm-X".
-static int DmNameFilter(const dirent* de) {
- if (android::base::StartsWith(de->d_name, "dm-")) {
- return 1;
- }
- return 0;
-}
-
-std::map<std::string, std::string> DeviceMapper::FindDmPartitions() {
- static constexpr auto DM_PATH_PREFIX = "/sys/block/";
- dirent** namelist;
- int n = scandir(DM_PATH_PREFIX, &namelist, DmNameFilter, alphasort);
- if (n == -1) {
- PLOG(ERROR) << "Failed to scan dir " << DM_PATH_PREFIX;
- return {};
- }
- if (n == 0) {
- LOG(ERROR) << "No dm block device found.";
- free(namelist);
- return {};
- }
-
- static constexpr auto DM_PATH_SUFFIX = "/dm/name";
- static constexpr auto DEV_PATH = "/dev/block/";
- std::map<std::string, std::string> dm_block_devices;
- while (n--) {
- std::string path = DM_PATH_PREFIX + std::string(namelist[n]->d_name) + DM_PATH_SUFFIX;
- std::string content;
- if (!android::base::ReadFileToString(path, &content)) {
- PLOG(WARNING) << "Failed to read " << path;
- } else {
- std::string dm_block_name = android::base::Trim(content);
- // AVB is using 'vroot' for the root block device but we're expecting 'system'.
- if (dm_block_name == "vroot") {
- dm_block_name = "system";
- } else if (android::base::EndsWith(dm_block_name, "-verity")) {
- auto npos = dm_block_name.rfind("-verity");
- dm_block_name = dm_block_name.substr(0, npos);
- } else if (!android::base::GetProperty("ro.boot.avb_version", "").empty()) {
- // Verified Boot 1.0 doesn't add a -verity suffix. On AVB 2 devices,
- // if DAP is enabled, then a -verity suffix must be used to
- // differentiate between dm-linear and dm-verity devices. If we get
- // here, we're AVB 2 and looking at a non-verity partition.
- free(namelist[n]);
- continue;
- }
-
- dm_block_devices.emplace(dm_block_name, DEV_PATH + std::string(namelist[n]->d_name));
- }
- free(namelist[n]);
- }
- free(namelist);
-
- return dm_block_devices;
-}
-
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 90d91a00c..b0639e611 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -109,10 +109,6 @@ void DmTargetVerity::IgnoreZeroBlocks() {
optional_args_.emplace_back("ignore_zero_blocks");
}
-void DmTargetVerity::CheckAtMostOnce() {
- optional_args_.emplace_back("check_at_most_once");
-}
-
std::string DmTargetVerity::GetParameterString() const {
std::string base = android::base::Join(base_args_, " ");
if (optional_args_.empty()) {
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 541f254cb..8006db220 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -29,7 +29,6 @@
#include <thread>
#include <android-base/file.h>
-#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
@@ -680,13 +679,3 @@ TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) {
ASSERT_NE(0, access(path.c_str(), F_OK));
ASSERT_EQ(ENOENT, errno);
}
-
-TEST(libdm, CreateEmptyDevice) {
- DeviceMapper& dm = DeviceMapper::Instance();
- ASSERT_TRUE(dm.CreateEmptyDevice("empty-device"));
- auto guard =
- android::base::make_scope_guard([&]() { dm.DeleteDeviceIfExists("empty-device", 5s); });
-
- // Empty device should be in suspended state.
- ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
-}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 1057d7f7a..bdbbf9112 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -17,18 +17,15 @@
#ifndef _LIBDM_DM_H_
#define _LIBDM_DM_H_
-#include <dirent.h>
#include <fcntl.h>
#include <linux/dm-ioctl.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <stdint.h>
#include <sys/sysmacros.h>
-#include <sys/types.h>
#include <unistd.h>
#include <chrono>
-#include <map>
#include <memory>
#include <optional>
#include <string>
@@ -56,33 +53,7 @@ static constexpr uint64_t kSectorSize = 512;
// that prefix.
std::optional<std::string> ExtractBlockDeviceName(const std::string& path);
-// This interface is for testing purposes. See DeviceMapper proper for what these methods do.
-class IDeviceMapper {
- public:
- virtual ~IDeviceMapper() {}
-
- struct TargetInfo {
- struct dm_target_spec spec;
- std::string data;
- TargetInfo() {}
- TargetInfo(const struct dm_target_spec& spec, const std::string& data)
- : spec(spec), data(data) {}
-
- bool IsOverflowSnapshot() const;
- };
-
- virtual bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
- const std::chrono::milliseconds& timeout_ms) = 0;
- virtual DmDeviceState GetState(const std::string& name) const = 0;
- virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) = 0;
- virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) = 0;
- virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) = 0;
- virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) = 0;
- virtual bool GetDeviceString(const std::string& name, std::string* dev) = 0;
- virtual bool DeleteDeviceIfExists(const std::string& name) = 0;
-};
-
-class DeviceMapper final : public IDeviceMapper {
+class DeviceMapper final {
public:
class DmBlockDevice final {
public:
@@ -122,7 +93,7 @@ class DeviceMapper final : public IDeviceMapper {
// Removes a device mapper device with the given name.
// Returns 'true' on success, false otherwise.
bool DeleteDevice(const std::string& name);
- bool DeleteDeviceIfExists(const std::string& name) override;
+ bool DeleteDeviceIfExists(const std::string& name);
// Removes a device mapper device with the given name and waits for |timeout_ms| milliseconds
// for the corresponding block device to be deleted.
bool DeleteDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
@@ -141,26 +112,13 @@ class DeviceMapper final : public IDeviceMapper {
// Returns the current state of the underlying device mapper device
// with given name.
// One of INVALID, SUSPENDED or ACTIVE.
- DmDeviceState GetState(const std::string& name) const override;
+ DmDeviceState GetState(const std::string& name) const;
// Puts the given device to the specified status, which must be either:
// - SUSPENDED: suspend the device, or
// - ACTIVE: resumes the device.
bool ChangeState(const std::string& name, DmDeviceState state);
- // Creates empty device.
- // This supports a use case when a caller doesn't need a device straight away, but instead
- // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd
- // to create user space paths.
- // Callers are expected to then activate their device by calling LoadTableAndActivate function.
- // To avoid race conditions, callers must still synchronize with ueventd by calling
- // WaitForDevice function.
- bool CreateEmptyDevice(const std::string& name);
-
- // Waits for device paths to be created in the user space.
- bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
- std::string* path);
-
// Creates a device, loads the given table, and activates it. If the device
// is not able to be activated, it is destroyed, and false is returned.
// After creation, |path| contains the result of calling
@@ -185,7 +143,7 @@ class DeviceMapper final : public IDeviceMapper {
// not |path| is available. It is the caller's responsibility to ensure
// there are no races.
bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
- const std::chrono::milliseconds& timeout_ms) override;
+ const std::chrono::milliseconds& timeout_ms);
// Create a device and activate the given table, without waiting to acquire
// a valid path. If the caller will use GetDmDevicePathByName(), it should
@@ -197,7 +155,7 @@ class DeviceMapper final : public IDeviceMapper {
// process. A device with the given name must already exist.
//
// Returns 'true' on success, false otherwise.
- bool LoadTableAndActivate(const std::string& name, const DmTable& table) override;
+ bool LoadTableAndActivate(const std::string& name, const DmTable& table);
// Returns true if a list of available device mapper targets registered in the kernel was
// successfully read and stored in 'targets'. Returns 'false' otherwise.
@@ -243,7 +201,7 @@ class DeviceMapper final : public IDeviceMapper {
// Returns a major:minor string for the named device-mapper node, that can
// be used as inputs to DmTargets that take a block device.
- bool GetDeviceString(const std::string& name, std::string* dev) override;
+ bool GetDeviceString(const std::string& name, std::string* dev);
// The only way to create a DeviceMapper object.
static DeviceMapper& Instance();
@@ -258,11 +216,20 @@ class DeviceMapper final : public IDeviceMapper {
// contain one TargetInfo for each target in the table. If the device does
// not exist, or there were too many targets, the call will fail and return
// false.
- bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override;
+ struct TargetInfo {
+ struct dm_target_spec spec;
+ std::string data;
+ TargetInfo() {}
+ TargetInfo(const struct dm_target_spec& spec, const std::string& data)
+ : spec(spec), data(data) {}
+
+ bool IsOverflowSnapshot() const;
+ };
+ bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table);
// Identical to GetTableStatus, except also retrives the active table for the device
// mapper device from the kernel.
- bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) override;
+ bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table);
static std::string GetTargetType(const struct dm_target_spec& spec);
@@ -279,12 +246,6 @@ class DeviceMapper final : public IDeviceMapper {
// * A failure occurred.
std::optional<std::string> GetParentBlockDeviceByPath(const std::string& path);
- // Iterate the content over "/sys/block/dm-x/dm/name" and find
- // all the dm-wrapped block devices.
- //
- // Returns mapping <partition-name, /dev/block/dm-x>
- std::map<std::string, std::string> FindDmPartitions();
-
private:
// Maximum possible device mapper targets registered in the kernel.
// This is only used to read the list of targets from kernel so we allocate
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 954305816..478a3c69c 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -127,7 +127,6 @@ class DmTargetVerity final : public DmTarget {
void UseFec(const std::string& device, uint32_t num_roots, uint32_t num_blocks, uint32_t start);
void SetVerityMode(const std::string& mode);
void IgnoreZeroBlocks();
- void CheckAtMostOnce();
std::string name() const override { return "verity"; }
std::string GetParameterString() const override;
diff --git a/fs_mgr/libdm/include/libdm/loop_control.h b/fs_mgr/libdm/include/libdm/loop_control.h
index f5190544e..ad53c11ab 100644
--- a/fs_mgr/libdm/include/libdm/loop_control.h
+++ b/fs_mgr/libdm/include/libdm/loop_control.h
@@ -46,9 +46,6 @@ class LoopControl final {
// Enable Direct I/O on a loop device. This requires kernel 4.9+.
static bool EnableDirectIo(int fd);
- // Set LO_FLAGS_AUTOCLEAR on a loop device.
- static bool SetAutoClearStatus(int fd);
-
LoopControl(const LoopControl&) = delete;
LoopControl& operator=(const LoopControl&) = delete;
LoopControl& operator=(LoopControl&&) = default;
diff --git a/fs_mgr/libdm/loop_control.cpp b/fs_mgr/libdm/loop_control.cpp
index 32d5f383e..2e40a18e2 100644
--- a/fs_mgr/libdm/loop_control.cpp
+++ b/fs_mgr/libdm/loop_control.cpp
@@ -133,16 +133,6 @@ bool LoopControl::EnableDirectIo(int fd) {
return true;
}
-bool LoopControl::SetAutoClearStatus(int fd) {
- struct loop_info64 info = {};
-
- info.lo_flags |= LO_FLAGS_AUTOCLEAR;
- if (ioctl(fd, LOOP_SET_STATUS64, &info)) {
- return false;
- }
- return true;
-}
-
LoopDevice::LoopDevice(android::base::borrowed_fd fd, const std::chrono::milliseconds& timeout_ms,
bool auto_close)
: fd_(fd), owned_fd_(-1) {
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 5deba659d..1c5872e6f 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -20,8 +20,6 @@ package {
cc_library_headers {
name: "libfiemap_headers",
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
export_include_dirs: ["include"],
}
@@ -90,9 +88,7 @@ cc_test {
test_suites: ["vts", "device-tests"],
auto_gen_config: true,
- test_options: {
- min_shipping_api_level: 29,
- },
+ test_min_api_level: 29,
require_root: true,
}
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 003e6edb2..31a57a800 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -66,7 +66,6 @@ class ImageManagerBinder final : public IImageManager {
bool RemoveDisabledImages() override;
bool GetMappedImageDevice(const std::string& name, std::string* device) override;
bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
- bool IsImageDisabled(const std::string& name) override;
std::vector<std::string> GetAllBackingImages() override;
@@ -220,17 +219,6 @@ bool ImageManagerBinder::GetMappedImageDevice(const std::string& name, std::stri
return !device->empty();
}
-bool ImageManagerBinder::IsImageDisabled(const std::string& name) {
- bool retval;
- auto status = manager_->isImageDisabled(name, &retval);
- if (!status.isOk()) {
- LOG(ERROR) << __PRETTY_FUNCTION__
- << " binder returned: " << status.exceptionMessage().string();
- return false;
- }
- return retval;
-}
-
bool ImageManagerBinder::MapAllImages(const std::function<bool(std::set<std::string>)>&) {
LOG(ERROR) << __PRETTY_FUNCTION__ << " not available over binder";
return false;
diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp
index 275388ed9..8acb88536 100644
--- a/fs_mgr/libfiemap/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer.cpp
@@ -498,6 +498,24 @@ bool FiemapWriter::HasPinnedExtents(const std::string& file_path) {
return IsFilePinned(fd, file_path, sfs.f_type);
}
+static bool CountFiemapExtents(int file_fd, const std::string& file_path, uint32_t* num_extents) {
+ struct fiemap fiemap = {};
+ fiemap.fm_start = 0;
+ fiemap.fm_length = UINT64_MAX;
+ fiemap.fm_flags = FIEMAP_FLAG_SYNC;
+ fiemap.fm_extent_count = 0;
+
+ if (ioctl(file_fd, FS_IOC_FIEMAP, &fiemap)) {
+ PLOG(ERROR) << "Failed to get FIEMAP from the kernel for file: " << file_path;
+ return false;
+ }
+
+ if (num_extents) {
+ *num_extents = fiemap.fm_mapped_extents;
+ }
+ return true;
+}
+
static bool IsValidExtent(const fiemap_extent* extent, std::string_view file_path) {
if (extent->fe_flags & kUnsupportedExtentFlags) {
LOG(ERROR) << "Extent at location " << extent->fe_logical << " of file " << file_path
@@ -512,16 +530,12 @@ static bool IsLastExtent(const fiemap_extent* extent) {
}
static bool FiemapToExtents(struct fiemap* fiemap, std::vector<struct fiemap_extent>* extents,
- std::string_view file_path) {
- uint32_t num_extents = fiemap->fm_mapped_extents;
- if (num_extents == 0) {
- LOG(ERROR) << "File " << file_path << " has zero extent";
- return false;
- }
+ uint32_t num_extents, std::string_view file_path) {
+ if (num_extents == 0) return false;
+
const struct fiemap_extent* last_extent = &fiemap->fm_extents[num_extents - 1];
if (!IsLastExtent(last_extent)) {
- LOG(ERROR) << "FIEMAP did not return a final extent for file: " << file_path
- << " num_extents=" << num_extents << " max_extents=" << kMaxExtents;
+ LOG(ERROR) << "FIEMAP did not return a final extent for file: " << file_path;
return false;
}
@@ -563,7 +577,21 @@ static bool FiemapToExtents(struct fiemap* fiemap, std::vector<struct fiemap_ext
static bool ReadFiemap(int file_fd, const std::string& file_path,
std::vector<struct fiemap_extent>* extents) {
- uint64_t fiemap_size = sizeof(struct fiemap) + kMaxExtents * sizeof(struct fiemap_extent);
+ uint32_t num_extents;
+ if (!CountFiemapExtents(file_fd, file_path, &num_extents)) {
+ return false;
+ }
+ if (num_extents == 0) {
+ LOG(ERROR) << "File " << file_path << " has zero extents";
+ return false;
+ }
+ if (num_extents > kMaxExtents) {
+ LOG(ERROR) << "File has " << num_extents << ", maximum is " << kMaxExtents << ": "
+ << file_path;
+ return false;
+ }
+
+ uint64_t fiemap_size = sizeof(struct fiemap) + num_extents * sizeof(struct fiemap_extent);
auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, fiemap_size), free);
if (buffer == nullptr) {
LOG(ERROR) << "Failed to allocate memory for fiemap";
@@ -575,13 +603,19 @@ static bool ReadFiemap(int file_fd, const std::string& file_path,
fiemap->fm_length = UINT64_MAX;
// make sure file is synced to disk before we read the fiemap
fiemap->fm_flags = FIEMAP_FLAG_SYNC;
- fiemap->fm_extent_count = kMaxExtents;
+ fiemap->fm_extent_count = num_extents;
if (ioctl(file_fd, FS_IOC_FIEMAP, fiemap)) {
PLOG(ERROR) << "Failed to get FIEMAP from the kernel for file: " << file_path;
return false;
}
- return FiemapToExtents(fiemap, extents, file_path);
+ if (fiemap->fm_mapped_extents != num_extents) {
+ LOG(ERROR) << "FIEMAP returned unexpected extent count (" << num_extents
+ << " expected, got " << fiemap->fm_mapped_extents << ") for file: " << file_path;
+ return false;
+ }
+
+ return FiemapToExtents(fiemap, extents, num_extents, file_path);
}
static bool ReadFibmap(int file_fd, const std::string& file_path,
diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp
index c65481b78..3c8ab42c1 100644
--- a/fs_mgr/libfiemap/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp
@@ -16,7 +16,6 @@
#include <fcntl.h>
#include <inttypes.h>
-#include <linux/limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -258,13 +257,6 @@ TEST_F(FiemapWriterTest, FibmapBlockAddressing) {
EXPECT_EQ(memcmp(actual.data(), data.data(), data.size()), 0);
}
-TEST_F(FiemapWriterTest, CheckEmptyFile) {
- // Can't get any fiemap_extent out of a zero-sized file.
- FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 0);
- EXPECT_EQ(fptr, nullptr);
- EXPECT_EQ(access(testfile.c_str(), F_OK), -1);
-}
-
TEST_F(SplitFiemapTest, Create) {
auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32);
ASSERT_NE(ptr, nullptr);
@@ -307,27 +299,6 @@ TEST_F(SplitFiemapTest, DeleteOnFail) {
ASSERT_EQ(errno, ENOENT);
}
-TEST_F(SplitFiemapTest, CorruptSplit) {
- unique_fd fd(open(testfile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0700));
- ASSERT_GE(fd, 0);
-
- // Make a giant random string.
- std::vector<char> data;
- for (size_t i = 0x1; i < 0x7f; i++) {
- for (size_t j = 0; j < 100; j++) {
- data.emplace_back(i);
- }
- }
- ASSERT_GT(data.size(), PATH_MAX);
-
- data.emplace_back('\n');
-
- ASSERT_TRUE(android::base::WriteFully(fd, data.data(), data.size()));
- fd = {};
-
- ASSERT_TRUE(SplitFiemap::RemoveSplitFiles(testfile));
-}
-
static string ReadSplitFiles(const std::string& base_path, size_t num_files) {
std::string result;
for (int i = 0; i < num_files; i++) {
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index c416f4df4..dcbbc5448 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -79,7 +79,7 @@ ImageManager::ImageManager(const std::string& metadata_dir, const std::string& d
partition_opener_ = std::make_unique<android::fs_mgr::PartitionOpener>();
// Allow overriding whether ImageManager thinks it's in recovery, for testing.
-#ifdef __ANDROID_RAMDISK__
+#ifdef __ANDROID_RECOVERY__
device_info_.is_recovery = {true};
#else
if (!device_info_.is_recovery.has_value()) {
@@ -523,7 +523,7 @@ bool ImageManager::MapImageDevice(const std::string& name,
auto image_header = GetImageHeaderPath(name);
-#ifndef __ANDROID_RAMDISK__
+#if !defined __ANDROID_RECOVERY__
// If there is a device-mapper node wrapping the block device, then we're
// able to create another node around it; the dm layer does not carry the
// exclusion lock down the stack when a mount occurs.
@@ -696,12 +696,7 @@ bool ImageManager::RemoveDisabledImages() {
bool ok = true;
for (const auto& partition : metadata->partitions) {
if (partition.attributes & LP_PARTITION_ATTR_DISABLED) {
- const auto name = GetPartitionName(partition);
- if (!DeleteBackingImage(name)) {
- ok = false;
- } else {
- LOG(INFO) << "Removed disabled partition image: " << name;
- }
+ ok &= DeleteBackingImage(GetPartitionName(partition));
}
}
return ok;
@@ -744,134 +739,6 @@ bool ImageManager::MapAllImages(const std::function<bool(std::set<std::string>)>
return CreateLogicalPartitions(*metadata.get(), data_partition_name);
}
-std::ostream& operator<<(std::ostream& os, android::fs_mgr::Extent* extent) {
- if (auto e = extent->AsLinearExtent()) {
- return os << "<begin:" << e->physical_sector() << ", end:" << e->end_sector()
- << ", device:" << e->device_index() << ">";
- }
- return os << "<unknown>";
-}
-
-static bool CompareExtent(android::fs_mgr::Extent* a, android::fs_mgr::Extent* b) {
- if (auto linear_a = a->AsLinearExtent()) {
- auto linear_b = b->AsLinearExtent();
- if (!linear_b) {
- return false;
- }
- return linear_a->physical_sector() == linear_b->physical_sector() &&
- linear_a->num_sectors() == linear_b->num_sectors() &&
- linear_a->device_index() == linear_b->device_index();
- }
- return false;
-}
-
-static bool CompareExtents(android::fs_mgr::Partition* oldp, android::fs_mgr::Partition* newp) {
- const auto& old_extents = oldp->extents();
- const auto& new_extents = newp->extents();
-
- auto old_iter = old_extents.begin();
- auto new_iter = new_extents.begin();
- while (true) {
- if (old_iter == old_extents.end()) {
- if (new_iter == new_extents.end()) {
- break;
- }
- LOG(ERROR) << "Unexpected extent added: " << (*new_iter);
- return false;
- }
- if (new_iter == new_extents.end()) {
- LOG(ERROR) << "Unexpected extent removed: " << (*old_iter);
- return false;
- }
-
- if (!CompareExtent(old_iter->get(), new_iter->get())) {
- LOG(ERROR) << "Extents do not match: " << old_iter->get() << ", " << new_iter->get();
- return false;
- }
-
- old_iter++;
- new_iter++;
- }
- return true;
-}
-
-bool ImageManager::ValidateImageMaps() {
- if (!MetadataExists(metadata_dir_)) {
- LOG(INFO) << "ImageManager skipping verification; no images for " << metadata_dir_;
- return true;
- }
-
- auto metadata = OpenMetadata(metadata_dir_);
- if (!metadata) {
- LOG(ERROR) << "ImageManager skipping verification; failed to open " << metadata_dir_;
- return true;
- }
-
- for (const auto& partition : metadata->partitions) {
- auto name = GetPartitionName(partition);
- auto image_path = GetImageHeaderPath(name);
- auto fiemap = SplitFiemap::Open(image_path);
- if (fiemap == nullptr) {
- LOG(ERROR) << "SplitFiemap::Open(\"" << image_path << "\") failed";
- return false;
- }
- if (!fiemap->HasPinnedExtents()) {
- LOG(ERROR) << "Image doesn't have pinned extents: " << image_path;
- return false;
- }
-
- android::fs_mgr::PartitionOpener opener;
- auto builder = android::fs_mgr::MetadataBuilder::New(*metadata.get(), &opener);
- if (!builder) {
- LOG(ERROR) << "Could not create metadata builder: " << image_path;
- return false;
- }
-
- auto new_p = builder->AddPartition("_temp_for_verify", 0);
- if (!new_p) {
- LOG(ERROR) << "Could not add temporary partition: " << image_path;
- return false;
- }
-
- auto partition_size = android::fs_mgr::GetPartitionSize(*metadata.get(), partition);
- if (!FillPartitionExtents(builder.get(), new_p, fiemap.get(), partition_size)) {
- LOG(ERROR) << "Could not fill partition extents: " << image_path;
- return false;
- }
-
- auto old_p = builder->FindPartition(name);
- if (!old_p) {
- LOG(ERROR) << "Could not find metadata for " << image_path;
- return false;
- }
-
- if (!CompareExtents(old_p, new_p)) {
- LOG(ERROR) << "Metadata for " << image_path << " does not match fiemap";
- return false;
- }
- }
-
- return true;
-}
-
-bool ImageManager::IsImageDisabled(const std::string& name) {
- if (!MetadataExists(metadata_dir_)) {
- return true;
- }
-
- auto metadata = OpenMetadata(metadata_dir_);
- if (!metadata) {
- return false;
- }
-
- auto partition = FindPartition(*metadata.get(), name);
- if (!partition) {
- return false;
- }
-
- return !!(partition->attributes & LP_PARTITION_ATTR_DISABLED);
-}
-
std::unique_ptr<MappedDevice> MappedDevice::Open(IImageManager* manager,
const std::chrono::milliseconds& timeout_ms,
const std::string& name) {
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index 74729494b..6d0975150 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -119,7 +119,6 @@ TEST_F(NativeTest, DisableImage) {
ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
ASSERT_TRUE(manager_->BackingImageExists(base_name_));
ASSERT_TRUE(manager_->DisableImage(base_name_));
- ASSERT_TRUE(manager_->IsImageDisabled(base_name_));
ASSERT_TRUE(manager_->RemoveDisabledImages());
ASSERT_TRUE(!manager_->BackingImageExists(base_name_));
}
diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
index 00dd661e9..3c8700025 100644
--- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h
+++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
@@ -131,9 +131,6 @@ class IImageManager {
virtual bool RemoveAllImages() = 0;
virtual bool UnmapImageIfExists(const std::string& name);
-
- // Returns whether DisableImage() was called.
- virtual bool IsImageDisabled(const std::string& name) = 0;
};
class ImageManager final : public IImageManager {
@@ -165,7 +162,6 @@ class ImageManager final : public IImageManager {
bool RemoveDisabledImages() override;
bool GetMappedImageDevice(const std::string& name, std::string* device) override;
bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
- bool IsImageDisabled(const std::string& name) override;
std::vector<std::string> GetAllBackingImages();
@@ -178,9 +174,6 @@ class ImageManager final : public IImageManager {
// Writes |bytes| zeros at the beginning of the passed image
FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes);
- // Validate that all images still have the same block map.
- bool ValidateImageMaps();
-
private:
ImageManager(const std::string& metadata_dir, const std::string& data_dir,
const DeviceInfo& device_info);
diff --git a/fs_mgr/libfiemap/metadata.h b/fs_mgr/libfiemap/metadata.h
index 30b2c61b1..4eb3ad5c5 100644
--- a/fs_mgr/libfiemap/metadata.h
+++ b/fs_mgr/libfiemap/metadata.h
@@ -20,7 +20,6 @@
#include <string>
#include <libfiemap/split_fiemap_writer.h>
-#include <liblp/builder.h>
#include <liblp/liblp.h>
namespace android {
@@ -35,9 +34,5 @@ bool AddAttributes(const std::string& metadata_dir, const std::string& partition
bool RemoveImageMetadata(const std::string& metadata_dir, const std::string& partition_name);
bool RemoveAllMetadata(const std::string& dir);
-bool FillPartitionExtents(android::fs_mgr::MetadataBuilder* builder,
- android::fs_mgr::Partition* partition, android::fiemap::SplitFiemap* file,
- uint64_t partition_size);
-
} // namespace fiemap
} // namespace android
diff --git a/fs_mgr/libfiemap/split_fiemap_writer.cpp b/fs_mgr/libfiemap/split_fiemap_writer.cpp
index 0df61253c..36bb3dfee 100644
--- a/fs_mgr/libfiemap/split_fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/split_fiemap_writer.cpp
@@ -136,7 +136,6 @@ FiemapStatus SplitFiemap::Create(const std::string& file_path, uint64_t file_siz
return FiemapStatus::FromErrno(errno);
}
}
- fsync(fd.get());
// Unset this bit, so we don't unlink on destruction.
out->creating_ = false;
@@ -193,9 +192,6 @@ bool SplitFiemap::RemoveSplitFiles(const std::string& file_path, std::string* me
std::vector<std::string> files;
if (GetSplitFileList(file_path, &files)) {
for (const auto& file : files) {
- if (access(file.c_str(), F_OK) != 0 && (errno == ENOENT || errno == ENAMETOOLONG)) {
- continue;
- }
ok &= android::base::RemoveFileIfExists(file, message);
}
}
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index a0ad20812..6892025a1 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -27,8 +27,6 @@ package {
cc_library_static {
name: "libfs_avb",
defaults: ["fs_mgr_defaults"],
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
host_supported: true,
export_include_dirs: ["include"],
@@ -152,7 +150,6 @@ cc_test {
static_libs: [
"libavb",
"libdm",
- "libext2_uuid",
"libfs_avb",
"libfstab",
],
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 85dbb36d6..31494c189 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -35,6 +35,19 @@ using android::base::unique_fd;
namespace android {
namespace fs_mgr {
+std::string GetAvbPropertyDescriptor(const std::string& key,
+ const std::vector<VBMetaData>& vbmeta_images) {
+ size_t value_size;
+ for (const auto& vbmeta : vbmeta_images) {
+ const char* value = avb_property_lookup(vbmeta.data(), vbmeta.size(), key.data(),
+ key.size(), &value_size);
+ if (value != nullptr) {
+ return {value, value_size};
+ }
+ }
+ return "";
+}
+
// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
// See the following link for more details:
// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
@@ -79,10 +92,6 @@ bool ConstructVerityTable(const FsAvbHashtreeDescriptor& hashtree_desc,
// Always use ignore_zero_blocks.
target.IgnoreZeroBlocks();
- if (hashtree_desc.flags & AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE) {
- target.CheckAtMostOnce();
- }
-
LINFO << "Built verity table: '" << target.GetParameterString() << "'";
return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
@@ -117,6 +126,64 @@ bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const FsAvbHashtreeDescripto
return true;
}
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
+ bool found = false;
+ const uint8_t* desc_partition_name;
+ auto hash_desc = std::make_unique<FsAvbHashDescriptor>();
+
+ for (const auto& vbmeta : vbmeta_images) {
+ size_t num_descriptors;
+ std::unique_ptr<const AvbDescriptor*[], decltype(&avb_free)> descriptors(
+ avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
+
+ if (!descriptors || num_descriptors < 1) {
+ continue;
+ }
+
+ for (size_t n = 0; n < num_descriptors && !found; n++) {
+ AvbDescriptor desc;
+ if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
+ LWARNING << "Descriptor[" << n << "] is invalid";
+ continue;
+ }
+ if (desc.tag == AVB_DESCRIPTOR_TAG_HASH) {
+ desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashDescriptor);
+ if (!avb_hash_descriptor_validate_and_byteswap((AvbHashDescriptor*)descriptors[n],
+ hash_desc.get())) {
+ continue;
+ }
+ if (hash_desc->partition_name_len != partition_name.length()) {
+ continue;
+ }
+ // Notes that desc_partition_name is not NUL-terminated.
+ std::string hash_partition_name((const char*)desc_partition_name,
+ hash_desc->partition_name_len);
+ if (hash_partition_name == partition_name) {
+ found = true;
+ }
+ }
+ }
+
+ if (found) break;
+ }
+
+ if (!found) {
+ LERROR << "Hash descriptor not found: " << partition_name;
+ return nullptr;
+ }
+
+ hash_desc->partition_name = partition_name;
+
+ const uint8_t* desc_salt = desc_partition_name + hash_desc->partition_name_len;
+ hash_desc->salt = BytesToHex(desc_salt, hash_desc->salt_len);
+
+ const uint8_t* desc_digest = desc_salt + hash_desc->salt_len;
+ hash_desc->digest = BytesToHex(desc_digest, hash_desc->digest_len);
+
+ return hash_desc;
+}
+
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
bool found = false;
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index 7941c705e..e8f7c39bf 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -37,6 +37,12 @@ struct ChainInfo {
: partition_name(chain_partition_name), public_key_blob(chain_public_key_blob) {}
};
+std::string GetAvbPropertyDescriptor(const std::string& key,
+ const std::vector<VBMetaData>& vbmeta_images);
+
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
+
// AvbHashtreeDescriptor to dm-verity table setup.
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index a28887627..1da71176c 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -37,7 +37,6 @@
#include "avb_ops.h"
#include "avb_util.h"
-#include "fs_avb/fs_avb_util.h"
#include "sha.h"
#include "util.h"
diff --git a/fs_mgr/libfs_avb/fs_avb_util.cpp b/fs_mgr/libfs_avb/fs_avb_util.cpp
index 532622694..1c14cc0d8 100644
--- a/fs_mgr/libfs_avb/fs_avb_util.cpp
+++ b/fs_mgr/libfs_avb/fs_avb_util.cpp
@@ -74,64 +74,6 @@ std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
return GetHashtreeDescriptor(avb_partition_name, vbmeta_images);
}
-std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
- const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
- bool found = false;
- const uint8_t* desc_partition_name;
- auto hash_desc = std::make_unique<FsAvbHashDescriptor>();
-
- for (const auto& vbmeta : vbmeta_images) {
- size_t num_descriptors;
- std::unique_ptr<const AvbDescriptor*[], decltype(&avb_free)> descriptors(
- avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
-
- if (!descriptors || num_descriptors < 1) {
- continue;
- }
-
- for (size_t n = 0; n < num_descriptors && !found; n++) {
- AvbDescriptor desc;
- if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
- LWARNING << "Descriptor[" << n << "] is invalid";
- continue;
- }
- if (desc.tag == AVB_DESCRIPTOR_TAG_HASH) {
- desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashDescriptor);
- if (!avb_hash_descriptor_validate_and_byteswap((AvbHashDescriptor*)descriptors[n],
- hash_desc.get())) {
- continue;
- }
- if (hash_desc->partition_name_len != partition_name.length()) {
- continue;
- }
- // Notes that desc_partition_name is not NUL-terminated.
- std::string hash_partition_name((const char*)desc_partition_name,
- hash_desc->partition_name_len);
- if (hash_partition_name == partition_name) {
- found = true;
- }
- }
- }
-
- if (found) break;
- }
-
- if (!found) {
- LERROR << "Hash descriptor not found: " << partition_name;
- return nullptr;
- }
-
- hash_desc->partition_name = partition_name;
-
- const uint8_t* desc_salt = desc_partition_name + hash_desc->partition_name_len;
- hash_desc->salt = BytesToHex(desc_salt, hash_desc->salt_len);
-
- const uint8_t* desc_digest = desc_salt + hash_desc->salt_len;
- hash_desc->digest = BytesToHex(desc_digest, hash_desc->digest_len);
-
- return hash_desc;
-}
-
// Given a path, loads and verifies the vbmeta, to extract the Avb Hash descriptor.
std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
VBMetaData&& vbmeta) {
@@ -142,18 +84,5 @@ std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_pa
return GetHashDescriptor(avb_partition_name, vbmeta_images);
}
-std::string GetAvbPropertyDescriptor(const std::string& key,
- const std::vector<VBMetaData>& vbmeta_images) {
- size_t value_size;
- for (const auto& vbmeta : vbmeta_images) {
- const char* value = avb_property_lookup(vbmeta.data(), vbmeta.size(), key.data(),
- key.size(), &value_size);
- if (value != nullptr) {
- return {value, value_size};
- }
- }
- return "";
-}
-
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
index 1b15db73c..3f37bd7db 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
@@ -43,15 +43,9 @@ std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& avb_partition_name, VBMetaData&& vbmeta);
-std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
- const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
-
// Gets the hash descriptor for avb_partition_name from the vbmeta.
std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
VBMetaData&& vbmeta);
-std::string GetAvbPropertyDescriptor(const std::string& key,
- const std::vector<VBMetaData>& vbmeta_images);
-
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/run_tests.sh b/fs_mgr/libfs_avb/run_tests.sh
index 3e945a4b1..5d2ce3df6 100755
--- a/fs_mgr/libfs_avb/run_tests.sh
+++ b/fs_mgr/libfs_avb/run_tests.sh
@@ -1,13 +1,8 @@
#!/bin/sh
#
# Run host tests
-atest --host libfs_avb_test # Tests public libfs_avb APIs.
-
-# Tests libfs_avb private APIs.
-# The tests need more time to finish, so increase the timeout to 5 mins.
-# The default timeout is only 60 seconds.
-atest --host libfs_avb_internal_test -- --test-arg \
- com.android.tradefed.testtype.HostGTest:native-test-timeout:5m
+atest libfs_avb_test # Tests public libfs_avb APIs.
+atest libfs_avb_internal_test # Tests libfs_avb private APIs.
# Run device tests
atest libfs_avb_device_test # Test public libfs_avb APIs on a device.
diff --git a/fs_mgr/libfs_avb/tests/avb_util_test.cpp b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
index 2e3492012..18275665c 100644
--- a/fs_mgr/libfs_avb/tests/avb_util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
@@ -23,7 +23,6 @@
#include <libavb/libavb.h>
#include "avb_util.h"
-#include "fs_avb/fs_avb_util.h"
#include "fs_avb_test_util.h"
// Target classes or functions to test:
@@ -756,7 +755,6 @@ TEST_F(AvbUtilTest, VerifyVBMetaDataError) {
std::string out_public_key_data;
std::unique_ptr<VBMetaData> vbmeta = VerifyVBMetaData(
fd, "system", "" /*expected_public_key_blob */, &out_public_key_data, &verify_result);
- ASSERT_EQ(0, close(fd.release()));
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
@@ -778,9 +776,8 @@ TEST_F(AvbUtilTest, VerifyVBMetaDataError) {
// Should return ErrorVerification.
vbmeta = VerifyVBMetaData(hash_modified_fd, "system", "" /*expected_public_key_blob */,
nullptr /* out_public_key_data */, &verify_result);
- ASSERT_EQ(0, close(hash_modified_fd.release()));
EXPECT_NE(nullptr, vbmeta);
- // EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta)); // b/187303962.
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
// Modifies the auxiliary data block.
@@ -794,9 +791,8 @@ TEST_F(AvbUtilTest, VerifyVBMetaDataError) {
// Should return ErrorVerification.
vbmeta = VerifyVBMetaData(aux_modified_fd, "system", "" /*expected_public_key_blob */,
nullptr /* out_public_key_data */, &verify_result);
- ASSERT_EQ(0, close(aux_modified_fd.release()));
EXPECT_NE(nullptr, vbmeta);
- // EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta)); // b/187303962.
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
// Resets previous modification by setting offset to -1, and checks the verification can pass.
@@ -806,9 +802,8 @@ TEST_F(AvbUtilTest, VerifyVBMetaDataError) {
// Should return ResultOK..
vbmeta = VerifyVBMetaData(ok_fd, "system", "" /*expected_public_key_blob */,
nullptr /* out_public_key_data */, &verify_result);
- ASSERT_EQ(0, close(ok_fd.release()));
EXPECT_NE(nullptr, vbmeta);
- // EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta)); // b/187303962.
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
}
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 4b81c2c07..7e528b164 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -30,8 +30,6 @@ liblp_lib_deps = [
cc_library {
name: "liblp",
host_supported: true,
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
defaults: ["fs_mgr_defaults"],
cppflags: [
@@ -105,9 +103,7 @@ cc_test {
defaults: ["liblp_test_defaults"],
test_suites: ["vts"],
auto_gen_config: true,
- test_options: {
- min_shipping_api_level: 29,
- },
+ test_min_api_level: 29,
require_root: true,
}
diff --git a/fs_mgr/liblp/OWNERS b/fs_mgr/liblp/OWNERS
deleted file mode 100644
index 6a95eb2ea..000000000
--- a/fs_mgr/liblp/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 391836
-dvander@google.com
diff --git a/fs_mgr/liblp/TEST_MAPPING b/fs_mgr/liblp/TEST_MAPPING
index 875ccb0d0..04bcbda54 100644
--- a/fs_mgr/liblp/TEST_MAPPING
+++ b/fs_mgr/liblp/TEST_MAPPING
@@ -3,10 +3,5 @@
{
"name": "liblp_test"
}
- ],
- "hwasan-postsubmit": [
- {
- "name": "liblp_test"
- }
]
}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 1759cf900..72827eb6c 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <android-base/properties.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
@@ -32,7 +31,6 @@ using ::testing::AnyNumber;
using ::testing::ElementsAre;
using ::testing::NiceMock;
using ::testing::Return;
-using android::base::GetProperty;
class Environment : public ::testing::Environment {
public:
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index d1233047c..e67fb33b6 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -20,10 +20,7 @@
#include <sys/syscall.h>
#include <android-base/file.h>
-#include <android-base/properties.h>
#include <android-base/unique_fd.h>
-#include <fs_mgr.h>
-#include <fstab/fstab.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
@@ -41,7 +38,6 @@ using namespace android::fs_mgr::testing;
using ::testing::_;
using ::testing::Return;
using unique_fd = android::base::unique_fd;
-using android::base::GetProperty;
// Our tests assume a 128KiB disk with two 512 byte metadata slots.
static const size_t kDiskSize = 131072;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 6db8f139f..6a764e4fa 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -118,7 +118,6 @@ cc_library_static {
native_coverage : true,
defaults: ["libsnapshot_defaults"],
srcs: [":libsnapshot_sources"],
- ramdisk_available: true,
recovery_available: true,
cflags: [
"-DLIBSNAPSHOT_NO_COW_WRITE",
@@ -182,6 +181,38 @@ cc_library_static {
vendor_ramdisk_available: true,
}
+cc_defaults {
+ name: "libsnapshot_snapuserd_defaults",
+ defaults: [
+ "fs_mgr_defaults",
+ ],
+ cflags: [
+ "-D_FILE_OFFSET_BITS=64",
+ "-Wall",
+ "-Werror",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "snapuserd_client.cpp",
+ ],
+}
+
+cc_library_static {
+ name: "libsnapshot_snapuserd",
+ defaults: [
+ "libsnapshot_snapuserd_defaults",
+ ],
+ recovery_available: true,
+ static_libs: [
+ "libcutils_sockets",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ ramdisk_available: true,
+}
+
cc_library_static {
name: "libsnapshot_test_helpers",
defaults: ["libsnapshot_defaults"],
@@ -236,7 +267,6 @@ cc_defaults {
"libbrotli",
"libc++fs",
"libfs_mgr_binder",
- "libgflags",
"libgsi",
"libgmock",
"liblp",
@@ -252,9 +282,7 @@ cc_defaults {
"vts",
"device-tests"
],
- test_options: {
- min_shipping_api_level: 29,
- },
+ test_min_api_level: 29,
auto_gen_config: true,
require_root: true,
}
@@ -264,35 +292,6 @@ cc_test {
defaults: ["libsnapshot_test_defaults"],
}
-sh_test {
- name: "run_snapshot_tests",
- src: "run_snapshot_tests.sh",
- test_suites: [
- "device-tests",
- ],
- required: [
- "vts_libsnapshot_test",
- ],
-}
-
-cc_test {
- name: "vts_ota_config_test",
- srcs: [
- "vts_ota_config_test.cpp",
- ],
- shared_libs: [
- "libbase",
- ],
- test_suites: [
- "vts",
- ],
- test_options: {
- min_shipping_api_level: 33,
- },
- auto_gen_config: true,
- require_root: true,
-}
-
cc_binary {
name: "snapshotctl",
srcs: [
@@ -311,6 +310,7 @@ cc_binary {
"android.hardware.boot@1.0",
"android.hardware.boot@1.1",
"libbase",
+ "libbinder",
"libext2_uuid",
"libext4_utils",
"libfs_mgr_binder",
@@ -412,6 +412,49 @@ cc_test {
require_root: true,
}
+cc_defaults {
+ name: "snapuserd_defaults",
+ defaults: [
+ "fs_mgr_defaults",
+ ],
+ srcs: [
+ "snapuserd_server.cpp",
+ "snapuserd.cpp",
+ "snapuserd_daemon.cpp",
+ "snapuserd_worker.cpp",
+ "snapuserd_readahead.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror"
+ ],
+
+ static_libs: [
+ "libbase",
+ "libbrotli",
+ "libcutils_sockets",
+ "libdm",
+ "libgflags",
+ "liblog",
+ "libsnapshot_cow",
+ "libz",
+ ],
+}
+
+cc_binary {
+ name: "snapuserd",
+ defaults: ["snapuserd_defaults"],
+ init_rc: [
+ "snapuserd.rc",
+ ],
+ static_executable: true,
+ system_shared_libs: [],
+ ramdisk_available: true,
+ vendor_ramdisk_available: true,
+ recovery_available: true,
+}
+
cc_test {
name: "cow_api_test",
defaults: [
@@ -439,9 +482,7 @@ cc_test {
test_suites: [
"device-tests"
],
- test_options: {
- min_shipping_api_level: 30,
- },
+ test_min_api_level: 30,
auto_gen_config: true,
require_root: false,
host_supported: true,
@@ -515,6 +556,43 @@ cc_binary {
},
}
+cc_test {
+ name: "cow_snapuserd_test",
+ defaults: [
+ "fs_mgr_defaults",
+ ],
+ srcs: [
+ "cow_snapuserd_test.cpp",
+ "snapuserd.cpp",
+ "snapuserd_worker.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ static_libs: [
+ "libbrotli",
+ "libgtest",
+ "libsnapshot_cow",
+ "libsnapshot_snapuserd",
+ "libcutils_sockets",
+ "libz",
+ "libfs_mgr",
+ "libdm",
+ ],
+ header_libs: [
+ "libstorage_literals_headers",
+ "libfiemap_headers",
+ ],
+ test_min_api_level: 30,
+ auto_gen_config: true,
+ require_root: false,
+}
+
cc_binary {
name: "inspect_cow",
host_supported: true,
@@ -538,13 +616,3 @@ cc_binary {
"inspect_cow.cpp",
],
}
-
-python_library_host {
- name: "snapshot_proto_python",
- srcs: [
- "android/snapshot/snapshot.proto",
- ],
- proto: {
- canonical_path_from_root: false,
- },
-}
diff --git a/fs_mgr/libsnapshot/OWNERS b/fs_mgr/libsnapshot/OWNERS
index 9d2b877ac..801c446c2 100644
--- a/fs_mgr/libsnapshot/OWNERS
+++ b/fs_mgr/libsnapshot/OWNERS
@@ -1,5 +1,3 @@
-# Bug component: 30545
balsini@google.com
dvander@google.com
elsk@google.com
-akailash@google.com
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 5daa84dc7..de8768c71 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -194,12 +194,6 @@ message SnapshotUpdateStatus {
// Source build fingerprint.
string source_build_fingerprint = 8;
-
- // user-space snapshots
- bool userspace_snapshots = 9;
-
- // io_uring support
- bool io_uring_enabled = 10;
}
// Next: 10
@@ -229,8 +223,7 @@ message SnapshotMergeReport {
// Time from sys.boot_completed to merge start, in milliseconds.
uint32 boot_complete_to_merge_start_time_ms = 8;
- // Merge failure code, filled if the merge failed at any time (regardless
- // of whether it succeeded at a later time).
+ // Merge failure code, filled if state == MergeFailed.
MergeFailureCode merge_failure_code = 9;
// The source fingerprint at the time the OTA was downloaded.
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index ba4044f7d..b75b154bf 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -140,85 +140,6 @@ TEST_F(CowTest, ReadWrite) {
ASSERT_TRUE(iter->Done());
}
-TEST_F(CowTest, ReadWriteXor) {
- CowOptions options;
- options.cluster_ops = 0;
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_->fd));
-
- std::string data = "This is some data, believe it";
- data.resize(options.block_size, '\0');
-
- ASSERT_TRUE(writer.AddCopy(10, 20));
- ASSERT_TRUE(writer.AddXorBlocks(50, data.data(), data.size(), 24, 10));
- ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
- ASSERT_TRUE(writer.Finalize());
-
- ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
-
- CowReader reader;
- CowHeader header;
- CowFooter footer;
- ASSERT_TRUE(reader.Parse(cow_->fd));
- ASSERT_TRUE(reader.GetHeader(&header));
- ASSERT_TRUE(reader.GetFooter(&footer));
- ASSERT_EQ(header.magic, kCowMagicNumber);
- ASSERT_EQ(header.major_version, kCowVersionMajor);
- ASSERT_EQ(header.minor_version, kCowVersionMinor);
- ASSERT_EQ(header.block_size, options.block_size);
- ASSERT_EQ(footer.op.num_ops, 4);
-
- auto iter = reader.GetOpIter();
- ASSERT_NE(iter, nullptr);
- ASSERT_FALSE(iter->Done());
- auto op = &iter->Get();
-
- ASSERT_EQ(op->type, kCowCopyOp);
- ASSERT_EQ(op->compression, kCowCompressNone);
- ASSERT_EQ(op->data_length, 0);
- ASSERT_EQ(op->new_block, 10);
- ASSERT_EQ(op->source, 20);
-
- StringSink sink;
-
- iter->Next();
- ASSERT_FALSE(iter->Done());
- op = &iter->Get();
-
- ASSERT_EQ(op->type, kCowXorOp);
- ASSERT_EQ(op->compression, kCowCompressNone);
- ASSERT_EQ(op->data_length, 4096);
- ASSERT_EQ(op->new_block, 50);
- ASSERT_EQ(op->source, 98314); // 4096 * 24 + 10
- ASSERT_TRUE(reader.ReadData(*op, &sink));
- ASSERT_EQ(sink.stream(), data);
-
- iter->Next();
- ASSERT_FALSE(iter->Done());
- op = &iter->Get();
-
- // Note: the zero operation gets split into two blocks.
- ASSERT_EQ(op->type, kCowZeroOp);
- ASSERT_EQ(op->compression, kCowCompressNone);
- ASSERT_EQ(op->data_length, 0);
- ASSERT_EQ(op->new_block, 51);
- ASSERT_EQ(op->source, 0);
-
- iter->Next();
- ASSERT_FALSE(iter->Done());
- op = &iter->Get();
-
- ASSERT_EQ(op->type, kCowZeroOp);
- ASSERT_EQ(op->compression, kCowCompressNone);
- ASSERT_EQ(op->data_length, 0);
- ASSERT_EQ(op->new_block, 52);
- ASSERT_EQ(op->source, 0);
-
- iter->Next();
- ASSERT_TRUE(iter->Done());
-}
-
TEST_F(CowTest, CompressGz) {
CowOptions options;
options.cluster_ops = 0;
@@ -1060,239 +981,6 @@ TEST_F(CowTest, DeleteMidCluster) {
ASSERT_EQ(num_clusters, 1);
}
-TEST_F(CowTest, BigSeqOp) {
- CowOptions options;
- CowWriter writer(options);
- const int seq_len = std::numeric_limits<uint16_t>::max() / sizeof(uint32_t) + 1;
- uint32_t sequence[seq_len];
- for (int i = 0; i < seq_len; i++) {
- sequence[i] = i + 1;
- }
-
- ASSERT_TRUE(writer.Initialize(cow_->fd));
-
- ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence));
- ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len));
- ASSERT_TRUE(writer.Finalize());
-
- ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
-
- CowReader reader;
- ASSERT_TRUE(reader.Parse(cow_->fd));
- auto iter = reader.GetRevMergeOpIter();
-
- for (int i = 0; i < seq_len; i++) {
- ASSERT_TRUE(!iter->Done());
- const auto& op = iter->Get();
-
- ASSERT_EQ(op.new_block, seq_len - i);
-
- iter->Next();
- }
- ASSERT_TRUE(iter->Done());
-}
-
-TEST_F(CowTest, MissingSeqOp) {
- CowOptions options;
- CowWriter writer(options);
- const int seq_len = 10;
- uint32_t sequence[seq_len];
- for (int i = 0; i < seq_len; i++) {
- sequence[i] = i + 1;
- }
-
- ASSERT_TRUE(writer.Initialize(cow_->fd));
-
- ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence));
- ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len - 1));
- ASSERT_TRUE(writer.Finalize());
-
- ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
-
- CowReader reader;
- ASSERT_FALSE(reader.Parse(cow_->fd));
-}
-
-TEST_F(CowTest, ResumeSeqOp) {
- CowOptions options;
- auto writer = std::make_unique<CowWriter>(options);
- const int seq_len = 10;
- uint32_t sequence[seq_len];
- for (int i = 0; i < seq_len; i++) {
- sequence[i] = i + 1;
- }
-
- ASSERT_TRUE(writer->Initialize(cow_->fd));
-
- ASSERT_TRUE(writer->AddSequenceData(seq_len, sequence));
- ASSERT_TRUE(writer->AddZeroBlocks(1, seq_len / 2));
- ASSERT_TRUE(writer->AddLabel(1));
- ASSERT_TRUE(writer->AddZeroBlocks(1 + seq_len / 2, 1));
-
- ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
- auto reader = std::make_unique<CowReader>();
- ASSERT_TRUE(reader->Parse(cow_->fd, 1));
- auto itr = reader->GetRevMergeOpIter();
- ASSERT_TRUE(itr->Done());
-
- writer = std::make_unique<CowWriter>(options);
- ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
- ASSERT_TRUE(writer->AddZeroBlocks(1 + seq_len / 2, seq_len / 2));
- ASSERT_TRUE(writer->Finalize());
-
- ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
-
- reader = std::make_unique<CowReader>();
- ASSERT_TRUE(reader->Parse(cow_->fd));
-
- auto iter = reader->GetRevMergeOpIter();
-
- uint64_t expected_block = 10;
- while (!iter->Done() && expected_block > 0) {
- ASSERT_FALSE(iter->Done());
- const auto& op = iter->Get();
-
- ASSERT_EQ(op.new_block, expected_block);
-
- iter->Next();
- expected_block--;
- }
- ASSERT_EQ(expected_block, 0);
- ASSERT_TRUE(iter->Done());
-}
-
-TEST_F(CowTest, RevMergeOpItrTest) {
- CowOptions options;
- options.cluster_ops = 5;
- options.num_merge_ops = 1;
- CowWriter writer(options);
- uint32_t sequence[] = {2, 10, 6, 7, 3, 5};
-
- ASSERT_TRUE(writer.Initialize(cow_->fd));
-
- ASSERT_TRUE(writer.AddSequenceData(6, sequence));
- ASSERT_TRUE(writer.AddCopy(6, 13));
- ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
- ASSERT_TRUE(writer.AddCopy(3, 15));
- ASSERT_TRUE(writer.AddCopy(2, 11));
- ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
- ASSERT_TRUE(writer.AddCopy(5, 16));
- ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
- ASSERT_TRUE(writer.AddCopy(10, 12));
- ASSERT_TRUE(writer.AddCopy(7, 14));
- ASSERT_TRUE(writer.Finalize());
-
- // New block in cow order is 6, 12, 8, 11, 3, 2, 4, 9, 5, 1, 10, 7
- // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
- // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
- // new block 2 is "already merged", so will be left out.
-
- std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
-
- ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
-
- CowReader reader;
- ASSERT_TRUE(reader.Parse(cow_->fd));
- auto iter = reader.GetRevMergeOpIter();
- auto expected_new_block = revMergeOpSequence.begin();
-
- while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
- const auto& op = iter->Get();
-
- ASSERT_EQ(op.new_block, *expected_new_block);
-
- iter->Next();
- expected_new_block++;
- }
- ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
- ASSERT_TRUE(iter->Done());
-}
-
-TEST_F(CowTest, LegacyRevMergeOpItrTest) {
- CowOptions options;
- options.cluster_ops = 5;
- options.num_merge_ops = 1;
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_->fd));
-
- ASSERT_TRUE(writer.AddCopy(2, 11));
- ASSERT_TRUE(writer.AddCopy(10, 12));
- ASSERT_TRUE(writer.AddCopy(6, 13));
- ASSERT_TRUE(writer.AddCopy(7, 14));
- ASSERT_TRUE(writer.AddCopy(3, 15));
- ASSERT_TRUE(writer.AddCopy(5, 16));
- ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
- ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
-
- ASSERT_TRUE(writer.Finalize());
-
- // New block in cow order is 2, 10, 6, 7, 3, 5, 12, 8, 11, 4, 9, 1
- // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
- // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
- // new block 2 is "already merged", so will be left out.
-
- std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
-
- ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
-
- CowReader reader;
- ASSERT_TRUE(reader.Parse(cow_->fd));
- auto iter = reader.GetRevMergeOpIter();
- auto expected_new_block = revMergeOpSequence.begin();
-
- while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
- const auto& op = iter->Get();
-
- ASSERT_EQ(op.new_block, *expected_new_block);
-
- iter->Next();
- expected_new_block++;
- }
- ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
- ASSERT_TRUE(iter->Done());
-}
-
-TEST_F(CowTest, InvalidMergeOrderTest) {
- CowOptions options;
- options.cluster_ops = 5;
- options.num_merge_ops = 1;
- std::string data = "This is some data, believe it";
- data.resize(options.block_size, '\0');
- auto writer = std::make_unique<CowWriter>(options);
- CowReader reader;
-
- ASSERT_TRUE(writer->Initialize(cow_->fd));
-
- ASSERT_TRUE(writer->AddCopy(3, 2));
- ASSERT_TRUE(writer->AddCopy(2, 1));
- ASSERT_TRUE(writer->AddLabel(1));
- ASSERT_TRUE(writer->Finalize());
- ASSERT_TRUE(reader.Parse(cow_->fd));
- ASSERT_TRUE(reader.VerifyMergeOps());
-
- ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
- ASSERT_TRUE(writer->AddCopy(4, 2));
- ASSERT_TRUE(writer->Finalize());
- ASSERT_TRUE(reader.Parse(cow_->fd));
- ASSERT_FALSE(reader.VerifyMergeOps());
-
- writer = std::make_unique<CowWriter>(options);
- ASSERT_TRUE(writer->Initialize(cow_->fd));
- ASSERT_TRUE(writer->AddCopy(2, 1));
- ASSERT_TRUE(writer->AddXorBlocks(3, &data, data.size(), 1, 1));
- ASSERT_TRUE(writer->Finalize());
- ASSERT_TRUE(reader.Parse(cow_->fd));
- ASSERT_FALSE(reader.VerifyMergeOps());
-}
-
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_format.cpp b/fs_mgr/libsnapshot/cow_format.cpp
index 94c41093c..0753c492e 100644
--- a/fs_mgr/libsnapshot/cow_format.cpp
+++ b/fs_mgr/libsnapshot/cow_format.cpp
@@ -37,10 +37,6 @@ std::ostream& operator<<(std::ostream& os, CowOperation const& op) {
os << "kCowLabelOp, ";
else if (op.type == kCowClusterOp)
os << "kCowClusterOp ";
- else if (op.type == kCowXorOp)
- os << "kCowXorOp ";
- else if (op.type == kCowSequenceOp)
- os << "kCowSequenceOp ";
else if (op.type == kCowFooterOp)
os << "kCowFooterOp ";
else
@@ -56,17 +52,14 @@ std::ostream& operator<<(std::ostream& os, CowOperation const& op) {
os << (int)op.compression << "?, ";
os << "data_length:" << op.data_length << ",\t";
os << "new_block:" << op.new_block << ",\t";
- os << "source:" << op.source;
- if (op.type == kCowXorOp)
- os << " (block:" << op.source / BLOCK_SZ << " offset:" << op.source % BLOCK_SZ << ")";
- os << ")";
+ os << "source:" << op.source << ")";
return os;
}
int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_ops) {
if (op.type == kCowClusterOp) {
return op.source;
- } else if ((op.type == kCowReplaceOp || op.type == kCowXorOp) && cluster_ops == 0) {
+ } else if (op.type == kCowReplaceOp && cluster_ops == 0) {
return op.data_length;
} else {
return 0;
@@ -88,17 +81,6 @@ bool IsMetadataOp(const CowOperation& op) {
case kCowLabelOp:
case kCowClusterOp:
case kCowFooterOp:
- case kCowSequenceOp:
- return true;
- default:
- return false;
- }
-}
-
-bool IsOrderedOp(const CowOperation& op) {
- switch (op.type) {
- case kCowCopyOp:
- case kCowXorOp:
return true;
default:
return false;
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 746feeb8d..2349e4a06 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -19,9 +19,6 @@
#include <limits>
#include <optional>
-#include <set>
-#include <unordered_map>
-#include <unordered_set>
#include <vector>
#include <android-base/file.h>
@@ -34,12 +31,7 @@
namespace android {
namespace snapshot {
-CowReader::CowReader(ReaderFlags reader_flag)
- : fd_(-1),
- header_(),
- fd_size_(0),
- merge_op_blocks_(std::make_shared<std::vector<uint32_t>>()),
- reader_flag_(reader_flag) {}
+CowReader::CowReader() : fd_(-1), header_(), fd_size_(0) {}
static void SHA256(const void*, size_t, uint8_t[]) {
#if 0
@@ -50,24 +42,6 @@ static void SHA256(const void*, size_t, uint8_t[]) {
#endif
}
-std::unique_ptr<CowReader> CowReader::CloneCowReader() {
- auto cow = std::make_unique<CowReader>();
- cow->owned_fd_.reset();
- cow->header_ = header_;
- cow->footer_ = footer_;
- cow->fd_size_ = fd_size_;
- cow->last_label_ = last_label_;
- cow->ops_ = ops_;
- cow->merge_op_blocks_ = merge_op_blocks_;
- cow->merge_op_start_ = merge_op_start_;
- cow->block_map_ = block_map_;
- cow->num_total_data_ops_ = num_total_data_ops_;
- cow->num_ordered_ops_to_merge_ = num_ordered_ops_to_merge_;
- cow->has_seq_ops_ = has_seq_ops_;
- cow->data_loc_ = data_loc_;
- return cow;
-}
-
bool CowReader::InitForMerge(android::base::unique_fd&& fd) {
owned_fd_ = std::move(fd);
fd_ = owned_fd_.get();
@@ -153,17 +127,11 @@ bool CowReader::Parse(android::base::borrowed_fd fd, std::optional<uint64_t> lab
return false;
}
- if (!ParseOps(label)) {
- return false;
- }
- // If we're resuming a write, we're not ready to merge
- if (label.has_value()) return true;
- return PrepMergeOps();
+ return ParseOps(label);
}
bool CowReader::ParseOps(std::optional<uint64_t> label) {
uint64_t pos;
- auto data_loc = std::make_shared<std::unordered_map<uint64_t, uint64_t>>();
// Skip the scratch space
if (header_.major_version >= 2 && (header_.buffer_size > 0)) {
@@ -183,13 +151,6 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
// Reading a v1 version of COW which doesn't have buffer_size.
header_.buffer_size = 0;
}
- uint64_t data_pos = 0;
-
- if (header_.cluster_ops) {
- data_pos = pos + header_.cluster_ops * sizeof(CowOperation);
- } else {
- data_pos = pos + sizeof(CowOperation);
- }
auto ops_buffer = std::make_shared<std::vector<CowOperation>>();
uint64_t current_op_num = 0;
@@ -210,11 +171,7 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
while (current_op_num < ops_buffer->size()) {
auto& current_op = ops_buffer->data()[current_op_num];
current_op_num++;
- if (current_op.type == kCowXorOp) {
- data_loc->insert({current_op.new_block, data_pos});
- }
pos += sizeof(CowOperation) + GetNextOpOffset(current_op, header_.cluster_ops);
- data_pos += current_op.data_length + GetNextDataOffset(current_op, header_.cluster_ops);
if (current_op.type == kCowClusterOp) {
break;
@@ -232,7 +189,7 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
memcpy(&footer_->op, &current_op, sizeof(footer->op));
off_t offs = lseek(fd_.get(), pos, SEEK_SET);
if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
- PLOG(ERROR) << "lseek next op failed " << offs;
+ PLOG(ERROR) << "lseek next op failed";
return false;
}
if (!android::base::ReadFully(fd_, &footer->data, sizeof(footer->data))) {
@@ -244,15 +201,13 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
current_op_num--;
done = true;
break;
- } else if (current_op.type == kCowSequenceOp) {
- has_seq_ops_ = true;
}
}
// Position for next cluster read
off_t offs = lseek(fd_.get(), pos, SEEK_SET);
if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
- PLOG(ERROR) << "lseek next op failed " << offs;
+ PLOG(ERROR) << "lseek next op failed";
return false;
}
ops_buffer->resize(current_op_num);
@@ -296,7 +251,7 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
LOG(ERROR) << "ops checksum does not match";
return false;
}
- SHA256(ops_buffer->data(), footer_->op.ops_size, csum);
+ SHA256(ops_buffer.get()->data(), footer_->op.ops_size, csum);
if (memcmp(csum, footer_->data.ops_checksum, sizeof(csum)) != 0) {
LOG(ERROR) << "ops checksum does not match";
return false;
@@ -305,224 +260,142 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
ops_ = ops_buffer;
ops_->shrink_to_fit();
- data_loc_ = data_loc;
return true;
}
-//
-// This sets up the data needed for MergeOpIter. MergeOpIter presents
-// data in the order we intend to merge in.
-//
-// We merge all order sensitive ops up front, and sort the rest to allow for
-// batch merging. Order sensitive ops can either be presented in their proper
-// order in the cow, or be ordered by sequence ops (kCowSequenceOp), in which
-// case we want to merge those ops first, followed by any ops not specified by
-// new_block value by the sequence op, in sorted order.
-// We will re-arrange the vector in such a way that
-// kernel can batch merge. Ex:
-//
-// Existing COW format; All the copy operations
-// are at the beginning.
-// =======================================
-// Copy-op-1 - cow_op->new_block = 1
-// Copy-op-2 - cow_op->new_block = 2
-// Copy-op-3 - cow_op->new_block = 3
-// Replace-op-4 - cow_op->new_block = 6
-// Replace-op-5 - cow_op->new_block = 4
-// Replace-op-6 - cow_op->new_block = 8
-// Replace-op-7 - cow_op->new_block = 9
-// Zero-op-8 - cow_op->new_block = 7
-// Zero-op-9 - cow_op->new_block = 5
-// =======================================
-//
-// First find the operation which isn't a copy-op
-// and then sort all the operations in descending order
-// with the key being cow_op->new_block (source block)
-//
-// The data-structure will look like:
-//
-// =======================================
-// Copy-op-1 - cow_op->new_block = 1
-// Copy-op-2 - cow_op->new_block = 2
-// Copy-op-3 - cow_op->new_block = 3
-// Replace-op-7 - cow_op->new_block = 9
-// Replace-op-6 - cow_op->new_block = 8
-// Zero-op-8 - cow_op->new_block = 7
-// Replace-op-4 - cow_op->new_block = 6
-// Zero-op-9 - cow_op->new_block = 5
-// Replace-op-5 - cow_op->new_block = 4
-// =======================================
-//
-// Daemon will read the above data-structure in reverse-order
-// when reading metadata. Thus, kernel will get the metadata
-// in the following order:
-//
-// ========================================
-// Replace-op-5 - cow_op->new_block = 4
-// Zero-op-9 - cow_op->new_block = 5
-// Replace-op-4 - cow_op->new_block = 6
-// Zero-op-8 - cow_op->new_block = 7
-// Replace-op-6 - cow_op->new_block = 8
-// Replace-op-7 - cow_op->new_block = 9
-// Copy-op-3 - cow_op->new_block = 3
-// Copy-op-2 - cow_op->new_block = 2
-// Copy-op-1 - cow_op->new_block = 1
-// ===========================================
-//
-// When merging begins, kernel will start from the last
-// metadata which was read: In the above format, Copy-op-1
-// will be the first merge operation.
-//
-// Now, batching of the merge operations happens only when
-// 1: origin block numbers in the base device are contiguous
-// (cow_op->new_block) and,
-// 2: cow block numbers which are assigned by daemon in ReadMetadata()
-// are contiguous. These are monotonically increasing numbers.
-//
-// When both (1) and (2) are true, kernel will batch merge the operations.
-// In the above case, we have to ensure that the copy operations
-// are merged first before replace operations are done. Hence,
-// we will not change the order of copy operations. Since,
-// cow_op->new_block numbers are contiguous, we will ensure that the
-// cow block numbers assigned in ReadMetadata() for these respective copy
-// operations are not contiguous forcing kernel to issue merge for each
-// copy operations without batch merging.
-//
-// For all the other operations viz. Replace and Zero op, the cow block
-// numbers assigned by daemon will be contiguous allowing kernel to batch
-// merge.
-//
-// The final format after assiging COW block numbers by the daemon will
-// look something like:
-//
-// =========================================================
-// Replace-op-5 - cow_op->new_block = 4 cow-block-num = 2
-// Zero-op-9 - cow_op->new_block = 5 cow-block-num = 3
-// Replace-op-4 - cow_op->new_block = 6 cow-block-num = 4
-// Zero-op-8 - cow_op->new_block = 7 cow-block-num = 5
-// Replace-op-6 - cow_op->new_block = 8 cow-block-num = 6
-// Replace-op-7 - cow_op->new_block = 9 cow-block-num = 7
-// Copy-op-3 - cow_op->new_block = 3 cow-block-num = 9
-// Copy-op-2 - cow_op->new_block = 2 cow-block-num = 11
-// Copy-op-1 - cow_op->new_block = 1 cow-block-num = 13
-// ==========================================================
-//
-// Merge sequence will look like:
-//
-// Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
-// Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
-// Replace-op-4, Zero-op-9, Replace-op-5 }
-//==============================================================
-bool CowReader::PrepMergeOps() {
- auto merge_op_blocks = std::make_shared<std::vector<uint32_t>>();
- std::vector<int> other_ops;
- auto seq_ops_set = std::unordered_set<uint32_t>();
- auto block_map = std::make_shared<std::unordered_map<uint32_t, int>>();
- size_t num_seqs = 0;
- size_t read;
-
- for (size_t i = 0; i < ops_->size(); i++) {
- auto& current_op = ops_->data()[i];
+void CowReader::InitializeMerge() {
+ uint64_t num_copy_ops = 0;
- if (current_op.type == kCowSequenceOp) {
- size_t seq_len = current_op.data_length / sizeof(uint32_t);
+ // Remove all the metadata operations
+ ops_->erase(std::remove_if(ops_.get()->begin(), ops_.get()->end(),
+ [](CowOperation& op) { return IsMetadataOp(op); }),
+ ops_.get()->end());
- merge_op_blocks->resize(merge_op_blocks->size() + seq_len);
- if (!GetRawBytes(current_op.source, &merge_op_blocks->data()[num_seqs],
- current_op.data_length, &read)) {
- PLOG(ERROR) << "Failed to read sequence op!";
- return false;
- }
- for (size_t j = num_seqs; j < num_seqs + seq_len; j++) {
- seq_ops_set.insert(merge_op_blocks->data()[j]);
- }
- num_seqs += seq_len;
- }
-
- if (IsMetadataOp(current_op)) {
- continue;
- }
-
- if (!has_seq_ops_ && IsOrderedOp(current_op)) {
- merge_op_blocks->emplace_back(current_op.new_block);
- } else if (seq_ops_set.count(current_op.new_block) == 0) {
- other_ops.push_back(current_op.new_block);
- }
- block_map->insert({current_op.new_block, i});
- }
- for (auto block : *merge_op_blocks) {
- if (block_map->count(block) == 0) {
- LOG(ERROR) << "Invalid Sequence Ops. Could not find Cow Op for new block " << block;
- return false;
- }
- }
-
- if (merge_op_blocks->size() > header_.num_merge_ops) {
- num_ordered_ops_to_merge_ = merge_op_blocks->size() - header_.num_merge_ops;
- } else {
- num_ordered_ops_to_merge_ = 0;
- }
-
- // Sort the vector in increasing order if merging in user-space as
- // we can batch merge them when iterating from forward.
+ set_total_data_ops(ops_->size());
+ // We will re-arrange the vector in such a way that
+ // kernel can batch merge. Ex:
//
- // dm-snapshot-merge requires decreasing order as we iterate the blocks
- // in reverse order.
- if (reader_flag_ == ReaderFlags::USERSPACE_MERGE) {
- std::sort(other_ops.begin(), other_ops.end());
- } else {
- std::sort(other_ops.begin(), other_ops.end(), std::greater<int>());
- }
+ // Existing COW format; All the copy operations
+ // are at the beginning.
+ // =======================================
+ // Copy-op-1 - cow_op->new_block = 1
+ // Copy-op-2 - cow_op->new_block = 2
+ // Copy-op-3 - cow_op->new_block = 3
+ // Replace-op-4 - cow_op->new_block = 6
+ // Replace-op-5 - cow_op->new_block = 4
+ // Replace-op-6 - cow_op->new_block = 8
+ // Replace-op-7 - cow_op->new_block = 9
+ // Zero-op-8 - cow_op->new_block = 7
+ // Zero-op-9 - cow_op->new_block = 5
+ // =======================================
+ //
+ // First find the operation which isn't a copy-op
+ // and then sort all the operations in descending order
+ // with the key being cow_op->new_block (source block)
+ //
+ // The data-structure will look like:
+ //
+ // =======================================
+ // Copy-op-1 - cow_op->new_block = 1
+ // Copy-op-2 - cow_op->new_block = 2
+ // Copy-op-3 - cow_op->new_block = 3
+ // Replace-op-7 - cow_op->new_block = 9
+ // Replace-op-6 - cow_op->new_block = 8
+ // Zero-op-8 - cow_op->new_block = 7
+ // Replace-op-4 - cow_op->new_block = 6
+ // Zero-op-9 - cow_op->new_block = 5
+ // Replace-op-5 - cow_op->new_block = 4
+ // =======================================
+ //
+ // Daemon will read the above data-structure in reverse-order
+ // when reading metadata. Thus, kernel will get the metadata
+ // in the following order:
+ //
+ // ========================================
+ // Replace-op-5 - cow_op->new_block = 4
+ // Zero-op-9 - cow_op->new_block = 5
+ // Replace-op-4 - cow_op->new_block = 6
+ // Zero-op-8 - cow_op->new_block = 7
+ // Replace-op-6 - cow_op->new_block = 8
+ // Replace-op-7 - cow_op->new_block = 9
+ // Copy-op-3 - cow_op->new_block = 3
+ // Copy-op-2 - cow_op->new_block = 2
+ // Copy-op-1 - cow_op->new_block = 1
+ // ===========================================
+ //
+ // When merging begins, kernel will start from the last
+ // metadata which was read: In the above format, Copy-op-1
+ // will be the first merge operation.
+ //
+ // Now, batching of the merge operations happens only when
+ // 1: origin block numbers in the base device are contiguous
+ // (cow_op->new_block) and,
+ // 2: cow block numbers which are assigned by daemon in ReadMetadata()
+ // are contiguous. These are monotonically increasing numbers.
+ //
+ // When both (1) and (2) are true, kernel will batch merge the operations.
+ // In the above case, we have to ensure that the copy operations
+ // are merged first before replace operations are done. Hence,
+ // we will not change the order of copy operations. Since,
+ // cow_op->new_block numbers are contiguous, we will ensure that the
+ // cow block numbers assigned in ReadMetadata() for these respective copy
+ // operations are not contiguous forcing kernel to issue merge for each
+ // copy operations without batch merging.
+ //
+ // For all the other operations viz. Replace and Zero op, the cow block
+ // numbers assigned by daemon will be contiguous allowing kernel to batch
+ // merge.
+ //
+ // The final format after assiging COW block numbers by the daemon will
+ // look something like:
+ //
+ // =========================================================
+ // Replace-op-5 - cow_op->new_block = 4 cow-block-num = 2
+ // Zero-op-9 - cow_op->new_block = 5 cow-block-num = 3
+ // Replace-op-4 - cow_op->new_block = 6 cow-block-num = 4
+ // Zero-op-8 - cow_op->new_block = 7 cow-block-num = 5
+ // Replace-op-6 - cow_op->new_block = 8 cow-block-num = 6
+ // Replace-op-7 - cow_op->new_block = 9 cow-block-num = 7
+ // Copy-op-3 - cow_op->new_block = 3 cow-block-num = 9
+ // Copy-op-2 - cow_op->new_block = 2 cow-block-num = 11
+ // Copy-op-1 - cow_op->new_block = 1 cow-block-num = 13
+ // ==========================================================
+ //
+ // Merge sequence will look like:
+ //
+ // Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
+ // Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
+ // Replace-op-4, Zero-op-9, Replace-op-5 }
+ //==============================================================
- merge_op_blocks->insert(merge_op_blocks->end(), other_ops.begin(), other_ops.end());
+ num_copy_ops = FindNumCopyops();
+
+ std::sort(ops_.get()->begin() + num_copy_ops, ops_.get()->end(),
+ [](CowOperation& op1, CowOperation& op2) -> bool {
+ return op1.new_block > op2.new_block;
+ });
- num_total_data_ops_ = merge_op_blocks->size();
if (header_.num_merge_ops > 0) {
- merge_op_start_ = header_.num_merge_ops;
+ ops_->erase(ops_.get()->begin(), ops_.get()->begin() + header_.num_merge_ops);
}
- block_map_ = block_map;
- merge_op_blocks_ = merge_op_blocks;
- return true;
+ num_copy_ops = FindNumCopyops();
+ set_copy_ops(num_copy_ops);
}
-bool CowReader::VerifyMergeOps() {
- auto itr = GetMergeOpIter(true);
- std::unordered_map<uint64_t, CowOperation> overwritten_blocks;
- while (!itr->Done()) {
- CowOperation op = itr->Get();
- uint64_t block;
- bool offset;
- if (op.type == kCowCopyOp) {
- block = op.source;
- offset = false;
- } else if (op.type == kCowXorOp) {
- block = op.source / BLOCK_SZ;
- offset = (op.source % BLOCK_SZ) != 0;
- } else {
- itr->Next();
- continue;
- }
+uint64_t CowReader::FindNumCopyops() {
+ uint64_t num_copy_ops = 0;
- CowOperation* overwrite = nullptr;
- if (overwritten_blocks.count(block)) {
- overwrite = &overwritten_blocks[block];
- LOG(ERROR) << "Invalid Sequence! Block needed for op:\n"
- << op << "\noverwritten by previously merged op:\n"
- << *overwrite;
- }
- if (offset && overwritten_blocks.count(block + 1)) {
- overwrite = &overwritten_blocks[block + 1];
- LOG(ERROR) << "Invalid Sequence! Block needed for op:\n"
- << op << "\noverwritten by previously merged op:\n"
- << *overwrite;
+ for (uint64_t i = 0; i < ops_->size(); i++) {
+ auto& current_op = ops_->data()[i];
+ if (current_op.type != kCowCopyOp) {
+ break;
}
- if (overwrite != nullptr) return false;
- overwritten_blocks[op.new_block] = op;
- itr->Next();
+ num_copy_ops += 1;
}
- return true;
+
+ return num_copy_ops;
}
bool CowReader::GetHeader(CowHeader* header) {
@@ -550,9 +423,6 @@ class CowOpIter final : public ICowOpIter {
const CowOperation& Get() override;
void Next() override;
- void Prev() override;
- bool RDone() override;
-
private:
std::shared_ptr<std::vector<CowOperation>> ops_;
std::vector<CowOperation>::iterator op_iter_;
@@ -560,20 +430,11 @@ class CowOpIter final : public ICowOpIter {
CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops) {
ops_ = ops;
- op_iter_ = ops_->begin();
-}
-
-bool CowOpIter::RDone() {
- return op_iter_ == ops_->begin();
-}
-
-void CowOpIter::Prev() {
- CHECK(!RDone());
- op_iter_--;
+ op_iter_ = ops_.get()->begin();
}
bool CowOpIter::Done() {
- return op_iter_ == ops_->end();
+ return op_iter_ == ops_.get()->end();
}
void CowOpIter::Next() {
@@ -586,131 +447,44 @@ const CowOperation& CowOpIter::Get() {
return (*op_iter_);
}
-class CowRevMergeOpIter final : public ICowOpIter {
- public:
- explicit CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
- uint64_t start);
-
- bool Done() override;
- const CowOperation& Get() override;
- void Next() override;
-
- void Prev() override;
- bool RDone() override;
-
- private:
- std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
- std::vector<uint32_t>::reverse_iterator block_riter_;
- uint64_t start_;
-};
-
-class CowMergeOpIter final : public ICowOpIter {
+class CowOpReverseIter final : public ICowOpReverseIter {
public:
- explicit CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map, uint64_t start);
+ explicit CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops);
bool Done() override;
const CowOperation& Get() override;
void Next() override;
- void Prev() override;
- bool RDone() override;
-
private:
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
- std::vector<uint32_t>::iterator block_iter_;
- uint64_t start_;
+ std::vector<CowOperation>::reverse_iterator op_riter_;
};
-CowMergeOpIter::CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
- uint64_t start) {
- ops_ = ops;
- merge_op_blocks_ = merge_op_blocks;
- map_ = map;
- start_ = start;
-
- block_iter_ = merge_op_blocks->begin() + start;
-}
-
-bool CowMergeOpIter::RDone() {
- return block_iter_ == merge_op_blocks_->begin();
-}
-
-void CowMergeOpIter::Prev() {
- CHECK(!RDone());
- block_iter_--;
-}
-
-bool CowMergeOpIter::Done() {
- return block_iter_ == merge_op_blocks_->end();
-}
-
-void CowMergeOpIter::Next() {
- CHECK(!Done());
- block_iter_++;
-}
-
-const CowOperation& CowMergeOpIter::Get() {
- CHECK(!Done());
- return ops_->data()[map_->at(*block_iter_)];
-}
-
-CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
- uint64_t start) {
+CowOpReverseIter::CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops) {
ops_ = ops;
- merge_op_blocks_ = merge_op_blocks;
- map_ = map;
- start_ = start;
-
- block_riter_ = merge_op_blocks->rbegin();
-}
-
-bool CowRevMergeOpIter::RDone() {
- return block_riter_ == merge_op_blocks_->rbegin();
+ op_riter_ = ops_.get()->rbegin();
}
-void CowRevMergeOpIter::Prev() {
- CHECK(!RDone());
- block_riter_--;
+bool CowOpReverseIter::Done() {
+ return op_riter_ == ops_.get()->rend();
}
-bool CowRevMergeOpIter::Done() {
- return block_riter_ == merge_op_blocks_->rend() - start_;
-}
-
-void CowRevMergeOpIter::Next() {
+void CowOpReverseIter::Next() {
CHECK(!Done());
- block_riter_++;
+ op_riter_++;
}
-const CowOperation& CowRevMergeOpIter::Get() {
+const CowOperation& CowOpReverseIter::Get() {
CHECK(!Done());
- return ops_->data()[map_->at(*block_riter_)];
+ return (*op_riter_);
}
std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
return std::make_unique<CowOpIter>(ops_);
}
-std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter(bool ignore_progress) {
- return std::make_unique<CowRevMergeOpIter>(ops_, merge_op_blocks_, block_map_,
- ignore_progress ? 0 : merge_op_start_);
-}
-
-std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) {
- return std::make_unique<CowMergeOpIter>(ops_, merge_op_blocks_, block_map_,
- ignore_progress ? 0 : merge_op_start_);
+std::unique_ptr<ICowOpReverseIter> CowReader::GetRevOpIter() {
+ return std::make_unique<CowOpReverseIter>(ops_);
}
bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
@@ -780,13 +554,7 @@ bool CowReader::ReadData(const CowOperation& op, IByteSink* sink) {
return false;
}
- uint64_t offset;
- if (op.type == kCowXorOp) {
- offset = data_loc_->at(op.new_block);
- } else {
- offset = op.source;
- }
- CowDataStream stream(this, offset, op.data_length);
+ CowDataStream stream(this, op.source, op.data_length);
decompressor->set_stream(&stream);
decompressor->set_sink(sink);
return decompressor->Decompress(header_.block_size);
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 484a9c486..d09c6e9c9 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -33,8 +33,7 @@
#include <libdm/dm.h>
#include <libdm/loop_control.h>
#include <libsnapshot/cow_writer.h>
-#include <snapuserd/snapuserd_buffer.h>
-#include <snapuserd/snapuserd_client.h>
+#include <libsnapshot/snapuserd_client.h>
#include <storage_literals/storage_literals.h>
#include "snapuserd.h"
@@ -109,7 +108,6 @@ class CowSnapuserdTest final {
void MergeInterruptFixed(int duration);
void MergeInterruptRandomly(int max_duration);
void ReadDmUserBlockWithoutDaemon();
- void ReadLastBlock();
std::string snapshot_dev() const { return snapshot_dev_->path(); }
@@ -258,77 +256,10 @@ void CowSnapuserdTest::StartSnapuserdDaemon() {
}
}
-void CowSnapuserdTest::ReadLastBlock() {
- unique_fd rnd_fd;
- total_base_size_ = BLOCK_SZ * 2;
-
- base_fd_ = CreateTempFile("base_device", total_base_size_);
- ASSERT_GE(base_fd_, 0);
-
- rnd_fd.reset(open("/dev/random", O_RDONLY));
- ASSERT_TRUE(rnd_fd > 0);
-
- std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(BLOCK_SZ);
-
- for (size_t j = 0; j < ((total_base_size_) / BLOCK_SZ); j++) {
- ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), BLOCK_SZ, 0), true);
- ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), BLOCK_SZ), true);
- }
-
- ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
-
- base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
- ASSERT_TRUE(base_loop_->valid());
-
- std::string path = android::base::GetExecutableDirectory();
- cow_system_ = std::make_unique<TemporaryFile>(path);
-
- std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(total_base_size_);
- loff_t offset = 0;
-
- // Fill random data
- for (size_t j = 0; j < (total_base_size_ / BLOCK_SZ); j++) {
- ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, BLOCK_SZ, 0),
- true);
-
- offset += BLOCK_SZ;
- }
-
- CowOptions options;
- options.compression = "gz";
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_system_->fd));
-
- ASSERT_TRUE(writer.AddRawBlocks(0, random_buffer_1_.get(), BLOCK_SZ));
- ASSERT_TRUE(writer.AddRawBlocks(1, (char*)random_buffer_1_.get() + BLOCK_SZ, BLOCK_SZ));
-
- ASSERT_TRUE(writer.Finalize());
-
- SetDeviceControlName();
-
- StartSnapuserdDaemon();
- InitCowDevice();
-
- CreateDmUserDevice();
- InitDaemon();
-
- CreateSnapshotDevice();
-
- unique_fd snapshot_fd(open(snapshot_dev_->path().c_str(), O_RDONLY));
- ASSERT_TRUE(snapshot_fd > 0);
-
- std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(BLOCK_SZ);
-
- offset = 7680;
- ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), 512, offset), true);
- ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)random_buffer_1_.get() + offset, 512), 0);
-}
-
void CowSnapuserdTest::CreateBaseDevice() {
unique_fd rnd_fd;
- total_base_size_ = (size_ * 5);
+ total_base_size_ = (size_ * 4);
base_fd_ = CreateTempFile("base_device", total_base_size_);
ASSERT_GE(base_fd_, 0);
@@ -373,11 +304,6 @@ void CowSnapuserdTest::ReadSnapshotDeviceAndValidate() {
offset += size_;
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 3), size_), 0);
-
- // XOR
- offset += size_;
- ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
- ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0);
}
void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_2() {
@@ -502,10 +428,9 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() {
ASSERT_TRUE(writer.Initialize(cow_system_->fd));
size_t num_blocks = size_ / options.block_size;
- size_t blk_end_copy = num_blocks * 3;
+ size_t blk_end_copy = num_blocks * 2;
size_t source_blk = num_blocks - 1;
size_t blk_src_copy = blk_end_copy - 1;
- uint16_t xor_offset = 5;
size_t x = num_blocks;
while (1) {
@@ -518,11 +443,6 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() {
blk_src_copy -= 1;
}
- for (size_t i = num_blocks; i > 0; i--) {
- ASSERT_TRUE(writer.AddXorBlocks(num_blocks + i - 1,
- &random_buffer_1_.get()[options.block_size * (i - 1)],
- options.block_size, 2 * num_blocks + i - 1, xor_offset));
- }
// Flush operations
ASSERT_TRUE(writer.Finalize());
// Construct the buffer required for validation
@@ -531,11 +451,7 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() {
ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
true);
// Merged Buffer
- memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
- memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
- for (int i = 0; i < size_; i++) {
- orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
- }
+ memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + size_, size_);
}
void CowSnapuserdTest::CreateCowDeviceOrderedOps() {
@@ -557,7 +473,6 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOps() {
offset += 1_MiB;
}
- memset(random_buffer_1_.get(), 0, size_);
CowOptions options;
options.compression = "gz";
@@ -568,8 +483,7 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOps() {
size_t num_blocks = size_ / options.block_size;
size_t x = num_blocks;
size_t source_blk = 0;
- size_t blk_src_copy = 2 * num_blocks;
- uint16_t xor_offset = 5;
+ size_t blk_src_copy = num_blocks;
while (1) {
ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
@@ -582,8 +496,6 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOps() {
blk_src_copy += 1;
}
- ASSERT_TRUE(writer.AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks,
- xor_offset));
// Flush operations
ASSERT_TRUE(writer.Finalize());
// Construct the buffer required for validation
@@ -592,11 +504,7 @@ void CowSnapuserdTest::CreateCowDeviceOrderedOps() {
ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
true);
// Merged Buffer
- memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
- memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
- for (int i = 0; i < size_; i++) {
- orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
- }
+ memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + size_, size_);
}
void CowSnapuserdTest::CreateCowDevice() {
@@ -630,17 +538,6 @@ void CowSnapuserdTest::CreateCowDevice() {
size_t source_blk = num_blocks - 1;
size_t blk_src_copy = blk_end_copy - 1;
- uint32_t sequence[num_blocks * 2];
- // Sequence for Copy ops
- for (int i = 0; i < num_blocks; i++) {
- sequence[i] = num_blocks - 1 - i;
- }
- // Sequence for Xor ops
- for (int i = 0; i < num_blocks; i++) {
- sequence[num_blocks + i] = 5 * num_blocks - 1 - i;
- }
- ASSERT_TRUE(writer.AddSequenceData(2 * num_blocks, sequence));
-
size_t x = num_blocks;
while (1) {
ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
@@ -666,11 +563,6 @@ void CowSnapuserdTest::CreateCowDevice() {
ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_));
- size_t blk_xor_start = blk_random2_replace_start + num_blocks;
- size_t xor_offset = BLOCK_SZ / 2;
- ASSERT_TRUE(writer.AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks,
- xor_offset));
-
// Flush operations
ASSERT_TRUE(writer.Finalize());
// Construct the buffer required for validation
@@ -680,13 +572,6 @@ void CowSnapuserdTest::CreateCowDevice() {
memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_);
memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_);
memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_);
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, &orig_buffer_.get()[size_ * 4], size_,
- size_ + xor_offset),
- true);
- for (int i = 0; i < size_; i++) {
- orig_buffer_.get()[(size_ * 4) + i] =
- (uint8_t)(orig_buffer_.get()[(size_ * 4) + i] ^ random_buffer_1_.get()[i]);
- }
}
void CowSnapuserdTest::InitCowDevice() {
@@ -932,6 +817,7 @@ void CowSnapuserdMetadataTest::ValidatePartialFilledArea() {
ASSERT_EQ(area_sz, 2);
+ size_t new_chunk = 263;
// Verify the partially filled area
void* buffer = snapuserd_->GetExceptionBuffer(1);
loff_t offset = 0;
@@ -940,6 +826,7 @@ void CowSnapuserdMetadataTest::ValidatePartialFilledArea() {
de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
ASSERT_EQ(de->old_chunk, i);
offset += sizeof(struct disk_exception);
+ new_chunk += 1;
}
de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
@@ -1152,35 +1039,6 @@ void CowSnapuserdMetadataTest::ValidateMetadata() {
}
}
-TEST(Snapuserd_Test, xor_buffer) {
- std::string data = "Test String";
- std::string jumbled = {0x0C, 0x2A, 0x21, 0x54, 0x73, 0x27, 0x06, 0x1B, 0x07, 0x09, 0x46};
- std::string result = "XOR String!";
-
- BufferSink sink;
- XorSink xor_sink;
- sink.Initialize(sizeof(struct dm_user_header) + 10);
- int buffsize = 5;
- xor_sink.Initialize(&sink, buffsize);
-
- void* buff = sink.GetPayloadBuffer(data.length());
- memcpy(buff, data.data(), data.length());
-
- size_t actual;
- size_t count = 0;
- while (count < data.length()) {
- void* xor_buff = xor_sink.GetBuffer(10, &actual);
- ASSERT_EQ(actual, buffsize);
- ASSERT_NE(xor_buff, nullptr);
- memcpy(xor_buff, jumbled.data() + count, buffsize);
- xor_sink.ReturnData(xor_buff, actual);
- count += actual;
- }
-
- std::string answer = reinterpret_cast<char*>(sink.GetPayloadBufPtr());
- ASSERT_EQ(answer, result);
-}
-
TEST(Snapuserd_Test, Snapshot_Metadata) {
CowSnapuserdMetadataTest harness;
harness.Setup();
@@ -1210,12 +1068,6 @@ TEST(Snapuserd_Test, Snapshot_IO_TEST) {
harness.Shutdown();
}
-TEST(Snapuserd_Test, Snapshot_END_IO_TEST) {
- CowSnapuserdTest harness;
- harness.ReadLastBlock();
- harness.Shutdown();
-}
-
TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_1) {
CowSnapuserdTest harness;
ASSERT_TRUE(harness.SetupCopyOverlap_1());
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 5ce1d3bb2..51c00a96a 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -58,26 +58,6 @@ bool ICowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t
return EmitRawBlocks(new_block_start, data, size);
}
-bool ICowWriter::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size,
- uint32_t old_block, uint16_t offset) {
- if (size % options_.block_size != 0) {
- LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of "
- << options_.block_size;
- return false;
- }
-
- uint64_t num_blocks = size / options_.block_size;
- uint64_t last_block = new_block_start + num_blocks - 1;
- if (!ValidateNewBlock(last_block)) {
- return false;
- }
- if (offset >= options_.block_size) {
- LOG(ERROR) << "AddXorBlocks: offset " << offset << " is not less than "
- << options_.block_size;
- }
- return EmitXorBlocks(new_block_start, data, size, old_block, offset);
-}
-
bool ICowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
uint64_t last_block = new_block_start + num_blocks - 1;
if (!ValidateNewBlock(last_block)) {
@@ -90,10 +70,6 @@ bool ICowWriter::AddLabel(uint64_t label) {
return EmitLabel(label);
}
-bool ICowWriter::AddSequenceData(size_t num_ops, const uint32_t* data) {
- return EmitSequenceData(num_ops, data);
-}
-
bool ICowWriter::ValidateNewBlock(uint64_t new_block) {
if (options_.max_blocks && new_block >= options_.max_blocks.value()) {
LOG(ERROR) << "New block " << new_block << " exceeds maximum block count "
@@ -116,7 +92,7 @@ void CowWriter::SetupHeaders() {
header_.footer_size = sizeof(CowFooter);
header_.op_size = sizeof(CowOperation);
header_.block_size = options_.block_size;
- header_.num_merge_ops = options_.num_merge_ops;
+ header_.num_merge_ops = 0;
header_.cluster_ops = options_.cluster_ops;
header_.buffer_size = 0;
footer_ = {};
@@ -292,27 +268,13 @@ bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
}
bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
- return EmitBlocks(new_block_start, data, size, 0, 0, kCowReplaceOp);
-}
-
-bool CowWriter::EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
- uint32_t old_block, uint16_t offset) {
- return EmitBlocks(new_block_start, data, size, old_block, offset, kCowXorOp);
-}
-
-bool CowWriter::EmitBlocks(uint64_t new_block_start, const void* data, size_t size,
- uint64_t old_block, uint16_t offset, uint8_t type) {
const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
CHECK(!merge_in_progress_);
for (size_t i = 0; i < size / header_.block_size; i++) {
CowOperation op = {};
+ op.type = kCowReplaceOp;
op.new_block = new_block_start + i;
- op.type = type;
- if (type == kCowXorOp) {
- op.source = (old_block + i) * header_.block_size + offset;
- } else {
- op.source = next_data_pos_;
- }
+ op.source = next_data_pos_;
if (compression_) {
auto data = Compress(iter, header_.block_size);
@@ -364,26 +326,6 @@ bool CowWriter::EmitLabel(uint64_t label) {
return WriteOperation(op) && Sync();
}
-bool CowWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
- CHECK(!merge_in_progress_);
- size_t to_add = 0;
- size_t max_ops = std::numeric_limits<uint16_t>::max() / sizeof(uint32_t);
- while (num_ops > 0) {
- CowOperation op = {};
- op.type = kCowSequenceOp;
- op.source = next_data_pos_;
- to_add = std::min(num_ops, max_ops);
- op.data_length = static_cast<uint16_t>(to_add * sizeof(uint32_t));
- if (!WriteOperation(op, data, op.data_length)) {
- PLOG(ERROR) << "AddSequenceData: write failed";
- return false;
- }
- num_ops -= to_add;
- data += to_add;
- }
- return true;
-}
-
bool CowWriter::EmitCluster() {
CowOperation op = {};
op.type = kCowClusterOp;
diff --git a/fs_mgr/libsnapshot/device_info.cpp b/fs_mgr/libsnapshot/device_info.cpp
index a6d96ed82..14ce0ee0e 100644
--- a/fs_mgr/libsnapshot/device_info.cpp
+++ b/fs_mgr/libsnapshot/device_info.cpp
@@ -139,9 +139,5 @@ std::unique_ptr<android::fiemap::IImageManager> ISnapshotManager::IDeviceInfo::O
}
}
-android::dm::IDeviceMapper& DeviceInfo::GetDeviceMapper() {
- return android::dm::DeviceMapper::Instance();
-}
-
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/device_info.h b/fs_mgr/libsnapshot/device_info.h
index 8aefb8507..7999c99c2 100644
--- a/fs_mgr/libsnapshot/device_info.h
+++ b/fs_mgr/libsnapshot/device_info.h
@@ -40,7 +40,6 @@ class DeviceInfo final : public SnapshotManager::IDeviceInfo {
bool IsRecovery() const override;
std::unique_ptr<IImageManager> OpenImageManager() const override;
bool IsFirstStageInit() const override;
- android::dm::IDeviceMapper& GetDeviceMapper() override;
void set_first_stage_init(bool value) { first_stage_init_ = value; }
diff --git a/fs_mgr/libsnapshot/dm_snapshot_internals.h b/fs_mgr/libsnapshot/dm_snapshot_internals.h
index 4a3625197..ed77c1526 100644
--- a/fs_mgr/libsnapshot/dm_snapshot_internals.h
+++ b/fs_mgr/libsnapshot/dm_snapshot_internals.h
@@ -17,9 +17,8 @@
#include <android-base/logging.h>
#include <stdint.h>
-#include <limits>
#include <optional>
-#include <unordered_set>
+#include <vector>
namespace android {
namespace snapshot {
@@ -38,16 +37,21 @@ class DmSnapCowSizeCalculator {
return;
}
- if (chunk_id > std::numeric_limits<uint32_t>::max()) {
- LOG(ERROR) << "Chunk exceeds maximum size: " << chunk_id;
- valid_ = false;
- return;
- }
- if (modified_chunks_.count(chunk_id) > 0) {
- return;
+ if (modified_chunks_.size() <= chunk_id) {
+ if (modified_chunks_.max_size() <= chunk_id) {
+ LOG(ERROR) << "Invalid COW size, chunk_id is too large.";
+ valid_ = false;
+ return;
+ }
+ modified_chunks_.resize(chunk_id + 1, false);
+ if (modified_chunks_.size() <= chunk_id) {
+ LOG(ERROR) << "Invalid COW size, chunk_id is too large.";
+ valid_ = false;
+ return;
+ }
}
- modified_chunks_.emplace(chunk_id);
+ modified_chunks_[chunk_id] = true;
}
std::optional<uint64_t> cow_size_bytes() const {
@@ -87,16 +91,23 @@ class DmSnapCowSizeCalculator {
return std::nullopt;
}
+ uint64_t modified_chunks_count = 0;
uint64_t cow_chunks = 0;
+ for (const auto& c : modified_chunks_) {
+ if (c) {
+ ++modified_chunks_count;
+ }
+ }
+
/* disk header + padding = 1 chunk */
cow_chunks += 1;
/* snapshot modified chunks */
- cow_chunks += modified_chunks_.size();
+ cow_chunks += modified_chunks_count;
/* snapshot chunks index metadata */
- cow_chunks += 1 + modified_chunks_.size() / exceptions_per_chunk;
+ cow_chunks += 1 + modified_chunks_count / exceptions_per_chunk;
return cow_chunks;
}
@@ -139,8 +150,30 @@ class DmSnapCowSizeCalculator {
/*
* |modified_chunks_| is a container that keeps trace of the modified
* chunks.
+ * Multiple options were considered when choosing the most appropriate data
+ * structure for this container. Here follows a summary of why vector<bool>
+ * has been chosen, taking as a reference a snapshot partition of 4 GiB and
+ * chunk size of 4 KiB.
+ * - std::set<uint64_t> is very space-efficient for a small number of
+ * operations, but if the whole snapshot is changed, it would need to
+ * store
+ * 4 GiB / 4 KiB * (64 bit / 8) = 8 MiB
+ * just for the data, plus the additional data overhead for the red-black
+ * tree used for data sorting (if each rb-tree element stores 3 address
+ * and the word-aligne color, the total size grows to 32 MiB).
+ * - std::bitset<N> is not a good fit because requires a priori knowledge,
+ * at compile time, of the bitset size.
+ * - std::vector<bool> is a special case of vector, which uses a data
+ * compression that allows reducing the space utilization of each element
+ * to 1 bit. In detail, this data structure is composed of a resizable
+ * array of words, each of them representing a bitmap. On a 64 bit
+ * device, modifying the whole 4 GiB snapshot grows this container up to
+ * 4 * GiB / 4 KiB / 64 = 64 KiB
+ * that, even if is the same space requirement to change a single byte at
+ * the highest address of the snapshot, is a very affordable space
+ * requirement.
*/
- std::unordered_set<uint32_t> modified_chunks_;
+ std::vector<bool> modified_chunks_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 9f4ddbb61..000e5e14b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -26,8 +26,8 @@ static constexpr uint32_t kCowVersionMinor = 0;
static constexpr uint32_t kCowVersionManifest = 2;
-static constexpr size_t BLOCK_SZ = 4096;
-static constexpr size_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SZ) - 1);
+static constexpr uint32_t BLOCK_SZ = 4096;
+static constexpr uint32_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SZ) - 1);
// This header appears as the first sequence of bytes in the COW. All fields
// in the layout are little-endian encoded. The on-disk layout is:
@@ -138,8 +138,6 @@ struct CowOperation {
// For Label operations, this is the value of the applied label.
//
// For Cluster operations, this is the length of the following data region
- //
- // For Xor operations, this is the byte location in the source image.
uint64_t source;
} __attribute__((packed));
@@ -150,8 +148,6 @@ static constexpr uint8_t kCowReplaceOp = 2;
static constexpr uint8_t kCowZeroOp = 3;
static constexpr uint8_t kCowLabelOp = 4;
static constexpr uint8_t kCowClusterOp = 5;
-static constexpr uint8_t kCowXorOp = 6;
-static constexpr uint8_t kCowSequenceOp = 7;
static constexpr uint8_t kCowFooterOp = -1;
static constexpr uint8_t kCowCompressNone = 0;
@@ -188,10 +184,7 @@ std::ostream& operator<<(std::ostream& os, CowOperation const& arg);
int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_size);
int64_t GetNextDataOffset(const CowOperation& op, uint32_t cluster_size);
-// Ops that are internal to the Cow Format and not OTA data
bool IsMetadataOp(const CowOperation& op);
-// Ops that have dependencies on old blocks, and must take care in their merge order
-bool IsOrderedOp(const CowOperation& op);
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index f4d5c72f3..669e58ac6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -19,7 +19,6 @@
#include <functional>
#include <memory>
#include <optional>
-#include <unordered_map>
#include <android-base/unique_fd.h>
#include <libsnapshot/cow_format.h>
@@ -28,6 +27,7 @@ namespace android {
namespace snapshot {
class ICowOpIter;
+class ICowOpReverseIter;
// A ByteSink object handles requests for a buffer of a specific size. It
// always owns the underlying buffer. It's designed to minimize potential
@@ -68,7 +68,6 @@ class ICowReader {
// Return the file footer.
virtual bool GetFooter(CowFooter* footer) = 0;
- virtual bool VerifyMergeOps() = 0;
// Return the last valid label
virtual bool GetLastLabel(uint64_t* label) = 0;
@@ -76,11 +75,8 @@ class ICowReader {
// Return an iterator for retrieving CowOperation entries.
virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
- // Return an iterator for retrieving CowOperation entries in reverse merge order
- virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress) = 0;
-
- // Return an iterator for retrieving CowOperation entries in merge order
- virtual std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress) = 0;
+ // Return an reverse iterator for retrieving CowOperation entries.
+ virtual std::unique_ptr<ICowOpReverseIter> GetRevOpIter() = 0;
// Get decoded bytes from the data section, handling any decompression.
// All retrieved data is passed to the sink.
@@ -92,7 +88,7 @@ class ICowOpIter {
public:
virtual ~ICowOpIter() {}
- // True if there are no more items to read forward, false otherwise.
+ // True if there are more items to read, false otherwise.
virtual bool Done() = 0;
// Read the current operation.
@@ -100,22 +96,26 @@ class ICowOpIter {
// Advance to the next item.
virtual void Next() = 0;
+};
- // Advance to the previous item.
- virtual void Prev() = 0;
+// Reverse Iterate over a sequence of COW operations.
+class ICowOpReverseIter {
+ public:
+ virtual ~ICowOpReverseIter() {}
- // True if there are no more items to read backwards, false otherwise
- virtual bool RDone() = 0;
+ // True if there are more items to read, false otherwise.
+ virtual bool Done() = 0;
+
+ // Read the current operation.
+ virtual const CowOperation& Get() = 0;
+
+ // Advance to the next item.
+ virtual void Next() = 0;
};
-class CowReader final : public ICowReader {
+class CowReader : public ICowReader {
public:
- enum class ReaderFlags {
- DEFAULT = 0,
- USERSPACE_MERGE = 1,
- };
-
- CowReader(ReaderFlags reader_flag = ReaderFlags::DEFAULT);
+ CowReader();
~CowReader() { owned_fd_ = {}; }
// Parse the COW, optionally, up to the given label. If no label is
@@ -124,7 +124,6 @@ class CowReader final : public ICowReader {
bool Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label = {});
bool InitForMerge(android::base::unique_fd&& fd);
- bool VerifyMergeOps() override;
bool GetHeader(CowHeader* header) override;
bool GetFooter(CowFooter* footer) override;
@@ -136,31 +135,25 @@ class CowReader final : public ICowReader {
// whose lifetime depends on the CowOpIter object; the return
// value of these will never be null.
std::unique_ptr<ICowOpIter> GetOpIter() override;
- std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress = false) override;
- std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress = false) override;
+ std::unique_ptr<ICowOpReverseIter> GetRevOpIter() override;
bool ReadData(const CowOperation& op, IByteSink* sink) override;
bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
- // Returns the total number of data ops that should be merged. This is the
- // count of the merge sequence before removing already-merged operations.
- // It may be different than the actual data op count, for example, if there
- // are duplicate ops in the stream.
- uint64_t get_num_total_data_ops() { return num_total_data_ops_; }
+ void InitializeMerge();
- uint64_t get_num_ordered_ops_to_merge() { return num_ordered_ops_to_merge_; }
+ // Number of copy, replace, and zero ops. Set if InitializeMerge is called.
+ void set_total_data_ops(uint64_t size) { total_data_ops_ = size; }
+ uint64_t total_data_ops() { return total_data_ops_; }
+ // Number of copy ops. Set if InitializeMerge is called.
+ void set_copy_ops(uint64_t size) { copy_ops_ = size; }
+ uint64_t total_copy_ops() { return copy_ops_; }
void CloseCowFd() { owned_fd_ = {}; }
- // Creates a clone of the current CowReader without the file handlers
- std::unique_ptr<CowReader> CloneCowReader();
-
- void UpdateMergeOpsCompleted(int num_merge_ops) { header_.num_merge_ops += num_merge_ops; }
-
private:
bool ParseOps(std::optional<uint64_t> label);
- bool PrepMergeOps();
uint64_t FindNumCopyops();
android::base::unique_fd owned_fd_;
@@ -170,14 +163,8 @@ class CowReader final : public ICowReader {
uint64_t fd_size_;
std::optional<uint64_t> last_label_;
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- uint64_t merge_op_start_{};
- std::shared_ptr<std::unordered_map<uint32_t, int>> block_map_;
- uint64_t num_total_data_ops_{};
- uint64_t num_ordered_ops_to_merge_{};
- bool has_seq_ops_{};
- std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc_;
- ReaderFlags reader_flag_;
+ uint64_t total_data_ops_;
+ uint64_t copy_ops_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index e17b5c6a1..f43ea6834 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -38,9 +38,6 @@ struct CowOptions {
uint32_t cluster_ops = 200;
bool scratch_space = true;
-
- // Preset the number of merged ops. Only useful for testing.
- uint64_t num_merge_ops = 0;
};
// Interface for writing to a snapuserd COW. All operations are ordered; merges
@@ -58,19 +55,12 @@ class ICowWriter {
// Encode a sequence of raw blocks. |size| must be a multiple of the block size.
bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
- // Add a sequence of xor'd blocks. |size| must be a multiple of the block size.
- bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
- uint16_t offset);
-
// Encode a sequence of zeroed blocks. |size| must be a multiple of the block size.
bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks);
// Add a label to the op sequence.
bool AddLabel(uint64_t label);
- // Add sequence data for op merging. Data is a list of the destination block numbers.
- bool AddSequenceData(size_t num_ops, const uint32_t* data);
-
// Flush all pending writes. This must be called before closing the writer
// to ensure that the correct headers and footers are written.
virtual bool Finalize() = 0;
@@ -86,11 +76,8 @@ class ICowWriter {
protected:
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
- virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
- uint32_t old_block, uint16_t offset) = 0;
virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0;
virtual bool EmitLabel(uint64_t label) = 0;
- virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) = 0;
bool ValidateNewBlock(uint64_t new_block);
@@ -124,17 +111,12 @@ class CowWriter : public ICowWriter {
protected:
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
- virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
- uint32_t old_block, uint16_t offset) override;
virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
virtual bool EmitLabel(uint64_t label) override;
- virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
private:
bool EmitCluster();
bool EmitClusterIfNeeded();
- bool EmitBlocks(uint64_t new_block_start, const void* data, size_t size, uint64_t old_block,
- uint16_t offset, uint8_t type);
void SetupHeaders();
bool ParseOptions();
bool OpenForWrite();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index ba62330f1..ec58cca2e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -35,7 +35,6 @@ class MockSnapshotManager : public ISnapshotManager {
(override));
MOCK_METHOD(UpdateState, GetUpdateState, (double* progress), (override));
MOCK_METHOD(bool, UpdateUsesCompression, (), (override));
- MOCK_METHOD(bool, UpdateUsesUserSnapshots, (), (override));
MOCK_METHOD(Return, CreateUpdateSnapshots,
(const chromeos_update_engine::DeltaArchiveManifest& manifest), (override));
MOCK_METHOD(bool, MapUpdateSnapshot,
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
deleted file mode 100644
index b0be5a594..000000000
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-// 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 <gmock/gmock.h>
-#include <libsnapshot/snapshot_writer.h>
-
-namespace android::snapshot {
-
-class MockSnapshotWriter : public ISnapshotWriter {
- public:
- using FileDescriptor = ISnapshotWriter::FileDescriptor;
-
- explicit MockSnapshotWriter(const CowOptions& options) : ISnapshotWriter(options) {}
- MockSnapshotWriter() : ISnapshotWriter({}) {}
-
- MOCK_METHOD(bool, Finalize, (), (override));
-
- // Return number of bytes the cow image occupies on disk.
- MOCK_METHOD(uint64_t, GetCowSize, (), (override));
-
- // Returns true if AddCopy() operations are supported.
- MOCK_METHOD(bool, SupportsCopyOperation, (), (const override));
-
- MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t), (override));
- MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
- MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t),
- (override));
- MOCK_METHOD(bool, EmitZeroBlocks, (uint64_t, uint64_t), (override));
- MOCK_METHOD(bool, EmitLabel, (uint64_t), (override));
- MOCK_METHOD(bool, EmitSequenceData, (size_t, const uint32_t*), (override));
-
- // Open the writer in write mode (no append).
- MOCK_METHOD(bool, Initialize, (), (override));
- MOCK_METHOD(bool, VerifyMergeOps, (), (override, const, noexcept));
-
- // Open the writer in append mode, with the last label to resume
- // from. See CowWriter::InitializeAppend.
- MOCK_METHOD(bool, InitializeAppend, (uint64_t label), (override));
-
- MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenReader, (), (override));
-};
-} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 11da56854..15882b382 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -38,7 +38,7 @@
#include <libsnapshot/auto_device.h>
#include <libsnapshot/return.h>
#include <libsnapshot/snapshot_writer.h>
-#include <snapuserd/snapuserd_client.h>
+#include <libsnapshot/snapuserd_client.h>
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
@@ -110,7 +110,6 @@ class ISnapshotManager {
virtual bool IsTestDevice() const { return false; }
virtual bool IsFirstStageInit() const = 0;
virtual std::unique_ptr<IImageManager> OpenImageManager() const = 0;
- virtual android::dm::IDeviceMapper& GetDeviceMapper() = 0;
// Helper method for implementing OpenImageManager.
std::unique_ptr<IImageManager> OpenImageManager(const std::string& gsid_dir) const;
@@ -193,9 +192,6 @@ class ISnapshotManager {
// UpdateState is None, or no snapshots have been created.
virtual bool UpdateUsesCompression() = 0;
- // Returns true if userspace snapshots is enabled for the current update.
- virtual bool UpdateUsesUserSnapshots() = 0;
-
// Create necessary COW device / files for OTA clients. New logical partitions will be added to
// group "cow" in target_metadata. Regions of partitions of current_metadata will be
// "write-protected" and snapshotted.
@@ -355,7 +351,6 @@ class SnapshotManager final : public ISnapshotManager {
const std::function<bool()>& before_cancel = {}) override;
UpdateState GetUpdateState(double* progress = nullptr) override;
bool UpdateUsesCompression() override;
- bool UpdateUsesUserSnapshots() override;
Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
std::string* snapshot_path) override;
@@ -391,22 +386,6 @@ class SnapshotManager final : public ISnapshotManager {
// first-stage to decide whether to launch snapuserd.
bool IsSnapuserdRequired();
- enum class SnapshotDriver {
- DM_SNAPSHOT,
- DM_USER,
- };
-
- // Add new public entries above this line.
-
- // Helpers for failure injection.
- using MergeConsistencyChecker =
- std::function<MergeFailureCode(const std::string& name, const SnapshotStatus& status)>;
-
- void set_merge_consistency_checker(MergeConsistencyChecker checker) {
- merge_consistency_checker_ = checker;
- }
- MergeConsistencyChecker merge_consistency_checker() const { return merge_consistency_checker_; }
-
private:
FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
FRIEND_TEST(SnapshotTest, CreateSnapshot);
@@ -420,8 +399,6 @@ class SnapshotManager final : public ISnapshotManager {
FRIEND_TEST(SnapshotTest, MergeFailureCode);
FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
- FRIEND_TEST(SnapshotUpdateTest, AddPartition);
- FRIEND_TEST(SnapshotUpdateTest, ConsistencyCheckResume);
FRIEND_TEST(SnapshotUpdateTest, DaemonTransition);
FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
@@ -429,7 +406,6 @@ class SnapshotManager final : public ISnapshotManager {
FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
- FRIEND_TEST(SnapshotUpdateTest, QueryStatusError);
FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate);
friend class SnapshotTest;
@@ -477,8 +453,6 @@ class SnapshotManager final : public ISnapshotManager {
};
static std::unique_ptr<LockedFile> OpenFile(const std::string& file, int lock_flags);
- SnapshotDriver GetSnapshotDriver(LockedFile* lock);
-
// Create a new snapshot record. This creates the backing COW store and
// persists information needed to map the device. The device can be mapped
// with MapSnapshot().
@@ -514,8 +488,8 @@ class SnapshotManager final : public ISnapshotManager {
// Create a dm-user device for a given snapshot.
bool MapDmUserCow(LockedFile* lock, const std::string& name, const std::string& cow_file,
- const std::string& base_device, const std::string& base_path_merge,
- const std::chrono::milliseconds& timeout_ms, std::string* path);
+ const std::string& base_device, const std::chrono::milliseconds& timeout_ms,
+ std::string* path);
// Map the source device used for dm-user.
bool MapSourceDevice(LockedFile* lock, const std::string& name,
@@ -538,9 +512,6 @@ class SnapshotManager final : public ISnapshotManager {
// Unmap a COW and remove it from a MetadataBuilder.
void UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata);
- // Remove invalid snapshots if any
- void RemoveInvalidSnapshots(LockedFile* lock);
-
// Unmap and remove all known snapshots.
bool RemoveAllSnapshots(LockedFile* lock);
@@ -617,8 +588,7 @@ class SnapshotManager final : public ISnapshotManager {
// Internal callback for when merging is complete.
bool OnSnapshotMergeComplete(LockedFile* lock, const std::string& name,
const SnapshotStatus& status);
- bool CollapseSnapshotDevice(LockedFile* lock, const std::string& name,
- const SnapshotStatus& status);
+ bool CollapseSnapshotDevice(const std::string& name, const SnapshotStatus& status);
struct MergeResult {
explicit MergeResult(UpdateState state,
@@ -640,14 +610,6 @@ class SnapshotManager final : public ISnapshotManager {
MergeFailureCode CheckMergeConsistency(LockedFile* lock, const std::string& name,
const SnapshotStatus& update_status);
- // Get status or table information about a device-mapper node with a single target.
- enum class TableQuery {
- Table,
- Status,
- };
- bool GetSingleTarget(const std::string& dm_name, TableQuery query,
- android::dm::DeviceMapper::TargetInfo* target);
-
// Interact with status files under /metadata/ota/snapshots.
bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status);
@@ -716,10 +678,7 @@ class SnapshotManager final : public ISnapshotManager {
bool UnmapPartitionWithSnapshot(LockedFile* lock, const std::string& target_partition_name);
// Unmap a dm-user device through snapuserd.
- bool UnmapDmUserDevice(const std::string& dm_user_name);
-
- // Unmap a dm-user device for user space snapshots
- bool UnmapUserspaceSnapshotDevice(LockedFile* lock, const std::string& snapshot_name);
+ bool UnmapDmUserDevice(const std::string& snapshot_name);
// If there isn't a previous update, return true. |needs_merge| is set to false.
// If there is a previous update but the device has not boot into it, tries to cancel the
@@ -808,28 +767,20 @@ class SnapshotManager final : public ISnapshotManager {
// Helper of UpdateUsesCompression
bool UpdateUsesCompression(LockedFile* lock);
- // Locked and unlocked functions to test whether the current update uses
- // userspace snapshots.
- bool UpdateUsesUserSnapshots(LockedFile* lock);
-
- // Check if io_uring API's need to be used
- bool UpdateUsesIouring(LockedFile* lock);
// Wrapper around libdm, with diagnostics.
bool DeleteDeviceIfExists(const std::string& name,
const std::chrono::milliseconds& timeout_ms = {});
- android::dm::IDeviceMapper& dm_;
- std::unique_ptr<IDeviceInfo> device_;
+ std::string gsid_dir_;
std::string metadata_dir_;
+ std::unique_ptr<IDeviceInfo> device_;
std::unique_ptr<IImageManager> images_;
bool use_first_stage_snapuserd_ = false;
bool in_factory_data_reset_ = false;
std::function<bool(const std::string&)> uevent_regen_callback_;
std::unique_ptr<SnapuserdClient> snapuserd_client_;
std::unique_ptr<LpMetadata> old_partition_metadata_;
- std::optional<bool> is_snapshot_userspace_;
- MergeConsistencyChecker merge_consistency_checker_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 318e5259d..74b78c59b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -35,7 +35,6 @@ class SnapshotManagerStub : public ISnapshotManager {
const std::function<bool()>& before_cancel = {}) override;
UpdateState GetUpdateState(double* progress = nullptr) override;
bool UpdateUsesCompression() override;
- bool UpdateUsesUserSnapshots() override;
Return CreateUpdateSnapshots(
const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
index 545f1171d..bf5ce8bb5 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -47,7 +47,6 @@ class ISnapshotWriter : public ICowWriter {
virtual bool InitializeAppend(uint64_t label) = 0;
virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
- virtual bool VerifyMergeOps() const noexcept = 0;
protected:
android::base::borrowed_fd GetSourceFd();
@@ -59,7 +58,7 @@ class ISnapshotWriter : public ICowWriter {
};
// Send writes to a COW or a raw device directly, based on a threshold.
-class CompressedSnapshotWriter final : public ISnapshotWriter {
+class CompressedSnapshotWriter : public ISnapshotWriter {
public:
CompressedSnapshotWriter(const CowOptions& options);
@@ -71,26 +70,21 @@ class CompressedSnapshotWriter final : public ISnapshotWriter {
bool Finalize() override;
uint64_t GetCowSize() override;
std::unique_ptr<FileDescriptor> OpenReader() override;
- bool VerifyMergeOps() const noexcept;
protected:
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
- bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
- uint16_t offset) override;
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
bool EmitLabel(uint64_t label) override;
- bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
private:
- std::unique_ptr<CowReader> OpenCowReader() const;
android::base::unique_fd cow_device_;
std::unique_ptr<CowWriter> cow_;
};
// Write directly to a dm-snapshot device.
-class OnlineKernelSnapshotWriter final : public ISnapshotWriter {
+class OnlineKernelSnapshotWriter : public ISnapshotWriter {
public:
OnlineKernelSnapshotWriter(const CowOptions& options);
@@ -104,18 +98,11 @@ class OnlineKernelSnapshotWriter final : public ISnapshotWriter {
uint64_t GetCowSize() override { return cow_size_; }
std::unique_ptr<FileDescriptor> OpenReader() override;
- // Online kernel snapshot writer doesn't care about merge sequences.
- // So ignore.
- bool VerifyMergeOps() const noexcept override { return true; }
-
protected:
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
- bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
- uint16_t offset) override;
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
bool EmitLabel(uint64_t label) override;
- bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
private:
android::base::unique_fd snapshot_fd_;
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
index cebda1ccb..280e85730 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -31,7 +31,6 @@ namespace snapshot {
static constexpr uint32_t PACKET_SIZE = 512;
static constexpr char kSnapuserdSocket[] = "snapuserd";
-static constexpr char kSnapuserdSocketProxy[] = "snapuserd_proxy";
// Ensure that the second-stage daemon for snapuserd is running.
bool EnsureSnapuserdStarted();
@@ -63,8 +62,7 @@ class SnapuserdClient {
// The misc_name must be the "misc_name" given to dm-user in step 2.
//
uint64_t InitDmUserCow(const std::string& misc_name, const std::string& cow_device,
- const std::string& backing_device,
- const std::string& base_path_merge = "");
+ const std::string& backing_device);
bool AttachDmUser(const std::string& misc_name);
// Wait for snapuserd to disassociate with a dm-user control device. This
@@ -77,18 +75,6 @@ class SnapuserdClient {
// snapuserd to gracefully exit once all handler threads have terminated.
// This should only be used on first-stage instances of snapuserd.
bool DetachSnapuserd();
-
- // Returns true if the snapuserd instance supports bridging a socket to second-stage init.
- bool SupportsSecondStageSocketHandoff();
-
- // Returns true if the merge is started(or resumed from crash).
- bool InitiateMerge(const std::string& misc_name);
-
- // Returns Merge completion percentage
- double GetMergePercent();
-
- // Return the status of the snapshot
- std::string QuerySnapshotStatus(const std::string& misc_name);
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
index c592257ca..6bb7a394e 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
@@ -47,6 +47,8 @@ typedef sector_t chunk_t;
static constexpr uint32_t CHUNK_SIZE = 8;
static constexpr uint32_t CHUNK_SHIFT = (__builtin_ffs(CHUNK_SIZE) - 1);
+#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
+
// This structure represents the kernel COW header.
// All the below fields should be in Little Endian format.
struct disk_header {
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index c3b40dca4..4e7ccf145 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -99,12 +99,6 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
std::unique_ptr<IImageManager> OpenImageManager() const override {
return IDeviceInfo::OpenImageManager("ota/test");
}
- android::dm::IDeviceMapper& GetDeviceMapper() override {
- if (dm_) {
- return *dm_;
- }
- return android::dm::DeviceMapper::Instance();
- }
bool IsSlotUnbootable(uint32_t slot) { return unbootable_slots_.count(slot) != 0; }
@@ -114,8 +108,6 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
}
void set_recovery(bool value) { recovery_ = value; }
void set_first_stage_init(bool value) { first_stage_init_ = value; }
- void set_dm(android::dm::IDeviceMapper* dm) { dm_ = dm; }
-
MergeStatus merge_status() const { return merge_status_; }
private:
@@ -125,45 +117,6 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
bool recovery_ = false;
bool first_stage_init_ = false;
std::unordered_set<uint32_t> unbootable_slots_;
- android::dm::IDeviceMapper* dm_ = nullptr;
-};
-
-class DeviceMapperWrapper : public android::dm::IDeviceMapper {
- using DmDeviceState = android::dm::DmDeviceState;
- using DmTable = android::dm::DmTable;
-
- public:
- DeviceMapperWrapper() : impl_(android::dm::DeviceMapper::Instance()) {}
- explicit DeviceMapperWrapper(android::dm::IDeviceMapper& impl) : impl_(impl) {}
-
- virtual bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
- const std::chrono::milliseconds& timeout_ms) override {
- return impl_.CreateDevice(name, table, path, timeout_ms);
- }
- virtual DmDeviceState GetState(const std::string& name) const override {
- return impl_.GetState(name);
- }
- virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) {
- return impl_.LoadTableAndActivate(name, table);
- }
- virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
- return impl_.GetTableInfo(name, table);
- }
- virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
- return impl_.GetTableStatus(name, table);
- }
- virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) {
- return impl_.GetDmDevicePathByName(name, path);
- }
- virtual bool GetDeviceString(const std::string& name, std::string* dev) {
- return impl_.GetDeviceString(name, dev);
- }
- virtual bool DeleteDeviceIfExists(const std::string& name) {
- return impl_.DeleteDeviceIfExists(name);
- }
-
- private:
- android::dm::IDeviceMapper& impl_;
};
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 167ff8c35..4a84fba0d 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -16,10 +16,8 @@
#include <stdio.h>
#include <unistd.h>
-#include <iomanip>
#include <iostream>
#include <string>
-#include <vector>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
@@ -41,28 +39,9 @@ static void usage(void) {
LOG(ERROR) << "Usage: inspect_cow [-sd] <COW_FILE>";
LOG(ERROR) << "\t -s Run Silent";
LOG(ERROR) << "\t -d Attempt to decompress";
- LOG(ERROR) << "\t -b Show data for failed decompress";
- LOG(ERROR) << "\t -l Show ops";
- LOG(ERROR) << "\t -m Show ops in reverse merge order";
- LOG(ERROR) << "\t -n Show ops in merge order";
- LOG(ERROR) << "\t -a Include merged ops in any merge order listing";
- LOG(ERROR) << "\t -o Shows sequence op block order";
- LOG(ERROR) << "\t -v Verifies merge order has no conflicts\n";
+ LOG(ERROR) << "\t -b Show data for failed decompress\n";
}
-enum OpIter { Normal, RevMerge, Merge };
-
-struct Options {
- bool silent;
- bool decompress;
- bool show_ops;
- bool show_bad;
- bool show_seq;
- bool verify_sequence;
- OpIter iter_type;
- bool include_merged;
-};
-
// Sink that always appends to the end of a string.
class StringSink : public IByteSink {
public:
@@ -99,7 +78,7 @@ static void ShowBad(CowReader& reader, const struct CowOperation& op) {
}
}
-static bool Inspect(const std::string& path, Options opt) {
+static bool Inspect(const std::string& path, bool silent, bool decompress, bool show_bad) {
android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
if (fd < 0) {
PLOG(ERROR) << "open failed: " << path;
@@ -121,14 +100,12 @@ static bool Inspect(const std::string& path, Options opt) {
bool has_footer = false;
if (reader.GetFooter(&footer)) has_footer = true;
- if (!opt.silent) {
+ if (!silent) {
std::cout << "Major version: " << header.major_version << "\n";
std::cout << "Minor version: " << header.minor_version << "\n";
std::cout << "Header size: " << header.header_size << "\n";
std::cout << "Footer size: " << header.footer_size << "\n";
std::cout << "Block size: " << header.block_size << "\n";
- std::cout << "Num merge ops: " << header.num_merge_ops << "\n";
- std::cout << "RA buffer size: " << header.buffer_size << "\n";
std::cout << "\n";
if (has_footer) {
std::cout << "Total Ops size: " << footer.op.ops_size << "\n";
@@ -137,77 +114,26 @@ static bool Inspect(const std::string& path, Options opt) {
}
}
- if (opt.verify_sequence) {
- if (reader.VerifyMergeOps()) {
- std::cout << "\nMerge sequence is consistent.\n";
- } else {
- std::cout << "\nMerge sequence is inconsistent!\n";
- }
- }
-
- std::unique_ptr<ICowOpIter> iter;
- if (opt.iter_type == Normal) {
- iter = reader.GetOpIter();
- } else if (opt.iter_type == RevMerge) {
- iter = reader.GetRevMergeOpIter(opt.include_merged);
- } else if (opt.iter_type == Merge) {
- iter = reader.GetMergeOpIter(opt.include_merged);
- }
+ auto iter = reader.GetOpIter();
StringSink sink;
bool success = true;
- uint64_t xor_ops = 0, copy_ops = 0, replace_ops = 0, zero_ops = 0;
while (!iter->Done()) {
const CowOperation& op = iter->Get();
- if (!opt.silent && opt.show_ops) std::cout << op << "\n";
+ if (!silent) std::cout << op << "\n";
- if (opt.decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
+ if (decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
if (!reader.ReadData(op, &sink)) {
std::cerr << "Failed to decompress for :" << op << "\n";
success = false;
- if (opt.show_bad) ShowBad(reader, op);
+ if (show_bad) ShowBad(reader, op);
}
sink.Reset();
}
- if (op.type == kCowSequenceOp && opt.show_seq) {
- size_t read;
- std::vector<uint32_t> merge_op_blocks;
- size_t seq_len = op.data_length / sizeof(uint32_t);
- merge_op_blocks.resize(seq_len);
- if (!reader.GetRawBytes(op.source, merge_op_blocks.data(), op.data_length, &read)) {
- PLOG(ERROR) << "Failed to read sequence op!";
- return false;
- }
- if (!opt.silent) {
- std::cout << "Sequence for " << op << " is :\n";
- for (size_t i = 0; i < seq_len; i++) {
- std::cout << std::setfill('0') << std::setw(6) << merge_op_blocks[i] << ", ";
- if ((i + 1) % 10 == 0 || i + 1 == seq_len) std::cout << "\n";
- }
- }
- }
-
- if (op.type == kCowCopyOp) {
- copy_ops++;
- } else if (op.type == kCowReplaceOp) {
- replace_ops++;
- } else if (op.type == kCowZeroOp) {
- zero_ops++;
- } else if (op.type == kCowXorOp) {
- xor_ops++;
- }
-
iter->Next();
}
- if (!opt.silent) {
- auto total_ops = replace_ops + zero_ops + copy_ops + xor_ops;
- std::cout << "Total-data-ops: " << total_ops << "Replace-ops: " << replace_ops
- << " Zero-ops: " << zero_ops << " Copy-ops: " << copy_ops
- << " Xor_ops: " << xor_ops << std::endl;
- }
-
return success;
}
@@ -216,41 +142,19 @@ static bool Inspect(const std::string& path, Options opt) {
int main(int argc, char** argv) {
int ch;
- struct android::snapshot::Options opt;
- opt.silent = false;
- opt.decompress = false;
- opt.show_bad = false;
- opt.iter_type = android::snapshot::Normal;
- opt.verify_sequence = false;
- opt.include_merged = false;
- while ((ch = getopt(argc, argv, "sdbmnolva")) != -1) {
+ bool silent = false;
+ bool decompress = false;
+ bool show_bad = false;
+ while ((ch = getopt(argc, argv, "sdb")) != -1) {
switch (ch) {
case 's':
- opt.silent = true;
+ silent = true;
break;
case 'd':
- opt.decompress = true;
+ decompress = true;
break;
case 'b':
- opt.show_bad = true;
- break;
- case 'm':
- opt.iter_type = android::snapshot::RevMerge;
- break;
- case 'n':
- opt.iter_type = android::snapshot::Merge;
- break;
- case 'o':
- opt.show_seq = true;
- break;
- case 'l':
- opt.show_ops = true;
- break;
- case 'v':
- opt.verify_sequence = true;
- break;
- case 'a':
- opt.include_merged = true;
+ show_bad = true;
break;
default:
android::snapshot::usage();
@@ -263,7 +167,7 @@ int main(int argc, char** argv) {
return 1;
}
- if (!android::snapshot::Inspect(argv[optind], opt)) {
+ if (!android::snapshot::Inspect(argv[optind], silent, decompress, show_bad)) {
return 1;
}
return 0;
diff --git a/fs_mgr/libsnapshot/run_snapshot_tests.sh b/fs_mgr/libsnapshot/run_snapshot_tests.sh
deleted file mode 100644
index b03a4e075..000000000
--- a/fs_mgr/libsnapshot/run_snapshot_tests.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/system/bin/sh
-
-# Detect host or AOSP.
-getprop ro.build.version.sdk > /dev/null 2>&1
-if [ $? -eq 0 ]; then
- cmd_prefix=""
- local_root=""
-else
- cmd_prefix="adb shell"
- local_root="${ANDROID_PRODUCT_OUT}"
- set -e
- set -x
- adb root
- adb sync data
- set +x
- set +e
-fi
-
-testpath64="/data/nativetest64/vts_libsnapshot_test/vts_libsnapshot_test"
-testpath32="/data/nativetest/vts_libsnapshot_test/vts_libsnapshot_test"
-if [ -f "${local_root}/${testpath64}" ]; then
- testpath="${testpath64}"
-elif [ -f "${local_root}/${testpath32}" ]; then
- testpath="${testpath32}"
-else
- echo "ERROR: vts_libsnapshot_test not found." 1>&2
- echo "Make sure to build vts_libsnapshot_test or snapshot_tests first." 1>&2
- exit 1
-fi
-
-# Verbose, error on failure.
-set -x
-set -e
-
-time ${cmd_prefix} ${testpath}
diff --git a/fs_mgr/libsnapshot/scripts/Android.bp b/fs_mgr/libsnapshot/scripts/Android.bp
deleted file mode 100644
index 829f5bc92..000000000
--- a/fs_mgr/libsnapshot/scripts/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-python_binary_host {
- name: "dump_snapshot_proto",
- main: "dump_snapshot_proto.py",
- srcs: [
- "dump_snapshot_proto.py",
- ],
- libs: [
- "snapshot_proto_python",
- ],
-}
diff --git a/fs_mgr/libsnapshot/scripts/dump_snapshot_proto.py b/fs_mgr/libsnapshot/scripts/dump_snapshot_proto.py
deleted file mode 100644
index 566108d5d..000000000
--- a/fs_mgr/libsnapshot/scripts/dump_snapshot_proto.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# 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.
-
-import argparse
-
-from android.snapshot import snapshot_pb2
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('type', type = str, help = 'Type (snapshot or update)')
- parser.add_argument('file', type = str, help = 'Input file')
- args = parser.parse_args()
-
- with open(args.file, 'rb') as fp:
- data = fp.read()
-
- if args.type == 'snapshot':
- msg = snapshot_pb2.SnapshotStatus()
- elif args.type == 'update':
- msg = snapshot_pb2.SnapshotUpdateStatus()
- else:
- raise Exception('Unknown proto type')
-
- msg.ParseFromString(data)
- print(msg)
-
-if __name__ == '__main__':
- main()
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index a83f535b2..0e36da151 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -87,8 +87,6 @@ static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator";
static constexpr auto kUpdateStateCheckInterval = 2s;
-MergeFailureCode CheckMergeConsistency(const std::string& name, const SnapshotStatus& status);
-
// Note: IImageManager is an incomplete type in the header, so the default
// destructor doesn't work.
SnapshotManager::~SnapshotManager() {}
@@ -97,7 +95,6 @@ std::unique_ptr<SnapshotManager> SnapshotManager::New(IDeviceInfo* info) {
if (!info) {
info = new DeviceInfo();
}
-
return std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
}
@@ -117,43 +114,16 @@ std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceI
return sm;
}
-SnapshotManager::SnapshotManager(IDeviceInfo* device)
- : dm_(device->GetDeviceMapper()), device_(device), metadata_dir_(device_->GetMetadataDir()) {
- merge_consistency_checker_ = android::snapshot::CheckMergeConsistency;
+SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) {
+ metadata_dir_ = device_->GetMetadataDir();
}
static std::string GetCowName(const std::string& snapshot_name) {
return snapshot_name + "-cow";
}
-SnapshotManager::SnapshotDriver SnapshotManager::GetSnapshotDriver(LockedFile* lock) {
- if (UpdateUsesUserSnapshots(lock)) {
- return SnapshotManager::SnapshotDriver::DM_USER;
- } else {
- return SnapshotManager::SnapshotDriver::DM_SNAPSHOT;
- }
-}
-
-static std::string GetDmUserCowName(const std::string& snapshot_name,
- SnapshotManager::SnapshotDriver driver) {
- // dm-user block device will act as a snapshot device. We identify it with
- // the same partition name so that when partitions can be mounted off
- // dm-user.
-
- switch (driver) {
- case SnapshotManager::SnapshotDriver::DM_USER: {
- return snapshot_name;
- }
-
- case SnapshotManager::SnapshotDriver::DM_SNAPSHOT: {
- return snapshot_name + "-user-cow";
- }
-
- default: {
- LOG(ERROR) << "Invalid snapshot driver";
- return "";
- }
- }
+static std::string GetDmUserCowName(const std::string& snapshot_name) {
+ return snapshot_name + "-user-cow";
}
static std::string GetCowImageDeviceName(const std::string& snapshot_name) {
@@ -218,10 +188,7 @@ bool SnapshotManager::TryCancelUpdate(bool* needs_merge) {
if (!file) return false;
UpdateState state = ReadUpdateState(file.get());
- if (state == UpdateState::None) {
- RemoveInvalidSnapshots(file.get());
- return true;
- }
+ if (state == UpdateState::None) return true;
if (state == UpdateState::Initiated) {
LOG(INFO) << "Update has been initiated, now canceling";
@@ -432,32 +399,10 @@ Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name
bool SnapshotManager::MapDmUserCow(LockedFile* lock, const std::string& name,
const std::string& cow_file, const std::string& base_device,
- const std::string& base_path_merge,
const std::chrono::milliseconds& timeout_ms, std::string* path) {
CHECK(lock);
- if (UpdateUsesUserSnapshots(lock)) {
- SnapshotStatus status;
- if (!ReadSnapshotStatus(lock, name, &status)) {
- LOG(ERROR) << "MapDmUserCow: ReadSnapshotStatus failed...";
- return false;
- }
-
- if (status.state() == SnapshotState::NONE ||
- status.state() == SnapshotState::MERGE_COMPLETED) {
- LOG(ERROR) << "Should not create a snapshot device for " << name
- << " after merging has completed.";
- return false;
- }
-
- SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
- if (update_status.state() == UpdateState::MergeCompleted ||
- update_status.state() == UpdateState::MergeNeedsReboot) {
- LOG(ERROR) << "Should not create a snapshot device for " << name
- << " after global merging has completed.";
- return false;
- }
- }
+ auto& dm = DeviceMapper::Instance();
// Use an extra decoration for first-stage init, so we can transition
// to a new table entry in second-stage.
@@ -470,41 +415,18 @@ bool SnapshotManager::MapDmUserCow(LockedFile* lock, const std::string& name,
return false;
}
- uint64_t base_sectors = 0;
- if (!UpdateUsesUserSnapshots(lock)) {
- base_sectors = snapuserd_client_->InitDmUserCow(misc_name, cow_file, base_device);
- if (base_sectors == 0) {
- LOG(ERROR) << "Failed to retrieve base_sectors from Snapuserd";
- return false;
- }
- } else {
- // For userspace snapshots, the size of the base device is taken as the
- // size of the dm-user block device. Since there is no pseudo mapping
- // created in the daemon, we no longer need to rely on the daemon for
- // sizing the dm-user block device.
- unique_fd fd(TEMP_FAILURE_RETRY(open(base_path_merge.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd < 0) {
- LOG(ERROR) << "Cannot open block device: " << base_path_merge;
- return false;
- }
-
- uint64_t dev_sz = get_block_device_size(fd.get());
- if (!dev_sz) {
- LOG(ERROR) << "Failed to find block device size: " << base_path_merge;
- return false;
- }
-
- base_sectors = dev_sz >> 9;
+ uint64_t base_sectors = snapuserd_client_->InitDmUserCow(misc_name, cow_file, base_device);
+ if (base_sectors == 0) {
+ LOG(ERROR) << "Failed to retrieve base_sectors from Snapuserd";
+ return false;
}
DmTable table;
table.Emplace<DmTargetUser>(0, base_sectors, misc_name);
- if (!dm_.CreateDevice(name, table, path, timeout_ms)) {
- LOG(ERROR) << " dm-user: CreateDevice failed... ";
+ if (!dm.CreateDevice(name, table, path, timeout_ms)) {
return false;
}
if (!WaitForDevice(*path, timeout_ms)) {
- LOG(ERROR) << " dm-user: timeout: Failed to create block device for: " << name;
return false;
}
@@ -513,15 +435,6 @@ bool SnapshotManager::MapDmUserCow(LockedFile* lock, const std::string& name,
return false;
}
- if (UpdateUsesUserSnapshots(lock)) {
- // Now that the dm-user device is created, initialize the daemon and
- // spin up the worker threads.
- if (!snapuserd_client_->InitDmUserCow(misc_name, cow_file, base_device, base_path_merge)) {
- LOG(ERROR) << "InitDmUserCow failed";
- return false;
- }
- }
-
return snapuserd_client_->AttachDmUser(misc_name);
}
@@ -577,6 +490,8 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
+ auto& dm = DeviceMapper::Instance();
+
// Note that merging is a global state. We do track whether individual devices
// have completed merging, but the start of the merge process is considered
// atomic.
@@ -603,17 +518,10 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
break;
}
- if (mode == SnapshotStorageMode::Persistent && status.state() == SnapshotState::MERGING) {
- LOG(ERROR) << "Snapshot: " << name
- << " has snapshot status Merging but mode set to Persistent."
- << " Changing mode to Snapshot-Merge.";
- mode = SnapshotStorageMode::Merge;
- }
-
DmTable table;
table.Emplace<DmTargetSnapshot>(0, snapshot_sectors, base_device, cow_device, mode,
kSnapshotChunkSize);
- if (!dm_.CreateDevice(name, table, dev_path, timeout_ms)) {
+ if (!dm.CreateDevice(name, table, dev_path, timeout_ms)) {
LOG(ERROR) << "Could not create snapshot device: " << name;
return false;
}
@@ -675,15 +583,9 @@ bool SnapshotManager::MapSourceDevice(LockedFile* lock, const std::string& name,
bool SnapshotManager::UnmapSnapshot(LockedFile* lock, const std::string& name) {
CHECK(lock);
- if (UpdateUsesUserSnapshots(lock)) {
- if (!UnmapUserspaceSnapshotDevice(lock, name)) {
- return false;
- }
- } else {
- if (!DeleteDeviceIfExists(name)) {
- LOG(ERROR) << "Could not delete snapshot device: " << name;
- return false;
- }
+ if (!DeleteDeviceIfExists(name)) {
+ LOG(ERROR) << "Could not delete snapshot device: " << name;
+ return false;
}
return true;
}
@@ -750,6 +652,7 @@ bool SnapshotManager::InitiateMerge() {
auto other_suffix = device_->GetOtherSlotSuffix();
+ auto& dm = DeviceMapper::Instance();
for (const auto& snapshot : snapshots) {
if (android::base::EndsWith(snapshot, other_suffix)) {
// Allow the merge to continue, but log this unexpected case.
@@ -761,7 +664,7 @@ bool SnapshotManager::InitiateMerge() {
// the same time. This is a fairly serious error. We could forcefully
// map everything here, but it should have been mapped during first-
// stage init.
- if (dm_.GetState(snapshot) == DmDeviceState::INVALID) {
+ if (dm.GetState(snapshot) == DmDeviceState::INVALID) {
LOG(ERROR) << "Cannot begin merge; device " << snapshot << " is not mapped.";
return false;
}
@@ -794,15 +697,13 @@ bool SnapshotManager::InitiateMerge() {
DmTargetSnapshot::Status initial_target_values = {};
for (const auto& snapshot : snapshots) {
- if (!UpdateUsesUserSnapshots(lock.get())) {
- DmTargetSnapshot::Status current_status;
- if (!QuerySnapshotStatus(snapshot, nullptr, &current_status)) {
- return false;
- }
- initial_target_values.sectors_allocated += current_status.sectors_allocated;
- initial_target_values.total_sectors += current_status.total_sectors;
- initial_target_values.metadata_sectors += current_status.metadata_sectors;
+ DmTargetSnapshot::Status current_status;
+ if (!QuerySnapshotStatus(snapshot, nullptr, &current_status)) {
+ return false;
}
+ initial_target_values.sectors_allocated += current_status.sectors_allocated;
+ initial_target_values.total_sectors += current_status.total_sectors;
+ initial_target_values.metadata_sectors += current_status.metadata_sectors;
SnapshotStatus snapshot_status;
if (!ReadSnapshotStatus(lock.get(), snapshot, &snapshot_status)) {
@@ -817,14 +718,11 @@ bool SnapshotManager::InitiateMerge() {
SnapshotUpdateStatus initial_status = ReadSnapshotUpdateStatus(lock.get());
initial_status.set_state(UpdateState::Merging);
+ initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
+ initial_status.set_total_sectors(initial_target_values.total_sectors);
+ initial_status.set_metadata_sectors(initial_target_values.metadata_sectors);
initial_status.set_compression_enabled(compression_enabled);
- if (!UpdateUsesUserSnapshots(lock.get())) {
- initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
- initial_status.set_total_sectors(initial_target_values.total_sectors);
- initial_status.set_metadata_sectors(initial_target_values.metadata_sectors);
- }
-
// If any partitions shrunk, we need to merge them before we merge any other
// partitions (see b/177935716). Otherwise, a merge from another partition
// may overwrite the source block of a copy operation.
@@ -878,36 +776,20 @@ MergeFailureCode SnapshotManager::SwitchSnapshotToMerge(LockedFile* lock, const
<< " has unexpected state: " << SnapshotState_Name(status.state());
}
- if (UpdateUsesUserSnapshots(lock)) {
- if (EnsureSnapuserdConnected()) {
- // This is the point where we inform the daemon to initiate/resume
- // the merge
- if (!snapuserd_client_->InitiateMerge(name)) {
- return MergeFailureCode::UnknownTable;
- }
- } else {
- LOG(ERROR) << "Failed to connect to snapuserd daemon to initiate merge";
- return MergeFailureCode::UnknownTable;
- }
- } else {
- // After this, we return true because we technically did switch to a merge
- // target. Everything else we do here is just informational.
- if (auto code = RewriteSnapshotDeviceTable(name); code != MergeFailureCode::Ok) {
- return code;
- }
+ // After this, we return true because we technically did switch to a merge
+ // target. Everything else we do here is just informational.
+ if (auto code = RewriteSnapshotDeviceTable(name); code != MergeFailureCode::Ok) {
+ return code;
}
status.set_state(SnapshotState::MERGING);
- if (!UpdateUsesUserSnapshots(lock)) {
- DmTargetSnapshot::Status dm_status;
- if (!QuerySnapshotStatus(name, nullptr, &dm_status)) {
- LOG(ERROR) << "Could not query merge status for snapshot: " << name;
- }
- status.set_sectors_allocated(dm_status.sectors_allocated);
- status.set_metadata_sectors(dm_status.metadata_sectors);
+ DmTargetSnapshot::Status dm_status;
+ if (!QuerySnapshotStatus(name, nullptr, &dm_status)) {
+ LOG(ERROR) << "Could not query merge status for snapshot: " << name;
}
-
+ status.set_sectors_allocated(dm_status.sectors_allocated);
+ status.set_metadata_sectors(dm_status.metadata_sectors);
if (!WriteSnapshotStatus(lock, status)) {
LOG(ERROR) << "Could not update status file for snapshot: " << name;
}
@@ -915,8 +797,10 @@ MergeFailureCode SnapshotManager::SwitchSnapshotToMerge(LockedFile* lock, const
}
MergeFailureCode SnapshotManager::RewriteSnapshotDeviceTable(const std::string& name) {
+ auto& dm = DeviceMapper::Instance();
+
std::vector<DeviceMapper::TargetInfo> old_targets;
- if (!dm_.GetTableInfo(name, &old_targets)) {
+ if (!dm.GetTableInfo(name, &old_targets)) {
LOG(ERROR) << "Could not read snapshot device table: " << name;
return MergeFailureCode::GetTableInfo;
}
@@ -934,7 +818,7 @@ MergeFailureCode SnapshotManager::RewriteSnapshotDeviceTable(const std::string&
DmTable table;
table.Emplace<DmTargetSnapshot>(0, old_targets[0].spec.length, base_device, cow_device,
SnapshotStorageMode::Merge, kSnapshotChunkSize);
- if (!dm_.LoadTableAndActivate(name, table)) {
+ if (!dm.LoadTableAndActivate(name, table)) {
LOG(ERROR) << "Could not swap device-mapper tables on snapshot device " << name;
return MergeFailureCode::ActivateNewTable;
}
@@ -942,18 +826,24 @@ MergeFailureCode SnapshotManager::RewriteSnapshotDeviceTable(const std::string&
return MergeFailureCode::Ok;
}
-bool SnapshotManager::GetSingleTarget(const std::string& dm_name, TableQuery query,
- DeviceMapper::TargetInfo* target) {
- if (dm_.GetState(dm_name) == DmDeviceState::INVALID) {
+enum class TableQuery {
+ Table,
+ Status,
+};
+
+static bool GetSingleTarget(const std::string& dm_name, TableQuery query,
+ DeviceMapper::TargetInfo* target) {
+ auto& dm = DeviceMapper::Instance();
+ if (dm.GetState(dm_name) == DmDeviceState::INVALID) {
return false;
}
std::vector<DeviceMapper::TargetInfo> targets;
bool result;
if (query == TableQuery::Status) {
- result = dm_.GetTableStatus(dm_name, &targets);
+ result = dm.GetTableStatus(dm_name, &targets);
} else {
- result = dm_.GetTableInfo(dm_name, &targets);
+ result = dm.GetTableInfo(dm_name, &targets);
}
if (!result) {
LOG(ERROR) << "Could not query device: " << dm_name;
@@ -973,15 +863,9 @@ bool SnapshotManager::IsSnapshotDevice(const std::string& dm_name, TargetInfo* t
return false;
}
auto type = DeviceMapper::GetTargetType(snap_target.spec);
-
- // If this is not a user-snapshot device then it should either
- // be a dm-snapshot or dm-snapshot-merge target
- if (type != "user") {
- if (type != "snapshot" && type != "snapshot-merge") {
- return false;
- }
+ if (type != "snapshot" && type != "snapshot-merge") {
+ return false;
}
-
if (target) {
*target = std::move(snap_target);
}
@@ -1002,10 +886,6 @@ bool SnapshotManager::QuerySnapshotStatus(const std::string& dm_name, std::strin
if (target_type) {
*target_type = DeviceMapper::GetTargetType(target.spec);
}
- if (!status->error.empty()) {
- LOG(ERROR) << "Snapshot: " << dm_name << " returned error code: " << status->error;
- return false;
- }
return true;
}
@@ -1217,87 +1097,35 @@ auto SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std::string&
DCHECK((current_metadata = ReadCurrentMetadata()) &&
GetMetadataPartitionState(*current_metadata, name) == MetadataPartitionState::Updated);
- if (UpdateUsesUserSnapshots(lock)) {
- std::string merge_status;
- if (EnsureSnapuserdConnected()) {
- // Query the snapshot status from the daemon
- merge_status = snapuserd_client_->QuerySnapshotStatus(name);
- } else {
- MergeResult(UpdateState::MergeFailed, MergeFailureCode::QuerySnapshotStatus);
- }
-
- if (merge_status == "snapshot-merge-failed") {
- return MergeResult(UpdateState::MergeFailed, MergeFailureCode::UnknownTargetType);
- }
-
- // This is the case when device reboots during merge. Once the device boots,
- // snapuserd daemon will not resume merge immediately in first stage init.
- // This is slightly different as compared to dm-snapshot-merge; In this
- // case, metadata file will have "MERGING" state whereas the daemon will be
- // waiting to resume the merge. Thus, we resume the merge at this point.
- if (merge_status == "snapshot" && snapshot_status.state() == SnapshotState::MERGING) {
- if (!snapuserd_client_->InitiateMerge(name)) {
- return MergeResult(UpdateState::MergeFailed, MergeFailureCode::UnknownTargetType);
- }
- return MergeResult(UpdateState::Merging);
- }
-
- if (merge_status == "snapshot" &&
- DecideMergePhase(snapshot_status) == MergePhase::SECOND_PHASE &&
- update_status.merge_phase() == MergePhase::FIRST_PHASE) {
- // The snapshot is not being merged because it's in the wrong phase.
- return MergeResult(UpdateState::None);
- }
-
- if (merge_status == "snapshot-merge") {
- if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
- LOG(ERROR) << "Snapshot " << name
- << " is merging after being marked merge-complete.";
- return MergeResult(UpdateState::MergeFailed,
- MergeFailureCode::UnmergedSectorsAfterCompletion);
- }
- return MergeResult(UpdateState::Merging);
- }
-
- if (merge_status != "snapshot-merge-complete") {
- LOG(ERROR) << "Snapshot " << name << " has incorrect status: " << merge_status;
- return MergeResult(UpdateState::MergeFailed, MergeFailureCode::ExpectedMergeTarget);
- }
- } else {
- // dm-snapshot in the kernel
- std::string target_type;
- DmTargetSnapshot::Status status;
- if (!QuerySnapshotStatus(name, &target_type, &status)) {
- return MergeResult(UpdateState::MergeFailed, MergeFailureCode::QuerySnapshotStatus);
- }
- if (target_type == "snapshot" &&
- DecideMergePhase(snapshot_status) == MergePhase::SECOND_PHASE &&
- update_status.merge_phase() == MergePhase::FIRST_PHASE) {
- // The snapshot is not being merged because it's in the wrong phase.
- return MergeResult(UpdateState::None);
- }
- if (target_type != "snapshot-merge") {
- // We can get here if we failed to rewrite the target type in
- // InitiateMerge(). If we failed to create the target in first-stage
- // init, boot would not succeed.
- LOG(ERROR) << "Snapshot " << name << " has incorrect target type: " << target_type;
- return MergeResult(UpdateState::MergeFailed, MergeFailureCode::ExpectedMergeTarget);
- }
+ std::string target_type;
+ DmTargetSnapshot::Status status;
+ if (!QuerySnapshotStatus(name, &target_type, &status)) {
+ return MergeResult(UpdateState::MergeFailed, MergeFailureCode::QuerySnapshotStatus);
+ }
+ if (target_type == "snapshot" &&
+ DecideMergePhase(snapshot_status) == MergePhase::SECOND_PHASE &&
+ update_status.merge_phase() == MergePhase::FIRST_PHASE) {
+ // The snapshot is not being merged because it's in the wrong phase.
+ return MergeResult(UpdateState::None);
+ }
+ if (target_type != "snapshot-merge") {
+ // We can get here if we failed to rewrite the target type in
+ // InitiateMerge(). If we failed to create the target in first-stage
+ // init, boot would not succeed.
+ LOG(ERROR) << "Snapshot " << name << " has incorrect target type: " << target_type;
+ return MergeResult(UpdateState::MergeFailed, MergeFailureCode::ExpectedMergeTarget);
+ }
- // These two values are equal when merging is complete.
- if (status.sectors_allocated != status.metadata_sectors) {
- if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
- LOG(ERROR) << "Snapshot " << name
- << " is merging after being marked merge-complete.";
- return MergeResult(UpdateState::MergeFailed,
- MergeFailureCode::UnmergedSectorsAfterCompletion);
- }
- return MergeResult(UpdateState::Merging);
+ // These two values are equal when merging is complete.
+ if (status.sectors_allocated != status.metadata_sectors) {
+ if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
+ LOG(ERROR) << "Snapshot " << name << " is merging after being marked merge-complete.";
+ return MergeResult(UpdateState::MergeFailed,
+ MergeFailureCode::UnmergedSectorsAfterCompletion);
}
+ return MergeResult(UpdateState::Merging);
}
- // Merge is complete at this point
-
auto code = CheckMergeConsistency(lock, name, snapshot_status);
if (code != MergeFailureCode::Ok) {
return MergeResult(UpdateState::MergeFailed, code);
@@ -1336,10 +1164,6 @@ MergeFailureCode SnapshotManager::CheckMergeConsistency(LockedFile* lock, const
const SnapshotStatus& status) {
CHECK(lock);
- return merge_consistency_checker_(name, status);
-}
-
-MergeFailureCode CheckMergeConsistency(const std::string& name, const SnapshotStatus& status) {
if (!status.compression_enabled()) {
// Do not try to verify old-style COWs yet.
return MergeFailureCode::Ok;
@@ -1369,7 +1193,11 @@ MergeFailureCode CheckMergeConsistency(const std::string& name, const SnapshotSt
return MergeFailureCode::ParseCowConsistencyCheck;
}
- num_ops = reader.get_num_total_data_ops();
+ for (auto iter = reader.GetOpIter(); !iter->Done(); iter->Next()) {
+ if (!IsMetadataOp(iter->Get())) {
+ num_ops++;
+ }
+ }
}
// Second pass, try as hard as we can to get the actual number of blocks
@@ -1413,11 +1241,9 @@ MergeFailureCode SnapshotManager::MergeSecondPhaseSnapshots(LockedFile* lock) {
}
SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
- CHECK(update_status.state() == UpdateState::Merging ||
- update_status.state() == UpdateState::MergeFailed);
+ CHECK(update_status.state() == UpdateState::Merging);
CHECK(update_status.merge_phase() == MergePhase::FIRST_PHASE);
- update_status.set_state(UpdateState::Merging);
update_status.set_merge_phase(MergePhase::SECOND_PHASE);
if (!WriteSnapshotUpdateStatus(lock, update_status)) {
return MergeFailureCode::WriteStatus;
@@ -1470,14 +1296,6 @@ void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
}
RemoveAllUpdateState(lock);
-
- if (UpdateUsesUserSnapshots(lock) && !device()->IsTestDevice()) {
- if (snapuserd_client_) {
- snapuserd_client_->DetachSnapuserd();
- snapuserd_client_->CloseConnection();
- snapuserd_client_ = nullptr;
- }
- }
}
void SnapshotManager::AcknowledgeMergeFailure(MergeFailureCode failure_code) {
@@ -1502,40 +1320,30 @@ void SnapshotManager::AcknowledgeMergeFailure(MergeFailureCode failure_code) {
bool SnapshotManager::OnSnapshotMergeComplete(LockedFile* lock, const std::string& name,
const SnapshotStatus& status) {
- if (!UpdateUsesUserSnapshots(lock)) {
- if (IsSnapshotDevice(name)) {
- // We are extra-cautious here, to avoid deleting the wrong table.
- std::string target_type;
- DmTargetSnapshot::Status dm_status;
- if (!QuerySnapshotStatus(name, &target_type, &dm_status)) {
- return false;
- }
- if (target_type != "snapshot-merge") {
- LOG(ERROR) << "Unexpected target type " << target_type
- << " for snapshot device: " << name;
- return false;
- }
- if (dm_status.sectors_allocated != dm_status.metadata_sectors) {
- LOG(ERROR) << "Merge is unexpectedly incomplete for device " << name;
- return false;
- }
- if (!CollapseSnapshotDevice(lock, name, status)) {
- LOG(ERROR) << "Unable to collapse snapshot: " << name;
- return false;
- }
+ if (IsSnapshotDevice(name)) {
+ // We are extra-cautious here, to avoid deleting the wrong table.
+ std::string target_type;
+ DmTargetSnapshot::Status dm_status;
+ if (!QuerySnapshotStatus(name, &target_type, &dm_status)) {
+ return false;
}
- } else {
- // Just collapse the device - no need to query again as we just did
- // prior to calling this function
- if (!CollapseSnapshotDevice(lock, name, status)) {
+ if (target_type != "snapshot-merge") {
+ LOG(ERROR) << "Unexpected target type " << target_type
+ << " for snapshot device: " << name;
+ return false;
+ }
+ if (dm_status.sectors_allocated != dm_status.metadata_sectors) {
+ LOG(ERROR) << "Merge is unexpectedly incomplete for device " << name;
+ return false;
+ }
+ if (!CollapseSnapshotDevice(name, status)) {
LOG(ERROR) << "Unable to collapse snapshot: " << name;
return false;
}
+ // Note that collapsing is implicitly an Unmap, so we don't need to
+ // unmap the snapshot.
}
- // Note that collapsing is implicitly an Unmap, so we don't need to
- // unmap the snapshot.
-
if (!DeleteSnapshot(lock, name)) {
LOG(ERROR) << "Could not delete snapshot: " << name;
return false;
@@ -1543,26 +1351,25 @@ bool SnapshotManager::OnSnapshotMergeComplete(LockedFile* lock, const std::strin
return true;
}
-bool SnapshotManager::CollapseSnapshotDevice(LockedFile* lock, const std::string& name,
+bool SnapshotManager::CollapseSnapshotDevice(const std::string& name,
const SnapshotStatus& status) {
- if (!UpdateUsesUserSnapshots(lock)) {
- // Verify we have a snapshot-merge device.
- DeviceMapper::TargetInfo target;
- if (!GetSingleTarget(name, TableQuery::Table, &target)) {
- return false;
- }
- if (DeviceMapper::GetTargetType(target.spec) != "snapshot-merge") {
- // This should be impossible, it was checked earlier.
- LOG(ERROR) << "Snapshot device has invalid target type: " << name;
- return false;
- }
+ auto& dm = DeviceMapper::Instance();
- std::string base_device, cow_device;
- if (!DmTargetSnapshot::GetDevicesFromParams(target.data, &base_device, &cow_device)) {
- LOG(ERROR) << "Could not parse snapshot device " << name
- << " parameters: " << target.data;
- return false;
- }
+ // Verify we have a snapshot-merge device.
+ DeviceMapper::TargetInfo target;
+ if (!GetSingleTarget(name, TableQuery::Table, &target)) {
+ return false;
+ }
+ if (DeviceMapper::GetTargetType(target.spec) != "snapshot-merge") {
+ // This should be impossible, it was checked earlier.
+ LOG(ERROR) << "Snapshot device has invalid target type: " << name;
+ return false;
+ }
+
+ std::string base_device, cow_device;
+ if (!DmTargetSnapshot::GetDevicesFromParams(target.data, &base_device, &cow_device)) {
+ LOG(ERROR) << "Could not parse snapshot device " << name << " parameters: " << target.data;
+ return false;
}
uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
@@ -1586,36 +1393,18 @@ bool SnapshotManager::CollapseSnapshotDevice(LockedFile* lock, const std::string
return false;
}
- if (!dm_.LoadTableAndActivate(name, table)) {
+ if (!dm.LoadTableAndActivate(name, table)) {
return false;
}
- if (!UpdateUsesUserSnapshots(lock)) {
- // Attempt to delete the snapshot device if one still exists. Nothing
- // should be depending on the device, and device-mapper should have
- // flushed remaining I/O. We could in theory replace with dm-zero (or
- // re-use the table above), but for now it's better to know why this
- // would fail.
- //
- // Furthermore, we should not be trying to unmap for userspace snapshot
- // as unmap will fail since dm-user itself was a snapshot device prior
- // to switching of tables. Unmap will fail as the device will be mounted
- // by system partitions
- if (status.compression_enabled()) {
- auto dm_user_name = GetDmUserCowName(name, GetSnapshotDriver(lock));
- UnmapDmUserDevice(dm_user_name);
- }
- }
-
- // We can't delete base device immediately as daemon holds a reference.
- // Make sure we wait for all the worker threads to terminate and release
- // the reference
- if (UpdateUsesUserSnapshots(lock) && EnsureSnapuserdConnected()) {
- if (!snapuserd_client_->WaitForDeviceDelete(name)) {
- LOG(ERROR) << "Failed to wait for " << name << " control device to delete";
- }
+ // Attempt to delete the snapshot device if one still exists. Nothing
+ // should be depending on the device, and device-mapper should have
+ // flushed remaining I/O. We could in theory replace with dm-zero (or
+ // re-use the table above), but for now it's better to know why this
+ // would fail.
+ if (status.compression_enabled()) {
+ UnmapDmUserDevice(name);
}
-
auto base_name = GetBaseDeviceName(name);
if (!DeleteDeviceIfExists(base_name)) {
LOG(ERROR) << "Unable to delete base device for snapshot: " << base_name;
@@ -1667,7 +1456,7 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition,
std::vector<std::string>* snapuserd_argv) {
LOG(INFO) << "Performing transition for snapuserd.";
- // Don't use EnsureSnapuserdConnected() because this is called from init,
+ // Don't use EnsuerSnapuserdConnected() because this is called from init,
// and attempting to do so will deadlock.
if (!snapuserd_client_ && transition != InitTransition::SELINUX_DETACH) {
snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, 10s);
@@ -1677,6 +1466,8 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition,
}
}
+ auto& dm = DeviceMapper::Instance();
+
auto lock = LockExclusive();
if (!lock) return false;
@@ -1686,19 +1477,11 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition,
return false;
}
- if (UpdateUsesUserSnapshots(lock.get()) && transition == InitTransition::SELINUX_DETACH) {
- snapuserd_argv->emplace_back("-user_snapshot");
- if (UpdateUsesIouring(lock.get())) {
- snapuserd_argv->emplace_back("-io_uring");
- }
- }
-
size_t num_cows = 0;
size_t ok_cows = 0;
for (const auto& snapshot : snapshots) {
- std::string user_cow_name = GetDmUserCowName(snapshot, GetSnapshotDriver(lock.get()));
-
- if (dm_.GetState(user_cow_name) == DmDeviceState::INVALID) {
+ std::string user_cow_name = GetDmUserCowName(snapshot);
+ if (dm.GetState(user_cow_name) == DmDeviceState::INVALID) {
continue;
}
@@ -1725,26 +1508,13 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition,
DmTable table;
table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
- if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
+ if (!dm.LoadTableAndActivate(user_cow_name, table)) {
LOG(ERROR) << "Unable to swap tables for " << misc_name;
continue;
}
- std::string source_device_name;
- if (snapshot_status.old_partition_size() > 0) {
- source_device_name = GetSourceDeviceName(snapshot);
- } else {
- source_device_name = GetBaseDeviceName(snapshot);
- }
-
std::string source_device;
- if (!dm_.GetDmDevicePathByName(source_device_name, &source_device)) {
- LOG(ERROR) << "Could not get device path for " << GetSourceDeviceName(snapshot);
- continue;
- }
-
- std::string base_path_merge;
- if (!dm_.GetDmDevicePathByName(GetBaseDeviceName(snapshot), &base_path_merge)) {
+ if (!dm.GetDmDevicePathByName(GetSourceDeviceName(snapshot), &source_device)) {
LOG(ERROR) << "Could not get device path for " << GetSourceDeviceName(snapshot);
continue;
}
@@ -1752,7 +1522,7 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition,
std::string cow_image_name = GetMappedCowDeviceName(snapshot, snapshot_status);
std::string cow_image_device;
- if (!dm_.GetDmDevicePathByName(cow_image_name, &cow_image_device)) {
+ if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_device)) {
LOG(ERROR) << "Could not get device path for " << cow_image_name;
continue;
}
@@ -1765,14 +1535,8 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition,
}
if (transition == InitTransition::SELINUX_DETACH) {
- if (!UpdateUsesUserSnapshots(lock.get())) {
- auto message = misc_name + "," + cow_image_device + "," + source_device;
- snapuserd_argv->emplace_back(std::move(message));
- } else {
- auto message = misc_name + "," + cow_image_device + "," + source_device + "," +
- base_path_merge;
- snapuserd_argv->emplace_back(std::move(message));
- }
+ auto message = misc_name + "," + cow_image_device + "," + source_device;
+ snapuserd_argv->emplace_back(std::move(message));
// Do not attempt to connect to the new snapuserd yet, it hasn't
// been started. We do however want to wait for the misc device
@@ -1781,15 +1545,8 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition,
continue;
}
- uint64_t base_sectors;
- if (!UpdateUsesUserSnapshots(lock.get())) {
- base_sectors =
- snapuserd_client_->InitDmUserCow(misc_name, cow_image_device, source_device);
- } else {
- base_sectors = snapuserd_client_->InitDmUserCow(misc_name, cow_image_device,
- source_device, base_path_merge);
- }
-
+ uint64_t base_sectors =
+ snapuserd_client_->InitDmUserCow(misc_name, cow_image_device, source_device);
if (base_sectors == 0) {
// Unrecoverable as metadata reads from cow device failed
LOG(FATAL) << "Failed to retrieve base_sectors from Snapuserd";
@@ -1906,33 +1663,6 @@ bool SnapshotManager::GetSnapshotFlashingStatus(LockedFile* lock,
return true;
}
-void SnapshotManager::RemoveInvalidSnapshots(LockedFile* lock) {
- std::vector<std::string> snapshots;
-
- // Remove the stale snapshot metadata
- //
- // We make sure that all the three cases
- // are valid before removing the snapshot metadata:
- //
- // 1: dm state is active
- // 2: Root fs is not mounted off as a snapshot device
- // 3: Snapshot slot suffix should match current device slot
- if (!ListSnapshots(lock, &snapshots, device_->GetSlotSuffix()) || snapshots.empty()) {
- return;
- }
-
- // We indeed have some invalid snapshots
- for (const auto& name : snapshots) {
- if (dm_.GetState(name) == DmDeviceState::ACTIVE && !IsSnapshotDevice(name)) {
- if (!DeleteSnapshot(lock, name)) {
- LOG(ERROR) << "Failed to delete invalid snapshot: " << name;
- } else {
- LOG(INFO) << "Invalid snapshot: " << name << " deleted";
- }
- }
- }
-}
-
bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) {
std::vector<std::string> snapshots;
if (!ListSnapshots(lock, &snapshots)) {
@@ -1967,7 +1697,8 @@ bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) {
// snapshot, but it's on the wrong slot. We can't unmap an active
// partition. If this is not really a snapshot, skip the unmap
// step.
- if (dm_.GetState(name) == DmDeviceState::INVALID || !IsSnapshotDevice(name)) {
+ auto& dm = DeviceMapper::Instance();
+ if (dm.GetState(name) == DmDeviceState::INVALID || !IsSnapshotDevice(name)) {
LOG(ERROR) << "Detected snapshot " << name << " on " << current_slot << " slot"
<< " for source partition; removing without unmap.";
should_unmap = false;
@@ -2051,36 +1782,30 @@ UpdateState SnapshotManager::GetUpdateState(double* progress) {
return state;
}
- if (!UpdateUsesUserSnapshots(lock.get())) {
- // Sum all the snapshot states as if the system consists of a single huge
- // snapshots device, then compute the merge completion percentage of that
- // device.
- std::vector<std::string> snapshots;
- if (!ListSnapshots(lock.get(), &snapshots)) {
- LOG(ERROR) << "Could not list snapshots";
- return state;
- }
-
- DmTargetSnapshot::Status fake_snapshots_status = {};
- for (const auto& snapshot : snapshots) {
- DmTargetSnapshot::Status current_status;
+ // Sum all the snapshot states as if the system consists of a single huge
+ // snapshots device, then compute the merge completion percentage of that
+ // device.
+ std::vector<std::string> snapshots;
+ if (!ListSnapshots(lock.get(), &snapshots)) {
+ LOG(ERROR) << "Could not list snapshots";
+ return state;
+ }
- if (!IsSnapshotDevice(snapshot)) continue;
- if (!QuerySnapshotStatus(snapshot, nullptr, &current_status)) continue;
+ DmTargetSnapshot::Status fake_snapshots_status = {};
+ for (const auto& snapshot : snapshots) {
+ DmTargetSnapshot::Status current_status;
- fake_snapshots_status.sectors_allocated += current_status.sectors_allocated;
- fake_snapshots_status.total_sectors += current_status.total_sectors;
- fake_snapshots_status.metadata_sectors += current_status.metadata_sectors;
- }
+ if (!IsSnapshotDevice(snapshot)) continue;
+ if (!QuerySnapshotStatus(snapshot, nullptr, &current_status)) continue;
- *progress = DmTargetSnapshot::MergePercent(fake_snapshots_status,
- update_status.sectors_allocated());
- } else {
- if (EnsureSnapuserdConnected()) {
- *progress = snapuserd_client_->GetMergePercent();
- }
+ fake_snapshots_status.sectors_allocated += current_status.sectors_allocated;
+ fake_snapshots_status.total_sectors += current_status.total_sectors;
+ fake_snapshots_status.metadata_sectors += current_status.metadata_sectors;
}
+ *progress = DmTargetSnapshot::MergePercent(fake_snapshots_status,
+ update_status.sectors_allocated());
+
return state;
}
@@ -2095,43 +1820,6 @@ bool SnapshotManager::UpdateUsesCompression(LockedFile* lock) {
return update_status.compression_enabled();
}
-bool SnapshotManager::UpdateUsesIouring(LockedFile* lock) {
- SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
- return update_status.io_uring_enabled();
-}
-
-bool SnapshotManager::UpdateUsesUserSnapshots() {
- // This and the following function is constantly
- // invoked during snapshot merge. We want to avoid
- // constantly reading from disk. Hence, store this
- // value in memory.
- //
- // Furthermore, this value in the disk is set
- // only when OTA is applied and doesn't change
- // during merge phase. Hence, once we know that
- // the value is read from disk the very first time,
- // it is safe to read successive checks from memory.
- if (is_snapshot_userspace_.has_value()) {
- return is_snapshot_userspace_.value();
- }
-
- auto lock = LockShared();
- if (!lock) return false;
-
- return UpdateUsesUserSnapshots(lock.get());
-}
-
-bool SnapshotManager::UpdateUsesUserSnapshots(LockedFile* lock) {
- // See UpdateUsesUserSnapshots()
- if (is_snapshot_userspace_.has_value()) {
- return is_snapshot_userspace_.value();
- }
-
- SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
- is_snapshot_userspace_ = update_status.userspace_snapshots();
- return is_snapshot_userspace_.value();
-}
-
bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots,
const std::string& suffix) {
CHECK(lock);
@@ -2347,28 +2035,19 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
// Create the base device for the snapshot, or if there is no snapshot, the
// device itself. This device consists of the real blocks in the super
// partition that this logical partition occupies.
+ auto& dm = DeviceMapper::Instance();
std::string base_path;
if (!CreateLogicalPartition(params, &base_path)) {
LOG(ERROR) << "Could not create logical partition " << params.GetPartitionName()
<< " as device " << params.GetDeviceName();
return false;
}
- created_devices.EmplaceBack<AutoUnmapDevice>(&dm_, params.GetDeviceName());
+ created_devices.EmplaceBack<AutoUnmapDevice>(&dm, params.GetDeviceName());
if (paths) {
paths->target_device = base_path;
}
- auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
- if (remaining_time.count() < 0) {
- return false;
- }
-
- // Wait for the base device to appear
- if (!WaitForDevice(base_path, remaining_time)) {
- return false;
- }
-
if (!live_snapshot_status.has_value()) {
created_devices.Release();
return true;
@@ -2377,12 +2056,12 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
// We don't have ueventd in first-stage init, so use device major:minor
// strings instead.
std::string base_device;
- if (!dm_.GetDeviceString(params.GetDeviceName(), &base_device)) {
+ if (!dm.GetDeviceString(params.GetDeviceName(), &base_device)) {
LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName();
return false;
}
- remaining_time = GetRemainingTime(params.timeout_ms, begin);
+ auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
std::string cow_name;
@@ -2412,19 +2091,15 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
if (live_snapshot_status->compression_enabled()) {
// Get the source device (eg the view of the partition from before it was resized).
std::string source_device_path;
- if (live_snapshot_status->old_partition_size() > 0) {
- if (!MapSourceDevice(lock, params.GetPartitionName(), remaining_time,
- &source_device_path)) {
- LOG(ERROR) << "Could not map source device for: " << cow_name;
- return false;
- }
-
- auto source_device = GetSourceDeviceName(params.GetPartitionName());
- created_devices.EmplaceBack<AutoUnmapDevice>(&dm_, source_device);
- } else {
- source_device_path = base_path;
+ if (!MapSourceDevice(lock, params.GetPartitionName(), remaining_time,
+ &source_device_path)) {
+ LOG(ERROR) << "Could not map source device for: " << cow_name;
+ return false;
}
+ auto source_device = GetSourceDeviceName(params.GetPartitionName());
+ created_devices.EmplaceBack<AutoUnmapDevice>(&dm, source_device);
+
if (!WaitForDevice(source_device_path, remaining_time)) {
return false;
}
@@ -2438,16 +2113,16 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
return false;
}
- auto name = GetDmUserCowName(params.GetPartitionName(), GetSnapshotDriver(lock));
+ auto name = GetDmUserCowName(params.GetPartitionName());
std::string new_cow_device;
- if (!MapDmUserCow(lock, name, cow_path, source_device_path, base_path, remaining_time,
+ if (!MapDmUserCow(lock, name, cow_path, source_device_path, remaining_time,
&new_cow_device)) {
LOG(ERROR) << "Could not map dm-user device for partition "
<< params.GetPartitionName();
return false;
}
- created_devices.EmplaceBack<AutoUnmapDevice>(&dm_, name);
+ created_devices.EmplaceBack<AutoUnmapDevice>(&dm, name);
remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
@@ -2455,37 +2130,21 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
cow_device = new_cow_device;
}
- // For userspace snapshots, dm-user block device itself will act as a
- // snapshot device. There is one subtle difference - MapSnapshot will create
- // either snapshot target or snapshot-merge target based on the underlying
- // state of the snapshot device. If snapshot-merge target is created, merge
- // will immediately start in the kernel.
- //
- // This is no longer true with respect to userspace snapshots. When dm-user
- // block device is created, we just have the snapshots ready but daemon in
- // the user-space will not start the merge. We have to explicitly inform the
- // daemon to resume the merge. Check ProcessUpdateState() call stack.
- if (!UpdateUsesUserSnapshots(lock)) {
- std::string path;
- if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
- &path)) {
- LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
- return false;
- }
- // No need to add params.GetPartitionName() to created_devices since it is immediately
- // released.
+ std::string path;
+ if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
+ &path)) {
+ LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
+ return false;
+ }
+ // No need to add params.GetPartitionName() to created_devices since it is immediately released.
- if (paths) {
- paths->snapshot_device = path;
- }
- LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << path;
- } else {
- LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at "
- << cow_device;
+ if (paths) {
+ paths->snapshot_device = path;
}
created_devices.Release();
+ LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << path;
return true;
}
@@ -2529,6 +2188,8 @@ bool SnapshotManager::MapCowDevices(LockedFile* lock, const CreateLogicalPartiti
std::string cow_image_name = GetCowImageDeviceName(partition_name);
*cow_name = GetCowName(partition_name);
+ auto& dm = DeviceMapper::Instance();
+
// Map COW image if necessary.
if (snapshot_status.cow_file_size() > 0) {
if (!EnsureImageManager()) return false;
@@ -2579,11 +2240,11 @@ bool SnapshotManager::MapCowDevices(LockedFile* lock, const CreateLogicalPartiti
// We have created the DmTable now. Map it.
std::string cow_path;
- if (!dm_.CreateDevice(*cow_name, table, &cow_path, remaining_time)) {
+ if (!dm.CreateDevice(*cow_name, table, &cow_path, remaining_time)) {
LOG(ERROR) << "Could not create COW device: " << *cow_name;
return false;
}
- created_devices->EmplaceBack<AutoUnmapDevice>(&dm_, *cow_name);
+ created_devices->EmplaceBack<AutoUnmapDevice>(&dm, *cow_name);
LOG(INFO) << "Mapped COW device for " << params.GetPartitionName() << " at " << cow_path;
return true;
}
@@ -2592,11 +2253,8 @@ bool SnapshotManager::UnmapCowDevices(LockedFile* lock, const std::string& name)
CHECK(lock);
if (!EnsureImageManager()) return false;
- if (UpdateUsesCompression(lock) && !UpdateUsesUserSnapshots(lock)) {
- auto dm_user_name = GetDmUserCowName(name, GetSnapshotDriver(lock));
- if (!UnmapDmUserDevice(dm_user_name)) {
- return false;
- }
+ if (UpdateUsesCompression(lock) && !UnmapDmUserDevice(name)) {
+ return false;
}
if (!DeleteDeviceIfExists(GetCowName(name), 4000ms)) {
@@ -2612,8 +2270,11 @@ bool SnapshotManager::UnmapCowDevices(LockedFile* lock, const std::string& name)
return true;
}
-bool SnapshotManager::UnmapDmUserDevice(const std::string& dm_user_name) {
- if (dm_.GetState(dm_user_name) == DmDeviceState::INVALID) {
+bool SnapshotManager::UnmapDmUserDevice(const std::string& snapshot_name) {
+ auto& dm = DeviceMapper::Instance();
+
+ auto dm_user_name = GetDmUserCowName(snapshot_name);
+ if (dm.GetState(dm_user_name) == DmDeviceState::INVALID) {
return true;
}
@@ -2638,46 +2299,6 @@ bool SnapshotManager::UnmapDmUserDevice(const std::string& dm_user_name) {
return true;
}
-bool SnapshotManager::UnmapUserspaceSnapshotDevice(LockedFile* lock,
- const std::string& snapshot_name) {
- auto dm_user_name = GetDmUserCowName(snapshot_name, GetSnapshotDriver(lock));
- if (dm_.GetState(dm_user_name) == DmDeviceState::INVALID) {
- return true;
- }
-
- CHECK(lock);
-
- SnapshotStatus snapshot_status;
-
- if (!ReadSnapshotStatus(lock, snapshot_name, &snapshot_status)) {
- return false;
- }
- // If the merge is complete, then we switch dm tables which is equivalent
- // to unmap; hence, we can't be deleting the device
- // as the table would be mounted off partitions and will fail.
- if (snapshot_status.state() != SnapshotState::MERGE_COMPLETED) {
- if (!DeleteDeviceIfExists(dm_user_name)) {
- LOG(ERROR) << "Cannot unmap " << dm_user_name;
- return false;
- }
- }
-
- if (EnsureSnapuserdConnected()) {
- if (!snapuserd_client_->WaitForDeviceDelete(dm_user_name)) {
- LOG(ERROR) << "Failed to wait for " << dm_user_name << " control device to delete";
- return false;
- }
- }
-
- // Ensure the control device is gone so we don't run into ABA problems.
- auto control_device = "/dev/dm-user/" + dm_user_name;
- if (!android::fs_mgr::WaitForFileDeleted(control_device, 10s)) {
- LOG(ERROR) << "Timed out waiting for " << control_device << " to unlink";
- return false;
- }
- return true;
-}
-
bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds& timeout_ms) {
auto lock = LockExclusive();
if (!lock) return false;
@@ -2913,9 +2534,6 @@ bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state,
SnapshotUpdateStatus old_status = ReadSnapshotUpdateStatus(lock);
status.set_compression_enabled(old_status.compression_enabled());
status.set_source_build_fingerprint(old_status.source_build_fingerprint());
- status.set_merge_phase(old_status.merge_phase());
- status.set_userspace_snapshots(old_status.userspace_snapshots());
- status.set_io_uring_enabled(old_status.io_uring_enabled());
}
return WriteSnapshotUpdateStatus(lock, status);
}
@@ -3233,56 +2851,6 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
SnapshotUpdateStatus status = ReadSnapshotUpdateStatus(lock.get());
status.set_state(update_state);
status.set_compression_enabled(cow_creator.compression_enabled);
- if (cow_creator.compression_enabled) {
- if (!device()->IsTestDevice()) {
- bool userSnapshotsEnabled = IsUserspaceSnapshotsEnabled();
- const std::string UNKNOWN = "unknown";
- const std::string vendor_release = android::base::GetProperty(
- "ro.vendor.build.version.release_or_codename", UNKNOWN);
-
- // No user-space snapshots if vendor partition is on Android 12
- if (vendor_release.find("12") != std::string::npos) {
- LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
- << vendor_release;
- userSnapshotsEnabled = false;
- }
-
- // Userspace snapshots is enabled only if compression is enabled
- status.set_userspace_snapshots(userSnapshotsEnabled);
- if (userSnapshotsEnabled) {
- is_snapshot_userspace_ = true;
- status.set_io_uring_enabled(IsIouringEnabled());
- LOG(INFO) << "Userspace snapshots enabled";
- } else {
- is_snapshot_userspace_ = false;
- LOG(INFO) << "Userspace snapshots disabled";
- }
-
- // Terminate stale daemon if any
- std::unique_ptr<SnapuserdClient> snapuserd_client =
- SnapuserdClient::Connect(kSnapuserdSocket, 5s);
- if (snapuserd_client) {
- snapuserd_client->DetachSnapuserd();
- snapuserd_client->CloseConnection();
- snapuserd_client = nullptr;
- }
-
- // Clear the cached client if any
- if (snapuserd_client_) {
- snapuserd_client_->CloseConnection();
- snapuserd_client_ = nullptr;
- }
- } else {
- status.set_userspace_snapshots(!IsDmSnapshotTestingEnabled());
- if (IsDmSnapshotTestingEnabled()) {
- is_snapshot_userspace_ = false;
- LOG(INFO) << "User-space snapshots disabled for testing";
- } else {
- is_snapshot_userspace_ = true;
- LOG(INFO) << "User-space snapshots enabled for testing";
- }
- }
- }
if (!WriteSnapshotUpdateStatus(lock.get(), status)) {
LOG(ERROR) << "Unable to write new update state";
return Return::Error();
@@ -3925,6 +3493,7 @@ bool SnapshotManager::EnsureNoOverflowSnapshot(LockedFile* lock) {
return false;
}
+ auto& dm = DeviceMapper::Instance();
for (const auto& snapshot : snapshots) {
SnapshotStatus status;
if (!ReadSnapshotStatus(lock, snapshot, &status)) {
@@ -3935,7 +3504,7 @@ bool SnapshotManager::EnsureNoOverflowSnapshot(LockedFile* lock) {
}
std::vector<DeviceMapper::TargetInfo> targets;
- if (!dm_.GetTableStatus(snapshot, &targets)) {
+ if (!dm.GetTableStatus(snapshot, &targets)) {
LOG(ERROR) << "Could not read snapshot device table: " << snapshot;
return false;
}
@@ -4028,9 +3597,11 @@ ISnapshotMergeStats* SnapshotManager::GetSnapshotMergeStatsInstance() {
// isn't running yet.
bool SnapshotManager::GetMappedImageDevicePath(const std::string& device_name,
std::string* device_path) {
+ auto& dm = DeviceMapper::Instance();
+
// Try getting the device string if it is a device mapper device.
- if (dm_.GetState(device_name) != DmDeviceState::INVALID) {
- return dm_.GetDmDevicePathByName(device_name, device_path);
+ if (dm.GetState(device_name) != DmDeviceState::INVALID) {
+ return dm.GetDmDevicePathByName(device_name, device_path);
}
// Otherwise, get path from IImageManager.
@@ -4039,9 +3610,10 @@ bool SnapshotManager::GetMappedImageDevicePath(const std::string& device_name,
bool SnapshotManager::GetMappedImageDeviceStringOrPath(const std::string& device_name,
std::string* device_string_or_mapped_path) {
+ auto& dm = DeviceMapper::Instance();
// Try getting the device string if it is a device mapper device.
- if (dm_.GetState(device_name) != DmDeviceState::INVALID) {
- return dm_.GetDeviceString(device_name, device_string_or_mapped_path);
+ if (dm.GetState(device_name) != DmDeviceState::INVALID) {
+ return dm.GetDeviceString(device_name, device_string_or_mapped_path);
}
// Otherwise, get path from IImageManager.
@@ -4157,9 +3729,10 @@ void SnapshotManager::UpdateCowStats(ISnapshotMergeStats* stats) {
bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
const std::chrono::milliseconds& timeout_ms) {
+ auto& dm = DeviceMapper::Instance();
auto start = std::chrono::steady_clock::now();
while (true) {
- if (dm_.DeleteDeviceIfExists(name)) {
+ if (dm.DeleteDeviceIfExists(name)) {
return true;
}
auto now = std::chrono::steady_clock::now();
@@ -4172,7 +3745,7 @@ bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
// Try to diagnose why this failed. First get the actual device path.
std::string full_path;
- if (!dm_.GetDmDevicePathByName(name, &full_path)) {
+ if (!dm.GetDmDevicePathByName(name, &full_path)) {
LOG(ERROR) << "Unable to diagnose DM_DEV_REMOVE failure.";
return false;
}
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
index 54c6a0053..0096f85f8 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
@@ -139,7 +139,7 @@ std::vector<DeviceMapper::TargetInfo> GetTableInfoIfExists(const std::string& de
auto& dm = DeviceMapper::Instance();
std::vector<DeviceMapper::TargetInfo> table;
if (!dm.GetTableInfo(dev_name, &table)) {
- PCHECK(errno == ENODEV || errno == ENXIO);
+ PCHECK(errno == ENODEV);
return {};
}
return table;
@@ -488,7 +488,7 @@ std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMountFormatData(const std::str
.fs_type = "ext4",
.mount_point = mount_point,
};
- CHECK(0 == fs_mgr_do_format(entry));
+ CHECK(0 == fs_mgr_do_format(entry, false /* crypt_footer */));
CHECK(0 == fs_mgr_do_mount_one(entry));
return std::make_unique<AutoUnmount>(mount_point);
}
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index a648384ce..3ed27c836 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -101,8 +101,7 @@ class SnapshotFuzzDeviceInfo : public ISnapshotManager::IDeviceInfo {
: env_(env),
data_(&data),
partition_opener_(std::move(partition_opener)),
- metadata_dir_(metadata_dir),
- dm_(android::dm::DeviceMapper::Instance()) {}
+ metadata_dir_(metadata_dir) {}
// Following APIs are mocked.
std::string GetMetadataDir() const override { return metadata_dir_; }
@@ -126,7 +125,6 @@ class SnapshotFuzzDeviceInfo : public ISnapshotManager::IDeviceInfo {
}
bool IsRecovery() const override { return data_->is_recovery(); }
bool IsFirstStageInit() const override { return false; }
- android::dm::IDeviceMapper& GetDeviceMapper() override { return dm_; }
std::unique_ptr<IImageManager> OpenImageManager() const {
return env_->CheckCreateFakeImageManager();
}
@@ -139,7 +137,6 @@ class SnapshotFuzzDeviceInfo : public ISnapshotManager::IDeviceInfo {
std::unique_ptr<TestPartitionOpener> partition_opener_;
std::string metadata_dir_;
bool switched_slot_ = false;
- android::dm::DeviceMapper& dm_;
bool CurrentSlotIsA() const { return data_->slot_suffix_is_a() != switched_slot_; }
};
@@ -199,7 +196,6 @@ class SnapshotFuzzImageManager : public android::fiemap::IImageManager {
bool UnmapImageIfExists(const std::string& name) override {
return impl_->UnmapImageIfExists(name);
}
- bool IsImageDisabled(const std::string& name) override { return impl_->IsImageDisabled(name); }
private:
std::unique_ptr<android::fiemap::IImageManager> impl_;
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/snapshot_reader.cpp
index 6546c2a5c..5ee8e25d1 100644
--- a/fs_mgr/libsnapshot/snapshot_reader.cpp
+++ b/fs_mgr/libsnapshot/snapshot_reader.cpp
@@ -221,7 +221,7 @@ class PartialSink : public MemoryByteSink {
private:
size_t ignore_start_;
- char discard_[BLOCK_SZ];
+ char discard_[4096];
};
ssize_t CompressedSnapshotReader::ReadBlock(uint64_t chunk, IByteSink* sink, size_t start_offset,
@@ -277,29 +277,6 @@ ssize_t CompressedSnapshotReader::ReadBlock(uint64_t chunk, IByteSink* sink, siz
errno = EIO;
return -1;
}
- } else if (op->type == kCowXorOp) {
- borrowed_fd fd = GetSourceFd();
- if (fd < 0) {
- // GetSourceFd sets errno.
- return -1;
- }
-
- off64_t offset = op->source + start_offset;
- char data[BLOCK_SZ];
- if (!android::base::ReadFullyAtOffset(fd, &data, bytes_to_read, offset)) {
- PLOG(ERROR) << "read " << *source_device_;
- // ReadFullyAtOffset sets errno.
- return -1;
- }
- PartialSink partial_sink(buffer, bytes_to_read, start_offset);
- if (!cow_->ReadData(*op, &partial_sink)) {
- LOG(ERROR) << "CompressedSnapshotReader failed to read xor op";
- errno = EIO;
- return -1;
- }
- for (size_t i = 0; i < bytes_to_read; i++) {
- ((char*)buffer)[i] ^= data[i];
- }
} else {
LOG(ERROR) << "CompressedSnapshotReader unknown op type: " << uint32_t(op->type);
errno = EINVAL;
diff --git a/fs_mgr/libsnapshot/snapshot_reader_test.cpp b/fs_mgr/libsnapshot/snapshot_reader_test.cpp
index 9adc6551b..937305951 100644
--- a/fs_mgr/libsnapshot/snapshot_reader_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_reader_test.cpp
@@ -63,9 +63,7 @@ class OfflineSnapshotTest : public ::testing::Test {
void WriteCow(ISnapshotWriter* writer) {
std::string new_block = MakeNewBlockString();
- std::string xor_block = MakeXorBlockString();
- ASSERT_TRUE(writer->AddXorBlocks(1, xor_block.data(), xor_block.size(), 0, kBlockSize / 2));
ASSERT_TRUE(writer->AddCopy(3, 0));
ASSERT_TRUE(writer->AddRawBlocks(5, new_block.data(), new_block.size()));
ASSERT_TRUE(writer->AddZeroBlocks(7, 2));
@@ -77,7 +75,7 @@ class OfflineSnapshotTest : public ::testing::Test {
ASSERT_NE(reader, nullptr);
// Test that unchanged blocks are not modified.
- std::unordered_set<size_t> changed_blocks = {1, 3, 5, 7, 8};
+ std::unordered_set<size_t> changed_blocks = {3, 5, 7, 8};
for (size_t i = 0; i < kBlockCount; i++) {
if (changed_blocks.count(i)) {
continue;
@@ -90,17 +88,6 @@ class OfflineSnapshotTest : public ::testing::Test {
}
// Test that we can read back our modified blocks.
- std::string data(kBlockSize, 0);
- std::string offsetblock = base_blocks_[0].substr(kBlockSize / 2, kBlockSize / 2) +
- base_blocks_[1].substr(0, kBlockSize / 2);
- ASSERT_EQ(offsetblock.size(), kBlockSize);
- ASSERT_EQ(reader->Seek(1 * kBlockSize, SEEK_SET), 1 * kBlockSize);
- ASSERT_EQ(reader->Read(data.data(), data.size()), kBlockSize);
- for (int i = 0; i < 100; i++) {
- data[i] = (char)~(data[i]);
- }
- ASSERT_EQ(data, offsetblock);
-
std::string block(kBlockSize, 0);
ASSERT_EQ(reader->Seek(3 * kBlockSize, SEEK_SET), 3 * kBlockSize);
ASSERT_EQ(reader->Read(block.data(), block.size()), kBlockSize);
@@ -154,12 +141,6 @@ class OfflineSnapshotTest : public ::testing::Test {
return new_block;
}
- std::string MakeXorBlockString() {
- std::string data(kBlockSize, 0);
- memset(data.data(), 0xff, 100);
- return data;
- }
-
std::unique_ptr<TemporaryFile> base_;
std::unique_ptr<TemporaryFile> cow_;
std::vector<std::string> base_blocks_;
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 4af5367ac..a8d5b8a1a 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -121,11 +121,6 @@ bool SnapshotManagerStub::UpdateUsesCompression() {
return false;
}
-bool SnapshotManagerStub::UpdateUsesUserSnapshots() {
- LOG(ERROR) << __FUNCTION__ << " should never be called.";
- return false;
-}
-
class SnapshotMergeStatsStub : public ISnapshotMergeStats {
bool Start() override { return false; }
void set_state(android::snapshot::UpdateState, bool) override {}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 36abf712b..60186434a 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -34,7 +34,6 @@
#include <fs_mgr/file_wait.h>
#include <fs_mgr/roots.h>
#include <fs_mgr_dm_linear.h>
-#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
@@ -51,17 +50,12 @@
#include <libsnapshot/mock_device_info.h>
#include <libsnapshot/mock_snapshot.h>
-DEFINE_string(force_config, "", "Force testing mode (dmsnap, vab, vabc) ignoring device config.");
-DEFINE_string(force_iouring_disable, "",
- "Force testing mode (iouring_disabled) - disable io_uring");
-
namespace android {
namespace snapshot {
using android::base::unique_fd;
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
-using android::dm::IDeviceMapper;
using android::fiemap::FiemapStatus;
using android::fiemap::IImageManager;
using android::fs_mgr::BlockDeviceInfo;
@@ -90,8 +84,6 @@ TestDeviceInfo* test_device = nullptr;
std::string fake_super;
void MountMetadata();
-bool ShouldUseCompression();
-bool ShouldUseUserspaceSnapshots();
class SnapshotTest : public ::testing::Test {
public:
@@ -144,7 +136,11 @@ class SnapshotTest : public ::testing::Test {
std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a",
"test_partition_b"};
for (const auto& snapshot : snapshots) {
- CleanupSnapshotArtifacts(snapshot);
+ ASSERT_TRUE(DeleteSnapshotDevice(snapshot));
+ DeleteBackingImage(image_manager_, snapshot + "-cow-img");
+
+ auto status_file = sm->GetSnapshotStatusFilePath(snapshot);
+ android::base::RemoveFileIfExists(status_file);
}
// Remove stale partitions in fake super.
@@ -152,7 +148,7 @@ class SnapshotTest : public ::testing::Test {
"base-device",
"test_partition_b",
"test_partition_b-base",
- "test_partition_b-cow",
+ "test_partition_b-base",
};
for (const auto& partition : partitions) {
DeleteDevice(partition);
@@ -164,32 +160,6 @@ class SnapshotTest : public ::testing::Test {
}
}
- void CleanupSnapshotArtifacts(const std::string& snapshot) {
- // The device-mapper stack may have been collapsed to dm-linear, so it's
- // necessary to check what state it's in before attempting a cleanup.
- // SnapshotManager has no path like this because we'd never remove a
- // merged snapshot (a live partition).
- bool is_dm_user = false;
- DeviceMapper::TargetInfo target;
- if (sm->IsSnapshotDevice(snapshot, &target)) {
- is_dm_user = (DeviceMapper::GetTargetType(target.spec) == "user");
- }
-
- if (is_dm_user) {
- ASSERT_TRUE(sm->EnsureSnapuserdConnected());
- ASSERT_TRUE(AcquireLock());
-
- auto local_lock = std::move(lock_);
- ASSERT_TRUE(sm->UnmapUserspaceSnapshotDevice(local_lock.get(), snapshot));
- }
-
- ASSERT_TRUE(DeleteSnapshotDevice(snapshot));
- DeleteBackingImage(image_manager_, snapshot + "-cow-img");
-
- auto status_file = sm->GetSnapshotStatusFilePath(snapshot);
- android::base::RemoveFileIfExists(status_file);
- }
-
bool AcquireLock() {
lock_ = sm->LockExclusive();
return !!lock_;
@@ -301,7 +271,7 @@ class SnapshotTest : public ::testing::Test {
AssertionResult DeleteSnapshotDevice(const std::string& snapshot) {
AssertionResult res = AssertionSuccess();
if (!(res = DeleteDevice(snapshot))) return res;
- if (!sm->UnmapDmUserDevice(snapshot + "-user-cow")) {
+ if (!sm->UnmapDmUserDevice(snapshot)) {
return AssertionFailure() << "Cannot delete dm-user device for " << snapshot;
}
if (!(res = DeleteDevice(snapshot + "-inner"))) return res;
@@ -455,7 +425,7 @@ TEST_F(SnapshotTest, CreateSnapshot) {
ASSERT_TRUE(AcquireLock());
PartitionCowCreator cow_creator;
- cow_creator.compression_enabled = ShouldUseCompression();
+ cow_creator.compression_enabled = IsCompressionEnabled();
if (cow_creator.compression_enabled) {
cow_creator.compression_algorithm = "gz";
} else {
@@ -496,7 +466,7 @@ TEST_F(SnapshotTest, MapSnapshot) {
ASSERT_TRUE(AcquireLock());
PartitionCowCreator cow_creator;
- cow_creator.compression_enabled = ShouldUseCompression();
+ cow_creator.compression_enabled = IsCompressionEnabled();
static const uint64_t kDeviceSize = 1024 * 1024;
SnapshotStatus status;
@@ -554,8 +524,6 @@ TEST_F(SnapshotTest, Merge) {
std::unique_ptr<ISnapshotWriter> writer;
ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer));
- bool userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get());
-
// Release the lock.
lock_ = nullptr;
@@ -577,11 +545,7 @@ TEST_F(SnapshotTest, Merge) {
// The device should have been switched to a snapshot-merge target.
DeviceMapper::TargetInfo target;
ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target));
- if (userspace_snapshots) {
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
- } else {
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
- }
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
// We should not be able to cancel an update now.
ASSERT_FALSE(sm->CancelUpdate());
@@ -617,13 +581,11 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) {
ASSERT_TRUE(AcquireLock());
- bool userspace_snapshots = init->UpdateUsesUserSnapshots(lock_.get());
-
// Validate that we have a snapshot device.
SnapshotStatus status;
ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
ASSERT_EQ(status.state(), SnapshotState::CREATED);
- if (ShouldUseCompression()) {
+ if (IsCompressionEnabled()) {
ASSERT_EQ(status.compression_algorithm(), "gz");
} else {
ASSERT_EQ(status.compression_algorithm(), "none");
@@ -631,11 +593,7 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) {
DeviceMapper::TargetInfo target;
ASSERT_TRUE(init->IsSnapshotDevice("test_partition_b", &target));
- if (userspace_snapshots) {
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
- } else {
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
- }
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
}
TEST_F(SnapshotTest, FlashSuperDuringUpdate) {
@@ -897,7 +855,7 @@ class SnapshotUpdateTest : public SnapshotTest {
opener_ = std::make_unique<TestPartitionOpener>(fake_super);
auto dynamic_partition_metadata = manifest_.mutable_dynamic_partition_metadata();
- dynamic_partition_metadata->set_vabc_enabled(ShouldUseCompression());
+ dynamic_partition_metadata->set_vabc_enabled(IsCompressionEnabled());
dynamic_partition_metadata->set_cow_version(android::snapshot::kCowVersionMajor);
// Create a fake update package metadata.
@@ -936,9 +894,9 @@ class SnapshotUpdateTest : public SnapshotTest {
ASSERT_NE(nullptr, metadata);
ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
- // Map source partitions.
+ // Map source partitions. Additionally, map sys_b to simulate system_other after flashing.
std::string path;
- for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
+ for (const auto& name : {"sys_a", "vnd_a", "prd_a", "sys_b"}) {
ASSERT_TRUE(CreateLogicalPartition(
CreateLogicalPartitionParams{
.block_device = fake_super,
@@ -953,11 +911,6 @@ class SnapshotUpdateTest : public SnapshotTest {
ASSERT_TRUE(hash.has_value());
hashes_[name] = *hash;
}
-
- // OTA client blindly unmaps all partitions that are possibly mapped.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
- }
}
void TearDown() override {
RETURN_IF_NON_VIRTUAL_AB();
@@ -972,14 +925,6 @@ class SnapshotUpdateTest : public SnapshotTest {
MountMetadata();
for (const auto& suffix : {"_a", "_b"}) {
test_device->set_slot_suffix(suffix);
-
- // Cheat our way out of merge failed states.
- if (sm->ProcessUpdateState() == UpdateState::MergeFailed) {
- ASSERT_TRUE(AcquireLock());
- ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
- lock_ = {};
- }
-
EXPECT_TRUE(sm->CancelUpdate()) << suffix;
}
EXPECT_TRUE(UnmapAll());
@@ -1018,7 +963,7 @@ class SnapshotUpdateTest : public SnapshotTest {
}
AssertionResult UnmapAll() {
- for (const auto& name : {"sys", "vnd", "prd", "dlkm"}) {
+ for (const auto& name : {"sys", "vnd", "prd"}) {
if (!dm_.DeleteDeviceIfExists(name + "_a"s)) {
return AssertionFailure() << "Cannot unmap " << name << "_a";
}
@@ -1030,7 +975,7 @@ class SnapshotUpdateTest : public SnapshotTest {
}
AssertionResult MapOneUpdateSnapshot(const std::string& name) {
- if (ShouldUseCompression()) {
+ if (IsCompressionEnabled()) {
std::unique_ptr<ISnapshotWriter> writer;
return MapUpdateSnapshot(name, &writer);
} else {
@@ -1040,7 +985,7 @@ class SnapshotUpdateTest : public SnapshotTest {
}
AssertionResult WriteSnapshotAndHash(const std::string& name) {
- if (ShouldUseCompression()) {
+ if (IsCompressionEnabled()) {
std::unique_ptr<ISnapshotWriter> writer;
auto res = MapUpdateSnapshot(name, &writer);
if (!res) {
@@ -1152,6 +1097,11 @@ class SnapshotUpdateTest : public SnapshotTest {
// Also test UnmapUpdateSnapshot unmaps everything.
// Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
+ // OTA client blindly unmaps all partitions that are possibly mapped.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
+ }
+
// Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
// fit in super, but not |prd|.
constexpr uint64_t partition_size = 3788_KiB;
@@ -1208,7 +1158,7 @@ TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
// Initiate the merge and wait for it to be completed.
ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(init->IsSnapuserdRequired(), ShouldUseUserspaceSnapshots());
+ ASSERT_EQ(init->IsSnapuserdRequired(), IsCompressionEnabled());
{
// We should have started in SECOND_PHASE since nothing shrinks.
ASSERT_TRUE(AcquireLock());
@@ -1234,56 +1184,19 @@ TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
}
}
-TEST_F(SnapshotUpdateTest, DuplicateOps) {
- if (!ShouldUseCompression()) {
- GTEST_SKIP() << "Compression-only test";
- }
-
- // Execute the update.
- ASSERT_TRUE(sm->BeginUpdate());
- ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
-
- // Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
-
- std::vector<PartitionUpdate*> partitions = {sys_, vnd_, prd_};
- for (auto* partition : partitions) {
- AddOperation(partition);
-
- std::unique_ptr<ISnapshotWriter> writer;
- auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer);
- ASSERT_TRUE(res);
- ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
- ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
- ASSERT_TRUE(writer->Finalize());
- }
-
- ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
-
- // Simulate shutting down the device.
- ASSERT_TRUE(UnmapAll());
-
- // After reboot, init does first stage mount.
- auto init = NewManagerForFirstStageMount("_b");
- ASSERT_NE(init, nullptr);
- ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
-
- // Initiate the merge and wait for it to be completed.
- ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
-}
-
// Test that shrinking and growing partitions at the same time is handled
// correctly in VABC.
TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
- if (!ShouldUseCompression()) {
+ if (!IsCompressionEnabled()) {
// b/179111359
GTEST_SKIP() << "Skipping Virtual A/B Compression test";
}
+ // OTA client blindly unmaps all partitions that are possibly mapped.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
+ }
+
auto old_sys_size = GetSize(sys_);
auto old_prd_size = GetSize(prd_);
@@ -1342,7 +1255,7 @@ TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
// Initiate the merge and wait for it to be completed.
ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(init->IsSnapuserdRequired(), ShouldUseUserspaceSnapshots());
+ ASSERT_EQ(init->IsSnapuserdRequired(), IsCompressionEnabled());
{
// Check that the merge phase is FIRST_PHASE until at least one call
// to ProcessUpdateState() occurs.
@@ -1359,21 +1272,11 @@ TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
// Check that we used the correct types after rebooting mid-merge.
DeviceMapper::TargetInfo target;
ASSERT_TRUE(init->IsSnapshotDevice("prd_b", &target));
-
- bool userspace_snapshots = init->UpdateUsesUserSnapshots();
- if (userspace_snapshots) {
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
- ASSERT_TRUE(init->IsSnapshotDevice("sys_b", &target));
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
- ASSERT_TRUE(init->IsSnapshotDevice("vnd_b", &target));
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
- } else {
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
- ASSERT_TRUE(init->IsSnapshotDevice("sys_b", &target));
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
- ASSERT_TRUE(init->IsSnapshotDevice("vnd_b", &target));
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
- }
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
+ ASSERT_TRUE(init->IsSnapshotDevice("sys_b", &target));
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
+ ASSERT_TRUE(init->IsSnapshotDevice("vnd_b", &target));
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
// Complete the merge.
ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
@@ -1394,93 +1297,6 @@ TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
}
}
-// Test that a transient merge consistency check failure can resume properly.
-TEST_F(SnapshotUpdateTest, ConsistencyCheckResume) {
- if (!ShouldUseCompression()) {
- // b/179111359
- GTEST_SKIP() << "Skipping Virtual A/B Compression test";
- }
-
- auto old_sys_size = GetSize(sys_);
- auto old_prd_size = GetSize(prd_);
-
- // Grow |sys| but shrink |prd|.
- SetSize(sys_, old_sys_size * 2);
- sys_->set_estimate_cow_size(8_MiB);
- SetSize(prd_, old_prd_size / 2);
- prd_->set_estimate_cow_size(1_MiB);
-
- AddOperationForPartitions();
-
- ASSERT_TRUE(sm->BeginUpdate());
- ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
- ASSERT_TRUE(WriteSnapshotAndHash("vnd_b"));
- ASSERT_TRUE(ShiftAllSnapshotBlocks("prd_b", old_prd_size));
-
- sync();
-
- // Assert that source partitions aren't affected.
- for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
- ASSERT_TRUE(IsPartitionUnchanged(name));
- }
-
- ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
-
- // Simulate shutting down the device.
- ASSERT_TRUE(UnmapAll());
-
- // After reboot, init does first stage mount.
- auto init = NewManagerForFirstStageMount("_b");
- ASSERT_NE(init, nullptr);
- ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
-
- // Check that the target partitions have the same content.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(IsPartitionUnchanged(name));
- }
-
- auto old_checker = init->merge_consistency_checker();
-
- init->set_merge_consistency_checker(
- [](const std::string&, const SnapshotStatus&) -> MergeFailureCode {
- return MergeFailureCode::WrongMergeCountConsistencyCheck;
- });
-
- // Initiate the merge and wait for it to be completed.
- ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(init->IsSnapuserdRequired(), ShouldUseUserspaceSnapshots());
- {
- // Check that the merge phase is FIRST_PHASE until at least one call
- // to ProcessUpdateState() occurs.
- ASSERT_TRUE(AcquireLock());
- auto local_lock = std::move(lock_);
- auto status = init->ReadSnapshotUpdateStatus(local_lock.get());
- ASSERT_EQ(status.merge_phase(), MergePhase::FIRST_PHASE);
- }
-
- // Merge should have failed.
- ASSERT_EQ(UpdateState::MergeFailed, init->ProcessUpdateState());
-
- // Simulate shutting down the device and creating partitions again.
- ASSERT_TRUE(UnmapAll());
-
- // Restore the checker.
- init->set_merge_consistency_checker(std::move(old_checker));
-
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
-
- // Complete the merge.
- ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
-
- // Check that the target partitions have the same content after the merge.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(IsPartitionUnchanged(name))
- << "Content of " << name << " changes after the merge";
- }
-}
-
// Test that if new system partitions uses empty space in super, that region is not snapshotted.
TEST_F(SnapshotUpdateTest, DirectWriteEmptySpace) {
GTEST_SKIP() << "b/141889746";
@@ -1767,6 +1583,11 @@ TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
ASSERT_NE(nullptr, metadata);
ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
+ // OTA client blindly unmaps all partitions that are possibly mapped.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
+ }
+
// Add operations for sys. The whole device is written.
AddOperation(sys_);
@@ -1938,8 +1759,6 @@ TEST_F(SnapshotUpdateTest, MergeInFastboot) {
ASSERT_TRUE(new_sm->FinishMergeInRecovery());
- ASSERT_TRUE(UnmapAll());
-
auto mount = new_sm->EnsureMetadataMounted();
ASSERT_TRUE(mount && mount->HasDevice());
ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
@@ -2032,8 +1851,6 @@ TEST_F(SnapshotUpdateTest, DataWipeRequiredInPackage) {
ASSERT_FALSE(test_device->IsSlotUnbootable(1));
ASSERT_FALSE(test_device->IsSlotUnbootable(0));
- ASSERT_TRUE(UnmapAll());
-
// Now reboot into new slot.
test_device = new TestDeviceInfo(fake_super, "_b");
auto init = NewManagerForFirstStageMount(test_device);
@@ -2062,8 +1879,8 @@ TEST_F(SnapshotUpdateTest, DataWipeWithStaleSnapshots) {
ASSERT_TRUE(AcquireLock());
PartitionCowCreator cow_creator = {
- .compression_enabled = ShouldUseCompression(),
- .compression_algorithm = ShouldUseCompression() ? "gz" : "none",
+ .compression_enabled = IsCompressionEnabled(),
+ .compression_algorithm = IsCompressionEnabled() ? "gz" : "none",
};
SnapshotStatus status;
status.set_name("sys_a");
@@ -2095,8 +1912,6 @@ TEST_F(SnapshotUpdateTest, DataWipeWithStaleSnapshots) {
ASSERT_FALSE(test_device->IsSlotUnbootable(1));
ASSERT_FALSE(test_device->IsSlotUnbootable(0));
- ASSERT_TRUE(UnmapAll());
-
// Now reboot into new slot.
test_device = new TestDeviceInfo(fake_super, "_b");
auto init = NewManagerForFirstStageMount(test_device);
@@ -2159,7 +1974,7 @@ TEST_F(SnapshotUpdateTest, Hashtree) {
// Test for overflow bit after update
TEST_F(SnapshotUpdateTest, Overflow) {
- if (ShouldUseCompression()) {
+ if (IsCompressionEnabled()) {
GTEST_SKIP() << "No overflow bit set for userspace COWs";
}
@@ -2211,75 +2026,6 @@ TEST_F(SnapshotUpdateTest, LowSpace) {
ASSERT_LT(res.required_size(), 40_MiB);
}
-TEST_F(SnapshotUpdateTest, AddPartition) {
- group_->add_partition_names("dlkm");
-
- auto dlkm = manifest_.add_partitions();
- dlkm->set_partition_name("dlkm");
- dlkm->set_estimate_cow_size(2_MiB);
- SetSize(dlkm, 3_MiB);
-
- // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
- // fit in super, but not |prd|.
- constexpr uint64_t partition_size = 3788_KiB;
- SetSize(sys_, partition_size);
- SetSize(vnd_, partition_size);
- SetSize(prd_, partition_size);
- SetSize(dlkm, partition_size);
-
- AddOperationForPartitions({sys_, vnd_, prd_, dlkm});
-
- // Execute the update.
- ASSERT_TRUE(sm->BeginUpdate());
- ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
-
- // Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
-
- // Assert that source partitions aren't affected.
- for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
- ASSERT_TRUE(IsPartitionUnchanged(name));
- }
-
- ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
-
- // Simulate shutting down the device.
- ASSERT_TRUE(UnmapAll());
-
- // After reboot, init does first stage mount.
- auto init = NewManagerForFirstStageMount("_b");
- ASSERT_NE(init, nullptr);
-
- ASSERT_TRUE(init->EnsureSnapuserdConnected());
- init->set_use_first_stage_snapuserd(true);
-
- ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
-
- // Check that the target partitions have the same content.
- std::vector<std::string> partitions = {"sys_b", "vnd_b", "prd_b", "dlkm_b"};
- for (const auto& name : partitions) {
- ASSERT_TRUE(IsPartitionUnchanged(name));
- }
-
- ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SECOND_STAGE));
- for (const auto& name : partitions) {
- ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete(name + "-user-cow-init"));
- }
-
- // Initiate the merge and wait for it to be completed.
- ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
-
- // Check that the target partitions have the same content after the merge.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) {
- ASSERT_TRUE(IsPartitionUnchanged(name))
- << "Content of " << name << " changes after the merge";
- }
-}
-
class AutoKill final {
public:
explicit AutoKill(pid_t pid) : pid_(pid) {}
@@ -2294,7 +2040,7 @@ class AutoKill final {
};
TEST_F(SnapshotUpdateTest, DaemonTransition) {
- if (!ShouldUseCompression()) {
+ if (!IsCompressionEnabled()) {
GTEST_SKIP() << "Skipping Virtual A/B Compression test";
}
@@ -2320,38 +2066,21 @@ TEST_F(SnapshotUpdateTest, DaemonTransition) {
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
- bool userspace_snapshots = init->UpdateUsesUserSnapshots();
-
- if (userspace_snapshots) {
- ASSERT_EQ(access("/dev/dm-user/sys_b-init", F_OK), 0);
- ASSERT_EQ(access("/dev/dm-user/sys_b", F_OK), -1);
- } else {
- ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow-init", F_OK), 0);
- ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), -1);
- }
+ ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow-init", F_OK), 0);
+ ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), -1);
ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SECOND_STAGE));
// :TODO: this is a workaround to ensure the handler list stays empty. We
// should make this test more like actual init, and spawn two copies of
// snapuserd, given how many other tests we now have for normal snapuserd.
- if (userspace_snapshots) {
- ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("sys_b-init"));
- ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("vnd_b-init"));
- ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("prd_b-init"));
-
- // The control device should have been renamed.
- ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted("/dev/dm-user/sys_b-init", 10s));
- ASSERT_EQ(access("/dev/dm-user/sys_b", F_OK), 0);
- } else {
- ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("sys_b-user-cow-init"));
- ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("vnd_b-user-cow-init"));
- ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("prd_b-user-cow-init"));
+ ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("sys_b-user-cow-init"));
+ ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("vnd_b-user-cow-init"));
+ ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete("prd_b-user-cow-init"));
- // The control device should have been renamed.
- ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted("/dev/dm-user/sys_b-user-cow-init", 10s));
- ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), 0);
- }
+ // The control device should have been renamed.
+ ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted("/dev/dm-user/sys_b-user-cow-init", 10s));
+ ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), 0);
}
TEST_F(SnapshotUpdateTest, MapAllSnapshots) {
@@ -2374,8 +2103,6 @@ TEST_F(SnapshotUpdateTest, MapAllSnapshots) {
TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
AddOperationForPartitions();
- ASSERT_TRUE(UnmapAll());
-
// Execute the update from B->A.
test_device->set_slot_suffix("_b");
ASSERT_TRUE(sm->BeginUpdate());
@@ -2392,13 +2119,8 @@ TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
},
&path));
- bool userspace_snapshots = sm->UpdateUsesUserSnapshots();
-
- unique_fd fd;
- if (!userspace_snapshots) {
- // Hold sys_a open so it can't be unmapped.
- fd.reset(open(path.c_str(), O_RDONLY));
- }
+ // Hold sys_a open so it can't be unmapped.
+ unique_fd fd(open(path.c_str(), O_RDONLY));
// Switch back to "A", make sure we can cancel. Instead of unmapping sys_a
// we should simply delete the old snapshots.
@@ -2406,89 +2128,6 @@ TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
ASSERT_TRUE(sm->BeginUpdate());
}
-TEST_F(SnapshotUpdateTest, QueryStatusError) {
- // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
- // fit in super, but not |prd|.
- constexpr uint64_t partition_size = 3788_KiB;
- SetSize(sys_, partition_size);
- SetSize(vnd_, partition_size);
- SetSize(prd_, 18_MiB);
-
- // Make sure |prd| does not fit in super at all. On VABC, this means we
- // fake an extra large COW for |vnd| to fill up super.
- vnd_->set_estimate_cow_size(30_MiB);
- prd_->set_estimate_cow_size(30_MiB);
-
- AddOperationForPartitions();
-
- // Execute the update.
- ASSERT_TRUE(sm->BeginUpdate());
- ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
-
- if (sm->UpdateUsesUserSnapshots()) {
- GTEST_SKIP() << "Test does not apply to userspace snapshots";
- }
-
- // Test that partitions prioritize using space in super.
- auto tgt = MetadataBuilder::New(*opener_, "super", 1);
- ASSERT_NE(tgt, nullptr);
- ASSERT_NE(nullptr, tgt->FindPartition("sys_b-cow"));
- ASSERT_NE(nullptr, tgt->FindPartition("vnd_b-cow"));
- ASSERT_EQ(nullptr, tgt->FindPartition("prd_b-cow"));
-
- // Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
-
- // Assert that source partitions aren't affected.
- for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
- ASSERT_TRUE(IsPartitionUnchanged(name));
- }
-
- ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
-
- ASSERT_TRUE(UnmapAll());
-
- class DmStatusFailure final : public DeviceMapperWrapper {
- public:
- bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override {
- if (!DeviceMapperWrapper::GetTableStatus(name, table)) {
- return false;
- }
- if (name == "sys_b" && !table->empty()) {
- auto& info = table->at(0);
- if (DeviceMapper::GetTargetType(info.spec) == "snapshot-merge") {
- info.data = "Merge failed";
- }
- }
- return true;
- }
- };
- DmStatusFailure wrapper;
-
- // After reboot, init does first stage mount.
- auto info = new TestDeviceInfo(fake_super, "_b");
- info->set_dm(&wrapper);
-
- auto init = NewManagerForFirstStageMount(info);
- ASSERT_NE(init, nullptr);
-
- ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
-
- // Initiate the merge and wait for it to be completed.
- ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(UpdateState::MergeFailed, init->ProcessUpdateState());
-
- // Simulate a reboot that tries the merge again, with the non-failing dm.
- ASSERT_TRUE(UnmapAll());
- init = NewManagerForFirstStageMount("_b");
- ASSERT_NE(init, nullptr);
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
- ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
-}
-
class FlashAfterUpdateTest : public SnapshotUpdateTest,
public WithParamInterface<std::tuple<uint32_t, bool>> {
public:
@@ -2505,6 +2144,11 @@ class FlashAfterUpdateTest : public SnapshotUpdateTest,
};
TEST_P(FlashAfterUpdateTest, FlashSlotAfterUpdate) {
+ // OTA client blindly unmaps all partitions that are possibly mapped.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
+ }
+
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
@@ -2750,65 +2394,11 @@ void SnapshotTestEnvironment::TearDown() {
}
}
-bool ShouldUseUserspaceSnapshots() {
- if (FLAGS_force_config == "dmsnap") {
- return false;
- }
- if (!FLAGS_force_config.empty()) {
- return true;
- }
- return IsUserspaceSnapshotsEnabled();
-}
-
-bool ShouldUseCompression() {
- if (FLAGS_force_config == "vab" || FLAGS_force_config == "dmsnap") {
- return false;
- }
- if (FLAGS_force_config == "vabc") {
- return true;
- }
- return IsCompressionEnabled();
-}
-
} // namespace snapshot
} // namespace android
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::AddGlobalTestEnvironment(new ::android::snapshot::SnapshotTestEnvironment());
- gflags::ParseCommandLineFlags(&argc, &argv, false);
-
- android::base::SetProperty("ctl.stop", "snapuserd");
-
- std::unordered_set<std::string> configs = {"", "dmsnap", "vab", "vabc"};
- if (configs.count(FLAGS_force_config) == 0) {
- std::cerr << "Unexpected force_config argument\n";
- return 1;
- }
-
- if (FLAGS_force_config == "dmsnap") {
- if (!android::base::SetProperty("snapuserd.test.dm.snapshots", "1")) {
- return testing::AssertionFailure()
- << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
- }
- }
-
- if (FLAGS_force_iouring_disable == "iouring_disabled") {
- if (!android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1")) {
- return testing::AssertionFailure()
- << "Failed to disable property: snapuserd.test.io_uring.disabled";
- }
- }
-
- int ret = RUN_ALL_TESTS();
-
- if (FLAGS_force_config == "dmsnap") {
- android::base::SetProperty("snapuserd.test.dm.snapshots", "0");
- }
-
- if (FLAGS_force_iouring_disable == "iouring_disabled") {
- android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
- }
-
- return ret;
+ return RUN_ALL_TESTS();
}
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
index 48b7d80f7..080f3b79d 100644
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -67,7 +67,7 @@ uint64_t CompressedSnapshotWriter::GetCowSize() {
return cow_->GetCowSize();
}
-std::unique_ptr<CowReader> CompressedSnapshotWriter::OpenCowReader() const {
+std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
unique_fd cow_fd(dup(cow_device_.get()));
if (cow_fd < 0) {
PLOG(ERROR) << "dup COW device";
@@ -79,20 +79,6 @@ std::unique_ptr<CowReader> CompressedSnapshotWriter::OpenCowReader() const {
LOG(ERROR) << "Unable to read COW";
return nullptr;
}
- return cow;
-}
-
-bool CompressedSnapshotWriter::VerifyMergeOps() const noexcept {
- auto cow_reader = OpenCowReader();
- if (cow_reader == nullptr) {
- LOG(ERROR) << "Couldn't open CowReader";
- return false;
- }
- return cow_reader->VerifyMergeOps();
-}
-
-std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
- auto cow = OpenCowReader();
auto reader = std::make_unique<CompressedSnapshotReader>();
if (!reader->SetCow(std::move(cow))) {
@@ -120,11 +106,6 @@ bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const voi
return cow_->AddRawBlocks(new_block_start, data, size);
}
-bool CompressedSnapshotWriter::EmitXorBlocks(uint32_t new_block_start, const void* data,
- size_t size, uint32_t old_block, uint16_t offset) {
- return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset);
-}
-
bool CompressedSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
return cow_->AddZeroBlocks(new_block_start, num_blocks);
}
@@ -133,10 +114,6 @@ bool CompressedSnapshotWriter::EmitLabel(uint64_t label) {
return cow_->AddLabel(label);
}
-bool CompressedSnapshotWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
- return cow_->AddSequenceData(num_ops, data);
-}
-
bool CompressedSnapshotWriter::Initialize() {
return cow_->Initialize(cow_device_);
}
@@ -176,11 +153,6 @@ bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const v
return true;
}
-bool OnlineKernelSnapshotWriter::EmitXorBlocks(uint32_t, const void*, size_t, uint32_t, uint16_t) {
- LOG(ERROR) << "EmitXorBlocks not implemented.";
- return false;
-}
-
bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
std::string zeroes(options_.block_size, 0);
for (uint64_t i = 0; i < num_blocks; i++) {
@@ -211,11 +183,6 @@ bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) {
return true;
}
-bool OnlineKernelSnapshotWriter::EmitSequenceData(size_t, const uint32_t*) {
- // Not Needed
- return true;
-}
-
std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
unique_fd fd(dup(snapshot_fd_.get()));
if (fd < 0) {
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 67189d4be..5eb200378 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -36,9 +36,7 @@ int Usage() {
" dump\n"
" Print snapshot states.\n"
" merge\n"
- " Deprecated.\n"
- " map\n"
- " Map all partitions at /dev/block/mapper\n";
+ " Deprecated.\n";
return EX_USAGE;
}
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 5f4d7063b..57a61a791 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -16,23 +16,11 @@
#include "snapuserd.h"
-#include <dirent.h>
-#include <fcntl.h>
-#include <linux/fs.h>
-#include <unistd.h>
-#include <algorithm>
-
#include <csignal>
#include <optional>
#include <set>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <snapuserd/snapuserd_client.h>
+#include <libsnapshot/snapuserd_client.h>
namespace android {
namespace snapshot {
@@ -65,10 +53,6 @@ bool Snapuserd::InitializeWorkers() {
return true;
}
-std::unique_ptr<CowReader> Snapuserd::CloneReaderForWorker() {
- return reader_->CloneCowReader();
-}
-
bool Snapuserd::CommitMerge(int num_merge_ops) {
struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
ch->num_merge_ops += num_merge_ops;
@@ -80,7 +64,7 @@ bool Snapuserd::CommitMerge(int num_merge_ops) {
int ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC);
if (ret < 0) {
- SNAP_PLOG(ERROR) << "msync header failed: " << ret;
+ PLOG(ERROR) << "msync header failed: " << ret;
return false;
}
@@ -282,15 +266,14 @@ chunk_t Snapuserd::GetNextAllocatableChunkId(chunk_t chunk) {
void Snapuserd::CheckMergeCompletionStatus() {
if (!merge_initiated_) {
- SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: "
- << reader_->get_num_total_data_ops();
+ SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: " << reader_->total_data_ops();
return;
}
struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
SNAP_LOG(INFO) << "Merge-status: Total-Merged-ops: " << ch->num_merge_ops
- << " Total-data-ops: " << reader_->get_num_total_data_ops();
+ << " Total-data-ops: " << reader_->total_data_ops();
}
/*
@@ -350,7 +333,7 @@ bool Snapuserd::ReadMetadata() {
CowHeader header;
CowOptions options;
bool metadata_found = false;
- int replace_ops = 0, zero_ops = 0, copy_ops = 0, xor_ops = 0;
+ int replace_ops = 0, zero_ops = 0, copy_ops = 0;
SNAP_LOG(DEBUG) << "ReadMetadata: Parsing cow file";
@@ -369,6 +352,7 @@ bool Snapuserd::ReadMetadata() {
return false;
}
+ reader_->InitializeMerge();
SNAP_LOG(DEBUG) << "Merge-ops: " << header.num_merge_ops;
if (!MmapMetadata()) {
@@ -377,7 +361,7 @@ bool Snapuserd::ReadMetadata() {
}
// Initialize the iterator for reading metadata
- std::unique_ptr<ICowOpIter> cowop_rm_iter = reader_->GetRevMergeOpIter();
+ cowop_riter_ = reader_->GetRevOpIter();
exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception);
@@ -395,18 +379,23 @@ bool Snapuserd::ReadMetadata() {
// this memset will ensure that metadata read is completed.
memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
- while (!cowop_rm_iter->Done()) {
- const CowOperation* cow_op = &cowop_rm_iter->Get();
+ while (!cowop_riter_->Done()) {
+ const CowOperation* cow_op = &cowop_riter_->Get();
struct disk_exception* de =
reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
+ if (IsMetadataOp(*cow_op)) {
+ cowop_riter_->Next();
+ continue;
+ }
+
metadata_found = true;
// This loop will handle all the replace and zero ops.
// We will handle the copy ops later as it requires special
// handling of assigning chunk-id's. Furthermore, we make
// sure that replace/zero and copy ops are not batch merged; hence,
// the bump in the chunk_id before break of this loop
- if (IsOrderedOp(*cow_op)) {
+ if (cow_op->type == kCowCopyOp) {
data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
break;
}
@@ -421,11 +410,12 @@ bool Snapuserd::ReadMetadata() {
de->old_chunk = cow_op->new_block;
de->new_chunk = data_chunk_id;
+
// Store operation pointer.
chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op));
num_ops += 1;
offset += sizeof(struct disk_exception);
- cowop_rm_iter->Next();
+ cowop_riter_->Next();
SNAP_LOG(DEBUG) << num_ops << ":"
<< " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk;
@@ -442,7 +432,7 @@ bool Snapuserd::ReadMetadata() {
sizeof(struct disk_exception));
memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
- if (cowop_rm_iter->Done()) {
+ if (cowop_riter_->Done()) {
vec_.push_back(std::move(de_ptr));
}
}
@@ -455,16 +445,19 @@ bool Snapuserd::ReadMetadata() {
std::vector<const CowOperation*> vec;
std::set<uint64_t> dest_blocks;
std::set<uint64_t> source_blocks;
- size_t pending_ordered_ops = exceptions_per_area_ - num_ops;
- uint64_t total_ordered_ops = reader_->get_num_ordered_ops_to_merge();
+ size_t pending_copy_ops = exceptions_per_area_ - num_ops;
+ uint64_t total_copy_ops = reader_->total_copy_ops();
SNAP_LOG(DEBUG) << " Processing copy-ops at Area: " << vec_.size()
<< " Number of replace/zero ops completed in this area: " << num_ops
- << " Pending copy ops for this area: " << pending_ordered_ops;
-
- while (!cowop_rm_iter->Done()) {
+ << " Pending copy ops for this area: " << pending_copy_ops;
+ while (!cowop_riter_->Done()) {
do {
- const CowOperation* cow_op = &cowop_rm_iter->Get();
+ const CowOperation* cow_op = &cowop_riter_->Get();
+ if (IsMetadataOp(*cow_op)) {
+ cowop_riter_->Next();
+ continue;
+ }
// We have two cases specific cases:
//
@@ -509,38 +502,28 @@ bool Snapuserd::ReadMetadata() {
// is no loss of data.
//
// Note that we will follow the same order of COW operations
- // as present in the COW file. This will make sure that
+ // as present in the COW file. This will make sure that\
// the merge of operations are done based on the ops present
// in the file.
//===========================================================
- uint64_t block_source = cow_op->source;
- uint64_t block_offset = 0;
- if (cow_op->type == kCowXorOp) {
- block_source /= BLOCK_SZ;
- block_offset = cow_op->source % BLOCK_SZ;
- }
if (prev_id.has_value()) {
- if (dest_blocks.count(cow_op->new_block) || source_blocks.count(block_source) ||
- (block_offset > 0 && source_blocks.count(block_source + 1))) {
+ if (dest_blocks.count(cow_op->new_block) || source_blocks.count(cow_op->source)) {
break;
}
}
metadata_found = true;
- pending_ordered_ops -= 1;
+ pending_copy_ops -= 1;
vec.push_back(cow_op);
- dest_blocks.insert(block_source);
- if (block_offset > 0) {
- dest_blocks.insert(block_source + 1);
- }
+ dest_blocks.insert(cow_op->source);
source_blocks.insert(cow_op->new_block);
prev_id = cow_op->new_block;
- cowop_rm_iter->Next();
- } while (!cowop_rm_iter->Done() && pending_ordered_ops);
+ cowop_riter_->Next();
+ } while (!cowop_riter_->Done() && pending_copy_ops);
data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
- SNAP_LOG(DEBUG) << "Batch Merge copy-ops/xor-ops of size: " << vec.size()
+ SNAP_LOG(DEBUG) << "Batch Merge copy-ops of size: " << vec.size()
<< " Area: " << vec_.size() << " Area offset: " << offset
- << " Pending-ordered-ops in this area: " << pending_ordered_ops;
+ << " Pending-copy-ops in this area: " << pending_copy_ops;
for (size_t i = 0; i < vec.size(); i++) {
struct disk_exception* de =
@@ -554,18 +537,13 @@ bool Snapuserd::ReadMetadata() {
chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op));
offset += sizeof(struct disk_exception);
num_ops += 1;
- if (cow_op->type == kCowCopyOp) {
- copy_ops++;
- } else { // it->second->type == kCowXorOp
- xor_ops++;
- }
-
+ copy_ops++;
if (read_ahead_feature_) {
read_ahead_ops_.push_back(cow_op);
}
SNAP_LOG(DEBUG) << num_ops << ":"
- << " Ordered-op: "
+ << " Copy-op: "
<< " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk;
if (num_ops == exceptions_per_area_) {
@@ -580,27 +558,27 @@ bool Snapuserd::ReadMetadata() {
sizeof(struct disk_exception));
memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
- if (cowop_rm_iter->Done()) {
+ if (cowop_riter_->Done()) {
vec_.push_back(std::move(de_ptr));
SNAP_LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size();
}
- if (!(pending_ordered_ops == 0)) {
- SNAP_LOG(ERROR) << "Invalid pending_ordered_ops: expected: 0 found: "
- << pending_ordered_ops;
+ if (!(pending_copy_ops == 0)) {
+ SNAP_LOG(ERROR)
+ << "Invalid pending_copy_ops: expected: 0 found: " << pending_copy_ops;
return false;
}
- pending_ordered_ops = exceptions_per_area_;
+ pending_copy_ops = exceptions_per_area_;
}
data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
- total_ordered_ops -= 1;
+ total_copy_ops -= 1;
/*
* Split the number of ops based on the size of read-ahead buffer
* region. We need to ensure that kernel doesn't issue IO on blocks
* which are not read by the read-ahead thread.
*/
- if (read_ahead_feature_ && (total_ordered_ops % num_ra_ops_per_iter == 0)) {
+ if (read_ahead_feature_ && (total_copy_ops % num_ra_ops_per_iter == 0)) {
data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
}
}
@@ -629,9 +607,9 @@ bool Snapuserd::ReadMetadata() {
SNAP_LOG(INFO) << "ReadMetadata completed. Final-chunk-id: " << data_chunk_id
<< " Num Sector: " << ChunkToSector(data_chunk_id)
<< " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops
- << " Copy-ops: " << copy_ops << " Xor-ops: " << xor_ops
- << " Areas: " << vec_.size() << " Num-ops-merged: " << header.num_merge_ops
- << " Total-data-ops: " << reader_->get_num_total_data_ops();
+ << " Copy-ops: " << copy_ops << " Areas: " << vec_.size()
+ << " Num-ops-merged: " << header.num_merge_ops
+ << " Total-data-ops: " << reader_->total_data_ops();
// Total number of sectors required for creating dm-user device
num_sectors_ = ChunkToSector(data_chunk_id);
@@ -690,74 +668,6 @@ bool Snapuserd::InitCowDevice() {
return ReadMetadata();
}
-void Snapuserd::ReadBlocksToCache(const std::string& dm_block_device,
- const std::string& partition_name, off_t offset, size_t size) {
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
- if (fd.get() == -1) {
- SNAP_PLOG(ERROR) << "Error reading " << dm_block_device
- << " partition-name: " << partition_name;
- return;
- }
-
- size_t remain = size;
- off_t file_offset = offset;
- // We pick 4M I/O size based on the fact that the current
- // update_verifier has a similar I/O size.
- size_t read_sz = 1024 * BLOCK_SZ;
- std::vector<uint8_t> buf(read_sz);
-
- while (remain > 0) {
- size_t to_read = std::min(remain, read_sz);
-
- if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) {
- SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device
- << " at offset: " << file_offset
- << " partition-name: " << partition_name << " total-size: " << size
- << " remain_size: " << remain;
- return;
- }
-
- file_offset += to_read;
- remain -= to_read;
- }
-
- SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device
- << " partition: " << partition_name << " size: " << size
- << " offset: " << offset;
-}
-
-void Snapuserd::ReadBlocks(const std::string& partition_name, const std::string& dm_block_device) {
- SNAP_LOG(DEBUG) << "Reading partition: " << partition_name
- << " Block-Device: " << dm_block_device;
-
- uint64_t dev_sz = 0;
-
- unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd < 0) {
- SNAP_LOG(ERROR) << "Cannot open block device";
- return;
- }
-
- dev_sz = get_block_device_size(fd.get());
- if (!dev_sz) {
- SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device;
- return;
- }
-
- int num_threads = 2;
- size_t num_blocks = dev_sz >> BLOCK_SHIFT;
- size_t num_blocks_per_thread = num_blocks / num_threads;
- size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT;
- off_t offset = 0;
-
- for (int i = 0; i < num_threads; i++) {
- std::async(std::launch::async, &Snapuserd::ReadBlocksToCache, this, dm_block_device,
- partition_name, offset, read_sz_per_thread);
-
- offset += read_sz_per_thread;
- }
-}
-
/*
* Entry point to launch threads
*/
@@ -786,39 +696,6 @@ bool Snapuserd::Start() {
std::async(std::launch::async, &WorkerThread::RunThread, worker_threads_[i].get()));
}
- bool second_stage_init = true;
-
- // We don't want to read the blocks during first stage init.
- if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) {
- second_stage_init = false;
- }
-
- if (second_stage_init) {
- SNAP_LOG(INFO) << "Reading blocks to cache....";
- auto& dm = DeviceMapper::Instance();
- auto dm_block_devices = dm.FindDmPartitions();
- if (dm_block_devices.empty()) {
- SNAP_LOG(ERROR) << "No dm-enabled block device is found.";
- } else {
- auto parts = android::base::Split(misc_name_, "-");
- std::string partition_name = parts[0];
-
- const char* suffix_b = "_b";
- const char* suffix_a = "_a";
-
- partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1);
- partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1);
-
- if (dm_block_devices.find(partition_name) == dm_block_devices.end()) {
- SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name;
- } else {
- ReadBlocks(partition_name, dm_block_devices.at(partition_name));
- }
- }
- } else {
- SNAP_LOG(INFO) << "Not reading block device into cache";
- }
-
bool ret = true;
for (auto& t : threads) {
ret = t.get() && ret;
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h
index 47b9b2297..212c78e39 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd.h
@@ -38,12 +38,10 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
-#include <ext4_utils/ext4_utils.h>
#include <libdm/dm.h>
#include <libsnapshot/cow_reader.h>
#include <libsnapshot/cow_writer.h>
-#include <snapuserd/snapuserd_buffer.h>
-#include <snapuserd/snapuserd_kernel.h>
+#include <libsnapshot/snapuserd_kernel.h>
namespace android {
namespace snapshot {
@@ -90,6 +88,25 @@ enum class READ_AHEAD_IO_TRANSITION {
READ_AHEAD_FAILURE,
};
+class BufferSink : public IByteSink {
+ public:
+ void Initialize(size_t size);
+ void* GetBufPtr() { return buffer_.get(); }
+ void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
+ void* GetPayloadBuffer(size_t size);
+ void* GetBuffer(size_t requested, size_t* actual) override;
+ void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
+ struct dm_user_header* GetHeaderPtr();
+ bool ReturnData(void*, size_t) override { return true; }
+ void ResetBufferOffset() { buffer_offset_ = 0; }
+ void* GetPayloadBufPtr();
+
+ private:
+ std::unique_ptr<uint8_t[]> buffer_;
+ loff_t buffer_offset_;
+ size_t buffer_size_;
+};
+
class Snapuserd;
class ReadAheadThread {
@@ -99,10 +116,10 @@ class ReadAheadThread {
bool RunThread();
private:
- void InitializeRAIter();
- bool RAIterDone();
- void RAIterNext();
- const CowOperation* GetRAOpIter();
+ void InitializeIter();
+ bool IterDone();
+ void IterNext();
+ const CowOperation* GetIterOp();
void InitializeBuffer();
bool InitializeFds();
@@ -112,7 +129,7 @@ class ReadAheadThread {
}
bool ReadAheadIOStart();
- void PrepareReadAhead(uint64_t* source_offset, int* pending_ops, std::vector<uint64_t>& blocks);
+ void PrepareReadAhead(uint64_t* source_block, int* pending_ops, std::vector<uint64_t>& blocks);
bool ReconstructDataFromCow();
void CheckOverlap(const CowOperation* cow_op);
@@ -170,9 +187,7 @@ class WorkerThread {
// Processing COW operations
bool ProcessCowOp(const CowOperation* cow_op);
bool ProcessReplaceOp(const CowOperation* cow_op);
- // Handles Copy and Xor
bool ProcessCopyOp(const CowOperation* cow_op);
- bool ProcessXorOp(const CowOperation* cow_op);
bool ProcessZeroOp();
bool ReadFromBaseDevice(const CowOperation* cow_op);
@@ -191,7 +206,6 @@ class WorkerThread {
std::unique_ptr<CowReader> reader_;
BufferSink bufsink_;
- XorSink xorsink_;
std::string cow_device_;
std::string backing_store_device_;
@@ -230,7 +244,6 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
void* GetExceptionBuffer(size_t i) { return vec_[i].get(); }
bool InitializeWorkers();
- std::unique_ptr<CowReader> CloneReaderForWorker();
std::shared_ptr<Snapuserd> GetSharedPtr() { return shared_from_this(); }
std::vector<std::pair<sector_t, const CowOperation*>>& GetChunkVec() { return chunk_vec_; }
@@ -271,7 +284,6 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
// Total number of blocks to be merged in a given read-ahead buffer region
void SetTotalRaBlocksMerged(int x) { total_ra_blocks_merged_ = x; }
int GetTotalRaBlocksMerged() { return total_ra_blocks_merged_; }
- void SetSocketPresent(bool socket) { is_socket_present_ = socket; }
private:
bool IsChunkIdMetadata(chunk_t chunk);
@@ -284,10 +296,6 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
struct BufferState* GetBufferState();
- void ReadBlocks(const std::string& partition_name, const std::string& dm_block_device);
- void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name,
- off_t offset, size_t size);
-
std::string cow_device_;
std::string backing_store_device_;
std::string control_device_;
@@ -298,6 +306,8 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
uint32_t exceptions_per_area_;
uint64_t num_sectors_;
+ std::unique_ptr<ICowOpIter> cowop_iter_;
+ std::unique_ptr<ICowOpReverseIter> cowop_riter_;
std::unique_ptr<CowReader> reader_;
// Vector of disk exception which is a
@@ -327,7 +337,6 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
bool merge_initiated_ = false;
bool attached_ = false;
- bool is_socket_present_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd.rc b/fs_mgr/libsnapshot/snapuserd.rc
new file mode 100644
index 000000000..4bf34a2bd
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd.rc
@@ -0,0 +1,7 @@
+service snapuserd /system/bin/snapuserd
+ socket snapuserd stream 0660 system system
+ oneshot
+ disabled
+ user root
+ group root system
+ seclabel u:r:snapuserd:s0
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
deleted file mode 100644
index bc2bcebbf..000000000
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ /dev/null
@@ -1,200 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_defaults {
- name: "libsnapshot_snapuserd_defaults",
- defaults: [
- "fs_mgr_defaults",
- ],
- cflags: [
- "-D_FILE_OFFSET_BITS=64",
- "-Wall",
- "-Werror",
- ],
- export_include_dirs: ["include"],
- srcs: [
- "snapuserd_client.cpp",
- ],
-}
-
-cc_library_static {
- name: "libsnapshot_snapuserd",
- defaults: [
- "libsnapshot_snapuserd_defaults",
- ],
- recovery_available: true,
- static_libs: [
- "libcutils_sockets",
- ],
- shared_libs: [
- "libbase",
- "liblog",
- ],
- ramdisk_available: true,
-}
-
-cc_defaults {
- name: "snapuserd_defaults",
- defaults: [
- "fs_mgr_defaults",
- ],
- srcs: [
- "dm-snapshot-merge/snapuserd_server.cpp",
- "dm-snapshot-merge/snapuserd.cpp",
- "dm-snapshot-merge/snapuserd_worker.cpp",
- "dm-snapshot-merge/snapuserd_readahead.cpp",
- "snapuserd_daemon.cpp",
- "snapuserd_buffer.cpp",
- "user-space-merge/snapuserd_core.cpp",
- "user-space-merge/snapuserd_dm_user.cpp",
- "user-space-merge/snapuserd_merge.cpp",
- "user-space-merge/snapuserd_readahead.cpp",
- "user-space-merge/snapuserd_transitions.cpp",
- "user-space-merge/snapuserd_server.cpp",
- ],
-
- cflags: [
- "-Wall",
- "-Werror"
- ],
-
- static_libs: [
- "libbase",
- "libbrotli",
- "libcutils_sockets",
- "libdm",
- "libfs_mgr",
- "libgflags",
- "liblog",
- "libsnapshot_cow",
- "libz",
- "libext4_utils",
- "liburing",
- ],
- include_dirs: ["bionic/libc/kernel"],
-}
-
-cc_binary {
- name: "snapuserd",
- defaults: ["snapuserd_defaults"],
- init_rc: [
- "snapuserd.rc",
- ],
-
- // snapuserd is started during early boot by first-stage init. At that
- // point, /system is mounted using the "dm-user" device-mapper kernel
- // module. dm-user routes all I/O to userspace to be handled by
- // snapuserd, which would lead to deadlock if we had to handle page
- // faults for its code pages.
- static_executable: true,
-
- system_shared_libs: [],
- ramdisk_available: true,
- vendor_ramdisk_available: true,
- recovery_available: true,
-
- // Snapuserd segfaults with ThinLTO
- // http://b/208565717
- lto: {
- never: true,
- }
-}
-
-cc_test {
- name: "cow_snapuserd_test",
- defaults: [
- "fs_mgr_defaults",
- ],
- srcs: [
- "dm-snapshot-merge/cow_snapuserd_test.cpp",
- "dm-snapshot-merge/snapuserd.cpp",
- "dm-snapshot-merge/snapuserd_worker.cpp",
- "snapuserd_buffer.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: [
- "libbase",
- "liblog",
- ],
- static_libs: [
- "libbrotli",
- "libgtest",
- "libsnapshot_cow",
- "libsnapshot_snapuserd",
- "libcutils_sockets",
- "libz",
- "libfs_mgr",
- "libdm",
- "libext4_utils",
- ],
- header_libs: [
- "libstorage_literals_headers",
- "libfiemap_headers",
- ],
- test_options: {
- min_shipping_api_level: 30,
- },
- auto_gen_config: true,
- require_root: false,
-}
-
-cc_test {
- name: "snapuserd_test",
- defaults: [
- "fs_mgr_defaults",
- ],
- srcs: [
- "user-space-merge/snapuserd_test.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: [
- "libbase",
- "liblog",
- ],
- static_libs: [
- "libbrotli",
- "libgtest",
- "libsnapshot_cow",
- "libsnapshot_snapuserd",
- "libcutils_sockets",
- "libz",
- "libfs_mgr",
- "libdm",
- "libext4_utils",
- "liburing",
- "libgflags",
- ],
- include_dirs: ["bionic/libc/kernel"],
- header_libs: [
- "libstorage_literals_headers",
- "libfiemap_headers",
- ],
- test_options: {
- min_shipping_api_level: 30,
- },
- auto_gen_config: true,
- require_root: false,
-}
diff --git a/fs_mgr/libsnapshot/snapuserd/OWNERS b/fs_mgr/libsnapshot/snapuserd/OWNERS
deleted file mode 100644
index 2df0a2d84..000000000
--- a/fs_mgr/libsnapshot/snapuserd/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-akailash@google.com
-dvander@google.com
-drosen@google.com
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
deleted file mode 100644
index 2e4cac6c1..000000000
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <linux/types.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <iostream>
-
-#include <libsnapshot/cow_reader.h>
-
-namespace android {
-namespace snapshot {
-
-class BufferSink : public IByteSink {
- public:
- void Initialize(size_t size);
- void* GetBufPtr() { return buffer_.get(); }
- void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
- void* GetPayloadBuffer(size_t size);
- void* GetBuffer(size_t requested, size_t* actual) override;
- void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
- struct dm_user_header* GetHeaderPtr();
- bool ReturnData(void*, size_t) override { return true; }
- void ResetBufferOffset() { buffer_offset_ = 0; }
- void* GetPayloadBufPtr();
-
- private:
- std::unique_ptr<uint8_t[]> buffer_;
- loff_t buffer_offset_;
- size_t buffer_size_;
-};
-
-class XorSink : public IByteSink {
- public:
- void Initialize(BufferSink* sink, size_t size);
- void Reset();
- void* GetBuffer(size_t requested, size_t* actual) override;
- bool ReturnData(void* buffer, size_t len) override;
-
- private:
- BufferSink* bufsink_;
- std::unique_ptr<uint8_t[]> buffer_;
- size_t buffer_size_;
- size_t returned_;
-};
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd.rc b/fs_mgr/libsnapshot/snapuserd/snapuserd.rc
deleted file mode 100644
index 275009603..000000000
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd.rc
+++ /dev/null
@@ -1,19 +0,0 @@
-service snapuserd /system/bin/snapuserd
- socket snapuserd stream 0660 system system
- oneshot
- disabled
- user root
- group root system
- seclabel u:r:snapuserd:s0
-
-service snapuserd_proxy /system/bin/snapuserd -socket-handoff
- socket snapuserd stream 0660 system system
- socket snapuserd_proxy seqpacket 0660 system root
- oneshot
- disabled
- user root
- group root system
- seclabel u:r:snapuserd:s0
-
-on property:init.svc.snapuserd=stopped
- setprop snapuserd.ready false
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
deleted file mode 100644
index ab763ab7e..000000000
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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 <snapuserd/snapuserd_buffer.h>
-#include <snapuserd/snapuserd_kernel.h>
-
-namespace android {
-namespace snapshot {
-
-void BufferSink::Initialize(size_t size) {
- buffer_size_ = size;
- buffer_offset_ = 0;
- buffer_ = std::make_unique<uint8_t[]>(size);
-}
-
-void* BufferSink::GetPayloadBuffer(size_t size) {
- if ((buffer_size_ - buffer_offset_) < size) return nullptr;
-
- char* buffer = reinterpret_cast<char*>(GetBufPtr());
- struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
- return (char*)msg->payload.buf + buffer_offset_;
-}
-
-void* BufferSink::GetBuffer(size_t requested, size_t* actual) {
- void* buf = GetPayloadBuffer(requested);
- if (!buf) {
- *actual = 0;
- return nullptr;
- }
- *actual = requested;
- return buf;
-}
-
-struct dm_user_header* BufferSink::GetHeaderPtr() {
- if (!(sizeof(struct dm_user_header) <= buffer_size_)) {
- return nullptr;
- }
- char* buf = reinterpret_cast<char*>(GetBufPtr());
- struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
- return header;
-}
-
-void* BufferSink::GetPayloadBufPtr() {
- char* buffer = reinterpret_cast<char*>(GetBufPtr());
- struct dm_user_message* msg = reinterpret_cast<struct dm_user_message*>(&(buffer[0]));
- return msg->payload.buf;
-}
-
-void XorSink::Initialize(BufferSink* sink, size_t size) {
- bufsink_ = sink;
- buffer_size_ = size;
- returned_ = 0;
- buffer_ = std::make_unique<uint8_t[]>(size);
-}
-
-void XorSink::Reset() {
- returned_ = 0;
-}
-
-void* XorSink::GetBuffer(size_t requested, size_t* actual) {
- if (requested > buffer_size_) {
- *actual = buffer_size_;
- } else {
- *actual = requested;
- }
- return buffer_.get();
-}
-
-bool XorSink::ReturnData(void* buffer, size_t len) {
- uint8_t* xor_data = reinterpret_cast<uint8_t*>(buffer);
- uint8_t* buff = reinterpret_cast<uint8_t*>(bufsink_->GetPayloadBuffer(len + returned_));
- if (buff == nullptr) {
- return false;
- }
- for (size_t i = 0; i < len; i++) {
- buff[returned_ + i] ^= xor_data[i];
- }
- returned_ += len;
- return true;
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
deleted file mode 100644
index 2f7775cd1..000000000
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <gflags/gflags.h>
-#include <snapuserd/snapuserd_client.h>
-
-#include "snapuserd_daemon.h"
-
-DEFINE_string(socket, android::snapshot::kSnapuserdSocket, "Named socket or socket path.");
-DEFINE_bool(no_socket, false,
- "If true, no socket is used. Each additional argument is an INIT message.");
-DEFINE_bool(socket_handoff, false,
- "If true, perform a socket hand-off with an existing snapuserd instance, then exit.");
-DEFINE_bool(user_snapshot, false, "If true, user-space snapshots are used");
-DEFINE_bool(io_uring, false, "If true, io_uring feature is enabled");
-
-namespace android {
-namespace snapshot {
-
-bool Daemon::IsUserspaceSnapshotsEnabled() {
- const std::string UNKNOWN = "unknown";
- const std::string vendor_release =
- android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
-
- // No user-space snapshots if vendor partition is on Android 12
- if (vendor_release.find("12") != std::string::npos) {
- LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
- << vendor_release;
- return false;
- }
-
- return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
-}
-
-bool Daemon::IsDmSnapshotTestingEnabled() {
- return android::base::GetBoolProperty("snapuserd.test.dm.snapshots", false);
-}
-
-bool Daemon::StartDaemon(int argc, char** argv) {
- int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, true);
-
- // Daemon launched from first stage init and during selinux transition
- // will have the command line "-user_snapshot" flag set if the user-space
- // snapshots are enabled.
- //
- // Daemon launched as a init service during "socket-handoff" and when OTA
- // is applied will check for the property. This is ok as the system
- // properties are valid at this point. We can't do this during first
- // stage init and hence use the command line flags to get the information.
- bool user_snapshots = FLAGS_user_snapshot;
- if (!user_snapshots) {
- user_snapshots = (!IsDmSnapshotTestingEnabled() && IsUserspaceSnapshotsEnabled());
- }
-
- if (user_snapshots) {
- LOG(INFO) << "Starting daemon for user-space snapshots.....";
- return StartServerForUserspaceSnapshots(arg_start, argc, argv);
- } else {
- LOG(INFO) << "Starting daemon for dm-snapshots.....";
- return StartServerForDmSnapshot(arg_start, argc, argv);
- }
-}
-
-bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** argv) {
- sigfillset(&signal_mask_);
- sigdelset(&signal_mask_, SIGINT);
- sigdelset(&signal_mask_, SIGTERM);
- sigdelset(&signal_mask_, SIGUSR1);
-
- // Masking signals here ensure that after this point, we won't handle INT/TERM
- // until after we call into ppoll()
- signal(SIGINT, Daemon::SignalHandler);
- signal(SIGTERM, Daemon::SignalHandler);
- signal(SIGPIPE, Daemon::SignalHandler);
- signal(SIGUSR1, Daemon::SignalHandler);
-
- MaskAllSignalsExceptIntAndTerm();
-
- user_server_.SetServerRunning();
- if (FLAGS_io_uring) {
- user_server_.SetIouringEnabled();
- }
-
- if (FLAGS_socket_handoff) {
- return user_server_.RunForSocketHandoff();
- }
- if (!FLAGS_no_socket) {
- if (!user_server_.Start(FLAGS_socket)) {
- return false;
- }
- return user_server_.Run();
- }
-
- for (int i = arg_start; i < argc; i++) {
- auto parts = android::base::Split(argv[i], ",");
- if (parts.size() != 4) {
- LOG(ERROR) << "Malformed message, expected three sub-arguments.";
- return false;
- }
- auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]);
- if (!handler || !user_server_.StartHandler(handler)) {
- return false;
- }
- }
-
- // Skip the accept() call to avoid spurious log spam. The server will still
- // run until all handlers have completed.
- return user_server_.WaitForSocket();
-}
-
-bool Daemon::StartServerForDmSnapshot(int arg_start, int argc, char** argv) {
- sigfillset(&signal_mask_);
- sigdelset(&signal_mask_, SIGINT);
- sigdelset(&signal_mask_, SIGTERM);
- sigdelset(&signal_mask_, SIGUSR1);
-
- // Masking signals here ensure that after this point, we won't handle INT/TERM
- // until after we call into ppoll()
- signal(SIGINT, Daemon::SignalHandler);
- signal(SIGTERM, Daemon::SignalHandler);
- signal(SIGPIPE, Daemon::SignalHandler);
- signal(SIGUSR1, Daemon::SignalHandler);
-
- MaskAllSignalsExceptIntAndTerm();
-
- if (FLAGS_socket_handoff) {
- return server_.RunForSocketHandoff();
- }
- if (!FLAGS_no_socket) {
- if (!server_.Start(FLAGS_socket)) {
- return false;
- }
- return server_.Run();
- }
-
- for (int i = arg_start; i < argc; i++) {
- auto parts = android::base::Split(argv[i], ",");
- if (parts.size() != 3) {
- LOG(ERROR) << "Malformed message, expected three sub-arguments.";
- return false;
- }
- auto handler = server_.AddHandler(parts[0], parts[1], parts[2]);
- if (!handler || !server_.StartHandler(handler)) {
- return false;
- }
- }
-
- // Skip the accept() call to avoid spurious log spam. The server will still
- // run until all handlers have completed.
- return server_.WaitForSocket();
-}
-
-void Daemon::MaskAllSignalsExceptIntAndTerm() {
- sigset_t signal_mask;
- sigfillset(&signal_mask);
- sigdelset(&signal_mask, SIGINT);
- sigdelset(&signal_mask, SIGTERM);
- sigdelset(&signal_mask, SIGPIPE);
- sigdelset(&signal_mask, SIGUSR1);
- if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
- PLOG(ERROR) << "Failed to set sigprocmask";
- }
-}
-
-void Daemon::MaskAllSignals() {
- sigset_t signal_mask;
- sigfillset(&signal_mask);
- if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
- PLOG(ERROR) << "Couldn't mask all signals";
- }
-}
-
-void Daemon::Interrupt() {
- // TODO: We cannot access system property during first stage init.
- // Until we remove the dm-snapshot code, we will have this check
- // and verify it through a temp variable.
- if (user_server_.IsServerRunning()) {
- user_server_.Interrupt();
- } else {
- server_.Interrupt();
- }
-}
-
-void Daemon::ReceivedSocketSignal() {
- if (user_server_.IsServerRunning()) {
- user_server_.ReceivedSocketSignal();
- } else {
- server_.ReceivedSocketSignal();
- }
-}
-
-void Daemon::SignalHandler(int signal) {
- LOG(DEBUG) << "Snapuserd received signal: " << signal;
- switch (signal) {
- case SIGINT:
- case SIGTERM: {
- Daemon::Instance().Interrupt();
- break;
- }
- case SIGPIPE: {
- LOG(ERROR) << "Received SIGPIPE signal";
- break;
- }
- case SIGUSR1: {
- LOG(INFO) << "Received SIGUSR1, attaching to proxy socket";
- Daemon::Instance().ReceivedSocketSignal();
- break;
- }
- default:
- LOG(ERROR) << "Received unknown signal " << signal;
- break;
- }
-}
-
-} // namespace snapshot
-} // namespace android
-
-int main(int argc, char** argv) {
- android::base::InitLogging(argv, &android::base::KernelLogger);
-
- android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
-
- if (!daemon.StartDaemon(argc, argv)) {
- LOG(ERROR) << "Snapuserd daemon failed to start";
- exit(EXIT_FAILURE);
- }
-
- return 0;
-}
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
deleted file mode 100644
index 692cb740c..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
- * 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 "snapuserd_core.h"
-
-#include <sys/utsname.h>
-
-#include <android-base/properties.h>
-#include <android-base/scopeguard.h>
-#include <android-base/strings.h>
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-SnapshotHandler::SnapshotHandler(std::string misc_name, std::string cow_device,
- std::string backing_device, std::string base_path_merge) {
- misc_name_ = std::move(misc_name);
- cow_device_ = std::move(cow_device);
- backing_store_device_ = std::move(backing_device);
- control_device_ = "/dev/dm-user/" + misc_name_;
- base_path_merge_ = std::move(base_path_merge);
-}
-
-bool SnapshotHandler::InitializeWorkers() {
- int num_worker_threads = kNumWorkerThreads;
-
- // We will need multiple worker threads only during
- // device boot after OTA. For all other purposes,
- // one thread is sufficient. We don't want to consume
- // unnecessary memory especially during OTA install phase
- // when daemon will be up during entire post install phase.
- //
- // During boot up, we need multiple threads primarily for
- // update-verification.
- if (is_socket_present_) {
- num_worker_threads = 1;
- }
-
- for (int i = 0; i < num_worker_threads; i++) {
- std::unique_ptr<Worker> wt =
- std::make_unique<Worker>(cow_device_, backing_store_device_, control_device_,
- misc_name_, base_path_merge_, GetSharedPtr());
- if (!wt->Init()) {
- SNAP_LOG(ERROR) << "Thread initialization failed";
- return false;
- }
-
- worker_threads_.push_back(std::move(wt));
- }
-
- merge_thread_ = std::make_unique<Worker>(cow_device_, backing_store_device_, control_device_,
- misc_name_, base_path_merge_, GetSharedPtr());
-
- read_ahead_thread_ = std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_,
- GetSharedPtr());
- return true;
-}
-
-std::unique_ptr<CowReader> SnapshotHandler::CloneReaderForWorker() {
- return reader_->CloneCowReader();
-}
-
-void SnapshotHandler::UpdateMergeCompletionPercentage() {
- struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
- merge_completion_percentage_ = (ch->num_merge_ops * 100.0) / reader_->get_num_total_data_ops();
-
- SNAP_LOG(DEBUG) << "Merge-complete %: " << merge_completion_percentage_
- << " num_merge_ops: " << ch->num_merge_ops
- << " total-ops: " << reader_->get_num_total_data_ops();
-}
-
-bool SnapshotHandler::CommitMerge(int num_merge_ops) {
- struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
- ch->num_merge_ops += num_merge_ops;
-
- if (scratch_space_) {
- if (ra_thread_) {
- struct BufferState* ra_state = GetBufferState();
- ra_state->read_ahead_state = kCowReadAheadInProgress;
- }
-
- int ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC);
- if (ret < 0) {
- SNAP_PLOG(ERROR) << "msync header failed: " << ret;
- return false;
- }
- } else {
- reader_->UpdateMergeOpsCompleted(num_merge_ops);
- CowHeader header;
- reader_->GetHeader(&header);
-
- if (lseek(cow_fd_.get(), 0, SEEK_SET) < 0) {
- SNAP_PLOG(ERROR) << "lseek failed";
- return false;
- }
-
- if (!android::base::WriteFully(cow_fd_, &header, sizeof(CowHeader))) {
- SNAP_PLOG(ERROR) << "Write to header failed";
- return false;
- }
-
- if (fsync(cow_fd_.get()) < 0) {
- SNAP_PLOG(ERROR) << "fsync failed";
- return false;
- }
- }
-
- // Update the merge completion - this is used by update engine
- // to track the completion. No need to take a lock. It is ok
- // even if there is a miss on reading a latest updated value.
- // Subsequent polling will eventually converge to completion.
- UpdateMergeCompletionPercentage();
-
- return true;
-}
-
-void SnapshotHandler::PrepareReadAhead() {
- struct BufferState* ra_state = GetBufferState();
- // Check if the data has to be re-constructed from COW device
- if (ra_state->read_ahead_state == kCowReadAheadDone) {
- populate_data_from_cow_ = true;
- } else {
- populate_data_from_cow_ = false;
- }
-
- NotifyRAForMergeReady();
-}
-
-void SnapshotHandler::CheckMergeCompletionStatus() {
- if (!merge_initiated_) {
- SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: "
- << reader_->get_num_total_data_ops();
- return;
- }
-
- struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
-
- SNAP_LOG(INFO) << "Merge-status: Total-Merged-ops: " << ch->num_merge_ops
- << " Total-data-ops: " << reader_->get_num_total_data_ops();
-}
-
-bool SnapshotHandler::ReadMetadata() {
- reader_ = std::make_unique<CowReader>(CowReader::ReaderFlags::USERSPACE_MERGE);
- CowHeader header;
- CowOptions options;
-
- SNAP_LOG(DEBUG) << "ReadMetadata: Parsing cow file";
-
- if (!reader_->Parse(cow_fd_)) {
- SNAP_LOG(ERROR) << "Failed to parse";
- return false;
- }
-
- if (!reader_->GetHeader(&header)) {
- SNAP_LOG(ERROR) << "Failed to get header";
- return false;
- }
-
- if (!(header.block_size == BLOCK_SZ)) {
- SNAP_LOG(ERROR) << "Invalid header block size found: " << header.block_size;
- return false;
- }
-
- SNAP_LOG(INFO) << "Merge-ops: " << header.num_merge_ops;
-
- if (!MmapMetadata()) {
- SNAP_LOG(ERROR) << "mmap failed";
- return false;
- }
-
- UpdateMergeCompletionPercentage();
-
- // Initialize the iterator for reading metadata
- std::unique_ptr<ICowOpIter> cowop_iter = reader_->GetMergeOpIter();
-
- int num_ra_ops_per_iter = ((GetBufferDataSize()) / BLOCK_SZ);
- int ra_index = 0;
-
- size_t copy_ops = 0, replace_ops = 0, zero_ops = 0, xor_ops = 0;
-
- while (!cowop_iter->Done()) {
- const CowOperation* cow_op = &cowop_iter->Get();
-
- if (cow_op->type == kCowCopyOp) {
- copy_ops += 1;
- } else if (cow_op->type == kCowReplaceOp) {
- replace_ops += 1;
- } else if (cow_op->type == kCowZeroOp) {
- zero_ops += 1;
- } else if (cow_op->type == kCowXorOp) {
- xor_ops += 1;
- }
-
- chunk_vec_.push_back(std::make_pair(ChunkToSector(cow_op->new_block), cow_op));
-
- if (IsOrderedOp(*cow_op)) {
- ra_thread_ = true;
- block_to_ra_index_[cow_op->new_block] = ra_index;
- num_ra_ops_per_iter -= 1;
-
- if ((ra_index + 1) - merge_blk_state_.size() == 1) {
- std::unique_ptr<MergeGroupState> blk_state = std::make_unique<MergeGroupState>(
- MERGE_GROUP_STATE::GROUP_MERGE_PENDING, 0);
-
- merge_blk_state_.push_back(std::move(blk_state));
- }
-
- // Move to next RA block
- if (num_ra_ops_per_iter == 0) {
- num_ra_ops_per_iter = ((GetBufferDataSize()) / BLOCK_SZ);
- ra_index += 1;
- }
- }
- cowop_iter->Next();
- }
-
- chunk_vec_.shrink_to_fit();
-
- // Sort the vector based on sectors as we need this during un-aligned access
- std::sort(chunk_vec_.begin(), chunk_vec_.end(), compare);
-
- PrepareReadAhead();
-
- SNAP_LOG(INFO) << "Merged-ops: " << header.num_merge_ops
- << " Total-data-ops: " << reader_->get_num_total_data_ops()
- << " Unmerged-ops: " << chunk_vec_.size() << " Copy-ops: " << copy_ops
- << " Zero-ops: " << zero_ops << " Replace-ops: " << replace_ops
- << " Xor-ops: " << xor_ops;
-
- return true;
-}
-
-bool SnapshotHandler::MmapMetadata() {
- CowHeader header;
- reader_->GetHeader(&header);
-
- total_mapped_addr_length_ = header.header_size + BUFFER_REGION_DEFAULT_SIZE;
-
- if (header.major_version >= 2 && header.buffer_size > 0) {
- scratch_space_ = true;
- }
-
- if (scratch_space_) {
- mapped_addr_ = mmap(NULL, total_mapped_addr_length_, PROT_READ | PROT_WRITE, MAP_SHARED,
- cow_fd_.get(), 0);
- } else {
- mapped_addr_ = mmap(NULL, total_mapped_addr_length_, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
- ch->num_merge_ops = header.num_merge_ops;
- }
-
- if (mapped_addr_ == MAP_FAILED) {
- SNAP_LOG(ERROR) << "mmap metadata failed";
- return false;
- }
-
- return true;
-}
-
-void SnapshotHandler::UnmapBufferRegion() {
- int ret = munmap(mapped_addr_, total_mapped_addr_length_);
- if (ret < 0) {
- SNAP_PLOG(ERROR) << "munmap failed";
- }
-}
-
-bool SnapshotHandler::InitCowDevice() {
- cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
- if (cow_fd_ < 0) {
- SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
- return false;
- }
-
- unique_fd fd(TEMP_FAILURE_RETRY(open(base_path_merge_.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd < 0) {
- SNAP_LOG(ERROR) << "Cannot open block device";
- return false;
- }
-
- uint64_t dev_sz = get_block_device_size(fd.get());
- if (!dev_sz) {
- SNAP_LOG(ERROR) << "Failed to find block device size: " << base_path_merge_;
- return false;
- }
-
- num_sectors_ = dev_sz >> SECTOR_SHIFT;
-
- return ReadMetadata();
-}
-
-void SnapshotHandler::FinalizeIouring() {
- io_uring_queue_exit(ring_.get());
-}
-
-bool SnapshotHandler::InitializeIouring(int io_depth) {
- ring_ = std::make_unique<struct io_uring>();
-
- int ret = io_uring_queue_init(io_depth, ring_.get(), 0);
- if (ret) {
- LOG(ERROR) << "io_uring_queue_init failed with ret: " << ret;
- return false;
- }
-
- LOG(INFO) << "io_uring_queue_init success with io_depth: " << io_depth;
- return true;
-}
-
-bool SnapshotHandler::ReadBlocksAsync(const std::string& dm_block_device,
- const std::string& partition_name, size_t size) {
- // 64k block size with io_depth of 64 is optimal
- // for a single thread. We just need a single thread
- // to read all the blocks from all dynamic partitions.
- size_t io_depth = 64;
- size_t bs = (64 * 1024);
-
- if (!InitializeIouring(io_depth)) {
- return false;
- }
-
- LOG(INFO) << "ReadBlockAsync start "
- << " Block-device: " << dm_block_device << " Partition-name: " << partition_name
- << " Size: " << size;
-
- auto scope_guard = android::base::make_scope_guard([this]() -> void { FinalizeIouring(); });
-
- std::vector<std::unique_ptr<struct iovec>> vecs;
- using AlignedBuf = std::unique_ptr<void, decltype(free)*>;
- std::vector<AlignedBuf> alignedBufVector;
-
- /*
- * TODO: We need aligned memory for DIRECT-IO. However, if we do
- * a DIRECT-IO and verify the blocks then we need to inform
- * update-verifier that block verification has been done and
- * there is no need to repeat the same. We are not there yet
- * as we need to see if there are any boot time improvements doing
- * a DIRECT-IO.
- *
- * Also, we could you the same function post merge for block verification;
- * again, we can do a DIRECT-IO instead of thrashing page-cache and
- * hurting other applications.
- *
- * For now, we will just create aligned buffers but rely on buffered
- * I/O until we have perf numbers to justify DIRECT-IO.
- */
- for (int i = 0; i < io_depth; i++) {
- auto iovec = std::make_unique<struct iovec>();
- vecs.push_back(std::move(iovec));
-
- struct iovec* iovec_ptr = vecs[i].get();
-
- if (posix_memalign(&iovec_ptr->iov_base, BLOCK_SZ, bs)) {
- LOG(ERROR) << "posix_memalign failed";
- return false;
- }
-
- iovec_ptr->iov_len = bs;
- alignedBufVector.push_back(
- std::unique_ptr<void, decltype(free)*>(iovec_ptr->iov_base, free));
- }
-
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
- if (fd.get() == -1) {
- SNAP_PLOG(ERROR) << "File open failed - block-device " << dm_block_device
- << " partition-name: " << partition_name;
- return false;
- }
-
- loff_t offset = 0;
- size_t remain = size;
- size_t read_sz = io_depth * bs;
-
- while (remain > 0) {
- size_t to_read = std::min(remain, read_sz);
- size_t queue_size = to_read / bs;
-
- for (int i = 0; i < queue_size; i++) {
- struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get());
- if (!sqe) {
- SNAP_LOG(ERROR) << "io_uring_get_sqe() failed";
- return false;
- }
-
- struct iovec* iovec_ptr = vecs[i].get();
-
- io_uring_prep_read(sqe, fd.get(), iovec_ptr->iov_base, iovec_ptr->iov_len, offset);
- sqe->flags |= IOSQE_ASYNC;
- offset += bs;
- }
-
- int ret = io_uring_submit(ring_.get());
- if (ret != queue_size) {
- SNAP_LOG(ERROR) << "submit got: " << ret << " wanted: " << queue_size;
- return false;
- }
-
- for (int i = 0; i < queue_size; i++) {
- struct io_uring_cqe* cqe;
-
- int ret = io_uring_wait_cqe(ring_.get(), &cqe);
- if (ret) {
- SNAP_PLOG(ERROR) << "wait_cqe failed" << ret;
- return false;
- }
-
- if (cqe->res < 0) {
- SNAP_LOG(ERROR) << "io failed with res: " << cqe->res;
- return false;
- }
- io_uring_cqe_seen(ring_.get(), cqe);
- }
-
- remain -= to_read;
- }
-
- LOG(INFO) << "ReadBlockAsync complete: "
- << " Block-device: " << dm_block_device << " Partition-name: " << partition_name
- << " Size: " << size;
- return true;
-}
-
-void SnapshotHandler::ReadBlocksToCache(const std::string& dm_block_device,
- const std::string& partition_name, off_t offset,
- size_t size) {
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
- if (fd.get() == -1) {
- SNAP_PLOG(ERROR) << "Error reading " << dm_block_device
- << " partition-name: " << partition_name;
- return;
- }
-
- size_t remain = size;
- off_t file_offset = offset;
- // We pick 4M I/O size based on the fact that the current
- // update_verifier has a similar I/O size.
- size_t read_sz = 1024 * BLOCK_SZ;
- std::vector<uint8_t> buf(read_sz);
-
- while (remain > 0) {
- size_t to_read = std::min(remain, read_sz);
-
- if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) {
- SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device
- << " at offset: " << file_offset
- << " partition-name: " << partition_name << " total-size: " << size
- << " remain_size: " << remain;
- return;
- }
-
- file_offset += to_read;
- remain -= to_read;
- }
-
- SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device
- << " partition: " << partition_name << " size: " << size
- << " offset: " << offset;
-}
-
-void SnapshotHandler::ReadBlocks(const std::string partition_name,
- const std::string& dm_block_device) {
- SNAP_LOG(DEBUG) << "Reading partition: " << partition_name
- << " Block-Device: " << dm_block_device;
-
- uint64_t dev_sz = 0;
-
- unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd < 0) {
- SNAP_LOG(ERROR) << "Cannot open block device";
- return;
- }
-
- dev_sz = get_block_device_size(fd.get());
- if (!dev_sz) {
- SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device;
- return;
- }
-
- int num_threads = 2;
- size_t num_blocks = dev_sz >> BLOCK_SHIFT;
- size_t num_blocks_per_thread = num_blocks / num_threads;
- size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT;
- off_t offset = 0;
-
- for (int i = 0; i < num_threads; i++) {
- std::async(std::launch::async, &SnapshotHandler::ReadBlocksToCache, this, dm_block_device,
- partition_name, offset, read_sz_per_thread);
-
- offset += read_sz_per_thread;
- }
-}
-
-/*
- * Entry point to launch threads
- */
-bool SnapshotHandler::Start() {
- std::vector<std::future<bool>> threads;
- std::future<bool> ra_thread_status;
-
- if (ra_thread_) {
- ra_thread_status =
- std::async(std::launch::async, &ReadAhead::RunThread, read_ahead_thread_.get());
-
- SNAP_LOG(INFO) << "Read-ahead thread started...";
- }
-
- // Launch worker threads
- for (int i = 0; i < worker_threads_.size(); i++) {
- threads.emplace_back(
- std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get()));
- }
-
- bool second_stage_init = true;
-
- // We don't want to read the blocks during first stage init.
- if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) {
- second_stage_init = false;
- }
-
- if (second_stage_init) {
- SNAP_LOG(INFO) << "Reading blocks to cache....";
- auto& dm = DeviceMapper::Instance();
- auto dm_block_devices = dm.FindDmPartitions();
- if (dm_block_devices.empty()) {
- SNAP_LOG(ERROR) << "No dm-enabled block device is found.";
- } else {
- auto parts = android::base::Split(misc_name_, "-");
- std::string partition_name = parts[0];
-
- const char* suffix_b = "_b";
- const char* suffix_a = "_a";
-
- partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1);
- partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1);
-
- if (dm_block_devices.find(partition_name) == dm_block_devices.end()) {
- SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name;
- } else {
- ReadBlocks(partition_name, dm_block_devices.at(partition_name));
- }
- }
- } else {
- SNAP_LOG(INFO) << "Not reading block device into cache";
- }
-
- std::future<bool> merge_thread =
- std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get());
-
- bool ret = true;
- for (auto& t : threads) {
- ret = t.get() && ret;
- }
-
- // Worker threads are terminated by this point - this can only happen:
- //
- // 1: If dm-user device is destroyed
- // 2: We had an I/O failure when reading root partitions
- //
- // In case (1), this would be a graceful shutdown. In this case, merge
- // thread and RA thread should have already terminated by this point. We will be
- // destroying the dm-user device only _after_ merge is completed.
- //
- // In case (2), if merge thread had started, then it will be
- // continuing to merge; however, since we had an I/O failure and the
- // I/O on root partitions are no longer served, we will terminate the
- // merge
-
- NotifyIOTerminated();
-
- bool read_ahead_retval = false;
-
- SNAP_LOG(INFO) << "Snapshot I/O terminated. Waiting for merge thread....";
- bool merge_thread_status = merge_thread.get();
-
- if (ra_thread_) {
- read_ahead_retval = ra_thread_status.get();
- }
-
- SNAP_LOG(INFO) << "Worker threads terminated with ret: " << ret
- << " Merge-thread with ret: " << merge_thread_status
- << " RA-thread with ret: " << read_ahead_retval;
- return ret;
-}
-
-uint64_t SnapshotHandler::GetBufferMetadataOffset() {
- CowHeader header;
- reader_->GetHeader(&header);
-
- return (header.header_size + sizeof(BufferState));
-}
-
-/*
- * Metadata for read-ahead is 16 bytes. For a 2 MB region, we will
- * end up with 8k (2 PAGE) worth of metadata. Thus, a 2MB buffer
- * region is split into:
- *
- * 1: 8k metadata
- * 2: Scratch space
- *
- */
-size_t SnapshotHandler::GetBufferMetadataSize() {
- CowHeader header;
- reader_->GetHeader(&header);
- size_t buffer_size = header.buffer_size;
-
- // If there is no scratch space, then just use the
- // anonymous memory
- if (buffer_size == 0) {
- buffer_size = BUFFER_REGION_DEFAULT_SIZE;
- }
-
- return ((buffer_size * sizeof(struct ScratchMetadata)) / BLOCK_SZ);
-}
-
-size_t SnapshotHandler::GetBufferDataOffset() {
- CowHeader header;
- reader_->GetHeader(&header);
-
- return (header.header_size + GetBufferMetadataSize());
-}
-
-/*
- * (2MB - 8K = 2088960 bytes) will be the buffer region to hold the data.
- */
-size_t SnapshotHandler::GetBufferDataSize() {
- CowHeader header;
- reader_->GetHeader(&header);
- size_t buffer_size = header.buffer_size;
-
- // If there is no scratch space, then just use the
- // anonymous memory
- if (buffer_size == 0) {
- buffer_size = BUFFER_REGION_DEFAULT_SIZE;
- }
-
- return (buffer_size - GetBufferMetadataSize());
-}
-
-struct BufferState* SnapshotHandler::GetBufferState() {
- CowHeader header;
- reader_->GetHeader(&header);
-
- struct BufferState* ra_state =
- reinterpret_cast<struct BufferState*>((char*)mapped_addr_ + header.header_size);
- return ra_state;
-}
-
-bool SnapshotHandler::IsIouringSupported() {
- struct utsname uts;
- unsigned int major, minor;
-
- if (android::base::GetBoolProperty("snapuserd.test.io_uring.force_disable", false)) {
- SNAP_LOG(INFO) << "io_uring disabled for testing";
- return false;
- }
-
- if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) {
- SNAP_LOG(ERROR) << "Could not parse the kernel version from uname. "
- << " io_uring not supported";
- return false;
- }
-
- // We will only support kernels from 5.6 onwards as IOSQE_ASYNC flag and
- // IO_URING_OP_READ/WRITE opcodes were introduced only on 5.6 kernel
- if (major >= 5) {
- if (major == 5 && minor < 6) {
- return false;
- }
- } else {
- return false;
- }
-
- // During selinux init transition, libsnapshot will propagate the
- // status of io_uring enablement. As properties are not initialized,
- // we cannot query system property.
- if (is_io_uring_enabled_) {
- return true;
- }
-
- // Finally check the system property
- return android::base::GetBoolProperty("ro.virtual_ab.io_uring.enabled", false);
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
deleted file mode 100644
index 83d40f635..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ /dev/null
@@ -1,419 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <linux/types.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-
-#include <condition_variable>
-#include <cstring>
-#include <future>
-#include <iostream>
-#include <limits>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <ext4_utils/ext4_utils.h>
-#include <libdm/dm.h>
-#include <libsnapshot/cow_reader.h>
-#include <libsnapshot/cow_writer.h>
-#include <liburing.h>
-#include <snapuserd/snapuserd_buffer.h>
-#include <snapuserd/snapuserd_kernel.h>
-
-namespace android {
-namespace snapshot {
-
-using android::base::unique_fd;
-using namespace std::chrono_literals;
-
-static constexpr size_t PAYLOAD_BUFFER_SZ = (1UL << 20);
-static_assert(PAYLOAD_BUFFER_SZ >= BLOCK_SZ);
-
-static constexpr int kNumWorkerThreads = 4;
-
-#define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
-#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
-
-enum class MERGE_IO_TRANSITION {
- MERGE_READY,
- MERGE_BEGIN,
- MERGE_FAILED,
- MERGE_COMPLETE,
- IO_TERMINATED,
- READ_AHEAD_FAILURE,
-};
-
-class SnapshotHandler;
-
-enum class MERGE_GROUP_STATE {
- GROUP_MERGE_PENDING,
- GROUP_MERGE_RA_READY,
- GROUP_MERGE_IN_PROGRESS,
- GROUP_MERGE_COMPLETED,
- GROUP_MERGE_FAILED,
- GROUP_INVALID,
-};
-
-struct MergeGroupState {
- MERGE_GROUP_STATE merge_state_;
- // Ref count I/O when group state
- // is in "GROUP_MERGE_PENDING"
- size_t num_ios_in_progress;
- std::mutex m_lock;
- std::condition_variable m_cv;
-
- MergeGroupState(MERGE_GROUP_STATE state, size_t n_ios)
- : merge_state_(state), num_ios_in_progress(n_ios) {}
-};
-
-class ReadAhead {
- public:
- ReadAhead(const std::string& cow_device, const std::string& backing_device,
- const std::string& misc_name, std::shared_ptr<SnapshotHandler> snapuserd);
- bool RunThread();
-
- private:
- void InitializeRAIter();
- bool RAIterDone();
- void RAIterNext();
- void RAResetIter(uint64_t num_blocks);
- const CowOperation* GetRAOpIter();
-
- void InitializeBuffer();
- bool InitReader();
- bool InitializeFds();
-
- void CloseFds() { backing_store_fd_ = {}; }
-
- bool ReadAheadIOStart();
- int PrepareNextReadAhead(uint64_t* source_offset, int* pending_ops,
- std::vector<uint64_t>& blocks,
- std::vector<const CowOperation*>& xor_op_vec);
- bool ReconstructDataFromCow();
- void CheckOverlap(const CowOperation* cow_op);
-
- bool ReadAheadAsyncIO();
- bool ReapIoCompletions(int pending_ios_to_complete);
- bool ReadXorData(size_t block_index, size_t xor_op_index,
- std::vector<const CowOperation*>& xor_op_vec);
- void ProcessXorData(size_t& block_xor_index, size_t& xor_index,
- std::vector<const CowOperation*>& xor_op_vec, void* buffer,
- loff_t& buffer_offset);
- void UpdateScratchMetadata();
-
- bool ReadAheadSyncIO();
- bool InitializeIouring();
- void FinalizeIouring();
-
- void* read_ahead_buffer_;
- void* metadata_buffer_;
-
- std::unique_ptr<ICowOpIter> cowop_iter_;
-
- std::string cow_device_;
- std::string backing_store_device_;
- std::string misc_name_;
-
- unique_fd cow_fd_;
- unique_fd backing_store_fd_;
-
- std::shared_ptr<SnapshotHandler> snapuserd_;
- std::unique_ptr<CowReader> reader_;
-
- std::unordered_set<uint64_t> dest_blocks_;
- std::unordered_set<uint64_t> source_blocks_;
- bool overlap_;
- std::vector<uint64_t> blocks_;
- int total_blocks_merged_ = 0;
- std::unique_ptr<uint8_t[]> ra_temp_buffer_;
- std::unique_ptr<uint8_t[]> ra_temp_meta_buffer_;
- BufferSink bufsink_;
-
- uint64_t total_ra_blocks_completed_ = 0;
- bool read_ahead_async_ = false;
- // Queue depth of 8 seems optimal. We don't want
- // to have a huge depth as it may put more memory pressure
- // on the kernel worker threads given that we use
- // IOSQE_ASYNC flag - ASYNC flags can potentially
- // result in EINTR; Since we don't restart
- // syscalls and fallback to synchronous I/O, we
- // don't want huge queue depth
- int queue_depth_ = 8;
- std::unique_ptr<struct io_uring> ring_;
-};
-
-class Worker {
- public:
- Worker(const std::string& cow_device, const std::string& backing_device,
- const std::string& control_device, const std::string& misc_name,
- const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd);
- bool RunThread();
- bool RunMergeThread();
- bool Init();
-
- private:
- // Initialization
- void InitializeBufsink();
- bool InitializeFds();
- bool InitReader();
- void CloseFds() {
- ctrl_fd_ = {};
- backing_store_fd_ = {};
- base_path_merge_fd_ = {};
- }
-
- // Functions interacting with dm-user
- bool ReadDmUserHeader();
- bool WriteDmUserPayload(size_t size, bool header_response);
- bool DmuserReadRequest();
-
- // IO Path
- bool ProcessIORequest();
- bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); }
-
- bool ReadDataFromBaseDevice(sector_t sector, size_t read_size);
- bool ReadFromSourceDevice(const CowOperation* cow_op);
-
- bool ReadAlignedSector(sector_t sector, size_t sz, bool header_response);
- bool ReadUnalignedSector(sector_t sector, size_t size);
- int ReadUnalignedSector(sector_t sector, size_t size,
- std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it);
- bool RespondIOError(bool header_response);
-
- // Processing COW operations
- bool ProcessCowOp(const CowOperation* cow_op);
- bool ProcessReplaceOp(const CowOperation* cow_op);
- bool ProcessZeroOp();
-
- // Handles Copy and Xor
- bool ProcessCopyOp(const CowOperation* cow_op);
- bool ProcessXorOp(const CowOperation* cow_op);
- bool ProcessOrderedOp(const CowOperation* cow_op);
-
- // Merge related ops
- bool Merge();
- bool AsyncMerge();
- bool SyncMerge();
- bool MergeOrderedOps();
- bool MergeOrderedOpsAsync();
- bool MergeReplaceZeroOps();
- int PrepareMerge(uint64_t* source_offset, int* pending_ops,
- std::vector<const CowOperation*>* replace_zero_vec = nullptr);
-
- sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
- chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; }
-
- bool InitializeIouring();
- void FinalizeIouring();
-
- std::unique_ptr<CowReader> reader_;
- BufferSink bufsink_;
- XorSink xorsink_;
-
- std::string cow_device_;
- std::string backing_store_device_;
- std::string control_device_;
- std::string misc_name_;
- std::string base_path_merge_;
-
- unique_fd cow_fd_;
- unique_fd backing_store_fd_;
- unique_fd base_path_merge_fd_;
- unique_fd ctrl_fd_;
-
- std::unique_ptr<ICowOpIter> cowop_iter_;
- size_t ra_block_index_ = 0;
- uint64_t blocks_merged_in_group_ = 0;
- bool merge_async_ = false;
- // Queue depth of 8 seems optimal. We don't want
- // to have a huge depth as it may put more memory pressure
- // on the kernel worker threads given that we use
- // IOSQE_ASYNC flag - ASYNC flags can potentially
- // result in EINTR; Since we don't restart
- // syscalls and fallback to synchronous I/O, we
- // don't want huge queue depth
- int queue_depth_ = 8;
- std::unique_ptr<struct io_uring> ring_;
-
- std::shared_ptr<SnapshotHandler> snapuserd_;
-};
-
-class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
- public:
- SnapshotHandler(std::string misc_name, std::string cow_device, std::string backing_device,
- std::string base_path_merge);
- bool InitCowDevice();
- bool Start();
-
- const std::string& GetControlDevicePath() { return control_device_; }
- const std::string& GetMiscName() { return misc_name_; }
- const uint64_t& GetNumSectors() { return num_sectors_; }
- const bool& IsAttached() const { return attached_; }
- void AttachControlDevice() { attached_ = true; }
-
- void CheckMergeCompletionStatus();
- bool CommitMerge(int num_merge_ops);
-
- void CloseFds() { cow_fd_ = {}; }
- void FreeResources() {
- worker_threads_.clear();
- read_ahead_thread_ = nullptr;
- merge_thread_ = nullptr;
- }
-
- bool InitializeWorkers();
- std::unique_ptr<CowReader> CloneReaderForWorker();
- std::shared_ptr<SnapshotHandler> GetSharedPtr() { return shared_from_this(); }
-
- std::vector<std::pair<sector_t, const CowOperation*>>& GetChunkVec() { return chunk_vec_; }
-
- static bool compare(std::pair<sector_t, const CowOperation*> p1,
- std::pair<sector_t, const CowOperation*> p2) {
- return p1.first < p2.first;
- }
-
- void UnmapBufferRegion();
- bool MmapMetadata();
-
- // Read-ahead related functions
- void* GetMappedAddr() { return mapped_addr_; }
- void PrepareReadAhead();
- std::unordered_map<uint64_t, void*>& GetReadAheadMap() { return read_ahead_buffer_map_; }
-
- // State transitions for merge
- void InitiateMerge();
- void WaitForMergeComplete();
- bool WaitForMergeBegin();
- void NotifyRAForMergeReady();
- bool WaitForMergeReady();
- void MergeFailed();
- bool IsIOTerminated();
- void MergeCompleted();
- void NotifyIOTerminated();
- bool ReadAheadIOCompleted(bool sync);
- void ReadAheadIOFailed();
-
- bool ShouldReconstructDataFromCow() { return populate_data_from_cow_; }
- void FinishReconstructDataFromCow() { populate_data_from_cow_ = false; }
- // Return the snapshot status
- std::string GetMergeStatus();
-
- // RA related functions
- uint64_t GetBufferMetadataOffset();
- size_t GetBufferMetadataSize();
- size_t GetBufferDataOffset();
- size_t GetBufferDataSize();
-
- // Total number of blocks to be merged in a given read-ahead buffer region
- void SetMergedBlockCountForNextCommit(int x) { total_ra_blocks_merged_ = x; }
- int GetTotalBlocksToMerge() { return total_ra_blocks_merged_; }
- void SetSocketPresent(bool socket) { is_socket_present_ = socket; }
- void SetIouringEnabled(bool io_uring_enabled) { is_io_uring_enabled_ = io_uring_enabled; }
- bool MergeInitiated() { return merge_initiated_; }
- double GetMergePercentage() { return merge_completion_percentage_; }
-
- // Merge Block State Transitions
- void SetMergeCompleted(size_t block_index);
- void SetMergeInProgress(size_t block_index);
- void SetMergeFailed(size_t block_index);
- void NotifyIOCompletion(uint64_t new_block);
- bool GetRABuffer(std::unique_lock<std::mutex>* lock, uint64_t block, void* buffer);
- MERGE_GROUP_STATE ProcessMergingBlock(uint64_t new_block, void* buffer);
-
- bool IsIouringSupported();
-
- private:
- bool ReadMetadata();
- sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
- chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; }
- bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
- struct BufferState* GetBufferState();
- void UpdateMergeCompletionPercentage();
-
- void ReadBlocks(const std::string partition_name, const std::string& dm_block_device);
- void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name,
- off_t offset, size_t size);
-
- bool InitializeIouring(int io_depth);
- void FinalizeIouring();
- bool ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name,
- size_t size);
-
- // COW device
- std::string cow_device_;
- // Source device
- std::string backing_store_device_;
- // dm-user control device
- std::string control_device_;
- std::string misc_name_;
- // Base device for merging
- std::string base_path_merge_;
-
- unique_fd cow_fd_;
-
- uint64_t num_sectors_;
-
- std::unique_ptr<CowReader> reader_;
-
- // chunk_vec stores the pseudo mapping of sector
- // to COW operations.
- std::vector<std::pair<sector_t, const CowOperation*>> chunk_vec_;
-
- std::mutex lock_;
- std::condition_variable cv;
-
- void* mapped_addr_;
- size_t total_mapped_addr_length_;
-
- std::vector<std::unique_ptr<Worker>> worker_threads_;
- // Read-ahead related
- bool populate_data_from_cow_ = false;
- bool ra_thread_ = false;
- int total_ra_blocks_merged_ = 0;
- MERGE_IO_TRANSITION io_state_;
- std::unique_ptr<ReadAhead> read_ahead_thread_;
- std::unordered_map<uint64_t, void*> read_ahead_buffer_map_;
-
- // user-space-merging
- std::unordered_map<uint64_t, int> block_to_ra_index_;
-
- // Merge Block state
- std::vector<std::unique_ptr<MergeGroupState>> merge_blk_state_;
-
- std::unique_ptr<Worker> merge_thread_;
- double merge_completion_percentage_;
-
- bool merge_initiated_ = false;
- bool attached_ = false;
- bool is_socket_present_;
- bool is_io_uring_enabled_ = false;
- bool scratch_space_ = false;
-
- std::unique_ptr<struct io_uring> ring_;
-};
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp
deleted file mode 100644
index 1e300d2d4..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * 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 "snapuserd_core.h"
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-Worker::Worker(const std::string& cow_device, const std::string& backing_device,
- const std::string& control_device, const std::string& misc_name,
- const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd) {
- cow_device_ = cow_device;
- backing_store_device_ = backing_device;
- control_device_ = control_device;
- misc_name_ = misc_name;
- base_path_merge_ = base_path_merge;
- snapuserd_ = snapuserd;
-}
-
-bool Worker::InitializeFds() {
- backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
- if (backing_store_fd_ < 0) {
- SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_;
- return false;
- }
-
- cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
- if (cow_fd_ < 0) {
- SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
- return false;
- }
-
- ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR));
- if (ctrl_fd_ < 0) {
- SNAP_PLOG(ERROR) << "Unable to open " << control_device_;
- return false;
- }
-
- // Base device used by merge thread
- base_path_merge_fd_.reset(open(base_path_merge_.c_str(), O_RDWR));
- if (base_path_merge_fd_ < 0) {
- SNAP_PLOG(ERROR) << "Open Failed: " << base_path_merge_;
- return false;
- }
-
- return true;
-}
-
-bool Worker::InitReader() {
- reader_ = snapuserd_->CloneReaderForWorker();
-
- if (!reader_->InitForMerge(std::move(cow_fd_))) {
- return false;
- }
- return true;
-}
-
-// Start the replace operation. This will read the
-// internal COW format and if the block is compressed,
-// it will be de-compressed.
-bool Worker::ProcessReplaceOp(const CowOperation* cow_op) {
- if (!reader_->ReadData(*cow_op, &bufsink_)) {
- SNAP_LOG(ERROR) << "ProcessReplaceOp failed for block " << cow_op->new_block;
- return false;
- }
-
- return true;
-}
-
-bool Worker::ReadFromSourceDevice(const CowOperation* cow_op) {
- void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- if (buffer == nullptr) {
- SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
- return false;
- }
- SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
- << " Source: " << cow_op->source;
- uint64_t offset = cow_op->source;
- if (cow_op->type == kCowCopyOp) {
- offset *= BLOCK_SZ;
- }
- if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
- std::string op;
- if (cow_op->type == kCowCopyOp)
- op = "Copy-op";
- else {
- op = "Xor-op";
- }
- SNAP_PLOG(ERROR) << op << " failed. Read from backing store: " << backing_store_device_
- << "at block :" << offset / BLOCK_SZ << " offset:" << offset % BLOCK_SZ;
- return false;
- }
-
- return true;
-}
-
-// Start the copy operation. This will read the backing
-// block device which is represented by cow_op->source.
-bool Worker::ProcessCopyOp(const CowOperation* cow_op) {
- if (!ReadFromSourceDevice(cow_op)) {
- return false;
- }
-
- return true;
-}
-
-bool Worker::ProcessXorOp(const CowOperation* cow_op) {
- if (!ReadFromSourceDevice(cow_op)) {
- return false;
- }
- xorsink_.Reset();
- if (!reader_->ReadData(*cow_op, &xorsink_)) {
- SNAP_LOG(ERROR) << "ProcessXorOp failed for block " << cow_op->new_block;
- return false;
- }
-
- return true;
-}
-
-bool Worker::ProcessZeroOp() {
- // Zero out the entire block
- void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- if (buffer == nullptr) {
- SNAP_LOG(ERROR) << "ProcessZeroOp: Failed to get payload buffer";
- return false;
- }
-
- memset(buffer, 0, BLOCK_SZ);
- return true;
-}
-
-bool Worker::ProcessOrderedOp(const CowOperation* cow_op) {
- void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- if (buffer == nullptr) {
- SNAP_LOG(ERROR) << "ProcessOrderedOp: Failed to get payload buffer";
- return false;
- }
-
- MERGE_GROUP_STATE state = snapuserd_->ProcessMergingBlock(cow_op->new_block, buffer);
-
- switch (state) {
- case MERGE_GROUP_STATE::GROUP_MERGE_COMPLETED: {
- // Merge is completed for this COW op; just read directly from
- // the base device
- SNAP_LOG(DEBUG) << "Merge-completed: Reading from base device sector: "
- << (cow_op->new_block >> SECTOR_SHIFT)
- << " Block-number: " << cow_op->new_block;
- if (!ReadDataFromBaseDevice(ChunkToSector(cow_op->new_block), BLOCK_SZ)) {
- SNAP_LOG(ERROR) << "ReadDataFromBaseDevice at sector: "
- << (cow_op->new_block >> SECTOR_SHIFT) << " after merge-complete.";
- return false;
- }
- return true;
- }
- case MERGE_GROUP_STATE::GROUP_MERGE_PENDING: {
- bool ret;
- if (cow_op->type == kCowCopyOp) {
- ret = ProcessCopyOp(cow_op);
- } else {
- ret = ProcessXorOp(cow_op);
- }
-
- // I/O is complete - decrement the refcount irrespective of the return
- // status
- snapuserd_->NotifyIOCompletion(cow_op->new_block);
- return ret;
- }
- // We already have the data in the buffer retrieved from RA thread.
- // Nothing to process further.
- case MERGE_GROUP_STATE::GROUP_MERGE_RA_READY: {
- [[fallthrough]];
- }
- case MERGE_GROUP_STATE::GROUP_MERGE_IN_PROGRESS: {
- return true;
- }
- default: {
- // All other states, fail the I/O viz (GROUP_MERGE_FAILED and GROUP_INVALID)
- return false;
- }
- }
-
- return false;
-}
-
-bool Worker::ProcessCowOp(const CowOperation* cow_op) {
- if (cow_op == nullptr) {
- SNAP_LOG(ERROR) << "ProcessCowOp: Invalid cow_op";
- return false;
- }
-
- switch (cow_op->type) {
- case kCowReplaceOp: {
- return ProcessReplaceOp(cow_op);
- }
-
- case kCowZeroOp: {
- return ProcessZeroOp();
- }
-
- case kCowCopyOp:
- [[fallthrough]];
- case kCowXorOp: {
- return ProcessOrderedOp(cow_op);
- }
-
- default: {
- SNAP_LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
- }
- }
- return false;
-}
-
-void Worker::InitializeBufsink() {
- // Allocate the buffer which is used to communicate between
- // daemon and dm-user. The buffer comprises of header and a fixed payload.
- // If the dm-user requests a big IO, the IO will be broken into chunks
- // of PAYLOAD_BUFFER_SZ.
- size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_BUFFER_SZ;
- bufsink_.Initialize(buf_size);
-}
-
-bool Worker::Init() {
- InitializeBufsink();
- xorsink_.Initialize(&bufsink_, BLOCK_SZ);
-
- if (!InitializeFds()) {
- return false;
- }
-
- if (!InitReader()) {
- return false;
- }
-
- return true;
-}
-
-bool Worker::RunThread() {
- SNAP_LOG(INFO) << "Processing snapshot I/O requests....";
- // Start serving IO
- while (true) {
- if (!ProcessIORequest()) {
- break;
- }
- }
-
- CloseFds();
- reader_->CloseCowFd();
-
- return true;
-}
-
-// Read Header from dm-user misc device. This gives
-// us the sector number for which IO is issued by dm-snapshot device
-bool Worker::ReadDmUserHeader() {
- if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
- if (errno != ENOTBLK) {
- SNAP_PLOG(ERROR) << "Control-read failed";
- }
-
- SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
- return false;
- }
-
- return true;
-}
-
-// Send the payload/data back to dm-user misc device.
-bool Worker::WriteDmUserPayload(size_t size, bool header_response) {
- size_t payload_size = size;
- void* buf = bufsink_.GetPayloadBufPtr();
- if (header_response) {
- payload_size += sizeof(struct dm_user_header);
- buf = bufsink_.GetBufPtr();
- }
-
- if (!android::base::WriteFully(ctrl_fd_, buf, payload_size)) {
- SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << payload_size;
- return false;
- }
-
- return true;
-}
-
-bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) {
- CHECK(read_size <= BLOCK_SZ);
-
- void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- if (buffer == nullptr) {
- SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
- return false;
- }
-
- loff_t offset = sector << SECTOR_SHIFT;
- if (!android::base::ReadFullyAtOffset(base_path_merge_fd_, buffer, read_size, offset)) {
- SNAP_PLOG(ERROR) << "ReadDataFromBaseDevice failed. fd: " << base_path_merge_fd_
- << "at sector :" << sector << " size: " << read_size;
- return false;
- }
-
- return true;
-}
-
-bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) {
- struct dm_user_header* header = bufsink_.GetHeaderPtr();
- size_t remaining_size = sz;
- std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
- bool io_error = false;
- int ret = 0;
-
- do {
- // Process 1MB payload at a time
- size_t read_size = std::min(PAYLOAD_BUFFER_SZ, remaining_size);
-
- header->type = DM_USER_RESP_SUCCESS;
- size_t total_bytes_read = 0;
- io_error = false;
- bufsink_.ResetBufferOffset();
-
- while (read_size) {
- // We need to check every 4k block to verify if it is
- // present in the mapping.
- size_t size = std::min(BLOCK_SZ, read_size);
-
- auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
- std::make_pair(sector, nullptr), SnapshotHandler::compare);
- bool not_found = (it == chunk_vec.end() || it->first != sector);
-
- if (not_found) {
- // Block not found in map - which means this block was not
- // changed as per the OTA. Just route the I/O to the base
- // device.
- if (!ReadDataFromBaseDevice(sector, size)) {
- SNAP_LOG(ERROR) << "ReadDataFromBaseDevice failed";
- header->type = DM_USER_RESP_ERROR;
- }
-
- ret = size;
- } else {
- // We found the sector in mapping. Check the type of COW OP and
- // process it.
- if (!ProcessCowOp(it->second)) {
- SNAP_LOG(ERROR) << "ProcessCowOp failed";
- header->type = DM_USER_RESP_ERROR;
- }
-
- ret = BLOCK_SZ;
- }
-
- // Just return the header if it is an error
- if (header->type == DM_USER_RESP_ERROR) {
- if (!RespondIOError(header_response)) {
- return false;
- }
-
- io_error = true;
- break;
- }
-
- read_size -= ret;
- total_bytes_read += ret;
- sector += (ret >> SECTOR_SHIFT);
- bufsink_.UpdateBufferOffset(ret);
- }
-
- if (!io_error) {
- if (!WriteDmUserPayload(total_bytes_read, header_response)) {
- return false;
- }
-
- SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read
- << " header-response: " << header_response
- << " remaining_size: " << remaining_size;
- header_response = false;
- remaining_size -= total_bytes_read;
- }
- } while (remaining_size > 0 && !io_error);
-
- return true;
-}
-
-int Worker::ReadUnalignedSector(
- sector_t sector, size_t size,
- std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it) {
- size_t skip_sector_size = 0;
-
- SNAP_LOG(DEBUG) << "ReadUnalignedSector: sector " << sector << " size: " << size
- << " Aligned sector: " << it->first;
-
- if (!ProcessCowOp(it->second)) {
- SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size
- << " Aligned sector: " << it->first;
- return -1;
- }
-
- int num_sectors_skip = sector - it->first;
-
- if (num_sectors_skip > 0) {
- skip_sector_size = num_sectors_skip << SECTOR_SHIFT;
- char* buffer = reinterpret_cast<char*>(bufsink_.GetBufPtr());
- struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
-
- if (skip_sector_size == BLOCK_SZ) {
- SNAP_LOG(ERROR) << "Invalid un-aligned IO request at sector: " << sector
- << " Base-sector: " << it->first;
- return -1;
- }
-
- memmove(msg->payload.buf, (char*)msg->payload.buf + skip_sector_size,
- (BLOCK_SZ - skip_sector_size));
- }
-
- bufsink_.ResetBufferOffset();
- return std::min(size, (BLOCK_SZ - skip_sector_size));
-}
-
-bool Worker::ReadUnalignedSector(sector_t sector, size_t size) {
- struct dm_user_header* header = bufsink_.GetHeaderPtr();
- header->type = DM_USER_RESP_SUCCESS;
- bufsink_.ResetBufferOffset();
- std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
-
- auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr),
- SnapshotHandler::compare);
-
- // |-------|-------|-------|
- // 0 1 2 3
- //
- // Block 0 - op 1
- // Block 1 - op 2
- // Block 2 - op 3
- //
- // chunk_vec will have block 0, 1, 2 which maps to relavant COW ops.
- //
- // Each block is 4k bytes. Thus, the last block will span 8 sectors
- // ranging till block 3 (However, block 3 won't be in chunk_vec as
- // it doesn't have any mapping to COW ops. Now, if we get an I/O request for a sector
- // spanning between block 2 and block 3, we need to step back
- // and get hold of the last element.
- //
- // Additionally, we need to make sure that the requested sector is
- // indeed within the range of the final sector. It is perfectly valid
- // to get an I/O request for block 3 and beyond which are not mapped
- // to any COW ops. In that case, we just need to read from the base
- // device.
- bool merge_complete = false;
- bool header_response = true;
- if (it == chunk_vec.end()) {
- if (chunk_vec.size() > 0) {
- // I/O request beyond the last mapped sector
- it = std::prev(chunk_vec.end());
- } else {
- // This can happen when a partition merge is complete but snapshot
- // state in /metadata is not yet deleted; during this window if the
- // device is rebooted, subsequent attempt will mount the snapshot.
- // However, since the merge was completed we wouldn't have any
- // mapping to COW ops thus chunk_vec will be empty. In that case,
- // mark this as merge_complete and route the I/O to the base device.
- merge_complete = true;
- }
- } else if (it->first != sector) {
- if (it != chunk_vec.begin()) {
- --it;
- }
- } else {
- return ReadAlignedSector(sector, size, header_response);
- }
-
- loff_t requested_offset = sector << SECTOR_SHIFT;
-
- loff_t final_offset = 0;
- if (!merge_complete) {
- final_offset = it->first << SECTOR_SHIFT;
- }
-
- // Since a COW op span 4k block size, we need to make sure that the requested
- // offset is within the 4k region. Consider the following case:
- //
- // |-------|-------|-------|
- // 0 1 2 3
- //
- // Block 0 - op 1
- // Block 1 - op 2
- //
- // We have an I/O request for a sector between block 2 and block 3. However,
- // we have mapping to COW ops only for block 0 and block 1. Thus, the
- // requested offset in this case is beyond the last mapped COW op size (which
- // is block 1 in this case).
-
- size_t total_bytes_read = 0;
- size_t remaining_size = size;
- int ret = 0;
- if (!merge_complete && (requested_offset >= final_offset) &&
- (requested_offset - final_offset) < BLOCK_SZ) {
- // Read the partial un-aligned data
- ret = ReadUnalignedSector(sector, remaining_size, it);
- if (ret < 0) {
- SNAP_LOG(ERROR) << "ReadUnalignedSector failed for sector: " << sector
- << " size: " << size << " it->sector: " << it->first;
- return RespondIOError(header_response);
- }
-
- remaining_size -= ret;
- total_bytes_read += ret;
- sector += (ret >> SECTOR_SHIFT);
-
- // Send the data back
- if (!WriteDmUserPayload(total_bytes_read, header_response)) {
- return false;
- }
-
- header_response = false;
- // If we still have pending data to be processed, this will be aligned I/O
- if (remaining_size) {
- return ReadAlignedSector(sector, remaining_size, header_response);
- }
- } else {
- // This is all about handling I/O request to be routed to base device
- // as the I/O is not mapped to any of the COW ops.
- loff_t aligned_offset = requested_offset;
- // Align to nearest 4k
- aligned_offset += BLOCK_SZ - 1;
- aligned_offset &= ~(BLOCK_SZ - 1);
- // Find the diff of the aligned offset
- size_t diff_size = aligned_offset - requested_offset;
- CHECK(diff_size <= BLOCK_SZ);
- if (remaining_size < diff_size) {
- if (!ReadDataFromBaseDevice(sector, remaining_size)) {
- return RespondIOError(header_response);
- }
- total_bytes_read += remaining_size;
-
- if (!WriteDmUserPayload(total_bytes_read, header_response)) {
- return false;
- }
- } else {
- if (!ReadDataFromBaseDevice(sector, diff_size)) {
- return RespondIOError(header_response);
- }
-
- total_bytes_read += diff_size;
-
- if (!WriteDmUserPayload(total_bytes_read, header_response)) {
- return false;
- }
-
- remaining_size -= diff_size;
- size_t num_sectors_read = (diff_size >> SECTOR_SHIFT);
- sector += num_sectors_read;
- CHECK(IsBlockAligned(sector << SECTOR_SHIFT));
- header_response = false;
-
- // If we still have pending data to be processed, this will be aligned I/O
- return ReadAlignedSector(sector, remaining_size, header_response);
- }
- }
-
- return true;
-}
-
-bool Worker::RespondIOError(bool header_response) {
- struct dm_user_header* header = bufsink_.GetHeaderPtr();
- header->type = DM_USER_RESP_ERROR;
- // This is an issue with the dm-user interface. There
- // is no way to propagate the I/O error back to dm-user
- // if we have already communicated the header back. Header
- // is responded once at the beginning; however I/O can
- // be processed in chunks. If we encounter an I/O error
- // somewhere in the middle of the processing, we can't communicate
- // this back to dm-user.
- //
- // TODO: Fix the interface
- CHECK(header_response);
-
- if (!WriteDmUserPayload(0, header_response)) {
- return false;
- }
-
- // There is no need to process further as we have already seen
- // an I/O error
- return true;
-}
-
-bool Worker::DmuserReadRequest() {
- struct dm_user_header* header = bufsink_.GetHeaderPtr();
-
- // Unaligned I/O request
- if (!IsBlockAligned(header->sector << SECTOR_SHIFT)) {
- return ReadUnalignedSector(header->sector, header->len);
- }
-
- return ReadAlignedSector(header->sector, header->len, true);
-}
-
-bool Worker::ProcessIORequest() {
- struct dm_user_header* header = bufsink_.GetHeaderPtr();
-
- if (!ReadDmUserHeader()) {
- return false;
- }
-
- SNAP_LOG(DEBUG) << "Daemon: msg->seq: " << std::dec << header->seq;
- SNAP_LOG(DEBUG) << "Daemon: msg->len: " << std::dec << header->len;
- SNAP_LOG(DEBUG) << "Daemon: msg->sector: " << std::dec << header->sector;
- SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
- SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;
-
- switch (header->type) {
- case DM_USER_REQ_MAP_READ: {
- if (!DmuserReadRequest()) {
- return false;
- }
- break;
- }
-
- case DM_USER_REQ_MAP_WRITE: {
- // TODO: We should not get any write request
- // to dm-user as we mount all partitions
- // as read-only. Need to verify how are TRIM commands
- // handled during mount.
- return false;
- }
- }
-
- return true;
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
deleted file mode 100644
index c26a2cd5c..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * 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 "snapuserd_core.h"
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-int Worker::PrepareMerge(uint64_t* source_offset, int* pending_ops,
- std::vector<const CowOperation*>* replace_zero_vec) {
- int num_ops = *pending_ops;
- int nr_consecutive = 0;
- bool checkOrderedOp = (replace_zero_vec == nullptr);
-
- do {
- if (!cowop_iter_->Done() && num_ops) {
- const CowOperation* cow_op = &cowop_iter_->Get();
- if (checkOrderedOp && !IsOrderedOp(*cow_op)) {
- break;
- }
-
- *source_offset = cow_op->new_block * BLOCK_SZ;
- if (!checkOrderedOp) {
- replace_zero_vec->push_back(cow_op);
- }
-
- cowop_iter_->Next();
- num_ops -= 1;
- nr_consecutive = 1;
-
- while (!cowop_iter_->Done() && num_ops) {
- const CowOperation* op = &cowop_iter_->Get();
- if (checkOrderedOp && !IsOrderedOp(*op)) {
- break;
- }
-
- uint64_t next_offset = op->new_block * BLOCK_SZ;
- if (next_offset != (*source_offset + nr_consecutive * BLOCK_SZ)) {
- break;
- }
-
- if (!checkOrderedOp) {
- replace_zero_vec->push_back(op);
- }
-
- nr_consecutive += 1;
- num_ops -= 1;
- cowop_iter_->Next();
- }
- }
- } while (0);
-
- return nr_consecutive;
-}
-
-bool Worker::MergeReplaceZeroOps() {
- // Flush every 8192 ops. Since all ops are independent and there is no
- // dependency between COW ops, we will flush the data and the number
- // of ops merged in COW file for every 8192 ops. If there is a crash,
- // we will end up replaying some of the COW ops which were already merged.
- // That is ok.
- //
- // Why 8192 ops ? Increasing this may improve merge time 3-4 seconds but
- // we need to make sure that we checkpoint; 8k ops seems optimal. In-case
- // if there is a crash merge should always make forward progress.
- int total_ops_merged_per_commit = (PAYLOAD_BUFFER_SZ / BLOCK_SZ) * 32;
- int num_ops_merged = 0;
-
- SNAP_LOG(INFO) << "MergeReplaceZeroOps started....";
-
- while (!cowop_iter_->Done()) {
- int num_ops = PAYLOAD_BUFFER_SZ / BLOCK_SZ;
- std::vector<const CowOperation*> replace_zero_vec;
- uint64_t source_offset;
-
- int linear_blocks = PrepareMerge(&source_offset, &num_ops, &replace_zero_vec);
- if (linear_blocks == 0) {
- // Merge complete
- CHECK(cowop_iter_->Done());
- break;
- }
-
- for (size_t i = 0; i < replace_zero_vec.size(); i++) {
- const CowOperation* cow_op = replace_zero_vec[i];
- if (cow_op->type == kCowReplaceOp) {
- if (!ProcessReplaceOp(cow_op)) {
- SNAP_LOG(ERROR) << "Merge - ReplaceOp failed for block: " << cow_op->new_block;
- return false;
- }
- } else {
- CHECK(cow_op->type == kCowZeroOp);
- if (!ProcessZeroOp()) {
- SNAP_LOG(ERROR) << "Merge ZeroOp failed.";
- return false;
- }
- }
-
- bufsink_.UpdateBufferOffset(BLOCK_SZ);
- }
-
- size_t io_size = linear_blocks * BLOCK_SZ;
-
- // Merge - Write the contents back to base device
- int ret = TEMP_FAILURE_RETRY(pwrite(base_path_merge_fd_.get(), bufsink_.GetPayloadBufPtr(),
- io_size, source_offset));
- if (ret < 0 || ret != io_size) {
- SNAP_LOG(ERROR)
- << "Merge: ReplaceZeroOps: Failed to write to backing device while merging "
- << " at offset: " << source_offset << " io_size: " << io_size;
- return false;
- }
-
- num_ops_merged += linear_blocks;
-
- if (num_ops_merged >= total_ops_merged_per_commit) {
- // Flush the data
- if (fsync(base_path_merge_fd_.get()) < 0) {
- SNAP_LOG(ERROR) << "Merge: ReplaceZeroOps: Failed to fsync merged data";
- return false;
- }
-
- // Track the merge completion
- if (!snapuserd_->CommitMerge(num_ops_merged)) {
- SNAP_LOG(ERROR) << " Failed to commit the merged block in the header";
- return false;
- }
-
- num_ops_merged = 0;
- }
-
- bufsink_.ResetBufferOffset();
-
- if (snapuserd_->IsIOTerminated()) {
- SNAP_LOG(ERROR)
- << "MergeReplaceZeroOps: Worker threads terminated - shutting down merge";
- return false;
- }
- }
-
- // Any left over ops not flushed yet.
- if (num_ops_merged) {
- // Flush the data
- if (fsync(base_path_merge_fd_.get()) < 0) {
- SNAP_LOG(ERROR) << "Merge: ReplaceZeroOps: Failed to fsync merged data";
- return false;
- }
-
- if (!snapuserd_->CommitMerge(num_ops_merged)) {
- SNAP_LOG(ERROR) << " Failed to commit the merged block in the header";
- return false;
- }
-
- num_ops_merged = 0;
- }
-
- return true;
-}
-
-bool Worker::MergeOrderedOpsAsync() {
- void* mapped_addr = snapuserd_->GetMappedAddr();
- void* read_ahead_buffer =
- static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferDataOffset());
-
- SNAP_LOG(INFO) << "MergeOrderedOpsAsync started....";
-
- while (!cowop_iter_->Done()) {
- const CowOperation* cow_op = &cowop_iter_->Get();
- if (!IsOrderedOp(*cow_op)) {
- break;
- }
-
- SNAP_LOG(DEBUG) << "Waiting for merge begin...";
- // Wait for RA thread to notify that the merge window
- // is ready for merging.
- if (!snapuserd_->WaitForMergeBegin()) {
- return false;
- }
-
- snapuserd_->SetMergeInProgress(ra_block_index_);
-
- loff_t offset = 0;
- int num_ops = snapuserd_->GetTotalBlocksToMerge();
-
- int pending_sqe = queue_depth_;
- int pending_ios_to_submit = 0;
- bool flush_required = false;
- blocks_merged_in_group_ = 0;
-
- SNAP_LOG(DEBUG) << "Merging copy-ops of size: " << num_ops;
- while (num_ops) {
- uint64_t source_offset;
-
- int linear_blocks = PrepareMerge(&source_offset, &num_ops);
-
- if (linear_blocks != 0) {
- size_t io_size = (linear_blocks * BLOCK_SZ);
-
- // Get an SQE entry from the ring and populate the I/O variables
- struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get());
- if (!sqe) {
- SNAP_PLOG(ERROR) << "io_uring_get_sqe failed during merge-ordered ops";
- return false;
- }
-
- io_uring_prep_write(sqe, base_path_merge_fd_.get(),
- (char*)read_ahead_buffer + offset, io_size, source_offset);
-
- offset += io_size;
- num_ops -= linear_blocks;
- blocks_merged_in_group_ += linear_blocks;
-
- pending_sqe -= 1;
- pending_ios_to_submit += 1;
- // These flags are important - We need to make sure that the
- // blocks are linked and are written in the same order as
- // populated. This is because of overlapping block writes.
- //
- // If there are no dependency, we can optimize this further by
- // allowing parallel writes; but for now, just link all the SQ
- // entries.
- sqe->flags |= (IOSQE_IO_LINK | IOSQE_ASYNC);
- }
-
- // Ring is full or no more COW ops to be merged in this batch
- if (pending_sqe == 0 || num_ops == 0 || (linear_blocks == 0 && pending_ios_to_submit)) {
- // If this is a last set of COW ops to be merged in this batch, we need
- // to sync the merged data. We will try to grab an SQE entry
- // and set the FSYNC command; additionally, make sure that
- // the fsync is done after all the I/O operations queued
- // in the ring is completed by setting IOSQE_IO_DRAIN.
- //
- // If there is no space in the ring, we will flush it later
- // by explicitly calling fsync() system call.
- if (num_ops == 0 || (linear_blocks == 0 && pending_ios_to_submit)) {
- if (pending_sqe != 0) {
- struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get());
- if (!sqe) {
- // very unlikely but let's continue and not fail the
- // merge - we will flush it later
- SNAP_PLOG(ERROR) << "io_uring_get_sqe failed during merge-ordered ops";
- flush_required = true;
- } else {
- io_uring_prep_fsync(sqe, base_path_merge_fd_.get(), 0);
- // Drain the queue before fsync
- io_uring_sqe_set_flags(sqe, IOSQE_IO_DRAIN);
- pending_sqe -= 1;
- flush_required = false;
- pending_ios_to_submit += 1;
- sqe->flags |= (IOSQE_IO_LINK | IOSQE_ASYNC);
- }
- } else {
- flush_required = true;
- }
- }
-
- // Submit the IO for all the COW ops in a single syscall
- int ret = io_uring_submit(ring_.get());
- if (ret != pending_ios_to_submit) {
- SNAP_PLOG(ERROR)
- << "io_uring_submit failed for read-ahead: "
- << " io submit: " << ret << " expected: " << pending_ios_to_submit;
- return false;
- }
-
- int pending_ios_to_complete = pending_ios_to_submit;
- pending_ios_to_submit = 0;
-
- bool status = true;
-
- // Reap I/O completions
- while (pending_ios_to_complete) {
- struct io_uring_cqe* cqe;
-
- // io_uring_wait_cqe can potentially return -EAGAIN or -EINTR;
- // these error codes are not truly I/O errors; we can retry them
- // by re-populating the SQE entries and submitting the I/O
- // request back. However, we don't do that now; instead we
- // will fallback to synchronous I/O.
- ret = io_uring_wait_cqe(ring_.get(), &cqe);
- if (ret) {
- SNAP_LOG(ERROR) << "Merge: io_uring_wait_cqe failed: " << ret;
- status = false;
- break;
- }
-
- if (cqe->res < 0) {
- SNAP_LOG(ERROR) << "Merge: io_uring_wait_cqe failed with res: " << cqe->res;
- status = false;
- break;
- }
-
- io_uring_cqe_seen(ring_.get(), cqe);
- pending_ios_to_complete -= 1;
- }
-
- if (!status) {
- return false;
- }
-
- pending_sqe = queue_depth_;
- }
-
- if (linear_blocks == 0) {
- break;
- }
- }
-
- // Verify all ops are merged
- CHECK(num_ops == 0);
-
- // Flush the data
- if (flush_required && (fsync(base_path_merge_fd_.get()) < 0)) {
- SNAP_LOG(ERROR) << " Failed to fsync merged data";
- return false;
- }
-
- // Merge is done and data is on disk. Update the COW Header about
- // the merge completion
- if (!snapuserd_->CommitMerge(snapuserd_->GetTotalBlocksToMerge())) {
- SNAP_LOG(ERROR) << " Failed to commit the merged block in the header";
- return false;
- }
-
- SNAP_LOG(DEBUG) << "Block commit of size: " << snapuserd_->GetTotalBlocksToMerge();
-
- // Mark the block as merge complete
- snapuserd_->SetMergeCompleted(ra_block_index_);
-
- // Notify RA thread that the merge thread is ready to merge the next
- // window
- snapuserd_->NotifyRAForMergeReady();
-
- // Get the next block
- ra_block_index_ += 1;
- }
-
- return true;
-}
-
-bool Worker::MergeOrderedOps() {
- void* mapped_addr = snapuserd_->GetMappedAddr();
- void* read_ahead_buffer =
- static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferDataOffset());
-
- SNAP_LOG(INFO) << "MergeOrderedOps started....";
-
- while (!cowop_iter_->Done()) {
- const CowOperation* cow_op = &cowop_iter_->Get();
- if (!IsOrderedOp(*cow_op)) {
- break;
- }
-
- SNAP_LOG(DEBUG) << "Waiting for merge begin...";
- // Wait for RA thread to notify that the merge window
- // is ready for merging.
- if (!snapuserd_->WaitForMergeBegin()) {
- snapuserd_->SetMergeFailed(ra_block_index_);
- return false;
- }
-
- snapuserd_->SetMergeInProgress(ra_block_index_);
-
- loff_t offset = 0;
- int num_ops = snapuserd_->GetTotalBlocksToMerge();
- SNAP_LOG(DEBUG) << "Merging copy-ops of size: " << num_ops;
- while (num_ops) {
- uint64_t source_offset;
-
- int linear_blocks = PrepareMerge(&source_offset, &num_ops);
- if (linear_blocks == 0) {
- break;
- }
-
- size_t io_size = (linear_blocks * BLOCK_SZ);
- // Write to the base device. Data is already in the RA buffer. Note
- // that XOR ops is already handled by the RA thread. We just write
- // the contents out.
- int ret = TEMP_FAILURE_RETRY(pwrite(base_path_merge_fd_.get(),
- (char*)read_ahead_buffer + offset, io_size,
- source_offset));
- if (ret < 0 || ret != io_size) {
- SNAP_LOG(ERROR) << "Failed to write to backing device while merging "
- << " at offset: " << source_offset << " io_size: " << io_size;
- snapuserd_->SetMergeFailed(ra_block_index_);
- return false;
- }
-
- offset += io_size;
- num_ops -= linear_blocks;
- }
-
- // Verify all ops are merged
- CHECK(num_ops == 0);
-
- // Flush the data
- if (fsync(base_path_merge_fd_.get()) < 0) {
- SNAP_LOG(ERROR) << " Failed to fsync merged data";
- snapuserd_->SetMergeFailed(ra_block_index_);
- return false;
- }
-
- // Merge is done and data is on disk. Update the COW Header about
- // the merge completion
- if (!snapuserd_->CommitMerge(snapuserd_->GetTotalBlocksToMerge())) {
- SNAP_LOG(ERROR) << " Failed to commit the merged block in the header";
- snapuserd_->SetMergeFailed(ra_block_index_);
- return false;
- }
-
- SNAP_LOG(DEBUG) << "Block commit of size: " << snapuserd_->GetTotalBlocksToMerge();
- // Mark the block as merge complete
- snapuserd_->SetMergeCompleted(ra_block_index_);
-
- // Notify RA thread that the merge thread is ready to merge the next
- // window
- snapuserd_->NotifyRAForMergeReady();
-
- // Get the next block
- ra_block_index_ += 1;
- }
-
- return true;
-}
-
-bool Worker::AsyncMerge() {
- if (!MergeOrderedOpsAsync()) {
- SNAP_LOG(ERROR) << "MergeOrderedOpsAsync failed - Falling back to synchronous I/O";
- // Reset the iter so that we retry the merge
- while (blocks_merged_in_group_ && !cowop_iter_->RDone()) {
- cowop_iter_->Prev();
- blocks_merged_in_group_ -= 1;
- }
-
- return false;
- }
-
- SNAP_LOG(INFO) << "MergeOrderedOpsAsync completed";
- return true;
-}
-
-bool Worker::SyncMerge() {
- if (!MergeOrderedOps()) {
- SNAP_LOG(ERROR) << "Merge failed for ordered ops";
- return false;
- }
-
- SNAP_LOG(INFO) << "MergeOrderedOps completed";
- return true;
-}
-
-bool Worker::Merge() {
- cowop_iter_ = reader_->GetMergeOpIter();
-
- bool retry = false;
- bool ordered_ops_merge_status;
-
- // Start Async Merge
- if (merge_async_) {
- ordered_ops_merge_status = AsyncMerge();
- if (!ordered_ops_merge_status) {
- FinalizeIouring();
- retry = true;
- merge_async_ = false;
- }
- }
-
- // Check if we need to fallback and retry the merge
- //
- // If the device doesn't support async merge, we
- // will directly enter here (aka devices with 4.x kernels)
- const bool sync_merge_required = (retry || !merge_async_);
-
- if (sync_merge_required) {
- ordered_ops_merge_status = SyncMerge();
- if (!ordered_ops_merge_status) {
- // Merge failed. Device will continue to be mounted
- // off snapshots; merge will be retried during
- // next reboot
- SNAP_LOG(ERROR) << "Merge failed for ordered ops";
- snapuserd_->MergeFailed();
- return false;
- }
- }
-
- // Replace and Zero ops
- if (!MergeReplaceZeroOps()) {
- SNAP_LOG(ERROR) << "Merge failed for replace/zero ops";
- snapuserd_->MergeFailed();
- return false;
- }
-
- snapuserd_->MergeCompleted();
-
- return true;
-}
-
-bool Worker::InitializeIouring() {
- if (!snapuserd_->IsIouringSupported()) {
- return false;
- }
-
- ring_ = std::make_unique<struct io_uring>();
-
- int ret = io_uring_queue_init(queue_depth_, ring_.get(), 0);
- if (ret) {
- LOG(ERROR) << "Merge: io_uring_queue_init failed with ret: " << ret;
- return false;
- }
-
- merge_async_ = true;
-
- LOG(INFO) << "Merge: io_uring initialized with queue depth: " << queue_depth_;
- return true;
-}
-
-void Worker::FinalizeIouring() {
- if (merge_async_) {
- io_uring_queue_exit(ring_.get());
- }
-}
-
-bool Worker::RunMergeThread() {
- SNAP_LOG(DEBUG) << "Waiting for merge begin...";
- if (!snapuserd_->WaitForMergeBegin()) {
- SNAP_LOG(ERROR) << "Merge terminated early...";
- return true;
- }
-
- SNAP_LOG(INFO) << "Merge starting..";
-
- if (!Init()) {
- SNAP_LOG(ERROR) << "Merge thread initialization failed...";
- snapuserd_->MergeFailed();
- return false;
- }
-
- InitializeIouring();
-
- if (!Merge()) {
- return false;
- }
-
- FinalizeIouring();
- CloseFds();
- reader_->CloseCowFd();
-
- SNAP_LOG(INFO) << "Snapshot-Merge completed";
-
- return true;
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
deleted file mode 100644
index fa2866f39..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * 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 "snapuserd_core.h"
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-ReadAhead::ReadAhead(const std::string& cow_device, const std::string& backing_device,
- const std::string& misc_name, std::shared_ptr<SnapshotHandler> snapuserd) {
- cow_device_ = cow_device;
- backing_store_device_ = backing_device;
- misc_name_ = misc_name;
- snapuserd_ = snapuserd;
-}
-
-void ReadAhead::CheckOverlap(const CowOperation* cow_op) {
- uint64_t source_block = cow_op->source;
- uint64_t source_offset = 0;
- if (cow_op->type == kCowXorOp) {
- source_block /= BLOCK_SZ;
- source_offset = cow_op->source % BLOCK_SZ;
- }
- if (dest_blocks_.count(cow_op->new_block) || source_blocks_.count(source_block) ||
- (source_offset > 0 && source_blocks_.count(source_block + 1))) {
- overlap_ = true;
- }
-
- dest_blocks_.insert(source_block);
- if (source_offset > 0) {
- dest_blocks_.insert(source_block + 1);
- }
- source_blocks_.insert(cow_op->new_block);
-}
-
-int ReadAhead::PrepareNextReadAhead(uint64_t* source_offset, int* pending_ops,
- std::vector<uint64_t>& blocks,
- std::vector<const CowOperation*>& xor_op_vec) {
- int num_ops = *pending_ops;
- int nr_consecutive = 0;
-
- bool is_ops_present = (!RAIterDone() && num_ops);
-
- if (!is_ops_present) {
- return nr_consecutive;
- }
-
- // Get the first block with offset
- const CowOperation* cow_op = GetRAOpIter();
- *source_offset = cow_op->source;
-
- if (cow_op->type == kCowCopyOp) {
- *source_offset *= BLOCK_SZ;
- } else if (cow_op->type == kCowXorOp) {
- xor_op_vec.push_back(cow_op);
- }
-
- RAIterNext();
- num_ops -= 1;
- nr_consecutive = 1;
- blocks.push_back(cow_op->new_block);
-
- if (!overlap_) {
- CheckOverlap(cow_op);
- }
-
- /*
- * Find number of consecutive blocks
- */
- while (!RAIterDone() && num_ops) {
- const CowOperation* op = GetRAOpIter();
- uint64_t next_offset = op->source;
-
- if (cow_op->type == kCowCopyOp) {
- next_offset *= BLOCK_SZ;
- }
-
- // Check for consecutive blocks
- if (next_offset != (*source_offset + nr_consecutive * BLOCK_SZ)) {
- break;
- }
-
- if (op->type == kCowXorOp) {
- xor_op_vec.push_back(op);
- }
-
- nr_consecutive += 1;
- num_ops -= 1;
- blocks.push_back(op->new_block);
- RAIterNext();
-
- if (!overlap_) {
- CheckOverlap(op);
- }
- }
-
- return nr_consecutive;
-}
-
-bool ReadAhead::ReconstructDataFromCow() {
- std::unordered_map<uint64_t, void*>& read_ahead_buffer_map = snapuserd_->GetReadAheadMap();
- loff_t metadata_offset = 0;
- loff_t start_data_offset = snapuserd_->GetBufferDataOffset();
- int num_ops = 0;
- int total_blocks_merged = 0;
-
- // This memcpy is important as metadata_buffer_ will be an unaligned address and will fault
- // on 32-bit systems
- std::unique_ptr<uint8_t[]> metadata_buffer =
- std::make_unique<uint8_t[]>(snapuserd_->GetBufferMetadataSize());
- memcpy(metadata_buffer.get(), metadata_buffer_, snapuserd_->GetBufferMetadataSize());
-
- while (true) {
- struct ScratchMetadata* bm = reinterpret_cast<struct ScratchMetadata*>(
- (char*)metadata_buffer.get() + metadata_offset);
-
- // Done reading metadata
- if (bm->new_block == 0 && bm->file_offset == 0) {
- break;
- }
-
- loff_t buffer_offset = bm->file_offset - start_data_offset;
- void* bufptr = static_cast<void*>((char*)read_ahead_buffer_ + buffer_offset);
- read_ahead_buffer_map[bm->new_block] = bufptr;
- num_ops += 1;
- total_blocks_merged += 1;
-
- metadata_offset += sizeof(struct ScratchMetadata);
- }
-
- // We are done re-constructing the mapping; however, we need to make sure
- // all the COW operations to-be merged are present in the re-constructed
- // mapping.
- while (!RAIterDone()) {
- const CowOperation* op = GetRAOpIter();
- if (read_ahead_buffer_map.find(op->new_block) != read_ahead_buffer_map.end()) {
- num_ops -= 1;
- RAIterNext();
- continue;
- }
-
- // Verify that we have covered all the ops which were re-constructed
- // from COW device - These are the ops which are being
- // re-constructed after crash.
- if (!(num_ops == 0)) {
- SNAP_LOG(ERROR) << "ReconstructDataFromCow failed. Not all ops recoverd "
- << " Pending ops: " << num_ops;
- snapuserd_->ReadAheadIOFailed();
- return false;
- }
-
- break;
- }
-
- snapuserd_->SetMergedBlockCountForNextCommit(total_blocks_merged);
-
- snapuserd_->FinishReconstructDataFromCow();
-
- if (!snapuserd_->ReadAheadIOCompleted(true)) {
- SNAP_LOG(ERROR) << "ReadAheadIOCompleted failed...";
- snapuserd_->ReadAheadIOFailed();
- return false;
- }
-
- SNAP_LOG(INFO) << "ReconstructDataFromCow success";
- return true;
-}
-
-/*
- * With io_uring, the data flow is slightly different.
- *
- * The data flow is as follows:
- *
- * 1: Queue the I/O requests to be read from backing source device.
- * This is done by retrieving the SQE entry from ring and populating
- * the SQE entry. Note that the I/O is not submitted yet.
- *
- * 2: Once the ring is full (aka queue_depth), we will submit all
- * the queued I/O request with a single system call. This essentially
- * cuts down "queue_depth" number of system calls to a single system call.
- *
- * 3: Once the I/O is submitted, user-space thread will now work
- * on processing the XOR Operations. This happens in parallel when
- * I/O requests are submitted to the kernel. This is ok because, for XOR
- * operations, we first need to retrieve the compressed data form COW block
- * device. Thus, we have offloaded the backing source I/O to the kernel
- * and user-space is parallely working on fetching the data for XOR operations.
- *
- * 4: After the XOR operations are read from COW device, poll the completion
- * queue for all the I/O submitted. If the I/O's were already completed,
- * then user-space thread will just read the CQE requests from the ring
- * without doing any system call. If none of the I/O were completed yet,
- * user-space thread will do a system call and wait for I/O completions.
- *
- * Flow diagram:
- * SQ-RING
- * SQE1 <----------- Fetch SQE1 Entry ---------- |SQE1||SQE2|SQE3|
- *
- * SQE1 ------------ Populate SQE1 Entry ------> |SQE1-X||SQE2|SQE3|
- *
- * SQE2 <----------- Fetch SQE2 Entry ---------- |SQE1-X||SQE2|SQE3|
- *
- * SQE2 ------------ Populate SQE2 Entry ------> |SQE1-X||SQE2-X|SQE3|
- *
- * SQE3 <----------- Fetch SQE3 Entry ---------- |SQE1-X||SQE2-X|SQE3|
- *
- * SQE3 ------------ Populate SQE3 Entry ------> |SQE1-X||SQE2-X|SQE3-X|
- *
- * Submit-IO ---------------------------------> |SQE1-X||SQE2-X|SQE3-X|
- * | |
- * | Process I/O entries in kernel
- * | |
- * Retrieve XOR |
- * data from COW |
- * | |
- * | |
- * Fetch CQ completions
- * | CQ-RING
- * |CQE1-X||CQE2-X|CQE3-X|
- * |
- * CQE1 <------------Fetch CQE1 Entry |CQE1||CQE2-X|CQE3-X|
- * CQE2 <------------Fetch CQE2 Entry |CQE1||CQE2-|CQE3-X|
- * CQE3 <------------Fetch CQE3 Entry |CQE1||CQE2-|CQE3-|
- * |
- * |
- * Continue Next set of operations in the RING
- */
-
-bool ReadAhead::ReadAheadAsyncIO() {
- int num_ops = (snapuserd_->GetBufferDataSize()) / BLOCK_SZ;
- loff_t buffer_offset = 0;
- total_blocks_merged_ = 0;
- overlap_ = false;
- dest_blocks_.clear();
- source_blocks_.clear();
- blocks_.clear();
- std::vector<const CowOperation*> xor_op_vec;
-
- int pending_sqe = queue_depth_;
- int pending_ios_to_submit = 0;
-
- size_t xor_op_index = 0;
- size_t block_index = 0;
-
- loff_t offset = 0;
-
- bufsink_.ResetBufferOffset();
-
- // Number of ops to be merged in this window. This is a fixed size
- // except for the last window wherein the number of ops can be less
- // than the size of the RA window.
- while (num_ops) {
- uint64_t source_offset;
- struct io_uring_sqe* sqe;
-
- int linear_blocks = PrepareNextReadAhead(&source_offset, &num_ops, blocks_, xor_op_vec);
-
- if (linear_blocks != 0) {
- size_t io_size = (linear_blocks * BLOCK_SZ);
-
- // Get an SQE entry from the ring and populate the I/O variables
- sqe = io_uring_get_sqe(ring_.get());
- if (!sqe) {
- SNAP_PLOG(ERROR) << "io_uring_get_sqe failed during read-ahead";
- return false;
- }
-
- io_uring_prep_read(sqe, backing_store_fd_.get(),
- (char*)ra_temp_buffer_.get() + buffer_offset, io_size,
- source_offset);
-
- buffer_offset += io_size;
- num_ops -= linear_blocks;
- total_blocks_merged_ += linear_blocks;
-
- pending_sqe -= 1;
- pending_ios_to_submit += 1;
- sqe->flags |= IOSQE_ASYNC;
- }
-
- // pending_sqe == 0 : Ring is full
- //
- // num_ops == 0 : All the COW ops in this batch are processed - Submit
- // pending I/O requests in the ring
- //
- // linear_blocks == 0 : All the COW ops processing is done. Submit
- // pending I/O requests in the ring
- if (pending_sqe == 0 || num_ops == 0 || (linear_blocks == 0 && pending_ios_to_submit)) {
- // Submit the IO for all the COW ops in a single syscall
- int ret = io_uring_submit(ring_.get());
- if (ret != pending_ios_to_submit) {
- SNAP_PLOG(ERROR) << "io_uring_submit failed for read-ahead: "
- << " io submit: " << ret << " expected: " << pending_ios_to_submit;
- return false;
- }
-
- int pending_ios_to_complete = pending_ios_to_submit;
- pending_ios_to_submit = 0;
-
- bool xor_processing_required = (xor_op_vec.size() > 0);
-
- // Read XOR data from COW file in parallel when I/O's are in-flight
- if (xor_processing_required && !ReadXorData(block_index, xor_op_index, xor_op_vec)) {
- SNAP_LOG(ERROR) << "ReadXorData failed";
- return false;
- }
-
- // Fetch I/O completions
- if (!ReapIoCompletions(pending_ios_to_complete)) {
- SNAP_LOG(ERROR) << "ReapIoCompletions failed";
- return false;
- }
-
- // Retrieve XOR'ed data
- if (xor_processing_required) {
- ProcessXorData(block_index, xor_op_index, xor_op_vec, ra_temp_buffer_.get(),
- offset);
- }
-
- // All the I/O in the ring is processed.
- pending_sqe = queue_depth_;
- }
-
- if (linear_blocks == 0) {
- break;
- }
- }
-
- // Done with merging ordered ops
- if (RAIterDone() && total_blocks_merged_ == 0) {
- return true;
- }
-
- CHECK(blocks_.size() == total_blocks_merged_);
-
- UpdateScratchMetadata();
-
- return true;
-}
-
-void ReadAhead::UpdateScratchMetadata() {
- loff_t metadata_offset = 0;
-
- struct ScratchMetadata* bm = reinterpret_cast<struct ScratchMetadata*>(
- (char*)ra_temp_meta_buffer_.get() + metadata_offset);
-
- bm->new_block = 0;
- bm->file_offset = 0;
-
- loff_t file_offset = snapuserd_->GetBufferDataOffset();
-
- for (size_t block_index = 0; block_index < blocks_.size(); block_index++) {
- uint64_t new_block = blocks_[block_index];
- // Track the metadata blocks which are stored in scratch space
- bm = reinterpret_cast<struct ScratchMetadata*>((char*)ra_temp_meta_buffer_.get() +
- metadata_offset);
-
- bm->new_block = new_block;
- bm->file_offset = file_offset;
-
- metadata_offset += sizeof(struct ScratchMetadata);
- file_offset += BLOCK_SZ;
- }
-
- // This is important - explicitly set the contents to zero. This is used
- // when re-constructing the data after crash. This indicates end of
- // reading metadata contents when re-constructing the data
- bm = reinterpret_cast<struct ScratchMetadata*>((char*)ra_temp_meta_buffer_.get() +
- metadata_offset);
- bm->new_block = 0;
- bm->file_offset = 0;
-}
-
-bool ReadAhead::ReapIoCompletions(int pending_ios_to_complete) {
- bool status = true;
-
- // Reap I/O completions
- while (pending_ios_to_complete) {
- struct io_uring_cqe* cqe;
-
- // io_uring_wait_cqe can potentially return -EAGAIN or -EINTR;
- // these error codes are not truly I/O errors; we can retry them
- // by re-populating the SQE entries and submitting the I/O
- // request back. However, we don't do that now; instead we
- // will fallback to synchronous I/O.
- int ret = io_uring_wait_cqe(ring_.get(), &cqe);
- if (ret) {
- SNAP_LOG(ERROR) << "Read-ahead - io_uring_wait_cqe failed: " << ret;
- status = false;
- break;
- }
-
- if (cqe->res < 0) {
- SNAP_LOG(ERROR) << "Read-ahead - io_uring_Wait_cqe failed with res: " << cqe->res;
- status = false;
- break;
- }
-
- io_uring_cqe_seen(ring_.get(), cqe);
- pending_ios_to_complete -= 1;
- }
-
- return status;
-}
-
-void ReadAhead::ProcessXorData(size_t& block_xor_index, size_t& xor_index,
- std::vector<const CowOperation*>& xor_op_vec, void* buffer,
- loff_t& buffer_offset) {
- loff_t xor_buf_offset = 0;
-
- while (block_xor_index < blocks_.size()) {
- void* bufptr = static_cast<void*>((char*)buffer + buffer_offset);
- uint64_t new_block = blocks_[block_xor_index];
-
- if (xor_index < xor_op_vec.size()) {
- const CowOperation* xor_op = xor_op_vec[xor_index];
-
- // Check if this block is an XOR op
- if (xor_op->new_block == new_block) {
- // Pointer to the data read from base device
- uint8_t* buffer = reinterpret_cast<uint8_t*>(bufptr);
- // Get the xor'ed data read from COW device
- uint8_t* xor_data = reinterpret_cast<uint8_t*>((char*)bufsink_.GetPayloadBufPtr() +
- xor_buf_offset);
-
- for (size_t byte_offset = 0; byte_offset < BLOCK_SZ; byte_offset++) {
- buffer[byte_offset] ^= xor_data[byte_offset];
- }
-
- // Move to next XOR op
- xor_index += 1;
- xor_buf_offset += BLOCK_SZ;
- }
- }
-
- buffer_offset += BLOCK_SZ;
- block_xor_index += 1;
- }
-
- bufsink_.ResetBufferOffset();
-}
-
-bool ReadAhead::ReadXorData(size_t block_index, size_t xor_op_index,
- std::vector<const CowOperation*>& xor_op_vec) {
- // Process the XOR ops in parallel - We will be reading data
- // from COW file for XOR ops processing.
- while (block_index < blocks_.size()) {
- uint64_t new_block = blocks_[block_index];
-
- if (xor_op_index < xor_op_vec.size()) {
- const CowOperation* xor_op = xor_op_vec[xor_op_index];
- if (xor_op->new_block == new_block) {
- if (!reader_->ReadData(*xor_op, &bufsink_)) {
- SNAP_LOG(ERROR)
- << " ReadAhead - XorOp Read failed for block: " << xor_op->new_block;
- return false;
- }
-
- xor_op_index += 1;
- bufsink_.UpdateBufferOffset(BLOCK_SZ);
- }
- }
- block_index += 1;
- }
- return true;
-}
-
-bool ReadAhead::ReadAheadSyncIO() {
- int num_ops = (snapuserd_->GetBufferDataSize()) / BLOCK_SZ;
- loff_t buffer_offset = 0;
- total_blocks_merged_ = 0;
- overlap_ = false;
- dest_blocks_.clear();
- source_blocks_.clear();
- blocks_.clear();
- std::vector<const CowOperation*> xor_op_vec;
-
- bufsink_.ResetBufferOffset();
-
- // Number of ops to be merged in this window. This is a fixed size
- // except for the last window wherein the number of ops can be less
- // than the size of the RA window.
- while (num_ops) {
- uint64_t source_offset;
-
- int linear_blocks = PrepareNextReadAhead(&source_offset, &num_ops, blocks_, xor_op_vec);
- if (linear_blocks == 0) {
- // No more blocks to read
- SNAP_LOG(DEBUG) << " Read-ahead completed....";
- break;
- }
-
- size_t io_size = (linear_blocks * BLOCK_SZ);
-
- // Read from the base device consecutive set of blocks in one shot
- if (!android::base::ReadFullyAtOffset(backing_store_fd_,
- (char*)ra_temp_buffer_.get() + buffer_offset, io_size,
- source_offset)) {
- SNAP_PLOG(ERROR) << "Ordered-op failed. Read from backing store: "
- << backing_store_device_ << "at block :" << source_offset / BLOCK_SZ
- << " offset :" << source_offset % BLOCK_SZ
- << " buffer_offset : " << buffer_offset << " io_size : " << io_size
- << " buf-addr : " << read_ahead_buffer_;
-
- snapuserd_->ReadAheadIOFailed();
- return false;
- }
-
- buffer_offset += io_size;
- total_blocks_merged_ += linear_blocks;
- num_ops -= linear_blocks;
- }
-
- // Done with merging ordered ops
- if (RAIterDone() && total_blocks_merged_ == 0) {
- return true;
- }
-
- loff_t metadata_offset = 0;
-
- struct ScratchMetadata* bm = reinterpret_cast<struct ScratchMetadata*>(
- (char*)ra_temp_meta_buffer_.get() + metadata_offset);
-
- bm->new_block = 0;
- bm->file_offset = 0;
-
- loff_t file_offset = snapuserd_->GetBufferDataOffset();
-
- loff_t offset = 0;
- CHECK(blocks_.size() == total_blocks_merged_);
-
- size_t xor_index = 0;
- BufferSink bufsink;
- bufsink.Initialize(BLOCK_SZ * 2);
-
- for (size_t block_index = 0; block_index < blocks_.size(); block_index++) {
- void* bufptr = static_cast<void*>((char*)ra_temp_buffer_.get() + offset);
- uint64_t new_block = blocks_[block_index];
-
- if (xor_index < xor_op_vec.size()) {
- const CowOperation* xor_op = xor_op_vec[xor_index];
-
- // Check if this block is an XOR op
- if (xor_op->new_block == new_block) {
- // Read the xor'ed data from COW
- if (!reader_->ReadData(*xor_op, &bufsink)) {
- SNAP_LOG(ERROR)
- << " ReadAhead - XorOp Read failed for block: " << xor_op->new_block;
- snapuserd_->ReadAheadIOFailed();
- return false;
- }
- // Pointer to the data read from base device
- uint8_t* buffer = reinterpret_cast<uint8_t*>(bufptr);
- // Get the xor'ed data read from COW device
- uint8_t* xor_data = reinterpret_cast<uint8_t*>(bufsink.GetPayloadBufPtr());
-
- // Retrieve the original data
- for (size_t byte_offset = 0; byte_offset < BLOCK_SZ; byte_offset++) {
- buffer[byte_offset] ^= xor_data[byte_offset];
- }
-
- // Move to next XOR op
- xor_index += 1;
- }
- }
-
- offset += BLOCK_SZ;
- // Track the metadata blocks which are stored in scratch space
- bm = reinterpret_cast<struct ScratchMetadata*>((char*)ra_temp_meta_buffer_.get() +
- metadata_offset);
-
- bm->new_block = new_block;
- bm->file_offset = file_offset;
-
- metadata_offset += sizeof(struct ScratchMetadata);
- file_offset += BLOCK_SZ;
- }
-
- // Verify if all the xor blocks were scanned to retrieve the original data
- CHECK(xor_index == xor_op_vec.size());
-
- // This is important - explicitly set the contents to zero. This is used
- // when re-constructing the data after crash. This indicates end of
- // reading metadata contents when re-constructing the data
- bm = reinterpret_cast<struct ScratchMetadata*>((char*)ra_temp_meta_buffer_.get() +
- metadata_offset);
- bm->new_block = 0;
- bm->file_offset = 0;
-
- return true;
-}
-
-bool ReadAhead::ReadAheadIOStart() {
- // Check if the data has to be constructed from the COW file.
- // This will be true only once during boot up after a crash
- // during merge.
- if (snapuserd_->ShouldReconstructDataFromCow()) {
- return ReconstructDataFromCow();
- }
-
- bool retry = false;
- bool ra_status;
-
- // Start Async read-ahead
- if (read_ahead_async_) {
- ra_status = ReadAheadAsyncIO();
- if (!ra_status) {
- SNAP_LOG(ERROR) << "ReadAheadAsyncIO failed - Falling back synchronous I/O";
- FinalizeIouring();
- RAResetIter(total_blocks_merged_);
- retry = true;
- read_ahead_async_ = false;
- }
- }
-
- // Check if we need to fallback and retry the merge
- //
- // If the device doesn't support async operations, we
- // will directly enter here (aka devices with 4.x kernels)
-
- const bool ra_sync_required = (retry || !read_ahead_async_);
-
- if (ra_sync_required) {
- ra_status = ReadAheadSyncIO();
- if (!ra_status) {
- SNAP_LOG(ERROR) << "ReadAheadSyncIO failed";
- return false;
- }
- }
-
- SNAP_LOG(DEBUG) << "Read-ahead: total_ra_blocks_merged: " << total_ra_blocks_completed_;
-
- // Wait for the merge to finish for the previous RA window. We shouldn't
- // be touching the scratch space until merge is complete of previous RA
- // window. If there is a crash during this time frame, merge should resume
- // based on the contents of the scratch space.
- if (!snapuserd_->WaitForMergeReady()) {
- return false;
- }
-
- // Copy the data to scratch space
- memcpy(metadata_buffer_, ra_temp_meta_buffer_.get(), snapuserd_->GetBufferMetadataSize());
- memcpy(read_ahead_buffer_, ra_temp_buffer_.get(), total_blocks_merged_ * BLOCK_SZ);
-
- loff_t offset = 0;
- std::unordered_map<uint64_t, void*>& read_ahead_buffer_map = snapuserd_->GetReadAheadMap();
- read_ahead_buffer_map.clear();
-
- for (size_t block_index = 0; block_index < blocks_.size(); block_index++) {
- void* bufptr = static_cast<void*>((char*)read_ahead_buffer_ + offset);
- uint64_t new_block = blocks_[block_index];
-
- read_ahead_buffer_map[new_block] = bufptr;
- offset += BLOCK_SZ;
- }
-
- total_ra_blocks_completed_ += total_blocks_merged_;
- snapuserd_->SetMergedBlockCountForNextCommit(total_blocks_merged_);
-
- // Flush the data only if we have a overlapping blocks in the region
- // Notify the Merge thread to resume merging this window
- if (!snapuserd_->ReadAheadIOCompleted(overlap_)) {
- SNAP_LOG(ERROR) << "ReadAheadIOCompleted failed...";
- snapuserd_->ReadAheadIOFailed();
- return false;
- }
-
- return true;
-}
-
-bool ReadAhead::InitializeIouring() {
- if (!snapuserd_->IsIouringSupported()) {
- return false;
- }
-
- ring_ = std::make_unique<struct io_uring>();
-
- int ret = io_uring_queue_init(queue_depth_, ring_.get(), 0);
- if (ret) {
- SNAP_LOG(ERROR) << "io_uring_queue_init failed with ret: " << ret;
- return false;
- }
-
- // For xor ops processing
- bufsink_.Initialize(PAYLOAD_BUFFER_SZ * 2);
- read_ahead_async_ = true;
-
- SNAP_LOG(INFO) << "Read-ahead: io_uring initialized with queue depth: " << queue_depth_;
- return true;
-}
-
-void ReadAhead::FinalizeIouring() {
- if (read_ahead_async_) {
- io_uring_queue_exit(ring_.get());
- }
-}
-
-bool ReadAhead::RunThread() {
- if (!InitializeFds()) {
- return false;
- }
-
- InitializeBuffer();
-
- if (!InitReader()) {
- return false;
- }
-
- InitializeRAIter();
-
- InitializeIouring();
-
- while (!RAIterDone()) {
- if (!ReadAheadIOStart()) {
- break;
- }
- }
-
- FinalizeIouring();
- CloseFds();
- reader_->CloseCowFd();
-
- SNAP_LOG(INFO) << " ReadAhead thread terminating....";
- return true;
-}
-
-// Initialization
-bool ReadAhead::InitializeFds() {
- backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
- if (backing_store_fd_ < 0) {
- SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_;
- return false;
- }
-
- cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
- if (cow_fd_ < 0) {
- SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
- return false;
- }
-
- return true;
-}
-
-bool ReadAhead::InitReader() {
- reader_ = snapuserd_->CloneReaderForWorker();
-
- if (!reader_->InitForMerge(std::move(cow_fd_))) {
- return false;
- }
- return true;
-}
-
-void ReadAhead::InitializeRAIter() {
- cowop_iter_ = reader_->GetMergeOpIter();
-}
-
-bool ReadAhead::RAIterDone() {
- if (cowop_iter_->Done()) {
- return true;
- }
-
- const CowOperation* cow_op = GetRAOpIter();
-
- if (!IsOrderedOp(*cow_op)) {
- return true;
- }
-
- return false;
-}
-
-void ReadAhead::RAIterNext() {
- cowop_iter_->Next();
-}
-
-void ReadAhead::RAResetIter(uint64_t num_blocks) {
- while (num_blocks && !cowop_iter_->RDone()) {
- cowop_iter_->Prev();
- num_blocks -= 1;
- }
-}
-
-const CowOperation* ReadAhead::GetRAOpIter() {
- const CowOperation* cow_op = &cowop_iter_->Get();
- return cow_op;
-}
-
-void ReadAhead::InitializeBuffer() {
- void* mapped_addr = snapuserd_->GetMappedAddr();
- // Map the scratch space region into memory
- metadata_buffer_ =
- static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferMetadataOffset());
- read_ahead_buffer_ = static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferDataOffset());
-
- ra_temp_buffer_ = std::make_unique<uint8_t[]>(snapuserd_->GetBufferDataSize());
- ra_temp_meta_buffer_ = std::make_unique<uint8_t[]>(snapuserd_->GetBufferMetadataSize());
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
deleted file mode 100644
index 82b2b25dd..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <arpa/inet.h>
-#include <cutils/sockets.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android-base/cmsg.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/scopeguard.h>
-#include <fs_mgr/file_wait.h>
-#include <snapuserd/snapuserd_client.h>
-#include "snapuserd_server.h"
-
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-namespace android {
-namespace snapshot {
-
-using namespace std::string_literals;
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-
-DaemonOps UserSnapshotServer::Resolveop(std::string& input) {
- if (input == "init") return DaemonOps::INIT;
- if (input == "start") return DaemonOps::START;
- if (input == "stop") return DaemonOps::STOP;
- if (input == "query") return DaemonOps::QUERY;
- if (input == "delete") return DaemonOps::DELETE;
- if (input == "detach") return DaemonOps::DETACH;
- if (input == "supports") return DaemonOps::SUPPORTS;
- if (input == "initiate_merge") return DaemonOps::INITIATE;
- if (input == "merge_percent") return DaemonOps::PERCENTAGE;
- if (input == "getstatus") return DaemonOps::GETSTATUS;
-
- return DaemonOps::INVALID;
-}
-
-UserSnapshotServer::~UserSnapshotServer() {
- // Close any client sockets that were added via AcceptClient().
- for (size_t i = 1; i < watched_fds_.size(); i++) {
- close(watched_fds_[i].fd);
- }
-}
-
-std::string UserSnapshotServer::GetDaemonStatus() {
- std::string msg = "";
-
- if (IsTerminating())
- msg = "passive";
- else
- msg = "active";
-
- return msg;
-}
-
-void UserSnapshotServer::Parsemsg(std::string const& msg, const char delim,
- std::vector<std::string>& out) {
- std::stringstream ss(msg);
- std::string s;
-
- while (std::getline(ss, s, delim)) {
- out.push_back(s);
- }
-}
-
-void UserSnapshotServer::ShutdownThreads() {
- terminating_ = true;
- JoinAllThreads();
-}
-
-UserSnapshotDmUserHandler::UserSnapshotDmUserHandler(std::shared_ptr<SnapshotHandler> snapuserd)
- : snapuserd_(snapuserd), misc_name_(snapuserd_->GetMiscName()) {}
-
-bool UserSnapshotServer::Sendmsg(android::base::borrowed_fd fd, const std::string& msg) {
- ssize_t ret = TEMP_FAILURE_RETRY(send(fd.get(), msg.data(), msg.size(), MSG_NOSIGNAL));
- if (ret < 0) {
- PLOG(ERROR) << "Snapuserd:server: send() failed";
- return false;
- }
-
- if (ret < msg.size()) {
- LOG(ERROR) << "Partial send; expected " << msg.size() << " bytes, sent " << ret;
- return false;
- }
- return true;
-}
-
-bool UserSnapshotServer::Recv(android::base::borrowed_fd fd, std::string* data) {
- char msg[kMaxPacketSize];
- ssize_t rv = TEMP_FAILURE_RETRY(recv(fd.get(), msg, sizeof(msg), 0));
- if (rv < 0) {
- PLOG(ERROR) << "recv failed";
- return false;
- }
- *data = std::string(msg, rv);
- return true;
-}
-
-bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::string& str) {
- const char delim = ',';
-
- std::vector<std::string> out;
- Parsemsg(str, delim, out);
- DaemonOps op = Resolveop(out[0]);
-
- switch (op) {
- case DaemonOps::INIT: {
- // Message format:
- // init,<misc_name>,<cow_device_path>,<backing_device>,<base_path_merge>
- //
- // Reads the metadata and send the number of sectors
- if (out.size() != 5) {
- LOG(ERROR) << "Malformed init message, " << out.size() << " parts";
- return Sendmsg(fd, "fail");
- }
-
- auto handler = AddHandler(out[1], out[2], out[3], out[4]);
- if (!handler) {
- return Sendmsg(fd, "fail");
- }
-
- auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors());
- return Sendmsg(fd, retval);
- }
- case DaemonOps::START: {
- // Message format:
- // start,<misc_name>
- //
- // Start the new thread which binds to dm-user misc device
- if (out.size() != 2) {
- LOG(ERROR) << "Malformed start message, " << out.size() << " parts";
- return Sendmsg(fd, "fail");
- }
-
- std::lock_guard<std::mutex> lock(lock_);
- auto iter = FindHandler(&lock, out[1]);
- if (iter == dm_users_.end()) {
- LOG(ERROR) << "Could not find handler: " << out[1];
- return Sendmsg(fd, "fail");
- }
- if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) {
- LOG(ERROR) << "Tried to re-attach control device: " << out[1];
- return Sendmsg(fd, "fail");
- }
- if (!StartHandler(*iter)) {
- return Sendmsg(fd, "fail");
- }
- return Sendmsg(fd, "success");
- }
- case DaemonOps::STOP: {
- // Message format: stop
- //
- // Stop all the threads gracefully and then shutdown the
- // main thread
- SetTerminating();
- ShutdownThreads();
- return true;
- }
- case DaemonOps::QUERY: {
- // Message format: query
- //
- // As part of transition, Second stage daemon will be
- // created before terminating the first stage daemon. Hence,
- // for a brief period client may have to distiguish between
- // first stage daemon and second stage daemon.
- //
- // Second stage daemon is marked as active and hence will
- // be ready to receive control message.
- return Sendmsg(fd, GetDaemonStatus());
- }
- case DaemonOps::DELETE: {
- // Message format:
- // delete,<misc_name>
- if (out.size() != 2) {
- LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
- return Sendmsg(fd, "fail");
- }
- {
- std::lock_guard<std::mutex> lock(lock_);
- auto iter = FindHandler(&lock, out[1]);
- if (iter == dm_users_.end()) {
- // After merge is completed, we swap dm-user table with
- // the underlying dm-linear base device. Hence, worker
- // threads would have terminted and was removed from
- // the list.
- LOG(DEBUG) << "Could not find handler: " << out[1];
- return Sendmsg(fd, "success");
- }
-
- if (!(*iter)->ThreadTerminated()) {
- (*iter)->snapuserd()->NotifyIOTerminated();
- }
- }
- if (!RemoveAndJoinHandler(out[1])) {
- return Sendmsg(fd, "fail");
- }
- return Sendmsg(fd, "success");
- }
- case DaemonOps::DETACH: {
- std::lock_guard<std::mutex> lock(lock_);
- TerminateMergeThreads(&lock);
- terminating_ = true;
- return true;
- }
- case DaemonOps::SUPPORTS: {
- if (out.size() != 2) {
- LOG(ERROR) << "Malformed supports message, " << out.size() << " parts";
- return Sendmsg(fd, "fail");
- }
- if (out[1] == "second_stage_socket_handoff") {
- return Sendmsg(fd, "success");
- }
- return Sendmsg(fd, "fail");
- }
- case DaemonOps::INITIATE: {
- if (out.size() != 2) {
- LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts";
- return Sendmsg(fd, "fail");
- }
- if (out[0] == "initiate_merge") {
- std::lock_guard<std::mutex> lock(lock_);
- auto iter = FindHandler(&lock, out[1]);
- if (iter == dm_users_.end()) {
- LOG(ERROR) << "Could not find handler: " << out[1];
- return Sendmsg(fd, "fail");
- }
-
- if (!StartMerge(*iter)) {
- return Sendmsg(fd, "fail");
- }
-
- return Sendmsg(fd, "success");
- }
- return Sendmsg(fd, "fail");
- }
- case DaemonOps::PERCENTAGE: {
- std::lock_guard<std::mutex> lock(lock_);
- double percentage = GetMergePercentage(&lock);
-
- return Sendmsg(fd, std::to_string(percentage));
- }
- case DaemonOps::GETSTATUS: {
- // Message format:
- // getstatus,<misc_name>
- if (out.size() != 2) {
- LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
- return Sendmsg(fd, "snapshot-merge-failed");
- }
- {
- std::lock_guard<std::mutex> lock(lock_);
- auto iter = FindHandler(&lock, out[1]);
- if (iter == dm_users_.end()) {
- LOG(ERROR) << "Could not find handler: " << out[1];
- return Sendmsg(fd, "snapshot-merge-failed");
- }
-
- std::string merge_status = GetMergeStatus(*iter);
- return Sendmsg(fd, merge_status);
- }
- }
- default: {
- LOG(ERROR) << "Received unknown message type from client";
- Sendmsg(fd, "fail");
- return false;
- }
- }
-}
-
-void UserSnapshotServer::RunThread(std::shared_ptr<UserSnapshotDmUserHandler> handler) {
- LOG(INFO) << "Entering thread for handler: " << handler->misc_name();
-
- if (!handler->snapuserd()->Start()) {
- LOG(ERROR) << " Failed to launch all worker threads";
- }
-
- handler->snapuserd()->CloseFds();
- handler->snapuserd()->CheckMergeCompletionStatus();
- handler->snapuserd()->UnmapBufferRegion();
-
- auto misc_name = handler->misc_name();
- LOG(INFO) << "Handler thread about to exit: " << misc_name;
-
- {
- std::lock_guard<std::mutex> lock(lock_);
- num_partitions_merge_complete_ += 1;
- handler->SetThreadTerminated();
- auto iter = FindHandler(&lock, handler->misc_name());
- if (iter == dm_users_.end()) {
- // RemoveAndJoinHandler() already removed us from the list, and is
- // now waiting on a join(), so just return. Additionally, release
- // all the resources held by snapuserd object which are shared
- // by worker threads. This should be done when the last reference
- // of "handler" is released; but we will explicitly release here
- // to make sure snapuserd object is freed as it is the biggest
- // consumer of memory in the daemon.
- handler->FreeResources();
- LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name;
- return;
- }
-
- LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name;
-
- if (handler->snapuserd()->IsAttached()) {
- handler->thread().detach();
- }
-
- // Important: free resources within the lock. This ensures that if
- // WaitForDelete() is called, the handler is either in the list, or
- // it's not and its resources are guaranteed to be freed.
- handler->FreeResources();
- dm_users_.erase(iter);
- }
-}
-
-bool UserSnapshotServer::Start(const std::string& socketname) {
- bool start_listening = true;
-
- sockfd_.reset(android_get_control_socket(socketname.c_str()));
- if (sockfd_ < 0) {
- sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM));
- if (sockfd_ < 0) {
- PLOG(ERROR) << "Failed to create server socket " << socketname;
- return false;
- }
- start_listening = false;
- }
- return StartWithSocket(start_listening);
-}
-
-bool UserSnapshotServer::StartWithSocket(bool start_listening) {
- if (start_listening && listen(sockfd_.get(), 4) < 0) {
- PLOG(ERROR) << "listen socket failed";
- return false;
- }
-
- AddWatchedFd(sockfd_, POLLIN);
- is_socket_present_ = true;
-
- // If started in first-stage init, the property service won't be online.
- if (access("/dev/socket/property_service", F_OK) == 0) {
- if (!android::base::SetProperty("snapuserd.ready", "true")) {
- LOG(ERROR) << "Failed to set snapuserd.ready property";
- return false;
- }
- }
-
- LOG(DEBUG) << "Snapuserd server now accepting connections";
- return true;
-}
-
-bool UserSnapshotServer::Run() {
- LOG(INFO) << "Now listening on snapuserd socket";
-
- while (!IsTerminating()) {
- int rv = TEMP_FAILURE_RETRY(poll(watched_fds_.data(), watched_fds_.size(), -1));
- if (rv < 0) {
- PLOG(ERROR) << "poll failed";
- return false;
- }
- if (!rv) {
- continue;
- }
-
- if (watched_fds_[0].revents) {
- AcceptClient();
- }
-
- auto iter = watched_fds_.begin() + 1;
- while (iter != watched_fds_.end()) {
- if (iter->revents && !HandleClient(iter->fd, iter->revents)) {
- close(iter->fd);
- iter = watched_fds_.erase(iter);
- } else {
- iter++;
- }
- }
- }
-
- JoinAllThreads();
- return true;
-}
-
-void UserSnapshotServer::JoinAllThreads() {
- // Acquire the thread list within the lock.
- std::vector<std::shared_ptr<UserSnapshotDmUserHandler>> dm_users;
- {
- std::lock_guard<std::mutex> guard(lock_);
- dm_users = std::move(dm_users_);
- }
-
- for (auto& client : dm_users) {
- auto& th = client->thread();
-
- if (th.joinable()) th.join();
- }
-}
-
-void UserSnapshotServer::AddWatchedFd(android::base::borrowed_fd fd, int events) {
- struct pollfd p = {};
- p.fd = fd.get();
- p.events = events;
- watched_fds_.emplace_back(std::move(p));
-}
-
-void UserSnapshotServer::AcceptClient() {
- int fd = TEMP_FAILURE_RETRY(accept4(sockfd_.get(), nullptr, nullptr, SOCK_CLOEXEC));
- if (fd < 0) {
- PLOG(ERROR) << "accept4 failed";
- return;
- }
-
- AddWatchedFd(fd, POLLIN);
-}
-
-bool UserSnapshotServer::HandleClient(android::base::borrowed_fd fd, int revents) {
- if (revents & POLLHUP) {
- LOG(DEBUG) << "Snapuserd client disconnected";
- return false;
- }
-
- std::string str;
- if (!Recv(fd, &str)) {
- return false;
- }
- if (!Receivemsg(fd, str)) {
- LOG(ERROR) << "Encountered error handling client message, revents: " << revents;
- return false;
- }
- return true;
-}
-
-void UserSnapshotServer::Interrupt() {
- // Force close the socket so poll() fails.
- sockfd_ = {};
- SetTerminating();
-}
-
-std::shared_ptr<UserSnapshotDmUserHandler> UserSnapshotServer::AddHandler(
- const std::string& misc_name, const std::string& cow_device_path,
- const std::string& backing_device, const std::string& base_path_merge) {
- auto snapuserd = std::make_shared<SnapshotHandler>(misc_name, cow_device_path, backing_device,
- base_path_merge);
- if (!snapuserd->InitCowDevice()) {
- LOG(ERROR) << "Failed to initialize Snapuserd";
- return nullptr;
- }
-
- snapuserd->SetSocketPresent(is_socket_present_);
- snapuserd->SetIouringEnabled(io_uring_enabled_);
-
- if (!snapuserd->InitializeWorkers()) {
- LOG(ERROR) << "Failed to initialize workers";
- return nullptr;
- }
-
- auto handler = std::make_shared<UserSnapshotDmUserHandler>(snapuserd);
- {
- std::lock_guard<std::mutex> lock(lock_);
- if (FindHandler(&lock, misc_name) != dm_users_.end()) {
- LOG(ERROR) << "Handler already exists: " << misc_name;
- return nullptr;
- }
- dm_users_.push_back(handler);
- }
- return handler;
-}
-
-bool UserSnapshotServer::StartHandler(const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
- if (handler->snapuserd()->IsAttached()) {
- LOG(ERROR) << "Handler already attached";
- return false;
- }
-
- handler->snapuserd()->AttachControlDevice();
-
- handler->thread() = std::thread(std::bind(&UserSnapshotServer::RunThread, this, handler));
- return true;
-}
-
-bool UserSnapshotServer::StartMerge(const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
- if (!handler->snapuserd()->IsAttached()) {
- LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started";
- return false;
- }
-
- handler->snapuserd()->InitiateMerge();
- return true;
-}
-
-auto UserSnapshotServer::FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
- const std::string& misc_name) -> HandlerList::iterator {
- CHECK(proof_of_lock);
-
- for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
- if ((*iter)->misc_name() == misc_name) {
- return iter;
- }
- }
- return dm_users_.end();
-}
-
-void UserSnapshotServer::TerminateMergeThreads(std::lock_guard<std::mutex>* proof_of_lock) {
- CHECK(proof_of_lock);
-
- for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
- if (!(*iter)->ThreadTerminated()) {
- (*iter)->snapuserd()->NotifyIOTerminated();
- }
- }
-}
-
-std::string UserSnapshotServer::GetMergeStatus(
- const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
- return handler->snapuserd()->GetMergeStatus();
-}
-
-double UserSnapshotServer::GetMergePercentage(std::lock_guard<std::mutex>* proof_of_lock) {
- CHECK(proof_of_lock);
- double percentage = 0.0;
- int n = 0;
-
- for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
- auto& th = (*iter)->thread();
- if (th.joinable()) {
- // Merge percentage by individual partitions wherein merge is still
- // in-progress
- percentage += (*iter)->snapuserd()->GetMergePercentage();
- n += 1;
- }
- }
-
- // Calculate final merge including those partitions where merge was already
- // completed - num_partitions_merge_complete_ will track them when each
- // thread exists in RunThread.
- int total_partitions = n + num_partitions_merge_complete_;
-
- if (total_partitions) {
- percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions;
- }
-
- LOG(DEBUG) << "Merge %: " << percentage
- << " num_partitions_merge_complete_: " << num_partitions_merge_complete_
- << " total_partitions: " << total_partitions << " n: " << n;
- return percentage;
-}
-
-bool UserSnapshotServer::RemoveAndJoinHandler(const std::string& misc_name) {
- std::shared_ptr<UserSnapshotDmUserHandler> handler;
- {
- std::lock_guard<std::mutex> lock(lock_);
-
- auto iter = FindHandler(&lock, misc_name);
- if (iter == dm_users_.end()) {
- // Client already deleted.
- return true;
- }
- handler = std::move(*iter);
- dm_users_.erase(iter);
- }
-
- auto& th = handler->thread();
- if (th.joinable()) {
- th.join();
- }
- return true;
-}
-
-bool UserSnapshotServer::WaitForSocket() {
- auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); });
-
- auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy;
-
- if (!android::fs_mgr::WaitForFile(socket_path, std::chrono::milliseconds::max())) {
- LOG(ERROR)
- << "Failed to wait for proxy socket, second-stage snapuserd will fail to connect";
- return false;
- }
-
- // This initialization of system property is important. When daemon is
- // launched post selinux transition (before init second stage),
- // bionic libc initializes system property as part of __libc_init_common();
- // however that initialization fails silently given that fact that we don't
- // have /dev/__properties__ setup which is created at init second stage.
- //
- // At this point, we have the handlers setup and is safe to setup property.
- __system_properties_init();
-
- if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {
- LOG(ERROR)
- << "Failed to wait for proxy property, second-stage snapuserd will fail to connect";
- return false;
- }
-
- unique_fd fd(socket_local_client(kSnapuserdSocketProxy, ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET));
- if (fd < 0) {
- PLOG(ERROR) << "Failed to connect to socket proxy";
- return false;
- }
-
- char code[1];
- std::vector<unique_fd> fds;
- ssize_t rv = android::base::ReceiveFileDescriptorVector(fd, code, sizeof(code), 1, &fds);
- if (rv < 0) {
- PLOG(ERROR) << "Failed to receive server socket over proxy";
- return false;
- }
- if (fds.empty()) {
- LOG(ERROR) << "Expected at least one file descriptor from proxy";
- return false;
- }
-
- // We don't care if the ACK is received.
- code[0] = 'a';
- if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL) < 0)) {
- PLOG(ERROR) << "Failed to send ACK to proxy";
- return false;
- }
-
- sockfd_ = std::move(fds[0]);
- if (!StartWithSocket(true)) {
- return false;
- }
- return Run();
-}
-
-bool UserSnapshotServer::RunForSocketHandoff() {
- unique_fd proxy_fd(android_get_control_socket(kSnapuserdSocketProxy));
- if (proxy_fd < 0) {
- PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocketProxy;
- }
- borrowed_fd server_fd(android_get_control_socket(kSnapuserdSocket));
- if (server_fd < 0) {
- PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocket;
- }
-
- if (listen(proxy_fd.get(), 4) < 0) {
- PLOG(FATAL) << "Proxy listen socket failed";
- }
-
- if (!android::base::SetProperty("snapuserd.proxy_ready", "true")) {
- LOG(FATAL) << "Proxy failed to set ready property";
- }
-
- unique_fd client_fd(
- TEMP_FAILURE_RETRY(accept4(proxy_fd.get(), nullptr, nullptr, SOCK_CLOEXEC)));
- if (client_fd < 0) {
- PLOG(FATAL) << "Proxy accept failed";
- }
-
- char code[1] = {'a'};
- std::vector<int> fds = {server_fd.get()};
- ssize_t rv = android::base::SendFileDescriptorVector(client_fd, code, sizeof(code), fds);
- if (rv < 0) {
- PLOG(FATAL) << "Proxy could not send file descriptor to snapuserd";
- }
- // Wait for an ACK - results don't matter, we just don't want to risk closing
- // the proxy socket too early.
- if (recv(client_fd, code, sizeof(code), 0) < 0) {
- PLOG(FATAL) << "Proxy could not receive terminating code from snapuserd";
- }
- return true;
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
deleted file mode 100644
index 34e7941bc..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <poll.h>
-
-#include <cstdio>
-#include <cstring>
-#include <functional>
-#include <future>
-#include <iostream>
-#include <mutex>
-#include <sstream>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <android-base/unique_fd.h>
-#include "snapuserd_core.h"
-
-namespace android {
-namespace snapshot {
-
-static constexpr uint32_t kMaxPacketSize = 512;
-
-enum class DaemonOps {
- INIT,
- START,
- QUERY,
- STOP,
- DELETE,
- DETACH,
- SUPPORTS,
- INITIATE,
- PERCENTAGE,
- GETSTATUS,
- INVALID,
-};
-
-class UserSnapshotDmUserHandler {
- public:
- explicit UserSnapshotDmUserHandler(std::shared_ptr<SnapshotHandler> snapuserd);
-
- void FreeResources() {
- // Each worker thread holds a reference to snapuserd.
- // Clear them so that all the resources
- // held by snapuserd is released
- if (snapuserd_) {
- snapuserd_->FreeResources();
- snapuserd_ = nullptr;
- }
- }
- const std::shared_ptr<SnapshotHandler>& snapuserd() const { return snapuserd_; }
- std::thread& thread() { return thread_; }
-
- const std::string& misc_name() const { return misc_name_; }
- bool ThreadTerminated() { return thread_terminated_; }
- void SetThreadTerminated() { thread_terminated_ = true; }
-
- private:
- std::thread thread_;
- std::shared_ptr<SnapshotHandler> snapuserd_;
- std::string misc_name_;
- bool thread_terminated_ = false;
-};
-
-class UserSnapshotServer {
- private:
- android::base::unique_fd sockfd_;
- bool terminating_;
- volatile bool received_socket_signal_ = false;
- std::vector<struct pollfd> watched_fds_;
- bool is_socket_present_ = false;
- int num_partitions_merge_complete_ = 0;
- bool is_server_running_ = false;
- bool io_uring_enabled_ = false;
-
- std::mutex lock_;
-
- using HandlerList = std::vector<std::shared_ptr<UserSnapshotDmUserHandler>>;
- HandlerList dm_users_;
-
- void AddWatchedFd(android::base::borrowed_fd fd, int events);
- void AcceptClient();
- bool HandleClient(android::base::borrowed_fd fd, int revents);
- bool Recv(android::base::borrowed_fd fd, std::string* data);
- bool Sendmsg(android::base::borrowed_fd fd, const std::string& msg);
- bool Receivemsg(android::base::borrowed_fd fd, const std::string& str);
-
- void ShutdownThreads();
- bool RemoveAndJoinHandler(const std::string& control_device);
- DaemonOps Resolveop(std::string& input);
- std::string GetDaemonStatus();
- void Parsemsg(std::string const& msg, const char delim, std::vector<std::string>& out);
-
- bool IsTerminating() { return terminating_; }
-
- void RunThread(std::shared_ptr<UserSnapshotDmUserHandler> handler);
- void JoinAllThreads();
- bool StartWithSocket(bool start_listening);
-
- // Find a UserSnapshotDmUserHandler within a lock.
- HandlerList::iterator FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
- const std::string& misc_name);
-
- double GetMergePercentage(std::lock_guard<std::mutex>* proof_of_lock);
- void TerminateMergeThreads(std::lock_guard<std::mutex>* proof_of_lock);
-
- public:
- UserSnapshotServer() { terminating_ = false; }
- ~UserSnapshotServer();
-
- bool Start(const std::string& socketname);
- bool Run();
- void Interrupt();
- bool RunForSocketHandoff();
- bool WaitForSocket();
-
- std::shared_ptr<UserSnapshotDmUserHandler> AddHandler(const std::string& misc_name,
- const std::string& cow_device_path,
- const std::string& backing_device,
- const std::string& base_path_merge);
- bool StartHandler(const std::shared_ptr<UserSnapshotDmUserHandler>& handler);
- bool StartMerge(const std::shared_ptr<UserSnapshotDmUserHandler>& handler);
- std::string GetMergeStatus(const std::shared_ptr<UserSnapshotDmUserHandler>& handler);
-
- void SetTerminating() { terminating_ = true; }
- void ReceivedSocketSignal() { received_socket_signal_ = true; }
- void SetServerRunning() { is_server_running_ = true; }
- bool IsServerRunning() { return is_server_running_; }
- void SetIouringEnabled() { io_uring_enabled_ = true; }
- bool IsIouringEnabled() { return io_uring_enabled_; }
-};
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
deleted file mode 100644
index d670f1e53..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ /dev/null
@@ -1,885 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <android-base/strings.h>
-#include <gflags/gflags.h>
-
-#include <fcntl.h>
-#include <linux/fs.h>
-#include <linux/memfd.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <iostream>
-#include <memory>
-#include <string_view>
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <android-base/unique_fd.h>
-#include <fs_mgr/file_wait.h>
-#include <gtest/gtest.h>
-#include <libdm/dm.h>
-#include <libdm/loop_control.h>
-#include <libsnapshot/cow_writer.h>
-#include <snapuserd/snapuserd_client.h>
-#include <storage_literals/storage_literals.h>
-
-#include "snapuserd_core.h"
-
-DEFINE_string(force_config, "", "Force testing mode with iouring disabled");
-
-namespace android {
-namespace snapshot {
-
-using namespace android::storage_literals;
-using android::base::unique_fd;
-using LoopDevice = android::dm::LoopDevice;
-using namespace std::chrono_literals;
-using namespace android::dm;
-using namespace std;
-
-static constexpr char kSnapuserdSocketTest[] = "snapuserdTest";
-
-class Tempdevice {
- public:
- Tempdevice(const std::string& name, const DmTable& table)
- : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
- valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5));
- }
- Tempdevice(Tempdevice&& other) noexcept
- : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
- other.valid_ = false;
- }
- ~Tempdevice() {
- if (valid_) {
- dm_.DeleteDevice(name_);
- }
- }
- bool Destroy() {
- if (!valid_) {
- return false;
- }
- valid_ = false;
- return dm_.DeleteDevice(name_);
- }
- const std::string& path() const { return path_; }
- const std::string& name() const { return name_; }
- bool valid() const { return valid_; }
-
- Tempdevice(const Tempdevice&) = delete;
- Tempdevice& operator=(const Tempdevice&) = delete;
-
- Tempdevice& operator=(Tempdevice&& other) noexcept {
- name_ = other.name_;
- valid_ = other.valid_;
- other.valid_ = false;
- return *this;
- }
-
- private:
- DeviceMapper& dm_;
- std::string name_;
- std::string path_;
- bool valid_;
-};
-
-class SnapuserTest final {
- public:
- bool Setup();
- bool SetupOrderedOps();
- bool SetupOrderedOpsInverted();
- bool SetupCopyOverlap_1();
- bool SetupCopyOverlap_2();
- bool Merge();
- void ValidateMerge();
- void ReadSnapshotDeviceAndValidate();
- void Shutdown();
- void MergeInterrupt();
- void MergeInterruptFixed(int duration);
- void MergeInterruptRandomly(int max_duration);
- void StartMerge();
- void CheckMergeCompletion();
-
- static const uint64_t kSectorSize = 512;
-
- private:
- void SetupImpl();
-
- void SimulateDaemonRestart();
-
- void CreateCowDevice();
- void CreateCowDeviceOrderedOps();
- void CreateCowDeviceOrderedOpsInverted();
- void CreateCowDeviceWithCopyOverlap_1();
- void CreateCowDeviceWithCopyOverlap_2();
- bool SetupDaemon();
- void CreateBaseDevice();
- void InitCowDevice();
- void SetDeviceControlName();
- void InitDaemon();
- void CreateDmUserDevice();
- void StartSnapuserdDaemon();
-
- unique_ptr<LoopDevice> base_loop_;
- unique_ptr<Tempdevice> dmuser_dev_;
-
- std::string system_device_ctrl_name_;
- std::string system_device_name_;
-
- unique_fd base_fd_;
- std::unique_ptr<TemporaryFile> cow_system_;
- std::unique_ptr<SnapuserdClient> client_;
- std::unique_ptr<uint8_t[]> orig_buffer_;
- std::unique_ptr<uint8_t[]> merged_buffer_;
- bool setup_ok_ = false;
- bool merge_ok_ = false;
- size_t size_ = 100_MiB;
- int cow_num_sectors_;
- int total_base_size_;
-};
-
-static unique_fd CreateTempFile(const std::string& name, size_t size) {
- unique_fd fd(syscall(__NR_memfd_create, name.c_str(), MFD_ALLOW_SEALING));
- if (fd < 0) {
- return {};
- }
- if (size) {
- if (ftruncate(fd, size) < 0) {
- perror("ftruncate");
- return {};
- }
- if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
- perror("fcntl");
- return {};
- }
- }
- return fd;
-}
-
-void SnapuserTest::Shutdown() {
- ASSERT_TRUE(dmuser_dev_->Destroy());
-
- auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
- ASSERT_TRUE(client_->WaitForDeviceDelete(system_device_ctrl_name_));
- ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s));
- ASSERT_TRUE(client_->DetachSnapuserd());
-}
-
-bool SnapuserTest::Setup() {
- SetupImpl();
- return setup_ok_;
-}
-
-bool SnapuserTest::SetupOrderedOps() {
- CreateBaseDevice();
- CreateCowDeviceOrderedOps();
- return SetupDaemon();
-}
-
-bool SnapuserTest::SetupOrderedOpsInverted() {
- CreateBaseDevice();
- CreateCowDeviceOrderedOpsInverted();
- return SetupDaemon();
-}
-
-bool SnapuserTest::SetupCopyOverlap_1() {
- CreateBaseDevice();
- CreateCowDeviceWithCopyOverlap_1();
- return SetupDaemon();
-}
-
-bool SnapuserTest::SetupCopyOverlap_2() {
- CreateBaseDevice();
- CreateCowDeviceWithCopyOverlap_2();
- return SetupDaemon();
-}
-
-bool SnapuserTest::SetupDaemon() {
- SetDeviceControlName();
-
- StartSnapuserdDaemon();
-
- CreateDmUserDevice();
- InitCowDevice();
- InitDaemon();
-
- setup_ok_ = true;
-
- return setup_ok_;
-}
-
-void SnapuserTest::StartSnapuserdDaemon() {
- pid_t pid = fork();
- ASSERT_GE(pid, 0);
- if (pid == 0) {
- std::string arg0 = "/system/bin/snapuserd";
- std::string arg1 = "-socket="s + kSnapuserdSocketTest;
- char* const argv[] = {arg0.data(), arg1.data(), nullptr};
- ASSERT_GE(execv(arg0.c_str(), argv), 0);
- } else {
- client_ = SnapuserdClient::Connect(kSnapuserdSocketTest, 10s);
- ASSERT_NE(client_, nullptr);
- }
-}
-
-void SnapuserTest::CreateBaseDevice() {
- unique_fd rnd_fd;
-
- total_base_size_ = (size_ * 5);
- base_fd_ = CreateTempFile("base_device", total_base_size_);
- ASSERT_GE(base_fd_, 0);
-
- rnd_fd.reset(open("/dev/random", O_RDONLY));
- ASSERT_TRUE(rnd_fd > 0);
-
- std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
-
- for (size_t j = 0; j < ((total_base_size_) / 1_MiB); j++) {
- ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
- ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), 1_MiB), true);
- }
-
- ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
-
- base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
- ASSERT_TRUE(base_loop_->valid());
-}
-
-void SnapuserTest::ReadSnapshotDeviceAndValidate() {
- unique_fd fd(open(dmuser_dev_->path().c_str(), O_RDONLY));
- ASSERT_GE(fd, 0);
- std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
-
- // COPY
- loff_t offset = 0;
- ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
- ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), size_), 0);
-
- // REPLACE
- offset += size_;
- ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
- ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + size_, size_), 0);
-
- // ZERO
- offset += size_;
- ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
- ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 2), size_), 0);
-
- // REPLACE
- offset += size_;
- ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
- ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 3), size_), 0);
-
- // XOR
- offset += size_;
- ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
- ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0);
-}
-
-void SnapuserTest::CreateCowDeviceWithCopyOverlap_2() {
- std::string path = android::base::GetExecutableDirectory();
- cow_system_ = std::make_unique<TemporaryFile>(path);
-
- CowOptions options;
- options.compression = "gz";
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_system_->fd));
-
- size_t num_blocks = size_ / options.block_size;
- size_t x = num_blocks;
- size_t blk_src_copy = 0;
-
- // Create overlapping copy operations
- while (1) {
- ASSERT_TRUE(writer.AddCopy(blk_src_copy, blk_src_copy + 1));
- x -= 1;
- if (x == 1) {
- break;
- }
- blk_src_copy += 1;
- }
-
- // Flush operations
- ASSERT_TRUE(writer.Finalize());
-
- // Construct the buffer required for validation
- orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-
- // Read the entire base device
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
- true);
-
- // Merged operations required for validation
- int block_size = 4096;
- x = num_blocks;
- loff_t src_offset = block_size;
- loff_t dest_offset = 0;
-
- while (1) {
- memmove((char*)orig_buffer_.get() + dest_offset, (char*)orig_buffer_.get() + src_offset,
- block_size);
- x -= 1;
- if (x == 1) {
- break;
- }
- src_offset += block_size;
- dest_offset += block_size;
- }
-}
-
-void SnapuserTest::CreateCowDeviceWithCopyOverlap_1() {
- std::string path = android::base::GetExecutableDirectory();
- cow_system_ = std::make_unique<TemporaryFile>(path);
-
- CowOptions options;
- options.compression = "gz";
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_system_->fd));
-
- size_t num_blocks = size_ / options.block_size;
- size_t x = num_blocks;
- size_t blk_src_copy = num_blocks - 1;
-
- // Create overlapping copy operations
- while (1) {
- ASSERT_TRUE(writer.AddCopy(blk_src_copy + 1, blk_src_copy));
- x -= 1;
- if (x == 0) {
- ASSERT_EQ(blk_src_copy, 0);
- break;
- }
- blk_src_copy -= 1;
- }
-
- // Flush operations
- ASSERT_TRUE(writer.Finalize());
-
- // Construct the buffer required for validation
- orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-
- // Read the entire base device
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
- true);
-
- // Merged operations
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), options.block_size, 0),
- true);
- ASSERT_EQ(android::base::ReadFullyAtOffset(
- base_fd_, (char*)orig_buffer_.get() + options.block_size, size_, 0),
- true);
-}
-
-void SnapuserTest::CreateCowDeviceOrderedOpsInverted() {
- unique_fd rnd_fd;
- loff_t offset = 0;
-
- std::string path = android::base::GetExecutableDirectory();
- cow_system_ = std::make_unique<TemporaryFile>(path);
-
- rnd_fd.reset(open("/dev/random", O_RDONLY));
- ASSERT_TRUE(rnd_fd > 0);
-
- std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
-
- // Fill random data
- for (size_t j = 0; j < (size_ / 1_MiB); j++) {
- ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
- true);
-
- offset += 1_MiB;
- }
-
- CowOptions options;
- options.compression = "gz";
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_system_->fd));
-
- size_t num_blocks = size_ / options.block_size;
- size_t blk_end_copy = num_blocks * 3;
- size_t source_blk = num_blocks - 1;
- size_t blk_src_copy = blk_end_copy - 1;
- uint16_t xor_offset = 5;
-
- size_t x = num_blocks;
- while (1) {
- ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
- x -= 1;
- if (x == 0) {
- break;
- }
- source_blk -= 1;
- blk_src_copy -= 1;
- }
-
- for (size_t i = num_blocks; i > 0; i--) {
- ASSERT_TRUE(writer.AddXorBlocks(num_blocks + i - 1,
- &random_buffer_1_.get()[options.block_size * (i - 1)],
- options.block_size, 2 * num_blocks + i - 1, xor_offset));
- }
- // Flush operations
- ASSERT_TRUE(writer.Finalize());
- // Construct the buffer required for validation
- orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
- // Read the entire base device
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
- true);
- // Merged Buffer
- memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
- memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
- for (int i = 0; i < size_; i++) {
- orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
- }
-}
-
-void SnapuserTest::CreateCowDeviceOrderedOps() {
- unique_fd rnd_fd;
- loff_t offset = 0;
-
- std::string path = android::base::GetExecutableDirectory();
- cow_system_ = std::make_unique<TemporaryFile>(path);
-
- rnd_fd.reset(open("/dev/random", O_RDONLY));
- ASSERT_TRUE(rnd_fd > 0);
-
- std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
-
- // Fill random data
- for (size_t j = 0; j < (size_ / 1_MiB); j++) {
- ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
- true);
-
- offset += 1_MiB;
- }
- memset(random_buffer_1_.get(), 0, size_);
-
- CowOptions options;
- options.compression = "gz";
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_system_->fd));
-
- size_t num_blocks = size_ / options.block_size;
- size_t x = num_blocks;
- size_t source_blk = 0;
- size_t blk_src_copy = 2 * num_blocks;
- uint16_t xor_offset = 5;
-
- while (1) {
- ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
-
- x -= 1;
- if (x == 0) {
- break;
- }
- source_blk += 1;
- blk_src_copy += 1;
- }
-
- ASSERT_TRUE(writer.AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks,
- xor_offset));
- // Flush operations
- ASSERT_TRUE(writer.Finalize());
- // Construct the buffer required for validation
- orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
- // Read the entire base device
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
- true);
- // Merged Buffer
- memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
- memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
- for (int i = 0; i < size_; i++) {
- orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
- }
-}
-
-void SnapuserTest::CreateCowDevice() {
- unique_fd rnd_fd;
- loff_t offset = 0;
-
- std::string path = android::base::GetExecutableDirectory();
- cow_system_ = std::make_unique<TemporaryFile>(path);
-
- rnd_fd.reset(open("/dev/random", O_RDONLY));
- ASSERT_TRUE(rnd_fd > 0);
-
- std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
-
- // Fill random data
- for (size_t j = 0; j < (size_ / 1_MiB); j++) {
- ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
- true);
-
- offset += 1_MiB;
- }
-
- CowOptions options;
- options.compression = "gz";
- CowWriter writer(options);
-
- ASSERT_TRUE(writer.Initialize(cow_system_->fd));
-
- size_t num_blocks = size_ / options.block_size;
- size_t blk_end_copy = num_blocks * 2;
- size_t source_blk = num_blocks - 1;
- size_t blk_src_copy = blk_end_copy - 1;
-
- uint32_t sequence[num_blocks * 2];
- // Sequence for Copy ops
- for (int i = 0; i < num_blocks; i++) {
- sequence[i] = num_blocks - 1 - i;
- }
- // Sequence for Xor ops
- for (int i = 0; i < num_blocks; i++) {
- sequence[num_blocks + i] = 5 * num_blocks - 1 - i;
- }
- ASSERT_TRUE(writer.AddSequenceData(2 * num_blocks, sequence));
-
- size_t x = num_blocks;
- while (1) {
- ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
- x -= 1;
- if (x == 0) {
- break;
- }
- source_blk -= 1;
- blk_src_copy -= 1;
- }
-
- source_blk = num_blocks;
- blk_src_copy = blk_end_copy;
-
- ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_));
-
- size_t blk_zero_copy_start = source_blk + num_blocks;
- size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks;
-
- ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks));
-
- size_t blk_random2_replace_start = blk_zero_copy_end;
-
- ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_));
-
- size_t blk_xor_start = blk_random2_replace_start + num_blocks;
- size_t xor_offset = BLOCK_SZ / 2;
- ASSERT_TRUE(writer.AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks,
- xor_offset));
-
- // Flush operations
- ASSERT_TRUE(writer.Finalize());
- // Construct the buffer required for validation
- orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
- std::string zero_buffer(size_, 0);
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), size_, size_), true);
- memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_);
- memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_);
- memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_);
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, &orig_buffer_.get()[size_ * 4], size_,
- size_ + xor_offset),
- true);
- for (int i = 0; i < size_; i++) {
- orig_buffer_.get()[(size_ * 4) + i] =
- (uint8_t)(orig_buffer_.get()[(size_ * 4) + i] ^ random_buffer_1_.get()[i]);
- }
-}
-
-void SnapuserTest::InitCowDevice() {
- uint64_t num_sectors = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
- base_loop_->device(), base_loop_->device());
- ASSERT_NE(num_sectors, 0);
-}
-
-void SnapuserTest::SetDeviceControlName() {
- system_device_name_.clear();
- system_device_ctrl_name_.clear();
-
- std::string str(cow_system_->path);
- std::size_t found = str.find_last_of("/\\");
- ASSERT_NE(found, std::string::npos);
- system_device_name_ = str.substr(found + 1);
-
- system_device_ctrl_name_ = system_device_name_ + "-ctrl";
-}
-
-void SnapuserTest::CreateDmUserDevice() {
- unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC)));
- ASSERT_TRUE(fd > 0);
-
- uint64_t dev_sz = get_block_device_size(fd.get());
- ASSERT_TRUE(dev_sz > 0);
-
- cow_num_sectors_ = dev_sz >> 9;
-
- DmTable dmuser_table;
- ASSERT_TRUE(dmuser_table.AddTarget(
- std::make_unique<DmTargetUser>(0, cow_num_sectors_, system_device_ctrl_name_)));
- ASSERT_TRUE(dmuser_table.valid());
-
- dmuser_dev_ = std::make_unique<Tempdevice>(system_device_name_, dmuser_table);
- ASSERT_TRUE(dmuser_dev_->valid());
- ASSERT_FALSE(dmuser_dev_->path().empty());
-
- auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
- ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
-}
-
-void SnapuserTest::InitDaemon() {
- bool ok = client_->AttachDmUser(system_device_ctrl_name_);
- ASSERT_TRUE(ok);
-}
-
-void SnapuserTest::CheckMergeCompletion() {
- while (true) {
- double percentage = client_->GetMergePercent();
- if ((int)percentage == 100) {
- break;
- }
-
- std::this_thread::sleep_for(1s);
- }
-}
-
-void SnapuserTest::SetupImpl() {
- CreateBaseDevice();
- CreateCowDevice();
-
- SetDeviceControlName();
-
- StartSnapuserdDaemon();
-
- CreateDmUserDevice();
- InitCowDevice();
- InitDaemon();
-
- setup_ok_ = true;
-}
-
-bool SnapuserTest::Merge() {
- StartMerge();
- CheckMergeCompletion();
- merge_ok_ = true;
- return merge_ok_;
-}
-
-void SnapuserTest::StartMerge() {
- bool ok = client_->InitiateMerge(system_device_ctrl_name_);
- ASSERT_TRUE(ok);
-}
-
-void SnapuserTest::ValidateMerge() {
- merged_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
- ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, merged_buffer_.get(), total_base_size_, 0),
- true);
- ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
-}
-
-void SnapuserTest::SimulateDaemonRestart() {
- Shutdown();
- std::this_thread::sleep_for(500ms);
- SetDeviceControlName();
- StartSnapuserdDaemon();
- CreateDmUserDevice();
- InitCowDevice();
- InitDaemon();
-}
-
-void SnapuserTest::MergeInterruptRandomly(int max_duration) {
- std::srand(std::time(nullptr));
- StartMerge();
-
- for (int i = 0; i < 20; i++) {
- int duration = std::rand() % max_duration;
- std::this_thread::sleep_for(std::chrono::milliseconds(duration));
- SimulateDaemonRestart();
- StartMerge();
- }
-
- SimulateDaemonRestart();
- ASSERT_TRUE(Merge());
-}
-
-void SnapuserTest::MergeInterruptFixed(int duration) {
- StartMerge();
-
- for (int i = 0; i < 25; i++) {
- std::this_thread::sleep_for(std::chrono::milliseconds(duration));
- SimulateDaemonRestart();
- StartMerge();
- }
-
- SimulateDaemonRestart();
- ASSERT_TRUE(Merge());
-}
-
-void SnapuserTest::MergeInterrupt() {
- // Interrupt merge at various intervals
- StartMerge();
- std::this_thread::sleep_for(250ms);
- SimulateDaemonRestart();
-
- StartMerge();
- std::this_thread::sleep_for(250ms);
- SimulateDaemonRestart();
-
- StartMerge();
- std::this_thread::sleep_for(150ms);
- SimulateDaemonRestart();
-
- StartMerge();
- std::this_thread::sleep_for(100ms);
- SimulateDaemonRestart();
-
- StartMerge();
- std::this_thread::sleep_for(800ms);
- SimulateDaemonRestart();
-
- StartMerge();
- std::this_thread::sleep_for(600ms);
- SimulateDaemonRestart();
-
- ASSERT_TRUE(Merge());
-}
-
-TEST(Snapuserd_Test, Snapshot_IO_TEST) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.Setup());
- // I/O before merge
- harness.ReadSnapshotDeviceAndValidate();
- ASSERT_TRUE(harness.Merge());
- harness.ValidateMerge();
- // I/O after merge - daemon should read directly
- // from base device
- harness.ReadSnapshotDeviceAndValidate();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_MERGE_IO_TEST) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.Setup());
- // Issue I/O before merge begins
- std::async(std::launch::async, &SnapuserTest::ReadSnapshotDeviceAndValidate, &harness);
- // Start the merge
- ASSERT_TRUE(harness.Merge());
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_MERGE_IO_TEST_1) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.Setup());
- // Start the merge
- harness.StartMerge();
- // Issue I/O in parallel when merge is in-progress
- std::async(std::launch::async, &SnapuserTest::ReadSnapshotDeviceAndValidate, &harness);
- harness.CheckMergeCompletion();
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Resume) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.Setup());
- harness.MergeInterrupt();
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_1) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.SetupCopyOverlap_1());
- ASSERT_TRUE(harness.Merge());
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_2) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.SetupCopyOverlap_2());
- ASSERT_TRUE(harness.Merge());
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.SetupCopyOverlap_1());
- harness.MergeInterrupt();
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Ordered) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.SetupOrderedOps());
- harness.MergeInterruptFixed(300);
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Ordered) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.SetupOrderedOps());
- harness.MergeInterruptRandomly(500);
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Inverted) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.SetupOrderedOpsInverted());
- harness.MergeInterruptFixed(50);
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Inverted) {
- SnapuserTest harness;
- ASSERT_TRUE(harness.SetupOrderedOpsInverted());
- harness.MergeInterruptRandomly(50);
- harness.ValidateMerge();
- harness.Shutdown();
-}
-
-} // namespace snapshot
-} // namespace android
-
-int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
-
- gflags::ParseCommandLineFlags(&argc, &argv, false);
-
- android::base::SetProperty("ctl.stop", "snapuserd");
-
- if (FLAGS_force_config == "iouring_disabled") {
- if (!android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1")) {
- return testing::AssertionFailure()
- << "Failed to disable property: snapuserd.test.io_uring.disabled";
- }
- }
-
- int ret = RUN_ALL_TESTS();
-
- if (FLAGS_force_config == "iouring_disabled") {
- android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
- }
-
- return ret;
-}
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp
deleted file mode 100644
index d4e1d7c7e..000000000
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * 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 "snapuserd_core.h"
-
-/*
- * Readahead is used to optimize the merge of COPY and XOR Ops.
- *
- * We create a scratch space of 2MB to store the read-ahead data in the COW
- * device.
- *
- * +-----------------------+
- * | Header (fixed) |
- * +-----------------------+
- * | Scratch space | <-- 2MB
- * +-----------------------+
- *
- * Scratch space is as follows:
- *
- * +-----------------------+
- * | Metadata | <- 4k page
- * +-----------------------+
- * | Metadata | <- 4k page
- * +-----------------------+
- * | |
- * | Read-ahead data |
- * | |
- * +-----------------------+
- *
- *
- * * ===================================================================
- *
- * Example:
- *
- * We have 6 copy operations to be executed in OTA. Update-engine
- * will write to COW file as follows:
- *
- * Op-1: 20 -> 23
- * Op-2: 19 -> 22
- * Op-3: 18 -> 21
- * Op-4: 17 -> 20
- * Op-5: 16 -> 19
- * Op-6: 15 -> 18
- *
- * Read-ahead thread will read all the 6 source blocks and store the data in the
- * scratch space. Metadata will contain the destination block numbers. Thus,
- * scratch space will look something like this:
- *
- * +--------------+
- * | Block 23 |
- * | offset - 1 |
- * +--------------+
- * | Block 22 |
- * | offset - 2 |
- * +--------------+
- * | Block 21 |
- * | offset - 3 |
- * +--------------+
- * ...
- * ...
- * +--------------+
- * | Data-Block 20| <-- offset - 1
- * +--------------+
- * | Data-Block 19| <-- offset - 2
- * +--------------+
- * | Data-Block 18| <-- offset - 3
- * +--------------+
- * ...
- * ...
- *
- * ====================================================================
- *
- *
- * Read-ahead thread will process the COW Ops in fixed set. Consider
- * the following example:
- *
- * +--------------------------+
- * |op-1|op-2|op-3|....|op-510|
- * +--------------------------+
- *
- * <------ One RA Block ------>
- *
- * RA thread will read 510 ordered COW ops at a time and will store
- * the data in the scratch space.
- *
- * RA thread and Merge thread will go lock-step wherein RA thread
- * will make sure that 510 COW operation data are read upfront
- * and is in memory. Thus, when merge thread will pick up the data
- * directly from memory and write it back to base device.
- *
- *
- * +--------------------------+------------------------------------+
- * |op-1|op-2|op-3|....|op-510|op-511|op-512|op-513........|op-1020|
- * +--------------------------+------------------------------------+
- *
- * <------Merge 510 Blocks----><-Prepare 510 blocks for merge by RA->
- * ^ ^
- * | |
- * Merge thread RA thread
- *
- * Both Merge and RA thread will strive to work in parallel.
- *
- * ===========================================================================
- *
- * State transitions and communication between RA thread and Merge thread:
- *
- * Merge Thread RA Thread
- * ----------------------------------------------------------------------------
- *
- * | |
- * WAIT for RA Block N READ one RA Block (N)
- * for merge |
- * | |
- * | |
- * <--------------MERGE BEGIN--------READ Block N done(copy to scratch)
- * | |
- * | |
- * Merge Begin Block N READ one RA BLock (N+1)
- * | |
- * | |
- * | READ done. Wait for merge complete
- * | |
- * | WAIT
- * | |
- * Merge done Block N |
- * ----------------MERGE READY-------------->|
- * WAIT for RA Block N+1 Copy RA Block (N+1)
- * for merge to scratch space
- * | |
- * <---------------MERGE BEGIN---------BLOCK N+1 Done
- * | |
- * | |
- * Merge Begin Block N+1 READ one RA BLock (N+2)
- * | |
- * | |
- * | READ done. Wait for merge complete
- * | |
- * | WAIT
- * | |
- * Merge done Block N+1 |
- * ----------------MERGE READY-------------->|
- * WAIT for RA Block N+2 Copy RA Block (N+2)
- * for merge to scratch space
- * | |
- * <---------------MERGE BEGIN---------BLOCK N+2 Done
- */
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-// This is invoked once primarily by update-engine to initiate
-// the merge
-void SnapshotHandler::InitiateMerge() {
- {
- std::lock_guard<std::mutex> lock(lock_);
- merge_initiated_ = true;
-
- // If there are only REPLACE ops to be merged, then we need
- // to explicitly set the state to MERGE_BEGIN as there
- // is no read-ahead thread
- if (!ra_thread_) {
- io_state_ = MERGE_IO_TRANSITION::MERGE_BEGIN;
- }
- }
- cv.notify_all();
-}
-
-// Invoked by Merge thread - Waits on RA thread to resume merging. Will
-// be waken up RA thread.
-bool SnapshotHandler::WaitForMergeBegin() {
- {
- std::unique_lock<std::mutex> lock(lock_);
- while (!MergeInitiated()) {
- cv.wait(lock);
-
- if (io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE ||
- io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) {
- return false;
- }
- }
-
- while (!(io_state_ == MERGE_IO_TRANSITION::MERGE_BEGIN ||
- io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE ||
- io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED)) {
- cv.wait(lock);
- }
-
- if (io_state_ == MERGE_IO_TRANSITION::READ_AHEAD_FAILURE ||
- io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) {
- return false;
- }
-
- return true;
- }
-}
-
-// Invoked by RA thread - Flushes the RA block to scratch space if necessary
-// and then notifies the merge thread to resume merging
-bool SnapshotHandler::ReadAheadIOCompleted(bool sync) {
- if (sync) {
- // Flush the entire buffer region
- int ret = msync(mapped_addr_, total_mapped_addr_length_, MS_SYNC);
- if (ret < 0) {
- PLOG(ERROR) << "msync failed after ReadAheadIOCompleted: " << ret;
- return false;
- }
-
- // Metadata and data are synced. Now, update the state.
- // We need to update the state after flushing data; if there is a crash
- // when read-ahead IO is in progress, the state of data in the COW file
- // is unknown. kCowReadAheadDone acts as a checkpoint wherein the data
- // in the scratch space is good and during next reboot, read-ahead thread
- // can safely re-construct the data.
- struct BufferState* ra_state = GetBufferState();
- ra_state->read_ahead_state = kCowReadAheadDone;
-
- ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC);
- if (ret < 0) {
- PLOG(ERROR) << "msync failed to flush Readahead completion state...";
- return false;
- }
- }
-
- // Notify the merge thread to resume merging
- {
- std::lock_guard<std::mutex> lock(lock_);
- if (io_state_ != MERGE_IO_TRANSITION::IO_TERMINATED &&
- io_state_ != MERGE_IO_TRANSITION::MERGE_FAILED) {
- io_state_ = MERGE_IO_TRANSITION::MERGE_BEGIN;
- }
- }
-
- cv.notify_all();
- return true;
-}
-
-// Invoked by RA thread - Waits for merge thread to finish merging
-// RA Block N - RA thread would be ready will with Block N+1 but
-// will wait to merge thread to finish Block N. Once Block N
-// is merged, RA thread will be woken up by Merge thread and will
-// flush the data of Block N+1 to scratch space
-bool SnapshotHandler::WaitForMergeReady() {
- {
- std::unique_lock<std::mutex> lock(lock_);
- while (!(io_state_ == MERGE_IO_TRANSITION::MERGE_READY ||
- io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED ||
- io_state_ == MERGE_IO_TRANSITION::MERGE_COMPLETE ||
- io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED)) {
- cv.wait(lock);
- }
-
- // Check if merge failed
- if (io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED ||
- io_state_ == MERGE_IO_TRANSITION::MERGE_COMPLETE ||
- io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) {
- return false;
- }
- return true;
- }
-}
-
-// Invoked by Merge thread - Notify RA thread about Merge completion
-// for Block N and wake up
-void SnapshotHandler::NotifyRAForMergeReady() {
- {
- std::lock_guard<std::mutex> lock(lock_);
- if (io_state_ != MERGE_IO_TRANSITION::IO_TERMINATED &&
- io_state_ != MERGE_IO_TRANSITION::READ_AHEAD_FAILURE) {
- io_state_ = MERGE_IO_TRANSITION::MERGE_READY;
- }
- }
-
- cv.notify_all();
-}
-
-// The following transitions are mostly in the failure paths
-void SnapshotHandler::MergeFailed() {
- {
- std::lock_guard<std::mutex> lock(lock_);
- io_state_ = MERGE_IO_TRANSITION::MERGE_FAILED;
- }
-
- cv.notify_all();
-}
-
-void SnapshotHandler::MergeCompleted() {
- {
- std::lock_guard<std::mutex> lock(lock_);
- io_state_ = MERGE_IO_TRANSITION::MERGE_COMPLETE;
- }
-
- cv.notify_all();
-}
-
-// This is invoked by worker threads.
-//
-// Worker threads are terminated either by two scenarios:
-//
-// 1: If dm-user device is destroyed
-// 2: We had an I/O failure when reading root partitions
-//
-// In case (1), this would be a graceful shutdown. In this case, merge
-// thread and RA thread should have _already_ terminated by this point. We will be
-// destroying the dm-user device only _after_ merge is completed.
-//
-// In case (2), if merge thread had started, then it will be
-// continuing to merge; however, since we had an I/O failure and the
-// I/O on root partitions are no longer served, we will terminate the
-// merge.
-//
-// This functions is about handling case (2)
-void SnapshotHandler::NotifyIOTerminated() {
- {
- std::lock_guard<std::mutex> lock(lock_);
- io_state_ = MERGE_IO_TRANSITION::IO_TERMINATED;
- }
-
- cv.notify_all();
-}
-
-bool SnapshotHandler::IsIOTerminated() {
- std::lock_guard<std::mutex> lock(lock_);
- return (io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED);
-}
-
-// Invoked by RA thread
-void SnapshotHandler::ReadAheadIOFailed() {
- {
- std::lock_guard<std::mutex> lock(lock_);
- io_state_ = MERGE_IO_TRANSITION::READ_AHEAD_FAILURE;
- }
-
- cv.notify_all();
-}
-
-void SnapshotHandler::WaitForMergeComplete() {
- std::unique_lock<std::mutex> lock(lock_);
- while (!(io_state_ == MERGE_IO_TRANSITION::MERGE_COMPLETE ||
- io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED ||
- io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED)) {
- cv.wait(lock);
- }
-}
-
-std::string SnapshotHandler::GetMergeStatus() {
- bool merge_not_initiated = false;
- bool merge_failed = false;
-
- {
- std::lock_guard<std::mutex> lock(lock_);
- if (!MergeInitiated()) {
- merge_not_initiated = true;
- }
-
- if (io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED) {
- merge_failed = true;
- }
- }
-
- struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
- bool merge_complete = (ch->num_merge_ops == reader_->get_num_total_data_ops());
-
- if (merge_not_initiated) {
- // Merge was not initiated yet; however, we have merge completion
- // recorded in the COW Header. This can happen if the device was
- // rebooted during merge. During next reboot, libsnapshot will
- // query the status and if the merge is completed, then snapshot-status
- // file will be deleted
- if (merge_complete) {
- return "snapshot-merge-complete";
- }
-
- // Return the state as "snapshot". If the device was rebooted during
- // merge, we will return the status as "snapshot". This is ok, as
- // libsnapshot will explicitly resume the merge. This is slightly
- // different from kernel snapshot wherein once the snapshot was switched
- // to merge target, during next boot, we immediately switch to merge
- // target. We don't do that here because, during first stage init, we
- // don't want to initiate the merge. The problem is that we have daemon
- // transition between first and second stage init. If the merge was
- // started, then we will have to quiesce the merge before switching
- // the dm tables. Instead, we just wait until second stage daemon is up
- // before resuming the merge.
- return "snapshot";
- }
-
- if (merge_failed) {
- return "snapshot-merge-failed";
- }
-
- // Merge complete
- if (merge_complete) {
- return "snapshot-merge-complete";
- }
-
- // Merge is in-progress
- return "snapshot-merge";
-}
-
-//========== End of Read-ahead state transition functions ====================
-
-/*
- * Root partitions are mounted off dm-user and the I/O's are served
- * by snapuserd worker threads.
- *
- * When there is an I/O request to be served by worker threads, we check
- * if the corresponding sector is "changed" due to OTA by doing a lookup.
- * If the lookup succeeds then the sector has been changed and that can
- * either fall into 4 COW operations viz: COPY, XOR, REPLACE and ZERO.
- *
- * For the case of REPLACE and ZERO ops, there is not much of a concern
- * as there is no dependency between blocks. Hence all the I/O request
- * mapped to these two COW operations will be served by reading the COW device.
- *
- * However, COPY and XOR ops are tricky. Since the merge operations are
- * in-progress, we cannot just go and read from the source device. We need
- * to be in sync with the state of the merge thread before serving the I/O.
- *
- * Given that we know merge thread processes a set of COW ops called as RA
- * Blocks - These set of COW ops are fixed size wherein each Block comprises
- * of 510 COW ops.
- *
- * +--------------------------+
- * |op-1|op-2|op-3|....|op-510|
- * +--------------------------+
- *
- * <------ Merge Group Block N ------>
- *
- * Thus, a Merge Group Block N, will fall into one of these states and will
- * transition the states in the following order:
- *
- * 1: GROUP_MERGE_PENDING
- * 2: GROUP_MERGE_RA_READY
- * 2: GROUP_MERGE_IN_PROGRESS
- * 3: GROUP_MERGE_COMPLETED
- * 4: GROUP_MERGE_FAILED
- *
- * Let's say that we have the I/O request from dm-user whose sector gets mapped
- * to a COPY operation with op-10 in the above "Merge Group Block N".
- *
- * 1: If the Group is in "GROUP_MERGE_PENDING" state:
- *
- * Just read the data from source block based on COW op->source field. Note,
- * that we will take a ref count on "Block N". This ref count will prevent
- * merge thread to begin merging if there are any pending I/Os. Once the I/O
- * is completed, ref count on "Group N" is decremented. Merge thread will
- * resume merging "Group N" if there are no pending I/Os.
- *
- * 2: If the Group is in "GROUP_MERGE_IN_PROGRESS" or "GROUP_MERGE_RA_READY" state:
- *
- * When the merge thread is ready to process a "Group", it will first move
- * the state to GROUP_MERGE_PENDING -> GROUP_MERGE_RA_READY. From this point
- * onwards, I/O will be served from Read-ahead buffer. However, merge thread
- * cannot start merging this "Group" immediately. If there were any in-flight
- * I/O requests, merge thread should wait and allow those I/O's to drain.
- * Once all the in-flight I/O's are completed, merge thread will move the
- * state from "GROUP_MERGE_RA_READY" -> "GROUP_MERGE_IN_PROGRESS". I/O will
- * be continued to serve from Read-ahead buffer during the entire duration
- * of the merge.
- *
- * See SetMergeInProgress().
- *
- * 3: If the Group is in "GROUP_MERGE_COMPLETED" state:
- *
- * This is straightforward. We just read the data directly from "Base"
- * device. We should not be reading the COW op->source field.
- *
- * 4: If the Block is in "GROUP_MERGE_FAILED" state:
- *
- * Terminate the I/O with an I/O error as we don't know which "op" in the
- * "Group" failed.
- *
- * Transition ensures that the I/O from root partitions are never made to
- * wait and are processed immediately. Thus the state transition for any
- * "Group" is:
- *
- * GROUP_MERGE_PENDING
- * |
- * |
- * v
- * GROUP_MERGE_RA_READY
- * |
- * |
- * v
- * GROUP_MERGE_IN_PROGRESS
- * |
- * |----------------------------(on failure)
- * | |
- * v v
- * GROUP_MERGE_COMPLETED GROUP_MERGE_FAILED
- *
- */
-
-// Invoked by Merge thread
-void SnapshotHandler::SetMergeCompleted(size_t ra_index) {
- MergeGroupState* blk_state = merge_blk_state_[ra_index].get();
- {
- std::lock_guard<std::mutex> lock(blk_state->m_lock);
-
- CHECK(blk_state->merge_state_ == MERGE_GROUP_STATE::GROUP_MERGE_IN_PROGRESS);
- CHECK(blk_state->num_ios_in_progress == 0);
-
- // Merge is complete - All I/O henceforth should be read directly
- // from base device
- blk_state->merge_state_ = MERGE_GROUP_STATE::GROUP_MERGE_COMPLETED;
- }
-}
-
-// Invoked by Merge thread. This is called just before the beginning
-// of merging a given Block of 510 ops. If there are any in-flight I/O's
-// from dm-user then wait for them to complete.
-void SnapshotHandler::SetMergeInProgress(size_t ra_index) {
- MergeGroupState* blk_state = merge_blk_state_[ra_index].get();
- {
- std::unique_lock<std::mutex> lock(blk_state->m_lock);
-
- // We may have fallback from Async-merge to synchronous merging
- // on the existing block. There is no need to reset as the
- // merge is already in progress.
- if (blk_state->merge_state_ == MERGE_GROUP_STATE::GROUP_MERGE_IN_PROGRESS) {
- return;
- }
-
- CHECK(blk_state->merge_state_ == MERGE_GROUP_STATE::GROUP_MERGE_PENDING);
-
- // First set the state to RA_READY so that in-flight I/O will drain
- // and any new I/O will start reading from RA buffer
- blk_state->merge_state_ = MERGE_GROUP_STATE::GROUP_MERGE_RA_READY;
-
- // Wait if there are any in-flight I/O's - we cannot merge at this point
- while (!(blk_state->num_ios_in_progress == 0)) {
- blk_state->m_cv.wait(lock);
- }
-
- blk_state->merge_state_ = MERGE_GROUP_STATE::GROUP_MERGE_IN_PROGRESS;
- }
-}
-
-// Invoked by Merge thread on failure
-void SnapshotHandler::SetMergeFailed(size_t ra_index) {
- MergeGroupState* blk_state = merge_blk_state_[ra_index].get();
- {
- std::unique_lock<std::mutex> lock(blk_state->m_lock);
-
- blk_state->merge_state_ = MERGE_GROUP_STATE::GROUP_MERGE_FAILED;
- }
-}
-
-// Invoked by worker threads when I/O is complete on a "MERGE_PENDING"
-// Block. If there are no more in-flight I/Os, wake up merge thread
-// to resume merging.
-void SnapshotHandler::NotifyIOCompletion(uint64_t new_block) {
- auto it = block_to_ra_index_.find(new_block);
- CHECK(it != block_to_ra_index_.end()) << " invalid block: " << new_block;
-
- bool pending_ios = true;
-
- int ra_index = it->second;
- MergeGroupState* blk_state = merge_blk_state_[ra_index].get();
- {
- std::unique_lock<std::mutex> lock(blk_state->m_lock);
-
- blk_state->num_ios_in_progress -= 1;
- if (blk_state->num_ios_in_progress == 0) {
- pending_ios = false;
- }
- }
-
- // Give a chance to merge-thread to resume merge
- // as there are no pending I/O.
- if (!pending_ios) {
- blk_state->m_cv.notify_all();
- }
-}
-
-bool SnapshotHandler::GetRABuffer(std::unique_lock<std::mutex>* lock, uint64_t block,
- void* buffer) {
- if (!lock->owns_lock()) {
- SNAP_LOG(ERROR) << "GetRABuffer - Lock not held";
- return false;
- }
- std::unordered_map<uint64_t, void*>::iterator it = read_ahead_buffer_map_.find(block);
-
- if (it == read_ahead_buffer_map_.end()) {
- SNAP_LOG(ERROR) << "Block: " << block << " not found in RA buffer";
- return false;
- }
-
- memcpy(buffer, it->second, BLOCK_SZ);
- return true;
-}
-
-// Invoked by worker threads in the I/O path. This is called when a sector
-// is mapped to a COPY/XOR COW op.
-MERGE_GROUP_STATE SnapshotHandler::ProcessMergingBlock(uint64_t new_block, void* buffer) {
- auto it = block_to_ra_index_.find(new_block);
- if (it == block_to_ra_index_.end()) {
- return MERGE_GROUP_STATE::GROUP_INVALID;
- }
-
- int ra_index = it->second;
- MergeGroupState* blk_state = merge_blk_state_[ra_index].get();
- {
- std::unique_lock<std::mutex> lock(blk_state->m_lock);
-
- MERGE_GROUP_STATE state = blk_state->merge_state_;
- switch (state) {
- case MERGE_GROUP_STATE::GROUP_MERGE_PENDING: {
- blk_state->num_ios_in_progress += 1; // ref count
- [[fallthrough]];
- }
- case MERGE_GROUP_STATE::GROUP_MERGE_COMPLETED: {
- [[fallthrough]];
- }
- case MERGE_GROUP_STATE::GROUP_MERGE_FAILED: {
- return state;
- }
- // Fetch the data from RA buffer.
- case MERGE_GROUP_STATE::GROUP_MERGE_RA_READY: {
- [[fallthrough]];
- }
- case MERGE_GROUP_STATE::GROUP_MERGE_IN_PROGRESS: {
- if (!GetRABuffer(&lock, new_block, buffer)) {
- return MERGE_GROUP_STATE::GROUP_INVALID;
- }
- return state;
- }
- default: {
- return MERGE_GROUP_STATE::GROUP_INVALID;
- }
- }
- }
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd_client.cpp
index 7b1c7a3a6..41ab34409 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_client.cpp
@@ -33,7 +33,7 @@
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <snapuserd/snapuserd_client.h>
+#include <libsnapshot/snapuserd_client.h>
namespace android {
namespace snapshot {
@@ -42,15 +42,13 @@ using namespace std::chrono_literals;
using android::base::unique_fd;
bool EnsureSnapuserdStarted() {
- if (android::base::GetProperty("init.svc.snapuserd", "") != "running") {
- android::base::SetProperty("ctl.start", "snapuserd");
- if (!android::base::WaitForProperty("init.svc.snapuserd", "running", 10s)) {
- LOG(ERROR) << "Timed out waiting for snapuserd to start.";
- return false;
- }
+ if (android::base::GetProperty("init.svc.snapuserd", "") == "running") {
+ return true;
}
- if (!android::base::WaitForProperty("snapuserd.ready", "true", 10s)) {
- LOG(ERROR) << "Timed out waiting for snapuserd to be ready.";
+
+ android::base::SetProperty("ctl.start", "snapuserd");
+ if (!android::base::WaitForProperty("init.svc.snapuserd", "running", 10s)) {
+ LOG(ERROR) << "Timed out waiting for snapuserd to start.";
return false;
}
return true;
@@ -143,16 +141,6 @@ bool SnapuserdClient::WaitForDeviceDelete(const std::string& control_device) {
return true;
}
-bool SnapuserdClient::SupportsSecondStageSocketHandoff() {
- std::string msg = "supports,second_stage_socket_handoff";
- if (!Sendmsg(msg)) {
- LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
- return false;
- }
- std::string response = Receivemsg();
- return response == "success";
-}
-
std::string SnapuserdClient::Receivemsg() {
char msg[PACKET_SIZE];
ssize_t ret = TEMP_FAILURE_RETRY(recv(sockfd_, msg, sizeof(msg), 0));
@@ -195,16 +183,8 @@ bool SnapuserdClient::AttachDmUser(const std::string& misc_name) {
}
uint64_t SnapuserdClient::InitDmUserCow(const std::string& misc_name, const std::string& cow_device,
- const std::string& backing_device,
- const std::string& base_path_merge) {
- std::vector<std::string> parts;
-
- if (base_path_merge.empty()) {
- parts = {"init", misc_name, cow_device, backing_device};
- } else {
- // For userspace snapshots
- parts = {"init", misc_name, cow_device, backing_device, base_path_merge};
- }
+ const std::string& backing_device) {
+ std::vector<std::string> parts = {"init", misc_name, cow_device, backing_device};
std::string msg = android::base::Join(parts, ",");
if (!Sendmsg(msg)) {
LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
@@ -239,35 +219,5 @@ bool SnapuserdClient::DetachSnapuserd() {
return true;
}
-bool SnapuserdClient::InitiateMerge(const std::string& misc_name) {
- std::string msg = "initiate_merge," + misc_name;
- if (!Sendmsg(msg)) {
- LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
- return false;
- }
- std::string response = Receivemsg();
- return response == "success";
-}
-
-double SnapuserdClient::GetMergePercent() {
- std::string msg = "merge_percent";
- if (!Sendmsg(msg)) {
- LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
- return false;
- }
- std::string response = Receivemsg();
-
- return std::stod(response);
-}
-
-std::string SnapuserdClient::QuerySnapshotStatus(const std::string& misc_name) {
- std::string msg = "getstatus," + misc_name;
- if (!Sendmsg(msg)) {
- LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
- return "snapshot-merge-failed";
- }
- return Receivemsg();
-}
-
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
new file mode 100644
index 000000000..7fa01b78f
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "snapuserd_daemon.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
+#include <libsnapshot/snapuserd_client.h>
+
+#include "snapuserd_server.h"
+
+DEFINE_string(socket, android::snapshot::kSnapuserdSocket, "Named socket or socket path.");
+DEFINE_bool(no_socket, false,
+ "If true, no socket is used. Each additional argument is an INIT message.");
+
+namespace android {
+namespace snapshot {
+
+bool Daemon::StartServer(int argc, char** argv) {
+ int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+ if (!FLAGS_no_socket) {
+ return server_.Start(FLAGS_socket);
+ }
+
+ for (int i = arg_start; i < argc; i++) {
+ auto parts = android::base::Split(argv[i], ",");
+ if (parts.size() != 3) {
+ LOG(ERROR) << "Malformed message, expected three sub-arguments.";
+ return false;
+ }
+ auto handler = server_.AddHandler(parts[0], parts[1], parts[2]);
+ if (!handler || !server_.StartHandler(handler)) {
+ return false;
+ }
+ }
+
+ // Skip the accept() call to avoid spurious log spam. The server will still
+ // run until all handlers have completed.
+ server_.SetTerminating();
+ return true;
+}
+
+void Daemon::MaskAllSignalsExceptIntAndTerm() {
+ sigset_t signal_mask;
+ sigfillset(&signal_mask);
+ sigdelset(&signal_mask, SIGINT);
+ sigdelset(&signal_mask, SIGTERM);
+ sigdelset(&signal_mask, SIGPIPE);
+ if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
+ PLOG(ERROR) << "Failed to set sigprocmask";
+ }
+}
+
+void Daemon::MaskAllSignals() {
+ sigset_t signal_mask;
+ sigfillset(&signal_mask);
+ if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
+ PLOG(ERROR) << "Couldn't mask all signals";
+ }
+}
+
+void Daemon::Run() {
+ sigfillset(&signal_mask_);
+ sigdelset(&signal_mask_, SIGINT);
+ sigdelset(&signal_mask_, SIGTERM);
+
+ // Masking signals here ensure that after this point, we won't handle INT/TERM
+ // until after we call into ppoll()
+ signal(SIGINT, Daemon::SignalHandler);
+ signal(SIGTERM, Daemon::SignalHandler);
+ signal(SIGPIPE, Daemon::SignalHandler);
+
+ LOG(DEBUG) << "Snapuserd-server: ready to accept connections";
+
+ MaskAllSignalsExceptIntAndTerm();
+
+ server_.Run();
+}
+
+void Daemon::Interrupt() {
+ server_.Interrupt();
+}
+
+void Daemon::SignalHandler(int signal) {
+ LOG(DEBUG) << "Snapuserd received signal: " << signal;
+ switch (signal) {
+ case SIGINT:
+ case SIGTERM: {
+ Daemon::Instance().Interrupt();
+ break;
+ }
+ case SIGPIPE: {
+ LOG(ERROR) << "Received SIGPIPE signal";
+ break;
+ }
+ default:
+ LOG(ERROR) << "Received unknown signal " << signal;
+ break;
+ }
+}
+
+} // namespace snapshot
+} // namespace android
+
+int main(int argc, char** argv) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+
+ android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
+
+ if (!daemon.StartServer(argc, argv)) {
+ LOG(ERROR) << "Snapuserd daemon failed to start.";
+ exit(EXIT_FAILURE);
+ }
+ daemon.Run();
+
+ return 0;
+}
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.h b/fs_mgr/libsnapshot/snapuserd_daemon.h
index cf3b917e5..f8afac559 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.h
+++ b/fs_mgr/libsnapshot/snapuserd_daemon.h
@@ -19,8 +19,7 @@
#include <string>
#include <vector>
-#include "dm-snapshot-merge/snapuserd_server.h"
-#include "user-space-merge/snapuserd_server.h"
+#include "snapuserd_server.h"
namespace android {
namespace snapshot {
@@ -36,13 +35,9 @@ class Daemon {
return instance;
}
- bool StartServerForDmSnapshot(int arg_start, int argc, char** argv);
- bool StartServerForUserspaceSnapshots(int arg_start, int argc, char** argv);
+ bool StartServer(int argc, char** argv);
+ void Run();
void Interrupt();
- void ReceivedSocketSignal();
- bool IsUserspaceSnapshotsEnabled();
- bool IsDmSnapshotTestingEnabled();
- bool StartDaemon(int argc, char** argv);
private:
// Signal mask used with ppoll()
@@ -52,7 +47,6 @@ class Daemon {
void operator=(Daemon const&) = delete;
SnapuserdServer server_;
- UserSnapshotServer user_server_;
void MaskAllSignalsExceptIntAndTerm();
void MaskAllSignals();
static void SignalHandler(int signal);
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd_readahead.cpp
index c201b23dc..16d5919a5 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_readahead.cpp
@@ -20,7 +20,7 @@
#include <optional>
#include <set>
-#include <snapuserd/snapuserd_client.h>
+#include <libsnapshot/snapuserd_client.h>
namespace android {
namespace snapshot {
@@ -172,39 +172,24 @@ ReadAheadThread::ReadAheadThread(const std::string& cow_device, const std::strin
}
void ReadAheadThread::CheckOverlap(const CowOperation* cow_op) {
- uint64_t source_block = cow_op->source;
- uint64_t source_offset = 0;
- if (cow_op->type == kCowXorOp) {
- source_block /= BLOCK_SZ;
- source_offset = cow_op->source % BLOCK_SZ;
- }
- if (dest_blocks_.count(cow_op->new_block) || source_blocks_.count(source_block) ||
- (source_offset > 0 && source_blocks_.count(source_block + 1))) {
+ if (dest_blocks_.count(cow_op->new_block) || source_blocks_.count(cow_op->source)) {
overlap_ = true;
}
- dest_blocks_.insert(source_block);
- if (source_offset > 0) {
- dest_blocks_.insert(source_block + 1);
- }
+ dest_blocks_.insert(cow_op->source);
source_blocks_.insert(cow_op->new_block);
}
-void ReadAheadThread::PrepareReadAhead(uint64_t* source_offset, int* pending_ops,
+void ReadAheadThread::PrepareReadAhead(uint64_t* source_block, int* pending_ops,
std::vector<uint64_t>& blocks) {
int num_ops = *pending_ops;
int nr_consecutive = 0;
- CHECK_NE(source_offset, nullptr);
-
- if (!RAIterDone() && num_ops) {
- // Get the first block with offset
- const CowOperation* cow_op = GetRAOpIter();
- CHECK_NE(cow_op, nullptr);
- *source_offset = cow_op->source;
- if (cow_op->type == kCowCopyOp) {
- *source_offset *= BLOCK_SZ;
- }
- RAIterNext();
+
+ if (!IterDone() && num_ops) {
+ // Get the first block
+ const CowOperation* cow_op = GetIterOp();
+ *source_block = cow_op->source;
+ IterNext();
num_ops -= 1;
nr_consecutive = 1;
blocks.push_back(cow_op->new_block);
@@ -216,20 +201,15 @@ void ReadAheadThread::PrepareReadAhead(uint64_t* source_offset, int* pending_ops
/*
* Find number of consecutive blocks working backwards.
*/
- while (!RAIterDone() && num_ops) {
- const CowOperation* op = GetRAOpIter();
- CHECK_NE(op, nullptr);
- uint64_t next_offset = op->source;
- if (op->type == kCowCopyOp) {
- next_offset *= BLOCK_SZ;
- }
- if (next_offset + nr_consecutive * BLOCK_SZ != *source_offset) {
+ while (!IterDone() && num_ops) {
+ const CowOperation* op = GetIterOp();
+ if (op->source != (*source_block - nr_consecutive)) {
break;
}
nr_consecutive += 1;
num_ops -= 1;
blocks.push_back(op->new_block);
- RAIterNext();
+ IterNext();
if (!overlap_) {
CheckOverlap(op);
@@ -246,15 +226,9 @@ bool ReadAheadThread::ReconstructDataFromCow() {
int num_ops = 0;
int total_blocks_merged = 0;
- // This memcpy is important as metadata_buffer_ will be an unaligned address and will fault
- // on 32-bit systems
- std::unique_ptr<uint8_t[]> metadata_buffer =
- std::make_unique<uint8_t[]>(snapuserd_->GetBufferMetadataSize());
- memcpy(metadata_buffer.get(), metadata_buffer_, snapuserd_->GetBufferMetadataSize());
-
while (true) {
struct ScratchMetadata* bm = reinterpret_cast<struct ScratchMetadata*>(
- (char*)metadata_buffer.get() + metadata_offset);
+ (char*)metadata_buffer_ + metadata_offset);
// Done reading metadata
if (bm->new_block == 0 && bm->file_offset == 0) {
@@ -273,12 +247,12 @@ bool ReadAheadThread::ReconstructDataFromCow() {
// We are done re-constructing the mapping; however, we need to make sure
// all the COW operations to-be merged are present in the re-constructed
// mapping.
- while (!RAIterDone()) {
- const CowOperation* op = GetRAOpIter();
+ while (!IterDone()) {
+ const CowOperation* op = GetIterOp();
if (read_ahead_buffer_map.find(op->new_block) != read_ahead_buffer_map.end()) {
num_ops -= 1;
snapuserd_->SetFinalBlockMerged(op->new_block);
- RAIterNext();
+ IterNext();
} else {
// Verify that we have covered all the ops which were re-constructed
// from COW device - These are the ops which are being
@@ -338,10 +312,10 @@ bool ReadAheadThread::ReadAheadIOStart() {
source_blocks_.clear();
while (true) {
- uint64_t source_offset;
+ uint64_t source_block;
int linear_blocks;
- PrepareReadAhead(&source_offset, &num_ops, blocks);
+ PrepareReadAhead(&source_block, &num_ops, blocks);
linear_blocks = blocks.size();
if (linear_blocks == 0) {
// No more blocks to read
@@ -350,7 +324,7 @@ bool ReadAheadThread::ReadAheadIOStart() {
}
// Get the first block in the consecutive set of blocks
- source_offset = source_offset - (linear_blocks - 1) * BLOCK_SZ;
+ source_block = source_block + 1 - linear_blocks;
size_t io_size = (linear_blocks * BLOCK_SZ);
num_ops -= linear_blocks;
total_blocks_merged += linear_blocks;
@@ -384,12 +358,10 @@ bool ReadAheadThread::ReadAheadIOStart() {
// Read from the base device consecutive set of blocks in one shot
if (!android::base::ReadFullyAtOffset(backing_store_fd_,
(char*)read_ahead_buffer_ + buffer_offset, io_size,
- source_offset)) {
- SNAP_PLOG(ERROR) << "Ordered-op failed. Read from backing store: "
- << backing_store_device_ << "at block :" << source_offset / BLOCK_SZ
- << " offset :" << source_offset % BLOCK_SZ
- << " buffer_offset : " << buffer_offset << " io_size : " << io_size
- << " buf-addr : " << read_ahead_buffer_;
+ source_block * BLOCK_SZ)) {
+ SNAP_PLOG(ERROR) << "Copy-op failed. Read from backing store: " << backing_store_device_
+ << "at block :" << source_block << " buffer_offset : " << buffer_offset
+ << " io_size : " << io_size << " buf-addr : " << read_ahead_buffer_;
snapuserd_->ReadAheadIOFailed();
return false;
@@ -422,10 +394,10 @@ bool ReadAheadThread::RunThread() {
return false;
}
- InitializeRAIter();
+ InitializeIter();
InitializeBuffer();
- while (!RAIterDone()) {
+ while (!IterDone()) {
if (!ReadAheadIOStart()) {
return false;
}
@@ -461,21 +433,21 @@ bool ReadAheadThread::InitializeFds() {
return true;
}
-void ReadAheadThread::InitializeRAIter() {
+void ReadAheadThread::InitializeIter() {
std::vector<const CowOperation*>& read_ahead_ops = snapuserd_->GetReadAheadOpsVec();
read_ahead_iter_ = read_ahead_ops.rbegin();
}
-bool ReadAheadThread::RAIterDone() {
+bool ReadAheadThread::IterDone() {
std::vector<const CowOperation*>& read_ahead_ops = snapuserd_->GetReadAheadOpsVec();
return read_ahead_iter_ == read_ahead_ops.rend();
}
-void ReadAheadThread::RAIterNext() {
+void ReadAheadThread::IterNext() {
read_ahead_iter_++;
}
-const CowOperation* ReadAheadThread::GetRAOpIter() {
+const CowOperation* ReadAheadThread::GetIterOp() {
return *read_ahead_iter_;
}
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 9ddc96389..833969094 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -25,26 +25,14 @@
#include <sys/types.h>
#include <unistd.h>
-#include <android-base/cmsg.h>
#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/scopeguard.h>
-#include <fs_mgr/file_wait.h>
-#include <snapuserd/snapuserd_client.h>
+#include "snapuserd.h"
#include "snapuserd_server.h"
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
namespace android {
namespace snapshot {
-using namespace std::string_literals;
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-
DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
if (input == "init") return DaemonOperations::INIT;
if (input == "start") return DaemonOperations::START;
@@ -52,7 +40,6 @@ DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
if (input == "query") return DaemonOperations::QUERY;
if (input == "delete") return DaemonOperations::DELETE;
if (input == "detach") return DaemonOperations::DETACH;
- if (input == "supports") return DaemonOperations::SUPPORTS;
return DaemonOperations::INVALID;
}
@@ -206,16 +193,6 @@ bool SnapuserdServer::Receivemsg(android::base::borrowed_fd fd, const std::strin
terminating_ = true;
return true;
}
- case DaemonOperations::SUPPORTS: {
- if (out.size() != 2) {
- LOG(ERROR) << "Malformed supports message, " << out.size() << " parts";
- return Sendmsg(fd, "fail");
- }
- if (out[1] == "second_stage_socket_handoff") {
- return Sendmsg(fd, "success");
- }
- return Sendmsg(fd, "fail");
- }
default: {
LOG(ERROR) << "Received unknown message type from client";
Sendmsg(fd, "fail");
@@ -227,7 +204,6 @@ bool SnapuserdServer::Receivemsg(android::base::borrowed_fd fd, const std::strin
void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
LOG(INFO) << "Entering thread for handler: " << handler->misc_name();
- handler->snapuserd()->SetSocketPresent(is_socket_present_);
if (!handler->snapuserd()->Start()) {
LOG(ERROR) << " Failed to launch all worker threads";
}
@@ -269,45 +245,28 @@ void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
}
bool SnapuserdServer::Start(const std::string& socketname) {
- bool start_listening = true;
-
sockfd_.reset(android_get_control_socket(socketname.c_str()));
- if (sockfd_ < 0) {
+ if (sockfd_ >= 0) {
+ if (listen(sockfd_.get(), 4) < 0) {
+ PLOG(ERROR) << "listen socket failed: " << socketname;
+ return false;
+ }
+ } else {
sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM));
if (sockfd_ < 0) {
PLOG(ERROR) << "Failed to create server socket " << socketname;
return false;
}
- start_listening = false;
- }
- return StartWithSocket(start_listening);
-}
-
-bool SnapuserdServer::StartWithSocket(bool start_listening) {
- if (start_listening && listen(sockfd_.get(), 4) < 0) {
- PLOG(ERROR) << "listen socket failed";
- return false;
}
- AddWatchedFd(sockfd_, POLLIN);
- is_socket_present_ = true;
+ AddWatchedFd(sockfd_);
- // If started in first-stage init, the property service won't be online.
- if (access("/dev/socket/property_service", F_OK) == 0) {
- if (!android::base::SetProperty("snapuserd.ready", "true")) {
- LOG(ERROR) << "Failed to set snapuserd.ready property";
- return false;
- }
- }
-
- LOG(DEBUG) << "Snapuserd server now accepting connections";
+ LOG(DEBUG) << "Snapuserd server successfully started with socket name " << socketname;
return true;
}
bool SnapuserdServer::Run() {
- LOG(INFO) << "Now listening on snapuserd socket";
-
while (!IsTerminating()) {
int rv = TEMP_FAILURE_RETRY(poll(watched_fds_.data(), watched_fds_.size(), -1));
if (rv < 0) {
@@ -352,10 +311,10 @@ void SnapuserdServer::JoinAllThreads() {
}
}
-void SnapuserdServer::AddWatchedFd(android::base::borrowed_fd fd, int events) {
+void SnapuserdServer::AddWatchedFd(android::base::borrowed_fd fd) {
struct pollfd p = {};
p.fd = fd.get();
- p.events = events;
+ p.events = POLLIN;
watched_fds_.emplace_back(std::move(p));
}
@@ -366,7 +325,7 @@ void SnapuserdServer::AcceptClient() {
return;
}
- AddWatchedFd(fd, POLLIN);
+ AddWatchedFd(fd);
}
bool SnapuserdServer::HandleClient(android::base::borrowed_fd fd, int revents) {
@@ -463,97 +422,5 @@ bool SnapuserdServer::RemoveAndJoinHandler(const std::string& misc_name) {
return true;
}
-bool SnapuserdServer::WaitForSocket() {
- auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); });
-
- auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy;
-
- if (!android::fs_mgr::WaitForFile(socket_path, std::chrono::milliseconds::max())) {
- LOG(ERROR)
- << "Failed to wait for proxy socket, second-stage snapuserd will fail to connect";
- return false;
- }
-
- // We must re-initialize property service access, since we launched before
- // second-stage init.
- __system_properties_init();
-
- if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {
- LOG(ERROR)
- << "Failed to wait for proxy property, second-stage snapuserd will fail to connect";
- return false;
- }
-
- unique_fd fd(socket_local_client(kSnapuserdSocketProxy, ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET));
- if (fd < 0) {
- PLOG(ERROR) << "Failed to connect to socket proxy";
- return false;
- }
-
- char code[1];
- std::vector<unique_fd> fds;
- ssize_t rv = android::base::ReceiveFileDescriptorVector(fd, code, sizeof(code), 1, &fds);
- if (rv < 0) {
- PLOG(ERROR) << "Failed to receive server socket over proxy";
- return false;
- }
- if (fds.empty()) {
- LOG(ERROR) << "Expected at least one file descriptor from proxy";
- return false;
- }
-
- // We don't care if the ACK is received.
- code[0] = 'a';
- if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL) < 0)) {
- PLOG(ERROR) << "Failed to send ACK to proxy";
- return false;
- }
-
- sockfd_ = std::move(fds[0]);
- if (!StartWithSocket(true)) {
- return false;
- }
- return Run();
-}
-
-bool SnapuserdServer::RunForSocketHandoff() {
- unique_fd proxy_fd(android_get_control_socket(kSnapuserdSocketProxy));
- if (proxy_fd < 0) {
- PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocketProxy;
- }
- borrowed_fd server_fd(android_get_control_socket(kSnapuserdSocket));
- if (server_fd < 0) {
- PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocket;
- }
-
- if (listen(proxy_fd.get(), 4) < 0) {
- PLOG(FATAL) << "Proxy listen socket failed";
- }
-
- if (!android::base::SetProperty("snapuserd.proxy_ready", "true")) {
- LOG(FATAL) << "Proxy failed to set ready property";
- }
-
- unique_fd client_fd(
- TEMP_FAILURE_RETRY(accept4(proxy_fd.get(), nullptr, nullptr, SOCK_CLOEXEC)));
- if (client_fd < 0) {
- PLOG(FATAL) << "Proxy accept failed";
- }
-
- char code[1] = {'a'};
- std::vector<int> fds = {server_fd.get()};
- ssize_t rv = android::base::SendFileDescriptorVector(client_fd, code, sizeof(code), fds);
- if (rv < 0) {
- PLOG(FATAL) << "Proxy could not send file descriptor to snapuserd";
- }
- // Wait for an ACK - results don't matter, we just don't want to risk closing
- // the proxy socket too early.
- if (recv(client_fd, code, sizeof(code), 0) < 0) {
- PLOG(FATAL) << "Proxy could not receive terminating code from snapuserd";
- }
- return true;
-}
-
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd_server.h
index 3b6ff1583..6699189ea 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd_server.h
@@ -42,7 +42,6 @@ enum class DaemonOperations {
STOP,
DELETE,
DETACH,
- SUPPORTS,
INVALID,
};
@@ -94,16 +93,14 @@ class SnapuserdServer : public Stoppable {
private:
android::base::unique_fd sockfd_;
bool terminating_;
- volatile bool received_socket_signal_ = false;
std::vector<struct pollfd> watched_fds_;
- bool is_socket_present_ = false;
std::mutex lock_;
using HandlerList = std::vector<std::shared_ptr<DmUserHandler>>;
HandlerList dm_users_;
- void AddWatchedFd(android::base::borrowed_fd fd, int events);
+ void AddWatchedFd(android::base::borrowed_fd fd);
void AcceptClient();
bool HandleClient(android::base::borrowed_fd fd, int revents);
bool Recv(android::base::borrowed_fd fd, std::string* data);
@@ -120,7 +117,6 @@ class SnapuserdServer : public Stoppable {
void RunThread(std::shared_ptr<DmUserHandler> handler);
void JoinAllThreads();
- bool StartWithSocket(bool start_listening);
// Find a DmUserHandler within a lock.
HandlerList::iterator FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
@@ -133,8 +129,6 @@ class SnapuserdServer : public Stoppable {
bool Start(const std::string& socketname);
bool Run();
void Interrupt();
- bool RunForSocketHandoff();
- bool WaitForSocket();
std::shared_ptr<DmUserHandler> AddHandler(const std::string& misc_name,
const std::string& cow_device_path,
@@ -142,7 +136,6 @@ class SnapuserdServer : public Stoppable {
bool StartHandler(const std::shared_ptr<DmUserHandler>& handler);
void SetTerminating() { terminating_ = true; }
- void ReceivedSocketSignal() { received_socket_signal_ = true; }
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp b/fs_mgr/libsnapshot/snapuserd_worker.cpp
index 0e9f0f11a..682f9da58 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_worker.cpp
@@ -20,7 +20,7 @@
#include <optional>
#include <set>
-#include <snapuserd/snapuserd_client.h>
+#include <libsnapshot/snapuserd_client.h>
namespace android {
namespace snapshot {
@@ -32,6 +32,45 @@ using android::base::unique_fd;
#define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
+void BufferSink::Initialize(size_t size) {
+ buffer_size_ = size;
+ buffer_offset_ = 0;
+ buffer_ = std::make_unique<uint8_t[]>(size);
+}
+
+void* BufferSink::GetPayloadBuffer(size_t size) {
+ if ((buffer_size_ - buffer_offset_) < size) return nullptr;
+
+ char* buffer = reinterpret_cast<char*>(GetBufPtr());
+ struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
+ return (char*)msg->payload.buf + buffer_offset_;
+}
+
+void* BufferSink::GetBuffer(size_t requested, size_t* actual) {
+ void* buf = GetPayloadBuffer(requested);
+ if (!buf) {
+ *actual = 0;
+ return nullptr;
+ }
+ *actual = requested;
+ return buf;
+}
+
+struct dm_user_header* BufferSink::GetHeaderPtr() {
+ if (!(sizeof(struct dm_user_header) <= buffer_size_)) {
+ return nullptr;
+ }
+ char* buf = reinterpret_cast<char*>(GetBufPtr());
+ struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
+ return header;
+}
+
+void* BufferSink::GetPayloadBufPtr() {
+ char* buffer = reinterpret_cast<char*>(GetBufPtr());
+ struct dm_user_message* msg = reinterpret_cast<struct dm_user_message*>(&(buffer[0]));
+ return msg->payload.buf;
+}
+
WorkerThread::WorkerThread(const std::string& cow_device, const std::string& backing_device,
const std::string& control_device, const std::string& misc_name,
std::shared_ptr<Snapuserd> snapuserd) {
@@ -66,11 +105,11 @@ bool WorkerThread::InitializeFds() {
}
bool WorkerThread::InitReader() {
- reader_ = snapuserd_->CloneReaderForWorker();
-
+ reader_ = std::make_unique<CowReader>();
if (!reader_->InitForMerge(std::move(cow_fd_))) {
return false;
}
+
return true;
}
@@ -111,19 +150,10 @@ bool WorkerThread::ReadFromBaseDevice(const CowOperation* cow_op) {
}
SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
<< " Source: " << cow_op->source;
- uint64_t offset = cow_op->source;
- if (cow_op->type == kCowCopyOp) {
- offset *= BLOCK_SZ;
- }
- if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
- std::string op;
- if (cow_op->type == kCowCopyOp)
- op = "Copy-op";
- else {
- op = "Xor-op";
- }
- SNAP_PLOG(ERROR) << op << " failed. Read from backing store: " << backing_store_device_
- << "at block :" << offset / BLOCK_SZ << " offset:" << offset % BLOCK_SZ;
+ if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ,
+ cow_op->source * BLOCK_SZ)) {
+ SNAP_PLOG(ERROR) << "Copy-op failed. Read from backing store: " << backing_store_device_
+ << "at block :" << cow_op->source;
return false;
}
@@ -158,23 +188,6 @@ bool WorkerThread::ProcessCopyOp(const CowOperation* cow_op) {
return true;
}
-bool WorkerThread::ProcessXorOp(const CowOperation* cow_op) {
- if (!GetReadAheadPopulatedBuffer(cow_op)) {
- SNAP_LOG(DEBUG) << " GetReadAheadPopulatedBuffer failed..."
- << " new_block: " << cow_op->new_block;
- if (!ReadFromBaseDevice(cow_op)) {
- return false;
- }
- }
- xorsink_.Reset();
- if (!reader_->ReadData(*cow_op, &xorsink_)) {
- SNAP_LOG(ERROR) << "ProcessXorOp failed for block " << cow_op->new_block;
- return false;
- }
-
- return true;
-}
-
bool WorkerThread::ProcessZeroOp() {
// Zero out the entire block
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
@@ -206,10 +219,6 @@ bool WorkerThread::ProcessCowOp(const CowOperation* cow_op) {
return ProcessCopyOp(cow_op);
}
- case kCowXorOp: {
- return ProcessXorOp(cow_op);
- }
-
default: {
SNAP_LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
}
@@ -278,36 +287,16 @@ int WorkerThread::ReadData(sector_t sector, size_t size) {
it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr),
Snapuserd::compare);
- bool read_end_of_device = false;
- if (it == chunk_vec.end()) {
- // |-------|-------|-------|
- // 0 1 2 3
- //
- // Block 0 - op 1
- // Block 1 - op 2
- // Block 2 - op 3
- //
- // chunk_vec will have block 0, 1, 2 which maps to relavant COW ops.
- //
- // Each block is 4k bytes. Thus, the last block will span 8 sectors
- // ranging till block 3 (However, block 3 won't be in chunk_vec as
- // it doesn't have any mapping to COW ops. Now, if we get an I/O request for a sector
- // spanning between block 2 and block 3, we need to step back
- // and get hold of the last element.
- //
- // Additionally, dm-snapshot makes sure that I/O request beyond block 3
- // will not be routed to the daemon. Hence, it is safe to assume that
- // if a sector is not available in the chunk_vec, the I/O falls in the
- // end of region.
- it = std::prev(chunk_vec.end());
- read_end_of_device = true;
+ if (!(it != chunk_vec.end())) {
+ SNAP_LOG(ERROR) << "ReadData: Sector " << sector << " not found in chunk_vec";
+ return -1;
}
// We didn't find the required sector; hence find the previous sector
// as lower_bound will gives us the value greater than
// the requested sector
if (it->first != sector) {
- if (it != chunk_vec.begin() && !read_end_of_device) {
+ if (it != chunk_vec.begin()) {
--it;
}
@@ -481,10 +470,10 @@ loff_t WorkerThread::GetMergeStartOffset(void* merged_buffer, void* unmerged_buf
}
int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffer, loff_t offset,
- int unmerged_exceptions, bool* ordered_op, bool* commit) {
+ int unmerged_exceptions, bool* copy_op, bool* commit) {
int merged_ops_cur_iter = 0;
std::unordered_map<uint64_t, void*>& read_ahead_buffer_map = snapuserd_->GetReadAheadMap();
- *ordered_op = false;
+ *copy_op = false;
std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
// Find the operations which are merged in this cycle.
@@ -522,9 +511,9 @@ int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffe
}
const CowOperation* cow_op = it->second;
- if (snapuserd_->IsReadAheadFeaturePresent() && IsOrderedOp(*cow_op)) {
- *ordered_op = true;
- // Every single ordered operation has to come from read-ahead
+ if (snapuserd_->IsReadAheadFeaturePresent() && cow_op->type == kCowCopyOp) {
+ *copy_op = true;
+ // Every single copy operation has to come from read-ahead
// cache.
if (read_ahead_buffer_map.find(cow_op->new_block) == read_ahead_buffer_map.end()) {
SNAP_LOG(ERROR)
@@ -568,7 +557,7 @@ int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffe
bool WorkerThread::ProcessMergeComplete(chunk_t chunk, void* buffer) {
uint32_t stride = exceptions_per_area_ + 1;
const std::vector<std::unique_ptr<uint8_t[]>>& vec = snapuserd_->GetMetadataVec();
- bool ordered_op = false;
+ bool copy_op = false;
bool commit = false;
// ChunkID to vector index
@@ -593,7 +582,7 @@ bool WorkerThread::ProcessMergeComplete(chunk_t chunk, void* buffer) {
}
int merged_ops_cur_iter = GetNumberOfMergedOps(buffer, vec[divresult.quot].get(), offset,
- unmerged_exceptions, &ordered_op, &commit);
+ unmerged_exceptions, &copy_op, &commit);
// There should be at least one operation merged in this cycle
if (!(merged_ops_cur_iter > 0)) {
@@ -601,7 +590,7 @@ bool WorkerThread::ProcessMergeComplete(chunk_t chunk, void* buffer) {
return false;
}
- if (ordered_op) {
+ if (copy_op) {
if (commit) {
// Push the flushing logic to read-ahead thread so that merge thread
// can make forward progress. Sync will happen in the background
@@ -830,7 +819,6 @@ void WorkerThread::InitializeBufsink() {
bool WorkerThread::RunThread() {
InitializeBufsink();
- xorsink_.Initialize(&bufsink_, BLOCK_SZ);
if (!InitializeFds()) {
return false;
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index 71fe12435..e3e3af853 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -267,8 +267,8 @@ AssertionResult LowSpaceUserdata::Init(uint64_t max_free_space) {
return AssertionFailure() << "Temp file allocated to " << big_file_->path << ", not in "
<< kUserDataDevice;
}
- uint64_t next_consume = std::min(available_space_ - max_free_space,
- (uint64_t)std::numeric_limits<off_t>::max());
+ uint64_t next_consume =
+ std::min(free_space_ - max_free_space, (uint64_t)std::numeric_limits<off_t>::max());
off_t allocated = 0;
while (next_consume > 0 && free_space_ > max_free_space) {
int status = fallocate(big_file_->fd, 0, allocated, next_consume);
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index f01bec938..4a2af1c10 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -22,7 +22,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <fs_mgr/roots.h>
@@ -188,14 +187,6 @@ bool IsCompressionEnabled() {
return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
}
-bool IsUserspaceSnapshotsEnabled() {
- return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
-}
-
-bool IsIouringEnabled() {
- return android::base::GetBoolProperty("ro.virtual_ab.io_uring.enabled", false);
-}
-
std::string GetOtherPartitionName(const std::string& name) {
auto suffix = android::fs_mgr::GetPartitionSlotSuffix(name);
CHECK(suffix == "_a" || suffix == "_b");
@@ -204,9 +195,5 @@ std::string GetOtherPartitionName(const std::string& name) {
return name.substr(0, name.size() - suffix.size()) + other_suffix;
}
-bool IsDmSnapshotTestingEnabled() {
- return android::base::GetBoolProperty("snapuserd.test.dm.snapshots", false);
-}
-
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 0ef3234fd..671de9dbc 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -57,14 +57,14 @@ struct AutoDeviceList {
// Automatically unmap a device upon deletion.
struct AutoUnmapDevice : AutoDevice {
// On destruct, delete |name| from device mapper.
- AutoUnmapDevice(android::dm::IDeviceMapper* dm, const std::string& name)
+ AutoUnmapDevice(android::dm::DeviceMapper* dm, const std::string& name)
: AutoDevice(name), dm_(dm) {}
AutoUnmapDevice(AutoUnmapDevice&& other) = default;
~AutoUnmapDevice();
private:
DISALLOW_COPY_AND_ASSIGN(AutoUnmapDevice);
- android::dm::IDeviceMapper* dm_ = nullptr;
+ android::dm::DeviceMapper* dm_ = nullptr;
};
// Automatically unmap an image upon deletion.
@@ -131,13 +131,8 @@ void AppendExtent(google::protobuf::RepeatedPtrField<chromeos_update_engine::Ext
bool IsCompressionEnabled();
-bool IsUserspaceSnapshotsEnabled();
-
-bool IsDmSnapshotTestingEnabled();
-
-bool IsIouringEnabled();
-
// Swap the suffix of a partition name.
std::string GetOtherPartitionName(const std::string& name);
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/vts_ota_config_test.cpp b/fs_mgr/libsnapshot/vts_ota_config_test.cpp
deleted file mode 100644
index afc2d81a4..000000000
--- a/fs_mgr/libsnapshot/vts_ota_config_test.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT 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/properties.h>
-#include <gtest/gtest.h>
-
-TEST(VAB, Enabled) {
- ASSERT_TRUE(android::base::GetBoolProperty("ro.virtual_ab.enabled", false));
- ASSERT_TRUE(android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false));
-}
diff --git a/fs_mgr/libstorage_literals/Android.bp b/fs_mgr/libstorage_literals/Android.bp
index 42abd0937..5b0716851 100644
--- a/fs_mgr/libstorage_literals/Android.bp
+++ b/fs_mgr/libstorage_literals/Android.bp
@@ -6,8 +6,6 @@ package {
cc_library_headers {
name: "libstorage_literals_headers",
host_supported: true,
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
export_include_dirs: ["."],
target: {
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index d82d56667..335da9e61 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -88,32 +88,3 @@ java_test_host {
test_suites: ["general-tests"],
}
-
-cc_test {
- name: "vts_fs_test",
- test_suites: [
- "vts",
- "device-tests",
- ],
- test_options: {
- min_shipping_api_level: 29,
- },
- require_root: true,
- auto_gen_config: true,
- cflags: [
- "-Wall",
- "-Werror",
- ],
- srcs: [
- "vts_fs_test.cpp",
- ],
- shared_libs: [
- "libbase",
- ],
- static_libs: [
- "libfs_mgr",
- "libfstab",
- "libgmock",
- "libgtest",
- ],
-}
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 6c881c0bf..953574b66 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -120,7 +120,7 @@ const std::vector<std::pair<std::string, std::string>> result_space = {
};
const std::string bootconfig =
- "androidboot.bootdevice = \"1d84000.ufshc\"\n"
+ "androidboot.bootdevice = \" \"1d84000.ufshc\"\n"
"androidboot.boot_devices = \"dev1\", \"dev2,withcomma\", \"dev3\"\n"
"androidboot.baseband = \"sdy\"\n"
"androidboot.keymaster = \"1\"\n"
@@ -192,13 +192,17 @@ bool CompareFlags(FstabEntry::FsMgrFlags& lhs, FstabEntry::FsMgrFlags& rhs) {
lhs.nonremovable == rhs.nonremovable &&
lhs.vold_managed == rhs.vold_managed &&
lhs.recovery_only == rhs.recovery_only &&
+ lhs.verify == rhs.verify &&
+ lhs.force_crypt == rhs.force_crypt &&
lhs.no_emulated_sd == rhs.no_emulated_sd &&
lhs.no_trim == rhs.no_trim &&
lhs.file_encryption == rhs.file_encryption &&
lhs.formattable == rhs.formattable &&
lhs.slot_select == rhs.slot_select &&
+ lhs.force_fde_or_fbe == rhs.force_fde_or_fbe &&
lhs.late_mount == rhs.late_mount &&
lhs.no_fail == rhs.no_fail &&
+ lhs.verify_at_boot == rhs.verify_at_boot &&
lhs.quota == rhs.quota &&
lhs.avb == rhs.avb &&
lhs.logical == rhs.logical &&
@@ -407,7 +411,7 @@ TEST(fs_mgr, ReadFstabFromFile_FsMgrFlags) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source none0 swap defaults wait,check,nonremovable,recoveryonly
+source none0 swap defaults wait,check,nonremovable,recoveryonly,verifyatboot,verify
source none1 swap defaults avb,noemulatedsd,notrim,formattable,nofail
source none2 swap defaults first_stage_mount,latemount,quota,logical
source none3 swap defaults checkpoint=block
@@ -428,6 +432,8 @@ source none5 swap defaults defaults
flags.check = true;
flags.nonremovable = true;
flags.recovery_only = true;
+ flags.verify_at_boot = true;
+ flags.verify = true;
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
@@ -482,16 +488,18 @@ TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_AllBad) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source none0 swap defaults fileencryption,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_backingdev_size
+source none0 swap defaults encryptable,forceencrypt,fileencryption,forcefdeorfbe,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_backingdev_size
-source none1 swap defaults fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_backingdev_size=
+source none1 swap defaults encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_backingdev_size=
+
+source none2 swap defaults forcefdeorfbe=
)fs";
ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
Fstab fstab;
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
- ASSERT_LE(2U, fstab.size());
+ ASSERT_LE(3U, fstab.size());
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
@@ -499,6 +507,7 @@ source none1 swap defaults fileencryption=,keydirectory=,length=,sw
FstabEntry::FsMgrFlags flags = {};
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
+ EXPECT_EQ("", entry->key_loc);
EXPECT_EQ("", entry->metadata_key_dir);
EXPECT_EQ(0, entry->length);
EXPECT_EQ("", entry->label);
@@ -517,10 +526,13 @@ source none1 swap defaults fileencryption=,keydirectory=,length=,sw
EXPECT_EQ("none1", entry->mount_point);
{
FstabEntry::FsMgrFlags flags = {};
+ flags.crypt = true;
+ flags.force_crypt = true;
flags.file_encryption = true;
flags.avb = true;
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
+ EXPECT_EQ("", entry->key_loc);
EXPECT_EQ("", entry->metadata_key_dir);
EXPECT_EQ(0, entry->length);
EXPECT_EQ("", entry->label);
@@ -534,26 +546,24 @@ source none1 swap defaults fileencryption=,keydirectory=,length=,sw
EXPECT_EQ(0, entry->logical_blk_size);
EXPECT_EQ("", entry->sysfs_path);
EXPECT_EQ(0U, entry->zram_backingdev_size);
-}
-
-// FDE is no longer supported, so an fstab with FDE enabled should be rejected.
-TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FDE) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
- std::string fstab_contents = R"fs(
-source /data ext4 noatime forceencrypt=footer
-)fs";
- ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+ entry++;
- Fstab fstab;
- EXPECT_FALSE(ReadFstabFromFile(tf.path, &fstab));
+ // forcefdeorfbe has its own encryption_options defaults, so test it separately.
+ EXPECT_EQ("none2", entry->mount_point);
+ {
+ FstabEntry::FsMgrFlags flags = {};
+ flags.force_fde_or_fbe = true;
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ }
+ EXPECT_EQ("aes-256-xts:aes-256-cts", entry->encryption_options);
+ EXPECT_EQ("", entry->key_loc);
}
-TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_AdoptableStorage) {
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Encryptable) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source none0 swap defaults encryptable=userdata,voldmanaged=sdcard:auto
+source none0 swap defaults encryptable=/dir/key
)fs";
ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
@@ -563,11 +573,11 @@ source none0 swap defaults encryptable=userdata,voldmanaged=sdcard:
FstabEntry::FsMgrFlags flags = {};
flags.crypt = true;
- flags.vold_managed = true;
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ("/dir/key", entry->key_loc);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_VoldManaged) {
@@ -715,6 +725,53 @@ source none5 swap defaults zramsize=%
EXPECT_EQ(0, entry->zram_size);
}
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ForceEncrypt) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ std::string fstab_contents = R"fs(
+source none0 swap defaults forceencrypt=/dir/key
+)fs";
+
+ ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+ Fstab fstab;
+ EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+ ASSERT_LE(1U, fstab.size());
+
+ auto entry = fstab.begin();
+ EXPECT_EQ("none0", entry->mount_point);
+
+ FstabEntry::FsMgrFlags flags = {};
+ flags.force_crypt = true;
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+
+ EXPECT_EQ("/dir/key", entry->key_loc);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ForceFdeOrFbe) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ std::string fstab_contents = R"fs(
+source none0 swap defaults forcefdeorfbe=/dir/key
+)fs";
+
+ ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+ Fstab fstab;
+ EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+ ASSERT_LE(1U, fstab.size());
+
+ auto entry = fstab.begin();
+ EXPECT_EQ("none0", entry->mount_point);
+
+ FstabEntry::FsMgrFlags flags = {};
+ flags.force_fde_or_fbe = true;
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+
+ EXPECT_EQ("/dir/key", entry->key_loc);
+ EXPECT_EQ("aes-256-xts:aes-256-cts", entry->encryption_options);
+}
+
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
@@ -943,7 +1000,7 @@ source none0 swap defaults keydirectory=/dir/key,metadata_encryptio
ASSERT_LE(1U, fstab.size());
auto entry = fstab.begin();
- EXPECT_EQ("adiantum", entry->metadata_encryption_options);
+ EXPECT_EQ("adiantum", entry->metadata_encryption);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption_WrappedKey) {
@@ -960,8 +1017,8 @@ source none0 swap defaults keydirectory=/dir/key,metadata_encryptio
ASSERT_LE(1U, fstab.size());
auto entry = fstab.begin();
- EXPECT_EQ("aes-256-xts:wrappedkey_v0", entry->metadata_encryption_options);
- auto parts = android::base::Split(entry->metadata_encryption_options, ":");
+ EXPECT_EQ("aes-256-xts:wrappedkey_v0", entry->metadata_encryption);
+ auto parts = android::base::Split(entry->metadata_encryption, ":");
EXPECT_EQ(2U, parts.size());
EXPECT_EQ("aes-256-xts", parts[0]);
EXPECT_EQ("wrappedkey_v0", parts[1]);
@@ -1104,76 +1161,3 @@ source none6 swap defaults readahead_size_kb=0
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->readahead_size_kb);
}
-
-TEST(fs_mgr, TransformFstabForDsu) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
- std::string fstab_contents = R"fs(
-system /system erofs ro wait,logical,first_stage_mount
-system /system ext4 ro wait,logical,first_stage_mount
-vendor /vendor ext4 ro wait,logical,first_stage_mount
-data /data f2fs noatime wait
-)fs";
-
- ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
-
- Fstab fstab;
- EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
- TransformFstabForDsu(&fstab, "dsu", {"system_gsi", "userdata_gsi"});
- ASSERT_EQ(4U, fstab.size());
-
- auto entry = fstab.begin();
-
- EXPECT_EQ("/system", entry->mount_point);
- EXPECT_EQ("system_gsi", entry->blk_device);
- entry++;
-
- EXPECT_EQ("/system", entry->mount_point);
- EXPECT_EQ("system_gsi", entry->blk_device);
- entry++;
-
- EXPECT_EQ("/vendor", entry->mount_point);
- EXPECT_EQ("vendor", entry->blk_device);
- entry++;
-
- EXPECT_EQ("/data", entry->mount_point);
- EXPECT_EQ("userdata_gsi", entry->blk_device);
- entry++;
-}
-
-TEST(fs_mgr, TransformFstabForDsu_synthesisExt4Entry) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
- std::string fstab_contents = R"fs(
-system /system erofs ro wait,logical,first_stage_mount
-vendor /vendor ext4 ro wait,logical,first_stage_mount
-data /data f2fs noatime wait
-)fs";
-
- ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
-
- Fstab fstab;
- EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
- TransformFstabForDsu(&fstab, "dsu", {"system_gsi", "userdata_gsi"});
- ASSERT_EQ(4U, fstab.size());
-
- auto entry = fstab.begin();
-
- EXPECT_EQ("/system", entry->mount_point);
- EXPECT_EQ("system_gsi", entry->blk_device);
- EXPECT_EQ("erofs", entry->fs_type);
- entry++;
-
- EXPECT_EQ("/system", entry->mount_point);
- EXPECT_EQ("system_gsi", entry->blk_device);
- EXPECT_EQ("ext4", entry->fs_type);
- entry++;
-
- EXPECT_EQ("/vendor", entry->mount_point);
- EXPECT_EQ("vendor", entry->blk_device);
- entry++;
-
- EXPECT_EQ("/data", entry->mount_point);
- EXPECT_EQ("userdata_gsi", entry->blk_device);
- entry++;
-}
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
deleted file mode 100644
index aac2cfd9b..000000000
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <sys/mount.h>
-#include <sys/utsname.h>
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <fstab/fstab.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <libdm/dm.h>
-
-static int GetVsrLevel() {
- return android::base::GetIntProperty("ro.vendor.api_level", -1);
-}
-
-TEST(fs, ErofsSupported) {
- // S and higher for this test.
- if (GetVsrLevel() < __ANDROID_API_S__) {
- GTEST_SKIP();
- }
-
- struct utsname uts;
- ASSERT_EQ(uname(&uts), 0);
-
- unsigned int major, minor;
- ASSERT_EQ(sscanf(uts.release, "%u.%u", &major, &minor), 2);
-
- // EROFS support only required in 5.10+
- if (major < 5 || (major == 5 && minor < 10)) {
- GTEST_SKIP();
- }
-
- std::string fs;
- ASSERT_TRUE(android::base::ReadFileToString("/proc/filesystems", &fs));
- EXPECT_THAT(fs, ::testing::HasSubstr("\terofs\n"));
-
- ASSERT_EQ(access("/sys/fs/erofs", F_OK), 0);
-}
-
-TEST(fs, PartitionTypes) {
- android::fs_mgr::Fstab fstab;
- ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab));
-
- auto& dm = android::dm::DeviceMapper::Instance();
-
- std::string super_bdev, userdata_bdev;
- ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/super", &super_bdev));
- ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/userdata", &userdata_bdev));
-
- int vsr_level = GetVsrLevel();
-
- for (const auto& entry : fstab) {
- std::string parent_bdev = entry.blk_device;
- while (true) {
- auto basename = android::base::Basename(parent_bdev);
- if (!android::base::StartsWith(basename, "dm-")) {
- break;
- }
-
- auto parent = dm.GetParentBlockDeviceByPath(parent_bdev);
- if (!parent || *parent == parent_bdev) {
- break;
- }
- parent_bdev = *parent;
- }
-
- if (parent_bdev == userdata_bdev ||
- android::base::StartsWith(parent_bdev, "/dev/block/loop")) {
- if (entry.flags & MS_RDONLY) {
- // APEXes should not be F2FS.
- EXPECT_NE(entry.fs_type, "f2fs");
- }
- continue;
- }
-
- if (vsr_level < __ANDROID_API_T__) {
- continue;
- }
- if (vsr_level == __ANDROID_API_T__ && parent_bdev != super_bdev) {
- // Only check for dynamic partitions at this VSR level.
- continue;
- }
-
- if (entry.flags & MS_RDONLY) {
- std::vector<std::string> allowed = {"erofs", "ext4"};
- if (vsr_level == __ANDROID_API_T__) {
- allowed.emplace_back("f2fs");
- }
-
- EXPECT_NE(std::find(allowed.begin(), allowed.end(), entry.fs_type), allowed.end())
- << entry.mount_point;
- } else {
- EXPECT_NE(entry.fs_type, "ext4") << entry.mount_point;
- }
- }
-}
-
-TEST(fs, NoDtFstab) {
- if (GetVsrLevel() < __ANDROID_API_Q__) {
- GTEST_SKIP();
- }
-
- android::fs_mgr::Fstab fstab;
- EXPECT_FALSE(android::fs_mgr::ReadFstabFromDt(&fstab, false));
-}
diff --git a/gatekeeperd/Android.bp b/gatekeeperd/Android.bp
index 0aedc5816..95e814b6a 100644
--- a/gatekeeperd/Android.bp
+++ b/gatekeeperd/Android.bp
@@ -29,9 +29,7 @@ cc_binary {
srcs: [
"gatekeeperd.cpp",
],
- defaults: [
- "keymint_use_latest_hal_aidl_ndk_shared",
- ],
+
shared_libs: [
"libbinder",
"libbinder_ndk",
@@ -45,7 +43,8 @@ cc_binary {
"libhidlbase",
"android.hardware.gatekeeper@1.0",
"libgatekeeper_aidl",
- "android.security.authorization-ndk",
+ "android.hardware.security.keymint-V1-ndk_platform",
+ "android.security.authorization-ndk_platform",
],
static_libs: ["libscrypt_static"],
diff --git a/gatekeeperd/gatekeeperd.rc b/gatekeeperd/gatekeeperd.rc
index f572b11e1..8b126d588 100644
--- a/gatekeeperd/gatekeeperd.rc
+++ b/gatekeeperd/gatekeeperd.rc
@@ -1,4 +1,4 @@
service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
class late_start
user system
- task_profiles ServiceCapacityLow
+ writepid /dev/cpuset/system-background/tasks
diff --git a/healthd/Android.bp b/healthd/Android.bp
index f18000662..ec47f68b3 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -22,15 +22,9 @@ cc_library_static {
"libutils",
"libbase",
- // Need HealthInfo definition from headers of these shared
- // libraries. Clients don't need to link to these.
+ // Need latest HealthInfo definition from headers of this shared
+ // library. Clients don't need to link to this.
"android.hardware.health@2.1",
- "android.hardware.health-V1-ndk",
- ],
- whole_static_libs: [
- // Need to translate HIDL to AIDL to support legacy APIs in
- // BatteryMonitor.
- "android.hardware.health-translate-ndk",
],
header_libs: ["libhealthd_headers"],
export_header_lib_headers: ["libhealthd_headers"],
@@ -112,7 +106,6 @@ sysprop_library {
cc_library_static {
name: "libhealthd_draw",
- vendor_available: true,
export_include_dirs: ["."],
static_libs: [
"libcharger_sysprop",
@@ -124,34 +117,24 @@ cc_library_static {
header_libs: ["libbatteryservice_headers"],
srcs: ["healthd_draw.cpp"],
-
- target: {
- vendor: {
- exclude_static_libs: [
- "libcharger_sysprop",
- ],
- },
- },
}
cc_library_static {
- name: "libhealthd_charger_ui",
- vendor_available: true,
- export_include_dirs: [
- "include",
- "include_charger",
- ],
+ name: "libhealthd_charger",
+ local_include_dirs: ["include"],
+ export_include_dirs: [".", "include"],
static_libs: [
- "android.hardware.health-V1-ndk",
- "android.hardware.health-translate-ndk",
+ "android.hardware.health@1.0-convert",
"libcharger_sysprop",
"libhealthd_draw",
"libhealthloop",
+ "libhealth2impl",
"libminui",
],
shared_libs: [
+ "android.hardware.health@2.1",
"libbase",
"libcutils",
"liblog",
@@ -160,60 +143,14 @@ cc_library_static {
"libutils",
],
- header_libs: [
- "libhealthd_headers",
- ],
-
- export_static_lib_headers: [
- "android.hardware.health-V1-ndk",
- ],
-
srcs: [
"healthd_mode_charger.cpp",
"AnimationParser.cpp",
],
-
- target: {
- vendor: {
- exclude_static_libs: [
- "libcharger_sysprop",
- ],
- },
- },
-}
-
-cc_library_static {
- name: "libhealthd_charger",
- export_include_dirs: [
- "include",
- "include_charger",
- ],
-
- static_libs: [
- "android.hardware.health@1.0-convert",
- "libcharger_sysprop",
- "libhealth2impl",
- "libhealthd_charger_ui",
- ],
-
- shared_libs: [
- "android.hardware.health@2.1",
- "libbase",
- "libcutils",
- "liblog",
- "libutils",
- ],
-
- srcs: [
- "healthd_mode_charger_hidl.cpp",
- ],
}
cc_defaults {
name: "charger_defaults",
- local_include_dirs: [
- "include_charger",
- ],
cflags: [
"-Wall",
@@ -222,6 +159,8 @@ cc_defaults {
shared_libs: [
// common
+ "android.hardware.health@2.0",
+ "android.hardware.health@2.1",
"libbase",
"libcutils",
"libhidlbase",
@@ -235,7 +174,6 @@ cc_defaults {
static_libs: [
// common
"android.hardware.health@1.0-convert",
- "android.hardware.health-V1-ndk",
"libbatterymonitor",
"libcharger_sysprop",
"libhealthd_charger_nops",
@@ -245,7 +183,6 @@ cc_defaults {
// system charger only
"libhealthd_draw",
"libhealthd_charger",
- "libhealthd_charger_ui",
"libminui",
"libsuspend",
],
@@ -259,10 +196,6 @@ cc_binary {
"charger.cpp",
"charger_utils.cpp",
],
- shared_libs: [
- "android.hardware.health@2.0",
- "android.hardware.health@2.1",
- ],
target: {
recovery: {
@@ -276,7 +209,6 @@ cc_binary {
exclude_static_libs: [
"libhealthd_draw",
"libhealthd_charger",
- "libhealthd_charger_ui",
"libminui",
"libsuspend",
],
@@ -288,11 +220,6 @@ cc_test {
name: "charger_test",
defaults: ["charger_defaults"],
srcs: ["charger_test.cpp"],
- static_libs: [
- "android.hardware.health@1.0",
- "android.hardware.health@2.0",
- "android.hardware.health@2.1",
- ],
}
cc_test {
@@ -303,9 +230,6 @@ cc_test {
"healthd_mode_charger_test.cpp"
],
static_libs: [
- "android.hardware.health@1.0",
- "android.hardware.health@2.0",
- "android.hardware.health@2.1",
"libgmock",
],
test_suites: [
@@ -341,29 +265,3 @@ phony {
"system_core_charger_res_images_battery_scale.png",
],
}
-
-// /vendor/etc/res/images/charger/battery_fail.png
-prebuilt_etc {
- name: "system_core_charger_res_images_battery_fail.png_default_vendor",
- src: "images/battery_fail.png",
- relative_install_path: "res/images/charger/default",
- vendor: true,
- filename: "battery_fail.png",
-}
-
-// /vendor/etc/res/images/charger/battery_scale.png
-prebuilt_etc {
- name: "system_core_charger_res_images_battery_scale.png_default_vendor",
- src: "images/battery_scale.png",
- relative_install_path: "res/images/charger/default",
- vendor: true,
- filename: "battery_scale.png",
-}
-
-phony {
- name: "charger_res_images_vendor",
- required: [
- "system_core_charger_res_images_battery_fail.png_default_vendor",
- "system_core_charger_res_images_battery_scale.png_default_vendor",
- ],
-}
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index a7571a260..377acb75e 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -31,12 +31,10 @@
#include <memory>
#include <optional>
-#include <aidl/android/hardware/health/HealthInfo.h>
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android/hardware/health/2.1/types.h>
-#include <android/hardware/health/translate-ndk.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <cutils/properties.h>
@@ -54,54 +52,10 @@
using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
using HealthInfo_2_0 = android::hardware::health::V2_0::HealthInfo;
using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
-using aidl::android::hardware::health::BatteryCapacityLevel;
-using aidl::android::hardware::health::BatteryHealth;
-using aidl::android::hardware::health::BatteryStatus;
-using aidl::android::hardware::health::HealthInfo;
-
-namespace {
-
-// Translate from AIDL back to HIDL definition for getHealthInfo_*_* calls.
-// Skips storageInfo and diskStats.
-void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
- ::android::hardware::health::V1_0::HealthInfo* out) {
- out->chargerAcOnline = in.chargerAcOnline;
- out->chargerUsbOnline = in.chargerUsbOnline;
- out->chargerWirelessOnline = in.chargerWirelessOnline;
- out->maxChargingCurrent = in.maxChargingCurrentMicroamps;
- out->maxChargingVoltage = in.maxChargingVoltageMicrovolts;
- out->batteryStatus =
- static_cast<::android::hardware::health::V1_0::BatteryStatus>(in.batteryStatus);
- out->batteryHealth =
- static_cast<::android::hardware::health::V1_0::BatteryHealth>(in.batteryHealth);
- out->batteryPresent = in.batteryPresent;
- out->batteryLevel = in.batteryLevel;
- out->batteryVoltage = in.batteryVoltageMillivolts;
- out->batteryTemperature = in.batteryTemperatureTenthsCelsius;
- out->batteryCurrent = in.batteryCurrentMicroamps;
- out->batteryCycleCount = in.batteryCycleCount;
- out->batteryFullCharge = in.batteryFullChargeUah;
- out->batteryChargeCounter = in.batteryChargeCounterUah;
- out->batteryTechnology = in.batteryTechnology;
-}
-
-void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
- ::android::hardware::health::V2_0::HealthInfo* out) {
- translateToHidl(in, &out->legacy);
- out->batteryCurrentAverage = in.batteryCurrentAverageMicroamps;
- // Skip storageInfo and diskStats
-}
-
-void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
- ::android::hardware::health::V2_1::HealthInfo* out) {
- translateToHidl(in, &out->legacy);
- out->batteryCapacityLevel = static_cast<android::hardware::health::V2_1::BatteryCapacityLevel>(
- in.batteryCapacityLevel);
- out->batteryChargeTimeToFullNowSeconds = in.batteryChargeTimeToFullNowSeconds;
- out->batteryFullChargeDesignCapacityUah = in.batteryFullChargeDesignCapacityUah;
-}
-
-} // namespace
+using android::hardware::health::V1_0::BatteryHealth;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V2_1::BatteryCapacityLevel;
+using android::hardware::health::V2_1::Constants;
namespace android {
@@ -120,14 +74,17 @@ static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> ma
return std::nullopt;
}
-static void initHealthInfo(HealthInfo* health_info) {
- *health_info = {
- .batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED,
- .batteryChargeTimeToFullNowSeconds =
- (int64_t)HealthInfo::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED,
- .batteryStatus = BatteryStatus::UNKNOWN,
- .batteryHealth = BatteryHealth::UNKNOWN,
- };
+static void initHealthInfo(HealthInfo_2_1* health_info_2_1) {
+ *health_info_2_1 = HealthInfo_2_1{};
+
+ // HIDL enum values are zero initialized, so they need to be initialized
+ // properly.
+ health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED;
+ health_info_2_1->batteryChargeTimeToFullNowSeconds =
+ (int64_t)Constants::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
+ auto* props = &health_info_2_1->legacy.legacy;
+ props->batteryStatus = BatteryStatus::UNKNOWN;
+ props->batteryHealth = BatteryHealth::UNKNOWN;
}
BatteryMonitor::BatteryMonitor()
@@ -135,31 +92,21 @@ BatteryMonitor::BatteryMonitor()
mBatteryDevicePresent(false),
mBatteryFixedCapacity(0),
mBatteryFixedTemperature(0),
- mHealthInfo(std::make_unique<HealthInfo>()) {
+ mHealthInfo(std::make_unique<HealthInfo_2_1>()) {
initHealthInfo(mHealthInfo.get());
}
BatteryMonitor::~BatteryMonitor() {}
-HealthInfo_1_0 BatteryMonitor::getHealthInfo_1_0() const {
- HealthInfo_1_0 health_info_1_0;
- translateToHidl(*mHealthInfo, &health_info_1_0);
- return health_info_1_0;
-}
-
-HealthInfo_2_0 BatteryMonitor::getHealthInfo_2_0() const {
- HealthInfo_2_0 health_info_2_0;
- translateToHidl(*mHealthInfo, &health_info_2_0);
- return health_info_2_0;
+const HealthInfo_1_0& BatteryMonitor::getHealthInfo_1_0() const {
+ return getHealthInfo_2_0().legacy;
}
-HealthInfo_2_1 BatteryMonitor::getHealthInfo_2_1() const {
- HealthInfo_2_1 health_info_2_1;
- translateToHidl(*mHealthInfo, &health_info_2_1);
- return health_info_2_1;
+const HealthInfo_2_0& BatteryMonitor::getHealthInfo_2_0() const {
+ return getHealthInfo_2_1().legacy;
}
-const HealthInfo& BatteryMonitor::getHealthInfo() const {
+const HealthInfo_2_1& BatteryMonitor::getHealthInfo_2_1() const {
return *mHealthInfo;
}
@@ -227,48 +174,45 @@ BatteryHealth getBatteryHealth(const char* status) {
return *ret;
}
-static int readFromFile(const String8& path, std::string* buf) {
- buf->clear();
+int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
if (android::base::ReadFileToString(path.c_str(), buf)) {
*buf = android::base::Trim(*buf);
}
return buf->length();
}
-static BatteryMonitor::PowerSupplyType readPowerSupplyType(const String8& path) {
+BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
static SysfsStringEnumMap<int> supplyTypeMap[] = {
- {"Unknown", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
- {"Battery", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_BATTERY},
- {"UPS", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"Mains", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"USB", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
- {"USB_DCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"USB_HVDCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"USB_CDP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"USB_ACA", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"USB_C", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"USB_PD", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
- {"USB_PD_DRP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
- {"Wireless", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
- {"Dock", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_DOCK},
+ {"Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
+ {"Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY},
+ {"UPS", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"Mains", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB", ANDROID_POWER_SUPPLY_TYPE_USB},
+ {"USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_C", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB},
+ {"Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
{NULL, 0},
};
std::string buf;
- if (readFromFile(path, &buf) <= 0) {
- return BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
- }
+ if (readFromFile(path, &buf) <= 0)
+ return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
if (!ret) {
KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
- *ret = BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
+ *ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
}
return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
}
-static bool getBooleanField(const String8& path) {
+bool BatteryMonitor::getBooleanField(const String8& path) {
std::string buf;
bool value = false;
@@ -279,7 +223,7 @@ static bool getBooleanField(const String8& path) {
return value;
}
-static int getIntField(const String8& path) {
+int BatteryMonitor::getIntField(const String8& path) {
std::string buf;
int value = 0;
@@ -289,7 +233,7 @@ static int getIntField(const String8& path) {
return value;
}
-static bool isScopedPowerSupply(const char* name) {
+bool BatteryMonitor::isScopedPowerSupply(const char* name) {
constexpr char kScopeDevice[] = "Device";
String8 path;
@@ -301,31 +245,32 @@ static bool isScopedPowerSupply(const char* name) {
void BatteryMonitor::updateValues(void) {
initHealthInfo(mHealthInfo.get());
+ HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
+
if (!mHealthdConfig->batteryPresentPath.isEmpty())
- mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
+ props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
else
- mHealthInfo->batteryPresent = mBatteryDevicePresent;
+ props.batteryPresent = mBatteryDevicePresent;
- mHealthInfo->batteryLevel = mBatteryFixedCapacity
- ? mBatteryFixedCapacity
- : getIntField(mHealthdConfig->batteryCapacityPath);
- mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
+ props.batteryLevel = mBatteryFixedCapacity ?
+ mBatteryFixedCapacity :
+ getIntField(mHealthdConfig->batteryCapacityPath);
+ props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
- mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath);
+ props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath);
if (!mHealthdConfig->batteryFullChargePath.isEmpty())
- mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath);
+ props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
- mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
+ props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
- mHealthInfo->batteryChargeCounterUah =
- getIntField(mHealthdConfig->batteryChargeCounterPath);
+ props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
- mHealthInfo->batteryCurrentAverageMicroamps =
+ mHealthInfo->legacy.batteryCurrentAverage =
getIntField(mHealthdConfig->batteryCurrentAvgPath);
if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
@@ -336,9 +281,9 @@ void BatteryMonitor::updateValues(void) {
mHealthInfo->batteryFullChargeDesignCapacityUah =
getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
- mHealthInfo->batteryTemperatureTenthsCelsius =
- mBatteryFixedTemperature ? mBatteryFixedTemperature
- : getIntField(mHealthdConfig->batteryTemperaturePath);
+ props.batteryTemperature = mBatteryFixedTemperature ?
+ mBatteryFixedTemperature :
+ getIntField(mHealthdConfig->batteryTemperaturePath);
std::string buf;
@@ -346,13 +291,13 @@ void BatteryMonitor::updateValues(void) {
mHealthInfo->batteryCapacityLevel = getBatteryCapacityLevel(buf.c_str());
if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
- mHealthInfo->batteryStatus = getBatteryStatus(buf.c_str());
+ props.batteryStatus = getBatteryStatus(buf.c_str());
if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
- mHealthInfo->batteryHealth = getBatteryHealth(buf.c_str());
+ props.batteryHealth = getBatteryHealth(buf.c_str());
if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
- mHealthInfo->batteryTechnology = String8(buf.c_str());
+ props.batteryTechnology = String8(buf.c_str());
double MaxPower = 0;
@@ -366,26 +311,17 @@ void BatteryMonitor::updateValues(void) {
mChargerNames[i].string());
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
- mHealthInfo->chargerAcOnline = true;
+ props.chargerAcOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_USB:
- mHealthInfo->chargerUsbOnline = true;
+ props.chargerUsbOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
- mHealthInfo->chargerWirelessOnline = true;
- break;
- case ANDROID_POWER_SUPPLY_TYPE_DOCK:
- mHealthInfo->chargerDockOnline = true;
+ props.chargerWirelessOnline = true;
break;
default:
- path.clear();
- path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- if (access(path.string(), R_OK) == 0)
- mHealthInfo->chargerDockOnline = true;
- else
- KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
- mChargerNames[i].string());
+ KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
+ mChargerNames[i].string());
}
path.clear();
path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
@@ -404,34 +340,38 @@ void BatteryMonitor::updateValues(void) {
double power = ((double)ChargingCurrent / MILLION) *
((double)ChargingVoltage / MILLION);
if (MaxPower < power) {
- mHealthInfo->maxChargingCurrentMicroamps = ChargingCurrent;
- mHealthInfo->maxChargingVoltageMicrovolts = ChargingVoltage;
+ props.maxChargingCurrent = ChargingCurrent;
+ props.maxChargingVoltage = ChargingVoltage;
MaxPower = power;
}
}
}
}
-static void doLogValues(const HealthInfo& props, const struct healthd_config& healthd_config) {
+void BatteryMonitor::logValues(void) {
+ logValues(*mHealthInfo, *mHealthdConfig);
+}
+
+void BatteryMonitor::logValues(const android::hardware::health::V2_1::HealthInfo& health_info,
+ const struct healthd_config& healthd_config) {
char dmesgline[256];
size_t len;
+ const HealthInfo_1_0& props = health_info.legacy.legacy;
if (props.batteryPresent) {
snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
- props.batteryLevel, props.batteryVoltageMillivolts,
- props.batteryTemperatureTenthsCelsius < 0 ? "-" : "",
- abs(props.batteryTemperatureTenthsCelsius / 10),
- abs(props.batteryTemperatureTenthsCelsius % 10), props.batteryHealth,
- props.batteryStatus);
+ props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "",
+ abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10),
+ props.batteryHealth, props.batteryStatus);
len = strlen(dmesgline);
if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
- props.batteryCurrentMicroamps);
+ props.batteryCurrent);
}
if (!healthd_config.batteryFullChargePath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
- props.batteryFullChargeUah);
+ props.batteryFullCharge);
}
if (!healthd_config.batteryCycleCountPath.isEmpty()) {
@@ -442,28 +382,17 @@ static void doLogValues(const HealthInfo& props, const struct healthd_config& he
len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
}
- snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s%s",
+ snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
- props.chargerWirelessOnline ? "w" : "", props.chargerDockOnline ? "d" : "");
+ props.chargerWirelessOnline ? "w" : "");
KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
}
-void BatteryMonitor::logValues(const HealthInfo_2_1& health_info,
- const struct healthd_config& healthd_config) {
- HealthInfo aidl_health_info;
- (void)android::h2a::translate(health_info, &aidl_health_info);
- doLogValues(aidl_health_info, healthd_config);
-}
-
-void BatteryMonitor::logValues(void) {
- doLogValues(*mHealthInfo, *mHealthdConfig);
-}
-
bool BatteryMonitor::isChargerOnline() {
- const HealthInfo& props = *mHealthInfo;
- return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline |
- props.chargerDockOnline;
+ const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
+ return props.chargerAcOnline | props.chargerUsbOnline |
+ props.chargerWirelessOnline;
}
int BatteryMonitor::getChargeStatus() {
@@ -546,19 +475,19 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
void BatteryMonitor::dumpState(int fd) {
int v;
char vs[128];
- const HealthInfo& props = *mHealthInfo;
+ const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
- snprintf(vs, sizeof(vs),
- "ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
- props.chargerAcOnline, props.chargerUsbOnline, props.chargerWirelessOnline,
- props.chargerDockOnline, props.maxChargingCurrentMicroamps,
- props.maxChargingVoltageMicrovolts);
+ snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
+ props.chargerAcOnline, props.chargerUsbOnline,
+ props.chargerWirelessOnline, props.maxChargingCurrent,
+ props.maxChargingVoltage);
write(fd, vs, strlen(vs));
snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
props.batteryStatus, props.batteryHealth, props.batteryPresent);
write(fd, vs, strlen(vs));
- snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n", props.batteryLevel,
- props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
+ snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
+ props.batteryLevel, props.batteryVoltage,
+ props.batteryTemperature);
write(fd, vs, strlen(vs));
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
@@ -580,7 +509,7 @@ void BatteryMonitor::dumpState(int fd) {
}
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
- snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps);
+ snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent);
write(fd, vs, strlen(vs));
}
@@ -590,7 +519,7 @@ void BatteryMonitor::dumpState(int fd) {
}
if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
- snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah);
+ snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge);
write(fd, vs, strlen(vs));
}
}
@@ -608,13 +537,13 @@ void BatteryMonitor::init(struct healthd_config *hc) {
while ((entry = readdir(dir.get()))) {
const char* name = entry->d_name;
+ std::vector<String8>::iterator itIgnoreName;
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
- std::vector<String8>::iterator itIgnoreName =
- find(hc->ignorePowerSupplyNames.begin(), hc->ignorePowerSupplyNames.end(),
- String8(name));
+ itIgnoreName = find(hc->ignorePowerSupplyNames.begin(),
+ hc->ignorePowerSupplyNames.end(), String8(name));
if (itIgnoreName != hc->ignorePowerSupplyNames.end())
continue;
@@ -625,7 +554,6 @@ void BatteryMonitor::init(struct healthd_config *hc) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
case ANDROID_POWER_SUPPLY_TYPE_USB:
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
- case ANDROID_POWER_SUPPLY_TYPE_DOCK:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
if (access(path.string(), R_OK) == 0)
@@ -763,17 +691,6 @@ void BatteryMonitor::init(struct healthd_config *hc) {
case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
break;
}
-
- // Look for "is_dock" file
- path.clear();
- path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0) {
- path.clear();
- path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path.string(), R_OK) == 0)
- mChargerNames.add(String8(name));
-
- }
}
}
diff --git a/healthd/OWNERS b/healthd/OWNERS
index e64c33d1a..d3f875809 100644
--- a/healthd/OWNERS
+++ b/healthd/OWNERS
@@ -1 +1,2 @@
elsk@google.com
+hridya@google.com
diff --git a/healthd/TEST_MAPPING b/healthd/TEST_MAPPING
index 17e363d46..5893d10c7 100644
--- a/healthd/TEST_MAPPING
+++ b/healthd/TEST_MAPPING
@@ -3,10 +3,5 @@
{
"name": "libhealthd_charger_test"
}
- ],
- "hwasan-postsubmit": [
- {
- "name": "libhealthd_charger_test"
- }
]
}
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
index 73e04fe78..d03978d4f 100644
--- a/healthd/charger.cpp
+++ b/healthd/charger.cpp
@@ -15,9 +15,9 @@
*/
#include <android-base/logging.h>
-#include <charger.sysprop.h>
-#include "healthd_mode_charger_hidl.h"
+#include "charger.sysprop.h"
+#include "healthd_mode_charger.h"
#include "healthd_mode_charger_nops.h"
#ifndef CHARGER_FORCE_NO_UI
diff --git a/healthd/charger_test.cpp b/healthd/charger_test.cpp
index dc5c459d7..e0bde681b 100644
--- a/healthd/charger_test.cpp
+++ b/healthd/charger_test.cpp
@@ -31,7 +31,7 @@
#include <health/utils.h>
#include <health2impl/Health.h>
-#include "healthd_mode_charger_hidl.h"
+#include "healthd_mode_charger.h"
using android::hardware::health::InitHealthdConfig;
using android::hardware::health::V2_1::HealthInfo;
@@ -153,7 +153,7 @@ int main(int /*argc*/, char** /*argv*/) {
sp<IHealth> passthrough = new TestHealth(std::move(config));
std::thread bgThread([=] {
- android::ChargerHidl charger(passthrough);
+ android::Charger charger(passthrough);
charger.StartLoop();
});
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
index 3e73fcd08..50eee198f 100644
--- a/healthd/healthd_draw.cpp
+++ b/healthd/healthd_draw.cpp
@@ -18,30 +18,19 @@
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
-#include "healthd_draw.h"
-
-#if !defined(__ANDROID_VNDK__)
#include "charger.sysprop.h"
-#endif
+#include "healthd_draw.h"
#define LOGE(x...) KLOG_ERROR("charger", x);
#define LOGW(x...) KLOG_WARNING("charger", x);
#define LOGV(x...) KLOG_DEBUG("charger", x);
static bool get_split_screen() {
-#if !defined(__ANDROID_VNDK__)
return android::sysprop::ChargerProperties::draw_split_screen().value_or(false);
-#else
- return false;
-#endif
}
static int get_split_offset() {
-#if !defined(__ANDROID_VNDK__)
int64_t value = android::sysprop::ChargerProperties::draw_split_offset().value_or(0);
-#else
- int64_t value = 0;
-#endif
if (value < static_cast<int64_t>(std::numeric_limits<int>::min())) {
LOGW("draw_split_offset = %" PRId64 " overflow for an int; resetting to %d.\n", value,
std::numeric_limits<int>::min());
@@ -57,6 +46,14 @@ static int get_split_offset() {
HealthdDraw::HealthdDraw(animation* anim)
: kSplitScreen(get_split_screen()), kSplitOffset(get_split_offset()) {
+ int ret = gr_init();
+
+ if (ret < 0) {
+ LOGE("gr_init failed\n");
+ graphics_available = false;
+ return;
+ }
+
graphics_available = true;
sys_font = gr_sys_font();
if (sys_font == nullptr) {
@@ -94,18 +91,9 @@ void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unkn
gr_flip();
}
-void HealthdDraw::blank_screen(bool blank, int drm) {
+void HealthdDraw::blank_screen(bool blank) {
if (!graphics_available) return;
- gr_fb_blank(blank, drm);
-}
-
-/* support screen rotation for foldable phone */
-void HealthdDraw::rotate_screen(int drm) {
- if (!graphics_available) return;
- if (drm == 0)
- gr_rotate(GRRotation::RIGHT /* landscape mode */);
- else
- gr_rotate(GRRotation::NONE /* Portrait mode */);
+ gr_fb_blank(blank);
}
void HealthdDraw::clear_screen(void) {
@@ -148,8 +136,6 @@ int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) {
void HealthdDraw::determine_xy(const animation::text_field& field,
const int length, int* x, int* y) {
*x = field.pos_x;
- screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1);
- screen_height_ = gr_fb_height();
int str_len_px = length * field.font->char_width;
if (field.pos_x == CENTER_VAL) {
@@ -249,11 +235,3 @@ void HealthdDraw::draw_unknown(GRSurface* surf_unknown) {
LOGW("Charging, level unknown\n");
}
}
-
-std::unique_ptr<HealthdDraw> HealthdDraw::Create(animation *anim) {
- if (gr_init() < 0) {
- LOGE("gr_init failed\n");
- return nullptr;
- }
- return std::unique_ptr<HealthdDraw>(new HealthdDraw(anim));
-}
diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h
index 3d4abbdda..7c847bdbf 100644
--- a/healthd/healthd_draw.h
+++ b/healthd/healthd_draw.h
@@ -26,19 +26,15 @@ using namespace android;
class HealthdDraw {
public:
+ // Configures font using given animation.
+ HealthdDraw(animation* anim);
virtual ~HealthdDraw();
// Redraws screen.
void redraw_screen(const animation* batt_anim, GRSurface* surf_unknown);
- // According to the index of Direct Rendering Manager,
// Blanks screen if true, unblanks if false.
- virtual void blank_screen(bool blank, int drm);
-
- // Rotate screen.
- virtual void rotate_screen(int drm);
-
- static std::unique_ptr<HealthdDraw> Create(animation *anim);
+ virtual void blank_screen(bool blank);
protected:
virtual void clear_screen();
@@ -80,10 +76,6 @@ class HealthdDraw {
// true if minui init'ed OK, false if minui init failed
bool graphics_available;
-
- private:
- // Configures font using given animation.
- HealthdDraw(animation* anim);
};
#endif // HEALTHD_DRAW_H
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 9fe85d40d..e95efc04c 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <charger/healthd_mode_charger.h>
+#include "healthd_mode_charger.h"
#include <dirent.h>
#include <errno.h>
@@ -50,20 +50,27 @@
#include <suspend/autosuspend.h>
#include "AnimationParser.h"
+#include "charger.sysprop.h"
+#include "charger_utils.h"
#include "healthd_draw.h"
-#include <aidl/android/hardware/health/BatteryStatus.h>
-#include <health/HealthLoop.h>
+#include <android/hardware/health/2.0/IHealthInfoCallback.h>
+#include <health/utils.h>
+#include <health2impl/HalHealthLoop.h>
+#include <health2impl/Health.h>
#include <healthd/healthd.h>
-#if !defined(__ANDROID_VNDK__)
-#include "charger.sysprop.h"
-#endif
-
using std::string_literals::operator""s;
using namespace android;
-using aidl::android::hardware::health::BatteryStatus;
+using android::hardware::Return;
+using android::hardware::health::GetHealthServiceOrDefault;
using android::hardware::health::HealthLoop;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_1::IHealth;
+using IHealth_2_0 = android::hardware::health::V2_0::IHealth;
+using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
+using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
// main healthd loop
extern int healthd_main(void);
@@ -99,13 +106,6 @@ char* locale;
namespace android {
-#if defined(__ANDROID_VNDK__)
-static constexpr const char* vendor_animation_desc_path =
- "/vendor/etc/res/values/charger/animation.txt";
-static constexpr const char* vendor_animation_root = "/vendor/etc/res/images/";
-static constexpr const char* vendor_default_animation_root = "/vendor/etc/res/images/default/";
-#else
-
// Legacy animation resources are loaded from this directory.
static constexpr const char* legacy_animation_root = "/res/images/";
@@ -119,7 +119,6 @@ static constexpr const char* product_animation_desc_path =
"/product/etc/res/values/charger/animation.txt";
static constexpr const char* product_animation_root = "/product/etc/res/images/";
static constexpr const char* animation_desc_path = "/res/values/charger/animation.txt";
-#endif
static const animation BASE_ANIMATION = {
.text_clock =
@@ -200,8 +199,8 @@ void Charger::InitDefaultAnimationFrames() {
};
}
-Charger::Charger(ChargerConfigurationInterface* configuration)
- : batt_anim_(BASE_ANIMATION), configuration_(configuration) {}
+Charger::Charger(const sp<IHealth>& service)
+ : HalHealthLoop("charger", service), batt_anim_(BASE_ANIMATION) {}
Charger::~Charger() {}
@@ -219,7 +218,9 @@ static void dump_last_kmsg(void) {
char* ptr;
size_t len;
+ LOGW("\n");
LOGW("*************** LAST KMSG ***************\n");
+ LOGW("\n");
const char* kmsg[] = {
// clang-format off
"/sys/fs/pstore/console-ramoops-0",
@@ -262,21 +263,20 @@ static void dump_last_kmsg(void) {
}
out:
+ LOGW("\n");
LOGW("************* END LAST KMSG *************\n");
+ LOGW("\n");
}
-int Charger::RequestEnableSuspend() {
- if (!configuration_->ChargerEnableSuspend()) {
+static int request_suspend(bool enable) {
+ if (!android::sysprop::ChargerProperties::enable_suspend().value_or(false)) {
return 0;
}
- return autosuspend_enable();
-}
-int Charger::RequestDisableSuspend() {
- if (!configuration_->ChargerEnableSuspend()) {
- return 0;
- }
- return autosuspend_disable();
+ if (enable)
+ return autosuspend_enable();
+ else
+ return autosuspend_disable();
}
static void kick_animation(animation* anim) {
@@ -295,7 +295,7 @@ void Charger::UpdateScreenState(int64_t now) {
if (!batt_anim_.run || now < next_screen_transition_) return;
// If battery level is not ready, keep checking in the defined time
- if (health_info_.battery_level == 0 && health_info_.battery_status == BatteryStatus::UNKNOWN) {
+ if (health_info_.batteryLevel == 0 && health_info_.batteryStatus == BatteryStatus::UNKNOWN) {
if (wait_batt_level_timestamp_ == 0) {
// Set max delay time and skip drawing screen
wait_batt_level_timestamp_ = now + MAX_BATT_LEVEL_WAIT_TIME;
@@ -309,65 +309,54 @@ void Charger::UpdateScreenState(int64_t now) {
}
if (healthd_draw_ == nullptr) {
- std::optional<bool> out_screen_on = configuration_->ChargerShouldKeepScreenOn();
+ std::optional<bool> out_screen_on;
+ service()->shouldKeepScreenOn([&](Result res, bool screen_on) {
+ if (res == Result::SUCCESS) {
+ *out_screen_on = screen_on;
+ }
+ });
if (out_screen_on.has_value()) {
if (!*out_screen_on) {
LOGV("[%" PRId64 "] leave screen off\n", now);
batt_anim_.run = false;
next_screen_transition_ = -1;
- if (configuration_->ChargerIsOnline()) {
- RequestEnableSuspend();
- }
+ if (charger_online()) request_suspend(true);
return;
}
}
- healthd_draw_ = HealthdDraw::Create(&batt_anim_);
- if (healthd_draw_ == nullptr) return;
+ healthd_draw_.reset(new HealthdDraw(&batt_anim_));
-#if !defined(__ANDROID_VNDK__)
if (android::sysprop::ChargerProperties::disable_init_blank().value_or(false)) {
- healthd_draw_->blank_screen(true, static_cast<int>(drm_));
+ healthd_draw_->blank_screen(true);
screen_blanked_ = true;
}
-#endif
}
/* animation is over, blank screen and leave */
if (batt_anim_.num_cycles > 0 && batt_anim_.cur_cycle == batt_anim_.num_cycles) {
reset_animation(&batt_anim_);
next_screen_transition_ = -1;
- healthd_draw_->blank_screen(true, static_cast<int>(drm_));
+ healthd_draw_->blank_screen(true);
screen_blanked_ = true;
LOGV("[%" PRId64 "] animation done\n", now);
- if (configuration_->ChargerIsOnline()) {
- RequestEnableSuspend();
- }
+ if (charger_online()) request_suspend(true);
return;
}
disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time;
- /* turn off all screen */
- if (screen_switch_ == SCREEN_SWITCH_ENABLE) {
- healthd_draw_->blank_screen(true, 0 /* drm */);
- healthd_draw_->blank_screen(true, 1 /* drm */);
- healthd_draw_->rotate_screen(static_cast<int>(drm_));
- screen_blanked_ = true;
- screen_switch_ = SCREEN_SWITCH_DISABLE;
- }
-
if (screen_blanked_) {
- healthd_draw_->blank_screen(false, static_cast<int>(drm_));
+ healthd_draw_->blank_screen(false);
screen_blanked_ = false;
}
/* animation starting, set up the animation */
if (batt_anim_.cur_frame == 0) {
LOGV("[%" PRId64 "] animation starting\n", now);
- batt_anim_.cur_level = health_info_.battery_level;
- batt_anim_.cur_status = (int)health_info_.battery_status;
- if (health_info_.battery_level >= 0 && batt_anim_.num_frames != 0) {
+ batt_anim_.cur_level = health_info_.batteryLevel;
+ batt_anim_.cur_status = (int)health_info_.batteryStatus;
+ if (health_info_.batteryLevel >= 0 && batt_anim_.num_frames != 0) {
/* find first frame given current battery level */
for (int i = 0; i < batt_anim_.num_frames; i++) {
if (batt_anim_.cur_level >= batt_anim_.frames[i].min_level &&
@@ -377,7 +366,7 @@ void Charger::UpdateScreenState(int64_t now) {
}
}
- if (configuration_->ChargerIsOnline()) {
+ if (charger_online()) {
// repeat the first frame first_frame_repeats times
disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time *
batt_anim_.first_frame_repeats;
@@ -408,7 +397,7 @@ void Charger::UpdateScreenState(int64_t now) {
/* advance frame cntr to the next valid frame only if we are charging
* if necessary, advance cycle cntr, and reset frame cntr
*/
- if (configuration_->ChargerIsOnline()) {
+ if (charger_online()) {
batt_anim_.cur_frame++;
while (batt_anim_.cur_frame < batt_anim_.num_frames &&
@@ -461,26 +450,7 @@ int Charger::SetKeyCallback(int code, int value) {
return 0;
}
-int Charger::SetSwCallback(int code, int value) {
- if (code > SW_MAX) return -1;
- if (code == SW_LID) {
- if ((screen_switch_ == SCREEN_SWITCH_DEFAULT) || ((value != 0) && (drm_ == DRM_INNER)) ||
- ((value == 0) && (drm_ == DRM_OUTER))) {
- screen_switch_ = SCREEN_SWITCH_ENABLE;
- drm_ = (value != 0) ? DRM_OUTER : DRM_INNER;
- keys_[code].pending = true;
- }
- }
-
- return 0;
-}
-
void Charger::UpdateInputState(input_event* ev) {
- if (ev->type == EV_SW && ev->code == SW_LID) {
- SetSwCallback(ev->code, ev->value);
- return;
- }
-
if (ev->type != EV_KEY) return;
SetKeyCallback(ev->code, ev->value);
}
@@ -525,13 +495,13 @@ void Charger::ProcessKey(int code, int64_t now) {
* rather than on key release
*/
kick_animation(&batt_anim_);
- RequestDisableSuspend();
+ request_suspend(false);
}
} else {
/* if the power key got released, force screen state cycle */
if (key->pending) {
kick_animation(&batt_anim_);
- RequestDisableSuspend();
+ request_suspend(false);
}
}
}
@@ -539,34 +509,18 @@ void Charger::ProcessKey(int code, int64_t now) {
key->pending = false;
}
-void Charger::ProcessHallSensor(int code) {
- key_state* key = &keys_[code];
-
- if (code == SW_LID) {
- if (key->pending) {
- reset_animation(&batt_anim_);
- kick_animation(&batt_anim_);
- RequestDisableSuspend();
- }
- }
-
- key->pending = false;
-}
-
void Charger::HandleInputState(int64_t now) {
ProcessKey(KEY_POWER, now);
if (next_key_check_ != -1 && now > next_key_check_) next_key_check_ = -1;
-
- ProcessHallSensor(SW_LID);
}
void Charger::HandlePowerSupplyState(int64_t now) {
int timer_shutdown = UNPLUGGED_SHUTDOWN_TIME;
if (!have_battery_state_) return;
- if (!configuration_->ChargerIsOnline()) {
- RequestDisableSuspend();
+ if (!charger_online()) {
+ request_suspend(false);
if (next_pwr_check_ == -1) {
/* Last cycle would have stopped at the extreme top of battery-icon
* Need to show the correct level corresponding to capacity.
@@ -596,7 +550,7 @@ void Charger::HandlePowerSupplyState(int64_t now) {
* Reset & kick animation to show complete animation cycles
* when charger connected again.
*/
- RequestDisableSuspend();
+ request_suspend(false);
next_screen_transition_ = now - 1;
reset_animation(&batt_anim_);
kick_animation(&batt_anim_);
@@ -606,7 +560,7 @@ void Charger::HandlePowerSupplyState(int64_t now) {
}
}
-void Charger::OnHeartbeat() {
+void Charger::Heartbeat() {
// charger* charger = &charger_state;
int64_t now = curr_time_ms();
@@ -619,18 +573,22 @@ void Charger::OnHeartbeat() {
UpdateScreenState(now);
}
-void Charger::OnHealthInfoChanged(const ChargerHealthInfo& health_info) {
+void Charger::OnHealthInfoChanged(const HealthInfo_2_1& health_info) {
+ set_charger_online(health_info);
+
if (!have_battery_state_) {
have_battery_state_ = true;
next_screen_transition_ = curr_time_ms() - 1;
- RequestDisableSuspend();
+ request_suspend(false);
reset_animation(&batt_anim_);
kick_animation(&batt_anim_);
}
- health_info_ = health_info;
+ health_info_ = health_info.legacy.legacy;
+
+ AdjustWakealarmPeriods(charger_online());
}
-int Charger::OnPrepareToWait(void) {
+int Charger::PrepareToWait(void) {
int64_t now = curr_time_ms();
int64_t next_event = INT64_MAX;
int64_t timeout;
@@ -671,16 +629,6 @@ void Charger::InitAnimation() {
bool parse_success;
std::string content;
-
-#if defined(__ANDROID_VNDK__)
- if (base::ReadFileToString(vendor_animation_desc_path, &content)) {
- parse_success = parse_animation_desc(content, &batt_anim_);
- batt_anim_.set_resource_root(vendor_animation_root);
- } else {
- LOGW("Could not open animation description at %s\n", vendor_animation_desc_path);
- parse_success = false;
- }
-#else
if (base::ReadFileToString(product_animation_desc_path, &content)) {
parse_success = parse_animation_desc(content, &batt_anim_);
batt_anim_.set_resource_root(product_animation_root);
@@ -696,26 +644,17 @@ void Charger::InitAnimation() {
LOGW("Could not open animation description at %s\n", animation_desc_path);
parse_success = false;
}
-#endif
-
-#if defined(__ANDROID_VNDK__)
- auto default_animation_root = vendor_default_animation_root;
-#else
- auto default_animation_root = system_animation_root;
-#endif
if (!parse_success) {
- LOGW("Could not parse animation description. "
- "Using default animation with resources at %s\n",
- default_animation_root);
+ LOGW("Could not parse animation description. Using default animation.\n");
batt_anim_ = BASE_ANIMATION;
- batt_anim_.animation_file.assign(default_animation_root + "charger/battery_scale.png"s);
+ batt_anim_.animation_file.assign(system_animation_root + "charger/battery_scale.png"s);
InitDefaultAnimationFrames();
batt_anim_.frames = owned_frames_.data();
batt_anim_.num_frames = owned_frames_.size();
}
if (batt_anim_.fail_file.empty()) {
- batt_anim_.fail_file.assign(default_animation_root + "charger/battery_fail.png"s);
+ batt_anim_.fail_file.assign(system_animation_root + "charger/battery_fail.png"s);
}
LOGV("Animation Description:\n");
@@ -736,7 +675,7 @@ void Charger::InitAnimation() {
}
}
-void Charger::OnInit(struct healthd_config* config) {
+void Charger::Init(struct healthd_config* config) {
int ret;
int i;
int epollfd;
@@ -749,18 +688,16 @@ void Charger::OnInit(struct healthd_config* config) {
std::bind(&Charger::InputCallback, this, std::placeholders::_1, std::placeholders::_2));
if (!ret) {
epollfd = ev_get_epollfd();
- configuration_->ChargerRegisterEvent(epollfd, &charger_event_handler, EVENT_WAKEUP_FD);
+ RegisterEvent(epollfd, &charger_event_handler, EVENT_WAKEUP_FD);
}
InitAnimation();
ret = CreateDisplaySurface(batt_anim_.fail_file, &surf_unknown_);
if (ret < 0) {
-#if !defined(__ANDROID_VNDK__)
LOGE("Cannot load custom battery_fail image. Reverting to built in: %d\n", ret);
ret = CreateDisplaySurface((system_animation_root + "charger/battery_fail.png"s).c_str(),
&surf_unknown_);
-#endif
if (ret < 0) {
LOGE("Cannot load built in battery_fail image\n");
surf_unknown_ = NULL;
@@ -787,21 +724,16 @@ void Charger::OnInit(struct healthd_config* config) {
batt_anim_.frames[i].surface = scale_frames[i];
}
}
- drm_ = DRM_INNER;
- screen_switch_ = SCREEN_SWITCH_DEFAULT;
ev_sync_key_state(std::bind(&Charger::SetKeyCallback, this, std::placeholders::_1,
std::placeholders::_2));
- (void)ev_sync_sw_state(
- std::bind(&Charger::SetSwCallback, this, std::placeholders::_1, std::placeholders::_2));
-
next_screen_transition_ = -1;
next_key_check_ = -1;
next_pwr_check_ = -1;
wait_batt_level_timestamp_ = 0;
// Retrieve healthd_config from the existing health HAL.
- configuration_->ChargerInitConfig(config);
+ HalHealthLoop::Init(config);
boot_min_cap_ = config->boot_min_cap;
}
@@ -844,3 +776,25 @@ void animation::set_resource_root(const std::string& root, const std::string& ba
}
} // namespace android
+
+int healthd_charger_main(int argc, char** argv) {
+ int ch;
+
+ while ((ch = getopt(argc, argv, "cr")) != -1) {
+ switch (ch) {
+ case 'c':
+ // -c is now a noop
+ break;
+ case 'r':
+ // -r is now a noop
+ break;
+ case '?':
+ default:
+ LOGE("Unrecognized charger option: %c\n", optopt);
+ exit(1);
+ }
+ }
+
+ Charger charger(GetHealthServiceOrDefault());
+ return charger.StartLoop();
+}
diff --git a/healthd/include_charger/charger/healthd_mode_charger.h b/healthd/healthd_mode_charger.h
index 28e1fb531..6f9ae8c0e 100644
--- a/healthd/include_charger/charger/healthd_mode_charger.h
+++ b/healthd/healthd_mode_charger.h
@@ -19,12 +19,11 @@
#include <linux/input.h>
#include <memory>
-#include <optional>
#include <vector>
-#include <aidl/android/hardware/health/BatteryStatus.h>
-#include <health/HealthLoop.h>
-#include <healthd/healthd.h>
+#include <android/hardware/health/2.0/IHealthInfoCallback.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <health2impl/HalHealthLoop.h>
#include "animation.h"
@@ -38,55 +37,22 @@ struct key_state {
int64_t timestamp;
};
-// Health info that interests charger
-struct ChargerHealthInfo {
- int32_t battery_level;
- aidl::android::hardware::health::BatteryStatus battery_status;
-};
-
-enum DirectRenderManager {
- DRM_INNER,
- DRM_OUTER,
-};
-
-enum SrceenSwitch {
- SCREEN_SWITCH_DEFAULT,
- SCREEN_SWITCH_DISABLE,
- SCREEN_SWITCH_ENABLE,
-};
-
-// Configuration interface for charger. This includes:
-// - HalHealthLoop APIs that interests charger.
-// - configuration values that used to be provided by sysprops
-class ChargerConfigurationInterface {
+class Charger : public ::android::hardware::health::V2_1::implementation::HalHealthLoop {
public:
- virtual ~ChargerConfigurationInterface() = default;
- // HalHealthLoop related APIs
- virtual std::optional<bool> ChargerShouldKeepScreenOn() = 0;
- virtual bool ChargerIsOnline() = 0;
- virtual void ChargerInitConfig(healthd_config* config) = 0;
- using BoundFunction =
- std::function<void(android::hardware::health::HealthLoop*, uint32_t /* epevents */)>;
- virtual int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) = 0;
-
- // Other configuration values
- virtual bool ChargerEnableSuspend() = 0;
-};
+ using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
+ using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
-// charger UI
-class Charger {
- public:
- explicit Charger(ChargerConfigurationInterface* configuration);
- virtual ~Charger();
-
- // Hooks for ChargerConfigurationInterface
- void OnHeartbeat();
- int OnPrepareToWait();
- // |cookie| is passed to ChargerConfigurationInterface::ChargerInitConfig
- void OnInit(struct healthd_config* config);
- void OnHealthInfoChanged(const ChargerHealthInfo& health_info);
+ Charger(const sp<android::hardware::health::V2_1::IHealth>& service);
+ ~Charger();
protected:
+ // HealthLoop overrides.
+ void Heartbeat() override;
+ int PrepareToWait() override;
+ void Init(struct healthd_config* config) override;
+ // HalHealthLoop overrides
+ void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
+
// Allowed to be mocked for testing.
virtual int CreateDisplaySurface(const std::string& name, GRSurface** surface);
virtual int CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
@@ -96,17 +62,13 @@ class Charger {
void InitDefaultAnimationFrames();
void UpdateScreenState(int64_t now);
int SetKeyCallback(int code, int value);
- int SetSwCallback(int code, int value);
void UpdateInputState(input_event* ev);
void SetNextKeyCheck(key_state* key, int64_t timeout);
void ProcessKey(int code, int64_t now);
- void ProcessHallSensor(int code);
void HandleInputState(int64_t now);
void HandlePowerSupplyState(int64_t now);
int InputCallback(int fd, unsigned int epevents);
void InitAnimation();
- int RequestEnableSuspend();
- int RequestDisableSuspend();
bool have_battery_state_ = false;
bool screen_blanked_ = false;
@@ -115,19 +77,16 @@ class Charger {
int64_t next_pwr_check_ = 0;
int64_t wait_batt_level_timestamp_ = 0;
- DirectRenderManager drm_;
- SrceenSwitch screen_switch_;
-
key_state keys_[KEY_MAX + 1] = {};
animation batt_anim_;
GRSurface* surf_unknown_ = nullptr;
int boot_min_cap_ = 0;
- ChargerHealthInfo health_info_ = {};
+ HealthInfo_1_0 health_info_ = {};
std::unique_ptr<HealthdDraw> healthd_draw_;
std::vector<animation::frame> owned_frames_;
-
- ChargerConfigurationInterface* configuration_;
};
} // namespace android
+
+int healthd_charger_main(int argc, char** argv);
diff --git a/healthd/healthd_mode_charger_hidl.cpp b/healthd/healthd_mode_charger_hidl.cpp
deleted file mode 100644
index 3a33c02c5..000000000
--- a/healthd/healthd_mode_charger_hidl.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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 "healthd_mode_charger_hidl.h"
-
-#include <android/hardware/health/2.0/types.h>
-#include <charger.sysprop.h>
-#include <cutils/klog.h>
-
-#include "charger_utils.h"
-
-using android::hardware::health::GetHealthServiceOrDefault;
-using android::hardware::health::V2_0::Result;
-
-namespace android {
-
-ChargerHidl::ChargerHidl(const sp<android::hardware::health::V2_1::IHealth>& service)
- : HalHealthLoop("charger", service), charger_(std::make_unique<Charger>(this)) {}
-
-void ChargerHidl::OnHealthInfoChanged(const HealthInfo_2_1& health_info) {
- set_charger_online(health_info);
-
- charger_->OnHealthInfoChanged(ChargerHealthInfo{
- .battery_level = health_info.legacy.legacy.batteryLevel,
- .battery_status = static_cast<::aidl::android::hardware::health::BatteryStatus>(
- health_info.legacy.legacy.batteryStatus),
- });
-
- AdjustWakealarmPeriods(charger_online());
-}
-
-std::optional<bool> ChargerHidl::ChargerShouldKeepScreenOn() {
- std::optional<bool> out_screen_on;
- service()->shouldKeepScreenOn([&](Result res, bool screen_on) {
- if (res == Result::SUCCESS) {
- *out_screen_on = screen_on;
- }
- });
- return out_screen_on;
-}
-
-bool ChargerHidl::ChargerEnableSuspend() {
- return android::sysprop::ChargerProperties::enable_suspend().value_or(false);
-}
-
-} // namespace android
-
-int healthd_charger_main(int argc, char** argv) {
- int ch;
-
- while ((ch = getopt(argc, argv, "cr")) != -1) {
- switch (ch) {
- case 'c':
- // -c is now a noop
- break;
- case 'r':
- // -r is now a noop
- break;
- case '?':
- default:
- KLOG_ERROR("charger", "Unrecognized charger option: %c\n", optopt);
- exit(1);
- }
- }
-
- android::ChargerHidl charger(GetHealthServiceOrDefault());
- return charger.StartLoop();
-}
diff --git a/healthd/healthd_mode_charger_hidl.h b/healthd/healthd_mode_charger_hidl.h
deleted file mode 100644
index 0149d0713..000000000
--- a/healthd/healthd_mode_charger_hidl.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <health2impl/HalHealthLoop.h>
-
-#include <charger/healthd_mode_charger.h>
-
-namespace android {
-
-// An implementation of Charger backed by HIDL implementation. Uses HIDL health
-// HAL's HalHealthLoop.
-class ChargerHidl : public ::android::ChargerConfigurationInterface,
- public ::android::hardware::health::V2_1::implementation::HalHealthLoop {
- using HalHealthLoop = ::android::hardware::health::V2_1::implementation::HalHealthLoop;
- using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
-
- public:
- explicit ChargerHidl(const sp<android::hardware::health::V2_1::IHealth>& service);
- std::optional<bool> ChargerShouldKeepScreenOn() override;
- bool ChargerIsOnline() override { return HalHealthLoop::charger_online(); }
- void ChargerInitConfig(healthd_config* config) override { return HalHealthLoop::Init(config); }
- int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) override {
- return HalHealthLoop::RegisterEvent(fd, func, wakeup);
- }
- bool ChargerEnableSuspend() override;
- // HealthLoop overrides
- void Heartbeat() override { charger_->OnHeartbeat(); }
- int PrepareToWait() override { return charger_->OnPrepareToWait(); }
- void Init(struct healthd_config* config) override { charger_->OnInit(config); }
- // HalHealthLoop overrides
- void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
-
- private:
- sp<android::hardware::health::V2_1::IHealth> service_;
- std::unique_ptr<Charger> charger_;
-};
-
-} // namespace android
-
-int healthd_charger_main(int argc, char** argv);
diff --git a/healthd/healthd_mode_charger_test.cpp b/healthd/healthd_mode_charger_test.cpp
index b7aace302..f444f66ad 100644
--- a/healthd/healthd_mode_charger_test.cpp
+++ b/healthd/healthd_mode_charger_test.cpp
@@ -23,12 +23,11 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
-#include <android/hardware/health/2.1/IHealth.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <health/utils.h>
-#include "healthd_mode_charger_hidl.h"
+#include "healthd_mode_charger.h"
using android::hardware::Return;
using android::hardware::health::InitHealthdConfig;
@@ -103,12 +102,12 @@ class MockHealth : public android::hardware::health::V2_1::IHealth {
MOCK_METHOD(Return<void>, shouldKeepScreenOn, (shouldKeepScreenOn_cb _hidl_cb));
};
-class TestCharger : public ChargerHidl {
+class TestCharger : public Charger {
public:
// Inherit constructor.
- using ChargerHidl::ChargerHidl;
+ using Charger::Charger;
// Expose protected functions to be used in tests.
- void Init(struct healthd_config* config) override { ChargerHidl::Init(config); }
+ void Init(struct healthd_config* config) override { Charger::Init(config); }
MOCK_METHOD(int, CreateDisplaySurface, (const std::string& name, GRSurface** surface));
MOCK_METHOD(int, CreateMultiDisplaySurface,
(const std::string& name, int* frames, int* fps, GRSurface*** surface));
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 8cbf5ead6..3cda727be 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -25,10 +25,6 @@
#include <healthd/healthd.h>
-namespace aidl::android::hardware::health {
-class HealthInfo;
-} // namespace aidl::android::hardware::health
-
namespace android {
namespace hardware {
namespace health {
@@ -52,8 +48,7 @@ class BatteryMonitor {
ANDROID_POWER_SUPPLY_TYPE_AC,
ANDROID_POWER_SUPPLY_TYPE_USB,
ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
- ANDROID_POWER_SUPPLY_TYPE_BATTERY,
- ANDROID_POWER_SUPPLY_TYPE_DOCK
+ ANDROID_POWER_SUPPLY_TYPE_BATTERY
};
BatteryMonitor();
@@ -63,10 +58,9 @@ class BatteryMonitor {
status_t getProperty(int id, struct BatteryProperty *val);
void dumpState(int fd);
- android::hardware::health::V1_0::HealthInfo getHealthInfo_1_0() const;
- android::hardware::health::V2_0::HealthInfo getHealthInfo_2_0() const;
- android::hardware::health::V2_1::HealthInfo getHealthInfo_2_1() const;
- const aidl::android::hardware::health::HealthInfo& getHealthInfo() const;
+ const android::hardware::health::V1_0::HealthInfo& getHealthInfo_1_0() const;
+ const android::hardware::health::V2_0::HealthInfo& getHealthInfo_2_0() const;
+ const android::hardware::health::V2_1::HealthInfo& getHealthInfo_2_1() const;
void updateValues(void);
void logValues(void);
@@ -81,7 +75,13 @@ class BatteryMonitor {
bool mBatteryDevicePresent;
int mBatteryFixedCapacity;
int mBatteryFixedTemperature;
- std::unique_ptr<aidl::android::hardware::health::HealthInfo> mHealthInfo;
+ std::unique_ptr<android::hardware::health::V2_1::HealthInfo> mHealthInfo;
+
+ int readFromFile(const String8& path, std::string* buf);
+ PowerSupplyType readPowerSupplyType(const String8& path);
+ bool getBooleanField(const String8& path);
+ int getIntField(const String8& path);
+ bool isScopedPowerSupply(const char* name);
};
}; // namespace android
diff --git a/init/Android.bp b/init/Android.bp
index dd67d04c0..7eeafa24b 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -89,19 +89,7 @@ init_host_sources = [
"host_init_verifier.cpp",
]
-soong_config_module_type {
- name: "libinit_cc_defaults",
- module_type: "cc_defaults",
- config_namespace: "ANDROID",
- bool_variables: [
- "PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT",
- ],
- properties: [
- "cflags",
- ],
-}
-
-libinit_cc_defaults {
+cc_defaults {
name: "init_defaults",
sanitize: {
misc_undefined: ["signed-integer-overflow"],
@@ -121,7 +109,6 @@ libinit_cc_defaults {
"-DDUMP_ON_UMOUNT_FAILURE=0",
"-DSHUTDOWN_ZERO_TIMEOUT=0",
"-DINIT_FULL_SOURCES",
- "-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=0",
],
product_variables: {
debuggable: {
@@ -150,27 +137,16 @@ libinit_cc_defaults {
cppflags: ["-DUSER_MODE_LINUX"],
},
},
- soong_config_variables: {
- PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT: {
- cflags: [
- "-UINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT",
- "-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=1",
- ],
- },
- },
static_libs: [
"libavb",
"libc++fs",
"libcgrouprc_format",
- "libfsverity_init",
"liblmkd_utils",
- "libmini_keyctl_static",
"libmodprobe",
"libprocinfo",
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
"libpropertyinfoparser",
- "libsigningutils",
"libsnapshot_cow",
"libsnapshot_init",
"libxml2",
@@ -181,7 +157,6 @@ libinit_cc_defaults {
"libbacktrace",
"libbase",
"libbootloader_message",
- "libcrypto",
"libcutils",
"libdl",
"libext4_utils",
@@ -196,7 +171,6 @@ libinit_cc_defaults {
"libprocessgroup_setup",
"libselinux",
"libutils",
- "libziparchive",
],
bootstrap: true,
visibility: [":__subpackages__"],
@@ -254,20 +228,17 @@ cc_binary {
stem: "init",
defaults: ["init_defaults"],
static_libs: ["libinit"],
+ required: [
+ "e2fsdroid",
+ "init.rc",
+ "mke2fs",
+ "sload_f2fs",
+ "make_f2fs",
+ "ueventd.rc",
+ ],
srcs: ["main.cpp"],
symlinks: ["ueventd"],
target: {
- platform: {
- required: [
- "init.rc",
- "ueventd.rc",
- "e2fsdroid",
- "extra_free_kbytes.sh",
- "make_f2fs",
- "mke2fs",
- "sload_f2fs",
- ],
- },
recovery: {
cflags: ["-DRECOVERY"],
exclude_static_libs: [
@@ -277,45 +248,16 @@ cc_binary {
"libbinder",
"libutils",
],
- required: [
- "init_recovery.rc",
- "ueventd.rc.recovery",
- "e2fsdroid.recovery",
- "make_f2fs.recovery",
- "mke2fs.recovery",
- "sload_f2fs.recovery",
- ],
},
},
visibility: ["//packages/modules/Virtualization/microdroid"],
}
-soong_config_module_type {
- name: "init_first_stage_cc_defaults",
- module_type: "cc_defaults",
- config_namespace: "ANDROID",
- bool_variables: ["BOARD_BUILD_SYSTEM_ROOT_IMAGE", "BOARD_USES_RECOVERY_AS_BOOT"],
- properties: ["installable"],
-}
-
-// Do not install init_first_stage even with mma if we're system-as-root.
-// Otherwise, it will overwrite the symlink.
-init_first_stage_cc_defaults {
- name: "init_first_stage_defaults",
- soong_config_variables: {
- BOARD_BUILD_SYSTEM_ROOT_IMAGE: {
- installable: false,
- },
- BOARD_USES_RECOVERY_AS_BOOT: {
- installable: false,
- },
- },
-}
-
+// This currently is only for the VM usecase.
+// TODO(jiyong): replace init_first_stage in Android.mk with this
cc_binary {
- name: "init_first_stage",
- stem: "init",
- defaults: ["init_first_stage_defaults"],
+ name: "init_first_stage_soong",
+ stem: "init_vendor",
srcs: [
"block_dev_initializer.cpp",
@@ -326,6 +268,7 @@ cc_binary {
"first_stage_mount.cpp",
"reboot_utils.cpp",
"selabel.cpp",
+ "selinux.cpp",
"service_utils.cpp",
"snapuserd_transition.cpp",
"switch_root.cpp",
@@ -340,16 +283,23 @@ cc_binary {
"libfec",
"libfec_rs",
"libsquashfs_utils",
+ "liblogwrap",
+ "libext4_utils",
"libcrypto_utils",
+ "libsparse",
"libavb",
+ "libkeyutils",
"liblp",
"libcutils",
"libbase",
"liblog",
"libcrypto_static",
+ "libdl",
+ "libz",
"libselinux",
"libcap",
"libgsi",
+ "libcom.android.sysprop.apex",
"liblzma",
"libunwindstack_no_dex",
"libbacktrace_no_dex",
@@ -363,7 +313,6 @@ cc_binary {
],
static_executable: true,
- system_shared_libs: [],
cflags: [
"-Wall",
@@ -414,23 +363,8 @@ cc_binary {
sanitize: {
misc_undefined: ["signed-integer-overflow"],
-
- // First stage init is weird: it may start without stdout/stderr, and no /proc.
hwaddress: false,
},
-
- // Install adb_debug.prop into debug ramdisk.
- // This allows adb root on a user build, when debug ramdisk is used.
- required: ["adb_debug.prop"],
-
- ramdisk: true,
-
- install_in_root: true,
-}
-
-phony {
- name: "init_system",
- required: ["init_second_stage"],
}
// Tests
@@ -532,8 +466,8 @@ genrule {
cmd: "$(location host_builtin_map.py) --builtins $(location builtins.cpp) --check_builtins $(location check_builtins.cpp) > $(out)",
}
-cc_defaults {
- name: "init_host_defaults",
+cc_binary {
+ name: "host_init_verifier",
host_supported: true,
cflags: [
"-Wall",
@@ -556,6 +490,7 @@ cc_defaults {
"libprocessgroup",
"libprotobuf-cpp-lite",
],
+ srcs: init_common_sources + init_host_sources,
proto: {
type: "lite",
},
@@ -572,28 +507,3 @@ cc_defaults {
},
},
}
-
-cc_binary {
- name: "host_init_verifier",
- defaults: ["init_host_defaults"],
- srcs: init_common_sources + init_host_sources,
-}
-
-cc_library_host_static {
- name: "libinit_host",
- defaults: ["init_host_defaults"],
- srcs: init_common_sources,
- export_include_dirs: ["."],
- proto: {
- export_proto_headers: true,
- },
- visibility: [
- // host_apex_verifier performs a subset of init.rc validation
- "//system/apex/tools",
- ],
-}
-
-sh_binary {
- name: "extra_free_kbytes.sh",
- src: "extra_free_kbytes.sh",
-}
diff --git a/init/Android.mk b/init/Android.mk
index c08fe0393..3c7d95acf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -2,6 +2,153 @@
LOCAL_PATH:= $(call my-dir)
+-include system/sepolicy/policy_version.mk
+
+# --
+
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+init_options += \
+ -DALLOW_FIRST_STAGE_CONSOLE=1 \
+ -DALLOW_LOCAL_PROP_OVERRIDE=1 \
+ -DALLOW_PERMISSIVE_SELINUX=1 \
+ -DREBOOT_BOOTLOADER_ON_PANIC=1 \
+ -DWORLD_WRITABLE_KMSG=1 \
+ -DDUMP_ON_UMOUNT_FAILURE=1
+else
+init_options += \
+ -DALLOW_FIRST_STAGE_CONSOLE=0 \
+ -DALLOW_LOCAL_PROP_OVERRIDE=0 \
+ -DALLOW_PERMISSIVE_SELINUX=0 \
+ -DREBOOT_BOOTLOADER_ON_PANIC=0 \
+ -DWORLD_WRITABLE_KMSG=0 \
+ -DDUMP_ON_UMOUNT_FAILURE=0
+endif
+
+ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
+init_options += \
+ -DSHUTDOWN_ZERO_TIMEOUT=1
+else
+init_options += \
+ -DSHUTDOWN_ZERO_TIMEOUT=0
+endif
+
+init_options += -DLOG_UEVENTS=0 \
+ -DSEPOLICY_VERSION=$(POLICYVERS)
+
+init_cflags += \
+ $(init_options) \
+ -Wall -Wextra \
+ -Wno-unused-parameter \
+ -Werror \
+
+# --
+
+# Do not build this even with mmma if we're system-as-root, otherwise it will overwrite the symlink.
+ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
+include $(CLEAR_VARS)
+LOCAL_CPPFLAGS := $(init_cflags)
+LOCAL_SRC_FILES := \
+ block_dev_initializer.cpp \
+ devices.cpp \
+ first_stage_console.cpp \
+ first_stage_init.cpp \
+ first_stage_main.cpp \
+ first_stage_mount.cpp \
+ reboot_utils.cpp \
+ selabel.cpp \
+ selinux.cpp \
+ service_utils.cpp \
+ snapuserd_transition.cpp \
+ switch_root.cpp \
+ uevent_listener.cpp \
+ util.cpp \
+
+LOCAL_MODULE := init_first_stage
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
+LOCAL_MODULE_STEM := init
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
+LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
+
+# Install adb_debug.prop into debug ramdisk.
+# This allows adb root on a user build, when debug ramdisk is used.
+LOCAL_REQUIRED_MODULES := \
+ adb_debug.prop \
+
+# Set up the directories that first stage init mounts on.
+
+my_ramdisk_dirs := \
+ debug_ramdisk \
+ dev \
+ metadata \
+ mnt \
+ proc \
+ second_stage_resources \
+ sys \
+
+LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_RAMDISK_OUT)/,$(my_ramdisk_dirs))
+ifeq (true,$(BOARD_USES_GENERIC_KERNEL_IMAGE))
+ LOCAL_POST_INSTALL_CMD += $(addprefix $(TARGET_RAMDISK_OUT)/first_stage_ramdisk/,$(my_ramdisk_dirs))
+endif
+
+my_ramdisk_dirs :=
+
+LOCAL_STATIC_LIBRARIES := \
+ libc++fs \
+ libfs_avb \
+ libfs_mgr \
+ libfec \
+ libfec_rs \
+ libsquashfs_utils \
+ liblogwrap \
+ libext4_utils \
+ libcrypto_utils \
+ libsparse \
+ libavb \
+ libkeyutils \
+ liblp \
+ libcutils \
+ libbase \
+ liblog \
+ libcrypto_static \
+ libdl \
+ libz \
+ libselinux \
+ libcap \
+ libgsi \
+ libcom.android.sysprop.apex \
+ liblzma \
+ libunwindstack_no_dex \
+ libbacktrace_no_dex \
+ libmodprobe \
+ libext2_uuid \
+ libprotobuf-cpp-lite \
+ libsnapshot_cow \
+ libsnapshot_init \
+ update_metadata-protos \
+ libprocinfo \
+
+LOCAL_SANITIZE := signed-integer-overflow
+# First stage init is weird: it may start without stdout/stderr, and no /proc.
+LOCAL_NOSANITIZE := hwaddress
+include $(BUILD_EXECUTABLE)
+endif
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init_system
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
+LOCAL_REQUIRED_MODULES := \
+ init_second_stage \
+
+include $(BUILD_PHONY_PACKAGE)
+
include $(CLEAR_VARS)
LOCAL_MODULE := init_vendor
@@ -9,10 +156,8 @@ LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
LOCAL_REQUIRED_MODULES := \
init_first_stage \
-endif # BOARD_USES_RECOVERY_AS_BOOT
-endif # BOARD_BUILD_SYSTEM_ROOT_IMAGE
+endif
include $(BUILD_PHONY_PACKAGE)
diff --git a/init/OWNERS b/init/OWNERS
index 4604d0605..9e70e7dcf 100644
--- a/init/OWNERS
+++ b/init/OWNERS
@@ -1,2 +1 @@
dvander@google.com
-jiyong@google.com
diff --git a/init/README.md b/init/README.md
index 13c6ebdfa..4a262c920 100644
--- a/init/README.md
+++ b/init/README.md
@@ -77,43 +77,6 @@ monolithic init .rc files. This additionally will aid in merge
conflict resolution when multiple services are added to the system, as
each one will go into a separate file.
-Versioned RC files within APEXs
--------------------------------
-
-With the arrival of mainline on Android Q, the individual mainline
-modules carry their own init.rc files within their boundaries. Init
-processes these files according to the naming pattern `/apex/*/etc/*rc`.
-
-Because APEX modules must run on more than one release of Android,
-they may require different parameters as part of the services they
-define. This is achieved, starting in Android T, by incorporating
-the SDK version information in the name of the init file. The suffix
-is changed from `.rc` to `.#rc` where # is the first SDK where that
-RC file is accepted. An init file specific to SDK=31 might be named
-`init.31rc`. With this scheme, an APEX may include multiple init files. An
-example is appropriate.
-
-For an APEX module with the following files in /apex/sample-module/apex/etc/:
-
- 1. init.rc
- 2. init.32rc
- 4. init.35rc
-
-The selection rule chooses the highest `.#rc` value that does not
-exceed the SDK of the currently running system. The unadorned `.rc`
-is interpreted as sdk=0.
-
-When this APEX is installed on a device with SDK <=31, the system will
-process init.rc. When installed on a device running SDK 32, 33, or 34,
-it will use init.32rc. When installed on a device running SDKs >= 35,
-it will choose init.35rc
-
-This versioning scheme is used only for the init files within APEX
-modules; it does not apply to the init files stored in /system/etc/init,
-/vendor/etc/init, or other directories.
-
-This naming scheme is available after Android S.
-
Actions
-------
Actions are named sequences of commands. Actions have a trigger which
@@ -441,33 +404,6 @@ at three times:
3. Any time that property c transitions to value d, while property a already equals b.
-Trigger Sequence
-----------------
-
-Init uses the following sequence of triggers during early boot. These are the
-built-in triggers defined in init.cpp.
-
- 1. `early-init` - The first in the sequence, triggered after cgroups has been configured
- but before ueventd's coldboot is complete.
- 2. `init` - Triggered after coldboot is complete.
- 3. `charger` - Triggered if `ro.bootmode == "charger"`.
- 4. `late-init` - Triggered if `ro.bootmode != "charger"`, or via healthd triggering a boot
- from charging mode.
-
-Remaining triggers are configured in `init.rc` and are not built-in. The default sequence for
-these is specified under the "on late-init" event in `init.rc`. Actions internal to `init.rc`
-have been omitted.
-
- 1. `early-fs` - Start vold.
- 2. `fs` - Vold is up. Mount partitions not marked as first-stage or latemounted.
- 3. `post-fs` - Configure anything dependent on early mounts.
- 4. `late-fs` - Mount partitions marked as latemounted.
- 5. `post-fs-data` - Mount and configure `/data`; set up encryption. `/metadata` is
- reformatted here if it couldn't mount in first-stage init.
- 6. `zygote-start` - Start the zygote.
- 7. `early-boot` - After zygote has started.
- 8. `boot` - After `early-boot` actions have completed.
-
Commands
--------
@@ -487,6 +423,11 @@ Commands
not already running. See the start entry for more information on
starting services.
+`class_start_post_data <serviceclass>`
+> Like `class_start`, but only considers services that were started
+ after /data was mounted, and that were running at the time
+ `class_reset_post_data` was called. Only used for FDE devices.
+
`class_stop <serviceclass>`
> Stop and disable all services of the specified class if they are
currently running.
@@ -496,9 +437,12 @@ Commands
currently running, without disabling them. They can be restarted
later using `class_start`.
-`class_restart [--only-enabled] <serviceclass>`
-> Restarts all services of the specified class. If `--only-enabled` is
- specified, then disabled services are skipped.
+`class_reset_post_data <serviceclass>`
+> Like `class_reset`, but only considers services that were started
+ after /data was mounted. Only used for FDE devices.
+
+`class_restart <serviceclass>`
+> Restarts all services of the specified class.
`copy <src> <dst>`
> Copies a file. Similar to write, but useful for binary/large
@@ -599,7 +543,8 @@ provides the `aidl_lazy_test_1` interface.
Properties are expanded within _level_.
`mark_post_data`
-> Used to mark the point right after /data is mounted.
+> Used to mark the point right after /data is mounted. Used to implement the
+ `class_reset_post_data` and `class_start_post_data` commands.
`mkdir <path> [<mode>] [<owner>] [<group>] [encryption=<action>] [key=<key>]`
> Create a directory at _path_, optionally with the given mode, owner, and
@@ -641,10 +586,9 @@ provides the `aidl_lazy_test_1` interface.
configurations. Intended to be used only once when apexd notifies the mount
event by setting `apexd.status` to ready.
-`restart [--only-if-running] <service>`
+`restart <service>`
> Stops and restarts a running service, does nothing if the service is currently
- restarting, otherwise, it just starts the service. If "--only-if-running" is
- specified, the service is only restarted if it is already running.
+ restarting, otherwise, it just starts the service.
`restorecon <path> [ <path>\* ]`
> Restore the file named by _path_ to the security context specified
@@ -722,13 +666,10 @@ provides the `aidl_lazy_test_1` interface.
fstab.${ro.hardware} or fstab.${ro.hardware.platform} will be scanned for
under /odm/etc, /vendor/etc, or / at runtime, in that order.
-`verity_update_state`
+`verity_update_state <mount-point>`
> Internal implementation detail used to update dm-verity state and
set the partition._mount-point_.verified properties used by adb remount
- because fs\_mgr can't set them directly itself. This is required since
- Android 12, because CtsNativeVerifiedBootTestCases will read property
- "partition.${partition}.verified.hash_alg" to check that sha1 is not used.
- See https://r.android.com/1546980 for more details.
+ because fs\_mgr can't set them directly itself.
`wait <path> [ <timeout> ]`
> Poll for the existence of the given file and return when found,
@@ -804,18 +745,13 @@ Init provides state information with the following properties.
`init.svc.<name>`
> State of a named service ("stopped", "stopping", "running", "restarting")
-`dev.mnt.dev.<mount_point>`, `dev.mnt.blk.<mount_point>`, `dev.mnt.rootdisk.<mount_point>`
+`dev.mnt.blk.<mount_point>`
> Block device base name associated with a *mount_point*.
The *mount_point* has / replaced by . and if referencing the root mount point
- "/", it will use "/root".
- `dev.mnt.dev.<mount_point>` indicates a block device attached to filesystems.
- (e.g., dm-N or sdaN/mmcblk0pN to access `/sys/fs/ext4/${dev.mnt.dev.<mount_point>}/`)
-
- `dev.mnt.blk.<mount_point>` indicates the disk partition to the above block device.
- (e.g., sdaN / mmcblk0pN to access `/sys/class/block/${dev.mnt.blk.<mount_point>}/`)
-
- `dev.mnt.rootdisk.<mount_point>` indicates the root disk to contain the above disk partition.
- (e.g., sda / mmcblk0 to access `/sys/class/block/${dev.mnt.rootdisk.<mount_point>}/queue`)
+ "/", it will use "/root", specifically `dev.mnt.blk.root`.
+ Meant for references to `/sys/device/block/${dev.mnt.blk.<mount_point>}/` and
+ `/sys/fs/ext4/${dev.mnt.blk.<mount_point>}/` to tune the block device
+ characteristics in a device agnostic manner.
Init responds to properties that begin with `ctl.`. These properties take the format of
`ctl.[<target>_]<command>` and the _value_ of the system property is used as a parameter. The
@@ -1039,7 +975,7 @@ located at /init within the recovery ramdisk. These devices first switch root to
/first_stage_ramdisk to remove the recovery components from the environment, then proceed the same
as 2). Note that the decision to boot normally into Android instead of booting
into recovery mode is made if androidboot.force_normal_boot=1 is present in the
-kernel commandline, or in bootconfig with Android S and later.
+kernel commandline.
Once first stage init finishes it execs /system/bin/init with the "selinux_setup" argument. This
phase is where SELinux is optionally compiled and loaded onto the system. selinux.cpp contains more
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index 3c7107a4d..d22f68fb0 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -123,10 +123,7 @@ not present.
The exact firmware file to be served can be customized by running an external program by a
`external_firmware_handler` line in a ueventd.rc file. This line takes the format of
- external_firmware_handler <devpath> <user [group]> <path to external program>
-
-The handler will be run as the given user, or if a group is provided, as the given user and group.
-
+ external_firmware_handler <devpath> <user name to run as> <path to external program>
For example
external_firmware_handler /devices/leds/red/firmware/coeffs.bin system /vendor/bin/led_coeffs.bin
@@ -147,12 +144,6 @@ directories. If stdout cannot be read, or the program returns with any exit code
Ueventd will additionally log all messages sent to stderr from the external program to the serial
console after the external program has exited.
-If the kernel command-line argument `firmware_class.path` is set, this path
-will be used first by the kernel to search for the firmware files. If found,
-ueventd will not be called at all. See the
-[kernel documentation](https://www.kernel.org/doc/html/v5.10/driver-api/firmware/fw_search_path.html)
-for more details on this feature.
-
## Coldboot
--------
Ueventd must create devices in `/dev` for all devices that have already sent their uevents before
@@ -169,13 +160,3 @@ recommended that devices use genfscon for labeling sysfs nodes. However, some de
from enabling the parallelization option:
parallel_restorecon enabled
-
-Do parallel restorecon to speed up boot process, subdirectories under `/sys`
-can be sliced by ueventd.rc, and run on multiple process.
- parallel_restorecon_dir <directory>
-
-For example
- parallel_restorecon_dir /sys
- parallel_restorecon_dir /sys/devices
- parallel_restorecon_dir /sys/devices/platform
- parallel_restorecon_dir /sys/devices/platform/soc
diff --git a/init/TEST_MAPPING b/init/TEST_MAPPING
deleted file mode 100644
index fa1627ce8..000000000
--- a/init/TEST_MAPPING
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsInitTestCases"
- },
- {
- "name": "init_kill_services_test"
- },
- {
- "name": "MicrodroidHostTestCases"
- }
- ],
- "hwasan-postsubmit": [
- {
- "name": "CtsInitTestCases"
- },
- {
- "name": "init_kill_services_test"
- },
- {
- "name": "MicrodroidHostTestCases"
- }
- ]
-}
diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp
index 05e00edfd..9c2a7bb14 100644
--- a/init/block_dev_initializer.cpp
+++ b/init/block_dev_initializer.cpp
@@ -87,13 +87,7 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent,
auto iter = devices->find(name);
if (iter == devices->end()) {
- auto partition_name = DeviceHandler::GetPartitionNameForDevice(uevent.device_name);
- if (!partition_name.empty()) {
- iter = devices->find(partition_name);
- }
- if (iter == devices->end()) {
- return ListenerAction::kContinue;
- }
+ return ListenerAction::kContinue;
}
LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name;
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index f46fb0993..b7db9b6d6 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -140,20 +140,6 @@ static void log_processes(FILE* log) {
static void bootchart_thread_main() {
LOG(INFO) << "Bootcharting started";
- // Unshare the mount namespace of this thread so that the init process itself can switch
- // the mount namespace later while this thread is still running.
- // Otherwise, setns() call invoked as part of `enter_default_mount_ns` fails with EINVAL.
- //
- // Note that after unshare()'ing the mount namespace from the main thread, this thread won't
- // receive mount/unmount events from the other mount namespace unless the events are happening
- // from under a sharable mount.
- //
- // The bootchart thread is safe to unshare the mount namespace because it only reads from /proc
- // and write to /data which are not private mounts.
- if (unshare(CLONE_NEWNS) == -1) {
- PLOG(ERROR) << "Cannot create mount namespace";
- return;
- }
// Open log files.
auto stat_log = fopen_unique("/data/bootchart/proc_stat.log", "we");
if (!stat_log) return;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 01db4f5da..035038f32 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -28,7 +28,6 @@
#include <net/if.h>
#include <sched.h>
#include <signal.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -43,9 +42,9 @@
#include <sys/wait.h>
#include <unistd.h>
-#include <map>
#include <memory>
+#include <ApexProperties.sysprop.h>
#include <InitProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
@@ -88,7 +87,6 @@
using namespace std::literals::string_literals;
using android::base::Basename;
-using android::base::ResultError;
using android::base::SetProperty;
using android::base::Split;
using android::base::StartsWith;
@@ -117,7 +115,7 @@ class ErrorIgnoreEnoent {
android::base::GetMinimumLogSeverity() > android::base::DEBUG) {}
template <typename T>
- operator android::base::expected<T, ResultError<android::base::Errno>>() {
+ operator android::base::expected<T, ResultError>() {
if (ignore_error_) {
return {};
}
@@ -131,7 +129,7 @@ class ErrorIgnoreEnoent {
}
private:
- Error<> error_;
+ Error error_;
bool ignore_error_;
};
@@ -177,6 +175,28 @@ static Result<void> do_class_start(const BuiltinArguments& args) {
return {};
}
+static Result<void> do_class_start_post_data(const BuiltinArguments& args) {
+ if (args.context != kInitContext) {
+ return Error() << "command 'class_start_post_data' only available in init context";
+ }
+ static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false);
+
+ if (!is_apex_updatable) {
+ // No need to start these on devices that don't support APEX, since they're not
+ // stopped either.
+ return {};
+ }
+ for (const auto& service : ServiceList::GetInstance()) {
+ if (service->classnames().count(args[1])) {
+ if (auto result = service->StartIfPostData(); !result.ok()) {
+ LOG(ERROR) << "Could not start service '" << service->name()
+ << "' as part of class '" << args[1] << "': " << result.error();
+ }
+ }
+ }
+ return {};
+}
+
static Result<void> do_class_stop(const BuiltinArguments& args) {
ForEachServiceInClass(args[1], &Service::Stop);
return {};
@@ -187,35 +207,24 @@ static Result<void> do_class_reset(const BuiltinArguments& args) {
return {};
}
+static Result<void> do_class_reset_post_data(const BuiltinArguments& args) {
+ if (args.context != kInitContext) {
+ return Error() << "command 'class_reset_post_data' only available in init context";
+ }
+ static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false);
+ if (!is_apex_updatable) {
+ // No need to stop these on devices that don't support APEX.
+ return {};
+ }
+ ForEachServiceInClass(args[1], &Service::ResetIfPostData);
+ return {};
+}
+
static Result<void> do_class_restart(const BuiltinArguments& args) {
// Do not restart a class if it has a property persist.dont_start_class.CLASS set to 1.
if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
return {};
-
- std::string classname;
-
- CHECK(args.size() == 2 || args.size() == 3);
-
- bool only_enabled = false;
- if (args.size() == 3) {
- if (args[1] != "--only-enabled") {
- return Error() << "Unexpected argument: " << args[1];
- }
- only_enabled = true;
- classname = args[2];
- } else if (args.size() == 2) {
- classname = args[1];
- }
-
- for (const auto& service : ServiceList::GetInstance()) {
- if (!service->classnames().count(classname)) {
- continue;
- }
- if (only_enabled && !service->IsEnabled()) {
- continue;
- }
- service->Restart();
- }
+ ForEachServiceInClass(args[1], &Service::Restart);
return {};
}
@@ -575,7 +584,32 @@ static void import_late(const std::vector<std::string>& rc_paths) {
* return code is processed based on input code
*/
static Result<void> queue_fs_event(int code, bool userdata_remount) {
- if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
+ if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
+ if (userdata_remount) {
+ // FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION should only happen on FDE devices. Since we don't
+ // support userdata remount on FDE devices, this should never been triggered. Time to
+ // panic!
+ LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
+ trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
+ }
+ ActionManager::GetInstance().QueueEventTrigger("encrypt");
+ return {};
+ } else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
+ if (userdata_remount) {
+ // FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED should only happen on FDE devices. Since we
+ // don't support userdata remount on FDE devices, this should never been triggered.
+ // Time to panic!
+ LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
+ trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
+ }
+ SetProperty("ro.crypto.state", "encrypted");
+ ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+ return {};
+ } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+ SetProperty("ro.crypto.state", "unencrypted");
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
+ return {};
+ } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
SetProperty("ro.crypto.state", "unsupported");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return {};
@@ -775,21 +809,8 @@ static Result<void> do_stop(const BuiltinArguments& args) {
}
static Result<void> do_restart(const BuiltinArguments& args) {
- bool only_if_running = false;
- if (args.size() == 3) {
- if (args[1] == "--only-if-running") {
- only_if_running = true;
- } else {
- return Error() << "Unknown argument to restart: " << args[1];
- }
- }
-
- const auto& classname = args[args.size() - 1];
- Service* svc = ServiceList::GetInstance().FindService(classname);
- if (!svc) return Error() << "service " << classname << " not found";
- if (only_if_running && !svc->IsRunning()) {
- return {};
- }
+ Service* svc = ServiceList::GetInstance().FindService(args[1]);
+ if (!svc) return Error() << "service " << args[1] << " not found";
svc->Restart();
return {};
}
@@ -873,11 +894,9 @@ static Result<void> do_verity_update_state(const BuiltinArguments& args) {
std::string partition = entry.mount_point == "/" ? "system" : Basename(entry.mount_point);
SetProperty("partition." + partition + ".verified", std::to_string(mode));
- auto hashtree_info = fs_mgr_get_hashtree_info(entry);
- if (hashtree_info) {
- SetProperty("partition." + partition + ".verified.hash_alg", hashtree_info->algorithm);
- SetProperty("partition." + partition + ".verified.root_digest",
- hashtree_info->root_digest);
+ std::string hash_alg = fs_mgr_get_hashtree_algorithm(entry);
+ if (!hash_alg.empty()) {
+ SetProperty("partition." + partition + ".verified.hash_alg", hash_alg);
}
}
@@ -1096,6 +1115,17 @@ static Result<void> do_loglevel(const BuiltinArguments& args) {
}
static Result<void> do_load_persist_props(const BuiltinArguments& args) {
+ // Devices with FDE have load_persist_props called twice; the first time when the temporary
+ // /data partition is mounted and then again once /data is truly mounted. We do not want to
+ // read persistent properties from the temporary /data partition or mark persistent properties
+ // as having been loaded during the first call, so we return in that case.
+ std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
+ std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
+ if (crypto_state == "encrypted" && crypto_type == "block") {
+ static size_t num_calls = 0;
+ if (++num_calls == 1) return {};
+ }
+
SendLoadPersistentPropertiesMessage();
start_waiting_for_property("ro.persistent_properties.ready", "true");
@@ -1275,13 +1305,25 @@ static Result<void> MountLinkerConfigForDefaultNamespace() {
return {};
}
+
+static bool IsApexUpdatable() {
+ static bool updatable = android::sysprop::ApexProperties::updatable().value_or(false);
+ return updatable;
+}
+
static Result<void> do_update_linker_config(const BuiltinArguments&) {
- return GenerateLinkerConfiguration();
+ // If APEX is not updatable, then all APEX information are already included in the first
+ // linker config generation, so there is no need to update linker configuration again.
+ if (IsApexUpdatable()) {
+ return GenerateLinkerConfiguration();
+ }
+
+ return {};
}
static Result<void> parse_apex_configs() {
glob_t glob_result;
- static constexpr char glob_pattern[] = "/apex/*/etc/*rc";
+ static constexpr char glob_pattern[] = "/apex/*/etc/*.rc";
const int ret = glob(glob_pattern, GLOB_MARK, nullptr, &glob_result);
if (ret != 0 && ret != GLOB_NOMATCH) {
globfree(&glob_result);
@@ -1298,18 +1340,16 @@ static Result<void> parse_apex_configs() {
if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) {
continue;
}
- // Filter directories
- if (path.back() == '/') {
- continue;
- }
configs.push_back(path);
}
globfree(&glob_result);
- int active_sdk = android::base::GetIntProperty("ro.build.version.sdk", INT_MAX);
-
bool success = true;
- for (const auto& c : parser.FilterVersionedConfigs(configs, active_sdk)) {
+ for (const auto& c : configs) {
+ if (c.back() == '/') {
+ // skip if directory
+ continue;
+ }
success &= parser.ParseConfigFile(c);
}
ServiceList::GetInstance().MarkServicesUpdate();
@@ -1383,8 +1423,10 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
{"chmod", {2, 2, {true, do_chmod}}},
{"chown", {2, 3, {true, do_chown}}},
{"class_reset", {1, 1, {false, do_class_reset}}},
- {"class_restart", {1, 2, {false, do_class_restart}}},
+ {"class_reset_post_data", {1, 1, {false, do_class_reset_post_data}}},
+ {"class_restart", {1, 1, {false, do_class_restart}}},
{"class_start", {1, 1, {false, do_class_start}}},
+ {"class_start_post_data", {1, 1, {false, do_class_start_post_data}}},
{"class_stop", {1, 1, {false, do_class_stop}}},
{"copy", {2, 2, {true, do_copy}}},
{"copy_per_line", {2, 2, {true, do_copy_per_line}}},
@@ -1420,7 +1462,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
{"update_linker_config", {0, 0, {false, do_update_linker_config}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"remount_userdata", {0, 0, {false, do_remount_userdata}}},
- {"restart", {1, 2, {false, do_restart}}},
+ {"restart", {1, 1, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
{"rm", {1, 1, {true, do_rm}}},
diff --git a/init/devices.cpp b/init/devices.cpp
index d4a3cb9d3..ce6298a9d 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -46,7 +46,6 @@ using android::base::Dirname;
using android::base::ReadFileToString;
using android::base::Readlink;
using android::base::Realpath;
-using android::base::Split;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::Trim;
@@ -188,36 +187,6 @@ void SysfsPermissions::SetPermissions(const std::string& path) const {
}
}
-std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) {
- static const auto partition_map = [] {
- std::vector<std::pair<std::string, std::string>> partition_map;
- auto parser = [&partition_map](const std::string& key, const std::string& value) {
- if (key != "androidboot.partition_map") {
- return;
- }
- for (const auto& map : Split(value, ";")) {
- auto map_pieces = Split(map, ",");
- if (map_pieces.size() != 2) {
- LOG(ERROR) << "Expected a comma separated device,partition mapping, but found '"
- << map << "'";
- continue;
- }
- partition_map.emplace_back(map_pieces[0], map_pieces[1]);
- }
- };
- ImportKernelCmdline(parser);
- ImportBootconfig(parser);
- return partition_map;
- }();
-
- for (const auto& [device, partition] : partition_map) {
- if (query_device == device) {
- return partition;
- }
- }
- return {};
-}
-
// Given a path that may start with a platform device, find the parent platform device by finding a
// parent directory with a 'subsystem' symlink that points to the platform bus.
// If it doesn't start with a platform device, return false
@@ -295,8 +264,6 @@ void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, i
setfscreatecon(secontext.c_str());
}
- gid_t new_group = -1;
-
dev_t dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
* device node. Unforunately changing the euid would prevent creation of
@@ -324,21 +291,10 @@ void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, i
PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
<< "' device";
}
-
- struct stat s;
- if (stat(path.c_str(), &s) == 0) {
- if (gid != s.st_gid) {
- new_group = gid;
- }
- } else {
- PLOG(ERROR) << "Cannot stat " << path;
- }
}
out:
- if (chown(path.c_str(), uid, new_group) < 0) {
- PLOG(ERROR) << "Cannot chown " << path << " " << uid << " " << new_group;
- }
+ chown(path.c_str(), uid, -1);
if (setegid(AID_ROOT)) {
PLOG(FATAL) << "setegid(AID_ROOT) failed";
}
@@ -420,10 +376,6 @@ std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev
// If we don't have a partition name but we are a partition on a boot device, create a
// symlink of /dev/block/by-name/<device_name> for symmetry.
links.emplace_back("/dev/block/by-name/" + uevent.device_name);
- auto partition_name = GetPartitionNameForDevice(uevent.device_name);
- if (!partition_name.empty()) {
- links.emplace_back("/dev/block/by-name/" + partition_name);
- }
}
auto last_slash = uevent.path.rfind('/');
diff --git a/init/devices.h b/init/devices.h
index f9f4d7989..d70d746e8 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -122,12 +122,6 @@ class DeviceHandler : public UeventHandler {
std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
- // `androidboot.partition_map` allows associating a partition name for a raw block device
- // through a comma separated and semicolon deliminated list. For example,
- // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to
- // `userdata`.
- static std::string GetPartitionNameForDevice(const std::string& device);
-
private:
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 0580f8608..74d8aac96 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -23,8 +23,6 @@
#include <functional>
#include <map>
-#include <android-base/logging.h>
-
namespace android {
namespace init {
@@ -44,11 +42,8 @@ Result<void> Epoll::RegisterHandler(int fd, Handler handler, uint32_t events) {
if (!events) {
return Error() << "Must specify events";
}
-
- Info info;
- info.events = events;
- info.handler = std::make_shared<decltype(handler)>(std::move(handler));
- auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(info));
+ auto sp = std::make_shared<decltype(handler)>(std::move(handler));
+ auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(sp));
if (!inserted) {
return Error() << "Cannot specify two epoll handlers for a given FD";
}
@@ -89,14 +84,8 @@ Result<std::vector<std::shared_ptr<Epoll::Handler>>> Epoll::Wait(
}
std::vector<std::shared_ptr<Handler>> pending_functions;
for (int i = 0; i < num_events; ++i) {
- auto& info = *reinterpret_cast<Info*>(ev[i].data.ptr);
- if ((info.events & (EPOLLIN | EPOLLPRI)) == (EPOLLIN | EPOLLPRI) &&
- (ev[i].events & EPOLLIN) != ev[i].events) {
- // This handler wants to know about exception events, and just got one.
- // Log something informational.
- LOG(ERROR) << "Received unexpected epoll event set: " << ev[i].events;
- }
- pending_functions.emplace_back(info.handler);
+ auto sp = *reinterpret_cast<std::shared_ptr<Handler>*>(ev[i].data.ptr);
+ pending_functions.emplace_back(std::move(sp));
}
return pending_functions;
diff --git a/init/epoll.h b/init/epoll.h
index f58ae8df3..0df528935 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -46,13 +46,8 @@ class Epoll {
std::optional<std::chrono::milliseconds> timeout);
private:
- struct Info {
- std::shared_ptr<Handler> handler;
- uint32_t events;
- };
-
android::base::unique_fd epoll_fd_;
- std::map<int, Info> epoll_handlers_;
+ std::map<int, std::shared_ptr<Handler>> epoll_handlers_;
};
} // namespace init
diff --git a/init/extra_free_kbytes.sh b/init/extra_free_kbytes.sh
deleted file mode 100755
index aeaa91258..000000000
--- a/init/extra_free_kbytes.sh
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/sh
-
-# Script implements watermark_scale calculation which results in the same low
-# watermark as if extra_free_kbytes tunable were to be used.
-#
-# Usage: extra_free_kbytes.sh <extra_free_kbytes value>
-#
-# extra_free_kbytes is distributed between zones based on
-# zone.managed_pages/vm_total_pages ratio, where vm_total_pages is the sum of
-# zone.managed_pages for all zones (zone.high used in this calculation is 0
-# when this is calculated). Therefore for each zone its share is calculated as:
-#
-# extra_free_pages = extra_free_kbytes / page_size
-# extra_share = extra_free_pages * managed_pages / vm_total_pages
-#
-# This extra_share is added to the low and high watermarks:
-#
-# low = min + max(min / 4, managed_pages * (watermark_scale / 10000)) + extra_share
-# high = min + 2 * max(min / 4, managed_pages * (watermark_scale / 10000)) + extra_share
-#
-# Because Android uses extra_free_kbytes to adjust the low watermark, we ignore
-# the difference in how watermark_scale and extra_free_kbytes affect the high
-# watermark and will match the low watermark only.
-#
-# To eliminate extra_share and compansate the difference with watermark_scale,
-# a new watermark_scale_new is calculated as:
-#
-# (1) max(min / 4, managed_pages * (watermark_scale / 10000)) + extra_share =
-# max(min / 4, managed_pages * (watermark_scale_new / 10000))
-#
-# Two cases to consider:
-# A. managed_pages * (watermark_scale / 10000) > min / 4
-# The formula (1) becomes:
-#
-# managed_pages * (watermark_scale / 10000) + extra_share =
-# managed_pages * (watermark_scale_new / 10000)
-#
-# after simplifying and substituting extra_share formula becomes:
-#
-# (2) watermark_scale_new = watermark_scale + extra_free_pages / vm_total_pages * 10000
-#
-# B. managed_pages * (watermark_scale / 10000) < min / 4
-# The formula (1) becomes:
-#
-# min / 4 + extra_share = max(min / 4, managed_pages * (watermark_scale_new / 10000))
-#
-# after calculating watermark_scale_new, if (managed_pages * (watermark_scale_new / 10000))
-# is still smaller than min / 4 then we can't compensate extra_share with
-# watermark_scale anyway. Therefore calculation becomes:
-#
-# watermark_scale_new = (min / 4 + extra_share) / managed_pages * 10000
-#
-# after simplifying and substituting extra_share formula becomes:
-#
-# (3) watermark_scale_new = (min / 4) * 10000 / managed_pages + extra_free_pages / vm_total_pages * 10000
-#
-# After defining watermark_delta = extra_free_pages / vm_total_pages * 10000:
-#
-# if (managed_pages * (watermark_scale / 10000) > min / 4)
-# watermark_scale_new = watermark_scale + watermark_delta
-# else
-# watermark_scale_new = (min / 4) * 10000 / managed_pages + watermark_delta
-#
-
-if [ "$#" -ne 1 ]
-then
- echo "Usage: $0 <extra_free_kbytes value>"
- exit
-fi
-
-extra_free_kbytes=$1
-
-# if extra_free_kbytes knob exists, use it and exit
-if [ -e /proc/sys/vm/extra_free_kbytes ]
-then
- echo $extra_free_kbytes > /proc/sys/vm/extra_free_kbytes
- exit
-fi
-
-watermark_scale=`cat /proc/sys/vm/watermark_scale_factor`
-
-# convert extra_free_kbytes to pages
-page_size=$(getconf PAGESIZE)
-page_size_kb=$((page_size/1024))
-extra_free_pg=$((extra_free_kbytes/page_size_kb))
-
-managed=($(grep managed /proc/zoneinfo | awk '{print $2}'))
-length=${#managed[@]}
-min=($(grep "min" /proc/zoneinfo | awk '{print $2}'))
-
-# calculate vm_total_pages.
-# WARNING: if the final low watermark differs from the original, the source of
-# the error is likely vm_total_pages which is impossible to get exact from the
-# userspace. Grep for "Total pages" in the kernel logs to see the actual
-# vm_total_pages and plug it in the calculation to confirm the source of the
-# error. Error caused by this inaccuracy is normally within 1% range.
-vm_total_pages=0
-i=0
-while [ $i -lt $length ]
-do
- vm_total_pages=$((vm_total_pages + managed[i]))
- i=$((i+1))
-done
-
-# calculate watermark_scale_new for each zone and choose the max
-max_watermark_scale=0
-i=0
-while [ $i -lt $length ]
-do
- # skip unmanaged zones
- if [ ${managed[i]} -eq 0 ]
- then
- i=$((i+1))
- continue
- fi
-
- base_margin=$((min[i] / 4))
- calc_margin=$(echo "${managed[i]} * $watermark_scale / 10000" | bc)
- # round the value by adding 0.5 and truncating the decimal part
- watermark_delta=$(echo "x=($extra_free_pg / ($vm_total_pages / 10000) + 0.5); scale = 0; x/1" | bc -l)
- if [ $calc_margin -gt $base_margin ]
- then
- watermark_scale_new=$(echo "$watermark_scale + $watermark_delta" | bc)
- else
- watermark_scale_new=$(echo "$base_margin / (${managed[i]} / 10000) + $watermark_delta" | bc)
- fi
-
- if [ $max_watermark_scale -lt $watermark_scale_new ]
- then
- max_watermark_scale=$watermark_scale_new
- fi
-
- i=$((i+1))
-done
-
-echo $max_watermark_scale > /proc/sys/vm/watermark_scale_factor
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 30e808d9f..bdc292275 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -19,7 +19,6 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <glob.h>
-#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
@@ -82,9 +81,9 @@ static bool IsBooting() {
return access("/dev/.booting", F_OK) == 0;
}
-ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid,
+ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
std::string handler_path)
- : devpath(std::move(devpath)), uid(uid), gid(gid), handler_path(std::move(handler_path)) {
+ : devpath(std::move(devpath)), uid(uid), handler_path(std::move(handler_path)) {
auto wildcard_position = this->devpath.find('*');
if (wildcard_position != std::string::npos) {
if (wildcard_position == this->devpath.length() - 1) {
@@ -98,17 +97,13 @@ ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
}
}
-ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
- std::string handler_path)
- : ExternalFirmwareHandler(devpath, uid, 0, handler_path) {}
-
FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories,
std::vector<ExternalFirmwareHandler> external_firmware_handlers)
: firmware_directories_(std::move(firmware_directories)),
external_firmware_handlers_(std::move(external_firmware_handlers)) {}
Result<std::string> FirmwareHandler::RunExternalHandler(const std::string& handler, uid_t uid,
- gid_t gid, const Uevent& uevent) const {
+ const Uevent& uevent) const {
unique_fd child_stdout;
unique_fd parent_stdout;
if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) {
@@ -145,13 +140,6 @@ Result<std::string> FirmwareHandler::RunExternalHandler(const std::string& handl
}
c_args.emplace_back(nullptr);
- if (gid != 0) {
- if (setgid(gid) != 0) {
- fprintf(stderr, "setgid() failed: %s", strerror(errno));
- _exit(EXIT_FAILURE);
- }
- }
-
if (setuid(uid) != 0) {
fprintf(stderr, "setuid() failed: %s", strerror(errno));
_exit(EXIT_FAILURE);
@@ -208,8 +196,8 @@ std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const {
<< "' for devpath: '" << uevent.path << "' firmware: '" << uevent.firmware
<< "'";
- auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid,
- external_handler.gid, uevent);
+ auto result =
+ RunExternalHandler(external_handler.handler_path, external_handler.uid, uevent);
if (!result.ok()) {
LOG(ERROR) << "Using default firmware; External firmware handler failed: "
<< result.error();
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index d2f7347ce..3c35b1f16 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -16,7 +16,6 @@
#pragma once
-#include <grp.h>
#include <pwd.h>
#include <functional>
@@ -32,11 +31,9 @@ namespace init {
struct ExternalFirmwareHandler {
ExternalFirmwareHandler(std::string devpath, uid_t uid, std::string handler_path);
- ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid, std::string handler_path);
std::string devpath;
uid_t uid;
- gid_t gid;
std::string handler_path;
std::function<bool(const std::string&)> match;
@@ -54,7 +51,7 @@ class FirmwareHandler : public UeventHandler {
friend void FirmwareTestWithExternalHandler(const std::string& test_name,
bool expect_new_firmware);
- Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid, gid_t gid,
+ Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid,
const Uevent& uevent) const;
std::string GetFirmwarePath(const Uevent& uevent) const;
void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const;
diff --git a/init/first_stage_console.cpp b/init/first_stage_console.cpp
index 67cac1914..e2ea0ab40 100644
--- a/init/first_stage_console.cpp
+++ b/init/first_stage_console.cpp
@@ -85,10 +85,7 @@ namespace init {
void StartConsole(const std::string& cmdline) {
bool console = KernelConsolePresent(cmdline);
- // Use a simple sigchld handler -- first_stage_console doesn't need to track or log zombies
- const struct sigaction chld_act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDWAIT };
- sigaction(SIGCHLD, &chld_act, nullptr);
pid_t pid = fork();
if (pid != 0) {
int status;
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index d050ed783..78e5b60a1 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -27,7 +27,6 @@
#include <sys/utsname.h>
#include <unistd.h>
-#include <chrono>
#include <filesystem>
#include <string>
#include <vector>
@@ -108,39 +107,6 @@ bool ForceNormalBoot(const std::string& cmdline, const std::string& bootconfig)
cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
}
-static void Copy(const char* src, const char* dst) {
- if (link(src, dst) == 0) {
- LOG(INFO) << "hard linking " << src << " to " << dst << " succeeded";
- return;
- }
- PLOG(FATAL) << "hard linking " << src << " to " << dst << " failed";
-}
-
-// Move snapuserd before switching root, so that it is available at the same path
-// after switching root.
-void PrepareSwitchRoot() {
- constexpr const char* src = "/system/bin/snapuserd";
- constexpr const char* dst = "/first_stage_ramdisk/system/bin/snapuserd";
-
- if (access(dst, X_OK) == 0) {
- LOG(INFO) << dst << " already exists and it can be executed";
- return;
- }
-
- if (access(src, F_OK) != 0) {
- PLOG(INFO) << "Not moving " << src << " because it cannot be accessed";
- return;
- }
-
- auto dst_dir = android::base::Dirname(dst);
- std::error_code ec;
- if (access(dst_dir.c_str(), F_OK) != 0) {
- if (!fs::create_directories(dst_dir, ec)) {
- LOG(FATAL) << "Cannot create " << dst_dir << ": " << ec.message();
- }
- }
- Copy(src, dst);
-}
} // namespace
std::string GetModuleLoadList(bool recovery, const std::string& dir_path) {
@@ -157,7 +123,7 @@ std::string GetModuleLoadList(bool recovery, const std::string& dir_path) {
}
#define MODULE_BASE_DIR "/lib/modules"
-bool LoadKernelModules(bool recovery, bool want_console, bool want_parallel, int& modules_loaded) {
+bool LoadKernelModules(bool recovery, bool want_console, int& modules_loaded) {
struct utsname uts;
if (uname(&uts)) {
LOG(FATAL) << "Failed to get kernel version.";
@@ -206,8 +172,7 @@ bool LoadKernelModules(bool recovery, bool want_console, bool want_parallel, int
}
Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(recovery, MODULE_BASE_DIR));
- bool retval = (want_parallel) ? m.LoadModulesParallel(std::thread::hardware_concurrency())
- : m.LoadListedModules(!want_console);
+ bool retval = m.LoadListedModules(!want_console);
modules_loaded = m.GetModuleCount();
if (modules_loaded > 0) {
return retval;
@@ -289,9 +254,6 @@ int FirstStageMain(int argc, char** argv) {
// stage init
CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=0"))
-
- // First stage init stores Mainline sepolicy here.
- CHECKCALL(mkdir("/dev/selinux", 0744));
#undef CHECKCALL
SetStdioToDevNull(argv);
@@ -320,13 +282,11 @@ int FirstStageMain(int argc, char** argv) {
}
auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0;
- auto want_parallel =
- bootconfig.find("androidboot.load_modules_parallel = \"true\"") != std::string::npos;
boot_clock::time_point module_start_time = boot_clock::now();
int module_count = 0;
if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), want_console,
- want_parallel, module_count)) {
+ module_count)) {
if (want_console != FirstStageConsoleParam::DISABLED) {
LOG(ERROR) << "Failed to load kernel modules, starting console";
} else {
@@ -341,11 +301,12 @@ int FirstStageMain(int argc, char** argv) {
<< module_elapse_time.count() << " ms";
}
+
bool created_devices = false;
if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
if (!IsRecoveryMode()) {
created_devices = DoCreateDevices();
- if (!created_devices) {
+ if (!created_devices){
LOG(ERROR) << "Failed to create device nodes early";
}
}
@@ -369,30 +330,22 @@ int FirstStageMain(int argc, char** argv) {
// If "/force_debuggable" is present, the second-stage init will use a userdebug
// sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked.
if (access("/force_debuggable", F_OK) == 0) {
- constexpr const char adb_debug_prop_src[] = "/adb_debug.prop";
- constexpr const char userdebug_plat_sepolicy_cil_src[] = "/userdebug_plat_sepolicy.cil";
std::error_code ec; // to invoke the overloaded copy_file() that won't throw.
- if (access(adb_debug_prop_src, F_OK) == 0 &&
- !fs::copy_file(adb_debug_prop_src, kDebugRamdiskProp, ec)) {
- LOG(WARNING) << "Can't copy " << adb_debug_prop_src << " to " << kDebugRamdiskProp
- << ": " << ec.message();
- }
- if (access(userdebug_plat_sepolicy_cil_src, F_OK) == 0 &&
- !fs::copy_file(userdebug_plat_sepolicy_cil_src, kDebugRamdiskSEPolicy, ec)) {
- LOG(WARNING) << "Can't copy " << userdebug_plat_sepolicy_cil_src << " to "
- << kDebugRamdiskSEPolicy << ": " << ec.message();
+ if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) ||
+ !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) {
+ LOG(ERROR) << "Failed to setup debug ramdisk";
+ } else {
+ // setenv for second-stage init to read above kDebugRamdisk* files.
+ setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
}
- // setenv for second-stage init to read above kDebugRamdisk* files.
- setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
}
if (ForceNormalBoot(cmdline, bootconfig)) {
mkdir("/first_stage_ramdisk", 0755);
- PrepareSwitchRoot();
// SwitchRoot() must be called with a mount point as the target, so we bind mount the
// target directory to itself here.
if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
- PLOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
+ LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
}
SwitchRoot("/first_stage_ramdisk");
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 042988eff..f5c10bbd4 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -81,7 +81,8 @@ class FirstStageMount {
FirstStageMount(Fstab fstab);
virtual ~FirstStageMount() = default;
- // The factory method to create a FirstStageMountVBootV2 instance.
+ // The factory method to create either FirstStageMountVBootV1 or FirstStageMountVBootV2
+ // based on device tree configurations.
static Result<std::unique_ptr<FirstStageMount>> Create();
bool DoCreateDevices(); // Creates devices and logical partitions from storage devices
bool DoFirstStageMount(); // Mounts fstab entries read from device tree.
@@ -124,6 +125,16 @@ class FirstStageMount {
std::map<std::string, std::vector<std::string>> preload_avb_key_blobs_;
};
+class FirstStageMountVBootV1 : public FirstStageMount {
+ public:
+ FirstStageMountVBootV1(Fstab fstab) : FirstStageMount(std::move(fstab)) {}
+ ~FirstStageMountVBootV1() override = default;
+
+ protected:
+ bool GetDmVerityDevices(std::set<std::string>* devices) override;
+ bool SetUpDmVerity(FstabEntry* fstab_entry) override;
+};
+
class FirstStageMountVBootV2 : public FirstStageMount {
public:
friend void SetInitAvbVersionInRecovery();
@@ -191,6 +202,8 @@ static bool GetRootEntry(FstabEntry* root_entry) {
auto& dm = android::dm::DeviceMapper::Instance();
if (dm.GetState("vroot") != android::dm::DmDeviceState::INVALID) {
root_entry->fs_mgr_flags.avb = true;
+ } else {
+ root_entry->fs_mgr_flags.verify = true;
}
return true;
}
@@ -230,7 +243,11 @@ Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {
return fstab.error();
}
- return std::make_unique<FirstStageMountVBootV2>(std::move(*fstab));
+ if (IsDtVbmetaCompatible(*fstab)) {
+ return std::make_unique<FirstStageMountVBootV2>(std::move(*fstab));
+ } else {
+ return std::make_unique<FirstStageMountVBootV1>(std::move(*fstab));
+ }
}
bool FirstStageMount::DoCreateDevices() {
@@ -374,11 +391,7 @@ bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) {
use_snapuserd_ = sm->IsSnapuserdRequired();
if (use_snapuserd_) {
- if (sm->UpdateUsesUserSnapshots()) {
- LaunchFirstStageSnapuserd(SnapshotDriver::DM_USER);
- } else {
- LaunchFirstStageSnapuserd(SnapshotDriver::DM_SNAPSHOT);
- }
+ LaunchFirstStageSnapuserd();
}
sm->SetUeventRegenCallback([this](const std::string& device) -> bool {
@@ -662,6 +675,56 @@ void FirstStageMount::UseDsuIfPresent() {
TransformFstabForDsu(&fstab_, active_dsu, dsu_partitions);
}
+bool FirstStageMountVBootV1::GetDmVerityDevices(std::set<std::string>* devices) {
+ need_dm_verity_ = false;
+
+ for (const auto& fstab_entry : fstab_) {
+ // Don't allow verifyatboot in the first stage.
+ if (fstab_entry.fs_mgr_flags.verify_at_boot) {
+ LOG(ERROR) << "Partitions can't be verified at boot";
+ return false;
+ }
+ // Checks for verified partitions.
+ if (fstab_entry.fs_mgr_flags.verify) {
+ need_dm_verity_ = true;
+ }
+ }
+
+ // Includes the partition names of fstab records.
+ // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
+ for (const auto& fstab_entry : fstab_) {
+ // Skip pseudo filesystems.
+ if (fstab_entry.fs_type == "overlay") {
+ continue;
+ }
+ if (!fstab_entry.fs_mgr_flags.logical) {
+ devices->emplace(basename(fstab_entry.blk_device.c_str()));
+ }
+ }
+
+ return true;
+}
+
+bool FirstStageMountVBootV1::SetUpDmVerity(FstabEntry* fstab_entry) {
+ if (fstab_entry->fs_mgr_flags.verify) {
+ int ret = fs_mgr_setup_verity(fstab_entry, false /* wait_for_verity_dev */);
+ switch (ret) {
+ case FS_MGR_SETUP_VERITY_SKIPPED:
+ case FS_MGR_SETUP_VERITY_DISABLED:
+ LOG(INFO) << "Verity disabled/skipped for '" << fstab_entry->mount_point << "'";
+ return true;
+ case FS_MGR_SETUP_VERITY_SUCCESS:
+ // The exact block device name (fstab_rec->blk_device) is changed to
+ // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
+ // first stage.
+ return block_dev_init_.InitDmDevice(fstab_entry->blk_device);
+ default:
+ return false;
+ }
+ }
+ return true; // Returns true to mount the partition.
+}
+
// First retrieve any vbmeta partitions from device tree (legacy) then read through the fstab
// for any further vbmeta partitions.
FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab)
diff --git a/init/host_builtin_map.py b/init/host_builtin_map.py
index 41c86ac8a..6afcb173c 100755
--- a/init/host_builtin_map.py
+++ b/init/host_builtin_map.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
"""Generates the builtins map to be used by host_init_verifier.
It copies the builtin function map from builtins.cpp, then replaces do_xxx() functions with the
@@ -39,7 +39,8 @@ for line in function_map:
match = DO_REGEX.match(line)
if match:
if match.group(1) in check_functions:
- line = line.replace('do_', 'check_')
+ print line.replace('do_', 'check_'),
else:
- line = FUNCTION_REGEX.sub('check_stub', line)
- print(line, end=' ')
+ print FUNCTION_REGEX.sub('check_stub', line),
+ else:
+ print line,
diff --git a/init/init.cpp b/init/init.cpp
index 29f643ebd..942feb939 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,10 +33,7 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
-#include <filesystem>
-#include <fstream>
#include <functional>
-#include <iostream>
#include <map>
#include <memory>
#include <mutex>
@@ -581,30 +578,13 @@ static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
HandlePowerctlMessage("shutdown,container");
}
-static constexpr std::chrono::milliseconds kDiagnosticTimeout = 10s;
-
-static void HandleSignalFd(bool one_off) {
+static void HandleSignalFd() {
signalfd_siginfo siginfo;
- auto started = std::chrono::steady_clock::now();
- do {
- ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
- if (bytes_read < 0 && errno == EAGAIN) {
- auto now = std::chrono::steady_clock::now();
- std::chrono::duration<double> waited = now - started;
- if (waited >= kDiagnosticTimeout) {
- LOG(ERROR) << "epoll() woke us up, but we waited with no SIGCHLD!";
- started = now;
- }
-
- std::this_thread::sleep_for(100ms);
- continue;
- }
- if (bytes_read != sizeof(siginfo)) {
- PLOG(ERROR) << "Failed to read siginfo from signal_fd";
- return;
- }
- break;
- } while (!one_off);
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
+ if (bytes_read != sizeof(siginfo)) {
+ PLOG(ERROR) << "Failed to read siginfo from signal_fd";
+ return;
+ }
switch (siginfo.ssi_signo) {
case SIGCHLD:
@@ -659,14 +639,12 @@ static void InstallSignalFdHandler(Epoll* epoll) {
LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
}
- signal_fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
+ signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
if (signal_fd == -1) {
PLOG(FATAL) << "failed to create signalfd";
}
- constexpr int flags = EPOLLIN | EPOLLPRI;
- auto handler = std::bind(HandleSignalFd, false);
- if (auto result = epoll->RegisterHandler(signal_fd, handler, flags); !result.ok()) {
+ if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result.ok()) {
LOG(FATAL) << result.error();
}
}
@@ -761,75 +739,11 @@ void SendLoadPersistentPropertiesMessage() {
}
}
-static Result<void> ConnectEarlyStageSnapuserdAction(const BuiltinArguments& args) {
- auto pid = GetSnapuserdFirstStagePid();
- if (!pid) {
- return {};
- }
-
- auto info = GetSnapuserdFirstStageInfo();
- if (auto iter = std::find(info.begin(), info.end(), "socket"s); iter == info.end()) {
- // snapuserd does not support socket handoff, so exit early.
- return {};
- }
-
- // Socket handoff is supported.
- auto svc = ServiceList::GetInstance().FindService("snapuserd");
- if (!svc) {
- LOG(FATAL) << "Failed to find snapuserd service entry";
- }
-
- svc->SetShutdownCritical();
- svc->SetStartedInFirstStage(*pid);
-
- svc = ServiceList::GetInstance().FindService("snapuserd_proxy");
- if (!svc) {
- LOG(FATAL) << "Failed find snapuserd_proxy service entry, merge will never initiate";
- }
- if (!svc->MarkSocketPersistent("snapuserd")) {
- LOG(FATAL) << "Could not find snapuserd socket in snapuserd_proxy service entry";
- }
- if (auto result = svc->Start(); !result.ok()) {
- LOG(FATAL) << "Could not start snapuserd_proxy: " << result.error();
- }
- return {};
-}
-
-static void DumpPidFds(const std::string& prefix, pid_t pid) {
- std::error_code ec;
- std::string proc_dir = "/proc/" + std::to_string(pid) + "/fd";
- for (const auto& entry : std::filesystem::directory_iterator(proc_dir)) {
- std::string target;
- if (android::base::Readlink(entry.path(), &target)) {
- LOG(ERROR) << prefix << target;
- } else {
- LOG(ERROR) << prefix << entry.path();
- }
- }
-}
-
-static void DumpFile(const std::string& prefix, const std::string& file) {
- std::ifstream fp(file);
- if (!fp) {
- LOG(ERROR) << "Could not open " << file;
- return;
- }
-
- std::string line;
- while (std::getline(fp, line)) {
- LOG(ERROR) << prefix << line;
- }
-}
-
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
- // No threads should be spin up until signalfd
- // is registered. If the threads are indeed required,
- // each of these threads _should_ make sure SIGCHLD signal
- // is blocked. See b/223076262
boot_clock::time_point start_time = boot_clock::now();
trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
@@ -953,7 +867,6 @@ int SecondStageMain(int argc, char** argv) {
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
- am.QueueBuiltinAction(ConnectEarlyStageSnapuserdAction, "ConnectEarlyStageSnapuserd");
am.QueueEventTrigger("early-init");
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
@@ -989,7 +902,7 @@ int SecondStageMain(int argc, char** argv) {
setpriority(PRIO_PROCESS, 0, 0);
while (true) {
// By default, sleep until something happens.
- auto epoll_timeout = std::optional<std::chrono::milliseconds>{kDiagnosticTimeout};
+ auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
auto shutdown_command = shutdown_state.CheckShutdown();
if (shutdown_command) {
@@ -1029,25 +942,6 @@ int SecondStageMain(int argc, char** argv) {
for (const auto& function : *pending_functions) {
(*function)();
}
- } else if (Service::is_exec_service_running()) {
- static bool dumped_diagnostics = false;
- std::chrono::duration<double> waited =
- std::chrono::steady_clock::now() - Service::exec_service_started();
- if (waited >= kDiagnosticTimeout) {
- LOG(ERROR) << "Exec service is hung? Waited " << waited.count()
- << " without SIGCHLD";
- if (!dumped_diagnostics) {
- DumpPidFds("exec service opened: ", Service::exec_service_pid());
-
- std::string status_file =
- "/proc/" + std::to_string(Service::exec_service_pid()) + "/status";
- DumpFile("exec service: ", status_file);
- dumped_diagnostics = true;
-
- LOG(INFO) << "Attempting to handle any stuck SIGCHLDs...";
- HandleSignalFd(true);
- }
- }
}
if (!IsShuttingDown()) {
HandleControlMessages();
diff --git a/init/main.cpp b/init/main.cpp
index b01a3eeb2..23f5530fe 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -25,11 +25,9 @@
#if __has_feature(address_sanitizer)
#include <sanitizer/asan_interface.h>
-#elif __has_feature(hwaddress_sanitizer)
-#include <sanitizer/hwasan_interface.h>
#endif
-#if __has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer)
+#if __has_feature(address_sanitizer)
// Load asan.options if it exists since these are not yet in the environment.
// Always ensure detect_container_overflow=0 as there are false positives with this check.
// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
@@ -53,8 +51,6 @@ using namespace android::init;
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
-#elif __has_feature(hwaddress_sanitizer)
- __hwasan_set_error_report_callback(AsanReportCallback);
#endif
// Boost prio which will be restored later
setpriority(PRIO_PROCESS, 0, -20);
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index 227ce2fe4..46f833104 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -25,7 +25,6 @@
#include <unistd.h>
#include <algorithm>
-#include <filesystem>
#include <string>
#include <utility>
#include <vector>
@@ -33,7 +32,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <fs_mgr.h>
#include <fstab/fstab.h>
@@ -41,9 +39,6 @@
#include "epoll.h"
-using android::base::Basename;
-using android::base::StringPrintf;
-
namespace android {
namespace init {
@@ -72,82 +67,35 @@ MountHandlerEntry ParseMount(const std::string& line) {
return MountHandlerEntry(fields[0], fields[1], fields[2]);
}
-// return sda25 for dm-4, sda25 for sda25, or mmcblk0p24 for mmcblk0p24
-std::string GetDiskPart(std::string blockdev) {
- if (blockdev.find('/') != std::string::npos) return {};
-
- while (android::base::StartsWith(blockdev, "dm-")) {
- auto& dm = dm::DeviceMapper::Instance();
- std::optional<std::string> parent = dm.GetParentBlockDeviceByPath("/dev/block/" + blockdev);
- if (parent) {
- blockdev = android::base::Basename(*parent);
- } else {
- return {};
- }
- }
- return blockdev;
-}
-
-// return sda for sda25, or mmcblk0 for mmcblk0p24
-std::string GetRootDisk(std::string blockdev) {
- if (blockdev.empty()) return {};
- if (blockdev.find('/') != std::string::npos) return {};
-
- std::error_code ec;
- for (const auto& entry : std::filesystem::directory_iterator("/sys/block", ec)) {
- const std::string path = entry.path().string();
- if (std::filesystem::exists(StringPrintf("%s/%s", path.c_str(), blockdev.c_str()))) {
- return Basename(path);
- }
- }
- return {};
-}
-
void SetMountProperty(const MountHandlerEntry& entry, bool add) {
static constexpr char devblock[] = "/dev/block/";
if (!android::base::StartsWith(entry.blk_device, devblock)) return;
- auto target = entry.blk_device.substr(strlen(devblock));
- std::string diskpart, rootdisk;
+ std::string value;
if (add) {
- diskpart = GetDiskPart(target);
- rootdisk = GetRootDisk(diskpart);
-
+ value = entry.blk_device.substr(strlen(devblock));
+ if (android::base::StartsWith(value, "sd")) {
+ // All sd partitions inherit their queue characteristics
+ // from the whole device reference. Strip partition number.
+ auto it = std::find_if(value.begin(), value.end(), [](char c) { return isdigit(c); });
+ if (it != value.end()) value.erase(it, value.end());
+ }
+ auto queue = "/sys/block/" + value + "/queue";
struct stat sb;
- if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) rootdisk = "";
+ if (stat(queue.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
+ if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
// Clear the noise associated with loopback and APEX.
- if (android::base::StartsWith(target, "loop")) rootdisk = "";
- if (android::base::StartsWith(entry.mount_point, "/apex/")) rootdisk = "";
+ if (android::base::StartsWith(value, "loop")) value = "";
+ if (android::base::StartsWith(entry.mount_point, "/apex/")) value = "";
}
auto mount_prop = entry.mount_point;
if (mount_prop == "/") mount_prop = "/root";
std::replace(mount_prop.begin(), mount_prop.end(), '/', '.');
- auto blk_mount_prop = "dev.mnt.blk" + mount_prop;
- auto dev_mount_prop = "dev.mnt.dev" + mount_prop;
- auto rootdisk_mount_prop = "dev.mnt.rootdisk" + mount_prop;
- // Set property even if its rootdisk does not change to trigger 'on property:'
+ mount_prop = "dev.mnt.blk" + mount_prop;
+ // Set property even if its value does not change to trigger 'on property:'
// handling, except for clearing non-existent or already clear property.
// Goal is reduction of empty properties and associated triggers.
- if (rootdisk.empty() && android::base::GetProperty(blk_mount_prop, "").empty()) return;
-
- if (rootdisk.empty()) {
- android::base::SetProperty(blk_mount_prop, "");
- android::base::SetProperty(dev_mount_prop, "");
- android::base::SetProperty(rootdisk_mount_prop, "");
- return;
- }
-
- // 1. dm-N
- // dev.mnt.dev.data = dm-N
- // dev.mnt.blk.data = sdaN or mmcblk0pN
- // dev.mnt.rootdisk.data = sda or mmcblk0
- //
- // 2. sdaN or mmcblk0pN
- // dev.mnt.dev.data = sdaN or mmcblk0pN
- // dev.mnt.blk.data = sdaN or mmcblk0pN
- // dev.mnt.rootdisk.data = sda or mmcblk0
- android::base::SetProperty(dev_mount_prop, target);
- android::base::SetProperty(blk_mount_prop, diskpart);
- android::base::SetProperty(rootdisk_mount_prop, rootdisk);
+ if (value.empty() && android::base::GetProperty(mount_prop, "").empty()) return;
+ android::base::SetProperty(mount_prop, value);
}
} // namespace
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index bce1cc3de..2a578082b 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -82,16 +82,110 @@ static bool IsApexUpdatable() {
return updatable;
}
-// In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount
-// namespaces.
-static bool NeedsTwoMountNamespaces() {
- if (!IsApexUpdatable()) return false;
- if (IsRecoveryMode()) return false;
- // In microdroid, there's only one set of APEXes in built-in directories include block devices.
- if (IsMicrodroid()) return false;
+#ifdef ACTIVATE_FLATTENED_APEX
+
+static Result<void> MountDir(const std::string& path, const std::string& mount_path) {
+ if (int ret = mkdir(mount_path.c_str(), 0755); ret != 0 && errno != EEXIST) {
+ return ErrnoError() << "Could not create mount point " << mount_path;
+ }
+ if (mount(path.c_str(), mount_path.c_str(), nullptr, MS_BIND, nullptr) != 0) {
+ return ErrnoError() << "Could not bind mount " << path << " to " << mount_path;
+ }
+ return {};
+}
+
+static Result<apex::proto::ApexManifest> GetApexManifest(const std::string& apex_dir) {
+ const std::string manifest_path = apex_dir + "/apex_manifest.pb";
+ std::string content;
+ if (!android::base::ReadFileToString(manifest_path, &content)) {
+ return Error() << "Failed to read manifest file: " << manifest_path;
+ }
+ apex::proto::ApexManifest manifest;
+ if (!manifest.ParseFromString(content)) {
+ return Error() << "Can't parse manifest file: " << manifest_path;
+ }
+ return manifest;
+}
+
+template <typename Fn>
+static Result<void> ActivateFlattenedApexesFrom(const std::string& from_dir,
+ const std::string& to_dir, Fn on_activate) {
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(from_dir.c_str()), closedir);
+ if (!dir) {
+ return {};
+ }
+ dirent* entry;
+ std::vector<std::string> entries;
+
+ while ((entry = readdir(dir.get())) != nullptr) {
+ if (entry->d_name[0] == '.') continue;
+ if (entry->d_type == DT_DIR) {
+ entries.push_back(entry->d_name);
+ }
+ }
+
+ std::sort(entries.begin(), entries.end());
+ for (const auto& name : entries) {
+ const std::string apex_path = from_dir + "/" + name;
+ const auto apex_manifest = GetApexManifest(apex_path);
+ if (!apex_manifest.ok()) {
+ LOG(ERROR) << apex_path << " is not an APEX directory: " << apex_manifest.error();
+ continue;
+ }
+ const std::string mount_path = to_dir + "/" + apex_manifest->name();
+ if (auto result = MountDir(apex_path, mount_path); !result.ok()) {
+ return result;
+ }
+ on_activate(apex_path, *apex_manifest);
+ }
+ return {};
+}
+
+static bool ActivateFlattenedApexesIfPossible() {
+ if (IsRecoveryMode() || IsApexUpdatable()) {
+ return true;
+ }
+
+ const std::string kApexTop = "/apex";
+ const std::vector<std::string> kBuiltinDirsForApexes = {
+ "/system/apex",
+ "/system_ext/apex",
+ "/product/apex",
+ "/vendor/apex",
+ };
+
+ std::vector<com::android::apex::ApexInfo> apex_infos;
+ auto on_activate = [&](const std::string& apex_path,
+ const apex::proto::ApexManifest& apex_manifest) {
+ apex_infos.emplace_back(apex_manifest.name(), apex_path, apex_path, apex_manifest.version(),
+ apex_manifest.versionname(), /*isFactory=*/true, /*isActive=*/true,
+ /* lastUpdateMillis= */ 0);
+ };
+
+ for (const auto& dir : kBuiltinDirsForApexes) {
+ if (auto result = ActivateFlattenedApexesFrom(dir, kApexTop, on_activate); !result.ok()) {
+ LOG(ERROR) << result.error();
+ return false;
+ }
+ }
+
+ std::ostringstream oss;
+ com::android::apex::ApexInfoList apex_info_list(apex_infos);
+ com::android::apex::write(oss, apex_info_list);
+ const std::string kApexInfoList = kApexTop + "/apex-info-list.xml";
+ if (!android::base::WriteStringToFile(oss.str(), kApexInfoList)) {
+ PLOG(ERROR) << "Failed to write " << kApexInfoList;
+ return false;
+ }
+ if (selinux_android_restorecon(kApexInfoList.c_str(), 0) != 0) {
+ PLOG(ERROR) << "selinux_android_restorecon(" << kApexInfoList << ") failed";
+ }
+
return true;
}
+#endif // ACTIVATE_FLATTENED_APEX
+
static android::base::unique_fd bootstrap_ns_fd;
static android::base::unique_fd default_ns_fd;
@@ -166,7 +260,7 @@ bool SetupMountNamespaces() {
// number of essential APEXes (e.g. com.android.runtime) are activated.
// In the namespace for post-apexd processes, all APEXes are activated.
bool success = true;
- if (NeedsTwoMountNamespaces()) {
+ if (IsApexUpdatable() && !IsRecoveryMode()) {
// Creating a new namespace by cloning, saving, and switching back to
// the original namespace.
if (unshare(CLONE_NEWNS) == -1) {
@@ -185,7 +279,9 @@ bool SetupMountNamespaces() {
default_ns_fd.reset(OpenMountNamespace());
default_ns_id = GetMountNamespaceId();
}
-
+#ifdef ACTIVATE_FLATTENED_APEX
+ success &= ActivateFlattenedApexesIfPossible();
+#endif
LOG(INFO) << "SetupMountNamespaces done";
return success;
}
diff --git a/init/parser.cpp b/init/parser.cpp
index abc201742..5c18551e1 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -18,8 +18,6 @@
#include <dirent.h>
-#include <map>
-
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -156,58 +154,6 @@ bool Parser::ParseConfigFile(const std::string& path) {
return true;
}
-std::vector<std::string> Parser::FilterVersionedConfigs(const std::vector<std::string>& configs,
- int active_sdk) {
- std::vector<std::string> filtered_configs;
-
- std::map<std::string, std::pair<std::string, int>> script_map;
- for (const auto& c : configs) {
- int sdk = 0;
- const std::vector<std::string> parts = android::base::Split(c, ".");
- std::string base;
- if (parts.size() < 2) {
- continue;
- }
-
- // parts[size()-1], aka the suffix, should be "rc" or "#rc"
- // any other pattern gets discarded
-
- const auto& suffix = parts[parts.size() - 1];
- if (suffix == "rc") {
- sdk = 0;
- } else {
- char trailer[9] = {0};
- int r = sscanf(suffix.c_str(), "%d%8s", &sdk, trailer);
- if (r != 2) {
- continue;
- }
- if (strlen(trailer) > 2 || strcmp(trailer, "rc") != 0) {
- continue;
- }
- }
-
- if (sdk < 0 || sdk > active_sdk) {
- continue;
- }
-
- base = parts[0];
- for (unsigned int i = 1; i < parts.size() - 1; i++) {
- base = base + "." + parts[i];
- }
-
- // is this preferred over what we already have
- auto it = script_map.find(base);
- if (it == script_map.end() || it->second.second < sdk) {
- script_map[base] = std::make_pair(c, sdk);
- }
- }
-
- for (const auto& m : script_map) {
- filtered_configs.push_back(m.second.first);
- }
- return filtered_configs;
-}
-
bool Parser::ParseConfigDir(const std::string& path) {
LOG(INFO) << "Parsing directory " << path << "...";
std::unique_ptr<DIR, decltype(&closedir)> config_dir(opendir(path.c_str()), closedir);
diff --git a/init/parser.h b/init/parser.h
index 2f4108fd0..95b0cd76e 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -76,12 +76,6 @@ class Parser {
void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
void AddSingleLineParser(const std::string& prefix, LineCallback callback);
- // Compare all files */path.#rc and */path.rc with the same path prefix.
- // Keep the one with the highest # that doesn't exceed the system's SDK.
- // (.rc == .0rc for ranking purposes)
- std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
- int active_sdk);
-
// Host init verifier check file permissions.
bool ParseConfigFileInsecure(const std::string& path);
diff --git a/init/perfboot.py b/init/perfboot.py
index 968df38a1..4b23ad28c 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,7 +39,7 @@ $ ./perfboot.py --iterations=30 -v --output=data.tsv --tags=eventtags.txt
import argparse
import atexit
-import io
+import cStringIO
import glob
import inspect
import logging
@@ -102,7 +102,7 @@ class IntervalAdjuster(object):
self._wait_cpu_cool_down(self._product, self._temp_paths)
else:
if self._waited:
- print('Waiting for %d seconds' % self._interval)
+ print 'Waiting for %d seconds' % self._interval
time.sleep(self._interval)
self._waited = True
@@ -119,9 +119,9 @@ class IntervalAdjuster(object):
threshold = IntervalAdjuster._CPU_COOL_DOWN_THRESHOLDS.get(
self._product)
if threshold is None:
- print('No CPU temperature threshold is set for ' + self._product)
- print(('Just wait %d seconds' %
- IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT))
+ print 'No CPU temperature threshold is set for ' + self._product
+ print ('Just wait %d seconds' %
+ IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT)
time.sleep(IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT)
return
while True:
@@ -129,8 +129,8 @@ class IntervalAdjuster(object):
if temp < threshold:
logging.info('Current CPU temperature %s' % temp)
return
- print('Waiting until CPU temperature (%d) falls below %d' % (
- temp, threshold))
+ print 'Waiting until CPU temperature (%d) falls below %d' % (
+ temp, threshold)
time.sleep(IntervalAdjuster._CPU_COOL_DOWN_WAIT_INTERVAL)
@@ -260,7 +260,7 @@ def filter_event_tags(tags, device):
def get_values(record, tag):
"""Gets values that matches |tag| from |record|."""
- keys = [key for key in list(record.keys()) if key[0] == tag]
+ keys = [key for key in record.keys() if key[0] == tag]
return [record[k] for k in sorted(keys)]
@@ -304,7 +304,7 @@ def output_results(filename, record_list, tags):
with open(filename, 'w') as f:
f.write('\t'.join(labels) + '\n')
for record in record_list:
- line = io.StringIO()
+ line = cStringIO.StringIO()
invalid_line = False
for i, tag in enumerate(tags):
if i != 0:
@@ -319,7 +319,7 @@ def output_results(filename, record_list, tags):
logging.error('Invalid record found: ' + line.getvalue())
line.write('\n')
f.write(line.getvalue())
- print(('Wrote: ' + filename))
+ print 'Wrote: ' + filename
def median(data):
@@ -349,9 +349,9 @@ def print_summary(record_list, end_tag):
# Filter out invalid data.
end_times = [get_last_value(record, end_tag) for record in record_list
if get_last_value(record, end_tag) != 0]
- print(('mean:', int(round(mean(end_times))), 'ms'))
- print(('median:', int(round(median(end_times))), 'ms'))
- print(('standard deviation:', int(round(stddev(end_times))), 'ms'))
+ print 'mean:', int(round(mean(end_times))), 'ms'
+ print 'median:', int(round(median(end_times))), 'ms'
+ print 'standard deviation:', int(round(stddev(end_times))), 'ms'
def do_iteration(device, interval_adjuster, event_tags_re, end_tag):
@@ -359,7 +359,7 @@ def do_iteration(device, interval_adjuster, event_tags_re, end_tag):
device.wait()
interval_adjuster.wait()
device.reboot()
- print('Rebooted the device, waiting for tag', end_tag)
+ print 'Rebooted the device'
record = {}
booted = False
while not booted:
@@ -372,7 +372,7 @@ def do_iteration(device, interval_adjuster, event_tags_re, end_tag):
stdout=subprocess.PIPE)
for line in readlines_unbuffered(p):
if t.is_timedout():
- print('*** Timed out ***')
+ print '*** Timed out ***'
return record
m = event_tags_re.search(line)
if not m:
@@ -381,8 +381,8 @@ def do_iteration(device, interval_adjuster, event_tags_re, end_tag):
event_time = int(m.group('time'))
pid = m.group('pid')
record[(tag, pid)] = event_time
- print(('Event log recorded: %s (%s) - %d ms' % (
- tag, pid, event_time)))
+ print 'Event log recorded: %s (%s) - %d ms' % (
+ tag, pid, event_time)
if tag == end_tag:
booted = True
t.cancel()
@@ -420,7 +420,7 @@ def parse_args():
def install_apks(device, apk_dir):
for apk in glob.glob(os.path.join(apk_dir, '*.apk')):
- print('Installing: ' + apk)
+ print 'Installing: ' + apk
device.install(apk, replace=True)
@@ -452,7 +452,7 @@ def main():
event_tags_re = make_event_tags_re(event_tags)
for i in range(args.iterations):
- print('Run #%d ' % i)
+ print 'Run #%d ' % i
record = do_iteration(
device, interval_adjuster, event_tags_re, end_tag)
record_list.append(record)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 9f7c21543..2d67bf5d7 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -100,7 +100,6 @@ constexpr auto ID_PROP = "ro.build.id";
constexpr auto LEGACY_ID_PROP = "ro.build.legacy.id";
constexpr auto VBMETA_DIGEST_PROP = "ro.boot.vbmeta.digest";
constexpr auto DIGEST_SIZE_USED = 8;
-constexpr auto API_LEVEL_CURRENT = 10000;
static bool persistent_properties_loaded = false;
@@ -1018,39 +1017,6 @@ static void property_initialize_ro_cpu_abilist() {
}
}
-static int read_api_level_props(const std::vector<std::string>& api_level_props) {
- int api_level = API_LEVEL_CURRENT;
- for (const auto& api_level_prop : api_level_props) {
- api_level = android::base::GetIntProperty(api_level_prop, API_LEVEL_CURRENT);
- if (api_level != API_LEVEL_CURRENT) {
- break;
- }
- }
- return api_level;
-}
-
-static void property_initialize_ro_vendor_api_level() {
- // ro.vendor.api_level shows the api_level that the vendor images (vendor, odm, ...) are
- // required to support.
- constexpr auto VENDOR_API_LEVEL_PROP = "ro.vendor.api_level";
-
- // Api level properties of the board. The order of the properties must be kept.
- std::vector<std::string> BOARD_API_LEVEL_PROPS = {"ro.board.api_level",
- "ro.board.first_api_level"};
- // Api level properties of the device. The order of the properties must be kept.
- std::vector<std::string> DEVICE_API_LEVEL_PROPS = {"ro.product.first_api_level",
- "ro.build.version.sdk"};
-
- int api_level = std::min(read_api_level_props(BOARD_API_LEVEL_PROPS),
- read_api_level_props(DEVICE_API_LEVEL_PROPS));
- std::string error;
- uint32_t res = PropertySet(VENDOR_API_LEVEL_PROP, std::to_string(api_level), &error);
- if (res != PROP_SUCCESS) {
- LOG(ERROR) << "Failed to set " << VENDOR_API_LEVEL_PROP << " with " << api_level << ": "
- << error << "(" << res << ")";
- }
-}
-
void PropertyLoadBootDefaults() {
// We read the properties and their values into a map, in order to always allow properties
// loaded in the later property files to override the properties in loaded in the earlier
@@ -1107,7 +1073,6 @@ void PropertyLoadBootDefaults() {
LoadPropertiesFromSecondStageRes(&properties);
load_properties_from_file("/system/build.prop", nullptr, &properties);
load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
- load_properties_from_file("/system_dlkm/etc/build.prop", nullptr, &properties);
// TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
// all updated.
// if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
@@ -1137,7 +1102,6 @@ void PropertyLoadBootDefaults() {
property_derive_build_fingerprint();
property_derive_legacy_build_fingerprint();
property_initialize_ro_cpu_abilist();
- property_initialize_ro_vendor_api_level();
update_sys_usb_config();
}
@@ -1172,15 +1136,14 @@ void CreateSerializedPropertyInfo() {
// Don't check for failure here, since we don't always have all of these partitions.
// E.g. In case of recovery, the vendor partition will not have mounted and we
// still need the system / platform properties to function.
- if (access("/dev/selinux/apex_property_contexts", R_OK) != -1) {
- LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos);
- }
if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) {
LoadPropertyInfoFromFile("/system_ext/etc/selinux/system_ext_property_contexts",
&property_infos);
}
- if (access("/vendor/etc/selinux/vendor_property_contexts", R_OK) != -1) {
- LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
+ if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
+ &property_infos)) {
+ // Fallback to nonplat_* if vendor_* doesn't exist.
+ LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",
&property_infos);
}
if (access("/product/etc/selinux/product_property_contexts", R_OK) != -1) {
@@ -1195,10 +1158,12 @@ void CreateSerializedPropertyInfo() {
return;
}
LoadPropertyInfoFromFile("/system_ext_property_contexts", &property_infos);
- LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos);
+ if (!LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos)) {
+ // Fallback to nonplat_* if vendor_* doesn't exist.
+ LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
+ }
LoadPropertyInfoFromFile("/product_property_contexts", &property_infos);
LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos);
- LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos);
}
auto serialized_contexts = std::string();
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
index 5f34cc4da..ac6b7b271 100644
--- a/init/property_service_test.cpp
+++ b/init/property_service_test.cpp
@@ -99,7 +99,7 @@ TEST(property_service, check_fingerprint_with_legacy_build_id) {
std::string vbmeta_digest = GetProperty("ro.boot.vbmeta.digest", "");
ASSERT_GE(vbmeta_digest.size(), 8u);
- std::string build_id = GetProperty("ro.build.id", "");
+ std::string build_id = GetProperty("ro.boot.build.id", "");
// Check that the build id is constructed with the prefix of vbmeta digest
std::string expected_build_id = legacy_build_id + "." + vbmeta_digest.substr(0, 8);
ASSERT_EQ(expected_build_id, build_id);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 41cf748d8..a0ae4b4d4 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -18,7 +18,6 @@
#include <dirent.h>
#include <fcntl.h>
-#include <linux/f2fs.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <mntent.h>
@@ -219,7 +218,7 @@ static void LogShutdownTime(UmountStat stat, Timer* t) {
<< stat;
}
-static bool IsDataMounted(const std::string& fstype) {
+static bool IsDataMounted() {
std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
if (fp == nullptr) {
PLOG(ERROR) << "Failed to open /proc/mounts";
@@ -228,7 +227,7 @@ static bool IsDataMounted(const std::string& fstype) {
mntent* mentry;
while ((mentry = getmntent(fp.get())) != nullptr) {
if (mentry->mnt_dir == "/data"s) {
- return fstype == "*" || mentry->mnt_type == fstype;
+ return true;
}
}
return false;
@@ -479,11 +478,6 @@ static Result<void> KillZramBackingDevice() {
// cut the last "\n"
backing_dev.erase(backing_dev.length() - 1);
- if (android::base::StartsWith(backing_dev, "none")) {
- LOG(INFO) << "No zram backing device configured";
- return {};
- }
-
// shutdown zram handle
Timer swap_timer;
LOG(INFO) << "swapoff() start...";
@@ -634,13 +628,12 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
// If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
// worry about unmounting it.
- if (!IsDataMounted("*")) {
+ if (!IsDataMounted()) {
sync();
RebootSystem(cmd, reboot_target);
abort();
}
- bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false);
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set<std::string> to_starts{"watchdogd"};
std::set<std::string> stop_first;
@@ -654,8 +647,6 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
<< "': " << result.error();
}
s->SetShutdownCritical();
- } else if (do_shutdown_animation) {
- continue;
} else if (s->IsShutdownCritical()) {
// Start shutdown critical service if not started.
if (auto result = s->Start(); !result.ok()) {
@@ -668,13 +659,14 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
}
// remaining operations (specifically fsck) may take a substantial duration
- if (!do_shutdown_animation && (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown)) {
+ if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
TurnOffBacklight();
}
Service* boot_anim = ServiceList::GetInstance().FindService("bootanim");
Service* surface_flinger = ServiceList::GetInstance().FindService("surfaceflinger");
if (boot_anim != nullptr && surface_flinger != nullptr && surface_flinger->IsRunning()) {
+ bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false);
if (do_shutdown_animation) {
SetProperty("service.bootanim.exit", "0");
@@ -759,16 +751,6 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
sem_post(&reboot_semaphore);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
- if (IsDataMounted("f2fs")) {
- uint32_t flag = F2FS_GOING_DOWN_FULLSYNC;
- unique_fd fd(TEMP_FAILURE_RETRY(open("/data", O_RDONLY)));
- int ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
- if (ret) {
- PLOG(ERROR) << "Shutdown /data: ";
- } else {
- LOG(INFO) << "Shutdown /data";
- }
- }
RebootSystem(cmd, reboot_target);
abort();
}
@@ -1048,20 +1030,6 @@ void HandlePowerctlMessage(const std::string& command) {
return;
}
}
- } else if (reboot_target == "quiescent") {
- bootloader_message boot = {};
- if (std::string err; !read_bootloader_message(&boot, &err)) {
- LOG(ERROR) << "Failed to read bootloader message: " << err;
- }
- // Update the boot command field if it's empty, and preserve
- // the other arguments in the bootloader message.
- if (!CommandIsPresent(&boot)) {
- strlcpy(boot.command, "boot-quiescent", sizeof(boot.command));
- if (std::string err; !write_bootloader_message(boot, &err)) {
- LOG(ERROR) << "Failed to set bootloader message: " << err;
- return;
- }
- }
} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
reboot_target == "fastboot") {
std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
diff --git a/init/selinux.cpp b/init/selinux.cpp
index be8c5542f..42d302324 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -26,29 +26,26 @@
// The monolithic policy variant is for legacy non-treble devices that contain a single SEPolicy
// file located at /sepolicy and is directly loaded into the kernel SELinux subsystem.
-// The split policy is for supporting treble devices and updateable apexes. It splits the SEPolicy
-// across files on /system/etc/selinux (the 'plat' portion of the policy), /vendor/etc/selinux
-// (the 'vendor' portion of the policy), /system_ext/etc/selinux, /product/etc/selinux,
-// /odm/etc/selinux, and /dev/selinux (the apex portion of policy). This is necessary to allow
-// images to be updated independently of the vendor image, while maintaining contributions from
-// multiple partitions in the SEPolicy. This is especially important for VTS testing, where the
-// SEPolicy on the Google System Image may not be identical to the system image shipped on a
-// vendor's device.
+// The split policy is for supporting treble devices. It splits the SEPolicy across files on
+// /system/etc/selinux (the 'plat' portion of the policy) and /vendor/etc/selinux (the 'nonplat'
+// portion of the policy). This is necessary to allow the system image to be updated independently
+// of the vendor image, while maintaining contributions from both partitions in the SEPolicy. This
+// is especially important for VTS testing, where the SEPolicy on the Google System Image may not be
+// identical to the system image shipped on a vendor's device.
// The split SEPolicy is loaded as described below:
// 1) There is a precompiled SEPolicy located at either /vendor/etc/selinux/precompiled_sepolicy or
// /odm/etc/selinux/precompiled_sepolicy if odm parition is present. Stored along with this file
-// are the sha256 hashes of the parts of the SEPolicy on /system, /system_ext, /product, and apex
-// that were used to compile this precompiled policy. The system partition contains a similar
-// sha256 of the parts of the SEPolicy that it currently contains. Symmetrically, system_ext,
-// product, and apex contain sha256 hashes of their SEPolicy. Init loads this
+// are the sha256 hashes of the parts of the SEPolicy on /system, /system_ext and /product that
+// were used to compile this precompiled policy. The system partition contains a similar sha256
+// of the parts of the SEPolicy that it currently contains. Symmetrically, system_ext and
+// product paritition contain sha256 hashes of their SEPolicy. The init loads this
// precompiled_sepolicy directly if and only if the hashes along with the precompiled SEPolicy on
-// /vendor or /odm match the hashes for system, system_ext, product, and apex SEPolicy,
-// respectively.
-// 2) If these hashes do not match, then either /system or /system_ext /product, or apex (or some of
-// them) have been updated out of sync with /vendor (or /odm if it is present) and the init needs
-// to compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it is used by
-// the OpenSplitPolicy() function below to compile the SEPolicy to a temp directory and load it.
+// /vendor or /odm match the hashes for system, system_ext and product SEPolicy, respectively.
+// 2) If these hashes do not match, then either /system or /system_ext or /product (or some of them)
+// have been updated out of sync with /vendor (or /odm if it is present) and the init needs to
+// compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it is used by the
+// OpenSplitPolicy() function below to compile the SEPolicy to a temp directory and load it.
// That function contains even more documentation with the specific implementation details of how
// the SEPolicy is compiled if needed.
@@ -61,25 +58,19 @@
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <fstream>
-#include <CertUtils.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/result.h>
-#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
-#include <fsverity_init.h>
#include <libgsi/libgsi.h>
#include <libsnapshot/snapshot.h>
-#include <mini_keyctl_utils.h>
#include <selinux/android.h>
-#include <ziparchive/zip_archive.h>
#include "block_dev_initializer.h"
#include "debug_ramdisk.h"
@@ -256,7 +247,6 @@ Result<std::string> FindPrecompiledSplitPolicy() {
precompiled_sepolicy + ".system_ext_sepolicy_and_mapping.sha256"},
{"/product/etc/selinux/product_sepolicy_and_mapping.sha256",
precompiled_sepolicy + ".product_sepolicy_and_mapping.sha256"},
- {"/dev/selinux/apex_sepolicy.sha256", precompiled_sepolicy + ".apex_sepolicy.sha256"},
};
for (const auto& [actual_id_path, precompiled_id_path] : sepolicy_hashes) {
@@ -305,44 +295,28 @@ bool IsSplitPolicyDevice() {
return access(plat_policy_cil_file, R_OK) != -1;
}
-std::optional<const char*> GetUserdebugPlatformPolicyFile() {
- // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
- const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
- if (force_debuggable_env && "true"s == force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
- const std::vector<const char*> debug_policy_candidates = {
-#if INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT == 1
- "/system_ext/etc/selinux/userdebug_plat_sepolicy.cil",
-#endif
- kDebugRamdiskSEPolicy,
- };
- for (const char* debug_policy : debug_policy_candidates) {
- if (access(debug_policy, F_OK) == 0) {
- return debug_policy;
- }
- }
- }
- return std::nullopt;
-}
-
struct PolicyFile {
unique_fd fd;
std::string path;
};
bool OpenSplitPolicy(PolicyFile* policy_file) {
- // IMPLEMENTATION NOTE: Split policy consists of three or more CIL files:
+ // IMPLEMENTATION NOTE: Split policy consists of three CIL files:
// * platform -- policy needed due to logic contained in the system image,
- // * vendor -- policy needed due to logic contained in the vendor image,
+ // * non-platform -- policy needed due to logic contained in the vendor image,
// * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
// with newer versions of platform policy.
- // * (optional) policy needed due to logic on product, system_ext, odm, or apex.
+ //
// secilc is invoked to compile the above three policy files into a single monolithic policy
// file. This file is then loaded into the kernel.
- const auto userdebug_plat_sepolicy = GetUserdebugPlatformPolicyFile();
- const bool use_userdebug_policy = userdebug_plat_sepolicy.has_value();
+ // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
+ const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
+ bool use_userdebug_policy =
+ ((force_debuggable_env && "true"s == force_debuggable_env) &&
+ AvbHandle::IsDeviceUnlocked() && access(kDebugRamdiskSEPolicy, F_OK) == 0);
if (use_userdebug_policy) {
- LOG(INFO) << "Using userdebug system sepolicy " << *userdebug_plat_sepolicy;
+ LOG(WARNING) << "Using userdebug system sepolicy";
}
// Load precompiled policy from vendor image, if a matching policy is found there. The policy
@@ -414,14 +388,17 @@ bool OpenSplitPolicy(PolicyFile* policy_file) {
product_mapping_file.clear();
}
+ // vendor_sepolicy.cil and plat_pub_versioned.cil are the new design to replace
+ // nonplat_sepolicy.cil.
+ std::string plat_pub_versioned_cil_file("/vendor/etc/selinux/plat_pub_versioned.cil");
std::string vendor_policy_cil_file("/vendor/etc/selinux/vendor_sepolicy.cil");
- if (access(vendor_policy_cil_file.c_str(), F_OK) == -1) {
- LOG(ERROR) << "Missing " << vendor_policy_cil_file;
- return false;
- }
- std::string plat_pub_versioned_cil_file("/vendor/etc/selinux/plat_pub_versioned.cil");
- if (access(plat_pub_versioned_cil_file.c_str(), F_OK) == -1) {
+ if (access(vendor_policy_cil_file.c_str(), F_OK) == -1) {
+ // For backward compatibility.
+ // TODO: remove this after no device is using nonplat_sepolicy.cil.
+ vendor_policy_cil_file = "/vendor/etc/selinux/nonplat_sepolicy.cil";
+ plat_pub_versioned_cil_file.clear();
+ } else if (access(plat_pub_versioned_cil_file.c_str(), F_OK) == -1) {
LOG(ERROR) << "Missing " << plat_pub_versioned_cil_file;
return false;
}
@@ -431,18 +408,12 @@ bool OpenSplitPolicy(PolicyFile* policy_file) {
if (access(odm_policy_cil_file.c_str(), F_OK) == -1) {
odm_policy_cil_file.clear();
}
-
- // apex_sepolicy.cil is default but optional.
- std::string apex_policy_cil_file("/dev/selinux/apex_sepolicy.cil");
- if (access(apex_policy_cil_file.c_str(), F_OK) == -1) {
- apex_policy_cil_file.clear();
- }
const std::string version_as_string = std::to_string(SEPOLICY_VERSION);
// clang-format off
std::vector<const char*> compile_args {
"/system/bin/secilc",
- use_userdebug_policy ? *userdebug_plat_sepolicy : plat_policy_cil_file,
+ use_userdebug_policy ? kDebugRamdiskSEPolicy: plat_policy_cil_file,
"-m", "-M", "true", "-G", "-N",
"-c", version_as_string.c_str(),
plat_mapping_file.c_str(),
@@ -479,9 +450,6 @@ bool OpenSplitPolicy(PolicyFile* policy_file) {
if (!odm_policy_cil_file.empty()) {
compile_args.push_back(odm_policy_cil_file.c_str());
}
- if (!apex_policy_cil_file.empty()) {
- compile_args.push_back(apex_policy_cil_file.c_str());
- }
compile_args.push_back(nullptr);
if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) {
@@ -508,197 +476,6 @@ bool OpenMonolithicPolicy(PolicyFile* policy_file) {
return true;
}
-constexpr const char* kSigningCertRelease =
- "/system/etc/selinux/com.android.sepolicy.cert-release.der";
-constexpr const char* kFsVerityProcPath = "/proc/sys/fs/verity";
-const std::string kSepolicyApexMetadataDir = "/metadata/sepolicy/";
-const std::string kSepolicyApexSystemDir = "/system/etc/selinux/apex/";
-const std::string kSepolicyZip = "SEPolicy.zip";
-const std::string kSepolicySignature = "SEPolicy.zip.sig";
-
-const std::string kTmpfsDir = "/dev/selinux/";
-
-// Files that are deleted after policy is compiled/loaded.
-const std::vector<std::string> kApexSepolicyTmp{"apex_sepolicy.cil", "apex_sepolicy.sha256"};
-// Files that need to persist because they are used by userspace processes.
-const std::vector<std::string> kApexSepolicy{"apex_file_contexts", "apex_property_contexts",
- "apex_service_contexts", "apex_seapp_contexts",
- "apex_test"};
-
-Result<void> PutFileInTmpfs(ZipArchiveHandle archive, const std::string& fileName) {
- ZipEntry entry;
- std::string dstPath = kTmpfsDir + fileName;
-
- int ret = FindEntry(archive, fileName, &entry);
- if (ret != 0) {
- // All files are optional. If a file doesn't exist, return without error.
- return {};
- }
-
- unique_fd fd(TEMP_FAILURE_RETRY(
- open(dstPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR)));
- if (fd == -1) {
- return Error() << "Failed to open " << dstPath;
- }
-
- ret = ExtractEntryToFile(archive, &entry, fd);
- if (ret != 0) {
- return Error() << "Failed to extract entry \"" << fileName << "\" ("
- << entry.uncompressed_length << " bytes) to \"" << dstPath
- << "\": " << ErrorCodeString(ret);
- }
-
- return {};
-}
-
-Result<void> GetPolicyFromApex(const std::string& dir) {
- LOG(INFO) << "Loading APEX Sepolicy from " << dir + kSepolicyZip;
- unique_fd fd(open((dir + kSepolicyZip).c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
- if (fd < 0) {
- return ErrnoError() << "Failed to open package " << dir + kSepolicyZip;
- }
-
- ZipArchiveHandle handle;
- int ret = OpenArchiveFd(fd.get(), (dir + kSepolicyZip).c_str(), &handle,
- /*assume_ownership=*/false);
- if (ret < 0) {
- return Error() << "Failed to open package " << dir + kSepolicyZip << ": "
- << ErrorCodeString(ret);
- }
-
- auto handle_guard = android::base::make_scope_guard([&handle] { CloseArchive(handle); });
-
- for (const auto& file : kApexSepolicy) {
- auto extract = PutFileInTmpfs(handle, file);
- if (!extract.ok()) {
- return extract.error();
- }
- }
- for (const auto& file : kApexSepolicyTmp) {
- auto extract = PutFileInTmpfs(handle, file);
- if (!extract.ok()) {
- return extract.error();
- }
- }
- return {};
-}
-
-Result<void> LoadSepolicyApexCerts() {
- key_serial_t keyring_id = android::GetKeyringId(".fs-verity");
- if (keyring_id < 0) {
- return Error() << "Failed to find .fs-verity keyring id";
- }
-
- // TODO(b/199914227) the release key should always exist. Once it's checked in, start
- // throwing an error here if it doesn't exist.
- if (access(kSigningCertRelease, F_OK) == 0) {
- LoadKeyFromFile(keyring_id, "fsv_sepolicy_apex_release", kSigningCertRelease);
- }
- return {};
-}
-
-Result<void> SepolicyFsVerityCheck() {
- return Error() << "TODO implementent support for fsverity SEPolicy.";
-}
-
-Result<void> SepolicyCheckSignature(const std::string& dir) {
- std::string signature;
- if (!android::base::ReadFileToString(dir + kSepolicySignature, &signature)) {
- return ErrnoError() << "Failed to read " << kSepolicySignature;
- }
-
- std::fstream sepolicyZip(dir + kSepolicyZip, std::ios::in | std::ios::binary);
- if (!sepolicyZip) {
- return Error() << "Failed to open " << kSepolicyZip;
- }
- sepolicyZip.seekg(0);
- std::string sepolicyStr((std::istreambuf_iterator<char>(sepolicyZip)),
- std::istreambuf_iterator<char>());
-
- auto releaseKey = extractPublicKeyFromX509(kSigningCertRelease);
- if (!releaseKey.ok()) {
- return releaseKey.error();
- }
-
- return verifySignature(sepolicyStr, signature, *releaseKey);
-}
-
-Result<void> SepolicyVerify(const std::string& dir, bool supportsFsVerity) {
- if (supportsFsVerity) {
- auto fsVerityCheck = SepolicyFsVerityCheck();
- if (fsVerityCheck.ok()) {
- return fsVerityCheck;
- }
- // TODO(b/199914227) If the device supports fsverity, but we fail here, we should fail to
- // boot and not carry on. For now, fallback to a signature checkuntil the fsverity
- // logic is implemented.
- LOG(INFO) << "Falling back to standard signature check. " << fsVerityCheck.error();
- }
-
- auto sepolicySignature = SepolicyCheckSignature(dir);
- if (!sepolicySignature.ok()) {
- return Error() << "Apex SEPolicy failed signature check";
- }
- return {};
-}
-
-void CleanupApexSepolicy() {
- for (const auto& file : kApexSepolicyTmp) {
- std::string path = kTmpfsDir + file;
- unlink(path.c_str());
- }
-}
-
-// Updatable sepolicy is shipped within an zip within an APEX. Because
-// it needs to be available before Apexes are mounted, apexd copies
-// the zip from the APEX and stores it in /metadata/sepolicy. If there is
-// no updatable sepolicy in /metadata/sepolicy, then the updatable policy is
-// loaded from /system/etc/selinux/apex. Init performs the following
-// steps on boot:
-//
-// 1. Validates the zip by checking its signature against a public key that is
-// stored in /system/etc/selinux.
-// 2. Extracts files from zip and stores them in /dev/selinux.
-// 3. Checks if the apex_sepolicy.sha256 matches the sha256 of precompiled_sepolicy.
-// if so, the precompiled sepolicy is used. Otherwise, an on-device compile of the policy
-// is used. This is the same flow as on-device compilation of policy for Treble.
-// 4. Cleans up files in /dev/selinux which are no longer needed.
-// 5. Restorecons the remaining files in /dev/selinux.
-// 6. Sets selinux into enforcing mode and continues normal booting.
-//
-void PrepareApexSepolicy() {
- bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0;
- if (supportsFsVerity) {
- auto loadSepolicyApexCerts = LoadSepolicyApexCerts();
- if (!loadSepolicyApexCerts.ok()) {
- // TODO(b/199914227) If the device supports fsverity, but we fail here, we should fail
- // to boot and not carry on. For now, fallback to a signature checkuntil the fsverity
- // logic is implemented.
- LOG(INFO) << loadSepolicyApexCerts.error();
- }
- }
- // If apex sepolicy zip exists in /metadata/sepolicy, use that, otherwise use version on
- // /system.
- auto dir = (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0)
- ? kSepolicyApexMetadataDir
- : kSepolicyApexSystemDir;
-
- auto sepolicyVerify = SepolicyVerify(dir, supportsFsVerity);
- if (!sepolicyVerify.ok()) {
- LOG(INFO) << "Error: " << sepolicyVerify.error();
- // If signature verification fails, fall back to version on /system.
- // This file doesn't need to be verified because it lives on the system partition which
- // is signed and protected by verified boot.
- dir = kSepolicyApexSystemDir;
- }
-
- auto apex = GetPolicyFromApex(dir);
- if (!apex.ok()) {
- // TODO(b/199914227) Make failure fatal. For now continue booting with non-apex sepolicy.
- LOG(ERROR) << apex.error();
- }
-}
-
void ReadPolicy(std::string* policy) {
PolicyFile policy_file;
@@ -762,7 +539,6 @@ void SelinuxAvcLog(char* buf, size_t buf_len) {
void SelinuxRestoreContext() {
LOG(INFO) << "Running restorecon...";
selinux_android_restorecon("/dev", 0);
- selinux_android_restorecon("/dev/console", 0);
selinux_android_restorecon("/dev/kmsg", 0);
if constexpr (WORLD_WRITABLE_KMSG) {
selinux_android_restorecon("/dev/kmsg_debug", 0);
@@ -951,12 +727,9 @@ int SetupSelinux(char** argv) {
LOG(INFO) << "Opening SELinux policy";
- PrepareApexSepolicy();
-
// Read the policy before potentially killing snapuserd.
std::string policy;
ReadPolicy(&policy);
- CleanupApexSepolicy();
auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
if (snapuserd_helper) {
@@ -974,13 +747,6 @@ int SetupSelinux(char** argv) {
snapuserd_helper = nullptr;
}
- // This restorecon is intentionally done before SelinuxSetEnforcement because the permissions
- // needed to transition files from tmpfs to *_contexts_file context should not be granted to
- // any process after selinux is set into enforcing mode.
- if (selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE) == -1) {
- PLOG(FATAL) << "restorecon failed of /dev/selinux failed";
- }
-
SelinuxSetEnforcement();
// We're in the kernel domain and want to transition to the init domain. File systems that
diff --git a/init/service.cpp b/init/service.cpp
index bd704cf8e..c3069f5b2 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -127,8 +127,6 @@ static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigsto
unsigned long Service::next_start_order_ = 1;
bool Service::is_exec_service_running_ = false;
-pid_t Service::exec_service_pid_ = -1;
-std::chrono::time_point<std::chrono::steady_clock> Service::exec_service_started_;
Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
const std::vector<std::string>& args, bool from_apex)
@@ -271,9 +269,6 @@ void Service::Reap(const siginfo_t& siginfo) {
// Remove any socket resources we may have created.
for (const auto& socket : sockets_) {
- if (socket.persist) {
- continue;
- }
auto path = ANDROID_SOCKET_DIR "/" + socket.name;
unlink(path.c_str());
}
@@ -289,10 +284,6 @@ void Service::Reap(const siginfo_t& siginfo) {
if (flags_ & SVC_EXEC) UnSetExec();
- if (name_ == "zygote" || name_ == "zygote64") {
- removeAllEmptyProcessGroups();
- }
-
if (flags_ & SVC_TEMPORARY) return;
pid_ = 0;
@@ -394,8 +385,6 @@ Result<void> Service::ExecStart() {
flags_ |= SVC_EXEC;
is_exec_service_running_ = true;
- exec_service_pid_ = pid_;
- exec_service_started_ = std::chrono::steady_clock::now();
LOG(INFO) << "SVC_EXEC service '" << name_ << "' pid " << pid_ << " (uid " << proc_attr_.uid
<< " gid " << proc_attr_.gid << "+" << proc_attr_.supp_gids.size() << " context "
@@ -405,122 +394,6 @@ Result<void> Service::ExecStart() {
return {};
}
-static void ClosePipe(const std::array<int, 2>* pipe) {
- for (const auto fd : *pipe) {
- if (fd >= 0) {
- close(fd);
- }
- }
-}
-
-Result<void> Service::CheckConsole() {
- if (!(flags_ & SVC_CONSOLE)) {
- return {};
- }
-
- if (proc_attr_.console.empty()) {
- proc_attr_.console = "/dev/" + GetProperty("ro.boot.console", "console");
- }
-
- // Make sure that open call succeeds to ensure a console driver is
- // properly registered for the device node
- int console_fd = open(proc_attr_.console.c_str(), O_RDWR | O_CLOEXEC);
- if (console_fd < 0) {
- flags_ |= SVC_DISABLED;
- return ErrnoError() << "Couldn't open console '" << proc_attr_.console << "'";
- }
- close(console_fd);
- return {};
-}
-
-// Configures the memory cgroup properties for the service.
-void Service::ConfigureMemcg() {
- if (swappiness_ != -1) {
- if (!setProcessGroupSwappiness(proc_attr_.uid, pid_, swappiness_)) {
- PLOG(ERROR) << "setProcessGroupSwappiness failed";
- }
- }
-
- if (soft_limit_in_bytes_ != -1) {
- if (!setProcessGroupSoftLimit(proc_attr_.uid, pid_, soft_limit_in_bytes_)) {
- PLOG(ERROR) << "setProcessGroupSoftLimit failed";
- }
- }
-
- size_t computed_limit_in_bytes = limit_in_bytes_;
- if (limit_percent_ != -1) {
- long page_size = sysconf(_SC_PAGESIZE);
- long num_pages = sysconf(_SC_PHYS_PAGES);
- if (page_size > 0 && num_pages > 0) {
- size_t max_mem = SIZE_MAX;
- if (size_t(num_pages) < SIZE_MAX / size_t(page_size)) {
- max_mem = size_t(num_pages) * size_t(page_size);
- }
- computed_limit_in_bytes =
- std::min(computed_limit_in_bytes, max_mem / 100 * limit_percent_);
- }
- }
-
- if (!limit_property_.empty()) {
- // This ends up overwriting computed_limit_in_bytes but only if the
- // property is defined.
- computed_limit_in_bytes =
- android::base::GetUintProperty(limit_property_, computed_limit_in_bytes, SIZE_MAX);
- }
-
- if (computed_limit_in_bytes != size_t(-1)) {
- if (!setProcessGroupLimit(proc_attr_.uid, pid_, computed_limit_in_bytes)) {
- PLOG(ERROR) << "setProcessGroupLimit failed";
- }
- }
-}
-
-// Enters namespaces, sets environment variables, writes PID files and runs the service executable.
-void Service::RunService(const std::optional<MountNamespace>& override_mount_namespace,
- const std::vector<Descriptor>& descriptors,
- std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd) {
- if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace); !result.ok()) {
- LOG(FATAL) << "Service '" << name_ << "' failed to set up namespaces: " << result.error();
- }
-
- for (const auto& [key, value] : environment_vars_) {
- setenv(key.c_str(), value.c_str(), 1);
- }
-
- for (const auto& descriptor : descriptors) {
- descriptor.Publish();
- }
-
- if (auto result = WritePidToFiles(&writepid_files_); !result.ok()) {
- LOG(ERROR) << "failed to write pid to files: " << result.error();
- }
-
- // Wait until the cgroups have been created and until the cgroup controllers have been
- // activated.
- char byte = 0;
- if (read((*pipefd)[0], &byte, 1) < 0) {
- PLOG(ERROR) << "failed to read from notification channel";
- }
- pipefd.reset();
- if (!byte) {
- LOG(FATAL) << "Service '" << name_ << "' failed to start due to a fatal error";
- _exit(EXIT_FAILURE);
- }
-
- if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
- LOG(ERROR) << "failed to set task profiles";
- }
-
- // As requested, set our gid, supplemental gids, uid, context, and
- // priority. Aborts on failure.
- SetProcessAttributesAndCaps();
-
- if (!ExpandArgsAndExecv(args_, sigstop_)) {
- PLOG(ERROR) << "cannot execv('" << args_[0]
- << "'). See the 'Debugging init' section of init's README.md for tips";
- }
-}
-
Result<void> Service::Start() {
auto reboot_on_failure = make_scope_guard([this] {
if (on_failure_reboot_target_) {
@@ -536,7 +409,9 @@ Result<void> Service::Start() {
}
bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
- ResetFlagsForStart();
+ // Starting a service removes it from the disabled or reset state and
+ // immediately takes it out of the restarting state if it was in there.
+ flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// Running processes require no additional work --- if they're in the
// process of exiting, we've ensured that they will immediately restart
@@ -547,23 +422,25 @@ Result<void> Service::Start() {
if ((flags_ & SVC_ONESHOT) && disabled) {
flags_ |= SVC_RESTART;
}
-
- LOG(INFO) << "service '" << name_
- << "' requested start, but it is already running (flags: " << flags_ << ")";
-
// It is not an error to try to start a service that is already running.
reboot_on_failure.Disable();
return {};
}
- std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd(new std::array<int, 2>{-1, -1},
- ClosePipe);
- if (pipe(pipefd->data()) < 0) {
- return ErrnoError() << "pipe()";
- }
+ bool needs_console = (flags_ & SVC_CONSOLE);
+ if (needs_console) {
+ if (proc_attr_.console.empty()) {
+ proc_attr_.console = "/dev/" + GetProperty("ro.boot.console", "console");
+ }
- if (Result<void> result = CheckConsole(); !result.ok()) {
- return result;
+ // Make sure that open call succeeds to ensure a console driver is
+ // properly registered for the device node
+ int console_fd = open(proc_attr_.console.c_str(), O_RDWR | O_CLOEXEC);
+ if (console_fd < 0) {
+ flags_ |= SVC_DISABLED;
+ return ErrnoError() << "Couldn't open console '" << proc_attr_.console << "'";
+ }
+ close(console_fd);
}
struct stat sb;
@@ -635,7 +512,38 @@ Result<void> Service::Start() {
if (pid == 0) {
umask(077);
- RunService(override_mount_namespace, descriptors, std::move(pipefd));
+
+ if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace);
+ !result.ok()) {
+ LOG(FATAL) << "Service '" << name_
+ << "' failed to set up namespaces: " << result.error();
+ }
+
+ for (const auto& [key, value] : environment_vars_) {
+ setenv(key.c_str(), value.c_str(), 1);
+ }
+
+ for (const auto& descriptor : descriptors) {
+ descriptor.Publish();
+ }
+
+ if (auto result = WritePidToFiles(&writepid_files_); !result.ok()) {
+ LOG(ERROR) << "failed to write pid to files: " << result.error();
+ }
+
+ if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
+ LOG(ERROR) << "failed to set task profiles";
+ }
+
+ // As requested, set our gid, supplemental gids, uid, context, and
+ // priority. Aborts on failure.
+ SetProcessAttributesAndCaps();
+
+ if (!ExpandArgsAndExecv(args_, sigstop_)) {
+ PLOG(ERROR) << "cannot execv('" << args_[0]
+ << "'). See the 'Debugging init' section of init's README.md for tips";
+ }
+
_exit(127);
}
@@ -662,47 +570,58 @@ Result<void> Service::Start() {
limit_percent_ != -1 || !limit_property_.empty();
errno = -createProcessGroup(proc_attr_.uid, pid_, use_memcg);
if (errno != 0) {
- if (char byte = 0; write((*pipefd)[1], &byte, 1) < 0) {
- return ErrnoError() << "sending notification failed";
+ PLOG(ERROR) << "createProcessGroup(" << proc_attr_.uid << ", " << pid_
+ << ") failed for service '" << name_ << "'";
+ } else if (use_memcg) {
+ if (swappiness_ != -1) {
+ if (!setProcessGroupSwappiness(proc_attr_.uid, pid_, swappiness_)) {
+ PLOG(ERROR) << "setProcessGroupSwappiness failed";
+ }
+ }
+
+ if (soft_limit_in_bytes_ != -1) {
+ if (!setProcessGroupSoftLimit(proc_attr_.uid, pid_, soft_limit_in_bytes_)) {
+ PLOG(ERROR) << "setProcessGroupSoftLimit failed";
+ }
+ }
+
+ size_t computed_limit_in_bytes = limit_in_bytes_;
+ if (limit_percent_ != -1) {
+ long page_size = sysconf(_SC_PAGESIZE);
+ long num_pages = sysconf(_SC_PHYS_PAGES);
+ if (page_size > 0 && num_pages > 0) {
+ size_t max_mem = SIZE_MAX;
+ if (size_t(num_pages) < SIZE_MAX / size_t(page_size)) {
+ max_mem = size_t(num_pages) * size_t(page_size);
+ }
+ computed_limit_in_bytes =
+ std::min(computed_limit_in_bytes, max_mem / 100 * limit_percent_);
+ }
}
- return Error() << "createProcessGroup(" << proc_attr_.uid << ", " << pid_
- << ") failed for service '" << name_ << "'";
- }
- if (use_memcg) {
- ConfigureMemcg();
+ if (!limit_property_.empty()) {
+ // This ends up overwriting computed_limit_in_bytes but only if the
+ // property is defined.
+ computed_limit_in_bytes = android::base::GetUintProperty(
+ limit_property_, computed_limit_in_bytes, SIZE_MAX);
+ }
+
+ if (computed_limit_in_bytes != size_t(-1)) {
+ if (!setProcessGroupLimit(proc_attr_.uid, pid_, computed_limit_in_bytes)) {
+ PLOG(ERROR) << "setProcessGroupLimit failed";
+ }
+ }
}
if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_);
}
- if (char byte = 1; write((*pipefd)[1], &byte, 1) < 0) {
- return ErrnoError() << "sending notification failed";
- }
-
NotifyStateChange("running");
reboot_on_failure.Disable();
return {};
}
-void Service::SetStartedInFirstStage(pid_t pid) {
- LOG(INFO) << "adding first-stage service '" << name_ << "'...";
-
- time_started_ = boot_clock::now(); // not accurate, but doesn't matter here
- pid_ = pid;
- flags_ |= SVC_RUNNING;
- start_order_ = next_start_order_++;
-
- NotifyStateChange("running");
-}
-
-void Service::ResetFlagsForStart() {
- // Starting a service removes it from the disabled or reset state and
- // immediately takes it out of the restarting state if it was in there.
- flags_ &= ~(SVC_DISABLED | SVC_RESTARTING | SVC_RESET | SVC_RESTART | SVC_DISABLED_START);
-}
-
Result<void> Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
@@ -724,6 +643,25 @@ void Service::Reset() {
StopOrReset(SVC_RESET);
}
+void Service::ResetIfPostData() {
+ if (post_data_) {
+ if (flags_ & SVC_RUNNING) {
+ running_at_post_data_reset_ = true;
+ }
+ StopOrReset(SVC_RESET);
+ }
+}
+
+Result<void> Service::StartIfPostData() {
+ // Start the service, but only if it was started after /data was mounted,
+ // and it was still running when we reset the post-data services.
+ if (running_at_post_data_reset_) {
+ return Start();
+ }
+
+ return {};
+}
+
void Service::Stop() {
StopOrReset(SVC_DISABLED);
}
@@ -854,18 +792,5 @@ Result<std::unique_ptr<Service>> Service::MakeTemporaryOneshotService(
nullptr, str_args, false);
}
-// This is used for snapuserd_proxy, which hands off a socket to snapuserd. It's
-// a special case to support the daemon launched in first-stage init. The persist
-// feature is not part of the init language and is only used here.
-bool Service::MarkSocketPersistent(const std::string& socket_name) {
- for (auto& socket : sockets_) {
- if (socket.name == socket_name) {
- socket.persist = true;
- return true;
- }
- }
- return false;
-}
-
} // namespace init
} // namespace android
diff --git a/init/service.h b/init/service.h
index c314aa1c6..043555fa4 100644
--- a/init/service.h
+++ b/init/service.h
@@ -80,8 +80,10 @@ class Service {
Result<void> ExecStart();
Result<void> Start();
Result<void> StartIfNotDisabled();
+ Result<void> StartIfPostData();
Result<void> Enable();
void Reset();
+ void ResetIfPostData();
void Stop();
void Terminate();
void Timeout();
@@ -97,15 +99,9 @@ class Service {
void AddReapCallback(std::function<void(const siginfo_t& siginfo)> callback) {
reap_callbacks_.emplace_back(std::move(callback));
}
- void SetStartedInFirstStage(pid_t pid);
- bool MarkSocketPersistent(const std::string& socket_name);
size_t CheckAllCommands() const { return onrestart_.CheckAllCommands(); }
static bool is_exec_service_running() { return is_exec_service_running_; }
- static pid_t exec_service_pid() { return exec_service_pid_; }
- static std::chrono::time_point<std::chrono::steady_clock> exec_service_started() {
- return exec_service_started_;
- }
const std::string& name() const { return name_; }
const std::set<std::string>& classnames() const { return classnames_; }
@@ -148,18 +144,9 @@ class Service {
void StopOrReset(int how);
void KillProcessGroup(int signal, bool report_oneshot = false);
void SetProcessAttributesAndCaps();
- void ResetFlagsForStart();
- Result<void> CheckConsole();
- void ConfigureMemcg();
- void RunService(
- const std::optional<MountNamespace>& override_mount_namespace,
- const std::vector<Descriptor>& descriptors,
- std::unique_ptr<std::array<int, 2>, void (*)(const std::array<int, 2>* pipe)> pipefd);
static unsigned long next_start_order_;
static bool is_exec_service_running_;
- static std::chrono::time_point<std::chrono::steady_clock> exec_service_started_;
- static pid_t exec_service_pid_;
std::string name_;
std::set<std::string> classnames_;
@@ -224,6 +211,8 @@ class Service {
bool post_data_ = false;
+ bool running_at_post_data_reset_ = false;
+
std::optional<std::string> on_failure_reboot_target_;
bool from_apex_ = false;
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 9e914ee7c..57c311a52 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -27,7 +27,6 @@
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <hidl-util/FQName.h>
-#include <processgroup/processgroup.h>
#include <system/thread_defs.h>
#include "lmkd_service.h"
@@ -203,7 +202,7 @@ Result<void> ServiceParser::ParseInterface(std::vector<std::string>&& args) {
const std::string fullname = interface_name + "/" + instance_name;
for (const auto& svc : *service_list_) {
- if (svc->interfaces().count(fullname) > 0 && !service_->is_override()) {
+ if (svc->interfaces().count(fullname) > 0) {
return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
<< " but is already defined by " << svc->name();
}
@@ -396,15 +395,7 @@ Result<void> ServiceParser::ParseShutdown(std::vector<std::string>&& args) {
Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
args.erase(args.begin());
- if (service_->task_profiles_.empty()) {
- service_->task_profiles_ = std::move(args);
- } else {
- // Some task profiles might have been added during writepid conversions
- service_->task_profiles_.insert(service_->task_profiles_.end(),
- std::make_move_iterator(args.begin()),
- std::make_move_iterator(args.end()));
- args.clear();
- }
+ service_->task_profiles_ = std::move(args);
return {};
}
@@ -530,37 +521,8 @@ Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
return {};
}
-// Convert legacy paths used to migrate processes between cgroups using writepid command.
-// We can't get these paths from TaskProfiles because profile definitions are changing
-// when we migrate to cgroups v2 while these hardcoded paths stay the same.
-static std::optional<const std::string> ConvertTaskFileToProfile(const std::string& file) {
- static const std::map<const std::string, const std::string> map = {
- {"/dev/stune/top-app/tasks", "MaxPerformance"},
- {"/dev/stune/foreground/tasks", "HighPerformance"},
- {"/dev/cpuset/camera-daemon/tasks", "CameraServiceCapacity"},
- {"/dev/cpuset/foreground/tasks", "ProcessCapacityHigh"},
- {"/dev/cpuset/system-background/tasks", "ServiceCapacityLow"},
- {"/dev/stune/nnapi-hal/tasks", "NNApiHALPerformance"},
- {"/dev/blkio/background/tasks", "LowIoPriority"},
- };
- auto iter = map.find(file);
- return iter == map.end() ? std::nullopt : std::make_optional<const std::string>(iter->second);
-}
-
Result<void> ServiceParser::ParseWritepid(std::vector<std::string>&& args) {
args.erase(args.begin());
- // Convert any cgroup writes into appropriate task_profiles
- for (auto iter = args.begin(); iter != args.end();) {
- auto task_profile = ConvertTaskFileToProfile(*iter);
- if (task_profile) {
- LOG(WARNING) << "'writepid " << *iter << "' is converted into 'task_profiles "
- << task_profile.value() << "' for service " << service_->name();
- service_->task_profiles_.push_back(task_profile.value());
- iter = args.erase(iter);
- } else {
- ++iter;
- }
- }
service_->writepid_files_ = std::move(args);
return {};
}
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index eed5c65db..f2383d7a6 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -18,7 +18,6 @@
#include <fcntl.h>
#include <grp.h>
-#include <map>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/wait.h>
@@ -191,6 +190,8 @@ Result<Descriptor> FileDescriptor::Create() const {
// Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
fcntl(fd, F_SETFL, flags);
+ LOG(INFO) << "Opened file '" << name << "', flags " << flags;
+
return Descriptor(ANDROID_FILE_ENV_PREFIX + name, std::move(fd));
}
@@ -306,16 +307,6 @@ Result<void> WritePidToFiles(std::vector<std::string>* files) {
} else {
LOG(ERROR) << "cpuset cgroup controller is not mounted!";
}
-
- // Issue a warning whenever writepid is being used with a cgroup. This can't be done during
- // command parsing because cgroups might not be configured at the time or parsing.
- for (const auto& file : *files) {
- if (CgroupGetControllerFromPath(file, nullptr)) {
- LOG(WARNING) << "writepid usage with cgroups path '" << file
- << "' is obsolete, please use task_profiles!";
- }
- }
-
std::string pid_str = std::to_string(getpid());
for (const auto& file : *files) {
if (!WriteStringToFile(pid_str, file)) {
diff --git a/init/service_utils.h b/init/service_utils.h
index 9b65dca74..1e0b4bd2b 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -54,7 +54,6 @@ struct SocketDescriptor {
int perm = 0;
std::string context;
bool passcred = false;
- bool persist = false;
// Create() creates the named unix domain socket in /dev/socket and returns a Descriptor object.
// It should be called when starting a service, before calling fork(), such that the socket is
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 6fc64df33..9b2c7d939 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -95,10 +95,7 @@ static pid_t ReapOneProcess() {
LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;
}
- if (!service) {
- LOG(INFO) << name << " did not have an associated service entry and will not be reaped";
- return pid;
- }
+ if (!service) return pid;
service->Reap(siginfo);
diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp
index 5c821b05c..40467b7d3 100644
--- a/init/snapuserd_transition.cpp
+++ b/init/snapuserd_transition.cpp
@@ -29,19 +29,16 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
-#include <fs_avb/fs_avb.h>
#include <libsnapshot/snapshot.h>
+#include <libsnapshot/snapuserd_client.h>
#include <private/android_filesystem_config.h>
#include <procinfo/process_map.h>
#include <selinux/android.h>
-#include <snapuserd/snapuserd_client.h>
#include "block_dev_initializer.h"
-#include "lmkd_service.h"
#include "service_utils.h"
#include "util.h"
@@ -57,11 +54,10 @@ using android::snapshot::SnapuserdClient;
static constexpr char kSnapuserdPath[] = "/system/bin/snapuserd";
static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
static constexpr char kSnapuserdFirstStageFdVar[] = "FIRST_STAGE_SNAPUSERD_FD";
-static constexpr char kSnapuserdFirstStageInfoVar[] = "FIRST_STAGE_SNAPUSERD_INFO";
static constexpr char kSnapuserdLabel[] = "u:object_r:snapuserd_exec:s0";
static constexpr char kSnapuserdSocketLabel[] = "u:object_r:snapuserd_socket:s0";
-void LaunchFirstStageSnapuserd(SnapshotDriver driver) {
+void LaunchFirstStageSnapuserd() {
SocketDescriptor socket_desc;
socket_desc.name = android::snapshot::kSnapuserdSocket;
socket_desc.type = SOCK_STREAM;
@@ -83,31 +79,12 @@ void LaunchFirstStageSnapuserd(SnapshotDriver driver) {
}
if (pid == 0) {
socket->Publish();
-
- if (driver == SnapshotDriver::DM_USER) {
- char arg0[] = "/system/bin/snapuserd";
- char arg1[] = "-user_snapshot";
- char* const argv[] = {arg0, arg1, nullptr};
- if (execv(arg0, argv) < 0) {
- PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
- }
- _exit(127);
- } else {
- char arg0[] = "/system/bin/snapuserd";
- char* const argv[] = {arg0, nullptr};
- if (execv(arg0, argv) < 0) {
- PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
- }
- _exit(127);
+ char arg0[] = "/system/bin/snapuserd";
+ char* const argv[] = {arg0, nullptr};
+ if (execv(arg0, argv) < 0) {
+ PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
}
- }
-
- auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 10s);
- if (!client) {
- LOG(FATAL) << "Could not connect to first-stage snapuserd";
- }
- if (client->SupportsSecondStageSocketHandoff()) {
- setenv(kSnapuserdFirstStageInfoVar, "socket", 1);
+ _exit(127);
}
setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
@@ -250,56 +227,6 @@ void SnapuserdSelinuxHelper::FinishTransition() {
}
}
-/*
- * Before starting init second stage, we will wait
- * for snapuserd daemon to be up and running; bionic libc
- * may read /system/etc/selinux/plat_property_contexts file
- * before invoking main() function. This will happen if
- * init initializes property during second stage. Any access
- * to /system without snapuserd daemon will lead to a deadlock.
- *
- * Thus, we do a simple probe by reading system partition. This
- * read will eventually be serviced by daemon confirming that
- * daemon is up and running. Furthermore, we are still in the kernel
- * domain and sepolicy has not been enforced yet. Thus, access
- * to these device mapper block devices are ok even though
- * we may see audit logs.
- */
-bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() {
- std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
- android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_DIRECT));
- if (fd < 0) {
- PLOG(ERROR) << "open " << dev << " failed";
- return false;
- }
-
- void* addr;
- ssize_t page_size = getpagesize();
- if (posix_memalign(&addr, page_size, page_size) < 0) {
- PLOG(ERROR) << "posix_memalign with page size " << page_size;
- return false;
- }
-
- std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
-
- int iter = 0;
- while (iter < 10) {
- ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), buffer.get(), page_size, 0));
- if (n < 0) {
- // Wait for sometime before retry
- std::this_thread::sleep_for(100ms);
- } else if (n == page_size) {
- return true;
- } else {
- LOG(ERROR) << "pread returned: " << n << " from: " << dev << " expected: " << page_size;
- }
-
- iter += 1;
- }
-
- return false;
-}
-
void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
auto fd = GetRamdiskSnapuserdFd();
if (!fd) {
@@ -321,21 +248,6 @@ void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
-
- // Since daemon is not started as a service, we have
- // to explicitly set the OOM score to default which is unkillable
- std::string oom_str = std::to_string(DEFAULT_OOM_SCORE_ADJUST);
- std::string oom_file = android::base::StringPrintf("/proc/%d/oom_score_adj", pid);
- if (!android::base::WriteStringToFile(oom_str, oom_file)) {
- PLOG(ERROR) << "couldn't write oom_score_adj to snapuserd daemon with pid: " << pid;
- }
-
- if (!TestSnapuserdIsReady()) {
- PLOG(FATAL) << "snapuserd daemon failed to launch";
- } else {
- LOG(INFO) << "snapuserd daemon is up and running";
- }
-
return;
}
@@ -416,13 +328,5 @@ bool IsFirstStageSnapuserdRunning() {
return GetSnapuserdFirstStagePid().has_value();
}
-std::vector<std::string> GetSnapuserdFirstStageInfo() {
- const char* pid_str = getenv(kSnapuserdFirstStageInfoVar);
- if (!pid_str) {
- return {};
- }
- return android::base::Split(pid_str, ",");
-}
-
} // namespace init
} // namespace android
diff --git a/init/snapuserd_transition.h b/init/snapuserd_transition.h
index 557d10587..a5ab652b7 100644
--- a/init/snapuserd_transition.h
+++ b/init/snapuserd_transition.h
@@ -29,13 +29,8 @@
namespace android {
namespace init {
-enum class SnapshotDriver {
- DM_SNAPSHOT,
- DM_USER,
-};
-
// Fork and exec a new copy of snapuserd.
-void LaunchFirstStageSnapuserd(SnapshotDriver driver);
+void LaunchFirstStageSnapuserd();
class SnapuserdSelinuxHelper final {
using SnapshotManager = android::snapshot::SnapshotManager;
@@ -56,7 +51,6 @@ class SnapuserdSelinuxHelper final {
private:
void RelaunchFirstStageSnapuserd();
void ExecSnapuserd();
- bool TestSnapuserdIsReady();
std::unique_ptr<SnapshotManager> sm_;
BlockDevInitializer block_dev_init_;
@@ -82,9 +76,6 @@ bool IsFirstStageSnapuserdRunning();
// Return the pid of the first-stage instances of snapuserd, if it was started.
std::optional<pid_t> GetSnapuserdFirstStagePid();
-// Return snapuserd info strings that were set during first-stage init.
-std::vector<std::string> GetSnapuserdFirstStageInfo();
-
// Save an open fd to /system/bin (in the ramdisk) into an environment. This is
// used to later execveat() snapuserd.
void SaveRamdiskPathToSnapuserd();
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 7aa4a9d2c..fa48beab3 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -44,7 +44,6 @@
#endif
using android::base::GetExecutablePath;
-using android::base::GetProperty;
using android::base::Join;
using android::base::Socketpair;
using android::base::Split;
@@ -297,7 +296,7 @@ Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
auto& failure = subcontext_reply->failure();
- return ResultError<>(failure.error_string(), failure.error_errno());
+ return ResultError(failure.error_string(), failure.error_errno());
}
if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
@@ -321,7 +320,7 @@ Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::s
if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
auto& failure = subcontext_reply->failure();
- return ResultError<>(failure.error_string(), failure.error_errno());
+ return ResultError(failure.error_string(), failure.error_errno());
}
if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
@@ -338,11 +337,6 @@ Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::s
}
void InitializeSubcontext() {
- if (IsMicrodroid()) {
- LOG(INFO) << "Not using subcontext for microdroid";
- return;
- }
-
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
subcontext.reset(
new Subcontext(std::vector<std::string>{"/vendor", "/odm"}, kVendorContext));
diff --git a/init/switch_root.cpp b/init/switch_root.cpp
index 86fad80af..575b67f38 100644
--- a/init/switch_root.cpp
+++ b/init/switch_root.cpp
@@ -78,8 +78,7 @@ void SwitchRoot(const std::string& new_root) {
auto new_mount_path = new_root + mount_path;
mkdir(new_mount_path.c_str(), 0755);
if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
- PLOG(FATAL) << "Unable to move mount at '" << mount_path << "' to "
- << "'" << new_mount_path << "'";
+ PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
}
}
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index c6bf708a3..331255b1e 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -115,13 +115,11 @@ class ColdBoot {
public:
ColdBoot(UeventListener& uevent_listener,
std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers,
- bool enable_parallel_restorecon,
- std::vector<std::string> parallel_restorecon_queue)
+ bool enable_parallel_restorecon)
: uevent_listener_(uevent_listener),
uevent_handlers_(uevent_handlers),
num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4),
- enable_parallel_restorecon_(enable_parallel_restorecon),
- parallel_restorecon_queue_(parallel_restorecon_queue) {}
+ enable_parallel_restorecon_(enable_parallel_restorecon) {}
void Run();
@@ -144,8 +142,6 @@ class ColdBoot {
std::set<pid_t> subprocess_pids_;
std::vector<std::string> restorecon_queue_;
-
- std::vector<std::string> parallel_restorecon_queue_;
};
void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
@@ -159,34 +155,17 @@ void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_pr
}
void ColdBoot::RestoreConHandler(unsigned int process_num, unsigned int total_processes) {
- android::base::Timer t_process;
-
for (unsigned int i = process_num; i < restorecon_queue_.size(); i += total_processes) {
- android::base::Timer t;
auto& dir = restorecon_queue_[i];
selinux_android_restorecon(dir.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
-
- //Mark a dir restorecon operation for 50ms,
- //Maybe you can add this dir to the ueventd.rc script to parallel processing
- if (t.duration() > 50ms) {
- LOG(INFO) << "took " << t.duration().count() <<"ms restorecon '"
- << dir.c_str() << "' on process '" << process_num <<"'";
- }
}
-
- //Calculate process restorecon time
- LOG(VERBOSE) << "took " << t_process.duration().count() << "ms on process '"
- << process_num << "'";
}
void ColdBoot::GenerateRestoreCon(const std::string& directory) {
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(directory.c_str()), &closedir);
- if (!dir) {
- PLOG(WARNING) << "opendir " << directory.c_str();
- return;
- }
+ if (!dir) return;
struct dirent* dent;
while ((dent = readdir(dir.get())) != NULL) {
@@ -197,10 +176,7 @@ void ColdBoot::GenerateRestoreCon(const std::string& directory) {
if (S_ISDIR(st.st_mode)) {
std::string fullpath = directory + "/" + dent->d_name;
- auto parallel_restorecon =
- std::find(parallel_restorecon_queue_.begin(),
- parallel_restorecon_queue_.end(), fullpath);
- if (parallel_restorecon == parallel_restorecon_queue_.end()) {
+ if (fullpath != "/sys/devices") {
restorecon_queue_.emplace_back(fullpath);
}
}
@@ -272,16 +248,11 @@ void ColdBoot::Run() {
RegenerateUevents();
if (enable_parallel_restorecon_) {
- if (parallel_restorecon_queue_.empty()) {
- parallel_restorecon_queue_.emplace_back("/sys");
- // takes long time for /sys/devices, parallelize it
- parallel_restorecon_queue_.emplace_back("/sys/devices");
- LOG(INFO) << "Parallel processing directory is not set, set the default";
- }
- for (const auto& dir : parallel_restorecon_queue_) {
- selinux_android_restorecon(dir.c_str(), 0);
- GenerateRestoreCon(dir);
- }
+ selinux_android_restorecon("/sys", 0);
+ selinux_android_restorecon("/sys/devices", 0);
+ GenerateRestoreCon("/sys");
+ // takes long time for /sys/devices, parallelize it
+ GenerateRestoreCon("/sys/devices");
}
ForkSubProcesses();
@@ -297,27 +268,14 @@ void ColdBoot::Run() {
}
static UeventdConfiguration GetConfiguration() {
- auto hardware = android::base::GetProperty("ro.hardware", "");
- std::vector<std::string> legacy_paths{"/vendor/ueventd.rc", "/odm/ueventd.rc",
- "/ueventd." + hardware + ".rc"};
-
- std::vector<std::string> canonical{"/system/etc/ueventd.rc"};
-
- if (android::base::GetIntProperty("ro.product.first_api_level", 10000) < __ANDROID_API_T__) {
- // TODO: Remove these legacy paths once Android S is no longer supported.
- canonical.insert(canonical.end(), legacy_paths.begin(), legacy_paths.end());
- } else {
- // Warn if newer device is using legacy paths.
- for (const auto& path : legacy_paths) {
- if (access(path.c_str(), F_OK) == 0) {
- LOG(FATAL_WITHOUT_ABORT)
- << "Legacy ueventd configuration file detected and will not be parsed: "
- << path;
- }
- }
+ // TODO: Remove these legacy paths once Android S is no longer supported.
+ if (android::base::GetIntProperty("ro.product.first_api_level", 10000) <= __ANDROID_API_S__) {
+ auto hardware = android::base::GetProperty("ro.hardware", "");
+ return ParseConfig({"/system/etc/ueventd.rc", "/vendor/ueventd.rc", "/odm/ueventd.rc",
+ "/ueventd." + hardware + ".rc"});
}
- return ParseConfig(canonical);
+ return ParseConfig({"/system/etc/ueventd.rc"});
}
int ueventd_main(int argc, char** argv) {
@@ -355,8 +313,7 @@ int ueventd_main(int argc, char** argv) {
if (!android::base::GetBoolProperty(kColdBootDoneProp, false)) {
ColdBoot cold_boot(uevent_listener, uevent_handlers,
- ueventd_configuration.enable_parallel_restorecon,
- ueventd_configuration.parallel_restorecon_dirs);
+ ueventd_configuration.enable_parallel_restorecon);
cold_boot.Run();
}
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index d34672e24..2221228d1 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -101,8 +101,8 @@ Result<void> ParseFirmwareDirectoriesLine(std::vector<std::string>&& args,
Result<void> ParseExternalFirmwareHandlerLine(
std::vector<std::string>&& args,
std::vector<ExternalFirmwareHandler>* external_firmware_handlers) {
- if (args.size() != 4 && args.size() != 5) {
- return Error() << "external_firmware_handler lines must have 3 or 4 parameters";
+ if (args.size() != 4) {
+ return Error() << "external_firmware_handler lines must have exactly 3 parameters";
}
if (std::find_if(external_firmware_handlers->begin(), external_firmware_handlers->end(),
@@ -117,19 +117,7 @@ Result<void> ParseExternalFirmwareHandlerLine(
return ErrnoError() << "invalid handler uid'" << args[2] << "'";
}
- gid_t gid = 0;
- int handler_index = 3;
- if (args.size() == 5) {
- struct group* grp = getgrnam(args[3].c_str());
- if (!grp) {
- return ErrnoError() << "invalid handler gid '" << args[3] << "'";
- }
- gid = grp->gr_gid;
- handler_index = 4;
- }
-
- ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, gid,
- std::move(args[handler_index]));
+ ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, std::move(args[3]));
external_firmware_handlers->emplace_back(std::move(handler));
return {};
@@ -151,17 +139,6 @@ Result<void> ParseEnabledDisabledLine(std::vector<std::string>&& args, bool* fea
return {};
}
-Result<void> ParseParallelRestoreconDirsLine(std::vector<std::string>&& args,
- std::vector<std::string>* parallel_restorecon_dirs) {
- if (args.size() != 2) {
- return Error() << "parallel_restorecon_dir lines must have exactly 2 parameters";
- }
-
- std::move(std::next(args.begin()), args.end(), std::back_inserter(*parallel_restorecon_dirs));
-
- return {};
-}
-
Result<void> ParseUeventSocketRcvbufSizeLine(std::vector<std::string>&& args,
size_t* uevent_socket_rcvbuf_size) {
if (args.size() != 2) {
@@ -279,9 +256,6 @@ UeventdConfiguration ParseConfig(const std::vector<std::string>& configs) {
parser.AddSingleLineParser("uevent_socket_rcvbuf_size",
std::bind(ParseUeventSocketRcvbufSizeLine, _1,
&ueventd_configuration.uevent_socket_rcvbuf_size));
- parser.AddSingleLineParser("parallel_restorecon_dir",
- std::bind(ParseParallelRestoreconDirsLine, _1,
- &ueventd_configuration.parallel_restorecon_dirs));
parser.AddSingleLineParser("parallel_restorecon",
std::bind(ParseEnabledDisabledLine, _1,
&ueventd_configuration.enable_parallel_restorecon));
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 81f4e9d54..eaafa5aa7 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -31,7 +31,6 @@ struct UeventdConfiguration {
std::vector<Permissions> dev_permissions;
std::vector<std::string> firmware_directories;
std::vector<ExternalFirmwareHandler> external_firmware_handlers;
- std::vector<std::string> parallel_restorecon_dirs;
bool enable_modalias_handling = false;
size_t uevent_socket_rcvbuf_size = 0;
bool enable_parallel_restorecon = false;
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index 41924e235..c5aa9e3b5 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -49,7 +49,6 @@ void TestExternalFirmwareHandler(const ExternalFirmwareHandler& expected,
const ExternalFirmwareHandler& test) {
EXPECT_EQ(expected.devpath, test.devpath) << expected.devpath;
EXPECT_EQ(expected.uid, test.uid) << expected.uid;
- EXPECT_EQ(expected.gid, test.gid) << expected.gid;
EXPECT_EQ(expected.handler_path, test.handler_path) << expected.handler_path;
}
@@ -77,7 +76,6 @@ void TestUeventdFile(const std::string& content, const UeventdConfiguration& exp
EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
TestVector(expected.external_firmware_handlers, result.external_firmware_handlers,
TestExternalFirmwareHandler);
- EXPECT_EQ(expected.parallel_restorecon_dirs, result.parallel_restorecon_dirs);
}
TEST(ueventd_parser, EmptyFile) {
@@ -106,7 +104,7 @@ subsystem test_devpath_dirname
{"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
{"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
- TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}, {}});
+ TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}});
}
TEST(ueventd_parser, Permissions) {
@@ -132,7 +130,7 @@ TEST(ueventd_parser, Permissions) {
{"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT, true},
};
- TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}, {}, {}});
+ TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}, {}});
}
TEST(ueventd_parser, FirmwareDirectories) {
@@ -148,7 +146,7 @@ firmware_directories /more
"/more",
};
- TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories, {}, {}});
+ TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories, {}});
}
TEST(ueventd_parser, ExternalFirmwareHandlers) {
@@ -159,62 +157,42 @@ external_firmware_handler /devices/path/firmware/something002.bin radio "/vendor
external_firmware_handler /devices/path/firmware/* root "/vendor/bin/firmware_handler.sh"
external_firmware_handler /devices/path/firmware/something* system "/vendor/bin/firmware_handler.sh"
external_firmware_handler /devices/path/*/firmware/something*.bin radio "/vendor/bin/firmware_handler.sh"
-external_firmware_handler /devices/path/firmware/something003.bin system system /vendor/bin/firmware_handler.sh
-external_firmware_handler /devices/path/firmware/something004.bin radio radio "/vendor/bin/firmware_handler.sh --has --arguments"
)";
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
{
"devpath",
AID_ROOT,
- AID_ROOT,
"handler_path",
},
{
"/devices/path/firmware/something001.bin",
AID_SYSTEM,
- AID_ROOT,
"/vendor/bin/firmware_handler.sh",
},
{
"/devices/path/firmware/something002.bin",
AID_RADIO,
- AID_ROOT,
"/vendor/bin/firmware_handler.sh --has --arguments",
},
{
"/devices/path/firmware/",
AID_ROOT,
- AID_ROOT,
"/vendor/bin/firmware_handler.sh",
},
{
"/devices/path/firmware/something",
AID_SYSTEM,
- AID_ROOT,
"/vendor/bin/firmware_handler.sh",
},
{
"/devices/path/*/firmware/something*.bin",
AID_RADIO,
- AID_ROOT,
- "/vendor/bin/firmware_handler.sh",
- },
- {
- "/devices/path/firmware/something003.bin",
- AID_SYSTEM,
- AID_SYSTEM,
"/vendor/bin/firmware_handler.sh",
},
- {
- "/devices/path/firmware/something004.bin",
- AID_RADIO,
- AID_RADIO,
- "/vendor/bin/firmware_handler.sh --has --arguments",
- },
};
- TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}});
+ TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
}
TEST(ueventd_parser, ExternalFirmwareHandlersDuplicate) {
@@ -227,26 +205,11 @@ external_firmware_handler devpath root handler_path2
{
"devpath",
AID_ROOT,
- AID_ROOT,
"handler_path",
},
};
- TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}});
-}
-
-TEST(ueventd_parser, ParallelRestoreconDirs) {
- auto ueventd_file = R"(
-parallel_restorecon_dir /sys
-parallel_restorecon_dir /sys/devices
-)";
-
- auto parallel_restorecon_dirs = std::vector<std::string>{
- "/sys",
- "/sys/devices",
- };
-
- TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, parallel_restorecon_dirs});
+ TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
}
TEST(ueventd_parser, UeventSocketRcvbufSize) {
@@ -255,7 +218,7 @@ uevent_socket_rcvbuf_size 8k
uevent_socket_rcvbuf_size 8M
)";
- TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 8 * 1024 * 1024});
+ TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, false, 8 * 1024 * 1024});
}
TEST(ueventd_parser, EnabledDisabledLines) {
@@ -265,7 +228,7 @@ parallel_restorecon enabled
modalias_handling disabled
)";
- TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 0, true});
+ TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, false, 0, true});
auto ueventd_file2 = R"(
parallel_restorecon enabled
@@ -273,7 +236,7 @@ modalias_handling enabled
parallel_restorecon disabled
)";
- TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, {}, true, 0, false});
+ TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, true, 0, false});
}
TEST(ueventd_parser, AllTogether) {
@@ -313,9 +276,6 @@ uevent_socket_rcvbuf_size 6M
modalias_handling enabled
parallel_restorecon enabled
-parallel_restorecon_dir /sys
-parallel_restorecon_dir /sys/devices
-
#ending comment
)";
@@ -345,20 +305,14 @@ parallel_restorecon_dir /sys/devices
};
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
- {"/devices/path/firmware/firmware001.bin", AID_ROOT, AID_ROOT, "/vendor/bin/touch.sh"},
- };
-
- auto parallel_restorecon_dirs = std::vector<std::string>{
- "/sys",
- "/sys/devices",
+ {"/devices/path/firmware/firmware001.bin", AID_ROOT, "/vendor/bin/touch.sh"},
};
size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;
TestUeventdFile(ueventd_file,
{subsystems, sysfs_permissions, permissions, firmware_directories,
- external_firmware_handlers, parallel_restorecon_dirs, true,
- uevent_socket_rcvbuf_size, true});
+ external_firmware_handlers, true, uevent_socket_rcvbuf_size, true});
}
// All of these lines are ill-formed, so test that there is 0 output.
@@ -390,9 +344,6 @@ external_firmware_handler
external_firmware_handler blah blah
external_firmware_handler blah blah blah blah
-parallel_restorecon_dir
-parallel_restorecon_dir /sys /sys/devices
-
)";
TestUeventdFile(ueventd_file, {});
diff --git a/init/ueventd_test.cpp b/init/ueventd_test.cpp
index 1ac6d8ee0..fc3cdfb7d 100644
--- a/init/ueventd_test.cpp
+++ b/init/ueventd_test.cpp
@@ -99,7 +99,7 @@ TEST(ueventd, setfscreatecon_IsPerThread) {
const char* const contexts[] = {
"u:object_r:audio_device:s0",
"u:object_r:sensors_device:s0",
- "u:object_r:video_device:s0",
+ "u:object_r:video_device:s0"
"u:object_r:zero_device:s0",
};
diff --git a/init/util.cpp b/init/util.cpp
index d1e518b57..9f7bfdb5b 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -757,10 +757,5 @@ void SetDefaultMountNamespaceReady() {
is_default_mount_namespace_ready = true;
}
-bool IsMicrodroid() {
- static bool is_microdroid = android::base::GetProperty("ro.hardware", "") == "microdroid";
- return is_microdroid;
-}
-
} // namespace init
} // namespace android
diff --git a/init/util.h b/init/util.h
index bf5367531..daba85247 100644
--- a/init/util.h
+++ b/init/util.h
@@ -103,7 +103,5 @@ bool IsRecoveryMode();
bool IsDefaultMountNamespaceReady();
void SetDefaultMountNamespaceReady();
-
-bool IsMicrodroid();
} // namespace init
} // namespace android
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
index 296e20731..692e223a1 100644
--- a/libasyncio/Android.bp
+++ b/libasyncio/Android.bp
@@ -32,7 +32,6 @@ cc_library {
defaults: ["libasyncio_defaults"],
vendor_available: true,
recovery_available: true,
- min_sdk_version: "apex_inherit",
apex_available: [
"//apex_available:platform",
"com.android.adbd",
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index 2559137d9..b33d46d50 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -21,8 +21,6 @@ package {
cc_library {
name: "libcrypto_utils",
vendor_available: true,
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
vndk: {
enabled: true,
@@ -44,7 +42,6 @@ cc_library {
enabled: true,
},
},
- min_sdk_version: "apex_inherit",
apex_available: [
"//apex_available:platform",
"com.android.adbd",
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index c8bfb0194..f1333ddd1 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -355,3 +355,18 @@ cc_test {
defaults: ["libcutils_test_static_defaults"],
test_config: "KernelLibcutilsTest.xml",
}
+
+rust_bindgen {
+ name: "libcutils_bindgen",
+ wrapper_src: "rust/cutils.h",
+ crate_name: "cutils_bindgen",
+ source_stem: "bindings",
+ local_include_dirs: ["include"],
+ bindgen_flags: [
+ "--allowlist-function", "multiuser_get_app_id",
+ "--allowlist-function", "multiuser_get_uid",
+ "--allowlist-function", "multiuser_get_user_id",
+ "--allowlist-var", "AID_KEYSTORE",
+ "--allowlist-var", "AID_USER_OFFSET",
+ ],
+}
diff --git a/libcutils/TEST_MAPPING b/libcutils/TEST_MAPPING
deleted file mode 100644
index cca7d934c..000000000
--- a/libcutils/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "libcutils_test"
- }
- ],
- "hwasan-postsubmit": [
- {
- "name": "libcutils_test"
- }
- ]
-}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index a6835fc70..e9497a806 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -211,7 +211,6 @@ static const struct fs_path_config android_files[] = {
{ 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/resize2fs" },
{ 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/snapuserd" },
{ 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/tune2fs" },
- { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/fsck.f2fs" },
// generic defaults
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
diff --git a/libcutils/include/cutils/list.h b/libcutils/include/cutils/list.h
index 7eb872547..dfdc53be6 100644
--- a/libcutils/include/cutils/list.h
+++ b/libcutils/include/cutils/list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef _CUTILS_LIST_H_
+#define _CUTILS_LIST_H_
#include <stddef.h>
@@ -37,6 +38,9 @@ struct listnode
.prev = &(name), \
}
+#define list_for_each(node, list) \
+ for ((node) = (list)->next; (node) != (list); (node) = (node)->next)
+
#define list_for_each_reverse(node, list) \
for ((node) = (list)->prev; (node) != (list); (node) = (node)->prev)
@@ -45,10 +49,6 @@ struct listnode
(node) != (list); \
(node) = (n), (n) = (node)->next)
-#define list_for_each(node, list) \
- for (struct listnode* __n = ((node) = (list)->next)->next; (node) != (list); \
- (node) = __n, __n = (node)->next)
-
static inline void list_init(struct listnode *node)
{
node->next = node;
@@ -84,3 +84,5 @@ static inline void list_remove(struct listnode *item)
#ifdef __cplusplus
};
#endif /* __cplusplus */
+
+#endif
diff --git a/libcutils/include/cutils/multiuser.h b/libcutils/include/cutils/multiuser.h
index 0575ccf72..9a2305c98 100644
--- a/libcutils/include/cutils/multiuser.h
+++ b/libcutils/include/cutils/multiuser.h
@@ -30,8 +30,6 @@ extern userid_t multiuser_get_user_id(uid_t uid);
extern appid_t multiuser_get_app_id(uid_t uid);
extern uid_t multiuser_get_uid(userid_t user_id, appid_t app_id);
-extern uid_t multiuser_get_sdk_sandbox_uid(userid_t user_id, appid_t app_id);
-extern uid_t multiuser_convert_sdk_sandbox_to_app_uid(uid_t uid);
extern gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id);
extern gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id);
diff --git a/libcutils/include/cutils/qtaguid.h b/libcutils/include/cutils/qtaguid.h
index a5ffb0327..3f5e41fd3 100644
--- a/libcutils/include/cutils/qtaguid.h
+++ b/libcutils/include/cutils/qtaguid.h
@@ -34,6 +34,24 @@ extern int qtaguid_tagSocket(int sockfd, int tag, uid_t uid);
extern int qtaguid_untagSocket(int sockfd);
/*
+ * For the given uid, switch counter sets.
+ * The kernel only keeps a limited number of sets.
+ * 2 for now.
+ */
+extern int qtaguid_setCounterSet(int counterSetNum, uid_t uid);
+
+/*
+ * Delete all tag info that relates to the given tag an uid.
+ * If the tag is 0, then ALL info about the uid is freed.
+ * The delete data also affects active tagged sockets, which are
+ * then untagged.
+ * The calling process can only operate on its own tags.
+ * Unless it is part of the happy AID_NET_BW_ACCT group.
+ * In which case it can clobber everything.
+ */
+extern int qtaguid_deleteTagData(int tag, uid_t uid);
+
+/*
* Enable/disable qtaguid functionnality at a lower level.
* When pacified, the kernel will accept commands but do nothing.
*/
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index 98ae0d4ea..24c6ae629 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -75,8 +75,7 @@ __BEGIN_DECLS
#define ATRACE_TAG_AIDL (1<<24)
#define ATRACE_TAG_NNAPI (1<<25)
#define ATRACE_TAG_RRO (1<<26)
-#define ATRACE_TAG_THERMAL (1 << 27)
-#define ATRACE_TAG_LAST ATRACE_TAG_THERMAL
+#define ATRACE_TAG_LAST ATRACE_TAG_RRO
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1ULL<<63)
@@ -209,71 +208,6 @@ static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cook
}
/**
- * Trace the beginning of an asynchronous event. In addition to the name and a
- * cookie as in ATRACE_ASYNC_BEGIN/ATRACE_ASYNC_END, a track name argument is
- * provided, which is the name of the row where this async event should be
- * recorded. The track name, name, and cookie used to begin an event must be
- * used to end it.
- */
-#define ATRACE_ASYNC_FOR_TRACK_BEGIN(track_name, name, cookie) \
- atrace_async_for_track_begin(ATRACE_TAG, track_name, name, cookie)
-static inline void atrace_async_for_track_begin(uint64_t tag, const char* track_name,
- const char* name, int32_t cookie) {
- if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
- void atrace_async_for_track_begin_body(const char*, const char*, int32_t);
- atrace_async_for_track_begin_body(track_name, name, cookie);
- }
-}
-
-/**
- * Trace the end of an asynchronous event.
- * This should correspond to a previous ATRACE_ASYNC_FOR_TRACK_BEGIN.
- */
-#define ATRACE_ASYNC_FOR_TRACK_END(track_name, name, cookie) \
- atrace_async_for_track_end(ATRACE_TAG, track_name, name, cookie)
-static inline void atrace_async_for_track_end(uint64_t tag, const char* track_name,
- const char* name, int32_t cookie) {
- if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
- void atrace_async_for_track_end_body(const char*, const char*, int32_t);
- atrace_async_for_track_end_body(track_name, name, cookie);
- }
-}
-
-/**
- * Trace an instantaneous context. name is used to identify the context.
- *
- * An "instant" is an event with no defined duration. Visually is displayed like a single marker
- * in the timeline (rather than a span, in the case of begin/end events).
- *
- * By default, instant events are added into a dedicated track that has the same name of the event.
- * Use atrace_instant_for_track to put different instant events into the same timeline track/row.
- */
-#define ATRACE_INSTANT(name) atrace_instant(ATRACE_TAG, name)
-static inline void atrace_instant(uint64_t tag, const char* name) {
- if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
- void atrace_instant_body(const char*);
- atrace_instant_body(name);
- }
-}
-
-/**
- * Trace an instantaneous context. name is used to identify the context.
- * track_name is the name of the row where the event should be recorded.
- *
- * An "instant" is an event with no defined duration. Visually is displayed like a single marker
- * in the timeline (rather than a span, in the case of begin/end events).
- */
-#define ATRACE_INSTANT_FOR_TRACK(trackName, name) \
- atrace_instant_for_track(ATRACE_TAG, trackName, name)
-static inline void atrace_instant_for_track(uint64_t tag, const char* track_name,
- const char* name) {
- if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
- void atrace_instant_for_track_body(const char*, const char*);
- atrace_instant_for_track_body(track_name, name);
- }
-}
-
-/**
* Traces an integer counter value. name is used to identify the counter.
* This can be used to track how a value changes over time.
*/
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index bdb807538..8f22d8983 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -127,17 +127,9 @@
#define AID_EXT_DATA_RW 1078 /* GID for app-private data directories on external storage */
#define AID_EXT_OBB_RW 1079 /* GID for OBB directories on external storage */
#define AID_CONTEXT_HUB 1080 /* GID for access to the Context Hub */
-#define AID_VIRTUALIZATIONSERVICE 1081 /* VirtualizationService daemon */
+#define AID_VIRTMANAGER 1081 /* VirtManager daemon */
#define AID_ARTD 1082 /* ART Service daemon */
#define AID_UWB 1083 /* UWB subsystem */
-#define AID_THREAD_NETWORK 1084 /* Thread Network subsystem */
-#define AID_DICED 1085 /* Android's DICE daemon */
-#define AID_DMESGD 1086 /* dmesg parsing daemon for kernel report collection */
-#define AID_JC_WEAVER 1087 /* Javacard Weaver HAL - to manage omapi ARA rules */
-#define AID_JC_STRONGBOX 1088 /* Javacard Strongbox HAL - to manage omapi ARA rules */
-#define AID_JC_IDENTITYCRED 1089 /* Javacard Identity Cred HAL - to manage omapi ARA rules */
-#define AID_SDK_SANDBOX 1090 /* SDK sandbox virtual UID */
-#define AID_SECURITY_LOG_WRITER 1091 /* write to security log */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
@@ -165,7 +157,6 @@
#define AID_READPROC 3009 /* Allow /proc read access */
#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */
#define AID_UHID 3011 /* Allow read/write to /dev/uhid node */
-#define AID_READTRACEFS 3012 /* Allow tracefs read */
/* The range 5000-5999 is also reserved for vendor partition. */
#define AID_OEM_RESERVED_2_START 5000
@@ -215,10 +206,6 @@
*/
#define AID_OVERFLOWUID 65534 /* unmapped user in the user namespace */
-/* use the ranges below to determine whether a process is sdk sandbox */
-#define AID_SDK_SANDBOX_PROCESS_START 20000 /* start of uids allocated to sdk sandbox processes */
-#define AID_SDK_SANDBOX_PROCESS_END 29999 /* end of uids allocated to sdk sandbox processes */
-
/* use the ranges below to determine whether a process is isolated */
#define AID_ISOLATED_START 90000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
diff --git a/libcutils/include/private/android_projectid_config.h b/libcutils/include/private/android_projectid_config.h
index 56a39a625..7ef385405 100644
--- a/libcutils/include/private/android_projectid_config.h
+++ b/libcutils/include/private/android_projectid_config.h
@@ -49,13 +49,3 @@
#define PROJECT_ID_EXT_OBB_START 40000
/* End of project IDs for apps to mark external OBB data. */
#define PROJECT_ID_EXT_OBB_END 49999
-
-/* Start of project IDs for apps to mark internal app data. */
-#define PROJECT_ID_APP_START 50000
-/* End of project IDs for apps to mark internal app data. */
-#define PROJECT_ID_APP_END 59999
-
-/* Start of project IDs for apps to mark internal app cache data. */
-#define PROJECT_ID_APP_CACHE_START 60000
-/* End of project IDs for apps to mark internal app cache data. */
-#define PROJECT_ID_APP_CACHE_END 69999
diff --git a/libcutils/multiuser.cpp b/libcutils/multiuser.cpp
index 967f9918b..0fd3d0c52 100644
--- a/libcutils/multiuser.cpp
+++ b/libcutils/multiuser.cpp
@@ -29,25 +29,6 @@ uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) {
return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET);
}
-uid_t multiuser_get_sdk_sandbox_uid(userid_t user_id, appid_t app_id) {
- int sdk_sandbox_offset = AID_SDK_SANDBOX_PROCESS_START - AID_APP_START;
- if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
- return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET) + sdk_sandbox_offset;
- } else {
- return -1;
- }
-}
-
-uid_t multiuser_convert_sdk_sandbox_to_app_uid(uid_t uid) {
- appid_t app_id = multiuser_get_app_id(uid);
- int sdk_sandbox_offset = AID_SDK_SANDBOX_PROCESS_START - AID_APP_START;
- if (app_id >= AID_SDK_SANDBOX_PROCESS_START && app_id <= AID_SDK_SANDBOX_PROCESS_END) {
- return uid - sdk_sandbox_offset;
- } else {
- return -1;
- }
-}
-
gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id) {
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START);
diff --git a/libcutils/multiuser_test.cpp b/libcutils/multiuser_test.cpp
index b57223d17..4b0fd130f 100644
--- a/libcutils/multiuser_test.cpp
+++ b/libcutils/multiuser_test.cpp
@@ -18,7 +18,6 @@
#include <gtest/gtest.h>
static constexpr auto ERR_GID = static_cast<gid_t>(-1);
-static constexpr auto ERR_UID = static_cast<uid_t>(-1);
TEST(MultiuserTest, TestMerge) {
EXPECT_EQ(0U, multiuser_get_uid(0, 0));
@@ -31,40 +30,6 @@ TEST(MultiuserTest, TestMerge) {
EXPECT_EQ(1050000U, multiuser_get_uid(10, 50000));
}
-TEST(MultiuserTest, TestSdkSandboxUid) {
- EXPECT_EQ(ERR_UID, multiuser_get_sdk_sandbox_uid(0, 0));
- EXPECT_EQ(ERR_UID, multiuser_get_sdk_sandbox_uid(0, 1000));
- EXPECT_EQ(20000U, multiuser_get_sdk_sandbox_uid(0, 10000));
- EXPECT_EQ(25000U, multiuser_get_sdk_sandbox_uid(0, 15000));
- EXPECT_EQ(29999U, multiuser_get_sdk_sandbox_uid(0, 19999));
- EXPECT_EQ(ERR_UID, multiuser_get_sdk_sandbox_uid(0, 50000));
-
- EXPECT_EQ(ERR_UID, multiuser_get_sdk_sandbox_uid(10, 0));
- EXPECT_EQ(ERR_UID, multiuser_get_sdk_sandbox_uid(10, 1000));
- EXPECT_EQ(1020000U, multiuser_get_sdk_sandbox_uid(10, 10000));
- EXPECT_EQ(1025000U, multiuser_get_sdk_sandbox_uid(10, 15000));
- EXPECT_EQ(ERR_UID, multiuser_get_sdk_sandbox_uid(10, 20000));
- EXPECT_EQ(ERR_UID, multiuser_get_sdk_sandbox_uid(10, 50000));
-}
-
-TEST(MultiuserTest, TestSdkSandboxUidConvertation) {
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(0));
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(1000));
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(10000));
- EXPECT_EQ(10000U, multiuser_convert_sdk_sandbox_to_app_uid(20000));
- EXPECT_EQ(15000U, multiuser_convert_sdk_sandbox_to_app_uid(25000));
- EXPECT_EQ(19999U, multiuser_convert_sdk_sandbox_to_app_uid(29999));
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(50000));
-
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(1000000));
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(1001000));
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(1010000));
- EXPECT_EQ(1010000U, multiuser_convert_sdk_sandbox_to_app_uid(1020000));
- EXPECT_EQ(1015000U, multiuser_convert_sdk_sandbox_to_app_uid(1025000));
- EXPECT_EQ(1019999U, multiuser_convert_sdk_sandbox_to_app_uid(1029999));
- EXPECT_EQ(ERR_UID, multiuser_convert_sdk_sandbox_to_app_uid(1050000));
-}
-
TEST(MultiuserTest, TestSplitUser) {
EXPECT_EQ(0U, multiuser_get_user_id(0));
EXPECT_EQ(0U, multiuser_get_user_id(1000));
diff --git a/libcutils/qtaguid.cpp b/libcutils/qtaguid.cpp
index a987b855d..2fe877c4e 100644
--- a/libcutils/qtaguid.cpp
+++ b/libcutils/qtaguid.cpp
@@ -34,6 +34,8 @@ class netdHandler {
public:
int (*netdTagSocket)(int, uint32_t, uid_t);
int (*netdUntagSocket)(int);
+ int (*netdSetCounterSet)(uint32_t, uid_t);
+ int (*netdDeleteTagData)(uint32_t, uid_t);
};
int stubTagSocket(int, uint32_t, uid_t) {
@@ -44,8 +46,16 @@ int stubUntagSocket(int) {
return -EREMOTEIO;
}
+int stubSetCounterSet(uint32_t, uid_t) {
+ return -EREMOTEIO;
+}
+
+int stubDeleteTagData(uint32_t, uid_t) {
+ return -EREMOTEIO;
+}
+
netdHandler initHandler(void) {
- netdHandler handler = {stubTagSocket, stubUntagSocket};
+ netdHandler handler = {stubTagSocket, stubUntagSocket, stubSetCounterSet, stubDeleteTagData};
void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW);
if (!netdClientHandle) {
@@ -63,6 +73,15 @@ netdHandler initHandler(void) {
ALOGE("load netdUntagSocket handler failed: %s", dlerror());
}
+ handler.netdSetCounterSet = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "setCounterSet");
+ if (!handler.netdSetCounterSet) {
+ ALOGE("load netdSetCounterSet handler failed: %s", dlerror());
+ }
+
+ handler.netdDeleteTagData = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "deleteTagData");
+ if (!handler.netdDeleteTagData) {
+ ALOGE("load netdDeleteTagData handler failed: %s", dlerror());
+ }
return handler;
}
@@ -95,3 +114,13 @@ int qtaguid_untagSocket(int sockfd) {
ALOGV("Untagging socket %d", sockfd);
return getHandler().netdUntagSocket(sockfd);
}
+
+int qtaguid_setCounterSet(int counterSetNum, uid_t uid) {
+ ALOGV("Setting counters to set %d for uid %d", counterSetNum, uid);
+ return getHandler().netdSetCounterSet(counterSetNum, uid);
+}
+
+int qtaguid_deleteTagData(int tag, uid_t uid) {
+ ALOGV("Deleting tag data with tag %u for uid %d", tag, uid);
+ return getHandler().netdDeleteTagData(tag, uid);
+}
diff --git a/libcutils/rust/cutils.h b/libcutils/rust/cutils.h
new file mode 100644
index 000000000..9b78af631
--- /dev/null
+++ b/libcutils/rust/cutils.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <cutils/multiuser.h>
+#include <private/android_filesystem_config.h>
diff --git a/libcutils/trace-container.cpp b/libcutils/trace-container.cpp
index 8901e4a40..f7eed48aa 100644
--- a/libcutils/trace-container.cpp
+++ b/libcutils/trace-container.cpp
@@ -131,41 +131,29 @@ static inline uint64_t gettime(clockid_t clk_id)
// Write trace events to container trace file. Note that we need to amend tid and time information
// here comparing to normal ftrace, where those informations are added by kernel.
-#define WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, \
- track_name, name, value) { \
+#define WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value) { \
char buf[CONTAINER_ATRACE_MESSAGE_LENGTH]; \
- const char* track_name_sep = track_name[0] != '\0' ? "|" : ""; \
int pid = getpid(); \
int tid = gettid(); \
uint64_t ts = gettime(CLOCK_MONOTONIC); \
uint64_t tts = gettime(CLOCK_THREAD_CPUTIME_ID); \
int len = snprintf( \
buf, sizeof(buf), \
- ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s%s%s" value_format, \
- pid, tid, ts, tts, track_name, track_name_sep, name, value); \
+ ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s" value_format, \
+ pid, tid, ts, tts, name, value); \
if (len >= (int) sizeof(buf)) { \
int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
/* Truncate the name to make the message fit. */ \
if (name_len > 0) { \
+ ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
len = snprintf( \
- buf, sizeof(buf), \
- ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s%s%.*s" value_format, \
- pid, tid, ts, tts, track_name, track_name_sep, name_len, name, value); \
- } else { \
- int track_name_len = 0; \
- if (track_name[0] != '\0') { \
- track_name_len = strlen(track_name) - (len - strlen(name) - sizeof(buf)) - 2; \
- } \
- if (track_name_len <= 0){ \
- /* Data is still too long. Drop it. */ \
- len = 0; \
- } else { \
- /* Truncate the trackName and name to make the message fit. */ \
- len = snprintf( \
buf, sizeof(buf), \
- ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%.*s|%.1s" value_format, \
- pid, tid, ts, tts, track_name_len, track_name, name, value); \
- } \
+ ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%.*s" value_format, \
+ pid, tid, ts, tts, name_len, name, value); \
+ } else { \
+ /* Data is still too long. Drop it. */ \
+ ALOGW("Data is too long in %s: %s\n", __FUNCTION__, name); \
+ len = 0; \
} \
} \
if (len > 0) { \
@@ -173,10 +161,10 @@ static inline uint64_t gettime(clockid_t clk_id)
} \
}
-#define WRITE_MSG_IN_CONTAINER(ph, sep_before_name, value_format, track_name, name, value) { \
+#define WRITE_MSG_IN_CONTAINER(ph, sep_before_name, value_format, name, value) { \
pthread_rwlock_rdlock(&atrace_container_sock_rwlock); \
if (atrace_container_sock_fd != -1) { \
- WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, track_name, name, value); \
+ WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value); \
} \
pthread_rwlock_unlock(&atrace_container_sock_rwlock); \
}
@@ -184,115 +172,71 @@ static inline uint64_t gettime(clockid_t clk_id)
void atrace_begin_body(const char* name)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("B", "|", "%s", "", name, "");
+ WRITE_MSG_IN_CONTAINER("B", "|", "%s", name, "");
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("B|%d|", "%s", "", name, "");
+ WRITE_MSG("B|%d|", "%s", name, "");
}
void atrace_end_body()
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("E", "", "%s", "", "", "");
+ WRITE_MSG_IN_CONTAINER("E", "", "%s", "", "");
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("E|%d", "%s", "", "", "");
+ WRITE_MSG("E|%d", "%s", "", "");
}
void atrace_async_begin_body(const char* name, int32_t cookie)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("S", "|", "|%d", "", name, cookie);
+ WRITE_MSG_IN_CONTAINER("S", "|", "|%d", name, cookie);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("S|%d|", "|%" PRId32, "", name, cookie);
+ WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("F", "|", "|%d", "", name, cookie);
- return;
- }
-
- if (atrace_marker_fd < 0) return;
-
- WRITE_MSG("F|%d|", "|%" PRId32, "", name, cookie);
-}
-
-void atrace_async_for_track_begin_body(const char* track_name, const char* name, int32_t cookie) {
- if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("T", "|", "|%d", track_name, name, cookie);
- return;
- }
-
- if (atrace_marker_fd < 0) return;
-
- WRITE_MSG("T|%d|", "|%" PRId32, track_name, name, cookie);
-}
-
-void atrace_async_for_track_end_body(const char* track_name, const char* name, int32_t cookie) {
- if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("U", "|", "|%d", track_name, name, cookie);
- return;
- }
-
- if (atrace_marker_fd < 0) return;
-
- WRITE_MSG("U|%d|", "|%" PRId32, track_name, name, cookie);
-}
-
-void atrace_instant_body(const char* name) {
- if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("I", "|", "%s", "", name, "");
- return;
- }
-
- if (atrace_marker_fd < 0) return;
-
- WRITE_MSG("I|%d|", "%s", "", name, "");
-}
-
-void atrace_instant_for_track_body(const char* track_name, const char* name) {
- if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("N", "|", "%s", track_name, name, "");
+ WRITE_MSG_IN_CONTAINER("F", "|", "|%d", name, cookie);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("N|%d|", "%s", track_name, name, "");
+ WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
}
void atrace_int_body(const char* name, int32_t value)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId32, "", name, value);
+ WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId32, name, value);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("C|%d|", "|%" PRId32, "", name, value);
+ WRITE_MSG("C|%d|", "|%" PRId32, name, value);
}
void atrace_int64_body(const char* name, int64_t value)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId64, "", name, value);
+ WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId64, name, value);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("C|%d|", "|%" PRId64, "", name, value);
+ WRITE_MSG("C|%d|", "|%" PRId64, name, value);
}
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index eacc8ee56..1ab63dc2f 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -71,46 +71,30 @@ void atrace_setup()
void atrace_begin_body(const char* name)
{
- WRITE_MSG("B|%d|", "%s", "", name, "");
+ WRITE_MSG("B|%d|", "%s", name, "");
}
void atrace_end_body()
{
- WRITE_MSG("E|%d", "%s", "", "", "");
+ WRITE_MSG("E|%d", "%s", "", "");
}
void atrace_async_begin_body(const char* name, int32_t cookie)
{
- WRITE_MSG("S|%d|", "|%" PRId32, "", name, cookie);
+ WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
- WRITE_MSG("F|%d|", "|%" PRId32, "", name, cookie);
-}
-
-void atrace_async_for_track_begin_body(const char* track_name, const char* name, int32_t cookie) {
- WRITE_MSG("T|%d|", "|%" PRId32, track_name, name, cookie);
-}
-
-void atrace_async_for_track_end_body(const char* track_name, const char* name, int32_t cookie) {
- WRITE_MSG("U|%d|", "|%" PRId32, track_name, name, cookie);
-}
-
-void atrace_instant_body(const char* name) {
- WRITE_MSG("I|%d|", "%s", "", name, "");
-}
-
-void atrace_instant_for_track_body(const char* track_name, const char* name) {
- WRITE_MSG("N|%d|", "%s", track_name, name, "");
+ WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
}
void atrace_int_body(const char* name, int32_t value)
{
- WRITE_MSG("C|%d|", "|%" PRId32, "", name, value);
+ WRITE_MSG("C|%d|", "|%" PRId32, name, value);
}
void atrace_int64_body(const char* name, int64_t value)
{
- WRITE_MSG("C|%d|", "|%" PRId64, "", name, value);
+ WRITE_MSG("C|%d|", "|%" PRId64, name, value);
}
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index 94945ec7d..3b459e094 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -185,36 +185,21 @@ void atrace_update_tags()
}
}
-#define WRITE_MSG(format_begin, format_end, track_name, name, value) { \
+#define WRITE_MSG(format_begin, format_end, name, value) { \
char buf[ATRACE_MESSAGE_LENGTH] __attribute__((uninitialized)); \
- const char* track_name_sep = track_name[0] != '\0' ? "|" : ""; \
int pid = getpid(); \
- int len = snprintf(buf, sizeof(buf), format_begin "%s%s%s" format_end, pid, \
- track_name, track_name_sep, name, value); \
+ int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
+ name, value); \
if (len >= (int) sizeof(buf)) { \
+ /* Given the sizeof(buf), and all of the current format buffers, \
+ * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
/* Truncate the name to make the message fit. */ \
- if (name_len > 0) { \
- len = snprintf(buf, sizeof(buf), format_begin "%s%s%.*s" format_end, pid, \
- track_name, track_name_sep, name_len, name, value); \
- } else { \
- int track_name_len = 0; \
- if (track_name[0] != '\0') { \
- track_name_len = strlen(track_name) - (len - strlen(name) - sizeof(buf)) - 2; \
- } \
- if (track_name_len <= 0) { \
- /* Data is still too long. Drop it. */ \
- len = 0; \
- } else { \
- /* Truncate the trackName and name to make the message fit */ \
- len = snprintf(buf, sizeof(buf), format_begin "%.*s|%.1s" format_end, pid, \
- track_name_len, track_name, name, value); \
- } \
- } \
- } \
- if (len > 0) { \
- write(atrace_marker_fd, buf, len); \
+ ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
+ len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
+ name_len, name, value); \
} \
+ write(atrace_marker_fd, buf, len); \
}
#endif // __TRACE_DEV_INC
diff --git a/libcutils/trace-dev_test.cpp b/libcutils/trace-dev_test.cpp
index 841674a99..832b36a0c 100644
--- a/libcutils/trace-dev_test.cpp
+++ b/libcutils/trace-dev_test.cpp
@@ -195,383 +195,6 @@ TEST_F(TraceDevTest, atrace_async_end_body_truncated) {
ASSERT_STREQ(expected.c_str(), actual.c_str());
}
-TEST_F(TraceDevTest, atrace_async_for_track_begin_body_normal) {
- atrace_async_for_track_begin_body("fake_track", "fake_name", 12345);
-
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- std::string expected = android::base::StringPrintf("T|%d|fake_track|fake_name|12345", getpid());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_begin_body_exact_track_name) {
- const int name_size = 5;
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
- std::string track_name =
- MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - name_size - 6);
- atrace_async_for_track_begin_body(track_name.c_str(), "name", 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += track_name + "|name|12345";
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-
- // Add a single character and verify name truncation
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- track_name += '*';
- expected = android::base::StringPrintf("T|%d|", getpid());
- expected += track_name + "|nam|12345";
- atrace_async_for_track_begin_body(track_name.c_str(), "name", 12345);
- EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_begin_body_truncated_track_name) {
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
- std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_begin_body(track_name.c_str(), "name", 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 9;
- expected += android::base::StringPrintf("%.*s|n|12345", expected_len, track_name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_begin_body_exact_name) {
- const int track_name_size = 11;
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
- std::string name =
- MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - track_name_size - 6);
- atrace_async_for_track_begin_body("track_name", name.c_str(), 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += "track_name|" + name + "|12345";
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-
- // Add a single character and verify we get the same value as before.
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- name += '*';
- atrace_async_for_track_begin_body("track_name", name.c_str(), 12345);
- EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_begin_body_truncated_name) {
- std::string expected = android::base::StringPrintf("T|%d|track_name|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_begin_body("track_name", name.c_str(), 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1 - 6;
- expected += android::base::StringPrintf("%.*s|12345", expected_len, name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_begin_body_truncated_both) {
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_begin_body(track_name.c_str(), name.c_str(), 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 3 - 6;
- expected += android::base::StringPrintf("%.*s|%.1s|12345", expected_len, track_name.c_str(),
- name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_normal) {
- atrace_async_for_track_end_body("fake_track", "fake_name", 12345);
-
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- std::string expected = android::base::StringPrintf("U|%d|fake_track|fake_name|12345", getpid());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_exact_track_name) {
- const int name_size = 5;
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
- std::string track_name =
- MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - name_size - 6);
- atrace_async_for_track_end_body(track_name.c_str(), "name", 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += track_name + "|name|12345";
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-
- // Add a single character and verify name truncation
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- track_name += '*';
- expected = android::base::StringPrintf("U|%d|", getpid());
- expected += track_name + "|nam|12345";
- atrace_async_for_track_end_body(track_name.c_str(), "name", 12345);
- EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_truncated_track_name) {
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
- std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_end_body(track_name.c_str(), "name", 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 9;
- expected += android::base::StringPrintf("%.*s|n|12345", expected_len, track_name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_exact_name) {
- const int track_name_size = 11;
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
- std::string name =
- MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - track_name_size - 6);
- atrace_async_for_track_end_body("track_name", name.c_str(), 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += "track_name|" + name + "|12345";
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-
- // Add a single character and verify we get the same value as before.
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- name += '*';
- atrace_async_for_track_end_body("track_name", name.c_str(), 12345);
- EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_truncated_name) {
- std::string expected = android::base::StringPrintf("U|%d|track_name|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_end_body("track_name", name.c_str(), 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1 - 6;
- expected += android::base::StringPrintf("%.*s|12345", expected_len, name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_truncated_both) {
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_end_body(track_name.c_str(), name.c_str(), 12345);
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 3 - 6;
- expected += android::base::StringPrintf("%.*s|%.1s|12345", expected_len, track_name.c_str(),
- name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_body_normal) {
- atrace_instant_body("fake_name");
-
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- std::string expected = android::base::StringPrintf("I|%d|fake_name", getpid());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_body_exact) {
- std::string expected = android::base::StringPrintf("I|%d|", getpid());
- std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1);
- atrace_instant_body(name.c_str());
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += name;
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-
- // Add a single character and verify we get the exact same value as before.
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- name += '*';
- atrace_instant_body(name.c_str());
- EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_body_truncated) {
- std::string expected = android::base::StringPrintf("I|%d|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_instant_body(name.c_str());
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1;
- expected += android::base::StringPrintf("%.*s", expected_len, name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_for_track_body_normal) {
- atrace_instant_for_track_body("fake_track", "fake_name");
-
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- std::string expected = android::base::StringPrintf("N|%d|fake_track|fake_name", getpid());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_for_track_body_exact_track_name) {
- const int name_size = 5;
- std::string expected = android::base::StringPrintf("N|%d|", getpid());
- std::string track_name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - name_size);
- atrace_instant_for_track_body(track_name.c_str(), "name");
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += track_name + "|name";
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-
- // Add a single character and verify name truncation
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- track_name += '*';
- expected = android::base::StringPrintf("N|%d|", getpid());
- expected += track_name + "|nam";
- atrace_instant_for_track_body(track_name.c_str(), "name");
- EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated_track_name) {
- std::string expected = android::base::StringPrintf("N|%d|", getpid());
- std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_instant_for_track_body(track_name.c_str(), "name");
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 3;
- expected += android::base::StringPrintf("%.*s|n", expected_len, track_name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_for_track_body_exact_name) {
- const int track_name_size = 11;
- std::string expected = android::base::StringPrintf("N|%d|", getpid());
- std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - track_name_size);
- atrace_instant_for_track_body("track_name", name.c_str());
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += "track_name|" + name;
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-
- // Add a single character and verify we get the same value as before.
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- name += '*';
- atrace_instant_for_track_body("track_name", name.c_str());
- EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated_name) {
- std::string expected = android::base::StringPrintf("N|%d|track_name|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_instant_for_track_body("track_name", name.c_str());
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1;
- expected += android::base::StringPrintf("%.*s", expected_len, name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated_both) {
- std::string expected = android::base::StringPrintf("N|%d|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_instant_for_track_body(track_name.c_str(), name.c_str());
-
- ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
- ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
-
- std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 3;
- expected +=
- android::base::StringPrintf("%.*s|%.1s", expected_len, track_name.c_str(), name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
TEST_F(TraceDevTest, atrace_int_body_normal) {
atrace_int_body("fake_name", 12345);
diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp
index c2a379b2f..9781ad3e4 100644
--- a/libcutils/trace-host.cpp
+++ b/libcutils/trace-host.cpp
@@ -28,12 +28,6 @@ void atrace_begin_body(const char* /*name*/) {}
void atrace_end_body() { }
void atrace_async_begin_body(const char* /*name*/, int32_t /*cookie*/) {}
void atrace_async_end_body(const char* /*name*/, int32_t /*cookie*/) {}
-void atrace_async_for_track_begin_body(const char* /*track_name*/, const char* /*name*/,
- int32_t /*cookie*/) {}
-void atrace_async_for_track_end_body(const char* /*track_name*/, const char* /*name*/,
- int32_t /*cookie*/) {}
-void atrace_instant_body(const char* /*name*/) {}
-void atrace_instant_for_track_body(const char* /*track_name*/, const char* /*name*/) {}
void atrace_int_body(const char* /*name*/, int32_t /*value*/) {}
void atrace_int64_body(const char* /*name*/, int64_t /*value*/) {}
void atrace_init() {}
diff --git a/libdiskconfig/Android.bp b/libdiskconfig/Android.bp
index f523d4e70..a3d643e2c 100644
--- a/libdiskconfig/Android.bp
+++ b/libdiskconfig/Android.bp
@@ -27,8 +27,12 @@ cc_library {
darwin: {
enabled: false,
},
- host_linux: {
+ linux_glibc: {
cflags: [
+ "-O2",
+ "-g",
+ "-W",
+ "-Wall",
"-D_LARGEFILE64_SOURCE",
],
},
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index 16103d2f3..f31b5f1a0 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -44,9 +44,4 @@ cc_library {
shared_libs: ["android.hardware.graphics.allocator@2.0"],
header_libs: ["libhardware_headers"],
min_sdk_version: "29",
- apex_available: [
- "//apex_available:platform",
- "com.android.media.swcodec",
- "test_com.android.media.swcodec",
- ],
}
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index 3af07b47c..86f68fb57 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -5,16 +5,16 @@ package {
license {
name: "system_core_libkeyutils_license",
visibility: [":__subpackages__"],
- license_kinds: ["SPDX-license-identifier-BSD"],
- license_text: ["NOTICE"],
+ license_kinds: [
+ "SPDX-license-identifier-BSD",
+ ],
+ // large-scale-change unable to identify any license_text files
}
cc_library {
name: "libkeyutils",
cflags: ["-Werror"],
defaults: ["linux_bionic_supported"],
- ramdisk_available: true,
- vendor_ramdisk_available: true,
recovery_available: true,
export_include_dirs: ["include/"],
local_include_dirs: ["include/"],
diff --git a/libkeyutils/NOTICE b/libkeyutils/NOTICE
deleted file mode 100644
index 5828550d5..000000000
--- a/libkeyutils/NOTICE
+++ /dev/null
@@ -1,25 +0,0 @@
-Copyright (C) 2017 The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
diff --git a/libmodprobe/Android.bp b/libmodprobe/Android.bp
index 525a88063..ba11dc920 100644
--- a/libmodprobe/Android.bp
+++ b/libmodprobe/Android.bp
@@ -8,7 +8,6 @@ cc_library_static {
"-Werror",
],
vendor_available: true,
- ramdisk_available: true,
recovery_available: true,
srcs: [
"libmodprobe.cpp",
diff --git a/libmodprobe/TEST_MAPPING b/libmodprobe/TEST_MAPPING
deleted file mode 100644
index 888593e16..000000000
--- a/libmodprobe/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "libmodprobe_tests"
- }
- ],
- "hwasan-postsubmit": [
- {
- "name": "libmodprobe_tests"
- }
- ]
-}
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index 5d79d6ab6..c934860ec 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -16,21 +16,17 @@
#pragma once
-#include <mutex>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
-#include <android-base/thread_annotations.h>
-
class Modprobe {
public:
Modprobe(const std::vector<std::string>&, const std::string load_file = "modules.load",
bool use_blocklist = true);
- bool LoadModulesParallel(int num_threads);
bool LoadListedModules(bool strict = true);
bool LoadWithAliases(const std::string& module_name, bool strict,
const std::string& parameters = "");
@@ -70,9 +66,7 @@ class Modprobe {
std::vector<std::string> module_load_;
std::unordered_map<std::string, std::string> module_options_;
std::set<std::string> module_blocklist_;
- std::mutex module_loaded_lock_;
std::unordered_set<std::string> module_loaded_;
- std::unordered_set<std::string> module_loaded_paths_;
int module_count_ = 0;
bool blocklist_enabled = false;
};
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 3054d2b43..1a9d3642c 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -21,10 +21,8 @@
#include <sys/syscall.h>
#include <algorithm>
-#include <map>
#include <set>
#include <string>
-#include <thread>
#include <vector>
#include <android-base/chrono_utils.h>
@@ -439,97 +437,6 @@ bool Modprobe::IsBlocklisted(const std::string& module_name) {
return module_blocklist_.count(canonical_name) > 0;
}
-// Another option to load kernel modules. load in independent modules in parallel
-// and then load modules which only have soft dependency, third update dependency list of other
-// remaining modules, repeat these steps until all modules are loaded.
-bool Modprobe::LoadModulesParallel(int num_threads) {
- bool ret = true;
- std::map<std::string, std::set<std::string>> mod_with_deps;
- std::map<std::string, std::set<std::string>> mod_with_softdeps;
-
- // Get dependencies
- for (const auto& module : module_load_) {
- auto dependencies = GetDependencies(MakeCanonical(module));
-
- for (auto dep = dependencies.rbegin(); dep != dependencies.rend(); dep++) {
- mod_with_deps[module].emplace(*dep);
- }
- }
-
- // Get soft dependencies
- for (const auto& [it_mod, it_softdep] : module_pre_softdep_) {
- mod_with_softdeps[MakeCanonical(it_mod)].emplace(it_softdep);
- }
-
- // Get soft post dependencies
- for (const auto& [it_mod, it_softdep] : module_post_softdep_) {
- mod_with_softdeps[MakeCanonical(it_mod)].emplace(it_softdep);
- }
-
- while (!mod_with_deps.empty()) {
- std::vector<std::thread> threads;
- std::vector<std::string> mods_path_to_load;
- std::vector<std::string> mods_with_softdep_to_load;
- std::mutex vector_lock;
-
- // Find independent modules and modules only having soft dependencies
- for (const auto& [it_mod, it_dep] : mod_with_deps) {
- if (it_dep.size() == 1 && mod_with_softdeps[it_mod].empty()) {
- mods_path_to_load.emplace_back(*(it_dep.begin()));
- } else if (it_dep.size() == 1) {
- mods_with_softdep_to_load.emplace_back(it_mod);
- }
- }
-
- // Load independent modules in parallel
- auto thread_function = [&] {
- std::unique_lock lk(vector_lock);
- while (!mods_path_to_load.empty()) {
- auto mod_path_to_load = std::move(mods_path_to_load.back());
- mods_path_to_load.pop_back();
-
- lk.unlock();
- ret &= Insmod(mod_path_to_load, "");
- lk.lock();
- }
- };
-
- std::generate_n(std::back_inserter(threads), num_threads,
- [&] { return std::thread(thread_function); });
-
- // Wait for the threads.
- for (auto& thread : threads) {
- thread.join();
- }
-
- // Since we cannot assure if these soft dependencies tree are overlap,
- // we loaded these modules one by one.
- for (auto dep = mods_with_softdep_to_load.rbegin(); dep != mods_with_softdep_to_load.rend();
- dep++) {
- ret &= LoadWithAliases(*dep, true);
- }
-
- std::lock_guard guard(module_loaded_lock_);
- // Remove loaded module form mod_with_deps and soft dependencies of other modules
- for (const auto& module_loaded : module_loaded_) {
- mod_with_deps.erase(module_loaded);
-
- for (auto& [mod, softdeps] : mod_with_softdeps) {
- softdeps.erase(module_loaded);
- }
- }
-
- // Remove loaded module form dependencies of other modules which are not loaded yet
- for (const auto& module_loaded_path : module_loaded_paths_) {
- for (auto& [mod, deps] : mod_with_deps) {
- deps.erase(module_loaded_path);
- }
- }
- }
-
- return ret;
-}
-
bool Modprobe::LoadListedModules(bool strict) {
auto ret = true;
for (const auto& module : module_load_) {
diff --git a/libmodprobe/libmodprobe_ext.cpp b/libmodprobe/libmodprobe_ext.cpp
index 94a1dc4e9..fb1f5e73e 100644
--- a/libmodprobe/libmodprobe_ext.cpp
+++ b/libmodprobe/libmodprobe_ext.cpp
@@ -54,8 +54,6 @@ bool Modprobe::Insmod(const std::string& path_name, const std::string& parameter
if (ret != 0) {
if (errno == EEXIST) {
// Module already loaded
- std::lock_guard guard(module_loaded_lock_);
- module_loaded_paths_.emplace(path_name);
module_loaded_.emplace(canonical_name);
return true;
}
@@ -64,8 +62,6 @@ bool Modprobe::Insmod(const std::string& path_name, const std::string& parameter
}
LOG(INFO) << "Loaded kernel module " << path_name;
- std::lock_guard guard(module_loaded_lock_);
- module_loaded_paths_.emplace(path_name);
module_loaded_.emplace(canonical_name);
module_count_++;
return true;
@@ -78,7 +74,6 @@ bool Modprobe::Rmmod(const std::string& module_name) {
PLOG(ERROR) << "Failed to remove module '" << module_name << "'";
return false;
}
- std::lock_guard guard(module_loaded_lock_);
module_loaded_.erase(canonical_name);
return true;
}
diff --git a/libmodprobe/libmodprobe_test.cpp b/libmodprobe/libmodprobe_test.cpp
index f92a2b669..f960b6139 100644
--- a/libmodprobe/libmodprobe_test.cpp
+++ b/libmodprobe/libmodprobe_test.cpp
@@ -188,11 +188,10 @@ TEST(libmodprobe, Test) {
EXPECT_TRUE(modules_loaded == expected_after_remove);
- Modprobe m2({dir.path});
-
- EXPECT_FALSE(m2.LoadWithAliases("test4", true));
- while (modules_loaded.size() > 0) EXPECT_TRUE(m2.Remove(modules_loaded.front()));
- EXPECT_TRUE(m2.LoadListedModules());
+ m = Modprobe({dir.path});
+ EXPECT_FALSE(m.LoadWithAliases("test4", true));
+ while (modules_loaded.size() > 0) EXPECT_TRUE(m.Remove(modules_loaded.front()));
+ EXPECT_TRUE(m.LoadListedModules());
GTEST_LOG_(INFO) << "Expected modules loaded after enabling blocklist (in order):";
for (auto i = expected_modules_blocklist_enabled.begin();
diff --git a/libnetutils/Android.bp b/libnetutils/Android.bp
index 02bd2e3dc..2864ad050 100644
--- a/libnetutils/Android.bp
+++ b/libnetutils/Android.bp
@@ -23,6 +23,7 @@ cc_library_shared {
},
srcs: [
+ "checksum.c",
"dhcpclient.c",
"dhcpmsg.c",
"ifc_utils.c",
@@ -34,10 +35,6 @@ cc_library_shared {
"liblog",
],
- static_libs: [
- "libip_checksum",
- ],
-
cflags: ["-Werror"],
export_include_dirs: ["include"],
@@ -48,6 +45,21 @@ cc_library_shared {
],
}
+cc_library_static {
+ name: "libipchecksum",
+
+ srcs: [
+ "checksum.c",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ export_include_dirs: ["include"],
+}
+
cc_binary {
name: "dhcpdbg",
diff --git a/libnetutils/checksum.c b/libnetutils/checksum.c
new file mode 100644
index 000000000..74b5fddf6
--- /dev/null
+++ b/libnetutils/checksum.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Daniel Drown
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * checksum.c - ipv4/ipv6 checksum calculation
+ */
+#include <netinet/icmp6.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include "netutils/checksum.h"
+
+/* function: ip_checksum_add
+ * adds data to a checksum. only known to work on little-endian hosts
+ * current - the current checksum (or 0 to start a new checksum)
+ * data - the data to add to the checksum
+ * len - length of data
+ */
+uint32_t ip_checksum_add(uint32_t current, const void* data, int len) {
+ uint32_t checksum = current;
+ int left = len;
+ const uint16_t* data_16 = data;
+
+ while (left > 1) {
+ checksum += *data_16;
+ data_16++;
+ left -= 2;
+ }
+ if (left) {
+ checksum += *(uint8_t*)data_16;
+ }
+
+ return checksum;
+}
+
+/* function: ip_checksum_fold
+ * folds a 32-bit partial checksum into 16 bits
+ * temp_sum - sum from ip_checksum_add
+ * returns: the folded checksum in network byte order
+ */
+uint16_t ip_checksum_fold(uint32_t temp_sum) {
+ while (temp_sum > 0xffff) {
+ temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF);
+ }
+ return temp_sum;
+}
+
+/* function: ip_checksum_finish
+ * folds and closes the checksum
+ * temp_sum - sum from ip_checksum_add
+ * returns: a header checksum value in network byte order
+ */
+uint16_t ip_checksum_finish(uint32_t temp_sum) {
+ return ~ip_checksum_fold(temp_sum);
+}
+
+/* function: ip_checksum
+ * combined ip_checksum_add and ip_checksum_finish
+ * data - data to checksum
+ * len - length of data
+ */
+uint16_t ip_checksum(const void* data, int len) {
+ // TODO: consider starting from 0xffff so the checksum of a buffer entirely consisting of zeros
+ // is correctly calculated as 0.
+ uint32_t temp_sum;
+
+ temp_sum = ip_checksum_add(0, data, len);
+ return ip_checksum_finish(temp_sum);
+}
+
+/* function: ipv6_pseudo_header_checksum
+ * calculate the pseudo header checksum for use in tcp/udp/icmp headers
+ * ip6 - the ipv6 header
+ * len - the transport length (transport header + payload)
+ * protocol - the transport layer protocol, can be different from ip6->ip6_nxt for fragments
+ */
+uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, uint8_t protocol) {
+ uint32_t checksum_len = htonl(len);
+ uint32_t checksum_next = htonl(protocol);
+
+ uint32_t current = 0;
+
+ current = ip_checksum_add(current, &(ip6->ip6_src), sizeof(struct in6_addr));
+ current = ip_checksum_add(current, &(ip6->ip6_dst), sizeof(struct in6_addr));
+ current = ip_checksum_add(current, &checksum_len, sizeof(checksum_len));
+ current = ip_checksum_add(current, &checksum_next, sizeof(checksum_next));
+
+ return current;
+}
+
+/* function: ipv4_pseudo_header_checksum
+ * calculate the pseudo header checksum for use in tcp/udp headers
+ * ip - the ipv4 header
+ * len - the transport length (transport header + payload)
+ */
+uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len) {
+ uint16_t temp_protocol, temp_length;
+
+ temp_protocol = htons(ip->protocol);
+ temp_length = htons(len);
+
+ uint32_t current = 0;
+
+ current = ip_checksum_add(current, &(ip->saddr), sizeof(uint32_t));
+ current = ip_checksum_add(current, &(ip->daddr), sizeof(uint32_t));
+ current = ip_checksum_add(current, &temp_protocol, sizeof(uint16_t));
+ current = ip_checksum_add(current, &temp_length, sizeof(uint16_t));
+
+ return current;
+}
+
+/* function: ip_checksum_adjust
+ * calculates a new checksum given a previous checksum and the old and new pseudo-header checksums
+ * checksum - the header checksum in the original packet in network byte order
+ * old_hdr_sum - the pseudo-header checksum of the original packet
+ * new_hdr_sum - the pseudo-header checksum of the translated packet
+ * returns: the new header checksum in network byte order
+ */
+uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum) {
+ // Algorithm suggested in RFC 1624.
+ // http://tools.ietf.org/html/rfc1624#section-3
+ checksum = ~checksum;
+ uint16_t folded_sum = ip_checksum_fold(checksum + new_hdr_sum);
+ uint16_t folded_old = ip_checksum_fold(old_hdr_sum);
+ if (folded_sum > folded_old) {
+ return ~(folded_sum - folded_old);
+ } else {
+ return ~(folded_sum - folded_old - 1); // end-around borrow
+ }
+}
diff --git a/libnetutils/include/netutils/checksum.h b/libnetutils/include/netutils/checksum.h
new file mode 100644
index 000000000..868217c5d
--- /dev/null
+++ b/libnetutils/include/netutils/checksum.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 Daniel Drown
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * checksum.h - checksum functions
+ */
+#ifndef __CHECKSUM_H__
+#define __CHECKSUM_H__
+
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <stdint.h>
+
+uint32_t ip_checksum_add(uint32_t current, const void* data, int len);
+uint16_t ip_checksum_finish(uint32_t temp_sum);
+uint16_t ip_checksum(const void* data, int len);
+
+uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, uint8_t protocol);
+uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len);
+
+uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum);
+
+#endif /* __CHECKSUM_H__ */
diff --git a/libpackagelistparser/TEST_MAPPING b/libpackagelistparser/TEST_MAPPING
deleted file mode 100644
index d69a7fb1d..000000000
--- a/libpackagelistparser/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "libpackagelistparser_test"
- }
- ],
- "hwasan-postsubmit": [
- {
- "name": "libpackagelistparser_test"
- }
- ]
-}
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 7b0e0d301..c68552d11 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -73,29 +73,3 @@ cc_library {
],
min_sdk_version: "29",
}
-
-cc_test {
- name: "task_profiles_test",
- host_supported: true,
- cflags: [
- "-Wall",
- "-Werror",
- "-Wexit-time-destructors",
- "-Wno-unused-parameter",
- ],
- srcs: [
- "task_profiles_test.cpp",
- ],
- header_libs: [
- "libcutils_headers",
- "libprocessgroup_headers",
- ],
- shared_libs: [
- "libbase",
- "libcgrouprc",
- "libprocessgroup",
- ],
- static_libs: [
- "libgmock",
- ],
-}
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 8c0032670..5ca096787 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -34,7 +34,6 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cgroup_map.h>
#include <json/reader.h>
@@ -42,10 +41,8 @@
#include <processgroup/processgroup.h>
using android::base::GetBoolProperty;
-using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::unique_fd;
-using android::base::WriteStringToFile;
static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs";
static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
@@ -205,40 +202,3 @@ CgroupController CgroupMap::FindController(const std::string& name) const {
return CgroupController(nullptr);
}
-
-CgroupController CgroupMap::FindControllerByPath(const std::string& path) const {
- if (!loaded_) {
- LOG(ERROR) << "CgroupMap::FindControllerByPath called for [" << getpid()
- << "] failed, RC file was not initialized properly";
- return CgroupController(nullptr);
- }
-
- auto controller_count = ACgroupFile_getControllerCount();
- for (uint32_t i = 0; i < controller_count; ++i) {
- const ACgroupController* controller = ACgroupFile_getController(i);
- if (StartsWith(path, ACgroupController_getPath(controller))) {
- return CgroupController(controller);
- }
- }
-
- return CgroupController(nullptr);
-}
-
-int CgroupMap::ActivateControllers(const std::string& path) const {
- if (__builtin_available(android 30, *)) {
- auto controller_count = ACgroupFile_getControllerCount();
- for (uint32_t i = 0; i < controller_count; ++i) {
- const ACgroupController* controller = ACgroupFile_getController(i);
- if (ACgroupController_getFlags(controller) &
- CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
- std::string str("+");
- str.append(ACgroupController_getName(controller));
- if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) {
- return -errno;
- }
- }
- }
- return 0;
- }
- return -ENOSYS;
-}
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index 5cdf8b28c..427d71b40 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -62,8 +62,6 @@ class CgroupMap {
static CgroupMap& GetInstance();
CgroupController FindController(const std::string& name) const;
- CgroupController FindControllerByPath(const std::string& path) const;
- int ActivateControllers(const std::string& path) const;
private:
bool loaded_ = false;
diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
index e704a36aa..100d60ea9 100644
--- a/libprocessgroup/cgrouprc/include/android/cgrouprc.h
+++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
@@ -16,7 +16,6 @@
#pragma once
-#include <sys/cdefs.h>
#include <stdint.h>
__BEGIN_DECLS
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 39b9f3fc0..fa2642d86 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -26,7 +26,6 @@ __BEGIN_DECLS
static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
-bool CgroupGetControllerFromPath(const std::string& path, std::string* cgroup_name);
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path);
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
@@ -35,8 +34,6 @@ bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& pr
#ifndef __ANDROID_VNDK__
-bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
-
static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
bool UsePerAppMemcg();
@@ -67,7 +64,6 @@ bool setProcessGroupSoftLimit(uid_t uid, int initialPid, int64_t softLimitInByte
bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes);
void removeAllProcessGroups(void);
-void removeAllEmptyProcessGroups(void);
// Provides the path for an attribute in a specific process group
// Returns false in case of error, true in case of success
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 267e62c67..c824376e5 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -69,40 +69,9 @@ bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
return true;
}
-static bool CgroupGetMemcgAppsPath(std::string* path) {
- CgroupController controller = CgroupMap::GetInstance().FindController("memory");
-
- if (!controller.HasValue()) {
- return false;
- }
-
- if (path) {
- *path = controller.path();
- if (controller.version() == 1) {
- *path += "/apps";
- }
- }
-
- return true;
-}
-
-bool CgroupGetControllerFromPath(const std::string& path, std::string* cgroup_name) {
- auto controller = CgroupMap::GetInstance().FindControllerByPath(path);
-
- if (!controller.HasValue()) {
- return false;
- }
-
- if (cgroup_name) {
- *cgroup_name = controller.name();
- }
-
- return true;
-}
-
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
- const IProfileAttribute* attr = tp.GetAttribute(attr_name);
+ const ProfileAttribute* attr = tp.GetAttribute(attr_name);
if (attr == nullptr) {
return false;
@@ -117,7 +86,7 @@ bool CgroupGetAttributePath(const std::string& attr_name, std::string* path) {
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
- const IProfileAttribute* attr = tp.GetAttribute(attr_name);
+ const ProfileAttribute* attr = tp.GetAttribute(attr_name);
if (attr == nullptr) {
return false;
@@ -143,37 +112,17 @@ static bool isMemoryCgroupSupported() {
}
void DropTaskProfilesResourceCaching() {
- TaskProfiles::GetInstance().DropResourceCaching(ProfileAction::RCT_TASK);
- TaskProfiles::GetInstance().DropResourceCaching(ProfileAction::RCT_PROCESS);
+ TaskProfiles::GetInstance().DropResourceCaching();
}
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
- return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, false);
-}
-
-bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
- return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, true);
+ return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles);
}
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
return TaskProfiles::GetInstance().SetTaskProfiles(tid, profiles, use_fd_cache);
}
-// C wrapper for SetProcessProfiles.
-// No need to have this in the header file because this function is specifically for crosvm. Crosvm
-// which is written in Rust has its own declaration of this foreign function and doesn't rely on the
-// header. See
-// https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3574427/5/src/linux/android.rs#12
-extern "C" bool android_set_process_profiles(uid_t uid, pid_t pid, size_t num_profiles,
- const char* profiles[]) {
- std::vector<std::string> profiles_;
- profiles_.reserve(num_profiles);
- for (size_t i = 0; i < num_profiles; i++) {
- profiles_.emplace_back(profiles[i]);
- }
- return SetProcessProfiles(uid, pid, profiles_);
-}
-
static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
return StringPrintf("%s/uid_%d", cgroup, uid);
}
@@ -200,7 +149,7 @@ static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid, unsigned i
return ret;
}
-static bool RemoveUidProcessGroups(const std::string& uid_path, bool empty_only) {
+static bool RemoveUidProcessGroups(const std::string& uid_path) {
std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path.c_str()), closedir);
bool empty = true;
if (uid != NULL) {
@@ -215,21 +164,6 @@ static bool RemoveUidProcessGroups(const std::string& uid_path, bool empty_only)
}
auto path = StringPrintf("%s/%s", uid_path.c_str(), dir->d_name);
- if (empty_only) {
- struct stat st;
- auto procs_file = StringPrintf("%s/%s", path.c_str(),
- PROCESSGROUP_CGROUP_PROCS_FILE);
- if (stat(procs_file.c_str(), &st) == -1) {
- PLOG(ERROR) << "Failed to get stats for " << procs_file;
- continue;
- }
- if (st.st_size > 0) {
- // skip non-empty groups
- LOG(VERBOSE) << "Skipping non-empty group " << path;
- empty = false;
- continue;
- }
- }
LOG(VERBOSE) << "Removing " << path;
if (rmdir(path.c_str()) == -1) {
if (errno != EBUSY) {
@@ -242,21 +176,23 @@ static bool RemoveUidProcessGroups(const std::string& uid_path, bool empty_only)
return empty;
}
-void removeAllProcessGroupsInternal(bool empty_only) {
+void removeAllProcessGroups() {
+ LOG(VERBOSE) << "removeAllProcessGroups()";
+
std::vector<std::string> cgroups;
- std::string path, memcg_apps_path;
+ std::string path;
if (CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &path)) {
cgroups.push_back(path);
}
- if (CgroupGetMemcgAppsPath(&memcg_apps_path) && memcg_apps_path != path) {
- cgroups.push_back(memcg_apps_path);
+ if (CgroupGetControllerPath("memory", &path)) {
+ cgroups.push_back(path + "/apps");
}
for (std::string cgroup_root_path : cgroups) {
std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path.c_str()), closedir);
if (root == NULL) {
- PLOG(ERROR) << __func__ << " failed to open " << cgroup_root_path;
+ PLOG(ERROR) << "Failed to open " << cgroup_root_path;
} else {
dirent* dir;
while ((dir = readdir(root.get())) != nullptr) {
@@ -269,7 +205,7 @@ void removeAllProcessGroupsInternal(bool empty_only) {
}
auto path = StringPrintf("%s/%s", cgroup_root_path.c_str(), dir->d_name);
- if (!RemoveUidProcessGroups(path, empty_only)) {
+ if (!RemoveUidProcessGroups(path)) {
LOG(VERBOSE) << "Skip removing " << path;
continue;
}
@@ -282,16 +218,6 @@ void removeAllProcessGroupsInternal(bool empty_only) {
}
}
-void removeAllProcessGroups() {
- LOG(VERBOSE) << "removeAllProcessGroups()";
- removeAllProcessGroupsInternal(false);
-}
-
-void removeAllEmptyProcessGroups() {
- LOG(VERBOSE) << "removeAllEmptyProcessGroups()";
- removeAllProcessGroupsInternal(true);
-}
-
/**
* Process groups are primarily created by the Zygote, meaning that uid/pid groups are created by
* the user root. Ownership for the newly created cgroup and all of its files must thus be
@@ -352,8 +278,7 @@ static int DoKillProcessGroupOnce(const char* cgroup, uid_t uid, int initialPid,
// This happens when process is already dead
return 0;
}
- PLOG(WARNING) << __func__ << " failed to open process cgroup uid " << uid << " pid "
- << initialPid;
+ PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
return -1;
}
@@ -466,11 +391,10 @@ static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries,
int err = RemoveProcessGroup(cgroup, uid, initialPid, retries);
if (isMemoryCgroupSupported() && UsePerAppMemcg()) {
- std::string memcg_apps_path;
- if (CgroupGetMemcgAppsPath(&memcg_apps_path) &&
- RemoveProcessGroup(memcg_apps_path.c_str(), uid, initialPid, retries) < 0) {
- return -1;
- }
+ std::string memory_path;
+ CgroupGetControllerPath("memory", &memory_path);
+ memory_path += "/apps";
+ if (RemoveProcessGroup(memory_path.c_str(), uid, initialPid, retries)) return -1;
}
return err;
@@ -492,17 +416,15 @@ int killProcessGroupOnce(uid_t uid, int initialPid, int signal, int* max_process
return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/, max_processes);
}
-static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgroup,
- bool activate_controllers) {
+static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgroup) {
auto uid_path = ConvertUidToPath(cgroup.c_str(), uid);
struct stat cgroup_stat;
mode_t cgroup_mode = 0750;
- uid_t cgroup_uid = AID_SYSTEM;
- gid_t cgroup_gid = AID_SYSTEM;
- int ret = 0;
+ gid_t cgroup_uid = AID_SYSTEM;
+ uid_t cgroup_gid = AID_SYSTEM;
- if (stat(cgroup.c_str(), &cgroup_stat) < 0) {
+ if (stat(cgroup.c_str(), &cgroup_stat) == 1) {
PLOG(ERROR) << "Failed to get stats for " << cgroup;
} else {
cgroup_mode = cgroup_stat.st_mode;
@@ -514,13 +436,6 @@ static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgr
PLOG(ERROR) << "Failed to make and chown " << uid_path;
return -errno;
}
- if (activate_controllers) {
- ret = CgroupMap::GetInstance().ActivateControllers(uid_path);
- if (ret) {
- LOG(ERROR) << "Failed to activate controllers in " << uid_path;
- return ret;
- }
- }
auto uid_pid_path = ConvertUidPidToPath(cgroup.c_str(), uid, initialPid);
@@ -531,6 +446,7 @@ static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgr
auto uid_pid_procs_file = uid_pid_path + PROCESSGROUP_CGROUP_PROCS_FILE;
+ int ret = 0;
if (!WriteStringToFile(std::to_string(initialPid), uid_pid_procs_file)) {
ret = -errno;
PLOG(ERROR) << "Failed to write '" << initialPid << "' to " << uid_pid_procs_file;
@@ -547,19 +463,17 @@ int createProcessGroup(uid_t uid, int initialPid, bool memControl) {
return -EINVAL;
}
- if (std::string memcg_apps_path;
- isMemoryCgroupSupported() && UsePerAppMemcg() && CgroupGetMemcgAppsPath(&memcg_apps_path)) {
- // Note by bvanassche: passing 'false' as fourth argument below implies that the v1
- // hierarchy is used. It is not clear to me whether the above conditions guarantee that the
- // v1 hierarchy is used.
- int ret = createProcessGroupInternal(uid, initialPid, memcg_apps_path, false);
+ if (isMemoryCgroupSupported() && UsePerAppMemcg()) {
+ CgroupGetControllerPath("memory", &cgroup);
+ cgroup += "/apps";
+ int ret = createProcessGroupInternal(uid, initialPid, cgroup);
if (ret != 0) {
return ret;
}
}
CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cgroup);
- return createProcessGroupInternal(uid, initialPid, cgroup, true);
+ return createProcessGroupInternal(uid, initialPid, cgroup);
}
static bool SetProcessGroupValue(int tid, const std::string& attr_name, int64_t value) {
diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json
index 3e4393df2..063422091 100644
--- a/libprocessgroup/profiles/cgroups.json
+++ b/libprocessgroup/profiles/cgroups.json
@@ -3,7 +3,7 @@
{
"Controller": "blkio",
"Path": "/dev/blkio",
- "Mode": "0775",
+ "Mode": "0755",
"UID": "system",
"GID": "system"
},
@@ -32,13 +32,16 @@
],
"Cgroups2": {
"Path": "/sys/fs/cgroup",
- "Mode": "0775",
+ "Mode": "0755",
"UID": "system",
"GID": "system",
"Controllers": [
{
"Controller": "freezer",
- "Path": "."
+ "Path": ".",
+ "Mode": "0755",
+ "UID": "system",
+ "GID": "system"
}
]
}
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 4092c1a37..449a50546 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -16,21 +16,14 @@
"File": "top-app/cpus"
},
{
- "Name": "MemStats",
- "Controller": "memory",
- "File": "memory.stat"
- },
- {
"Name": "MemLimit",
"Controller": "memory",
- "File": "memory.limit_in_bytes",
- "FileV2": "memory.max"
+ "File": "memory.limit_in_bytes"
},
{
"Name": "MemSoftLimit",
"Controller": "memory",
- "File": "memory.soft_limit_in_bytes",
- "FileV2": "memory.low"
+ "File": "memory.soft_limit_in_bytes"
},
{
"Name": "MemSwappiness",
@@ -38,26 +31,6 @@
"File": "memory.swappiness"
},
{
- "Name": "MemUsage",
- "Controller": "memory",
- "File": "memory.usage_in_bytes"
- },
- {
- "Name": "MemAndSwapUsage",
- "Controller": "memory",
- "File": "memory.memsw.usage_in_bytes"
- },
- {
- "Name": "MemPressureLevel",
- "Controller": "memory",
- "File": "memory.pressure_level"
- },
- {
- "Name": "MemCgroupEventControl",
- "Controller": "memory",
- "File": "cgroup.event_control"
- },
- {
"Name": "UClampMin",
"Controller": "cpu",
"File": "cpu.uclamp.min"
@@ -210,19 +183,7 @@
}
]
},
- {
- "Name": "Dex2oatPerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "cpu",
- "Path": "dex2oat"
- }
- }
- ]
- },
+
{
"Name": "CpuPolicySpread",
"Actions": [
@@ -435,6 +396,7 @@
}
]
},
+
{
"Name": "LowIoPriority",
"Actions": [
@@ -647,10 +609,6 @@
"Profiles": [ "ServicePerformance", "LowIoPriority", "TimerSlackNormal" ]
},
{
- "Name": "VMCompilationPerformance",
- "Profiles": [ "HighPerformance", "ProcessCapacityHigh", "LowIoPriority", "TimerSlackNormal" ]
- },
- {
"Name": "SCHED_SP_RT_APP",
"Profiles": [ "RealtimePerformance", "MaxIoPriority", "TimerSlackNormal" ]
},
@@ -680,11 +638,7 @@
},
{
"Name": "Dex2OatBootComplete",
- "Profiles": [ "Dex2oatPerformance", "LowIoPriority", "TimerSlackHigh" ]
- },
- {
- "Name": "OtaProfiles",
- "Profiles": [ "ServiceCapacityLow", "LowIoPriority", "HighEnergySaving" ]
+ "Profiles": [ "SCHED_SP_BACKGROUND" ]
}
]
}
diff --git a/libprocessgroup/profiles/task_profiles.proto b/libprocessgroup/profiles/task_profiles.proto
index ebcd9b56e..1de4395e9 100644
--- a/libprocessgroup/profiles/task_profiles.proto
+++ b/libprocessgroup/profiles/task_profiles.proto
@@ -25,13 +25,11 @@ message TaskProfiles {
repeated AggregateProfiles aggregateprofiles = 3 [json_name = "AggregateProfiles"];
}
-// Next: 6
+// Next: 4
message Attribute {
string name = 1 [json_name = "Name"];
string controller = 2 [json_name = "Controller"];
string file = 3 [json_name = "File"];
- string filev2 = 4 [json_name = "FileV2"];
- string optional = 5 [json_name = "Optional"];
}
// Next: 3
diff --git a/libprocessgroup/profiles/task_profiles_28.json b/libprocessgroup/profiles/task_profiles_28.json
index e7be5487d..9f8378590 100644
--- a/libprocessgroup/profiles/task_profiles_28.json
+++ b/libprocessgroup/profiles/task_profiles_28.json
@@ -40,19 +40,6 @@
]
},
{
- "Name": "ServicePerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "schedtune",
- "Path": "background"
- }
- }
- ]
- },
- {
"Name": "HighPerformance",
"Actions": [
{
@@ -117,19 +104,7 @@
}
]
},
- {
- "Name": "Dex2oatPerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "schedtune",
- "Path": "background"
- }
- }
- ]
- },
+
{
"Name": "CpuPolicySpread",
"Actions": [
diff --git a/libprocessgroup/profiles/task_profiles_29.json b/libprocessgroup/profiles/task_profiles_29.json
index 6174c8d0f..9f8378590 100644
--- a/libprocessgroup/profiles/task_profiles_29.json
+++ b/libprocessgroup/profiles/task_profiles_29.json
@@ -53,19 +53,6 @@
]
},
{
- "Name": "ServicePerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "schedtune",
- "Path": "background"
- }
- }
- ]
- },
- {
"Name": "MaxPerformance",
"Actions": [
{
@@ -117,19 +104,7 @@
}
]
},
- {
- "Name": "Dex2oatPerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "schedtune",
- "Path": "background"
- }
- }
- ]
- },
+
{
"Name": "CpuPolicySpread",
"Actions": [
diff --git a/libprocessgroup/profiles/task_profiles_30.json b/libprocessgroup/profiles/task_profiles_30.json
index e7be5487d..9f8378590 100644
--- a/libprocessgroup/profiles/task_profiles_30.json
+++ b/libprocessgroup/profiles/task_profiles_30.json
@@ -40,19 +40,6 @@
]
},
{
- "Name": "ServicePerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "schedtune",
- "Path": "background"
- }
- }
- ]
- },
- {
"Name": "HighPerformance",
"Actions": [
{
@@ -117,19 +104,7 @@
}
]
},
- {
- "Name": "Dex2oatPerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "schedtune",
- "Path": "background"
- }
- }
- ]
- },
+
{
"Name": "CpuPolicySpread",
"Actions": [
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 169b1d3e0..1a4196a4d 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -165,7 +165,27 @@ static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) {
return 0;
}
-static int get_sched_policy_from_group(const std::string& group, SchedPolicy* policy) {
+int get_sched_policy(int tid, SchedPolicy* policy) {
+ if (tid == 0) {
+ tid = GetThreadId();
+ }
+
+ std::string group;
+ if (schedboost_enabled()) {
+ if ((getCGroupSubsys(tid, "schedtune", group) < 0) &&
+ (getCGroupSubsys(tid, "cpu", group) < 0)) {
+ LOG(ERROR) << "Failed to find cpu cgroup for tid " << tid;
+ return -1;
+ }
+ }
+ if (group.empty() && cpusets_enabled()) {
+ if (getCGroupSubsys(tid, "cpuset", group) < 0) {
+ LOG(ERROR) << "Failed to find cpuset cgroup for tid " << tid;
+ return -1;
+ }
+ }
+
+ // TODO: replace hardcoded directories
if (group.empty()) {
*policy = SP_FOREGROUND;
} else if (group == "foreground") {
@@ -185,35 +205,6 @@ static int get_sched_policy_from_group(const std::string& group, SchedPolicy* po
return 0;
}
-int get_sched_policy(int tid, SchedPolicy* policy) {
- if (tid == 0) {
- tid = GetThreadId();
- }
-
- std::string group;
- if (schedboost_enabled()) {
- if ((getCGroupSubsys(tid, "schedtune", group) < 0) &&
- (getCGroupSubsys(tid, "cpu", group) < 0)) {
- LOG(ERROR) << "Failed to find cpu cgroup for tid " << tid;
- return -1;
- }
- // Wipe invalid group to fallback to cpuset
- if (!group.empty()) {
- if (get_sched_policy_from_group(group, policy) < 0) {
- group.clear();
- } else {
- return 0;
- }
- }
- }
-
- if (cpusets_enabled() && getCGroupSubsys(tid, "cpuset", group) < 0) {
- LOG(ERROR) << "Failed to find cpuset cgroup for tid " << tid;
- return -1;
- }
- return get_sched_policy_from_group(group, policy);
-}
-
#else
/* Stubs for non-Android targets. */
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index 3831ef20a..3121d244b 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -147,17 +147,12 @@ static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid,
static void MergeCgroupToDescriptors(std::map<std::string, CgroupDescriptor>* descriptors,
const Json::Value& cgroup, const std::string& name,
const std::string& root_path, int cgroups_version) {
- const std::string cgroup_path = cgroup["Path"].asString();
std::string path;
if (!root_path.empty()) {
- path = root_path;
- if (cgroup_path != ".") {
- path += "/";
- path += cgroup_path;
- }
+ path = root_path + "/" + cgroup["Path"].asString();
} else {
- path = cgroup_path;
+ path = cgroup["Path"].asString();
}
uint32_t controller_flags = 0;
@@ -268,18 +263,8 @@ static bool SetupCgroup(const CgroupDescriptor& descriptor) {
return false;
}
- // The memory_recursiveprot mount option has been introduced by kernel commit
- // 8a931f801340 ("mm: memcontrol: recursive memory.low protection"; v5.7). Try first to
- // mount with that option enabled. If mounting fails because the kernel is too old,
- // retry without that mount option.
- if (mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
- "memory_recursiveprot") < 0) {
- LOG(INFO) << "Mounting memcg with memory_recursiveprot failed. Retrying without.";
- if (mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
- nullptr) < 0) {
- PLOG(ERROR) << "Failed to mount cgroup v2";
- }
- }
+ result = mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
+ nullptr);
// selinux permissions change after mounting, so it's ok to change mode and owner now
if (!ChangeDirModeAndOwner(controller->path(), descriptor.mode(), descriptor.uid(),
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index e1c593407..cf74e6557 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -51,69 +51,6 @@ static constexpr const char* TASK_PROFILE_DB_VENDOR_FILE = "/vendor/etc/task_pro
static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE =
"/etc/task_profiles/task_profiles_%u.json";
-class FdCacheHelper {
- public:
- enum FdState {
- FDS_INACCESSIBLE = -1,
- FDS_APP_DEPENDENT = -2,
- FDS_NOT_CACHED = -3,
- };
-
- static void Cache(const std::string& path, android::base::unique_fd& fd);
- static void Drop(android::base::unique_fd& fd);
- static void Init(const std::string& path, android::base::unique_fd& fd);
- static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; }
-
- private:
- static bool IsAppDependentPath(const std::string& path);
-};
-
-void FdCacheHelper::Init(const std::string& path, android::base::unique_fd& fd) {
- // file descriptors for app-dependent paths can't be cached
- if (IsAppDependentPath(path)) {
- // file descriptor is not cached
- fd.reset(FDS_APP_DEPENDENT);
- return;
- }
- // file descriptor can be cached later on request
- fd.reset(FDS_NOT_CACHED);
-}
-
-void FdCacheHelper::Cache(const std::string& path, android::base::unique_fd& fd) {
- if (fd != FDS_NOT_CACHED) {
- return;
- }
-
- if (access(path.c_str(), W_OK) != 0) {
- // file is not accessible
- fd.reset(FDS_INACCESSIBLE);
- return;
- }
-
- unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
- if (tmp_fd < 0) {
- PLOG(ERROR) << "Failed to cache fd '" << path << "'";
- fd.reset(FDS_INACCESSIBLE);
- return;
- }
-
- fd = std::move(tmp_fd);
-}
-
-void FdCacheHelper::Drop(android::base::unique_fd& fd) {
- if (fd == FDS_NOT_CACHED) {
- return;
- }
-
- fd.reset(FDS_NOT_CACHED);
-}
-
-bool FdCacheHelper::IsAppDependentPath(const std::string& path) {
- return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
-}
-
-IProfileAttribute::~IProfileAttribute() = default;
-
void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) {
controller_ = controller;
file_name_ = file_name;
@@ -129,12 +66,11 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const {
return true;
}
- const std::string& file_name =
- controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_;
if (subgroup.empty()) {
- *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str());
+ *path = StringPrintf("%s/%s", controller()->path(), file_name_.c_str());
} else {
- *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str());
+ *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(),
+ file_name_.c_str());
}
return true;
}
@@ -186,12 +122,6 @@ bool SetTimerSlackAction::ExecuteForTask(int tid) const {
return true;
}
-#else
-
-bool SetTimerSlackAction::ExecuteForTask(int) const {
- return true;
-};
-
#endif
bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const {
@@ -207,17 +137,6 @@ bool SetAttributeAction::ExecuteForTask(int tid) const {
}
if (!WriteStringToFile(value_, path)) {
- if (access(path.c_str(), F_OK) < 0) {
- if (optional_) {
- return true;
- } else {
- LOG(ERROR) << "No such cgroup attribute: " << path;
- return false;
- }
- }
- // The PLOG() statement below uses the error code stored in `errno` by
- // WriteStringToFile() because access() only overwrites `errno` if it fails
- // and because this code is only reached if the access() function returns 0.
PLOG(ERROR) << "Failed to write '" << value_ << "' to " << path;
return false;
}
@@ -225,89 +144,82 @@ bool SetAttributeAction::ExecuteForTask(int tid) const {
return true;
}
+bool SetCgroupAction::IsAppDependentPath(const std::string& path) {
+ return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
+}
+
SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
- FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
- // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
- FdCacheHelper::Init(controller_.GetProcsFilePath(path_, 0, 0), fd_[ProfileAction::RCT_PROCESS]);
+ // file descriptors for app-dependent paths can't be cached
+ if (IsAppDependentPath(path_)) {
+ // file descriptor is not cached
+ fd_.reset(FDS_APP_DEPENDENT);
+ return;
+ }
+
+ // file descriptor can be cached later on request
+ fd_.reset(FDS_NOT_CACHED);
}
-bool SetCgroupAction::AddTidToCgroup(int tid, int fd, const char* controller_name) {
- if (tid <= 0) {
- return true;
+void SetCgroupAction::EnableResourceCaching() {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (fd_ != FDS_NOT_CACHED) {
+ return;
}
- std::string value = std::to_string(tid);
+ std::string tasks_path = controller_.GetTasksFilePath(path_);
- if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) == value.length()) {
- return true;
+ if (access(tasks_path.c_str(), W_OK) != 0) {
+ // file is not accessible
+ fd_.reset(FDS_INACCESSIBLE);
+ return;
}
- // If the thread is in the process of exiting, don't flag an error
- if (errno == ESRCH) {
- return true;
+ unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'";
+ fd_.reset(FDS_INACCESSIBLE);
+ return;
}
- // ENOSPC is returned when cpuset cgroup that we are joining has no online cpus
- if (errno == ENOSPC && !strcmp(controller_name, "cpuset")) {
- // This is an abnormal case happening only in testing, so report it only once
- static bool empty_cpuset_reported = false;
-
- if (empty_cpuset_reported) {
- return true;
- }
+ fd_ = std::move(fd);
+}
- LOG(ERROR) << "Failed to add task '" << value
- << "' into cpuset because all cpus in that cpuset are offline";
- empty_cpuset_reported = true;
- } else {
- PLOG(ERROR) << "AddTidToCgroup failed to write '" << value << "'; fd=" << fd;
+void SetCgroupAction::DropResourceCaching() {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (fd_ == FDS_NOT_CACHED) {
+ return;
}
- return false;
+ fd_.reset(FDS_NOT_CACHED);
}
-ProfileAction::CacheUseResult SetCgroupAction::UseCachedFd(ResourceCacheType cache_type,
- int id) const {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (FdCacheHelper::IsCached(fd_[cache_type])) {
- // fd is cached, reuse it
- if (!AddTidToCgroup(id, fd_[cache_type], controller()->name())) {
- LOG(ERROR) << "Failed to add task into cgroup";
- return ProfileAction::FAIL;
- }
- return ProfileAction::SUCCESS;
+bool SetCgroupAction::AddTidToCgroup(int tid, int fd) {
+ if (tid <= 0) {
+ return true;
}
- if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) {
- // no permissions to access the file, ignore
- return ProfileAction::SUCCESS;
- }
+ std::string value = std::to_string(tid);
- if (cache_type == ResourceCacheType::RCT_TASK &&
- fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
- // application-dependent path can't be used with tid
- PLOG(ERROR) << "Application profile can't be applied to a thread";
- return ProfileAction::FAIL;
+ if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) < 0) {
+ // If the thread is in the process of exiting, don't flag an error
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "AddTidToCgroup failed to write '" << value << "'; fd=" << fd;
+ return false;
+ }
}
- return ProfileAction::UNUSED;
+ return true;
}
bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
- CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, pid);
- if (result != ProfileAction::UNUSED) {
- return result == ProfileAction::SUCCESS;
- }
-
- // fd was not cached or cached fd can't be used
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
PLOG(WARNING) << "Failed to open " << procs_path;
return false;
}
- if (!AddTidToCgroup(pid, tmp_fd, controller()->name())) {
+ if (!AddTidToCgroup(pid, tmp_fd)) {
LOG(ERROR) << "Failed to add task into cgroup";
return false;
}
@@ -316,19 +228,35 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
}
bool SetCgroupAction::ExecuteForTask(int tid) const {
- CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, tid);
- if (result != ProfileAction::UNUSED) {
- return result == ProfileAction::SUCCESS;
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (IsFdValid()) {
+ // fd is cached, reuse it
+ if (!AddTidToCgroup(tid, fd_)) {
+ LOG(ERROR) << "Failed to add task into cgroup";
+ return false;
+ }
+ return true;
+ }
+
+ if (fd_ == FDS_INACCESSIBLE) {
+ // no permissions to access the file, ignore
+ return true;
}
- // fd was not cached or cached fd can't be used
+ if (fd_ == FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
+ return false;
+ }
+
+ // fd was not cached because cached fd can't be used
std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
- PLOG(WARNING) << "Failed to open " << tasks_path;
+ PLOG(WARNING) << "Failed to open " << tasks_path << ": " << strerror(errno);
return false;
}
- if (!AddTidToCgroup(tid, tmp_fd, controller()->name())) {
+ if (!AddTidToCgroup(tid, tmp_fd)) {
LOG(ERROR) << "Failed to add task into cgroup";
return false;
}
@@ -336,171 +264,44 @@ bool SetCgroupAction::ExecuteForTask(int tid) const {
return true;
}
-void SetCgroupAction::EnableResourceCaching(ResourceCacheType cache_type) {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- // Return early to prevent unnecessary calls to controller_.Get{Tasks|Procs}FilePath() which
- // include regex evaluations
- if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) {
- return;
- }
- switch (cache_type) {
- case (ProfileAction::RCT_TASK):
- FdCacheHelper::Cache(controller_.GetTasksFilePath(path_), fd_[cache_type]);
- break;
- case (ProfileAction::RCT_PROCESS):
- // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
- FdCacheHelper::Cache(controller_.GetProcsFilePath(path_, 0, 0), fd_[cache_type]);
- break;
- default:
- LOG(ERROR) << "Invalid cache type is specified!";
- break;
- }
-}
-
-void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- FdCacheHelper::Drop(fd_[cache_type]);
-}
-
-WriteFileAction::WriteFileAction(const std::string& task_path, const std::string& proc_path,
- const std::string& value, bool logfailures)
- : task_path_(task_path), proc_path_(proc_path), value_(value), logfailures_(logfailures) {
- FdCacheHelper::Init(task_path_, fd_[ProfileAction::RCT_TASK]);
- if (!proc_path_.empty()) FdCacheHelper::Init(proc_path_, fd_[ProfileAction::RCT_PROCESS]);
-}
-
-bool WriteFileAction::WriteValueToFile(const std::string& value_, ResourceCacheType cache_type,
- int uid, int pid, bool logfailures) const {
- std::string value(value_);
+bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+ std::string filepath(filepath_), value(value_);
+ filepath = StringReplace(filepath, "<uid>", std::to_string(uid), true);
+ filepath = StringReplace(filepath, "<pid>", std::to_string(pid), true);
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(pid), true);
- CacheUseResult result = UseCachedFd(cache_type, value);
-
- if (result != ProfileAction::UNUSED) {
- return result == ProfileAction::SUCCESS;
- }
-
- std::string path;
- if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) {
- path = task_path_;
- } else {
- path = proc_path_;
- }
-
- // Use WriteStringToFd instead of WriteStringToFile because the latter will open file with
- // O_TRUNC which causes kernfs_mutex contention
- unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
-
- if (tmp_fd < 0) {
- if (logfailures) PLOG(WARNING) << "Failed to open " << path;
- return false;
- }
-
- if (!WriteStringToFd(value, tmp_fd)) {
- if (logfailures) PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
+ if (!WriteStringToFile(value, filepath)) {
+ if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << filepath;
return false;
}
return true;
}
-ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cache_type,
- const std::string& value) const {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (FdCacheHelper::IsCached(fd_[cache_type])) {
- // fd is cached, reuse it
- bool ret = WriteStringToFd(value, fd_[cache_type]);
-
- if (!ret && logfailures_) {
- if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) {
- PLOG(ERROR) << "Failed to write '" << value << "' to " << task_path_;
- } else {
- PLOG(ERROR) << "Failed to write '" << value << "' to " << proc_path_;
- }
- }
- return ret ? ProfileAction::SUCCESS : ProfileAction::FAIL;
- }
-
- if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) {
- // no permissions to access the file, ignore
- return ProfileAction::SUCCESS;
- }
-
- if (cache_type == ResourceCacheType::RCT_TASK &&
- fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
- // application-dependent path can't be used with tid
- PLOG(ERROR) << "Application profile can't be applied to a thread";
- return ProfileAction::FAIL;
- }
- return ProfileAction::UNUSED;
-}
-
-bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
- if (!proc_path_.empty()) {
- return WriteValueToFile(value_, ProfileAction::RCT_PROCESS, uid, pid, logfailures_);
- }
+bool WriteFileAction::ExecuteForTask(int tid) const {
+ std::string filepath(filepath_), value(value_);
+ int uid = getuid();
- DIR* d;
- struct dirent* de;
- char proc_path[255];
- int t_pid;
+ filepath = StringReplace(filepath, "<uid>", std::to_string(uid), true);
+ filepath = StringReplace(filepath, "<pid>", std::to_string(tid), true);
+ value = StringReplace(value, "<uid>", std::to_string(uid), true);
+ value = StringReplace(value, "<pid>", std::to_string(tid), true);
- sprintf(proc_path, "/proc/%d/task", pid);
- if (!(d = opendir(proc_path))) {
+ if (!WriteStringToFile(value, filepath)) {
+ if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << filepath;
return false;
}
- while ((de = readdir(d))) {
- if (de->d_name[0] == '.') {
- continue;
- }
-
- t_pid = atoi(de->d_name);
-
- if (!t_pid) {
- continue;
- }
-
- WriteValueToFile(value_, ProfileAction::RCT_TASK, uid, t_pid, logfailures_);
- }
-
- closedir(d);
-
return true;
}
-bool WriteFileAction::ExecuteForTask(int tid) const {
- return WriteValueToFile(value_, ProfileAction::RCT_TASK, getuid(), tid, logfailures_);
-}
-
-void WriteFileAction::EnableResourceCaching(ResourceCacheType cache_type) {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) {
- return;
- }
- switch (cache_type) {
- case (ProfileAction::RCT_TASK):
- FdCacheHelper::Cache(task_path_, fd_[cache_type]);
- break;
- case (ProfileAction::RCT_PROCESS):
- if (!proc_path_.empty()) FdCacheHelper::Cache(proc_path_, fd_[cache_type]);
- break;
- default:
- LOG(ERROR) << "Invalid cache type is specified!";
- break;
- }
-}
-
-void WriteFileAction::DropResourceCaching(ResourceCacheType cache_type) {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- FdCacheHelper::Drop(fd_[cache_type]);
-}
-
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
- profile->ExecuteForProcess(uid, pid);
+ if (!profile->ExecuteForProcess(uid, pid)) {
+ PLOG(WARNING) << "ExecuteForProcess failed for aggregate profile";
+ }
}
return true;
}
@@ -512,15 +313,15 @@ bool ApplyProfileAction::ExecuteForTask(int tid) const {
return true;
}
-void ApplyProfileAction::EnableResourceCaching(ResourceCacheType cache_type) {
+void ApplyProfileAction::EnableResourceCaching() {
for (const auto& profile : profiles_) {
- profile->EnableResourceCaching(cache_type);
+ profile->EnableResourceCaching();
}
}
-void ApplyProfileAction::DropResourceCaching(ResourceCacheType cache_type) {
+void ApplyProfileAction::DropResourceCaching() {
for (const auto& profile : profiles_) {
- profile->DropResourceCaching(cache_type);
+ profile->DropResourceCaching();
}
}
@@ -532,7 +333,6 @@ void TaskProfile::MoveTo(TaskProfile* profile) {
bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& element : elements_) {
if (!element->ExecuteForProcess(uid, pid)) {
- LOG(VERBOSE) << "Applying profile action " << element->Name() << " failed";
return false;
}
}
@@ -545,40 +345,39 @@ bool TaskProfile::ExecuteForTask(int tid) const {
}
for (const auto& element : elements_) {
if (!element->ExecuteForTask(tid)) {
- LOG(VERBOSE) << "Applying profile action " << element->Name() << " failed";
return false;
}
}
return true;
}
-void TaskProfile::EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) {
+void TaskProfile::EnableResourceCaching() {
if (res_cached_) {
return;
}
for (auto& element : elements_) {
- element->EnableResourceCaching(cache_type);
+ element->EnableResourceCaching();
}
res_cached_ = true;
}
-void TaskProfile::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) {
+void TaskProfile::DropResourceCaching() {
if (!res_cached_) {
return;
}
for (auto& element : elements_) {
- element->DropResourceCaching(cache_type);
+ element->DropResourceCaching();
}
res_cached_ = false;
}
-void TaskProfiles::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const {
+void TaskProfiles::DropResourceCaching() const {
for (auto& iter : profiles_) {
- iter.second->DropResourceCaching(cache_type);
+ iter.second->DropResourceCaching();
}
}
@@ -602,7 +401,8 @@ TaskProfiles::TaskProfiles() {
android::base::StringPrintf(TEMPLATE_TASK_PROFILE_API_FILE, api_level);
if (!access(api_profiles_path.c_str(), F_OK) || errno != ENOENT) {
if (!Load(CgroupMap::GetInstance(), api_profiles_path)) {
- LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid() << "] failed";
+ LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid()
+ << "] failed";
}
}
}
@@ -637,19 +437,12 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
std::string name = attr[i]["Name"].asString();
std::string controller_name = attr[i]["Controller"].asString();
std::string file_attr = attr[i]["File"].asString();
- std::string file_v2_attr = attr[i]["FileV2"].asString();
-
- if (!file_v2_attr.empty() && file_attr.empty()) {
- LOG(ERROR) << "Attribute " << name << " has FileV2 but no File property";
- return false;
- }
auto controller = cg_map.FindController(controller_name);
if (controller.HasValue()) {
auto iter = attributes_.find(name);
if (iter == attributes_.end()) {
- attributes_[name] =
- std::make_unique<ProfileAttribute>(controller, file_attr, file_v2_attr);
+ attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_attr);
} else {
iter->second->Reset(controller, file_attr);
}
@@ -664,7 +457,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
std::string profile_name = profile_val["Name"].asString();
const Json::Value& actions = profile_val["Actions"];
- auto profile = std::make_shared<TaskProfile>(profile_name);
+ auto profile = std::make_shared<TaskProfile>();
for (Json::Value::ArrayIndex act_idx = 0; act_idx < actions.size(); ++act_idx) {
const Json::Value& action_val = actions[act_idx];
@@ -694,12 +487,11 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
} else if (action_name == "SetAttribute") {
std::string attr_name = params_val["Name"].asString();
std::string attr_value = params_val["Value"].asString();
- bool optional = strcmp(params_val["Optional"].asString().c_str(), "true") == 0;
auto iter = attributes_.find(attr_name);
if (iter != attributes_.end()) {
- profile->Add(std::make_unique<SetAttributeAction>(iter->second.get(),
- attr_value, optional));
+ profile->Add(
+ std::make_unique<SetAttributeAction>(iter->second.get(), attr_value));
} else {
LOG(WARNING) << "SetAttribute: unknown attribute: " << attr_name;
}
@@ -722,14 +514,12 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
}
} else if (action_name == "WriteFile") {
std::string attr_filepath = params_val["FilePath"].asString();
- std::string attr_procfilepath = params_val["ProcFilePath"].asString();
std::string attr_value = params_val["Value"].asString();
- // FilePath and Value are mandatory
if (!attr_filepath.empty() && !attr_value.empty()) {
std::string attr_logfailures = params_val["LogFailures"].asString();
bool logfailures = attr_logfailures.empty() || attr_logfailures == "true";
- profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_procfilepath,
- attr_value, logfailures));
+ profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value,
+ logfailures));
} else if (attr_filepath.empty()) {
LOG(WARNING) << "WriteFile: invalid parameter: "
<< "empty filepath";
@@ -777,7 +567,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
}
}
if (ret) {
- auto profile = std::make_shared<TaskProfile>(aggregateprofile_name);
+ auto profile = std::make_shared<TaskProfile>();
profile->Add(std::make_unique<ApplyProfileAction>(profiles));
profiles_[aggregateprofile_name] = profile;
}
@@ -795,7 +585,7 @@ TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
return nullptr;
}
-const IProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
+const ProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
auto iter = attributes_.find(name);
if (iter != attributes_.end()) {
@@ -805,43 +595,34 @@ const IProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) con
}
bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
- const std::vector<std::string>& profiles, bool use_fd_cache) {
- bool success = true;
+ const std::vector<std::string>& profiles) {
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
- if (use_fd_cache) {
- profile->EnableResourceCaching(ProfileAction::RCT_PROCESS);
- }
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
- success = false;
}
} else {
- PLOG(WARNING) << "Failed to find " << name << " process profile";
- success = false;
+ PLOG(WARNING) << "Failed to find " << name << "process profile";
}
}
- return success;
+ return true;
}
bool TaskProfiles::SetTaskProfiles(int tid, const std::vector<std::string>& profiles,
bool use_fd_cache) {
- bool success = true;
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
- profile->EnableResourceCaching(ProfileAction::RCT_TASK);
+ profile->EnableResourceCaching();
}
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "Failed to apply " << name << " task profile";
- success = false;
}
} else {
- PLOG(WARNING) << "Failed to find " << name << " task profile";
- success = false;
+ PLOG(WARNING) << "Failed to find " << name << "task profile";
}
}
- return success;
+ return true;
}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index df08f65c7..25a84b0c1 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -26,55 +26,33 @@
#include <android-base/unique_fd.h>
#include <cgroup_map.h>
-class IProfileAttribute {
+class ProfileAttribute {
public:
- virtual ~IProfileAttribute() = 0;
- virtual void Reset(const CgroupController& controller, const std::string& file_name) = 0;
- virtual const CgroupController* controller() const = 0;
- virtual const std::string& file_name() const = 0;
- virtual bool GetPathForTask(int tid, std::string* path) const = 0;
-};
-
-class ProfileAttribute : public IProfileAttribute {
- public:
- // Cgroup attributes may have different names in the v1 and v2 hierarchies. If `file_v2_name` is
- // not empty, `file_name` is the name for the v1 hierarchy and `file_v2_name` is the name for
- // the v2 hierarchy. If `file_v2_name` is empty, `file_name` is used for both hierarchies.
- ProfileAttribute(const CgroupController& controller, const std::string& file_name,
- const std::string& file_v2_name)
- : controller_(controller), file_name_(file_name), file_v2_name_(file_v2_name) {}
- ~ProfileAttribute() = default;
+ ProfileAttribute(const CgroupController& controller, const std::string& file_name)
+ : controller_(controller), file_name_(file_name) {}
- const CgroupController* controller() const override { return &controller_; }
- const std::string& file_name() const override { return file_name_; }
- void Reset(const CgroupController& controller, const std::string& file_name) override;
+ const CgroupController* controller() const { return &controller_; }
+ const std::string& file_name() const { return file_name_; }
+ void Reset(const CgroupController& controller, const std::string& file_name);
- bool GetPathForTask(int tid, std::string* path) const override;
+ bool GetPathForTask(int tid, std::string* path) const;
private:
CgroupController controller_;
std::string file_name_;
- std::string file_v2_name_;
};
// Abstract profile element
class ProfileAction {
public:
- enum ResourceCacheType { RCT_TASK = 0, RCT_PROCESS, RCT_COUNT };
-
virtual ~ProfileAction() {}
- virtual const char* Name() const = 0;
-
// Default implementations will fail
virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
virtual bool ExecuteForTask(int) const { return false; };
- virtual void EnableResourceCaching(ResourceCacheType) {}
- virtual void DropResourceCaching(ResourceCacheType) {}
-
- protected:
- enum CacheUseResult { SUCCESS, FAIL, UNUSED };
+ virtual void EnableResourceCaching() {}
+ virtual void DropResourceCaching() {}
};
// Profile actions
@@ -82,21 +60,22 @@ class SetClampsAction : public ProfileAction {
public:
SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {}
- const char* Name() const override { return "SetClamps"; }
- bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
- bool ExecuteForTask(int tid) const override;
+ virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ virtual bool ExecuteForTask(int tid) const;
protected:
int boost_;
int clamp_;
};
+// To avoid issues in sdk_mac build
+#if defined(__ANDROID__)
+
class SetTimerSlackAction : public ProfileAction {
public:
SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {}
- const char* Name() const override { return "SetTimerSlack"; }
- bool ExecuteForTask(int tid) const override;
+ virtual bool ExecuteForTask(int tid) const;
private:
unsigned long slack_;
@@ -104,20 +83,29 @@ class SetTimerSlackAction : public ProfileAction {
static bool IsTimerSlackSupported(int tid);
};
+#else
+
+class SetTimerSlackAction : public ProfileAction {
+ public:
+ SetTimerSlackAction(unsigned long) noexcept {}
+
+ virtual bool ExecuteForTask(int) const { return true; }
+};
+
+#endif
+
// Set attribute profile element
class SetAttributeAction : public ProfileAction {
public:
- SetAttributeAction(const IProfileAttribute* attribute, const std::string& value, bool optional)
- : attribute_(attribute), value_(value), optional_(optional) {}
+ SetAttributeAction(const ProfileAttribute* attribute, const std::string& value)
+ : attribute_(attribute), value_(value) {}
- const char* Name() const override { return "SetAttribute"; }
- bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
- bool ExecuteForTask(int tid) const override;
+ virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ virtual bool ExecuteForTask(int tid) const;
private:
- const IProfileAttribute* attribute_;
+ const ProfileAttribute* attribute_;
std::string value_;
- bool optional_;
};
// Set cgroup profile element
@@ -125,62 +113,60 @@ class SetCgroupAction : public ProfileAction {
public:
SetCgroupAction(const CgroupController& c, const std::string& p);
- const char* Name() const override { return "SetCgroup"; }
- bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
- bool ExecuteForTask(int tid) const override;
- void EnableResourceCaching(ResourceCacheType cache_type) override;
- void DropResourceCaching(ResourceCacheType cache_type) override;
+ virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ virtual bool ExecuteForTask(int tid) const;
+ virtual void EnableResourceCaching();
+ virtual void DropResourceCaching();
const CgroupController* controller() const { return &controller_; }
+ std::string path() const { return path_; }
private:
+ enum FdState {
+ FDS_INACCESSIBLE = -1,
+ FDS_APP_DEPENDENT = -2,
+ FDS_NOT_CACHED = -3,
+ };
+
CgroupController controller_;
std::string path_;
- android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
+ android::base::unique_fd fd_;
mutable std::mutex fd_mutex_;
- static bool AddTidToCgroup(int tid, int fd, const char* controller_name);
- CacheUseResult UseCachedFd(ResourceCacheType cache_type, int id) const;
+ static bool IsAppDependentPath(const std::string& path);
+ static bool AddTidToCgroup(int tid, int fd);
+
+ bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
};
// Write to file action
class WriteFileAction : public ProfileAction {
public:
- WriteFileAction(const std::string& task_path, const std::string& proc_path,
- const std::string& value, bool logfailures);
+ WriteFileAction(const std::string& filepath, const std::string& value,
+ bool logfailures) noexcept
+ : filepath_(filepath), value_(value), logfailures_(logfailures) {}
- const char* Name() const override { return "WriteFile"; }
- bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
- bool ExecuteForTask(int tid) const override;
- void EnableResourceCaching(ResourceCacheType cache_type) override;
- void DropResourceCaching(ResourceCacheType cache_type) override;
+ virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ virtual bool ExecuteForTask(int tid) const;
private:
- std::string task_path_, proc_path_, value_;
+ std::string filepath_, value_;
bool logfailures_;
- android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
- mutable std::mutex fd_mutex_;
-
- bool WriteValueToFile(const std::string& value, ResourceCacheType cache_type, int uid, int pid,
- bool logfailures) const;
- CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const;
};
class TaskProfile {
public:
- TaskProfile(const std::string& name) : name_(name), res_cached_(false) {}
+ TaskProfile() : res_cached_(false) {}
- const std::string& Name() const { return name_; }
void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
void MoveTo(TaskProfile* profile);
bool ExecuteForProcess(uid_t uid, pid_t pid) const;
bool ExecuteForTask(int tid) const;
- void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
- void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
+ void EnableResourceCaching();
+ void DropResourceCaching();
private:
- const std::string name_;
bool res_cached_;
std::vector<std::unique_ptr<ProfileAction>> elements_;
};
@@ -191,11 +177,10 @@ class ApplyProfileAction : public ProfileAction {
ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>>& profiles)
: profiles_(profiles) {}
- const char* Name() const override { return "ApplyProfileAction"; }
- bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
- bool ExecuteForTask(int tid) const override;
- void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) override;
- void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) override;
+ virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ virtual bool ExecuteForTask(int tid) const;
+ virtual void EnableResourceCaching();
+ virtual void DropResourceCaching();
private:
std::vector<std::shared_ptr<TaskProfile>> profiles_;
@@ -207,15 +192,14 @@ class TaskProfiles {
static TaskProfiles& GetInstance();
TaskProfile* GetProfile(const std::string& name) const;
- const IProfileAttribute* GetAttribute(const std::string& name) const;
- void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const;
- bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
- bool use_fd_cache);
+ const ProfileAttribute* GetAttribute(const std::string& name) const;
+ void DropResourceCaching() const;
+ bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
private:
std::map<std::string, std::shared_ptr<TaskProfile>> profiles_;
- std::map<std::string, std::unique_ptr<IProfileAttribute>> attributes_;
+ std::map<std::string, std::unique_ptr<ProfileAttribute>> attributes_;
TaskProfiles();
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
deleted file mode 100644
index 09ac44c6b..000000000
--- a/libprocessgroup/task_profiles_test.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "task_profiles.h"
-#include <android-base/logging.h>
-#include <gtest/gtest.h>
-#include <mntent.h>
-#include <processgroup/processgroup.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <fstream>
-
-using ::android::base::ERROR;
-using ::android::base::LogFunction;
-using ::android::base::LogId;
-using ::android::base::LogSeverity;
-using ::android::base::SetLogger;
-using ::android::base::VERBOSE;
-using ::testing::TestWithParam;
-using ::testing::Values;
-
-namespace {
-
-bool IsCgroupV2Mounted() {
- std::unique_ptr<FILE, int (*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
- if (!mnts) {
- LOG(ERROR) << "Failed to open /proc/mounts";
- return false;
- }
- struct mntent* mnt;
- while ((mnt = getmntent(mnts.get()))) {
- if (strcmp(mnt->mnt_fsname, "cgroup2") == 0) {
- return true;
- }
- }
- return false;
-}
-
-class ScopedLogCapturer {
- public:
- struct log_args {
- LogId log_buffer_id;
- LogSeverity severity;
- std::string tag;
- std::string file;
- unsigned int line;
- std::string message;
- };
-
- // Constructor. Installs a new logger and saves the currently active logger.
- ScopedLogCapturer() {
- saved_severity_ = SetMinimumLogSeverity(android::base::VERBOSE);
- saved_logger_ = SetLogger([this](LogId log_buffer_id, LogSeverity severity, const char* tag,
- const char* file, unsigned int line, const char* message) {
- if (saved_logger_) {
- saved_logger_(log_buffer_id, severity, tag, file, line, message);
- }
- log_.emplace_back(log_args{.log_buffer_id = log_buffer_id,
- .severity = severity,
- .tag = tag,
- .file = file,
- .line = line,
- .message = message});
- });
- }
- // Destructor. Restores the original logger and log level.
- ~ScopedLogCapturer() {
- SetLogger(std::move(saved_logger_));
- SetMinimumLogSeverity(saved_severity_);
- }
- ScopedLogCapturer(const ScopedLogCapturer&) = delete;
- ScopedLogCapturer& operator=(const ScopedLogCapturer&) = delete;
- // Returns the logged lines.
- const std::vector<log_args>& Log() const { return log_; }
-
- private:
- LogSeverity saved_severity_;
- LogFunction saved_logger_;
- std::vector<log_args> log_;
-};
-
-// cgroup attribute at the top level of the cgroup hierarchy.
-class ProfileAttributeMock : public IProfileAttribute {
- public:
- ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {}
- ~ProfileAttributeMock() override = default;
- void Reset(const CgroupController& controller, const std::string& file_name) override {
- CHECK(false);
- }
- const CgroupController* controller() const override {
- CHECK(false);
- return {};
- }
- const std::string& file_name() const override { return file_name_; }
- bool GetPathForTask(int tid, std::string* path) const override {
-#ifdef __ANDROID__
- CHECK(CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, path));
- CHECK_GT(path->length(), 0);
- if (path->rbegin()[0] != '/') {
- *path += "/";
- }
-#else
- // Not Android.
- *path = "/sys/fs/cgroup/";
-#endif
- *path += file_name_;
- return true;
- };
-
- private:
- const std::string file_name_;
-};
-
-struct TestParam {
- const char* attr_name;
- const char* attr_value;
- bool optional_attr;
- bool result;
- LogSeverity log_severity;
- const char* log_prefix;
- const char* log_suffix;
-};
-
-class SetAttributeFixture : public TestWithParam<TestParam> {
- public:
- ~SetAttributeFixture() = default;
-};
-
-TEST_P(SetAttributeFixture, SetAttribute) {
- // Treehugger runs host tests inside a container without cgroupv2 support.
- if (!IsCgroupV2Mounted()) {
- GTEST_SKIP();
- return;
- }
- const TestParam params = GetParam();
- ScopedLogCapturer captured_log;
- ProfileAttributeMock pa(params.attr_name);
- SetAttributeAction a(&pa, params.attr_value, params.optional_attr);
- EXPECT_EQ(a.ExecuteForProcess(getuid(), getpid()), params.result);
- auto log = captured_log.Log();
- if (params.log_prefix || params.log_suffix) {
- ASSERT_EQ(log.size(), 1);
- EXPECT_EQ(log[0].severity, params.log_severity);
- if (params.log_prefix) {
- EXPECT_EQ(log[0].message.find(params.log_prefix), 0);
- }
- if (params.log_suffix) {
- EXPECT_NE(log[0].message.find(params.log_suffix), std::string::npos);
- }
- } else {
- ASSERT_EQ(log.size(), 0);
- }
-}
-
-// Test the four combinations of optional_attr {false, true} and cgroup attribute { does not exist,
-// exists }.
-INSTANTIATE_TEST_SUITE_P(
- SetAttributeTestSuite, SetAttributeFixture,
- Values(
- // Test that attempting to write into a non-existing cgroup attribute fails and also
- // that an error message is logged.
- TestParam{.attr_name = "no-such-attribute",
- .attr_value = ".",
- .optional_attr = false,
- .result = false,
- .log_severity = ERROR,
- .log_prefix = "No such cgroup attribute"},
- // Test that attempting to write into an optional non-existing cgroup attribute
- // results in the return value 'true' and also that no messages are logged.
- TestParam{.attr_name = "no-such-attribute",
- .attr_value = ".",
- .optional_attr = true,
- .result = true},
- // Test that attempting to write an invalid value into an existing optional cgroup
- // attribute fails and also that it causes an error
- // message to be logged.
- TestParam{.attr_name = "cgroup.procs",
- .attr_value = "-1",
- .optional_attr = true,
- .result = false,
- .log_severity = ERROR,
- .log_prefix = "Failed to write",
- .log_suffix = geteuid() == 0 ? "Invalid argument" : "Permission denied"},
- // Test that attempting to write into an existing optional read-only cgroup
- // attribute fails and also that it causes an error message to be logged.
- TestParam{
- .attr_name = "cgroup.controllers",
- .attr_value = ".",
- .optional_attr = false,
- .result = false,
- .log_severity = ERROR,
- .log_prefix = "Failed to write",
- .log_suffix = geteuid() == 0 ? "Invalid argument" : "Permission denied"}));
-
-} // namespace
diff --git a/libprocessgroup/tools/Android.bp b/libprocessgroup/tools/Android.bp
deleted file mode 100644
index 91418e1e1..000000000
--- a/libprocessgroup/tools/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_binary {
- name: "settaskprofile",
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- srcs: ["settaskprofile.cpp"],
- shared_libs: [
- "libprocessgroup",
- ],
-}
diff --git a/libprocessgroup/tools/settaskprofile.cpp b/libprocessgroup/tools/settaskprofile.cpp
deleted file mode 100644
index f83944a26..000000000
--- a/libprocessgroup/tools/settaskprofile.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-
-#include <iostream>
-
-#include <processgroup/processgroup.h>
-
-[[noreturn]] static void usage(int exit_status) {
- std::cerr << "Usage: " << getprogname() << " <tid> <profile> [... profileN]" << std::endl
- << " tid Thread ID to apply the profiles to." << std::endl
- << " profile Name of the profile to apply." << std::endl
- << "Applies listed profiles to the thread with specified ID." << std::endl
- << "Profiles are applied in the order specified in the command line." << std::endl
- << "If applying a profile fails, remaining profiles are ignored." << std::endl;
- exit(exit_status);
-}
-
-int main(int argc, char* argv[]) {
- if (argc < 3) {
- usage(EXIT_FAILURE);
- }
-
- int tid = atoi(argv[1]);
- if (tid == 0) {
- std::cerr << "Invalid thread id" << std::endl;
- exit(EXIT_FAILURE);
- }
-
- for (int i = 2; i < argc; i++) {
- if (!SetTaskProfiles(tid, {argv[i]})) {
- std::cerr << "Failed to apply " << argv[i] << " profile" << std::endl;
- exit(EXIT_FAILURE);
- }
- std::cout << "Profile " << argv[i] << " is applied successfully!" << std::endl;
- }
-
- return 0;
-}
diff --git a/libqtaguid/Android.bp b/libqtaguid/Android.bp
new file mode 100644
index 000000000..64db09580
--- /dev/null
+++ b/libqtaguid/Android.bp
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_headers {
+ name: "libqtaguid_headers",
+ vendor_available: false,
+ host_supported: false,
+ export_include_dirs: ["include"],
+ target: {
+ linux_bionic: {
+ enabled: true,
+ },
+ },
+}
+
+cc_library {
+ name: "libqtaguid",
+ vendor_available: false,
+ host_supported: false,
+ target: {
+ android: {
+ srcs: [
+ "qtaguid.c",
+ ],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+ },
+ },
+
+ shared_libs: ["liblog"],
+ header_libs: [
+ "libqtaguid_headers",
+ ],
+ export_header_lib_headers: ["libqtaguid_headers"],
+ local_include_dirs: ["include"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+}
diff --git a/libqtaguid/include/qtaguid/qtaguid.h b/libqtaguid/include/qtaguid/qtaguid.h
new file mode 100644
index 000000000..72285e532
--- /dev/null
+++ b/libqtaguid/include/qtaguid/qtaguid.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LEGACY_QTAGUID_H
+#define __LEGACY_QTAGUID_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Set tags (and owning UIDs) for network sockets. The socket must be untagged
+ * by calling qtaguid_untagSocket() before closing it, otherwise the qtaguid
+ * module will keep a reference to it even after close.
+ */
+extern int legacy_tagSocket(int sockfd, int tag, uid_t uid);
+
+/*
+ * Untag a network socket before closing.
+ */
+extern int legacy_untagSocket(int sockfd);
+
+/*
+ * For the given uid, switch counter sets.
+ * The kernel only keeps a limited number of sets.
+ * 2 for now.
+ */
+extern int legacy_setCounterSet(int counterSetNum, uid_t uid);
+
+/*
+ * Delete all tag info that relates to the given tag an uid.
+ * If the tag is 0, then ALL info about the uid is freeded.
+ * The delete data also affects active tagged socketd, which are
+ * then untagged.
+ * The calling process can only operate on its own tags.
+ * Unless it is part of the happy AID_NET_BW_ACCT group.
+ * In which case it can clobber everything.
+ */
+extern int legacy_deleteTagData(int tag, uid_t uid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LEGACY_QTAGUID_H */
diff --git a/libqtaguid/qtaguid.c b/libqtaguid/qtaguid.c
new file mode 100644
index 000000000..cd38bad77
--- /dev/null
+++ b/libqtaguid/qtaguid.c
@@ -0,0 +1,143 @@
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+// #define LOG_NDEBUG 0
+
+#define LOG_TAG "qtaguid"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <log/log.h>
+#include <qtaguid/qtaguid.h>
+
+static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl";
+static const int CTRL_MAX_INPUT_LEN = 128;
+
+/*
+ * One per proccess.
+ * Once the device is open, this process will have its socket tags tracked.
+ * And on exit or untimely death, all socket tags will be removed.
+ * A process can only open /dev/xt_qtaguid once.
+ * It should not close it unless it is really done with all the socket tags.
+ * Failure to open it will be visible when socket tagging will be attempted.
+ */
+static int resTrackFd = -1;
+pthread_once_t resTrackInitDone = PTHREAD_ONCE_INIT;
+
+/* Only call once per process. */
+void legacy_resTrack(void) {
+ resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY | O_CLOEXEC));
+}
+
+/*
+ * Returns:
+ * 0 on success.
+ * -errno on failure.
+ */
+static int write_ctrl(const char* cmd) {
+ int fd, res, savedErrno;
+
+ ALOGV("write_ctrl(%s)", cmd);
+
+ fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY | O_CLOEXEC));
+ if (fd < 0) {
+ return -errno;
+ }
+
+ res = TEMP_FAILURE_RETRY(write(fd, cmd, strlen(cmd)));
+ if (res < 0) {
+ savedErrno = errno;
+ } else {
+ savedErrno = 0;
+ }
+ if (res < 0) {
+ // ALOGV is enough because all the callers also log failures
+ ALOGV("Failed write_ctrl(%s) res=%d errno=%d", cmd, res, savedErrno);
+ }
+ close(fd);
+ return -savedErrno;
+}
+
+int legacy_tagSocket(int sockfd, int tag, uid_t uid) {
+ char lineBuf[CTRL_MAX_INPUT_LEN];
+ int res;
+ uint64_t kTag = ((uint64_t)tag << 32);
+
+ pthread_once(&resTrackInitDone, legacy_resTrack);
+
+ snprintf(lineBuf, sizeof(lineBuf), "t %d %" PRIu64 " %d", sockfd, kTag, uid);
+
+ ALOGV("Tagging socket %d with tag %" PRIx64 "{%u,0} for uid %d", sockfd, kTag, tag, uid);
+
+ res = write_ctrl(lineBuf);
+ if (res < 0) {
+ ALOGI("Tagging socket %d with tag %" PRIx64 "(%d) for uid %d failed errno=%d", sockfd, kTag,
+ tag, uid, res);
+ }
+
+ return res;
+}
+
+int legacy_untagSocket(int sockfd) {
+ char lineBuf[CTRL_MAX_INPUT_LEN];
+ int res;
+
+ ALOGV("Untagging socket %d", sockfd);
+
+ snprintf(lineBuf, sizeof(lineBuf), "u %d", sockfd);
+ res = write_ctrl(lineBuf);
+ if (res < 0) {
+ ALOGI("Untagging socket %d failed errno=%d", sockfd, res);
+ }
+
+ return res;
+}
+
+int legacy_setCounterSet(int counterSetNum, uid_t uid) {
+ char lineBuf[CTRL_MAX_INPUT_LEN];
+ int res;
+
+ ALOGV("Setting counters to set %d for uid %d", counterSetNum, uid);
+
+ snprintf(lineBuf, sizeof(lineBuf), "s %d %d", counterSetNum, uid);
+ res = write_ctrl(lineBuf);
+ return res;
+}
+
+int legacy_deleteTagData(int tag, uid_t uid) {
+ char lineBuf[CTRL_MAX_INPUT_LEN];
+ int cnt = 0, res = 0;
+ uint64_t kTag = (uint64_t)tag << 32;
+
+ ALOGV("Deleting tag data with tag %" PRIx64 "{%d,0} for uid %d", kTag, tag, uid);
+
+ pthread_once(&resTrackInitDone, legacy_resTrack);
+
+ snprintf(lineBuf, sizeof(lineBuf), "d %" PRIu64 " %d", kTag, uid);
+ res = write_ctrl(lineBuf);
+ if (res < 0) {
+ ALOGI("Deleting tag data with tag %" PRIx64 "/%d for uid %d failed with cnt=%d errno=%d",
+ kTag, tag, uid, cnt, errno);
+ }
+
+ return res;
+}
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 02bfee68d..0b4b640ad 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -85,25 +85,23 @@ python_binary_host {
srcs: ["simg_dump.py"],
version: {
py2: {
- enabled: false,
- },
- py3: {
embedded_launcher: true,
enabled: true,
},
+ py3: {
+ enabled: false,
+ },
},
}
cc_fuzz {
name: "sparse_fuzzer",
- host_supported: true,
+ host_supported: false,
srcs: [
"sparse_fuzzer.cpp",
],
static_libs: [
"libsparse",
- "libbase",
- "libz",
"liblog",
],
}
diff --git a/libsparse/img2simg.cpp b/libsparse/img2simg.cpp
index 3e24cc014..4c2c6ca6f 100644
--- a/libsparse/img2simg.cpp
+++ b/libsparse/img2simg.cpp
@@ -93,7 +93,7 @@ int main(int argc, char* argv[]) {
}
sparse_file_verbose(s);
- ret = sparse_file_read(s, in, SPARSE_READ_MODE_NORMAL, false);
+ ret = sparse_file_read(s, in, false, false);
if (ret) {
fprintf(stderr, "Failed to read file\n");
exit(-1);
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 7c52c3f90..2f75349a6 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -225,42 +225,38 @@ int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
int (*write)(void *priv, const void *data, size_t len, unsigned int block,
unsigned int nr_blocks),
void *priv);
-
/**
- * enum sparse_read_mode - The method to use when reading in files
- * @SPARSE_READ_MODE_NORMAL: The input is a regular file. Constant chunks of
- * data (including holes) will be be converted to
- * fill chunks.
- * @SPARSE_READ_MODE_SPARSE: The input is an Android sparse file.
- * @SPARSE_READ_MODE_HOLE: The input is a regular file. Holes will be converted
- * to "don't care" chunks. Other constant chunks will
- * be converted to fill chunks.
+ * sparse_file_read - read a file into a sparse file cookie
+ *
+ * @s - sparse file cookie
+ * @fd - file descriptor to read from
+ * @sparse - read a file in the Android sparse file format
+ * @crc - verify the crc of a file in the Android sparse file format
+ *
+ * Reads a file into a sparse file cookie. If sparse is true, the file is
+ * assumed to be in the Android sparse file format. If sparse is false, the
+ * file will be sparsed by looking for block aligned chunks of all zeros or
+ * another 32 bit value. If crc is true, the crc of the sparse file will be
+ * verified.
+ *
+ * Returns 0 on success, negative errno on error.
*/
-enum sparse_read_mode {
- SPARSE_READ_MODE_NORMAL = false,
- SPARSE_READ_MODE_SPARSE = true,
- SPARSE_READ_MODE_HOLE,
-};
+int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc);
/**
- * sparse_file_read - read a file into a sparse file cookie
+ * sparse_file_read_buf - read a buffer into a sparse file cookie
*
* @s - sparse file cookie
- * @fd - file descriptor to read from
- * @mode - mode to use when reading the input file
+ * @buf - buffer to read from
* @crc - verify the crc of a file in the Android sparse file format
*
- * Reads a file into a sparse file cookie. If @mode is
- * %SPARSE_READ_MODE_SPARSE, the file is assumed to be in the Android sparse
- * file format. If @mode is %SPARSE_READ_MODE_NORMAL, the file will be sparsed
- * by looking for block aligned chunks of all zeros or another 32 bit value. If
- * @mode is %SPARSE_READ_MODE_HOLE, the file will be sparsed like
- * %SPARSE_READ_MODE_NORMAL, but holes in the file will be converted to "don't
- * care" chunks. If crc is true, the crc of the sparse file will be verified.
+ * Reads a buffer into a sparse file cookie. The buffer must remain
+ * valid until the sparse file cookie is freed. If crc is true, the
+ * crc of the sparse file will be verified.
*
* Returns 0 on success, negative errno on error.
*/
-int sparse_file_read(struct sparse_file *s, int fd, enum sparse_read_mode mode, bool crc);
+int sparse_file_read_buf(struct sparse_file *s, char *buf, bool crc);
/**
* sparse_file_import - import an existing sparse file
@@ -281,7 +277,6 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc);
* sparse_file_import_buf - import an existing sparse file from a buffer
*
* @buf - buffer to read from
- * @len - length of buffer
* @verbose - print verbose errors while reading the sparse file
* @crc - verify the crc of a file in the Android sparse file format
*
@@ -291,7 +286,7 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc);
*
* Returns a new sparse file cookie on success, NULL on error.
*/
-struct sparse_file* sparse_file_import_buf(char* buf, size_t len, bool verbose, bool crc);
+struct sparse_file *sparse_file_import_buf(char* buf, bool verbose, bool crc);
/**
* sparse_file_import_auto - import an existing sparse or normal file
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index cb5d73052..b2c5407e1 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -54,8 +54,6 @@
#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
-#define FILL_ZERO_BUFSIZE (2 * 1024 * 1024)
-
#define container_of(inner, outer_t, elem) ((outer_t*)((char*)(inner)-offsetof(outer_t, elem)))
struct output_file_ops {
@@ -393,29 +391,13 @@ static int write_sparse_data_chunk(struct output_file* out, uint64_t len, void*
ret = out->ops->write(out, data, len);
if (ret < 0) return -1;
if (zero_len) {
- uint64_t len = zero_len;
- uint64_t write_len;
- while (len) {
- write_len = std::min(len, (uint64_t)FILL_ZERO_BUFSIZE);
- ret = out->ops->write(out, out->zero_buf, write_len);
- if (ret < 0) {
- return ret;
- }
- len -= write_len;
- }
+ ret = out->ops->write(out, out->zero_buf, zero_len);
+ if (ret < 0) return -1;
}
if (out->use_crc) {
out->crc32 = sparse_crc32(out->crc32, data, len);
- if (zero_len) {
- uint64_t len = zero_len;
- uint64_t write_len;
- while (len) {
- write_len = std::min(len, (uint64_t)FILL_ZERO_BUFSIZE);
- out->crc32 = sparse_crc32(out->crc32, out->zero_buf, write_len);
- len -= write_len;
- }
- }
+ if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
}
out->cur_out_ptr += rnd_up_len;
@@ -478,12 +460,12 @@ static int write_normal_fill_chunk(struct output_file* out, uint64_t len, uint32
uint64_t write_len;
/* Initialize fill_buf with the fill_val */
- for (i = 0; i < FILL_ZERO_BUFSIZE / sizeof(uint32_t); i++) {
+ for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
out->fill_buf[i] = fill_val;
}
while (len) {
- write_len = std::min(len, (uint64_t)FILL_ZERO_BUFSIZE);
+ write_len = std::min(len, (uint64_t)out->block_size);
ret = out->ops->write(out, out->fill_buf, write_len);
if (ret < 0) {
return ret;
@@ -530,15 +512,13 @@ static int output_file_init(struct output_file* out, int block_size, int64_t len
out->crc32 = 0;
out->use_crc = crc;
- // don't use sparse format block size as it can takes up to 32GB
- out->zero_buf = reinterpret_cast<char*>(calloc(FILL_ZERO_BUFSIZE, 1));
+ out->zero_buf = reinterpret_cast<char*>(calloc(block_size, 1));
if (!out->zero_buf) {
error_errno("malloc zero_buf");
return -ENOMEM;
}
- // don't use sparse format block size as it can takes up to 32GB
- out->fill_buf = reinterpret_cast<uint32_t*>(calloc(FILL_ZERO_BUFSIZE, 1));
+ out->fill_buf = reinterpret_cast<uint32_t*>(calloc(block_size, 1));
if (!out->fill_buf) {
error_errno("malloc fill_buf");
ret = -ENOMEM;
diff --git a/libsparse/simg_dump.py b/libsparse/simg_dump.py
index 8811a52fc..82a03ad95 100755
--- a/libsparse/simg_dump.py
+++ b/libsparse/simg_dump.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
# Copyright (C) 2012 The Android Open Source Project
#
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import print_function
import csv
import getopt
import hashlib
@@ -46,7 +47,7 @@ def main():
opts, args = getopt.getopt(sys.argv[1:],
"vsc:",
["verbose", "showhash", "csvfile"])
- except getopt.GetoptError as e:
+ except getopt.GetoptError, e:
print(e)
usage(me)
for o, a in opts:
@@ -120,7 +121,7 @@ def main():
"output offset", "output blocks", "type", "hash"])
offset = 0
- for i in range(1, total_chunks + 1):
+ for i in xrange(1, total_chunks + 1):
header_bin = FH.read(12)
header = struct.unpack("<2H2I", header_bin)
chunk_type = header[0]
@@ -159,7 +160,7 @@ def main():
if showhash:
h = hashlib.sha1()
data = fill_bin * (blk_sz / 4);
- for block in range(chunk_sz):
+ for block in xrange(chunk_sz):
h.update(data)
curhash = h.hexdigest()
elif chunk_type == 0xCAC3:
diff --git a/libsparse/sparse_fuzzer.cpp b/libsparse/sparse_fuzzer.cpp
index 235d15dce..42f331fc3 100644
--- a/libsparse/sparse_fuzzer.cpp
+++ b/libsparse/sparse_fuzzer.cpp
@@ -1,27 +1,16 @@
#include "include/sparse/sparse.h"
-static volatile int count;
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < 2 * sizeof(wchar_t)) return 0;
-int WriteCallback(void* priv __attribute__((__unused__)), const void* data, size_t len) {
- if (!data) {
- return 0;
- }
- if (len == 0) {
+ int64_t blocksize = 4096;
+ struct sparse_file* file = sparse_file_new(size, blocksize);
+ if (!file) {
return 0;
}
- const char* p = (const char*)data;
- // Just to make sure the data is accessible
- // We only check the head and tail to save time
- count += *p;
- count += *(p+len-1);
+ unsigned int block = 1;
+ sparse_file_add_data(file, &data, size, block);
+ sparse_file_destroy(file);
return 0;
}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- struct sparse_file* file = sparse_file_import_buf((char*)data, size, true, false);
- if (!file) {
- return 0;
- }
- return sparse_file_callback(file, false, false, WriteCallback, nullptr);
-}
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 028b6bed1..c4c182358 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -58,15 +58,14 @@ static std::string ErrorString(int err) {
class SparseFileSource {
public:
- /* Seeks the source ahead by the given offset.
- * Return 0 if successful. */
- virtual int Seek(int64_t offset) = 0;
+ /* Seeks the source ahead by the given offset. */
+ virtual void Seek(int64_t offset) = 0;
/* Return the current offset. */
virtual int64_t GetOffset() = 0;
- /* Rewind to beginning. Return 0 if successful. */
- virtual int Rewind() = 0;
+ /* Set the current offset. Return 0 if successful. */
+ virtual int SetOffset(int64_t offset) = 0;
/* Adds the given length from the current offset of the source to the file at the given block.
* Return 0 if successful. */
@@ -89,14 +88,12 @@ class SparseFileFdSource : public SparseFileSource {
SparseFileFdSource(int fd) : fd(fd) {}
~SparseFileFdSource() override {}
- int Seek(int64_t off) override {
- return lseek64(fd, off, SEEK_CUR) != -1 ? 0 : -errno;
- }
+ void Seek(int64_t off) override { lseek64(fd, off, SEEK_CUR); }
int64_t GetOffset() override { return lseek64(fd, 0, SEEK_CUR); }
- int Rewind() override {
- return lseek64(fd, 0, SEEK_SET) == 0 ? 0 : -errno;
+ int SetOffset(int64_t offset) override {
+ return lseek64(fd, offset, SEEK_SET) == offset ? 0 : -errno;
}
int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
@@ -123,74 +120,39 @@ class SparseFileFdSource : public SparseFileSource {
class SparseFileBufSource : public SparseFileSource {
private:
- char* buf_start;
- char* buf_end;
char* buf;
int64_t offset;
- int AccessOkay(int64_t len) {
- if (len <= 0) return -EINVAL;
- if (buf < buf_start) return -EOVERFLOW;
- if (buf >= buf_end) return -EOVERFLOW;
- if (len > buf_end - buf) return -EOVERFLOW;
-
- return 0;
- }
-
public:
- SparseFileBufSource(char* buf, uint64_t len) {
- this->buf = buf;
- this->offset = 0;
- this->buf_start = buf;
- this->buf_end = buf + len;
- }
+ SparseFileBufSource(char* buf) : buf(buf), offset(0) {}
~SparseFileBufSource() override {}
- int Seek(int64_t off) override {
- int ret = AccessOkay(off);
- if (ret < 0) {
- return ret;
- }
+ void Seek(int64_t off) override {
buf += off;
offset += off;
- return 0;
}
int64_t GetOffset() override { return offset; }
- int Rewind() override {
- buf = buf_start;
- offset = 0;
+ int SetOffset(int64_t off) override {
+ buf += off - offset;
+ offset = off;
return 0;
}
int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
- int ret = AccessOkay(len);
- if (ret < 0) {
- return ret;
- }
return sparse_file_add_data(s, buf, len, block);
}
int ReadValue(void* ptr, int len) override {
- int ret = AccessOkay(len);
- if (ret < 0) {
- return ret;
- }
memcpy(ptr, buf, len);
- buf += len;
- offset += len;
+ Seek(len);
return 0;
}
int GetCrc32(uint32_t* crc32, int64_t len) override {
- int ret = AccessOkay(len);
- if (ret < 0) {
- return ret;
- }
*crc32 = sparse_crc32(*crc32, buf, len);
- buf += len;
- offset += len;
+ Seek(len);
return 0;
}
};
@@ -213,7 +175,7 @@ static int process_raw_chunk(struct sparse_file* s, unsigned int chunk_size,
SparseFileSource* source, unsigned int blocks, unsigned int block,
uint32_t* crc32) {
int ret;
- int64_t len = (int64_t)blocks * s->block_size;
+ int64_t len = blocks * s->block_size;
if (chunk_size % s->block_size != 0) {
return -EINVAL;
@@ -234,10 +196,7 @@ static int process_raw_chunk(struct sparse_file* s, unsigned int chunk_size,
return ret;
}
} else {
- ret = source->Seek(len);
- if (ret < 0) {
- return ret;
- }
+ source->Seek(len);
}
return 0;
@@ -420,10 +379,7 @@ static int sparse_file_read_sparse(struct sparse_file* s, SparseFileSource* sour
/* Skip the remaining bytes in a header that is longer than
* we expected.
*/
- ret = source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
- if (ret < 0) {
- return ret;
- }
+ source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
}
for (i = 0; i < sparse_header.total_chunks; i++) {
@@ -436,10 +392,7 @@ static int sparse_file_read_sparse(struct sparse_file* s, SparseFileSource* sour
/* Skip the remaining bytes in a header that is longer than
* we expected.
*/
- ret = source->Seek(sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN);
- if (ret < 0) {
- return ret;
- }
+ source->Seek(sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN);
}
ret = process_chunk(s, source, sparse_header.chunk_hdr_sz, &chunk_header, cur_block, crc_ptr);
@@ -457,10 +410,12 @@ static int sparse_file_read_sparse(struct sparse_file* s, SparseFileSource* sour
return 0;
}
-static int do_sparse_file_read_normal(struct sparse_file* s, int fd, uint32_t* buf, int64_t offset,
- int64_t remain) {
+static int sparse_file_read_normal(struct sparse_file* s, int fd) {
int ret;
- unsigned int block = offset / s->block_size;
+ uint32_t* buf = (uint32_t*)malloc(s->block_size);
+ unsigned int block = 0;
+ int64_t remain = s->len;
+ int64_t offset = 0;
unsigned int to_read;
unsigned int i;
bool sparse_block;
@@ -474,6 +429,7 @@ static int do_sparse_file_read_normal(struct sparse_file* s, int fd, uint32_t* b
ret = read_all(fd, buf, to_read);
if (ret < 0) {
error("failed to read sparse file");
+ free(buf);
return ret;
}
@@ -501,96 +457,28 @@ static int do_sparse_file_read_normal(struct sparse_file* s, int fd, uint32_t* b
block++;
}
- return 0;
-}
-
-static int sparse_file_read_normal(struct sparse_file* s, int fd) {
- int ret;
- uint32_t* buf = (uint32_t*)malloc(s->block_size);
-
- if (!buf)
- return -ENOMEM;
-
- ret = do_sparse_file_read_normal(s, fd, buf, 0, s->len);
- free(buf);
- return ret;
-}
-
-#ifdef __linux__
-static int sparse_file_read_hole(struct sparse_file* s, int fd) {
- int ret;
- uint32_t* buf = (uint32_t*)malloc(s->block_size);
- int64_t end = 0;
- int64_t start = 0;
-
- if (!buf) {
- return -ENOMEM;
- }
-
- do {
- start = lseek(fd, end, SEEK_DATA);
- if (start < 0) {
- if (errno == ENXIO)
- /* The rest of the file is a hole */
- break;
-
- error("could not seek to data");
- free(buf);
- return -errno;
- } else if (start > s->len) {
- break;
- }
-
- end = lseek(fd, start, SEEK_HOLE);
- if (end < 0) {
- error("could not seek to end");
- free(buf);
- return -errno;
- }
- end = std::min(end, s->len);
-
- start = ALIGN_DOWN(start, s->block_size);
- end = ALIGN(end, s->block_size);
- if (lseek(fd, start, SEEK_SET) < 0) {
- free(buf);
- return -errno;
- }
-
- ret = do_sparse_file_read_normal(s, fd, buf, start, end - start);
- if (ret) {
- free(buf);
- return ret;
- }
- } while (end < s->len);
-
free(buf);
return 0;
}
-#else
-static int sparse_file_read_hole(struct sparse_file* s __unused, int fd __unused) {
- return -ENOTSUP;
-}
-#endif
-int sparse_file_read(struct sparse_file* s, int fd, enum sparse_read_mode mode, bool crc) {
- if (crc && mode != SPARSE_READ_MODE_SPARSE) {
+int sparse_file_read(struct sparse_file* s, int fd, bool sparse, bool crc) {
+ if (crc && !sparse) {
return -EINVAL;
}
- switch (mode) {
- case SPARSE_READ_MODE_SPARSE: {
- SparseFileFdSource source(fd);
- return sparse_file_read_sparse(s, &source, crc);
- }
- case SPARSE_READ_MODE_NORMAL:
- return sparse_file_read_normal(s, fd);
- case SPARSE_READ_MODE_HOLE:
- return sparse_file_read_hole(s, fd);
- default:
- return -EINVAL;
+ if (sparse) {
+ SparseFileFdSource source(fd);
+ return sparse_file_read_sparse(s, &source, crc);
+ } else {
+ return sparse_file_read_normal(s, fd);
}
}
+int sparse_file_read_buf(struct sparse_file* s, char* buf, bool crc) {
+ SparseFileBufSource source(buf);
+ return sparse_file_read_sparse(s, &source, crc);
+}
+
static struct sparse_file* sparse_file_import_source(SparseFileSource* source, bool verbose,
bool crc) {
int ret;
@@ -622,14 +510,6 @@ static struct sparse_file* sparse_file_import_source(SparseFileSource* source, b
return nullptr;
}
- if (!sparse_header.blk_sz || (sparse_header.blk_sz % 4)) {
- return nullptr;
- }
-
- if (!sparse_header.total_blks) {
- return nullptr;
- }
-
len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
s = sparse_file_new(sparse_header.blk_sz, len);
if (!s) {
@@ -637,7 +517,7 @@ static struct sparse_file* sparse_file_import_source(SparseFileSource* source, b
return nullptr;
}
- ret = source->Rewind();
+ ret = source->SetOffset(0);
if (ret < 0) {
verbose_error(verbose, ret, "seeking");
sparse_file_destroy(s);
@@ -660,8 +540,8 @@ struct sparse_file* sparse_file_import(int fd, bool verbose, bool crc) {
return sparse_file_import_source(&source, verbose, crc);
}
-struct sparse_file* sparse_file_import_buf(char* buf, size_t len, bool verbose, bool crc) {
- SparseFileBufSource source(buf, len);
+struct sparse_file* sparse_file_import_buf(char* buf, bool verbose, bool crc) {
+ SparseFileBufSource source(buf);
return sparse_file_import_source(&source, verbose, crc);
}
diff --git a/libstats/bootstrap/Android.bp b/libstats/bootstrap/Android.bp
deleted file mode 100644
index 332d9c81b..000000000
--- a/libstats/bootstrap/Android.bp
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// 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.
-//
-
-// =========================================================================
-// Native library that provide a client to StatsBootstrapAtomService.
-// This library should only be used by processes that start in the bootstrap namespace.
-// All other clients should use libstatssocket, provided by the statsd apex.
-// =========================================================================
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_defaults {
- name: "libstatsbootstrap_defaults",
- srcs: [
- "BootstrapClientInternal.cpp",
- "StatsBootstrapAtomClient.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: [
- "libbinder",
- "libutils",
- "android.os.statsbootstrap_aidl-cpp",
- ],
-}
-
-cc_library {
- name: "libstatsbootstrap",
- defaults: ["libstatsbootstrap_defaults"],
- export_include_dirs: ["include"],
-}
-
-
diff --git a/libstats/bootstrap/BootstrapClientInternal.cpp b/libstats/bootstrap/BootstrapClientInternal.cpp
deleted file mode 100644
index b02e11626..000000000
--- a/libstats/bootstrap/BootstrapClientInternal.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 "BootstrapClientInternal.h"
-
-#include <binder/IServiceManager.h>
-
-namespace android {
-namespace os {
-namespace stats {
-
-sp<BootstrapClientInternal> BootstrapClientInternal::getInstance() {
- static sp<BootstrapClientInternal> client = new BootstrapClientInternal();
- return client;
-}
-
-sp<IStatsBootstrapAtomService> BootstrapClientInternal::getServiceNonBlocking() {
- std::lock_guard<std::mutex> lock(mLock);
- if (mService != nullptr) {
- return mService;
- }
- connectNonBlockingLocked();
- return mService;
-}
-
-void BootstrapClientInternal::binderDied(const wp<IBinder>&) {
- std::lock_guard<std::mutex> lock(mLock);
- mService = nullptr;
- connectNonBlockingLocked();
-}
-
-void BootstrapClientInternal::connectNonBlockingLocked() {
- const String16 name("statsbootstrap");
- mService =
- interface_cast<IStatsBootstrapAtomService>(defaultServiceManager()->checkService(name));
- if (mService != nullptr) {
- // Set up binder death.
- IInterface::asBinder(mService)->linkToDeath(this);
- }
-}
-
-} // namespace stats
-} // namespace os
-} // namespace android \ No newline at end of file
diff --git a/libstats/bootstrap/BootstrapClientInternal.h b/libstats/bootstrap/BootstrapClientInternal.h
deleted file mode 100644
index 96238dade..000000000
--- a/libstats/bootstrap/BootstrapClientInternal.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/os/IStatsBootstrapAtomService.h>
-
-namespace android {
-namespace os {
-namespace stats {
-
-class BootstrapClientInternal : public IBinder::DeathRecipient {
- public:
- static sp<BootstrapClientInternal> getInstance();
- void binderDied(const wp<IBinder>& who) override;
- sp<IStatsBootstrapAtomService> getServiceNonBlocking();
-
- private:
- BootstrapClientInternal() {}
- void connectNonBlockingLocked();
-
- mutable std::mutex mLock;
- sp<IStatsBootstrapAtomService> mService;
-};
-
-} // namespace stats
-} // namespace os
-} // namespace android
diff --git a/libstats/bootstrap/StatsBootstrapAtomClient.cpp b/libstats/bootstrap/StatsBootstrapAtomClient.cpp
deleted file mode 100644
index 348b7fa72..000000000
--- a/libstats/bootstrap/StatsBootstrapAtomClient.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 "include/StatsBootstrapAtomClient.h"
-
-#include <android/os/IStatsBootstrapAtomService.h>
-
-#include "BootstrapClientInternal.h"
-
-namespace android {
-namespace os {
-namespace stats {
-
-bool StatsBootstrapAtomClient::reportBootstrapAtom(const StatsBootstrapAtom& atom) {
- sp<IStatsBootstrapAtomService> service =
- BootstrapClientInternal::getInstance()->getServiceNonBlocking();
- if (service == nullptr) {
- return false;
- }
- return service->reportBootstrapAtom(atom).isOk();
-}
-
-} // namespace stats
-} // namespace os
-} // namespace android \ No newline at end of file
diff --git a/libstats/bootstrap/include/StatsBootstrapAtomClient.h b/libstats/bootstrap/include/StatsBootstrapAtomClient.h
deleted file mode 100644
index 87930fd75..000000000
--- a/libstats/bootstrap/include/StatsBootstrapAtomClient.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/os/StatsBootstrapAtom.h>
-
-namespace android {
-namespace os {
-namespace stats {
-
-class StatsBootstrapAtomClient {
- public:
- static bool reportBootstrapAtom(const StatsBootstrapAtom& atom);
-};
-
-} // namespace stats
-} // namespace os
-} // namespace android \ No newline at end of file
diff --git a/libstats/pull_lazy/TEST_MAPPING b/libstats/pull_lazy/TEST_MAPPING
index 92f1e6ac5..89b8c2a1f 100644
--- a/libstats/pull_lazy/TEST_MAPPING
+++ b/libstats/pull_lazy/TEST_MAPPING
@@ -3,10 +3,5 @@
{
"name" : "libstatspull_lazy_test"
}
- ],
- "hwasan-postsubmit" : [
- {
- "name" : "libstatspull_lazy_test"
- }
]
} \ No newline at end of file
diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp
index 4ffa98d14..2a89e296e 100644
--- a/libstats/pull_rust/Android.bp
+++ b/libstats/pull_rust/Android.bp
@@ -44,11 +44,6 @@ rust_bindgen {
],
},
},
- min_sdk_version: "apex_inherit",
- apex_available: [
- "//apex_available:platform",
- "com.android.virt",
- ]
}
rust_library {
@@ -62,13 +57,3 @@ rust_library {
"libstatspull_bindgen",
],
}
-
-rust_test {
- name: "libstatspull_bindgen_test",
- srcs: [":libstatspull_bindgen"],
- crate_name: "statspull_bindgen_test",
- test_suites: ["general-tests"],
- auto_gen_config: true,
- clippy_lints: "none",
- lints: "none",
-}
diff --git a/libstats/pull_rust/stats_pull.rs b/libstats/pull_rust/stats_pull.rs
index 09b26232f..174125e9a 100644
--- a/libstats/pull_rust/stats_pull.rs
+++ b/libstats/pull_rust/stats_pull.rs
@@ -68,7 +68,7 @@ impl Metadata {
}
/// Calls AStatsManager_PullAtomMetadata_setAdditiveFields.
- pub fn set_additive_fields(&mut self, additive_fields: &mut [i32]) {
+ pub fn set_additive_fields(&mut self, additive_fields: &mut Vec<i32>) {
// Safety: Metadata::new ensures that self.metadata is a valid object.
unsafe {
AStatsManager_PullAtomMetadata_setAdditiveFields(
diff --git a/libstats/socket_lazy/TEST_MAPPING b/libstats/socket_lazy/TEST_MAPPING
index b182660b0..13afc0087 100644
--- a/libstats/socket_lazy/TEST_MAPPING
+++ b/libstats/socket_lazy/TEST_MAPPING
@@ -3,10 +3,5 @@
{
"name" : "libstatssocket_lazy_test"
}
- ],
- "hwasan-postsubmit" : [
- {
- "name" : "libstatssocket_lazy_test"
- }
]
} \ No newline at end of file
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
index 144b4b6ca..671de4d98 100644
--- a/libsuspend/Android.bp
+++ b/libsuspend/Android.bp
@@ -6,7 +6,6 @@ package {
cc_library {
name: "libsuspend",
- vendor_available: true,
srcs: [
"autosuspend.c",
"autosuspend_wakeup_count.cpp",
diff --git a/libsync/OWNERS b/libsync/OWNERS
index 8f69e505e..e75b15b8f 100644
--- a/libsync/OWNERS
+++ b/libsync/OWNERS
@@ -1,2 +1,3 @@
chrisforbes@google.com
+hridya@google.com
jessehall@google.com
diff --git a/libsystem/include/system/graphics.h b/libsystem/include/system/graphics.h
index a3c23b20c..1b6060a4e 100644
--- a/libsystem/include/system/graphics.h
+++ b/libsystem/include/system/graphics.h
@@ -59,14 +59,12 @@ typedef android_hdr_t android_hdr;
/*
* Structure for describing YCbCr formats for consumption by applications.
- * This is used with HAL_PIXEL_FORMAT_YCbCr_*.
+ * This is used with HAL_PIXEL_FORMAT_YCbCr_*_888.
*
* Buffer chroma subsampling is defined in the format.
* e.g. HAL_PIXEL_FORMAT_YCbCr_420_888 has subsampling 4:2:0.
*
- * Buffers must have a byte aligned channel depth or a byte aligned packed
- * channel depth (e.g. 10 bits packed into 16 bits for
- * HAL_PIXEL_FORMAT_YCbCr_P010).
+ * Buffers must have a 8 bit depth.
*
* y, cb, and cr point to the first byte of their respective planes.
*
@@ -77,8 +75,8 @@ typedef android_hdr_t android_hdr;
* cstride is the stride of the chroma planes.
*
* chroma_step is the distance in bytes from one chroma pixel value to the
- * next. This is `2 * channel depth` bytes for semiplanar (because chroma
- * values are interleaved) and `1 * channel depth` bytes for planar.
+ * next. This is 2 bytes for semiplanar (because chroma values are interleaved
+ * and each chroma value is one byte) and 1 for planar.
*/
struct android_ycbcr {
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 515cc1047..3b6cfd830 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -31,41 +31,14 @@
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/personality.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <sys/utsname.h>
-
-#include <android-base/parseint.h>
-#include <log/log.h>
-#include <sysutils/NetlinkEvent.h>
-
-using android::base::ParseInt;
/* From kernel's net/netfilter/xt_quota2.c */
const int LOCAL_QLOG_NL_EVENT = 112;
const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;
-/******************************************************************************
- * WARNING: HERE BE DRAGONS! *
- * *
- * This is here to provide for compatibility with both 32 and 64-bit kernels *
- * from 32-bit userspace. *
- * *
- * The kernel definition of this struct uses types (like long) that are not *
- * the same across 32-bit and 64-bit builds, and there is no compatibility *
- * layer to fix it up before it reaches userspace. *
- * As such we need to detect the bit-ness of the kernel and deal with it. *
- * *
- ******************************************************************************/
-
-/*
- * This is the verbatim kernel declaration from net/netfilter/xt_quota2.c,
- * it is *NOT* of a well defined layout and is included here for compile
- * time assertions only.
- *
- * It got there from deprecated ipt_ULOG.h to parse QLOG_NL_EVENT.
- */
+/* From deprecated ipt_ULOG.h to parse QLOG_NL_EVENT. */
#define ULOG_MAC_LEN 80
#define ULOG_PREFIX_LEN 32
typedef struct ulog_packet_msg {
@@ -82,117 +55,11 @@ typedef struct ulog_packet_msg {
unsigned char payload[0];
} ulog_packet_msg_t;
-// On Linux int is always 32 bits, while sizeof(long) == sizeof(void*),
-// thus long on a 32-bit Linux kernel is 32-bits, like int always is
-typedef int long32;
-typedef unsigned int ulong32;
-static_assert(sizeof(long32) == 4);
-static_assert(sizeof(ulong32) == 4);
-
-// Here's the same structure definition with the assumption the kernel
-// is compiled for 32-bits.
-typedef struct {
- ulong32 mark;
- long32 timestamp_sec;
- long32 timestamp_usec;
- unsigned int hook;
- char indev_name[IFNAMSIZ];
- char outdev_name[IFNAMSIZ];
- ulong32 data_len;
- char prefix[ULOG_PREFIX_LEN];
- unsigned char mac_len;
- unsigned char mac[ULOG_MAC_LEN];
- unsigned char payload[0];
-} ulog_packet_msg32_t;
-
-// long on a 64-bit kernel is 64-bits with 64-bit alignment,
-// while long long is 64-bit but may have 32-bit aligment.
-typedef long long __attribute__((__aligned__(8))) long64;
-typedef unsigned long long __attribute__((__aligned__(8))) ulong64;
-static_assert(sizeof(long64) == 8);
-static_assert(sizeof(ulong64) == 8);
-
-// Here's the same structure definition with the assumption the kernel
-// is compiled for 64-bits.
-typedef struct {
- ulong64 mark;
- long64 timestamp_sec;
- long64 timestamp_usec;
- unsigned int hook;
- char indev_name[IFNAMSIZ];
- char outdev_name[IFNAMSIZ];
- ulong64 data_len;
- char prefix[ULOG_PREFIX_LEN];
- unsigned char mac_len;
- unsigned char mac[ULOG_MAC_LEN];
- unsigned char payload[0];
-} ulog_packet_msg64_t;
-
-// One expects the 32-bit version to be smaller than the 64-bit version.
-static_assert(sizeof(ulog_packet_msg32_t) < sizeof(ulog_packet_msg64_t));
-// And either way the 'native' version should match either the 32 or 64 bit one.
-static_assert(sizeof(ulog_packet_msg_t) == sizeof(ulog_packet_msg32_t) ||
- sizeof(ulog_packet_msg_t) == sizeof(ulog_packet_msg64_t));
-
-// In practice these sizes are always simply (for both x86 and arm):
-static_assert(sizeof(ulog_packet_msg32_t) == 168);
-static_assert(sizeof(ulog_packet_msg64_t) == 192);
-
-// Figure out the bitness of userspace.
-// Trivial and known at compile time.
-static bool isUserspace64bit(void) {
- return sizeof(long) == 8;
-}
-
-// Figure out the bitness of the kernel.
-static bool isKernel64Bit(void) {
- // a 64-bit userspace requires a 64-bit kernel
- if (isUserspace64bit()) return true;
-
- static bool init = false;
- static bool cache = false;
- if (init) return cache;
-
- // Retrieve current personality - on Linux this system call *cannot* fail.
- int p = personality(0xffffffff);
- // But if it does just assume kernel and userspace (which is 32-bit) match...
- if (p == -1) return false;
-
- // This will effectively mask out the bottom 8 bits, and switch to 'native'
- // personality, and then return the previous personality of this thread
- // (likely PER_LINUX or PER_LINUX32) with any extra options unmodified.
- int q = personality((p & ~PER_MASK) | PER_LINUX);
- // Per man page this theoretically could error out with EINVAL,
- // but kernel code analysis suggests setting PER_LINUX cannot fail.
- // Either way, assume kernel and userspace (which is 32-bit) match...
- if (q != p) return false;
-
- struct utsname u;
- (void)uname(&u); // only possible failure is EFAULT, but u is on stack.
-
- // Switch back to previous personality.
- // Theoretically could fail with EINVAL on arm64 with no 32-bit support,
- // but then we wouldn't have fetched 'p' from the kernel in the first place.
- // Either way there's nothing meaningul we can do in case of error.
- // Since PER_LINUX32 vs PER_LINUX only affects uname.machine it doesn't
- // really hurt us either. We're really just switching back to be 'clean'.
- (void)personality(p);
-
- // Possible values of utsname.machine observed on x86_64 desktop (arm via qemu):
- // x86_64 i686 aarch64 armv7l
- // additionally observed on arm device:
- // armv8l
- // presumably also might just be possible:
- // i386 i486 i586
- // and there might be other weird arm32 cases.
- // We note that the 64 is present in both 64-bit archs,
- // and in general is likely to be present in only 64-bit archs.
- cache = !!strstr(u.machine, "64");
- init = true;
- return cache;
-}
+#include <android-base/parseint.h>
+#include <log/log.h>
+#include <sysutils/NetlinkEvent.h>
-/******************************************************************************/
+using android::base::ParseInt;
NetlinkEvent::NetlinkEvent() {
mAction = Action::kUnknown;
@@ -413,22 +280,13 @@ bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
* Parse a QLOG_NL_EVENT message.
*/
bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
- const char* alert;
- const char* devname;
-
- if (isKernel64Bit()) {
- ulog_packet_msg64_t* pm64 = (ulog_packet_msg64_t*)NLMSG_DATA(nh);
- if (!checkRtNetlinkLength(nh, sizeof(*pm64))) return false;
- alert = pm64->prefix;
- devname = pm64->indev_name[0] ? pm64->indev_name : pm64->outdev_name;
- } else {
- ulog_packet_msg32_t* pm32 = (ulog_packet_msg32_t*)NLMSG_DATA(nh);
- if (!checkRtNetlinkLength(nh, sizeof(*pm32))) return false;
- alert = pm32->prefix;
- devname = pm32->indev_name[0] ? pm32->indev_name : pm32->outdev_name;
- }
+ const char *devname;
+ ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
+ if (!checkRtNetlinkLength(nh, sizeof(*pm)))
+ return false;
- asprintf(&mParams[0], "ALERT_NAME=%s", alert);
+ devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
+ asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
asprintf(&mParams[1], "INTERFACE=%s", devname);
mSubsystem = strdup("qlog");
mAction = Action::kChange;
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp
index 9ae73d0d8..38833179b 100644
--- a/libusbhost/Android.bp
+++ b/libusbhost/Android.bp
@@ -30,9 +30,11 @@ cc_library {
export_include_dirs: ["include"],
target: {
android: {
- header_libs: ["jni_headers"],
+ cflags: [
+ "-g",
+ "-DUSE_LIBLOG",
+ ],
shared_libs: ["liblog"],
- srcs: ["usbhost_jni.cpp"],
},
darwin: {
enabled: false,
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index 01cd68bb9..7e62542ce 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -21,7 +21,6 @@
extern "C" {
#endif
-#include <stddef.h>
#include <stdint.h>
#include <linux/version.h>
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index d8f15cd6c..3bed0e367 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -18,9 +18,20 @@
#define _GNU_SOURCE
#endif
-#include <usbhost/usbhost.h>
+// #define DEBUG 1
+#if DEBUG
-#include "usbhost_private.h"
+#ifdef USE_LIBLOG
+#define LOG_TAG "usbhost"
+#include "log/log.h"
+#define D ALOGD
+#else
+#define D printf
+#endif
+
+#else
+#define D(...)
+#endif
#include <stdio.h>
#include <stdlib.h>
@@ -37,19 +48,12 @@
#include <errno.h>
#include <ctype.h>
#include <poll.h>
+#include <pthread.h>
#include <linux/usbdevice_fs.h>
+#include <asm/byteorder.h>
-// #define DEBUG 1
-#if defined(DEBUG)
-#if defined(__BIONIC__)
-#define D ALOGD
-#else
-#define D printf
-#endif
-#else
-#define D(...)
-#endif
+#include "usbhost/usbhost.h"
#define DEV_DIR "/dev"
#define DEV_BUS_DIR DEV_DIR "/bus"
@@ -72,6 +76,8 @@ struct usb_host_context {
int wddbus;
};
+#define MAX_DESCRIPTORS_LENGTH 4096
+
struct usb_device {
char dev_name[64];
unsigned char desc[MAX_DESCRIPTORS_LENGTH];
diff --git a/libusbhost/usbhost_jni.cpp b/libusbhost/usbhost_jni.cpp
deleted file mode 100644
index 0da83dc76..000000000
--- a/libusbhost/usbhost_jni.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <usbhost/usbhost_jni.h>
-
-#include "usbhost_private.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-jbyteArray usb_jni_read_descriptors(JNIEnv* env, int fd) {
- if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
- ALOGE("usb_jni_read_descriptors(%d): lseek() failed: %s", fd, strerror(errno));
- return NULL;
- }
-
- jbyte buf[MAX_DESCRIPTORS_LENGTH];
- ssize_t n = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
- if (n == -1) {
- ALOGE("usb_jni_read_descriptors: read failed: %s", strerror(errno));
- return NULL;
- }
-
- jbyteArray result = env->NewByteArray(n);
- if (result) env->SetByteArrayRegion(result, 0, n, buf);
- return result;
-}
diff --git a/libusbhost/usbhost_private.h b/libusbhost/usbhost_private.h
deleted file mode 100644
index 72d79384c..000000000
--- a/libusbhost/usbhost_private.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#define LOG_TAG "usbhost"
-#include <log/log.h>
-
-// Somewhat arbitrary: Sony has reported needing more than 4KiB (but less
-// than 8KiB), and some frameworks code had 16KiB without any explanation,
-// so we went with the largest of those.
-#define MAX_DESCRIPTORS_LENGTH (16 * 1024)
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 019a3687a..13e4c02de 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -28,18 +28,16 @@ cc_library_headers {
min_sdk_version: "apex_inherit",
header_libs: [
- "libbase_headers",
- "libcutils_headers",
"liblog_headers",
- "libprocessgroup_headers",
"libsystem_headers",
+ "libcutils_headers",
+ "libprocessgroup_headers",
],
export_header_lib_headers: [
- "libbase_headers",
- "libcutils_headers",
"liblog_headers",
- "libprocessgroup_headers",
"libsystem_headers",
+ "libcutils_headers",
+ "libprocessgroup_headers",
],
export_include_dirs: ["include"],
@@ -48,11 +46,13 @@ cc_library_headers {
header_libs: ["libbacktrace_headers"],
export_header_lib_headers: ["libbacktrace_headers"],
},
- host_linux: {
+ linux_glibc: {
header_libs: ["libbacktrace_headers"],
export_header_lib_headers: ["libbacktrace_headers"],
},
linux_bionic: {
+ header_libs: ["libbacktrace_headers"],
+ export_header_lib_headers: ["libbacktrace_headers"],
enabled: true,
},
windows: {
@@ -76,7 +76,6 @@ cc_defaults {
"-Wall",
"-Werror",
"-Wno-exit-time-destructors",
- "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
header_libs: [
"libbase_headers",
@@ -99,6 +98,8 @@ cc_defaults {
cflags: ["-fvisibility=protected"],
shared_libs: [
+ "libprocessgroup",
+ "libdl",
"libvndksupport",
],
@@ -129,9 +130,6 @@ cc_defaults {
enabled: true,
},
},
- fuzz_config: {
- cc: ["smoreland@google.com"],
- },
}
cc_library {
@@ -180,12 +178,6 @@ cc_library {
"//apex_available:platform",
],
min_sdk_version: "apex_inherit",
-
- afdo: true,
-
- header_abi_checker: {
- diff_flags: ["-allow-adding-removing-weak-symbols"],
- },
}
cc_library {
@@ -193,7 +185,6 @@ cc_library {
defaults: ["libutils_defaults"],
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
- min_sdk_version: "29",
srcs: [
"CallStack.cpp",
@@ -307,14 +298,13 @@ cc_test {
srcs: [
"BitSet_test.cpp",
- "Errors_test.cpp",
"FileMap_test.cpp",
"LruCache_test.cpp",
"Mutex_test.cpp",
"SharedBuffer_test.cpp",
"Singleton_test.cpp",
- "String16_test.cpp",
"String8_test.cpp",
+ "String16_test.cpp",
"StrongPointer_test.cpp",
"Timers_test.cpp",
"Unicode_test.cpp",
@@ -373,7 +363,6 @@ cc_test_library {
"-Wall",
"-Werror",
],
- header_libs: ["libutils_headers"],
}
cc_test_library {
@@ -386,7 +375,6 @@ cc_test_library {
"-Werror",
],
shared_libs: ["libutils_test_singleton1"],
- header_libs: ["libutils_headers"],
}
cc_benchmark {
diff --git a/libutils/Errors_test.cpp b/libutils/Errors_test.cpp
deleted file mode 100644
index 0d13bb03c..000000000
--- a/libutils/Errors_test.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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 "utils/ErrorsMacros.h"
-
-#include <android-base/result.h>
-
-#include <gtest/gtest.h>
-
-using namespace android;
-
-using android::base::Error;
-using android::base::Result;
-
-status_t success_or_fail(bool success) {
- if (success)
- return OK;
- else
- return PERMISSION_DENIED;
-}
-
-TEST(errors, unwrap_or_return) {
- auto f = [](bool success, int* val) -> status_t {
- OR_RETURN(success_or_fail(success));
- *val = 10;
- return OK;
- };
-
- int val;
- status_t s = f(true, &val);
- EXPECT_EQ(OK, s);
- EXPECT_EQ(10, val);
-
- val = 0; // reset
- status_t q = f(false, &val);
- EXPECT_EQ(PERMISSION_DENIED, q);
- EXPECT_EQ(0, val);
-}
-
-TEST(errors, unwrap_or_return_result) {
- auto f = [](bool success) -> Result<std::string, StatusT> {
- OR_RETURN(success_or_fail(success));
- return "hello";
- };
-
- auto r = f(true);
- EXPECT_TRUE(r.ok());
- EXPECT_EQ("hello", *r);
-
- auto s = f(false);
- EXPECT_FALSE(s.ok());
- EXPECT_EQ(PERMISSION_DENIED, s.error().code());
- EXPECT_EQ("PERMISSION_DENIED", s.error().message());
-}
-
-TEST(errors, unwrap_or_return_result_int) {
- auto f = [](bool success) -> Result<int, StatusT> {
- OR_RETURN(success_or_fail(success));
- return 10;
- };
-
- auto r = f(true);
- EXPECT_TRUE(r.ok());
- EXPECT_EQ(10, *r);
-
- auto s = f(false);
- EXPECT_FALSE(s.ok());
- EXPECT_EQ(PERMISSION_DENIED, s.error().code());
- EXPECT_EQ("PERMISSION_DENIED", s.error().message());
-}
-
-TEST(errors, unwrap_or_fatal) {
- OR_FATAL(success_or_fail(true));
-
- EXPECT_DEATH(OR_FATAL(success_or_fail(false)), "PERMISSION_DENIED");
-}
-
-TEST(errors, result_in_status) {
- auto f = [](bool success) -> Result<std::string, StatusT> {
- if (success)
- return "OK";
- else
- return Error<StatusT>(PERMISSION_DENIED) << "custom error message";
- };
-
- auto g = [&](bool success) -> status_t {
- std::string val = OR_RETURN(f(success));
- EXPECT_EQ("OK", val);
- return OK;
- };
-
- status_t a = g(true);
- EXPECT_EQ(OK, a);
-
- status_t b = g(false);
- EXPECT_EQ(PERMISSION_DENIED, b);
-}
-
-TEST(errors, conversion_promotion) {
- constexpr size_t successVal = 10ull;
- auto f = [&](bool success) -> Result<size_t, StatusT> {
- OR_RETURN(success_or_fail(success));
- return successVal;
- };
- auto s = f(true);
- ASSERT_TRUE(s.ok());
- EXPECT_EQ(s.value(), successVal);
- auto r = f(false);
- EXPECT_TRUE(!r.ok());
- EXPECT_EQ(PERMISSION_DENIED, r.error().code());
-}
-
-TEST(errors, conversion_promotion_bool) {
- constexpr size_t successVal = true;
- auto f = [&](bool success) -> Result<bool, StatusT> {
- OR_RETURN(success_or_fail(success));
- return successVal;
- };
- auto s = f(true);
- ASSERT_TRUE(s.ok());
- EXPECT_EQ(s.value(), successVal);
- auto r = f(false);
- EXPECT_TRUE(!r.ok());
- EXPECT_EQ(PERMISSION_DENIED, r.error().code());
-}
-
-TEST(errors, conversion_promotion_char) {
- constexpr char successVal = 'a';
- auto f = [&](bool success) -> Result<unsigned char, StatusT> {
- OR_RETURN(success_or_fail(success));
- return successVal;
- };
- auto s = f(true);
- ASSERT_TRUE(s.ok());
- EXPECT_EQ(s.value(), successVal);
- auto r = f(false);
- EXPECT_TRUE(!r.ok());
- EXPECT_EQ(PERMISSION_DENIED, r.error().code());
-}
-
-struct IntContainer {
- // Implicit conversion from int is desired
- IntContainer(int val) : val_(val) {}
- int val_;
-};
-
-TEST(errors, conversion_construct) {
- constexpr int successVal = 10;
- auto f = [&](bool success) -> Result<IntContainer, StatusT> {
- OR_RETURN(success_or_fail(success));
- return successVal;
- };
- auto s = f(true);
- ASSERT_TRUE(s.ok());
- EXPECT_EQ(s.value().val_, successVal);
- auto r = f(false);
- EXPECT_TRUE(!r.ok());
- EXPECT_EQ(PERMISSION_DENIED, r.error().code());
-}
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 1a3f34bed..14e3e35c7 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -20,16 +20,6 @@
namespace android {
-namespace {
-
-constexpr uint64_t WAKE_EVENT_FD_SEQ = 1;
-
-epoll_event createEpollEvent(uint32_t events, uint64_t seq) {
- return {.events = events, .data = {.u64 = seq}};
-}
-
-} // namespace
-
// --- WeakMessageHandler ---
WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) :
@@ -74,7 +64,7 @@ Looper::Looper(bool allowNonCallbacks)
mSendingMessage(false),
mPolling(false),
mEpollRebuildRequired(false),
- mNextRequestSeq(WAKE_EVENT_FD_SEQ + 1),
+ mNextRequestSeq(0),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
@@ -117,15 +107,14 @@ sp<Looper> Looper::getForThread() {
int result = pthread_once(& gTLSOnce, initTLSKey);
LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
- Looper* looper = (Looper*)pthread_getspecific(gTLSKey);
- return sp<Looper>::fromExisting(looper);
+ return (Looper*)pthread_getspecific(gTLSKey);
}
sp<Looper> Looper::prepare(int opts) {
bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
sp<Looper> looper = Looper::getForThread();
if (looper == nullptr) {
- looper = sp<Looper>::make(allowNonCallbacks);
+ looper = new Looper(allowNonCallbacks);
Looper::setForThread(looper);
}
if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
@@ -148,17 +137,22 @@ void Looper::rebuildEpollLocked() {
mEpollFd.reset();
}
- // Allocate the new epoll instance and register the WakeEventFd.
+ // Allocate the new epoll instance and register the wake pipe.
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
- epoll_event wakeEvent = createEpollEvent(EPOLLIN, WAKE_EVENT_FD_SEQ);
- int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &wakeEvent);
+ struct epoll_event eventItem;
+ memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+ eventItem.events = EPOLLIN;
+ eventItem.data.fd = mWakeEventFd.get();
+ int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
strerror(errno));
- for (const auto& [seq, request] : mRequests) {
- epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);
+ for (size_t i = 0; i < mRequests.size(); i++) {
+ const Request& request = mRequests.valueAt(i);
+ struct epoll_event eventItem;
+ request.initEventItem(&eventItem);
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
if (epollResult < 0) {
@@ -282,28 +276,26 @@ int Looper::pollInner(int timeoutMillis) {
#endif
for (int i = 0; i < eventCount; i++) {
- const SequenceNumber seq = eventItems[i].data.u64;
+ int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
- if (seq == WAKE_EVENT_FD_SEQ) {
+ if (fd == mWakeEventFd.get()) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
- const auto& request_it = mRequests.find(seq);
- if (request_it != mRequests.end()) {
- const auto& request = request_it->second;
+ ssize_t requestIndex = mRequests.indexOfKey(fd);
+ if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
- mResponses.push({.seq = seq, .events = events, .request = request});
+ pushResponse(events, mRequests.valueAt(requestIndex));
} else {
- ALOGW("Ignoring unexpected epoll events 0x%x for sequence number %" PRIu64
- " that is no longer registered.",
- epollEvents, seq);
+ ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
+ "no longer registered.", epollEvents, fd);
}
}
}
@@ -362,8 +354,7 @@ Done: ;
// we need to be a little careful when removing the file descriptor afterwards.
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
- AutoMutex _l(mLock);
- removeSequenceNumberLocked(response.seq);
+ removeFd(fd, response.request.seq);
}
// Clear the callback reference in the response structure promptly because we
@@ -425,12 +416,15 @@ void Looper::awoken() {
TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
}
+void Looper::pushResponse(int events, const Request& request) {
+ Response response;
+ response.events = events;
+ response.request = request;
+ mResponses.push(response);
+}
+
int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
- sp<SimpleLooperCallback> looperCallback;
- if (callback) {
- looperCallback = sp<SimpleLooperCallback>::make(callback);
- }
- return addFd(fd, ident, events, looperCallback, data);
+ return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : nullptr, data);
}
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
@@ -455,27 +449,27 @@ int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callb
{ // acquire lock
AutoMutex _l(mLock);
- // There is a sequence number reserved for the WakeEventFd.
- if (mNextRequestSeq == WAKE_EVENT_FD_SEQ) mNextRequestSeq++;
- const SequenceNumber seq = mNextRequestSeq++;
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
+ request.seq = mNextRequestSeq++;
request.callback = callback;
request.data = data;
+ if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
- epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);
- auto seq_it = mSequenceNumberByFd.find(fd);
- if (seq_it == mSequenceNumberByFd.end()) {
+ struct epoll_event eventItem;
+ request.initEventItem(&eventItem);
+
+ ssize_t requestIndex = mRequests.indexOfKey(fd);
+ if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
return -1;
}
- mRequests.emplace(seq, request);
- mSequenceNumberByFd.emplace(fd, seq);
+ mRequests.add(fd, request);
} else {
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
if (epollResult < 0) {
@@ -492,7 +486,7 @@ int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callb
// set from scratch because it may contain an old file handle that we are
// now unable to remove since its file descriptor is no longer valid.
// No such problem would have occurred if we were using the poll system
- // call instead, but that approach carries other disadvantages.
+ // call instead, but that approach carries others disadvantages.
#if DEBUG_CALLBACKS
ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
"being recycled, falling back on EPOLL_CTL_ADD: %s",
@@ -510,69 +504,71 @@ int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callb
return -1;
}
}
- const SequenceNumber oldSeq = seq_it->second;
- mRequests.erase(oldSeq);
- mRequests.emplace(seq, request);
- seq_it->second = seq;
+ mRequests.replaceValueAt(requestIndex, request);
}
} // release lock
return 1;
}
int Looper::removeFd(int fd) {
- AutoMutex _l(mLock);
- const auto& it = mSequenceNumberByFd.find(fd);
- if (it == mSequenceNumberByFd.end()) {
- return 0;
- }
- return removeSequenceNumberLocked(it->second);
+ return removeFd(fd, -1);
}
-int Looper::removeSequenceNumberLocked(SequenceNumber seq) {
+int Looper::removeFd(int fd, int seq) {
#if DEBUG_CALLBACKS
- ALOGD("%p ~ removeFd - fd=%d, seq=%u", this, fd, seq);
+ ALOGD("%p ~ removeFd - fd=%d, seq=%d", this, fd, seq);
#endif
- const auto& request_it = mRequests.find(seq);
- if (request_it == mRequests.end()) {
- return 0;
- }
- const int fd = request_it->second.fd;
-
- // Always remove the FD from the request map even if an error occurs while
- // updating the epoll set so that we avoid accidentally leaking callbacks.
- mRequests.erase(request_it);
- mSequenceNumberByFd.erase(fd);
-
- int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_DEL, fd, nullptr);
- if (epollResult < 0) {
- if (errno == EBADF || errno == ENOENT) {
- // Tolerate EBADF or ENOENT because it means that the file descriptor was closed
- // before its callback was unregistered. This error may occur naturally when a
- // callback has the side-effect of closing the file descriptor before returning and
- // unregistering itself.
- //
- // Unfortunately due to kernel limitations we need to rebuild the epoll
- // set from scratch because it may contain an old file handle that we are
- // now unable to remove since its file descriptor is no longer valid.
- // No such problem would have occurred if we were using the poll system
- // call instead, but that approach carries other disadvantages.
+ { // acquire lock
+ AutoMutex _l(mLock);
+ ssize_t requestIndex = mRequests.indexOfKey(fd);
+ if (requestIndex < 0) {
+ return 0;
+ }
+
+ // Check the sequence number if one was given.
+ if (seq != -1 && mRequests.valueAt(requestIndex).seq != seq) {
#if DEBUG_CALLBACKS
- ALOGD("%p ~ removeFd - EPOLL_CTL_DEL failed due to file descriptor "
- "being closed: %s",
- this, strerror(errno));
+ ALOGD("%p ~ removeFd - sequence number mismatch, oldSeq=%d",
+ this, mRequests.valueAt(requestIndex).seq);
#endif
- scheduleEpollRebuildLocked();
- } else {
- // Some other error occurred. This is really weird because it means
- // our list of callbacks got out of sync with the epoll set somehow.
- // We defensively rebuild the epoll set to avoid getting spurious
- // notifications with nowhere to go.
- ALOGE("Error removing epoll events for fd %d: %s", fd, strerror(errno));
- scheduleEpollRebuildLocked();
- return -1;
+ return 0;
}
- }
+
+ // Always remove the FD from the request map even if an error occurs while
+ // updating the epoll set so that we avoid accidentally leaking callbacks.
+ mRequests.removeItemsAt(requestIndex);
+
+ int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_DEL, fd, nullptr);
+ if (epollResult < 0) {
+ if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
+ // Tolerate EBADF or ENOENT when the sequence number is known because it
+ // means that the file descriptor was closed before its callback was
+ // unregistered. This error may occur naturally when a callback has the
+ // side-effect of closing the file descriptor before returning and
+ // unregistering itself.
+ //
+ // Unfortunately due to kernel limitations we need to rebuild the epoll
+ // set from scratch because it may contain an old file handle that we are
+ // now unable to remove since its file descriptor is no longer valid.
+ // No such problem would have occurred if we were using the poll system
+ // call instead, but that approach carries others disadvantages.
+#if DEBUG_CALLBACKS
+ ALOGD("%p ~ removeFd - EPOLL_CTL_DEL failed due to file descriptor "
+ "being closed: %s", this, strerror(errno));
+#endif
+ scheduleEpollRebuildLocked();
+ } else {
+ // Some other error occurred. This is really weird because it means
+ // our list of callbacks got out of sync with the epoll set somehow.
+ // We defensively rebuild the epoll set to avoid getting spurious
+ // notifications with nowhere to go.
+ ALOGE("Error removing epoll events for fd %d: %s", fd, strerror(errno));
+ scheduleEpollRebuildLocked();
+ return -1;
+ }
+ }
+ } // release lock
return 1;
}
@@ -660,11 +656,14 @@ bool Looper::isPolling() const {
return mPolling;
}
-uint32_t Looper::Request::getEpollEvents() const {
- uint32_t epollEvents = 0;
+void Looper::Request::initEventItem(struct epoll_event* eventItem) const {
+ int epollEvents = 0;
if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
- return epollEvents;
+
+ memset(eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+ eventItem->events = epollEvents;
+ eventItem->data.fd = fd;
}
MessageHandler::~MessageHandler() { }
diff --git a/libutils/Looper_test.cpp b/libutils/Looper_test.cpp
index c859f9c61..34f424b83 100644
--- a/libutils/Looper_test.cpp
+++ b/libutils/Looper_test.cpp
@@ -8,9 +8,6 @@
#include <utils/Looper.h>
#include <utils/StopWatch.h>
#include <utils/Timers.h>
-#include <thread>
-#include <unordered_map>
-#include <utility>
#include "Looper_test_pipe.h"
#include <utils/threads.h>
@@ -713,123 +710,4 @@ TEST_F(LooperTest, RemoveMessage_WhenRemovingSomeMessagesForHandler_ShouldRemove
<< "no more messages to handle";
}
-class LooperEventCallback : public LooperCallback {
- public:
- using Callback = std::function<int(int fd, int events)>;
- explicit LooperEventCallback(Callback callback) : mCallback(std::move(callback)) {}
- int handleEvent(int fd, int events, void* /*data*/) override { return mCallback(fd, events); }
-
- private:
- Callback mCallback;
-};
-
-// A utility class that allows for pipes to be added and removed from the looper, and polls the
-// looper from a different thread.
-class ThreadedLooperUtil {
- public:
- explicit ThreadedLooperUtil(const sp<Looper>& looper) : mLooper(looper), mRunning(true) {
- mThread = std::thread([this]() {
- while (mRunning) {
- static constexpr std::chrono::milliseconds POLL_TIMEOUT(500);
- mLooper->pollOnce(POLL_TIMEOUT.count());
- }
- });
- }
-
- ~ThreadedLooperUtil() {
- mRunning = false;
- mThread.join();
- }
-
- // Create a new pipe, and return the write end of the pipe and the id used to track the pipe.
- // The read end of the pipe is added to the looper.
- std::pair<int /*id*/, base::unique_fd> createPipe() {
- int pipeFd[2];
- if (pipe(pipeFd)) {
- ADD_FAILURE() << "pipe() failed.";
- return {};
- }
- const int readFd = pipeFd[0];
- const int writeFd = pipeFd[1];
-
- int id;
- { // acquire lock
- std::scoped_lock l(mLock);
-
- id = mNextId++;
- mFds.emplace(id, readFd);
-
- auto removeCallback = [this, id, readFd](int fd, int events) {
- EXPECT_EQ(readFd, fd) << "Received callback for incorrect fd.";
- if ((events & Looper::EVENT_HANGUP) == 0) {
- return 1; // Not a hangup, keep the callback.
- }
- removePipe(id);
- return 0; // Remove the callback.
- };
-
- mLooper->addFd(readFd, 0, Looper::EVENT_INPUT,
- new LooperEventCallback(std::move(removeCallback)), nullptr);
- } // release lock
-
- return {id, base::unique_fd(writeFd)};
- }
-
- // Remove the pipe with the given id.
- void removePipe(int id) {
- std::scoped_lock l(mLock);
- if (mFds.find(id) == mFds.end()) {
- return;
- }
- mLooper->removeFd(mFds[id].get());
- mFds.erase(id);
- }
-
- // Check if the pipe with the given id exists and has not been removed.
- bool hasPipe(int id) {
- std::scoped_lock l(mLock);
- return mFds.find(id) != mFds.end();
- }
-
- private:
- sp<Looper> mLooper;
- std::atomic<bool> mRunning;
- std::thread mThread;
-
- std::mutex mLock;
- std::unordered_map<int, base::unique_fd> mFds GUARDED_BY(mLock);
- int mNextId GUARDED_BY(mLock) = 0;
-};
-
-TEST_F(LooperTest, MultiThreaded_NoUnexpectedFdRemoval) {
- ThreadedLooperUtil util(mLooper);
-
- // Iterate repeatedly to try to recreate a flaky instance.
- for (int i = 0; i < 1000; i++) {
- auto [firstPipeId, firstPipeFd] = util.createPipe();
- const int firstFdNumber = firstPipeFd.get();
-
- // Close the first pipe's fd, causing a fd hangup.
- firstPipeFd.reset();
-
- // Request to remove the pipe from this test thread. This causes a race for pipe removal
- // between the hangup in the looper's thread and this remove request from the test thread.
- util.removePipe(firstPipeId);
-
- // Create the second pipe. Since the fds for the first pipe are closed, this pipe should
- // have the same fd numbers as the first pipe because the lowest unused fd number is used.
- const auto [secondPipeId, fd] = util.createPipe();
- EXPECT_EQ(firstFdNumber, fd.get())
- << "The first and second fds must match for the purposes of this test.";
-
- // Wait for unexpected hangup to occur.
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
-
- ASSERT_TRUE(util.hasPipe(secondPipeId)) << "The second pipe was removed unexpectedly.";
-
- util.removePipe(secondPipeId);
- }
- SUCCEED() << "No unexpectedly removed fds.";
-}
-
} // namespace android
diff --git a/libutils/LruCache_test.cpp b/libutils/LruCache_test.cpp
index 8b16947be..c4d917b40 100644
--- a/libutils/LruCache_test.cpp
+++ b/libutils/LruCache_test.cpp
@@ -298,8 +298,8 @@ TEST_F(LruCacheTest, ClearReuseOk) {
}
TEST_F(LruCacheTest, Callback) {
- EntryRemovedCallback callback;
LruCache<SimpleKey, StringValue> cache(100);
+ EntryRemovedCallback callback;
cache.setOnEntryRemovedListener(&callback);
cache.put(1, "one");
@@ -313,8 +313,8 @@ TEST_F(LruCacheTest, Callback) {
}
TEST_F(LruCacheTest, CallbackOnClear) {
- EntryRemovedCallback callback;
LruCache<SimpleKey, StringValue> cache(100);
+ EntryRemovedCallback callback;
cache.setOnEntryRemovedListener(&callback);
cache.put(1, "one");
@@ -326,8 +326,8 @@ TEST_F(LruCacheTest, CallbackOnClear) {
}
TEST_F(LruCacheTest, CallbackRemovesKeyWorksOK) {
- InvalidateKeyCallback callback;
LruCache<KeyWithPointer, StringValue> cache(1);
+ InvalidateKeyCallback callback;
cache.setOnEntryRemovedListener(&callback);
KeyWithPointer key1;
key1.ptr = new int(1);
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
index 819a60352..d437a9fc9 100644
--- a/libutils/NativeHandle.cpp
+++ b/libutils/NativeHandle.cpp
@@ -20,7 +20,7 @@
namespace android {
sp<NativeHandle> NativeHandle::create(native_handle_t* handle, bool ownsHandle) {
- return handle ? sp<NativeHandle>::make(handle, ownsHandle) : nullptr;
+ return handle ? new NativeHandle(handle, ownsHandle) : nullptr;
}
NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 4ddac3d2e..b57e28741 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -50,7 +50,12 @@
// log all reference counting operations
#define PRINT_REFS 0
-#if defined(__linux__)
+// Continue after logging a stack trace if ~RefBase discovers that reference
+// count has never been incremented. Normally we conspicuously crash in that
+// case.
+#define DEBUG_REFBASE_DESTRUCTION 1
+
+#if !defined(_WIN32) && !defined(__APPLE__)
// CallStack is only supported on linux type platforms.
#define CALLSTACK_ENABLED 1
#else
@@ -165,7 +170,7 @@ public:
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
- , mFlags(OBJECT_LIFETIME_STRONG)
+ , mFlags(0)
{
}
@@ -184,7 +189,7 @@ public:
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
- , mFlags(OBJECT_LIFETIME_STRONG)
+ , mFlags(0)
, mStrongRefs(NULL)
, mWeakRefs(NULL)
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
@@ -746,19 +751,17 @@ RefBase::~RefBase()
}
} else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
// We never acquired a strong reference on this object.
-
- // TODO: make this fatal, but too much code in Android manages RefBase with
- // new/delete manually (or using other mechanisms such as std::make_unique).
- // However, this is dangerous because it's also common for code to use the
- // sp<T>(T*) constructor, assuming that if the object is around, it is already
- // owned by an sp<>.
- ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
- "object.",
- mRefs->mWeak.load(), this);
+#if DEBUG_REFBASE_DESTRUCTION
+ // Treating this as fatal is prone to causing boot loops. For debugging, it's
+ // better to treat as non-fatal.
+ ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
+#else
+ LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
+#endif
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
const_cast<weakref_impl*&>(mRefs) = nullptr;
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 68642d84f..d08b212fd 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -96,12 +96,6 @@ String16::String16(const String16& o)
acquire();
}
-String16::String16(String16&& o) noexcept
- : mString(o.mString)
-{
- o.mString = getEmptyString();
-}
-
String16::String16(const String16& o, size_t len, size_t begin)
: mString(getEmptyString())
{
@@ -132,13 +126,6 @@ String16::~String16()
release();
}
-String16& String16::operator=(String16&& other) noexcept {
- release();
- mString = other.mString;
- other.mString = getEmptyString();
- return *this;
-}
-
size_t String16::size() const
{
if (isStaticString()) {
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
index c6e6f746a..c4783211f 100644
--- a/libutils/String16_test.cpp
+++ b/libutils/String16_test.cpp
@@ -58,27 +58,12 @@ TEST(String16Test, Copy) {
EXPECT_STR16EQ(u"Verify me", another);
}
-TEST(String16Test, CopyAssign) {
- String16 tmp("Verify me");
- String16 another;
- another = tmp;
- EXPECT_STR16EQ(u"Verify me", tmp);
- EXPECT_STR16EQ(u"Verify me", another);
-}
-
TEST(String16Test, Move) {
String16 tmp("Verify me");
String16 another(std::move(tmp));
EXPECT_STR16EQ(u"Verify me", another);
}
-TEST(String16Test, MoveAssign) {
- String16 tmp("Verify me");
- String16 another;
- another = std::move(tmp);
- EXPECT_STR16EQ(u"Verify me", another);
-}
-
TEST(String16Test, Size) {
String16 tmp("Verify me");
EXPECT_EQ(9U, tmp.size());
@@ -189,22 +174,10 @@ TEST(String16Test, StringSetToStaticString) {
EXPECT_STR16EQ(u"Verify me", another);
}
-TEST(String16Test, StringCopyAssignFromStaticString) {
- StaticString16 tmp(u"Verify me");
- String16 another(u"nonstatic");
- another = tmp;
- EXPECT_STR16EQ(u"Verify me", another);
- EXPECT_TRUE(another.isStaticString());
- EXPECT_STR16EQ(u"Verify me", tmp);
- EXPECT_TRUE(tmp.isStaticString());
-}
-
-TEST(String16Test, StringMoveAssignFromStaticString) {
+TEST(String16Test, StringMoveFromStaticString) {
StaticString16 tmp(u"Verify me");
- String16 another(u"nonstatic");
- another = std::move(tmp);
+ String16 another(std::move(tmp));
EXPECT_STR16EQ(u"Verify me", another);
- EXPECT_TRUE(another.isStaticString());
}
TEST(String16Test, EmptyStringIsStatic) {
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 369038901..b391b1a18 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -313,7 +313,7 @@ status_t String8::appendFormatV(const char* fmt, va_list args)
if (n > 0) {
size_t oldLength = length();
- if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
+ if (n > std::numeric_limits<size_t>::max() - 1 ||
oldLength > std::numeric_limits<size_t>::max() - n - 1) {
return NO_MEMORY;
}
@@ -431,17 +431,24 @@ void String8::toLower()
// ---------------------------------------------------------------------------
// Path functions
-static void setPathName(String8& s, const char* name) {
- size_t len = strlen(name);
- char* buf = s.lockBuffer(len);
+void String8::setPathName(const char* name)
+{
+ setPathName(name, strlen(name));
+}
+
+void String8::setPathName(const char* name, size_t len)
+{
+ char* buf = lockBuffer(len);
memcpy(buf, name, len);
// remove trailing path separator, if present
- if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
+ if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
+ len--;
+
buf[len] = '\0';
- s.unlockBuffer(len);
+ unlockBuffer(len);
}
String8 String8::getPathLeaf(void) const
@@ -554,7 +561,7 @@ String8& String8::appendPath(const char* name)
size_t len = length();
if (len == 0) {
// no existing filename, just use the new one
- setPathName(*this, name);
+ setPathName(name);
return *this;
}
@@ -574,7 +581,7 @@ String8& String8::appendPath(const char* name)
return *this;
} else {
- setPathName(*this, name);
+ setPathName(name);
return *this;
}
}
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index faf49b66b..a45d67514 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -91,6 +91,10 @@ std::vector<std::function<void(FuzzedDataProvider*, android::String8*, android::
},
[](FuzzedDataProvider* dataProvider, android::String8* str1,
android::String8*) -> void {
+ str1->setPathName(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
+ },
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8*) -> void {
str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
},
};
diff --git a/libutils/TEST_MAPPING b/libutils/TEST_MAPPING
deleted file mode 100644
index c8ef45cc3..000000000
--- a/libutils/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "libutils_test"
- }
- ]
-}
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index e756fecca..540dcf49d 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -84,6 +84,12 @@ struct thread_data_t {
delete t;
setpriority(PRIO_PROCESS, 0, prio);
+ // A new thread will be in its parent's sched group by default,
+ // so we just need to handle the background case.
+ if (prio >= ANDROID_PRIORITY_BACKGROUND) {
+ SetTaskProfiles(0, {"SCHED_SP_BACKGROUND"}, true);
+ }
+
if (name) {
androidSetThreadName(name);
free(name);
@@ -299,16 +305,30 @@ void androidSetCreateThreadFunc(android_create_thread_fn func)
int androidSetThreadPriority(pid_t tid, int pri)
{
int rc = 0;
+ int lasterr = 0;
int curr_pri = getpriority(PRIO_PROCESS, tid);
if (curr_pri == pri) {
return rc;
}
+ if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+ rc = SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
+ } else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
+ SchedPolicy policy = SP_FOREGROUND;
+ // Change to the sched policy group of the process.
+ get_sched_policy(getpid(), &policy);
+ rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
+ }
+
+ if (rc) {
+ lasterr = errno;
+ }
+
if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
rc = INVALID_OPERATION;
} else {
- errno = 0;
+ errno = lasterr;
}
return rc;
@@ -673,7 +693,7 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack)
mThread = thread_id_t(-1);
// hold a strong reference on ourself
- mHoldSelf = sp<Thread>::fromExisting(this);
+ mHoldSelf = this;
mRunning = true;
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index 4cfac57be..fd3f4a957 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+//
+// Timer functions.
+//
#include <utils/Timers.h>
#include <limits.h>
@@ -21,12 +24,11 @@
#include <time.h>
#include <android-base/macros.h>
-#include <utils/Log.h>
static constexpr size_t clock_id_max = 5;
static void checkClockId(int clock) {
- LOG_ALWAYS_FATAL_IF(clock < 0 || clock >= clock_id_max, "invalid clock id");
+ if (clock < 0 || clock >= clock_id_max) abort();
}
#if defined(__linux__)
@@ -54,10 +56,18 @@ nsecs_t systemTime(int clock) {
}
#endif
-int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) {
- if (timeoutTime <= referenceTime) return 0;
-
- uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
- if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) return -1;
- return (timeoutDelay + 999999LL) / 1000000LL;
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
+{
+ nsecs_t timeoutDelayMillis;
+ if (timeoutTime > referenceTime) {
+ uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+ if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+ timeoutDelayMillis = -1;
+ } else {
+ timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+ }
+ } else {
+ timeoutDelayMillis = 0;
+ }
+ return (int)timeoutDelayMillis;
}
diff --git a/libutils/Timers_test.cpp b/libutils/Timers_test.cpp
index c0a6d4997..ec0051e67 100644
--- a/libutils/Timers_test.cpp
+++ b/libutils/Timers_test.cpp
@@ -27,12 +27,3 @@ TEST(Timers, systemTime_invalid) {
systemTime(SYSTEM_TIME_BOOTTIME);
EXPECT_EXIT(systemTime(SYSTEM_TIME_BOOTTIME + 1), testing::KilledBySignal(SIGABRT), "");
}
-
-TEST(Timers, toMillisecondTimeoutDelay) {
- EXPECT_EQ(0, toMillisecondTimeoutDelay(100, 100));
- EXPECT_EQ(0, toMillisecondTimeoutDelay(100, 10));
-
- EXPECT_EQ(-1, toMillisecondTimeoutDelay(0, INT_MAX * 1000000LL));
-
- EXPECT_EQ(123, toMillisecondTimeoutDelay(0, 123000000));
-}
diff --git a/libutils/Unicode_test.cpp b/libutils/Unicode_test.cpp
index 8b994d9af..b92eef866 100644
--- a/libutils/Unicode_test.cpp
+++ b/libutils/Unicode_test.cpp
@@ -100,7 +100,7 @@ TEST_F(UnicodeTest, UTF8toUTF16Normal) {
0xF0, 0x90, 0x80, 0x80, // U+10000, 2 UTF-16 character
};
- char16_t output[1 + 1 + 1 + 2 + 1]; // Room for null
+ char16_t output[1 + 1 + 1 + 2 + 1]; // Room for NULL
utf8_to_utf16(str, sizeof(str), output, sizeof(output) / sizeof(output[0]));
@@ -114,7 +114,8 @@ TEST_F(UnicodeTest, UTF8toUTF16Normal) {
<< "should be first half of surrogate U+10000";
EXPECT_EQ(0xDC00, output[4])
<< "should be second half of surrogate U+10000";
- EXPECT_EQ(0, output[5]) << "should be null terminated";
+ EXPECT_EQ(NULL, output[5])
+ << "should be NULL terminated";
}
TEST_F(UnicodeTest, strstr16EmptyTarget) {
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index d951b8bbb..c97a19bc6 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -279,12 +279,14 @@ ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
{
- size_t end;
- LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(index, count, &end), "overflow: index=%zu count=%zu",
- index, count);
- if (end > size()) return BAD_VALUE;
- _shrink(index, count);
- return index;
+ ALOG_ASSERT((index+count)<=size(),
+ "[%p] remove: index=%d, count=%d, size=%d",
+ this, (int)index, (int)count, (int)size());
+
+ if ((index+count) > size())
+ return BAD_VALUE;
+ _shrink(index, count);
+ return index;
}
void VectorImpl::finish_vector()
diff --git a/libutils/Vector_test.cpp b/libutils/Vector_test.cpp
index 6d90eaa9e..5336c40c3 100644
--- a/libutils/Vector_test.cpp
+++ b/libutils/Vector_test.cpp
@@ -136,13 +136,4 @@ TEST_F(VectorTest, editArray_Shared) {
}
}
-TEST_F(VectorTest, removeItemsAt_overflow) {
- android::Vector<int> v;
- for (int i = 0; i < 666; i++) v.add(i);
-
- ASSERT_DEATH(v.removeItemsAt(SIZE_MAX, 666), "overflow");
- ASSERT_DEATH(v.removeItemsAt(666, SIZE_MAX), "overflow");
- ASSERT_DEATH(v.removeItemsAt(SIZE_MAX, SIZE_MAX), "overflow");
-}
-
} // namespace android
diff --git a/libutils/include/utils/Compat.h b/libutils/include/utils/Compat.h
index 3221899f7..60025678c 100644
--- a/libutils/include/utils/Compat.h
+++ b/libutils/include/utils/Compat.h
@@ -71,17 +71,19 @@ static inline int ftruncate64(int fd, off64_t length) {
#define CONSTEXPR
#endif
-/* TEMP_FAILURE_RETRY is not available on macOS, but still useful there. */
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
#ifndef TEMP_FAILURE_RETRY
/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) \
- ({ \
- __typeof__(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (_rc == -1 && errno == EINTR); \
- _rc; \
- })
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
#endif
#if defined(_WIN32)
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 22fb36d25..d14d2231d 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -34,13 +34,15 @@ typedef int32_t status_t;
* All error codes are negative values.
*/
+// Win32 #defines NO_ERROR as well. It has the same value, so there's no
+// real conflict, though it's a bit awkward.
+#ifdef _WIN32
+# undef NO_ERROR
+#endif
+
enum {
OK = 0, // Preferred constant for checking success.
-#ifndef NO_ERROR
- // Win32 #defines NO_ERROR as well. It has the same value, so there's no
- // real conflict, though it's a bit awkward.
NO_ERROR = OK, // Deprecated synonym for `OK`. Prefer `OK` because it doesn't conflict with Windows.
-#endif
UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
@@ -74,4 +76,10 @@ enum {
// Human readable name of error
std::string statusToString(status_t status);
+// Restore define; enumeration is in "android" namespace, so the value defined
+// there won't work for Win32 code in a different namespace.
+#ifdef _WIN32
+# define NO_ERROR 0L
+#endif
+
} // namespace android
diff --git a/libutils/include/utils/ErrorsMacros.h b/libutils/include/utils/ErrorsMacros.h
deleted file mode 100644
index fdc46e617..000000000
--- a/libutils/include/utils/ErrorsMacros.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Errors.h"
-
-// It would have been better if this file (ErrorsMacros.h) is entirely in utils/Errors.h. However
-// that is infeasible as some (actually many) are using utils/Errors.h via the implicit include path
-// `system/core/include` [1]. Since such users are not guaranteed to specify the dependency to
-// libbase_headers, the following headers from libbase_headers can't be found.
-// [1] build/soong/cc/config/global.go#commonGlobalIncludes
-#include <android-base/errors.h>
-#include <android-base/result.h>
-#include <log/log_main.h>
-
-#include <assert.h>
-
-namespace android {
-
-// StatusT is a wrapper class for status_t. Use this type instead of status_t when instantiating
-// Result<T, E> and Error<E> template classes. This is required to distinguish status_t from
-// other integer-based error code types like errno, and also to provide utility functions like
-// print().
-struct StatusT {
- StatusT() : val_(OK) {}
- StatusT(status_t s) : val_(s) {}
- const status_t& value() const { return val_; }
- operator status_t() const { return val_; }
- std::string print() const { return statusToString(val_); }
-
- status_t val_;
-};
-
-
-namespace base {
-// TODO(b/221235365) StatusT fulfill ResultError contract and cleanup.
-
-// Unlike typical ResultError types, the underlying code should be a status_t
-// instead of a StatusT. We also special-case message generation.
-template<>
-struct ResultError<StatusT, false> {
- ResultError(status_t s) : val_(s) {
- LOG_FATAL_IF(s == OK, "Result error should not hold success");
- }
-
- template <typename T>
- operator expected<T, ResultError<StatusT, false>>() const {
- return unexpected(*this);
- }
-
- std::string message() const { return statusToString(val_); }
- status_t code() const { return val_; }
-
- private:
- const status_t val_;
-};
-
-template<>
-struct ResultError<StatusT, true> {
- template <typename T>
- ResultError(T&& message, status_t s) : val_(s), message_(std::forward<T>(message)) {
- LOG_FATAL_IF(s == OK, "Result error should not hold success");
- }
-
- ResultError(status_t s) : val_(s) {}
-
- template <typename T>
- operator expected<T, ResultError<StatusT, true>>() const {
- return unexpected(*this);
- }
-
- status_t code() const { return val_; }
-
- std::string message() const { return statusToString(val_) + message_; }
- private:
- const status_t val_;
- std::string message_;
-};
-
-// Specialization of android::base::OkOrFail<V> for V = status_t. This is used to use the OR_RETURN
-// and OR_FATAL macros with statements that yields a value of status_t. See android-base/errors.h
-// for the detailed contract.
-template <>
-struct OkOrFail<status_t> {
- static_assert(std::is_same_v<status_t, int>);
- // Tests if status_t is a success value of not.
- static bool IsOk(const status_t& s) { return s == OK; }
-
- // Unwrapping status_t in the success case is just asserting that it is actually a success.
- // We don't return OK because it would be redundant.
- static void Unwrap([[maybe_unused]] status_t&& s) { assert(IsOk(s)); }
-
- // Consumes status_t when it's a fail value
- static OkOrFail<status_t> Fail(status_t&& s) {
- assert(!IsOk(s));
- return OkOrFail<status_t>{s};
- }
- status_t val_;
-
- // And converts back into status_t. This is used when OR_RETURN is used in a function whose
- // return type is status_t.
- operator status_t() && { return val_; }
-
- // Or converts into Result<T, StatusT>. This is used when OR_RETURN is used in a function whose
- // return type is Result<T, StatusT>.
-
- template <typename T>
- operator Result<T, StatusT>() && {
- return ResultError<StatusT>(std::move(val_));
- }
-
- template<typename T>
- operator Result<T, StatusT, false>() && {
- return ResultError<StatusT, false>(std::move(val_));
- }
-
- // Since user defined conversion can be followed by numeric conversion,
- // we have to specialize all conversions to results holding numeric types to
- // avoid conversion ambiguities with the constructor of expected.
-#pragma push_macro("SPECIALIZED_CONVERSION")
-#define SPECIALIZED_CONVERSION(type)\
- operator Result<type, StatusT>() && { return ResultError<StatusT>(std::move(val_)); }\
- operator Result<type, StatusT, false>() && { return ResultError<StatusT, false>(std::move(val_));}
-
- SPECIALIZED_CONVERSION(int)
- SPECIALIZED_CONVERSION(short int)
- SPECIALIZED_CONVERSION(unsigned short int)
- SPECIALIZED_CONVERSION(unsigned int)
- SPECIALIZED_CONVERSION(long int)
- SPECIALIZED_CONVERSION(unsigned long int)
- SPECIALIZED_CONVERSION(long long int)
- SPECIALIZED_CONVERSION(unsigned long long int)
- SPECIALIZED_CONVERSION(bool)
- SPECIALIZED_CONVERSION(char)
- SPECIALIZED_CONVERSION(unsigned char)
- SPECIALIZED_CONVERSION(signed char)
- SPECIALIZED_CONVERSION(wchar_t)
- SPECIALIZED_CONVERSION(char16_t)
- SPECIALIZED_CONVERSION(char32_t)
- SPECIALIZED_CONVERSION(float)
- SPECIALIZED_CONVERSION(double)
- SPECIALIZED_CONVERSION(long double)
-#undef SPECIALIZED_CONVERSION
-#pragma pop_macro("SPECIALIZED_CONVERSION")
- // String representation of the error value.
- static std::string ErrorMessage(const status_t& s) { return statusToString(s); }
-};
-} // namespace base
-
-
-// These conversions make StatusT directly comparable to status_t in order to
-// avoid calling code whenever comparisons are desired.
-
-template <bool include_message>
-bool operator==(const base::ResultError<StatusT, include_message>& l, const status_t& r) {
- return (l.code() == r);
-}
-template <bool include_message>
-bool operator==(const status_t& l, const base::ResultError<StatusT, include_message>& r) {
- return (l == r.code());
-}
-
-template <bool include_message>
-bool operator!=(const base::ResultError<StatusT, include_message>& l, const status_t& r) {
- return (l.code() != r);
-}
-template <bool include_message>
-bool operator!=(const status_t& l, const base::ResultError<StatusT, include_message>& r) {
- return (l != r.code());
-}
-
-} // namespace android
diff --git a/libutils/include/utils/Looper.h b/libutils/include/utils/Looper.h
index b387d68c6..466fbb726 100644
--- a/libutils/include/utils/Looper.h
+++ b/libutils/include/utils/Looper.h
@@ -17,16 +17,15 @@
#ifndef UTILS_LOOPER_H
#define UTILS_LOOPER_H
+#include <utils/threads.h>
#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
#include <utils/Timers.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
#include <sys/epoll.h>
#include <android-base/unique_fd.h>
-#include <unordered_map>
#include <utility>
namespace android {
@@ -422,20 +421,18 @@ public:
static sp<Looper> getForThread();
private:
- using SequenceNumber = uint64_t;
-
- struct Request {
- int fd;
- int ident;
- int events;
- sp<LooperCallback> callback;
- void* data;
+ struct Request {
+ int fd;
+ int ident;
+ int events;
+ int seq;
+ sp<LooperCallback> callback;
+ void* data;
- uint32_t getEpollEvents() const;
- };
+ void initEventItem(struct epoll_event* eventItem) const;
+ };
struct Response {
- SequenceNumber seq;
int events;
Request request;
};
@@ -466,14 +463,9 @@ private:
android::base::unique_fd mEpollFd; // guarded by mLock but only modified on the looper thread
bool mEpollRebuildRequired; // guarded by mLock
- // Locked maps of fds and sequence numbers monitoring requests.
- // Both maps must be kept in sync at all times.
- std::unordered_map<SequenceNumber, Request> mRequests; // guarded by mLock
- std::unordered_map<int /*fd*/, SequenceNumber> mSequenceNumberByFd; // guarded by mLock
-
- // The sequence number to use for the next fd that is added to the looper.
- // The sequence number 0 is reserved for the WakeEventFd.
- SequenceNumber mNextRequestSeq; // guarded by mLock
+ // Locked list of file descriptor monitoring requests.
+ KeyedVector<int, Request> mRequests; // guarded by mLock
+ int mNextRequestSeq;
// This state is only used privately by pollOnce and does not require a lock since
// it runs on a single thread.
@@ -482,8 +474,9 @@ private:
nsecs_t mNextMessageUptime; // set to LLONG_MAX when none
int pollInner(int timeoutMillis);
- int removeSequenceNumberLocked(SequenceNumber seq); // requires mLock
+ int removeFd(int fd, int seq);
void awoken();
+ void pushResponse(int events, const Request& request);
void rebuildEpollLocked();
void scheduleEpollRebuildLocked();
diff --git a/libutils/include/utils/NativeHandle.h b/libutils/include/utils/NativeHandle.h
index f26a1a4d9..73fe804cc 100644
--- a/libutils/include/utils/NativeHandle.h
+++ b/libutils/include/utils/NativeHandle.h
@@ -39,8 +39,6 @@ public:
private:
// for access to the destructor
friend class LightRefBase<NativeHandle>;
- // for access to the constructor
- friend class sp<NativeHandle>;
NativeHandle(native_handle_t* handle, bool ownsHandle);
~NativeHandle();
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 3ef56a3cf..60d523a4c 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -41,7 +41,6 @@ class String16
public:
String16();
String16(const String16& o);
- String16(String16&& o) noexcept;
String16(const String16& o,
size_t len,
size_t begin=0);
@@ -70,7 +69,6 @@ public:
status_t append(const char16_t* other, size_t len);
inline String16& operator=(const String16& other);
- String16& operator=(String16&& other) noexcept;
inline String16& operator+=(const String16& other);
inline String16 operator+(const String16& other) const;
@@ -174,6 +172,10 @@ protected:
template <size_t N>
explicit constexpr String16(const StaticData<N>& s) : mString(s.data) {}
+
+public:
+ template <size_t N>
+ explicit constexpr String16(const StaticString16<N>& s) : mString(s.mString) {}
};
// String16 can be trivially moved using memcpy() because moving does not
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 8b2dcf9a0..cee5dc640 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -137,6 +137,14 @@ public:
*/
/*
+ * Set the filename field to a specific value.
+ *
+ * Normalizes the filename, removing a trailing '/' if present.
+ */
+ void setPathName(const char* name);
+ void setPathName(const char* name, size_t numChars);
+
+ /*
* Get just the filename component.
*
* "/tmp/foo/bar.c" --> "bar.c"
diff --git a/libvndksupport/TEST_MAPPING b/libvndksupport/TEST_MAPPING
deleted file mode 100644
index c9b3b20be..000000000
--- a/libvndksupport/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "postsubmit": [
- {
- "name": "libvndksupport-tests"
- }
- ]
-}
diff --git a/libvndksupport/linker.cpp b/libvndksupport/linker.cpp
index ad4fb31ef..30b9c2e28 100644
--- a/libvndksupport/linker.cpp
+++ b/libvndksupport/linker.cpp
@@ -39,7 +39,7 @@ struct VendorNamespace {
static VendorNamespace get_vendor_namespace() {
static VendorNamespace result = ([] {
- for (const char* name : {"sphal", "vendor", "default"}) {
+ for (const char* name : {"sphal", "default"}) {
if (android_namespace_t* ns = android_get_exported_namespace(name)) {
return VendorNamespace{ns, name};
}
diff --git a/libvndksupport/tests/Android.bp b/libvndksupport/tests/Android.bp
index 015939501..ba700cbb9 100644
--- a/libvndksupport/tests/Android.bp
+++ b/libvndksupport/tests/Android.bp
@@ -31,6 +31,4 @@ cc_test {
"libvndksupport",
"libbase",
],
-
- test_suites: ["general-tests"],
}
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 42602e9ee..c4c58eef3 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -1283,7 +1283,8 @@ bool llkInit(const char* threadname) {
llkEnableSysrqT &= !llkLowRam;
if (debuggable) {
llkEnableSysrqT |= llkCheckEng(LLK_ENABLE_SYSRQ_T_PROPERTY);
- if (!LLK_ENABLE_DEFAULT) {
+ if (!LLK_ENABLE_DEFAULT) { // NB: default is currently true ...
+ llkEnable |= llkCheckEng(LLK_ENABLE_PROPERTY);
khtEnable |= llkCheckEng(KHT_ENABLE_PROPERTY);
}
}
diff --git a/llkd/llkd-debuggable.rc b/llkd/llkd-debuggable.rc
index 8355e9d96..4b11b1c7a 100644
--- a/llkd/llkd-debuggable.rc
+++ b/llkd/llkd-debuggable.rc
@@ -1,5 +1,5 @@
on property:ro.debuggable=1
- setprop llk.enable ${ro.llk.enable:-0}
+ setprop llk.enable ${ro.llk.enable:-1}
setprop khungtask.enable ${ro.khungtask.enable:-1}
on property:ro.llk.enable=eng
@@ -16,4 +16,4 @@ service llkd-1 /system/bin/llkd
capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE SYS_ADMIN
file /dev/kmsg w
file /proc/sysrq-trigger w
- task_profiles ServiceCapacityLow
+ writepid /dev/cpuset/system-background/tasks
diff --git a/llkd/llkd.rc b/llkd/llkd.rc
index 5d701fcc0..b1f96a8f3 100644
--- a/llkd/llkd.rc
+++ b/llkd/llkd.rc
@@ -42,4 +42,4 @@ service llkd-0 /system/bin/llkd
capabilities KILL IPC_LOCK
file /dev/kmsg w
file /proc/sysrq-trigger w
- task_profiles ServiceCapacityLow
+ writepid /dev/cpuset/system-background/tasks
diff --git a/llkd/tests/llkd_test.cpp b/llkd/tests/llkd_test.cpp
index 8eb9b001f..475512c38 100644
--- a/llkd/tests/llkd_test.cpp
+++ b/llkd/tests/llkd_test.cpp
@@ -69,9 +69,13 @@ void execute(const char* command) {
seconds llkdSleepPeriod(char state) {
auto default_eng = android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng";
auto default_enable = LLK_ENABLE_DEFAULT;
+ if (!LLK_ENABLE_DEFAULT && default_eng &&
+ android::base::GetBoolProperty("ro.debuggable", false)) {
+ default_enable = true;
+ }
default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
if (default_eng) {
- GTEST_LOG_INFO << LLK_ENABLE_PROPERTY " defaults to "
+ GTEST_LOG_INFO << LLK_ENABLE_PROPERTY " defaults to \"eng\" thus "
<< (default_enable ? "true" : "false") << "\n";
}
// Hail Mary hope is unconfigured.
@@ -104,6 +108,10 @@ seconds llkdSleepPeriod(char state) {
rest();
}
default_enable = LLK_ENABLE_DEFAULT;
+ if (!LLK_ENABLE_DEFAULT && (android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng") &&
+ android::base::GetBoolProperty("ro.debuggable", false)) {
+ default_enable = true;
+ }
default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
if (default_enable) {
execute("start llkd-1");
diff --git a/mini_keyctl/Android.bp b/mini_keyctl/Android.bp
index 0325c5b4b..417ddac18 100644
--- a/mini_keyctl/Android.bp
+++ b/mini_keyctl/Android.bp
@@ -13,7 +13,6 @@ cc_library_static {
],
cflags: ["-Werror", "-Wall", "-Wextra"],
export_include_dirs: ["."],
- recovery_available: true,
}
cc_binary {
diff --git a/mini_keyctl/OWNERS b/mini_keyctl/OWNERS
deleted file mode 100644
index f9e7b25ea..000000000
--- a/mini_keyctl/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-alanstokes@google.com
-ebiggers@google.com
-jeffv@google.com
-jiyong@google.com
-victorhsieh@google.com
diff --git a/property_service/TEST_MAPPING b/property_service/TEST_MAPPING
deleted file mode 100644
index 20f6c84c9..000000000
--- a/property_service/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "propertyinfoserializer_tests"
- }
- ],
- "hwasan-postsubmit": [
- {
- "name": "propertyinfoserializer_tests"
- }
- ]
-}
diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp
index 87646f99d..68614566b 100644
--- a/property_service/libpropertyinfoparser/Android.bp
+++ b/property_service/libpropertyinfoparser/Android.bp
@@ -18,11 +18,7 @@ cc_library_static {
"-Werror",
],
stl: "none",
- target: {
- bionic: {
- system_shared_libs: [],
- header_libs: ["libc_headers"],
- },
- },
+ system_shared_libs: [],
+ header_libs: ["libc_headers"],
export_include_dirs: ["include"],
}
diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
index 77cbdd4d7..3907413cc 100644
--- a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
@@ -490,6 +490,7 @@ TEST(propertyinfoserializer, RealProperties) {
{"media.recorder.show_manufacturer_and_model", "u:object_r:default_prop:s0"},
{"net.bt.name", "u:object_r:system_prop:s0"},
{"net.lte.ims.data.enabled", "u:object_r:net_radio_prop:s0"},
+ {"net.qtaguid_enabled", "u:object_r:system_prop:s0"},
{"net.tcp.default_init_rwnd", "u:object_r:system_prop:s0"},
{"nfc.initialized", "u:object_r:nfc_prop:s0"},
{"persist.audio.fluence.speaker", "u:object_r:audio_prop:s0"},
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index e98733ada..ae21633da 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -45,11 +45,4 @@ prebuilt_etc {
src: "etc/public.libraries.android.txt",
filename: "public.libraries.txt",
installable: false,
-}
-
-// adb_debug.prop in debug ramdisk
-prebuilt_root {
- name: "adb_debug.prop",
- src: "adb_debug.prop",
- debug_ramdisk: true,
-}
+} \ No newline at end of file
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index fe23b6206..99d8f9a83 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -1,7 +1,5 @@
LOCAL_PATH:= $(call my-dir)
-$(eval $(call declare-1p-copy-files,system/core/rootdir,))
-
#######################################
# init-debug.rc
include $(CLEAR_VARS)
@@ -79,11 +77,7 @@ endif
EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS :=
ifeq ($(CLANG_COVERAGE),true)
- ifeq ($(CLANG_COVERAGE_CONTINUOUS_MODE),true)
- EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang%c-%20m.profraw
- else
- EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang-%20m.profraw
- endif
+ EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang-%20m.profraw
endif
# Put it here instead of in init.rc module definition,
@@ -155,9 +149,6 @@ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm_dlkm
# via /odm/lib/modules directly.
LOCAL_POST_INSTALL_CMD += ; ln -sf /odm/odm_dlkm/etc $(TARGET_ROOT_OUT)/odm_dlkm/etc
-# For /system_dlkm partition
-LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/system_dlkm
-
ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
else
@@ -203,9 +194,15 @@ LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := \
- $(SANITIZER_STEMS) \
- $(2ND_SANITIZER_STEMS)
+$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(addsuffix .so,\
+ $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(HWADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(UBSAN_RUNTIME_LIBRARY) \
+ $(TSAN_RUNTIME_LIBRARY) \
+ $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(2ND_HWADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(2ND_UBSAN_RUNTIME_LIBRARY) \
+ $(2ND_TSAN_RUNTIME_LIBRARY))
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
@@ -213,4 +210,15 @@ $(LOCAL_BUILT_MODULE):
$(hide) $(foreach lib,$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES), \
echo $(lib) >> $@;)
+#######################################
+# adb_debug.prop in debug ramdisk
+include $(CLEAR_VARS)
+LOCAL_MODULE := adb_debug.prop
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_DEBUG_RAMDISK_OUT)
+include $(BUILD_PREBUILT)
+
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/avb/Android.bp b/rootdir/avb/Android.bp
new file mode 100644
index 000000000..cfc59a71b
--- /dev/null
+++ b/rootdir/avb/Android.bp
@@ -0,0 +1,31 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "q-gsi_avbpubkey",
+ srcs: [
+ "q-gsi.avbpubkey",
+ ],
+}
+
+filegroup {
+ name: "r-gsi_avbpubkey",
+ srcs: [
+ "r-gsi.avbpubkey",
+ ],
+}
+
+filegroup {
+ name: "s-gsi_avbpubkey",
+ srcs: [
+ "s-gsi.avbpubkey",
+ ],
+}
+
+filegroup {
+ name: "qcar-gsi_avbpubkey",
+ srcs: [
+ "qcar-gsi.avbpubkey",
+ ],
+}
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
index 8cf317231..647cfa21b 100644
--- a/rootdir/avb/Android.mk
+++ b/rootdir/avb/Android.mk
@@ -15,6 +15,19 @@ else
endif
#######################################
+# q-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := q-gsi.avbpubkey
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
+
+include $(BUILD_PREBUILT)
+
+#######################################
# q-developer-gsi.avbpubkey
include $(CLEAR_VARS)
@@ -28,6 +41,19 @@ LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
include $(BUILD_PREBUILT)
#######################################
+# r-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := r-gsi.avbpubkey
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
+
+include $(BUILD_PREBUILT)
+
+#######################################
# r-developer-gsi.avbpubkey
include $(CLEAR_VARS)
@@ -41,6 +67,19 @@ LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
include $(BUILD_PREBUILT)
#######################################
+# s-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := s-gsi.avbpubkey
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
+
+include $(BUILD_PREBUILT)
+
+#######################################
# s-developer-gsi.avbpubkey
include $(CLEAR_VARS)
@@ -53,4 +92,17 @@ LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
include $(BUILD_PREBUILT)
+#######################################
+# qcar-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := qcar-gsi.avbpubkey
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
+
+include $(BUILD_PREBUILT)
+
my_gsi_avb_keys_path :=
diff --git a/rootdir/avb/q-gsi.avbpubkey b/rootdir/avb/q-gsi.avbpubkey
new file mode 100644
index 000000000..5ed7543ba
--- /dev/null
+++ b/rootdir/avb/q-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/avb/qcar-gsi.avbpubkey b/rootdir/avb/qcar-gsi.avbpubkey
new file mode 100644
index 000000000..ce56646d0
--- /dev/null
+++ b/rootdir/avb/qcar-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/avb/r-gsi.avbpubkey b/rootdir/avb/r-gsi.avbpubkey
new file mode 100644
index 000000000..2609b3037
--- /dev/null
+++ b/rootdir/avb/r-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/avb/s-gsi.avbpubkey b/rootdir/avb/s-gsi.avbpubkey
new file mode 100644
index 000000000..9065fb83f
--- /dev/null
+++ b/rootdir/avb/s-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/etc/TEST_MAPPING b/rootdir/etc/TEST_MAPPING
index 1c7b71618..e4d3d5e1f 100644
--- a/rootdir/etc/TEST_MAPPING
+++ b/rootdir/etc/TEST_MAPPING
@@ -3,10 +3,5 @@
{
"name": "CtsBionicTestCases"
}
- ],
- "hwasan-postsubmit": [
- {
- "name": "CtsBionicTestCases"
- }
]
}
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index c88c7ff1e..c58f29828 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -11,17 +11,12 @@
"libsigchain.so",
// TODO(b/122876336): Remove libpac.so once it's migrated to Webview
"libpac.so",
- // TODO(b/184872979): Remove libbinder_rpc_unstable.so once stablized and
- // added to libbinder_ndk.
- "libbinder_rpc_unstable.so",
// TODO(b/120786417 or b/134659294): libicuuc.so
// and libicui18n.so are kept for app compat.
"libicui18n.so",
"libicuuc.so",
// resolv
"libnetd_resolv.so",
- // netd
- "libnetd_updatable.so",
// nn
"libneuralnetworks.so",
// statsd
@@ -31,9 +26,5 @@
"libadb_pairing_auth.so",
"libadb_pairing_connection.so",
"libadb_pairing_server.so"
- ],
- "provideLibs": [
- "libaptX_encoder.so",
- "libaptXHD_encoder.so"
]
}
diff --git a/rootdir/init.no_zygote.rc b/rootdir/init.no_zygote.rc
deleted file mode 100644
index 8e0afcb51..000000000
--- a/rootdir/init.no_zygote.rc
+++ /dev/null
@@ -1,2 +0,0 @@
-# This is an empty file that does not specify any zygote services.
-# It exists to support targets that do not include a zygote.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index cd71aa8aa..451595092 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -78,8 +78,8 @@ on early-init
mkdir /dev/boringssl 0755 root root
mkdir /dev/boringssl/selftest 0755 root root
- # Mount tracefs (with GID=AID_READTRACEFS)
- mount tracefs tracefs /sys/kernel/tracing gid=3012
+ # Mount tracefs
+ mount tracefs tracefs /sys/kernel/tracing
# create sys dirctory
mkdir /dev/sys 0755 system system
@@ -97,18 +97,22 @@ on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
exec_start boringssl_self_test_apex64
service boringssl_self_test32 /system/bin/boringssl_self_test32
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
service boringssl_self_test64 /system/bin/boringssl_self_test64
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
@@ -138,21 +142,11 @@ on init
chown system system /dev/stune/background/tasks
chown system system /dev/stune/top-app/tasks
chown system system /dev/stune/rt/tasks
- chown system system /dev/stune/cgroup.procs
- chown system system /dev/stune/foreground/cgroup.procs
- chown system system /dev/stune/background/cgroup.procs
- chown system system /dev/stune/top-app/cgroup.procs
- chown system system /dev/stune/rt/cgroup.procs
chmod 0664 /dev/stune/tasks
chmod 0664 /dev/stune/foreground/tasks
chmod 0664 /dev/stune/background/tasks
chmod 0664 /dev/stune/top-app/tasks
chmod 0664 /dev/stune/rt/tasks
- chmod 0664 /dev/stune/cgroup.procs
- chmod 0664 /dev/stune/foreground/cgroup.procs
- chmod 0664 /dev/stune/background/cgroup.procs
- chmod 0664 /dev/stune/top-app/cgroup.procs
- chmod 0664 /dev/stune/rt/cgroup.procs
# cpuctl hierarchy for devices using utilclamp
mkdir /dev/cpuctl/foreground
@@ -161,7 +155,6 @@ on init
mkdir /dev/cpuctl/rt
mkdir /dev/cpuctl/system
mkdir /dev/cpuctl/system-background
- mkdir /dev/cpuctl/dex2oat
chown system system /dev/cpuctl
chown system system /dev/cpuctl/foreground
chown system system /dev/cpuctl/background
@@ -169,7 +162,6 @@ on init
chown system system /dev/cpuctl/rt
chown system system /dev/cpuctl/system
chown system system /dev/cpuctl/system-background
- chown system system /dev/cpuctl/dex2oat
chown system system /dev/cpuctl/tasks
chown system system /dev/cpuctl/foreground/tasks
chown system system /dev/cpuctl/background/tasks
@@ -177,15 +169,6 @@ on init
chown system system /dev/cpuctl/rt/tasks
chown system system /dev/cpuctl/system/tasks
chown system system /dev/cpuctl/system-background/tasks
- chown system system /dev/cpuctl/dex2oat/tasks
- chown system system /dev/cpuctl/cgroup.procs
- chown system system /dev/cpuctl/foreground/cgroup.procs
- chown system system /dev/cpuctl/background/cgroup.procs
- chown system system /dev/cpuctl/top-app/cgroup.procs
- chown system system /dev/cpuctl/rt/cgroup.procs
- chown system system /dev/cpuctl/system/cgroup.procs
- chown system system /dev/cpuctl/system-background/cgroup.procs
- chown system system /dev/cpuctl/dex2oat/cgroup.procs
chmod 0664 /dev/cpuctl/tasks
chmod 0664 /dev/cpuctl/foreground/tasks
chmod 0664 /dev/cpuctl/background/tasks
@@ -193,23 +176,12 @@ on init
chmod 0664 /dev/cpuctl/rt/tasks
chmod 0664 /dev/cpuctl/system/tasks
chmod 0664 /dev/cpuctl/system-background/tasks
- chmod 0664 /dev/cpuctl/dex2oat/tasks
- chmod 0664 /dev/cpuctl/cgroup.procs
- chmod 0664 /dev/cpuctl/foreground/cgroup.procs
- chmod 0664 /dev/cpuctl/background/cgroup.procs
- chmod 0664 /dev/cpuctl/top-app/cgroup.procs
- chmod 0664 /dev/cpuctl/rt/cgroup.procs
- chmod 0664 /dev/cpuctl/system/cgroup.procs
- chmod 0664 /dev/cpuctl/system-background/cgroup.procs
- chmod 0664 /dev/cpuctl/dex2oat/cgroup.procs
# Create a cpu group for NNAPI HAL processes
mkdir /dev/cpuctl/nnapi-hal
chown system system /dev/cpuctl/nnapi-hal
chown system system /dev/cpuctl/nnapi-hal/tasks
- chown system system /dev/cpuctl/nnapi-hal/cgroup.procs
chmod 0664 /dev/cpuctl/nnapi-hal/tasks
- chmod 0664 /dev/cpuctl/nnapi-hal/cgroup.procs
write /dev/cpuctl/nnapi-hal/cpu.uclamp.min 1
write /dev/cpuctl/nnapi-hal/cpu.uclamp.latency_sensitive 1
@@ -217,25 +189,19 @@ on init
mkdir /dev/cpuctl/camera-daemon
chown system system /dev/cpuctl/camera-daemon
chown system system /dev/cpuctl/camera-daemon/tasks
- chown system system /dev/cpuctl/camera-daemon/cgroup.procs
chmod 0664 /dev/cpuctl/camera-daemon/tasks
- chmod 0664 /dev/cpuctl/camera-daemon/cgroup.procs
# Create an stune group for camera-specific processes
mkdir /dev/stune/camera-daemon
chown system system /dev/stune/camera-daemon
chown system system /dev/stune/camera-daemon/tasks
- chown system system /dev/stune/camera-daemon/cgroup.procs
chmod 0664 /dev/stune/camera-daemon/tasks
- chmod 0664 /dev/stune/camera-daemon/cgroup.procs
# Create an stune group for NNAPI HAL processes
mkdir /dev/stune/nnapi-hal
chown system system /dev/stune/nnapi-hal
chown system system /dev/stune/nnapi-hal/tasks
- chown system system /dev/stune/nnapi-hal/cgroup.procs
chmod 0664 /dev/stune/nnapi-hal/tasks
- chmod 0664 /dev/stune/nnapi-hal/cgroup.procs
write /dev/stune/nnapi-hal/schedtune.boost 1
write /dev/stune/nnapi-hal/schedtune.prefer_idle 1
@@ -247,12 +213,8 @@ on init
chown system system /dev/blkio/background
chown system system /dev/blkio/tasks
chown system system /dev/blkio/background/tasks
- chown system system /dev/blkio/cgroup.procs
- chown system system /dev/blkio/background/cgroup.procs
chmod 0664 /dev/blkio/tasks
chmod 0664 /dev/blkio/background/tasks
- chmod 0664 /dev/blkio/cgroup.procs
- chmod 0664 /dev/blkio/background/cgroup.procs
write /dev/blkio/blkio.weight 1000
write /dev/blkio/background/blkio.weight 200
write /dev/blkio/background/blkio.bfq.weight 10
@@ -401,13 +363,6 @@ on init
chown system system /dev/cpuset/top-app/tasks
chown system system /dev/cpuset/restricted/tasks
chown system system /dev/cpuset/camera-daemon/tasks
- chown system system /dev/cpuset/cgroup.procs
- chown system system /dev/cpuset/foreground/cgroup.procs
- chown system system /dev/cpuset/background/cgroup.procs
- chown system system /dev/cpuset/system-background/cgroup.procs
- chown system system /dev/cpuset/top-app/cgroup.procs
- chown system system /dev/cpuset/restricted/cgroup.procs
- chown system system /dev/cpuset/camera-daemon/cgroup.procs
# set system-background to 0775 so SurfaceFlinger can touch it
chmod 0775 /dev/cpuset/system-background
@@ -419,13 +374,6 @@ on init
chmod 0664 /dev/cpuset/restricted/tasks
chmod 0664 /dev/cpuset/tasks
chmod 0664 /dev/cpuset/camera-daemon/tasks
- chmod 0664 /dev/cpuset/foreground/cgroup.procs
- chmod 0664 /dev/cpuset/background/cgroup.procs
- chmod 0664 /dev/cpuset/system-background/cgroup.procs
- chmod 0664 /dev/cpuset/top-app/cgroup.procs
- chmod 0664 /dev/cpuset/restricted/cgroup.procs
- chmod 0664 /dev/cpuset/cgroup.procs
- chmod 0664 /dev/cpuset/camera-daemon/cgroup.procs
# make the PSI monitor accessible to others
chown system system /proc/pressure/memory
@@ -490,7 +438,6 @@ on init
# Start logd before any other services run to ensure we capture all of their logs.
start logd
# Start lmkd before any other services run so that it can register them
- write /proc/sys/vm/watermark_boost_factor 0
chown root system /sys/module/lowmemorykiller/parameters/adj
chmod 0664 /sys/module/lowmemorykiller/parameters/adj
chown root system /sys/module/lowmemorykiller/parameters/minfree
@@ -508,6 +455,11 @@ on property:sys.boot_from_charger_mode=1
class_stop charger
trigger late-init
+on load_persist_props_action
+ load_persist_props
+ start logd
+ start logd-reinit
+
# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
rm /dev/.booting
@@ -534,6 +486,9 @@ on late-init
# /data, which in turn can only be loaded when system properties are present.
trigger post-fs-data
+ # Load persist properties and override properties (if enabled) from /data.
+ trigger load_persist_props_action
+
# Should be before netd, but after apex, properties and logging is available.
trigger load_bpf_programs
@@ -623,7 +578,6 @@ on post-fs
restorecon_recursive /metadata/apex
mkdir /metadata/staged-install 0770 root system
- mkdir /metadata/sepolicy 0700 root root
on late-fs
# Ensure that tracefs has the correct permissions.
# This does not work correctly if it is called in post-fs.
@@ -717,18 +671,6 @@ on post-fs-data
# use of MAX_BOOT_LEVEL keys.
exec - system system -- /system/bin/vdc keymaster earlyBootEnded
- # Multi-installed APEXes are selected using persist props.
- # Load persist properties and override properties (if enabled) from /data,
- # before starting apexd.
- load_persist_props
- start logd
- start logd-reinit
- # Some existing vendor rc files use 'on load_persist_props_action' to know
- # when persist props are ready. These are difficult to change due to GRF,
- # so continue triggering this action here even though props are already loaded
- # by the 'load_persist_props' call above.
- trigger load_persist_props_action
-
# /data/apex is now available. Start apexd to scan and activate APEXes.
#
# To handle userspace reboots as well as devices that use FDE, make sure
@@ -820,15 +762,7 @@ on post-fs-data
# directory used for on-device refresh metrics file.
mkdir /data/misc/odrefresh 0777 system system
# directory used for on-device signing key blob
- mkdir /data/misc/odsign 0710 root system
- # directory used for odsign metrics
- mkdir /data/misc/odsign/metrics 0770 root system
-
- # Directory for VirtualizationService temporary image files.
- # Delete any stale files owned by the old virtualizationservice uid (b/230056726).
- chmod 0770 /data/misc/virtualizationservice
- exec - virtualizationservice system -- /bin/rm -rf /data/misc/virtualizationservice
- mkdir /data/misc/virtualizationservice 0770 system system
+ mkdir /data/misc/odsign 0700 root root
mkdir /data/preloads 0775 system system encryption=None
@@ -852,13 +786,11 @@ on post-fs-data
# Create directories to push tests to for each linker namespace.
# Create the subdirectories in case the first test is run as root
# so it doesn't end up owned by root.
- # Set directories to be executable by any process so that debuggerd,
- # aka crash_dump, can read any executables/shared libraries.
- mkdir /data/local/tests 0701 shell shell
- mkdir /data/local/tests/product 0701 shell shell
- mkdir /data/local/tests/system 0701 shell shell
- mkdir /data/local/tests/unrestricted 0701 shell shell
- mkdir /data/local/tests/vendor 0701 shell shell
+ mkdir /data/local/tests 0700 shell shell
+ mkdir /data/local/tests/product 0700 shell shell
+ mkdir /data/local/tests/system 0700 shell shell
+ mkdir /data/local/tests/unrestricted 0700 shell shell
+ mkdir /data/local/tests/vendor 0700 shell shell
# create dalvik-cache, so as to enforce our permissions
mkdir /data/dalvik-cache 0771 root root encryption=Require
@@ -968,9 +900,6 @@ on post-fs-data
exec - media_rw media_rw -- /system/bin/chattr +F /data/media
mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
- # Create directories for boot animation.
- mkdir /data/bootanim 0755 system system encryption=DeleteIfNecessary
-
exec_start derive_sdk
init_user0
@@ -1010,6 +939,12 @@ on post-fs-data
# module, delete if not.
exec - system system -- /system/bin/tzdatacheck /apex/com.android.tzdata/etc/tz /data/misc/zoneinfo
+ # If there is no post-fs-data action in the init.<device>.rc file, you
+ # must uncomment this line, otherwise encrypted filesystems
+ # won't work.
+ # Set indication (checked by vold) that we have finished this action
+ #setprop vold.post_fs_data_done 1
+
# sys.memfd_use set to false by default, which keeps it disabled
# until it is confirmed that apps and vendor processes don't make
# IOCTLs on ashmem fds any more.
@@ -1079,13 +1014,11 @@ on boot
# to access F2FS sysfs on dm-<num> directly
mkdir /dev/sys/fs/by-name 0755 system system
- symlink /sys/fs/f2fs/${dev.mnt.dev.data} /dev/sys/fs/by-name/userdata
+ symlink /sys/fs/f2fs/${dev.mnt.blk.data} /dev/sys/fs/by-name/userdata
- # dev.mnt.dev.data=dm-N, dev.mnt.blk.data=sdaN/mmcblk0pN, dev.mnt.rootdisk.data=sda/mmcblk0, or
- # dev.mnt.dev.data=sdaN/mmcblk0pN, dev.mnt.blk.data=sdaN/mmcblk0pN, dev.mnt.rootdisk.data=sda/mmcblk0
+ # to access dm-<num> sysfs
mkdir /dev/sys/block/by-name 0755 system system
- symlink /sys/class/block/${dev.mnt.dev.data} /dev/sys/block/by-name/userdata
- symlink /sys/class/block/${dev.mnt.rootdisk.data} /dev/sys/block/by-name/rootdisk
+ symlink /sys/devices/virtual/block/${dev.mnt.blk.data} /dev/sys/block/by-name/userdata
# F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs,
# to avoid power consumption when system becomes mostly idle. Be careful
@@ -1095,14 +1028,10 @@ on boot
write /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time 50
write /dev/sys/fs/by-name/userdata/iostat_enable 1
- # set readahead multiplier for POSIX_FADV_SEQUENTIAL files
- write /dev/sys/fs/by-name/userdata/seq_file_ra_mul 16
-
# limit discard size to 128MB in order to avoid long IO latency
# for filesystem tuning first (dm or sda)
- # this requires enabling selinux entry for sda/mmcblk0 in vendor side
+ # Note that, if dm-<num> is used, sda/mmcblk0 should be tuned in vendor/init.rc
write /dev/sys/block/by-name/userdata/queue/discard_max_bytes 134217728
- write /dev/sys/block/by-name/rootdisk/queue/discard_max_bytes 134217728
# Permissions for System Server and daemons.
chown system system /sys/power/autosleep
@@ -1163,9 +1092,6 @@ on boot
# Define default initial receive window size in segments.
setprop net.tcp_def_init_rwnd 60
- # Update dm-verity state and set partition.*.verified properties.
- verity_update_state
-
# Start standard binderized HAL daemons
class_start hal
@@ -1181,6 +1107,37 @@ on property:sys.init_log_level=*
on charger
class_start charger
+on property:vold.decrypt=trigger_load_persist_props
+ load_persist_props
+ start logd
+ start logd-reinit
+
+on property:vold.decrypt=trigger_post_fs_data
+ trigger post-fs-data
+ trigger zygote-start
+
+on property:vold.decrypt=trigger_restart_min_framework
+ # A/B update verifier that marks a successful boot.
+ exec_start update_verifier
+ class_start main
+
+on property:vold.decrypt=trigger_restart_framework
+ # A/B update verifier that marks a successful boot.
+ exec_start update_verifier
+ class_start_post_data hal
+ class_start_post_data core
+ class_start main
+ class_start late_start
+ setprop service.bootanim.exit 0
+ setprop service.bootanim.progress 0
+ start bootanim
+
+on property:vold.decrypt=trigger_shutdown_framework
+ class_reset late_start
+ class_reset main
+ class_reset_post_data core
+ class_reset_post_data hal
+
on property:sys.boot_completed=1
bootchart stop
# Setup per_boot directory so other .rc could start to use it on boot_completed
@@ -1191,7 +1148,7 @@ on property:sys.boot_completed=1
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
- exec -- /system/bin/extra_free_kbytes.sh ${sys.sysctl.extra_free_kbytes}
+ write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
# Allow users to drop caches
on property:perf.drop_caches=3
@@ -1308,15 +1265,3 @@ on userspace-reboot-resume
on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
setprop sys.init.userspace_reboot.in_progress ""
-
-# Multi-Gen LRU Experiment
-on property:persist.device_config.mglru_native.lru_gen_config=none
- write /sys/kernel/mm/lru_gen/enabled 0
-on property:persist.device_config.mglru_native.lru_gen_config=core
- write /sys/kernel/mm/lru_gen/enabled 1
-on property:persist.device_config.mglru_native.lru_gen_config=core_and_mm_walk
- write /sys/kernel/mm/lru_gen/enabled 3
-on property:persist.device_config.mglru_native.lru_gen_config=core_and_nonleaf_young
- write /sys/kernel/mm/lru_gen/enabled 5
-on property:persist.device_config.mglru_native.lru_gen_config=all
- write /sys/kernel/mm/lru_gen/enabled 7
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 63b09c0d6..9469a4873 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -10,8 +10,7 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
- onrestart restart media.tuner
onrestart restart netd
onrestart restart wificond
- task_profiles ProcessCapacityHigh
+ writepid /dev/cpuset/foreground/tasks
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 5bde5f469..98dc0881f 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -10,8 +10,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
- onrestart restart media.tuner
onrestart restart netd
onrestart restart wificond
- task_profiles ProcessCapacityHigh
+ writepid /dev/cpuset/foreground/tasks
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index efb30d664..3eee180ba 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -10,7 +10,6 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
- onrestart restart media.tuner
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index a140c8c51..56e774bdc 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -67,8 +67,9 @@ subsystem dma_heap
# CDMA radio interface MUX
/dev/ppp 0660 radio vpn
-/dev/kvm 0600 system system
-/dev/vhost-vsock 0600 system system
+# Virtualisation is managed by Virt Manager
+/dev/kvm 0600 virtmanager root
+/dev/vhost-vsock 0600 virtmanager root
# sysfs properties
/sys/devices/platform/trusty.* trusty_version 0440 root log
diff --git a/rustfmt.toml b/rustfmt.toml
deleted file mode 120000
index ee92d9efc..000000000
--- a/rustfmt.toml
+++ /dev/null
@@ -1 +0,0 @@
-../../build/soong/scripts/rustfmt.toml \ No newline at end of file
diff --git a/set-verity-state/set-verity-state.cpp b/set-verity-state/set-verity-state.cpp
index 52a7f7473..0a26abaa2 100644
--- a/set-verity-state/set-verity-state.cpp
+++ b/set-verity-state/set-verity-state.cpp
@@ -244,6 +244,25 @@ int main(int argc, char* argv[]) {
any_changed = true;
}
avb_ops_user_free(ops);
+ } else {
+ // Not using AVB - assume VB1.0.
+
+ // read all fstab entries at once from all sources
+ android::fs_mgr::Fstab fstab;
+ if (!android::fs_mgr::ReadDefaultFstab(&fstab)) {
+ printf("Failed to read fstab\n");
+ suggest_run_adb_root();
+ return 0;
+ }
+
+ // Loop through entries looking for ones that verity manages.
+ for (const auto& entry : fstab) {
+ if (entry.fs_mgr_flags.verify) {
+ if (set_verity_enabled_state(entry.blk_device.c_str(), entry.mount_point.c_str(), enable)) {
+ any_changed = true;
+ }
+ }
+ }
}
if (!any_changed) any_changed = overlayfs_setup(enable);
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index d85f6edb3..b7d7490dc 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -18,15 +18,12 @@ phony {
"awk",
"bc",
"bzip2",
- "fsck.exfat",
"ldd",
"logwrapper",
"mini-keyctl",
- "mkfs.exfat",
"mkshrc",
"newfs_msdos",
"reboot",
- "settaskprofile",
"sh",
"simpleperf",
"simpleperf_app_runner",
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index ca522b71c..f339553f0 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -34,160 +34,103 @@ commands than there are symlinks for in `/system/bin`. You can get the
full list for a release by running `toybox` directly.
-## Android 13 ("T")
-
-BSD: fsck\_msdos newfs\_msdos
-
-bzip2: bzcat bzip2 bunzip2
-
-gavinhoward/bc: bc
-
-one-true-awk: awk
-
-toolbox: getevent getprop setprop start stop
-
-toybox (0.8.6-ish): [ acpi base64 basename blkdiscard blkid blockdev cal cat chattr chcon
-chgrp chmod chown chroot chrt cksum clear cmp comm cp cpio cut date
-dd devmem df diff dirname dmesg dos2unix du echo egrep env expand
-expr fallocate false fgrep file find flock fmt free freeramdisk fsfreeze
-fsync getconf getenforce getfattr getopt grep groups gunzip gzip head
-help hostname hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig
-inotifyd insmod install ionice iorenice iotop kill killall ln load\_policy
-log logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum
-microcom mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount
-mountpoint mv nbd-client nc netcat netstat nice nl nohup nproc nsenter
-od partprobe paste patch pgrep pidof ping ping6 pivot\_root pkill pmap
-printenv printf prlimit ps pwd pwdx readelf readlink realpath renice
-restorecon rev rfkill rm rmdir rmmod rtcwake runcon sed sendevent
-seq setenforce setfattr setsid sha1sum sha224sum sha256sum sha384sum
-sha512sum sleep sort split stat strings stty swapoff swapon sync sysctl
-tac tail tar taskset tee test time timeout top touch tr traceroute
-traceroute6 true truncate tty tunctl **uclampset** ulimit umount uname
-uniq unix2dos unlink unshare uptime usleep uudecode uuencode uuidgen
-vconfig vi vmstat watch wc which whoami xargs xxd yes zcat
+## Android 2.3 (Gingerbread)
+BSD: cat dd newfs\_msdos
-## Android 12 ("S")
+toolbox: chmod chown cmp date df dmesg getevent getprop hd id ifconfig
+iftop insmod ioctl ionice kill ln log ls lsmod lsof mkdir mount mv
+nandread netstat notify printenv ps reboot renice rm rmdir rmmod route
+schedtop sendevent setconsole setprop sleep smd start stop sync top
+umount uptime vmstat watchprops wipe
-BSD: fsck\_msdos newfs\_msdos
-bzip2: bzcat bzip2 bunzip2
+## Android 4.0 (IceCreamSandwich)
-gavinhoward/bc: bc
+BSD: cat dd newfs\_msdos
-one-true-awk: awk
+toolbox: chmod chown cmp date df dmesg getevent getprop hd id ifconfig
+iftop insmod ioctl ionice kill ln log ls lsmod lsof mkdir mount mv
+nandread netstat notify printenv ps reboot renice rm rmdir rmmod route
+schedtop sendevent setconsole setprop sleep smd start stop sync top
+touch umount uptime vmstat watchprops wipe
-toolbox: getevent getprop setprop start stop
-toybox (0.8.4-ish): **[** acpi base64 basename **blkdiscard** blkid blockdev cal cat chattr chcon
-chgrp chmod chown chroot chrt cksum clear cmp comm cp cpio cut date
-dd devmem df diff dirname dmesg dos2unix du echo egrep env expand
-expr fallocate false fgrep file find flock fmt free freeramdisk fsfreeze
-fsync getconf getenforce getfattr getopt grep groups gunzip gzip head
-help hostname hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig
-inotifyd insmod install ionice iorenice iotop kill killall ln load\_policy
-log logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum
-microcom mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount
-mountpoint mv nbd-client nc netcat netstat nice nl nohup nproc nsenter
-od partprobe paste patch pgrep pidof ping ping6 pivot\_root pkill pmap
-printenv printf prlimit ps pwd pwdx readelf readlink realpath renice
-restorecon rev rfkill rm rmdir rmmod **rtcwake** runcon sed sendevent
-seq setenforce setfattr setsid sha1sum sha224sum sha256sum sha384sum
-sha512sum sleep sort split stat strings stty swapoff swapon sync sysctl
-tac tail tar taskset tee **test** time timeout top touch tr traceroute
-traceroute6 true truncate tty tunctl ulimit umount uname uniq unix2dos
-unlink unshare uptime usleep uudecode uuencode uuidgen vconfig vi
-vmstat watch wc which whoami xargs xxd yes zcat
+## Android 4.1-4.3 (JellyBean)
+BSD: cat cp dd du grep newfs\_msdos
-## Android 11 ("R")
+toolbox: chcon chmod chown clear cmp date df dmesg getenforce getevent
+getprop getsebool hd id ifconfig iftop insmod ioctl ionice kill ln
+load\_policy log ls lsmod lsof md5 mkdir mount mv nandread netstat notify
+printenv ps reboot renice restorecon rm rmdir rmmod route runcon schedtop
+sendevent setconsole setenforce setprop setsebool sleep smd start stop
+sync top touch umount uptime vmstat watchprops wipe
-BSD: fsck\_msdos newfs\_msdos
-bzip2: bzcat bzip2 bunzip2
+## Android 4.4 (KitKat)
-gavinhoward/bc: bc
+BSD: cat cp dd du grep newfs\_msdos
-one-true-awk: awk
+toolbox: chcon chmod chown clear cmp date df dmesg getenforce getevent
+getprop getsebool hd id ifconfig iftop insmod ioctl ionice kill ln
+load\_policy log ls lsmod lsof md5 mkdir mkswap mount mv nandread netstat
+notify printenv ps readlink renice restorecon rm rmdir rmmod route runcon
+schedtop sendevent setconsole setenforce setprop setsebool sleep smd start
+stop swapoff swapon sync top touch umount uptime vmstat watchprops wipe
-toolbox: getevent getprop setprop start stop
-toybox (0.8.3-ish): acpi base64 basename blkid blockdev cal cat chattr chcon chgrp chmod
-chown chroot chrt cksum clear cmp comm cp cpio cut date dd **devmem**
-df diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
-false fgrep file find flock fmt free freeramdisk fsfreeze **fsync** getconf
-getenforce getfattr **getopt** grep groups gunzip gzip head help hostname
-hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd
-insmod install ionice iorenice iotop kill killall ln load\_policy log
-logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
-mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
-mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe
-paste patch pgrep pidof ping ping6 pivot\_root pkill pmap printenv
-printf prlimit ps pwd pwdx **readelf** readlink realpath renice restorecon
-rev rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
-setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort
-split stat strings stty swapoff swapon sync sysctl tac tail tar taskset
-tee time timeout top touch tr traceroute traceroute6 true truncate
-tty tunctl ulimit umount uname uniq unix2dos unlink unshare uptime
-usleep uudecode uuencode uuidgen vconfig **vi** vmstat watch wc which
-whoami xargs xxd yes zcat
+## Android 5.0 (Lollipop)
+BSD: cat chown cp dd du grep kill ln mv printenv rm rmdir sleep sync
-## Android 10 ("Q")
+toolbox: chcon chmod clear cmp date df dmesg getenforce getevent getprop
+getsebool hd id ifconfig iftop insmod ioctl ionice load\_policy log ls
+lsmod lsof md5 mkdir mknod mkswap mount nandread netstat newfs\_msdos
+nohup notify ps readlink renice restorecon rmmod route runcon schedtop
+sendevent setenforce setprop setsebool smd start stop swapoff swapon
+top touch umount uptime vmstat watchprops wipe
-BSD: grep fsck\_msdos newfs\_msdos
-bzip2: bzcat bzip2 bunzip2
+## Android 6.0 (Marshmallow)
-one-true-awk: awk
+BSD: dd du grep
-toolbox: getevent getprop
+toolbox: df getevent iftop ioctl ionice log ls lsof mount nandread
+newfs\_msdos ps prlimit renice sendevent start stop top uptime watchprops
-toybox (0.8.0-ish): acpi base64 basename **bc** **blkid** blockdev cal cat **chattr** chcon chgrp
-chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df
-diff dirname dmesg dos2unix du echo **egrep** env expand expr fallocate
-false **fgrep** file find flock fmt free **freeramdisk** **fsfreeze** **getconf**
-getenforce **getfattr** grep groups gunzip gzip head **help** hostname hwclock
-**i2cdetect** **i2cdump** **i2cget** **i2cset** **iconv** id ifconfig inotifyd insmod
-**install** ionice iorenice **iotop** kill killall ln load\_policy log logname
-losetup ls **lsattr** lsmod lsof lspci lsusb **makedevs** md5sum microcom
-mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
-mv **nbd-client** **nc** **netcat** netstat nice nl nohup **nproc** **nsenter** od **partprobe**
-paste patch pgrep pidof **ping** **ping6** **pivot\_root** pkill pmap printenv
-printf **prlimit** ps pwd **pwdx** readlink realpath renice restorecon **rev**
-**rfkill** rm rmdir rmmod runcon sed sendevent seq setenforce **setfattr**
-setprop setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep
-sort split start stat stop strings stty swapoff swapon sync sysctl
-tac tail tar taskset tee time timeout top touch tr **traceroute** **traceroute6**
-true truncate tty **tunctl** ulimit umount uname uniq unix2dos **unlink**
-**unshare** uptime usleep uudecode uuencode **uuidgen** **vconfig** vmstat **watch**
-wc which whoami xargs xxd yes zcat
+toybox (0.5.2-ish): acpi basename blockdev bzcat cal cat chcon chgrp chmod chown
+chroot cksum clear comm cmp cp cpio cut date dirname dmesg dos2unix echo
+env expand expr fallocate false find free getenforce getprop groups
+head hostname hwclock id ifconfig inotifyd insmod kill load\_policy ln
+logname losetup lsmod lsusb md5sum mkdir mknod mkswap mktemp modinfo
+more mountpoint mv netstat nice nl nohup od paste patch pgrep pidof
+pkill pmap printenv printf pwd readlink realpath restorecon rm rmdir
+rmmod route runcon sed seq setenforce setprop setsid sha1sum sleep sort
+split stat strings swapoff swapon sync sysctl tac tail tar taskset tee
+time timeout touch tr true truncate umount uname uniq unix2dos usleep
+vmstat wc which whoami xargs yes
-## Android 9.0 (Pie)
+## Android 7.0 (Nougat)
BSD: dd grep
-bzip2: bzcat bzip2 bunzip2
-
-one-true-awk: awk
-
-toolbox: getevent getprop newfs\_msdos
+toolbox: getevent iftop ioctl log nandread newfs\_msdos ps prlimit
+sendevent start stop top
-toybox (0.7.6-ish): acpi base64 basename blockdev cal cat chcon chgrp chmod chown
-chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
-dos2unix du echo env expand expr fallocate false file find flock **fmt** free
-getenforce groups gunzip gzip head hostname hwclock id ifconfig inotifyd
-insmod ionice iorenice kill killall ln load\_policy log logname losetup ls
-lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod mkswap mktemp
-modinfo modprobe more mount mountpoint mv netstat nice nl nohup od paste
-patch pgrep pidof pkill pmap printenv printf ps pwd readlink realpath
-renice restorecon rm rmdir rmmod runcon sed sendevent seq setenforce
-setprop setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep
-sort split start stat stop strings **stty** swapoff swapon sync sysctl tac
-tail tar taskset tee time timeout top touch tr true truncate tty ulimit
-umount uname uniq unix2dos uptime usleep uudecode uuencode vmstat wc
-which whoami xargs xxd yes zcat
+toybox (0.7.0-ish): acpi **base64** basename blockdev bzcat cal cat chcon chgrp chmod
+chown chroot cksum clear comm cmp cp cpio cut date **df** dirname dmesg
+dos2unix **du** echo env expand expr fallocate false find **flock** free
+getenforce getprop groups head hostname hwclock id ifconfig inotifyd
+insmod **ionice** **iorenice** kill **killall** load\_policy ln logname losetup **ls**
+lsmod **lsof** lsusb md5sum mkdir mknod mkswap mktemp modinfo more *mount*
+mountpoint mv netstat nice nl nohup od paste patch pgrep pidof pkill
+pmap printenv printf pwd readlink realpath **renice** restorecon rm rmdir
+rmmod route runcon sed seq setenforce setprop setsid sha1sum sleep sort
+split stat strings swapoff swapon sync sysctl tac tail tar taskset tee
+time timeout touch tr true truncate **tty** **ulimit** umount uname uniq unix2dos
+**uptime** usleep vmstat wc which whoami xargs **xxd** yes
## Android 8.0 (Oreo)
@@ -214,100 +157,122 @@ tty ulimit umount uname uniq unix2dos uptime usleep **uudecode** **uuencode**
vmstat wc which whoami xargs xxd yes **zcat**
-## Android 7.0 (Nougat)
+## Android 9.0 (Pie)
BSD: dd grep
-toolbox: getevent iftop ioctl log nandread newfs\_msdos ps prlimit
-sendevent start stop top
-
-toybox (0.7.0-ish): acpi **base64** basename blockdev bzcat cal cat chcon chgrp chmod
-chown chroot cksum clear comm cmp cp cpio cut date **df** dirname dmesg
-dos2unix **du** echo env expand expr fallocate false find **flock** free
-getenforce getprop groups head hostname hwclock id ifconfig inotifyd
-insmod **ionice** **iorenice** kill **killall** load\_policy ln logname losetup **ls**
-lsmod **lsof** lsusb md5sum mkdir mknod mkswap mktemp modinfo more *mount*
-mountpoint mv netstat nice nl nohup od paste patch pgrep pidof pkill
-pmap printenv printf pwd readlink realpath **renice** restorecon rm rmdir
-rmmod route runcon sed seq setenforce setprop setsid sha1sum sleep sort
-split stat strings swapoff swapon sync sysctl tac tail tar taskset tee
-time timeout touch tr true truncate **tty** **ulimit** umount uname uniq unix2dos
-**uptime** usleep vmstat wc which whoami xargs **xxd** yes
-
+bzip2: bzcat bzip2 bunzip2
-## Android 6.0 (Marshmallow)
+one-true-awk: awk
-BSD: dd du grep
+toolbox: getevent getprop newfs\_msdos
-toolbox: df getevent iftop ioctl ionice log ls lsof mount nandread
-newfs\_msdos ps prlimit renice sendevent start stop top uptime watchprops
+toybox (0.7.6-ish): acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
+dos2unix du echo env expand expr fallocate false file find flock **fmt** free
+getenforce groups gunzip gzip head hostname hwclock id ifconfig inotifyd
+insmod ionice iorenice kill killall ln load\_policy log logname losetup ls
+lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod mkswap mktemp
+modinfo modprobe more mount mountpoint mv netstat nice nl nohup od paste
+patch pgrep pidof pkill pmap printenv printf ps pwd readlink realpath
+renice restorecon rm rmdir rmmod runcon sed sendevent seq setenforce
+setprop setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep
+sort split start stat stop strings **stty** swapoff swapon sync sysctl tac
+tail tar taskset tee time timeout top touch tr true truncate tty ulimit
+umount uname uniq unix2dos uptime usleep uudecode uuencode vmstat wc
+which whoami xargs xxd yes zcat
-toybox (0.5.2-ish): acpi basename blockdev bzcat cal cat chcon chgrp chmod chown
-chroot cksum clear comm cmp cp cpio cut date dirname dmesg dos2unix echo
-env expand expr fallocate false find free getenforce getprop groups
-head hostname hwclock id ifconfig inotifyd insmod kill load\_policy ln
-logname losetup lsmod lsusb md5sum mkdir mknod mkswap mktemp modinfo
-more mountpoint mv netstat nice nl nohup od paste patch pgrep pidof
-pkill pmap printenv printf pwd readlink realpath restorecon rm rmdir
-rmmod route runcon sed seq setenforce setprop setsid sha1sum sleep sort
-split stat strings swapoff swapon sync sysctl tac tail tar taskset tee
-time timeout touch tr true truncate umount uname uniq unix2dos usleep
-vmstat wc which whoami xargs yes
+## Android 10 ("Q")
-## Android 5.0 (Lollipop)
+BSD: grep fsck\_msdos newfs\_msdos
-BSD: cat chown cp dd du grep kill ln mv printenv rm rmdir sleep sync
+bzip2: bzcat bzip2 bunzip2
-toolbox: chcon chmod clear cmp date df dmesg getenforce getevent getprop
-getsebool hd id ifconfig iftop insmod ioctl ionice load\_policy log ls
-lsmod lsof md5 mkdir mknod mkswap mount nandread netstat newfs\_msdos
-nohup notify ps readlink renice restorecon rmmod route runcon schedtop
-sendevent setenforce setprop setsebool smd start stop swapoff swapon
-top touch umount uptime vmstat watchprops wipe
+one-true-awk: awk
+toolbox: getevent getprop
-## Android 4.4 (KitKat)
+toybox (0.8.0-ish): acpi base64 basename **bc** **blkid** blockdev cal cat **chattr** chcon chgrp
+chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df
+diff dirname dmesg dos2unix du echo **egrep** env expand expr fallocate
+false **fgrep** file find flock fmt free **freeramdisk** **fsfreeze** **getconf**
+getenforce **getfattr** grep groups gunzip gzip head **help** hostname hwclock
+**i2cdetect** **i2cdump** **i2cget** **i2cset** **iconv** id ifconfig inotifyd insmod
+**install** ionice iorenice **iotop** kill killall ln load\_policy log logname
+losetup ls **lsattr** lsmod lsof lspci lsusb **makedevs** md5sum microcom
+mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
+mv **nbd-client** **nc** **netcat** netstat nice nl nohup **nproc** **nsenter** od **partprobe**
+paste patch pgrep pidof **ping** **ping6** **pivot\_root** pkill pmap printenv
+printf **prlimit** ps pwd **pwdx** readlink realpath renice restorecon **rev**
+**rfkill** rm rmdir rmmod runcon sed sendevent seq setenforce **setfattr**
+setprop setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep
+sort split start stat stop strings stty swapoff swapon sync sysctl
+tac tail tar taskset tee time timeout top touch tr **traceroute** **traceroute6**
+true truncate tty **tunctl** ulimit umount uname uniq unix2dos **unlink**
+**unshare** uptime usleep uudecode uuencode **uuidgen** **vconfig** vmstat **watch**
+wc which whoami xargs xxd yes zcat
-BSD: cat cp dd du grep newfs\_msdos
+## Android 11 ("R")
-toolbox: chcon chmod chown clear cmp date df dmesg getenforce getevent
-getprop getsebool hd id ifconfig iftop insmod ioctl ionice kill ln
-load\_policy log ls lsmod lsof md5 mkdir mkswap mount mv nandread netstat
-notify printenv ps readlink renice restorecon rm rmdir rmmod route runcon
-schedtop sendevent setconsole setenforce setprop setsebool sleep smd start
-stop swapoff swapon sync top touch umount uptime vmstat watchprops wipe
+BSD: fsck\_msdos newfs\_msdos
+bzip2: bzcat bzip2 bunzip2
-## Android 4.1-4.3 (JellyBean)
+gavinhoward/bc: bc
-BSD: cat cp dd du grep newfs\_msdos
+one-true-awk: awk
-toolbox: chcon chmod chown clear cmp date df dmesg getenforce getevent
-getprop getsebool hd id ifconfig iftop insmod ioctl ionice kill ln
-load\_policy log ls lsmod lsof md5 mkdir mount mv nandread netstat notify
-printenv ps reboot renice restorecon rm rmdir rmmod route runcon schedtop
-sendevent setconsole setenforce setprop setsebool sleep smd start stop
-sync top touch umount uptime vmstat watchprops wipe
+toolbox: getevent getprop setprop start stop
+toybox (0.8.3-ish): acpi base64 basename blkid blockdev cal cat chattr chcon chgrp chmod
+chown chroot chrt cksum clear cmp comm cp cpio cut date dd **devmem**
+df diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
+false fgrep file find flock fmt free freeramdisk fsfreeze **fsync** getconf
+getenforce getfattr **getopt** grep groups gunzip gzip head help hostname
+hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd
+insmod install ionice iorenice iotop kill killall ln load\_policy log
+logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
+mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
+mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe
+paste patch pgrep pidof ping ping6 pivot\_root pkill pmap printenv
+printf prlimit ps pwd pwdx **readelf** readlink realpath renice restorecon
+rev rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
+setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort
+split stat strings stty swapoff swapon sync sysctl tac tail tar taskset
+tee time timeout top touch tr traceroute traceroute6 true truncate
+tty tunctl ulimit umount uname uniq unix2dos unlink unshare uptime
+usleep uudecode uuencode uuidgen vconfig **vi** vmstat watch wc which
+whoami xargs xxd yes zcat
-## Android 4.0 (IceCreamSandwich)
+## Android ("S")
-BSD: cat dd newfs\_msdos
+BSD: fsck\_msdos newfs\_msdos
-toolbox: chmod chown cmp date df dmesg getevent getprop hd id ifconfig
-iftop insmod ioctl ionice kill ln log ls lsmod lsof mkdir mount mv
-nandread netstat notify printenv ps reboot renice rm rmdir rmmod route
-schedtop sendevent setconsole setprop sleep smd start stop sync top
-touch umount uptime vmstat watchprops wipe
+bzip2: bzcat bzip2 bunzip2
+gavinhoward/bc: bc
-## Android 2.3 (Gingerbread)
+one-true-awk: awk
-BSD: cat dd newfs\_msdos
+toolbox: getevent getprop setprop start stop
-toolbox: chmod chown cmp date df dmesg getevent getprop hd id ifconfig
-iftop insmod ioctl ionice kill ln log ls lsmod lsof mkdir mount mv
-nandread netstat notify printenv ps reboot renice rm rmdir rmmod route
-schedtop sendevent setconsole setprop sleep smd start stop sync top
-umount uptime vmstat watchprops wipe
+toybox (0.8.4-ish): **[** acpi base64 basename **blkdiscard** blkid blockdev cal cat chattr chcon
+chgrp chmod chown chroot chrt cksum clear cmp comm cp cpio cut date
+dd devmem df diff dirname dmesg dos2unix du echo egrep env expand
+expr fallocate false fgrep file find flock fmt free freeramdisk fsfreeze
+fsync getconf getenforce getfattr getopt grep groups gunzip gzip head
+help hostname hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig
+inotifyd insmod install ionice iorenice iotop kill killall ln load\_policy
+log logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum
+microcom mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount
+mountpoint mv nbd-client nc netcat netstat nice nl nohup nproc nsenter
+od partprobe paste patch pgrep pidof ping ping6 pivot\_root pkill pmap
+printenv printf prlimit ps pwd pwdx readelf readlink realpath renice
+restorecon rev rfkill rm rmdir rmmod **rtcwake** runcon sed sendevent
+seq setenforce setfattr setsid sha1sum sha224sum sha256sum sha384sum
+sha512sum sleep sort split stat strings stty swapoff swapon sync sysctl
+tac tail tar taskset tee **test** time timeout top touch tr traceroute
+traceroute6 true truncate tty tunctl ulimit umount uname uniq unix2dos
+unlink unshare uptime usleep uudecode uuencode uuidgen vconfig vi
+vmstat watch wc which whoami xargs xxd yes zcat
diff --git a/storaged/Android.bp b/storaged/Android.bp
index 7960af314..ec27a08cb 100644
--- a/storaged/Android.bp
+++ b/storaged/Android.bp
@@ -24,23 +24,15 @@ cc_defaults {
shared_libs: [
"android.hardware.health@1.0",
"android.hardware.health@2.0",
- "android.hardware.health-V1-ndk",
"libbase",
"libbinder",
- "libbinder_ndk",
"libcutils",
"libhidlbase",
"liblog",
"libprotobuf-cpp-lite",
+ "libsysutils",
"libutils",
"libz",
- "packagemanager_aidl-cpp",
- ],
-
- static_libs: [
- "android.hardware.health-translate-ndk",
- "libhealthhalutils",
- "libhealthshim",
],
cflags: [
@@ -75,6 +67,7 @@ cc_library_static {
":storaged_aidl_private",
],
+ static_libs: ["libhealthhalutils"],
header_libs: ["libbatteryservice_headers"],
logtags: ["EventLogTags.logtags"],
@@ -97,6 +90,7 @@ cc_binary {
srcs: ["main.cpp"],
static_libs: [
+ "libhealthhalutils",
"libstoraged",
],
}
@@ -113,11 +107,9 @@ cc_test {
srcs: ["tests/storaged_test.cpp"],
static_libs: [
+ "libhealthhalutils",
"libstoraged",
],
- test_suites: [
- "general-tests",
- ],
}
// AIDL interface between storaged and framework.jar
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index e120271ee..79b5d41ac 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -28,7 +28,6 @@
#include <utils/Mutex.h>
-#include <aidl/android/hardware/health/IHealth.h>
#include <android/hardware/health/2.0/IHealth.h>
#define FRIEND_TEST(test_case_name, test_name) \
@@ -68,8 +67,6 @@ using namespace android;
// UID IO threshold in bytes
#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
-class storaged_t;
-
struct storaged_config {
int periodic_chores_interval_unit;
int periodic_chores_interval_disk_stats_publish;
@@ -78,33 +75,15 @@ struct storaged_config {
int event_time_check_usec; // check how much cputime spent in event loop
};
-struct HealthServicePair {
- std::shared_ptr<aidl::android::hardware::health::IHealth> aidl_health;
- android::sp<android::hardware::health::V2_0::IHealth> hidl_health;
- static HealthServicePair get();
-};
-
-class hidl_health_death_recipient : public android::hardware::hidl_death_recipient {
- public:
- hidl_health_death_recipient(const android::sp<android::hardware::health::V2_0::IHealth>& health)
- : mHealth(health) {}
- void serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who);
-
- private:
- android::sp<android::hardware::health::V2_0::IHealth> mHealth;
-};
-
-class storaged_t : public RefBase {
+class storaged_t : public android::hardware::health::V2_0::IHealthInfoCallback,
+ public android::hardware::hidl_death_recipient {
private:
time_t mTimer;
storaged_config mConfig;
unique_ptr<disk_stats_monitor> mDsm;
uid_monitor mUidm;
time_t mStarttime;
- std::shared_ptr<aidl::android::hardware::health::IHealth> health;
- sp<android::hardware::hidl_death_recipient> hidl_death_recp;
- ndk::ScopedAIBinder_DeathRecipient aidl_death_recp;
- shared_ptr<aidl::android::hardware::health::IHealthInfoCallback> aidl_health_callback;
+ sp<android::hardware::health::V2_0::IHealth> health;
unique_ptr<storage_info_t> storage_info;
static const uint32_t current_version;
Mutex proto_lock;
@@ -156,6 +135,10 @@ class storaged_t : public RefBase {
void add_user_ce(userid_t user_id);
void remove_user_ce(userid_t user_id);
+ virtual ::android::hardware::Return<void> healthInfoChanged(
+ const ::android::hardware::health::V2_0::HealthInfo& info);
+ void serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who);
+
void report_storage_info();
void flush_protos(unordered_map<int, StoragedProto>* protos);
diff --git a/storaged/include/storaged_diskstats.h b/storaged/include/storaged_diskstats.h
index 3996ef6d1..0b93ba6c5 100644
--- a/storaged/include/storaged_diskstats.h
+++ b/storaged/include/storaged_diskstats.h
@@ -19,7 +19,7 @@
#include <stdint.h>
-#include <aidl/android/hardware/health/IHealth.h>
+#include <android/hardware/health/2.0/IHealth.h>
// number of attributes diskstats has
#define DISK_STATS_SIZE ( 11 )
@@ -162,7 +162,7 @@ private:
const double mSigma;
struct disk_perf mMean;
struct disk_perf mStd;
- std::shared_ptr<aidl::android::hardware::health::IHealth> mHealth;
+ android::sp<android::hardware::health::V2_0::IHealth> mHealth;
void update_mean();
void update_std();
@@ -173,15 +173,14 @@ private:
void update(struct disk_stats* stats);
public:
- disk_stats_monitor(const std::shared_ptr<aidl::android::hardware::health::IHealth>& healthService,
+ disk_stats_monitor(const android::sp<android::hardware::health::V2_0::IHealth>& healthService,
uint32_t window_size = 5, double sigma = 1.0)
: DISK_STATS_PATH(
- healthService != nullptr
- ? nullptr
- : (access(MMC_DISK_STATS_PATH, R_OK) == 0
- ? MMC_DISK_STATS_PATH
- : (access(SDA_DISK_STATS_PATH, R_OK) == 0 ? SDA_DISK_STATS_PATH
- : nullptr))),
+ healthService != nullptr
+ ? nullptr
+ : (access(MMC_DISK_STATS_PATH, R_OK) == 0
+ ? MMC_DISK_STATS_PATH
+ : (access(SDA_DISK_STATS_PATH, R_OK) == 0 ? SDA_DISK_STATS_PATH : nullptr))),
mPrevious(),
mAccumulate(),
mAccumulate_pub(),
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 83c97ad07..9c3d0e784 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -21,7 +21,7 @@
#include <chrono>
-#include <aidl/android/hardware/health/IHealth.h>
+#include <android/hardware/health/2.0/IHealth.h>
#include <utils/Mutex.h>
#include "storaged.h"
@@ -71,8 +71,8 @@ class storage_info_t {
public:
static storage_info_t* get_storage_info(
- const shared_ptr<aidl::android::hardware::health::IHealth>& healthService);
- virtual ~storage_info_t(){};
+ const sp<android::hardware::health::V2_0::IHealth>& healthService);
+ virtual ~storage_info_t() {};
virtual void report() {};
void load_perf_history_proto(const IOPerfHistory& perf_history);
void refresh(IOPerfHistory* perf_history);
@@ -105,14 +105,14 @@ public:
class health_storage_info_t : public storage_info_t {
private:
- using IHealth = aidl::android::hardware::health::IHealth;
- using StorageInfo = aidl::android::hardware::health::StorageInfo;
+ using IHealth = hardware::health::V2_0::IHealth;
+ using StorageInfo = hardware::health::V2_0::StorageInfo;
- shared_ptr<IHealth> mHealth;
+ sp<IHealth> mHealth;
void set_values_from_hal_storage_info(const StorageInfo& halInfo);
public:
- health_storage_info_t(const shared_ptr<IHealth>& service) : mHealth(service){};
+ health_storage_info_t(const sp<IHealth>& service) : mHealth(service){};
virtual ~health_storage_info_t() {}
virtual void report();
};
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index cefef6e06..b7aa89ff7 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -28,16 +28,12 @@
#include <sstream>
#include <string>
-#include <aidl/android/hardware/health/BnHealthInfoCallback.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
-#include <android/binder_ibinder.h>
-#include <android/binder_manager.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <batteryservice/BatteryServiceConstants.h>
#include <cutils/properties.h>
-#include <health-shim/shim.h>
#include <healthhalutils/HealthHalUtils.h>
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/IPCThreadState.h>
@@ -68,59 +64,26 @@ constexpr ssize_t min_benchmark_size = 128 * 1024; // 128KB
const uint32_t storaged_t::current_version = 4;
-using aidl::android::hardware::health::BatteryStatus;
-using aidl::android::hardware::health::BnHealthInfoCallback;
-using aidl::android::hardware::health::HealthInfo;
-using aidl::android::hardware::health::IHealth;
-using aidl::android::hardware::health::IHealthInfoCallback;
using android::hardware::interfacesEqual;
+using android::hardware::Return;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
using android::hardware::health::V2_0::get_health_service;
+using android::hardware::health::V2_0::HealthInfo;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
using android::hidl::manager::V1_0::IServiceManager;
-using HidlHealth = android::hardware::health::V2_0::IHealth;
-using aidl::android::hardware::health::HealthShim;
-using ndk::ScopedAIBinder_DeathRecipient;
-using ndk::ScopedAStatus;
-
-HealthServicePair HealthServicePair::get() {
- HealthServicePair ret;
- auto service_name = IHealth::descriptor + "/default"s;
- if (AServiceManager_isDeclared(service_name.c_str())) {
- ndk::SpAIBinder binder(AServiceManager_waitForService(service_name.c_str()));
- ret.aidl_health = IHealth::fromBinder(binder);
- if (ret.aidl_health == nullptr) {
- LOG(WARNING) << "AIDL health service is declared, but it cannot be retrieved.";
- }
- }
- if (ret.aidl_health == nullptr) {
- LOG(INFO) << "Unable to get AIDL health service, trying HIDL...";
- ret.hidl_health = get_health_service();
- if (ret.hidl_health != nullptr) {
- ret.aidl_health = ndk::SharedRefBase::make<HealthShim>(ret.hidl_health);
- }
- }
- if (ret.aidl_health == nullptr) {
- LOG(WARNING) << "health: failed to find IHealth service";
- return {};
- }
- return ret;
-}
+
inline charger_stat_t is_charger_on(BatteryStatus prop) {
return (prop == BatteryStatus::CHARGING || prop == BatteryStatus::FULL) ?
CHARGER_ON : CHARGER_OFF;
}
-class HealthInfoCallback : public BnHealthInfoCallback {
- public:
- HealthInfoCallback(uid_monitor* uidm) : mUidm(uidm) {}
- ScopedAStatus healthInfoChanged(const HealthInfo& info) override {
- mUidm->set_charger_state(is_charger_on(info.batteryStatus));
- return ScopedAStatus::ok();
- }
-
- private:
- uid_monitor* mUidm;
-};
+Return<void> storaged_t::healthInfoChanged(const HealthInfo& props) {
+ mUidm.set_charger_state(is_charger_on(props.legacy.batteryStatus));
+ return android::hardware::Void();
+}
void storaged_t::init() {
init_health_service();
@@ -128,59 +91,42 @@ void storaged_t::init() {
storage_info.reset(storage_info_t::get_storage_info(health));
}
-static void onHealthBinderDied(void*) {
- LOG(ERROR) << "health service died, exiting";
- android::hardware::IPCThreadState::self()->stopProcess();
- exit(1);
-}
-
void storaged_t::init_health_service() {
if (!mUidm.enabled())
return;
- auto [aidlHealth, hidlHealth] = HealthServicePair::get();
- health = aidlHealth;
- if (health == nullptr) return;
+ health = get_health_service();
+ if (health == NULL) {
+ LOG(WARNING) << "health: failed to find IHealth service";
+ return;
+ }
BatteryStatus status = BatteryStatus::UNKNOWN;
- auto ret = health->getChargeStatus(&status);
+ auto ret = health->getChargeStatus([&](Result r, BatteryStatus v) {
+ if (r != Result::SUCCESS) {
+ LOG(WARNING) << "health: cannot get battery status " << toString(r);
+ return;
+ }
+ if (v == BatteryStatus::UNKNOWN) {
+ LOG(WARNING) << "health: invalid battery status";
+ }
+ status = v;
+ });
if (!ret.isOk()) {
- LOG(WARNING) << "health: cannot get battery status: " << ret.getDescription();
- }
- if (status == BatteryStatus::UNKNOWN) {
- LOG(WARNING) << "health: invalid battery status";
+ LOG(WARNING) << "health: get charge status transaction error " << ret.description();
}
mUidm.init(is_charger_on(status));
// register listener after init uid_monitor
- aidl_health_callback = ndk::SharedRefBase::make<HealthInfoCallback>(&mUidm);
- ret = health->registerCallback(aidl_health_callback);
- if (!ret.isOk()) {
- LOG(WARNING) << "health: failed to register callback: " << ret.getDescription();
- }
-
- if (hidlHealth != nullptr) {
- hidl_death_recp = new hidl_health_death_recipient(hidlHealth);
- auto ret = hidlHealth->linkToDeath(hidl_death_recp, 0 /* cookie */);
- if (!ret.isOk()) {
- LOG(WARNING) << "Failed to link to death (HIDL): " << ret.description();
- }
- } else {
- aidl_death_recp =
- ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(onHealthBinderDied));
- auto ret = AIBinder_linkToDeath(health->asBinder().get(), aidl_death_recp.get(),
- nullptr /* cookie */);
- if (ret != STATUS_OK) {
- LOG(WARNING) << "Failed to link to death (AIDL): "
- << ScopedAStatus(AStatus_fromStatus(ret)).getDescription();
- }
- }
+ health->registerCallback(this);
+ health->linkToDeath(this, 0 /* cookie */);
}
-void hidl_health_death_recipient::serviceDied(uint64_t cookie,
- const wp<::android::hidl::base::V1_0::IBase>& who) {
- if (mHealth != nullptr && interfacesEqual(mHealth, who.promote())) {
- onHealthBinderDied(reinterpret_cast<void*>(cookie));
+void storaged_t::serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) {
+ if (health != NULL && interfacesEqual(health, who.promote())) {
+ LOG(ERROR) << "health service died, exiting";
+ android::hardware::IPCThreadState::self()->stopProcess();
+ exit(1);
} else {
LOG(ERROR) << "unknown service died";
}
@@ -333,7 +279,7 @@ void storaged_t::flush_proto_data(userid_t user_id,
first_write = false;
}
- if (benchmark_size && benchmark_time_ns) {
+ if (benchmark_size) {
int perf = benchmark_size * 1000000LLU / benchmark_time_ns;
storage_info->update_perf_history(perf, system_clock::now());
}
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index 7085743fa..0614fadd1 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -3,6 +3,6 @@ service storaged /system/bin/storaged
capabilities DAC_READ_SEARCH
priority 10
file /d/mmc0/mmc0:0001/ext_csd r
- task_profiles ServiceCapacityLow
+ writepid /dev/cpuset/system-background/tasks
user root
group package_info
diff --git a/storaged/storaged_diskstats.cpp b/storaged/storaged_diskstats.cpp
index 1eae5a10b..52bd4e003 100644
--- a/storaged/storaged_diskstats.cpp
+++ b/storaged/storaged_diskstats.cpp
@@ -30,8 +30,11 @@
namespace {
-using aidl::android::hardware::health::DiskStats;
-using aidl::android::hardware::health::IHealth;
+using android::sp;
+using android::hardware::health::V2_0::DiskStats;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_0::toString;
#ifdef DEBUG
void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
@@ -118,30 +121,39 @@ void convert_hal_disk_stats(struct disk_stats* dst, const DiskStats& src) {
dst->io_in_queue = src.ioInQueue;
}
-bool get_disk_stats_from_health_hal(const std::shared_ptr<IHealth>& service,
- struct disk_stats* stats) {
+bool get_disk_stats_from_health_hal(const sp<IHealth>& service, struct disk_stats* stats) {
struct timespec ts;
if (!get_time(&ts)) {
return false;
}
- std::vector<DiskStats> halStats;
- auto ret = service->getDiskStats(&halStats);
- if (ret.isOk()) {
- if (halStats.size() > 0) {
- convert_hal_disk_stats(stats, halStats[0]);
- init_disk_stats_other(ts, stats);
- return true;
+ bool success = false;
+ auto ret = service->getDiskStats([&success, stats](auto result, const auto& halStats) {
+ if (result == Result::NOT_SUPPORTED) {
+ LOG(DEBUG) << "getDiskStats is not supported on health HAL.";
+ return;
+ }
+ if (result != Result::SUCCESS || halStats.size() == 0) {
+ LOG(ERROR) << "getDiskStats failed with result " << toString(result) << " and size "
+ << halStats.size();
+ return;
}
- LOG(ERROR) << "getDiskStats succeeded but size is 0";
+
+ convert_hal_disk_stats(stats, halStats[0]);
+ success = true;
+ });
+
+ if (!ret.isOk()) {
+ LOG(ERROR) << "getDiskStats failed with " << ret.description();
return false;
}
- if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
- LOG(DEBUG) << "getDiskStats is not supported on health HAL.";
+
+ if (!success) {
return false;
}
- LOG(ERROR) << "getDiskStats failed with " << ret.getDescription();
- return false;
+
+ init_disk_stats_other(ts, stats);
+ return true;
}
struct disk_perf get_disk_perf(struct disk_stats* stats)
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 3e646e006..bb2182919 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -36,8 +36,9 @@ using namespace chrono;
using namespace android::base;
using namespace storaged_proto;
-using aidl::android::hardware::health::IHealth;
-using aidl::android::hardware::health::StorageInfo;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_0::StorageInfo;
const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
const char* emmc_info_t::emmc_ver_str[9] = {
@@ -56,7 +57,7 @@ bool FileExists(const std::string& filename)
} // namespace
-storage_info_t* storage_info_t::get_storage_info(const shared_ptr<IHealth>& healthService) {
+storage_info_t* storage_info_t::get_storage_info(const sp<IHealth>& healthService) {
if (healthService != nullptr) {
return new health_storage_info_t(healthService);
}
@@ -325,22 +326,23 @@ void ufs_info_t::report()
}
void health_storage_info_t::report() {
- vector<StorageInfo> halInfos;
- auto ret = mHealth->getStorageInfo(&halInfos);
- if (ret.isOk()) {
- if (halInfos.size() != 0) {
- set_values_from_hal_storage_info(halInfos[0]);
- publish();
+ auto ret = mHealth->getStorageInfo([this](auto result, const auto& halInfos) {
+ if (result == Result::NOT_SUPPORTED) {
+ LOG(DEBUG) << "getStorageInfo is not supported on health HAL.";
return;
}
- LOG(ERROR) << "getStorageInfo succeeded but size is 0";
- return;
- }
- if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
- LOG(DEBUG) << "getStorageInfo is not supported on health HAL.";
- return;
+ if (result != Result::SUCCESS || halInfos.size() == 0) {
+ LOG(ERROR) << "getStorageInfo failed with result " << toString(result) << " and size "
+ << halInfos.size();
+ return;
+ }
+ set_values_from_hal_storage_info(halInfos[0]);
+ publish();
+ });
+
+ if (!ret.isOk()) {
+ LOG(ERROR) << "getStorageInfo failed with " << ret.description();
}
- LOG(ERROR) << "getStorageInfo failed with " << ret.getDescription();
}
void health_storage_info_t::set_values_from_hal_storage_info(const StorageInfo& halInfo) {
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index bb71bf3c2..64009c265 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -25,7 +25,6 @@
#include <gtest/gtest.h>
-#include <aidl/android/hardware/health/IHealth.h>
#include <healthhalutils/HealthHalUtils.h>
#include <storaged.h> // data structures
#include <storaged_utils.h> // functions to test
@@ -65,23 +64,20 @@ void write_and_pause(uint32_t sec) {
} // namespace
// the return values of the tested functions should be the expected ones
-const char* get_disk_stats_path() {
- if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
- return MMC_DISK_STATS_PATH;
- } else if (access(SDA_DISK_STATS_PATH, R_OK) >= 0) {
- return SDA_DISK_STATS_PATH;
- } else {
- return nullptr;
- }
-}
+const char* DISK_STATS_PATH;
TEST(storaged_test, retvals) {
struct disk_stats stats;
memset(&stats, 0, sizeof(struct disk_stats));
- auto disk_stats_path = get_disk_stats_path();
- if (disk_stats_path == nullptr) GTEST_SKIP();
+ if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
+ DISK_STATS_PATH = MMC_DISK_STATS_PATH;
+ } else if (access(SDA_DISK_STATS_PATH, R_OK) >= 0) {
+ DISK_STATS_PATH = SDA_DISK_STATS_PATH;
+ } else {
+ return;
+ }
- EXPECT_TRUE(parse_disk_stats(disk_stats_path, &stats));
+ EXPECT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
struct disk_stats old_stats;
memset(&old_stats, 0, sizeof(struct disk_stats));
@@ -96,9 +92,7 @@ TEST(storaged_test, retvals) {
TEST(storaged_test, disk_stats) {
struct disk_stats stats = {};
- auto disk_stats_path = get_disk_stats_path();
- if (disk_stats_path == nullptr) GTEST_SKIP();
- ASSERT_TRUE(parse_disk_stats(disk_stats_path, &stats));
+ ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
// every entry of stats (except io_in_flight) should all be greater than 0
for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
@@ -109,7 +103,7 @@ TEST(storaged_test, disk_stats) {
// accumulation of the increments should be the same with the overall increment
struct disk_stats base = {}, tmp = {}, curr, acc = {}, inc[5];
for (uint i = 0; i < 5; ++i) {
- ASSERT_TRUE(parse_disk_stats(disk_stats_path, &curr));
+ ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &curr));
if (i == 0) {
base = curr;
tmp = curr;
@@ -241,7 +235,9 @@ void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) {
}
TEST(storaged_test, disk_stats_monitor) {
- auto [healthService, hidlHealth] = HealthServicePair::get();
+ using android::hardware::health::V2_0::get_health_service;
+
+ auto healthService = get_health_service();
// asserting that there is one file for diskstats
ASSERT_TRUE(healthService != nullptr || access(MMC_DISK_STATS_PATH, R_OK) >= 0 ||
@@ -250,13 +246,6 @@ TEST(storaged_test, disk_stats_monitor) {
// testing if detect() will return the right value
disk_stats_monitor dsm_detect{healthService};
ASSERT_TRUE(dsm_detect.enabled());
-
- // Even if enabled(), healthService may not support disk stats. Check if it is supported.
- std::vector<aidl::android::hardware::health::DiskStats> halStats;
- if (healthService->getDiskStats(&halStats).getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
- GTEST_SKIP();
- }
-
// feed monitor with constant perf data for io perf baseline
// using constant perf is reasonable since the functionality of stream_stats
// has already been tested
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
index 20db63843..c0e9fce6e 100755
--- a/toolbox/generate-input.h-labels.py
+++ b/toolbox/generate-input.h-labels.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
#
# Copyright (C) 2015 The Android Open Source Project
#
@@ -16,7 +16,7 @@
#
# pylint: disable=bad-indentation,bad-continuation
-
+from __future__ import print_function
import os
import re
import sys
diff --git a/trusty/Android.bp b/trusty/Android.bp
index e73383939..38c6204db 100644
--- a/trusty/Android.bp
+++ b/trusty/Android.bp
@@ -14,5 +14,29 @@
// limitations under the License.
package {
- default_applicable_licenses: ["Android-Apache-2.0"],
+ default_applicable_licenses: ["system_core_trusty_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+ name: "system_core_trusty_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-MIT",
+ ],
+ // large-scale-change unable to identify any license_text files
}
diff --git a/trusty/apploader/apploader.cpp b/trusty/apploader/apploader.cpp
index 278499f17..4aca375fa 100644
--- a/trusty/apploader/apploader.cpp
+++ b/trusty/apploader/apploader.cpp
@@ -220,12 +220,6 @@ static ssize_t read_response(int tipc_fd) {
case APPLOADER_ERR_INTERNAL:
LOG(ERROR) << "Error: internal apploader error";
break;
- case APPLOADER_ERR_INVALID_VERSION:
- LOG(ERROR) << "Error: invalid application version";
- break;
- case APPLOADER_ERR_POLICY_VIOLATION:
- LOG(ERROR) << "Error: loading denied by policy engine";
- break;
default:
LOG(ERROR) << "Unrecognized error: " << resp.error;
break;
@@ -248,8 +242,6 @@ static ssize_t send_app_package(const char* package_file_name) {
tipc_fd = tipc_connect(dev_name, APPLOADER_PORT);
if (tipc_fd < 0) {
LOG(ERROR) << "Failed to connect to Trusty app loader: " << strerror(-tipc_fd);
- // print this to stderr too to avoid silently exiting when run as non-root
- fprintf(stderr, "Failed to connect to Trusty app loader: %s\n", strerror(-tipc_fd));
rc = tipc_fd;
goto err_tipc_connect;
}
diff --git a/trusty/apploader/apploader_ipc.h b/trusty/apploader/apploader_ipc.h
index 306596eba..d8c915eed 100644
--- a/trusty/apploader/apploader_ipc.h
+++ b/trusty/apploader/apploader_ipc.h
@@ -44,7 +44,6 @@ enum apploader_command : uint32_t {
* @APPLOADER_ERR_ALREADY_EXISTS: application has already been loaded
* @APPLOADER_ERR_INTERNAL: miscellaneous or internal apploader
* error not covered by the above
- * @APPLOADER_ERR_INVALID_VERSION: invalid application version
*/
enum apploader_error : uint32_t {
APPLOADER_NO_ERROR = 0,
@@ -55,8 +54,6 @@ enum apploader_error : uint32_t {
APPLOADER_ERR_LOADING_FAILED,
APPLOADER_ERR_ALREADY_EXISTS,
APPLOADER_ERR_INTERNAL,
- APPLOADER_ERR_INVALID_VERSION,
- APPLOADER_ERR_POLICY_VIOLATION,
};
/**
diff --git a/trusty/apploader/fuzz/Android.bp b/trusty/apploader/fuzz/Android.bp
index c961b36a2..e37dab1b0 100644
--- a/trusty/apploader/fuzz/Android.bp
+++ b/trusty/apploader/fuzz/Android.bp
@@ -25,10 +25,7 @@ cc_fuzz {
"-DTRUSTY_APP_PORT=\"com.android.trusty.apploader\"",
"-DTRUSTY_APP_UUID=\"081ba88f-f1ee-452e-b5e8-a7e9ef173a97\"",
"-DTRUSTY_APP_FILENAME=\"apploader.syms.elf\"",
- ],
- fuzz_config: {
- cc: ["trong@google.com"],
- },
+ ]
}
// Fuzz app package sent to apploader.
@@ -40,7 +37,4 @@ cc_fuzz {
shared_libs: [
"libdmabufheap",
],
- fuzz_config: {
- cc: ["trong@google.com"],
- },
}
diff --git a/trusty/confirmationui/fuzz/Android.bp b/trusty/confirmationui/fuzz/Android.bp
index 47809433a..ba571914d 100644
--- a/trusty/confirmationui/fuzz/Android.bp
+++ b/trusty/confirmationui/fuzz/Android.bp
@@ -25,9 +25,6 @@ cc_fuzz {
"-DTRUSTY_APP_UUID=\"7dee2364-c036-425b-b086-df0f6c233c1b\"",
"-DTRUSTY_APP_FILENAME=\"confirmationui.syms.elf\"",
],
- fuzz_config: {
- cc: ["trong@google.com"],
- },
}
@@ -39,9 +36,6 @@ cc_fuzz {
shared_libs: [
"libdmabufheap",
],
- fuzz_config: {
- cc: ["trong@google.com"],
- },
// The initial corpus for this fuzzer was derived by dumping messages from/to
// HAL to/from TA triggered by VtsHalConfirmationUIV1_0TargetTest.
diff --git a/trusty/confirmationui/fuzz/msg_fuzzer.cpp b/trusty/confirmationui/fuzz/msg_fuzzer.cpp
index ee55f828d..8e4443c78 100644
--- a/trusty/confirmationui/fuzz/msg_fuzzer.cpp
+++ b/trusty/confirmationui/fuzz/msg_fuzzer.cpp
@@ -37,7 +37,7 @@ using android::trusty::fuzz::TrustyApp;
#define CONFIRMATIONUI_MODULE_NAME "confirmationui.syms.elf"
/* A request to render to screen may take a while. */
-const size_t kTimeoutSeconds = 60;
+const size_t kTimeoutSeconds = 30;
/* ConfirmationUI TA's UUID is 7dee2364-c036-425b-b086-df0f6c233c1b */
static struct uuid confirmationui_uuid = {
diff --git a/trusty/fuzz/counters.cpp b/trusty/fuzz/counters.cpp
index 65a3ba6f4..c28fd05a5 100644
--- a/trusty/fuzz/counters.cpp
+++ b/trusty/fuzz/counters.cpp
@@ -33,7 +33,7 @@ using android::base::Result;
* We don't know how many counters the coverage record will contain. So, eyeball
* the size of this section.
*/
-static const size_t kMaxNumCounters = 0x10000;
+static const size_t kMaxNumCounters = 0x8000;
__attribute__((section("__libfuzzer_extra_counters"))) volatile uint8_t counters[kMaxNumCounters];
namespace android {
diff --git a/trusty/gatekeeper/fuzz/Android.bp b/trusty/gatekeeper/fuzz/Android.bp
index 67d0c0fbf..d084cb6b2 100644
--- a/trusty/gatekeeper/fuzz/Android.bp
+++ b/trusty/gatekeeper/fuzz/Android.bp
@@ -25,9 +25,6 @@ cc_fuzz {
"-DTRUSTY_APP_UUID=\"38ba0cdc-df0e-11e4-9869-233fb6ae4795\"",
"-DTRUSTY_APP_FILENAME=\"gatekeeper.syms.elf\"",
],
- fuzz_config: {
- cc: ["trong@google.com"],
- },
// The initial corpus for this fuzzer was derived by dumping messages from
// the `secure_env` emulator interface for cuttlefish while enrolling a new
diff --git a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
index 443a67021..d787f7a97 100644
--- a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
+++ b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
@@ -17,10 +17,9 @@
#define LOG_TAG "android.hardware.keymaster@3.0-impl.trusty"
+#include <authorization_set.h>
#include <cutils/log.h>
#include <keymaster/android_keymaster_messages.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster_tags.h>
#include <trusty_keymaster/TrustyKeymaster3Device.h>
#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
diff --git a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
index 9c7e781a8..e68ba82dc 100644
--- a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
+++ b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
@@ -18,10 +18,9 @@
#define LOG_TAG "android.hardware.keymaster@4.0-impl.trusty"
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+#include <authorization_set.h>
#include <cutils/log.h>
#include <keymaster/android_keymaster_messages.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster_tags.h>
#include <trusty_keymaster/TrustyKeymaster4Device.h>
#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 0e916ef37..cf056f091 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -105,12 +105,10 @@ cc_binary {
"keymint/TrustySharedSecret.cpp",
"keymint/service.cpp",
],
- defaults: [
- "keymint_use_latest_hal_aidl_ndk_shared",
- ],
shared_libs: [
- "android.hardware.security.secureclock-V1-ndk",
- "android.hardware.security.sharedsecret-V1-ndk",
+ "android.hardware.security.keymint-V1-ndk_platform",
+ "android.hardware.security.secureclock-V1-ndk_platform",
+ "android.hardware.security.sharedsecret-V1-ndk_platform",
"lib_android_keymaster_keymint_utils",
"libbase",
"libbinder_ndk",
@@ -119,7 +117,6 @@ cc_binary {
"libkeymint",
"liblog",
"libtrusty",
- "libutils",
],
required: [
"android.hardware.hardware_keystore.xml",
@@ -145,7 +142,6 @@ cc_library {
"libtrusty",
"libhardware",
"libkeymaster_messages",
- "libutils",
"libxml2",
],
export_include_dirs: ["include"],
@@ -173,7 +169,6 @@ cc_binary {
"libtrusty",
"libhardware",
"libkeymaster_messages",
- "libutils",
"libxml2",
],
cflags: [
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index e77940a1f..cdfbd9003 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -279,10 +279,4 @@ ConfigureVendorPatchlevelResponse TrustyKeymaster::ConfigureVendorPatchlevel(
return response;
}
-GetRootOfTrustResponse TrustyKeymaster::GetRootOfTrust(const GetRootOfTrustRequest& request) {
- GetRootOfTrustResponse response(message_version());
- ForwardCommand(KM_GET_ROOT_OF_TRUST, request, &response);
- return response;
-}
-
} // namespace keymaster
diff --git a/trusty/keymaster/fuzz/Android.bp b/trusty/keymaster/fuzz/Android.bp
index 5f24bc620..8d7ee0066 100644
--- a/trusty/keymaster/fuzz/Android.bp
+++ b/trusty/keymaster/fuzz/Android.bp
@@ -25,9 +25,6 @@ cc_fuzz {
"-DTRUSTY_APP_UUID=\"5f902ace-5e5c-4cd8-ae54-87b88c22ddaf\"",
"-DTRUSTY_APP_FILENAME=\"keymaster.syms.elf\"",
],
- fuzz_config: {
- cc: ["trong@google.com"],
- },
// The initial corpus for this fuzzer was derived by dumping messages from
// the `secure_env` emulator interface for cuttlefish while running the
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h
index c8d8932c4..5fd628f3c 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h
@@ -27,7 +27,6 @@ namespace aidl::android::hardware::security::keymint::trusty {
using ::keymaster::TrustyKeymaster;
using ::ndk::ScopedAStatus;
using secureclock::TimeStampToken;
-using ::std::array;
using ::std::optional;
using ::std::shared_ptr;
using ::std::vector;
@@ -78,13 +77,8 @@ class TrustyKeyMintDevice : public BnKeyMintDevice {
const optional<TimeStampToken>& timestampToken) override;
ScopedAStatus earlyBootEnded() override;
- ScopedAStatus convertStorageKeyToEphemeral(const vector<uint8_t>& storageKeyBlob,
- vector<uint8_t>* ephemeralKeyBlob) override;
-
- ScopedAStatus getRootOfTrustChallenge(array<uint8_t, 16>* challenge) override;
- ScopedAStatus getRootOfTrust(const array<uint8_t, 16>& challenge,
- vector<uint8_t>* rootOfTrust) override;
- ScopedAStatus sendRootOfTrust(const vector<uint8_t>& rootOfTrust) override;
+ ScopedAStatus convertStorageKeyToEphemeral(const std::vector<uint8_t>& storageKeyBlob,
+ std::vector<uint8_t>* ephemeralKeyBlob) override;
protected:
std::shared_ptr<TrustyKeymaster> impl_;
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index 9f4f39bf5..f80e02f37 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -66,7 +66,6 @@ class TrustyKeymaster {
DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
ConfigureVendorPatchlevelResponse ConfigureVendorPatchlevel(
const ConfigureVendorPatchlevelRequest& request);
- GetRootOfTrustResponse GetRootOfTrust(const GetRootOfTrustRequest& request);
uint32_t message_version() const { return message_version_; }
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index bf0cb703f..fa475ae90 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -59,7 +59,6 @@ enum keymaster_command : uint32_t {
KM_GENERATE_RKP_KEY = (31 << KEYMASTER_REQ_SHIFT),
KM_GENERATE_CSR = (32 << KEYMASTER_REQ_SHIFT),
KM_CONFIGURE_VENDOR_PATCHLEVEL = (33 << KEYMASTER_REQ_SHIFT),
- KM_GET_ROOT_OF_TRUST = (34 << KEYMASTER_REQ_SHIFT),
// Bootloader/provisioning calls.
KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
diff --git a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
index db1a9f407..2d4400989 100644
--- a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
@@ -19,7 +19,6 @@
// TODO: make this generic in libtrusty
#include <errno.h>
-#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
@@ -34,15 +33,11 @@
#include <trusty_keymaster/ipc/keymaster_ipc.h>
#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
-#include <utils/Timers.h>
#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
static int handle_ = -1;
-static const int timeout_ms = 10 * 1000;
-static const int max_timeout_ms = 60 * 1000;
-
int trusty_keymaster_connect() {
int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
if (rc < 0) {
@@ -89,38 +84,7 @@ std::variant<int, std::vector<uint8_t>> trusty_keymaster_call_2(uint32_t cmd, vo
msg->cmd = cmd;
memcpy(msg->payload, in, in_size);
- nsecs_t start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
- bool timed_out = false;
- int poll_timeout_ms = timeout_ms;
- while (true) {
- struct pollfd pfd;
- pfd.fd = handle_;
- pfd.events = POLLOUT;
- pfd.revents = 0;
-
- int p = poll(&pfd, 1, poll_timeout_ms);
- if (p == 0) {
- ALOGW("write for cmd %d is taking more than %lld nsecs", cmd,
- (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
- timed_out = true;
- poll_timeout_ms *= 2;
- if (poll_timeout_ms > max_timeout_ms) {
- poll_timeout_ms = max_timeout_ms;
- }
- continue;
- } else if (p < 0) {
- ALOGE("write poll error: %d", errno);
- } else if (pfd.revents != POLLOUT) {
- ALOGW("unexpected poll() result: %d", pfd.revents);
- }
- break;
- }
-
ssize_t rc = write(handle_, msg, msg_size);
- if (timed_out) {
- ALOGW("write for cmd %d finished after %lld nsecs", cmd,
- (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
- }
free(msg);
if (rc < 0) {
@@ -158,37 +122,8 @@ std::variant<int, std::vector<uint8_t>> trusty_keymaster_call_2(uint32_t cmd, vo
return -EOVERFLOW;
}
iov[1] = {.iov_base = write_pos, .iov_len = buffer_size};
- start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
- timed_out = false;
- poll_timeout_ms = timeout_ms;
- while (true) {
- struct pollfd pfd;
- pfd.fd = handle_;
- pfd.events = POLLIN;
- pfd.revents = 0;
-
- int p = poll(&pfd, 1, poll_timeout_ms);
- if (p == 0) {
- ALOGW("readv for cmd %d is taking more than %lld nsecs", cmd,
- (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
- timed_out = true;
- poll_timeout_ms *= 2;
- if (poll_timeout_ms > max_timeout_ms) {
- poll_timeout_ms = max_timeout_ms;
- }
- continue;
- } else if (p < 0) {
- ALOGE("read poll error: %d", errno);
- } else if (pfd.revents != POLLIN) {
- ALOGW("unexpected poll() result: %d", pfd.revents);
- }
- break;
- }
+
rc = readv(handle_, iov, 2);
- if (timed_out) {
- ALOGW("readv for cmd %d finished after %lld nsecs", cmd,
- (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
- }
if (rc < 0) {
ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
strerror(errno));
diff --git a/trusty/keymaster/keymint/TEST_MAPPING b/trusty/keymaster/keymint/TEST_MAPPING
deleted file mode 100644
index ae24fb4d0..000000000
--- a/trusty/keymaster/keymint/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit" : [
- {
- "name" : "vts_treble_vintf_framework_test"
- }
- ],
- "hwasan-postsubmit" : [
- {
- "name" : "vts_treble_vintf_framework_test"
- }
- ]
-} \ No newline at end of file
diff --git a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
index 7d58162cc..5f8524b01 100644
--- a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
+++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
@@ -91,7 +91,7 @@ void addClientAndAppData(const vector<uint8_t>& clientId, const vector<uint8_t>&
} // namespace
ScopedAStatus TrustyKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
- info->versionNumber = 2;
+ info->versionNumber = 1;
info->securityLevel = kSecurityLevel;
info->keyMintName = "TrustyKeyMintDevice";
info->keyMintAuthorName = "Google";
@@ -306,7 +306,7 @@ ScopedAStatus TrustyKeyMintDevice::earlyBootEnded() {
}
ScopedAStatus TrustyKeyMintDevice::convertStorageKeyToEphemeral(
- const vector<uint8_t>& storageKeyBlob, vector<uint8_t>* ephemeralKeyBlob) {
+ const std::vector<uint8_t>& storageKeyBlob, std::vector<uint8_t>* ephemeralKeyBlob) {
keymaster::ExportKeyRequest request(impl_->message_version());
request.SetKeyMaterial(storageKeyBlob.data(), storageKeyBlob.size());
request.key_format = KM_KEY_FORMAT_RAW;
@@ -321,28 +321,4 @@ ScopedAStatus TrustyKeyMintDevice::convertStorageKeyToEphemeral(
return ScopedAStatus::ok();
}
-ScopedAStatus TrustyKeyMintDevice::getRootOfTrustChallenge(array<uint8_t, 16>* /* challenge */) {
- return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
-}
-
-ScopedAStatus TrustyKeyMintDevice::getRootOfTrust(const array<uint8_t, 16>& challenge,
- vector<uint8_t>* rootOfTrust) {
- if (!rootOfTrust) {
- return kmError2ScopedAStatus(KM_ERROR_UNEXPECTED_NULL_POINTER);
- }
- keymaster::GetRootOfTrustRequest request(impl_->message_version(),
- {challenge.begin(), challenge.end()});
- keymaster::GetRootOfTrustResponse response = impl_->GetRootOfTrust(request);
- if (response.error != KM_ERROR_OK) {
- return kmError2ScopedAStatus(response.error);
- }
-
- *rootOfTrust = std::move(response.rootOfTrust);
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus TrustyKeyMintDevice::sendRootOfTrust(const vector<uint8_t>& /* rootOfTrust */) {
- return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
-}
-
} // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
index 78e765e9c..9440724da 100644
--- a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
+++ b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
@@ -52,15 +52,11 @@ TrustyKeyMintOperation::~TrustyKeyMintOperation() {
}
ScopedAStatus TrustyKeyMintOperation::updateAad(
- const vector<uint8_t>& input, const optional<HardwareAuthToken>& authToken,
+ const vector<uint8_t>& input, const optional<HardwareAuthToken>& /* authToken */,
const optional<TimeStampToken>& /* timestampToken */) {
UpdateOperationRequest request(impl_->message_version());
request.op_handle = opHandle_;
request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(), input.size());
- if (authToken) {
- auto tokenAsVec(authToken2AidlVec(*authToken));
- request.additional_params.push_back(TAG_AUTH_TOKEN, tokenAsVec.data(), tokenAsVec.size());
- }
UpdateOperationResponse response(impl_->message_version());
impl_->UpdateOperation(request, &response);
diff --git a/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
index 099f18961..5664829d8 100644
--- a/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
+++ b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
@@ -71,10 +71,9 @@ class Status {
} // namespace
ScopedAStatus TrustyRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
- info->versionNumber = 2;
+ info->versionNumber = 1;
info->rpcAuthorName = "Google";
info->supportedEekCurve = RpcHardwareInfo::CURVE_25519;
- info->uniqueId = "Trusty: My password is ******";
return ScopedAStatus::ok();
}
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
index 0b995a282..7ca50507d 100644
--- a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
@@ -1,7 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.security.keymint</name>
- <version>2</version>
<fqname>IKeyMintDevice/default</fqname>
</hal>
<hal format="aidl">
@@ -14,7 +13,6 @@
</hal>
<hal format="aidl">
<name>android.hardware.security.keymint</name>
- <version>2</version>
<fqname>IRemotelyProvisionedComponent/default</fqname>
</hal>
</manifest>
diff --git a/trusty/keymaster/keymint/service.cpp b/trusty/keymaster/keymint/service.cpp
index 3447b27b4..4060278d4 100644
--- a/trusty/keymaster/keymint/service.cpp
+++ b/trusty/keymaster/keymint/service.cpp
@@ -31,7 +31,7 @@ using aidl::android::hardware::security::sharedsecret::trusty::TrustySharedSecre
template <typename T, class... Args>
std::shared_ptr<T> addService(Args&&... args) {
- std::shared_ptr<T> service = ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
+ std::shared_ptr<T> service = std::make_shared<T>(std::forward<Args>(args)...);
auto instanceName = std::string(T::descriptor) + "/default";
LOG(ERROR) << "Adding service instance: " << instanceName;
auto status = AServiceManager_addService(service->asBinder().get(), instanceName.c_str());
@@ -41,7 +41,7 @@ std::shared_ptr<T> addService(Args&&... args) {
int main() {
auto trustyKeymaster = std::make_shared<keymaster::TrustyKeymaster>();
- int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMINT_2);
+ int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMINT_1);
if (err != 0) {
LOG(FATAL) << "Could not initialize TrustyKeymaster for KeyMint (" << err << ")";
return -1;
diff --git a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
index e2f376c39..df6b0f833 100644
--- a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
+++ b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
@@ -342,19 +342,6 @@ static int parse_xml_file(const char* filename) {
return 0;
}
-static int provision_ids(void) {
- keymaster::SetAttestationIdsRequest req(4 /* ver */);
- keymaster::EmptyKeymasterResponse rsp(4 /* ver */);
-
- req.brand.Reinitialize("trusty", 6);
- req.device.Reinitialize("trusty", 6);
- req.product.Reinitialize("trusty", 6);
- req.manufacturer.Reinitialize("trusty", 6);
- req.model.Reinitialize("trusty", 6);
-
- return trusty_keymaster_send(KM_SET_ATTESTATION_IDS, req, &rsp);
-}
-
int main(int argc, char** argv) {
int ret = 0;
@@ -366,22 +353,10 @@ int main(int argc, char** argv) {
ret = trusty_keymaster_connect();
if (ret) {
fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
- return EXIT_FAILURE;
- }
-
- ret = parse_xml_file(argv[optind]);
- if (ret) {
- fprintf(stderr, "parse_xml_file failed %d\n", ret);
- trusty_keymaster_disconnect();
- return EXIT_FAILURE;
- }
-
- ret = provision_ids();
- if (ret) {
- fprintf(stderr, "provision_ids failed %d\n", ret);
+ } else {
+ ret = parse_xml_file(argv[optind]);
trusty_keymaster_disconnect();
- return EXIT_FAILURE;
}
- return EXIT_SUCCESS;
+ return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/trusty/libtrusty-rs/Android.bp b/trusty/libtrusty-rs/Android.bp
deleted file mode 100644
index bc1dcf68e..000000000
--- a/trusty/libtrusty-rs/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-rust_library {
- name: "libtrusty-rs",
- crate_name: "trusty",
- srcs: [
- "src/lib.rs"
- ],
- rustlibs: [
- "libnix",
- "liblibc",
- ],
-}
-
-rust_test {
- name: "libtrusty-rs-tests",
- crate_name: "trusty_test",
- srcs: ["tests/test.rs"],
- rustlibs: [
- "libtrusty-rs",
- "liblibc",
- ]
-}
diff --git a/trusty/libtrusty-rs/src/lib.rs b/trusty/libtrusty-rs/src/lib.rs
deleted file mode 100644
index 28ea07505..000000000
--- a/trusty/libtrusty-rs/src/lib.rs
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Functionality for communicating with Trusty services.
-//!
-//! This crate provides the [`TipcChannel`] type, which allows you to establish a
-//! connection to a Trusty service and then communicate with that service.
-//!
-//! # Usage
-//!
-//! To connect to a Trusty service you need two things:
-//!
-//! * The filesystem path to the Trusty IPC device. This is usually
-//! `/dev/trusty-ipc-dev0`, which is exposed in the constant [`DEFAULT_DEVICE`].
-//! * The port name defined by the service, e.g. `com.android.ipc-unittest.srv.echo`.
-//!
-//! Pass these values to [`TipcChannel::connect`] to establish a connection to a
-//! service.
-//!
-//! Once connected use the [`send`][TipcChannel::send] and [`recv`][TipcChannel::recv]
-//! methods to communicate with the service. Messages are passed as byte buffers, and
-//! each Trusty service has its own protocol for what data messages are expected to
-//! contain. Consult the documentation for the service you are communicating with to
-//! determine how to format outgoing messages and interpret incoming ones.
-//!
-//! The connection is closed automatically when [`TipcChannel`] is dropped.
-//!
-//! # Examples
-//!
-//! This example is a simplified version of the echo test from `tipc-test-rs`:
-//!
-//! ```no_run
-//! use trusty::{DEFAULT_DEVICE, TipcChannel};
-//! use std::io::{Read, Write};
-//!
-//! let mut chann = TipcChannel::connect(
-//! DEFAULT_DEVICE,
-//! "com.android.ipc-unittest.srv.echo",
-//! ).unwrap();
-//!
-//! chann.send("Hello, world!".as_bytes()).unwrap();
-//!
-//! let mut read_buf = Vec::new();
-//! let read_len = stream.recv(&mut read_buf).unwrap();
-//!
-//! let response = std::str::from_utf8(&read_buf[..read_len]).unwrap();
-//! assert_eq!("Hello, world!", response);
-//!
-//! // The connection is closed here.
-//! ```
-
-use crate::sys::tipc_connect;
-use std::ffi::CString;
-use std::fs::File;
-use std::io::prelude::*;
-use std::io::{ErrorKind, Result};
-use std::os::unix::prelude::AsRawFd;
-use std::path::Path;
-
-mod sys;
-
-/// The default filesystem path for the Trusty IPC device.
-pub const DEFAULT_DEVICE: &str = "/dev/trusty-ipc-dev0";
-
-/// The maximum size an incoming TIPC message can be.
-///
-/// This can be used to pre-allocate buffer space in order to ensure that your
-/// read buffer can always hold an incoming message.
-pub const MAX_MESSAGE_SIZE: usize = 4096;
-
-/// A channel for communicating with a Trusty service.
-///
-/// See the [crate-level documentation][crate] for usage details and examples.
-#[derive(Debug)]
-pub struct TipcChannel(File);
-
-impl TipcChannel {
- /// Attempts to establish a connection to the specified Trusty service.
- ///
- /// The first argument is the path of the Trusty device in the local filesystem,
- /// e.g. `/dev/trusty-ipc-dev0`. The second argument is the name of the service
- /// to connect to, e.g. `com.android.ipc-unittest.srv.echo`.
- ///
- /// # Panics
- ///
- /// This function will panic if `service` contains any intermediate `NUL`
- /// bytes. This is handled with a panic because the service names are all
- /// hard-coded constants, and so such an error should always be indicative of a
- /// bug in the calling code.
- pub fn connect(device: impl AsRef<Path>, service: &str) -> Result<Self> {
- let file = File::options().read(true).write(true).open(device)?;
-
- let srv_name = CString::new(service).expect("Service name contained null bytes");
- unsafe {
- tipc_connect(file.as_raw_fd(), srv_name.as_ptr())?;
- }
-
- Ok(TipcChannel(file))
- }
-
- /// Sends a message to the connected service.
- ///
- /// The entire contents of `buf` will be sent as a single message to the
- /// connected service.
- pub fn send(&mut self, buf: &[u8]) -> Result<()> {
- let write_len = self.0.write(buf)?;
-
- // Verify that the expected number of bytes were written. The entire message
- // should always be written with a single `write` call, or an error should have
- // been returned if the message couldn't be written. An assertion failure here
- // potentially means a bug in the kernel driver.
- assert_eq!(
- buf.len(),
- write_len,
- "Failed to send full message ({} of {} bytes written)",
- write_len,
- buf.len(),
- );
-
- Ok(())
- }
-
- /// Reads the next incoming message.
- ///
- /// Attempts to read the next incoming message from the connected service if any
- /// exist. If the initial capacity of `buf` is not enough to hold the incoming
- /// message the function repeatedly attempts to reserve additional space until
- /// it is able to fully read the message.
- ///
- /// Blocks until there is an incoming message if there is not already a message
- /// ready to be received.
- ///
- /// # Errors
- ///
- /// If this function encounters an error of the kind [`ErrorKind::Interrupted`]
- /// then the error is ignored and the operation will be tried again.
- ///
- /// If this function encounters an error with the error code `EMSGSIZE` then
- /// additional space will be reserved in `buf` and the operation will be tried
- /// again.
- ///
- /// If any other read error is encountered then this function immediately
- /// returns the error to the caller, and the length of `buf` is set to 0.
- pub fn recv(&mut self, buf: &mut Vec<u8>) -> Result<()> {
- // If no space has been allocated in the buffer reserve enough space to hold any
- // incoming message.
- if buf.capacity() == 0 {
- buf.reserve(MAX_MESSAGE_SIZE);
- }
-
- loop {
- // Resize the vec to make its full capacity available to write into.
- buf.resize(buf.capacity(), 0);
-
- match self.0.read(buf.as_mut_slice()) {
- Ok(len) => {
- buf.truncate(len);
- return Ok(());
- }
-
- Err(err) => {
- if let Some(libc::EMSGSIZE) = err.raw_os_error() {
- // Ensure that we didn't get `EMSGSIZE` when we already had enough capacity
- // to contain the maximum message size. This should never happen, but if it
- // does we don't want to hang by looping infinitely.
- assert!(
- buf.capacity() < MAX_MESSAGE_SIZE,
- "Received `EMSGSIZE` error when buffer capacity was already at maximum",
- );
-
- // If we didn't have enough space to hold the incoming message, reserve
- // enough space to fit the maximum message size regardless of how much
- // capacity the buffer already had.
- buf.reserve(MAX_MESSAGE_SIZE - buf.capacity());
- } else if err.kind() == ErrorKind::Interrupted {
- // If we get an interrupted error the operation can be retried as-is, i.e.
- // we don't need to allocate additional space.
- continue;
- } else {
- buf.truncate(0);
- return Err(err);
- }
- }
- }
- }
- }
-
- /// Reads the next incoming message without allocating.
- ///
- /// Returns the number of bytes in the received message, or any error that
- /// occurred when reading the message.
- ///
- /// Blocks until there is an incoming message if there is not already a message
- /// ready to be received.
- ///
- /// # Errors
- ///
- /// Returns an error with native error code `EMSGSIZE` if `buf` isn't large
- /// enough to contain the incoming message. Use
- /// [`raw_os_error`][std::io::Error::raw_os_error] to check the error code to
- /// determine if you need to increase the size of `buf`. If error code
- /// `EMSGSIZE` is returned the incoming message will not be dropped, and a
- /// subsequent call to `recv_no_alloc` can still read it.
- ///
- /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read
- /// operation should be retried if there is nothing else to do.
- pub fn recv_no_alloc(&mut self, buf: &mut [u8]) -> Result<usize> {
- self.0.read(buf)
- }
-
- // TODO: Add method that is equivalent to `tipc_send`, i.e. that supports
- // sending shared memory buffers.
-}
diff --git a/trusty/libtrusty-rs/src/sys.rs b/trusty/libtrusty-rs/src/sys.rs
deleted file mode 100644
index f1c8c5f14..000000000
--- a/trusty/libtrusty-rs/src/sys.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// NOTE: The ioctl definitions are sequestered into this module because the
-// `ioctl_*!` macros provided by the nix crate generate public functions that we
-// don't want to be part of this crate's public API.
-//
-// NOTE: We are manually re-declaring the types and constants here instead of using
-// bindgen and a separate `-sys` crate because the defines used for the ioctl
-// numbers (`TIPC_IOC_CONNECT` and `TIPC_IOC_SEND_MSG`) can't currently be
-// translated by bindgen.
-
-use std::os::raw::c_char;
-
-const TIPC_IOC_MAGIC: u8 = b'r';
-
-// NOTE: We use `ioctl_write_ptr_bad!` here due to an error in how the ioctl
-// code is defined in `trusty/ipc.h`.
-//
-// If we were to do `ioctl_write_ptr!(TIPC_IOC_MAGIC, 0x80, c_char)` it would
-// generate a function that takes a `*const c_char` data arg and would use
-// `size_of::<c_char>()` when generating the ioctl number. However, in
-// `trusty/ipc.h` the definition for `TIPC_IOC_CONNECT` declares the ioctl with
-// `char*`, meaning we need to use `size_of::<*const c_char>()` to generate an
-// ioctl number that matches what Trusty expects.
-//
-// To maintain compatibility with the `trusty/ipc.h` and the kernel driver we
-// use `ioctl_write_ptr_bad!` and manually use `request_code_write!` to generate
-// the ioctl number using the correct size.
-nix::ioctl_write_ptr_bad!(
- tipc_connect,
- nix::request_code_write!(TIPC_IOC_MAGIC, 0x80, std::mem::size_of::<*const c_char>()),
- c_char
-);
diff --git a/trusty/libtrusty-rs/tests/test.rs b/trusty/libtrusty-rs/tests/test.rs
deleted file mode 100644
index 6bff47909..000000000
--- a/trusty/libtrusty-rs/tests/test.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use trusty::{TipcChannel, DEFAULT_DEVICE};
-
-const ECHO_NAME: &str = "com.android.ipc-unittest.srv.echo";
-
-#[test]
-fn recv_no_alloc() {
- let mut connection = TipcChannel::connect(DEFAULT_DEVICE, ECHO_NAME)
- .expect("Failed to connect to Trusty service");
-
- // Send a message to the echo TA.
- let send_buf = [7u8; 32];
- connection.send(send_buf.as_slice()).unwrap();
-
- // Receive the response message from the TA. The response message will be the
- // same as the message we just sent.
- let mut recv_buf = [0u8; 32];
- let read_len = connection.recv_no_alloc(recv_buf.as_mut_slice()).unwrap();
-
- assert_eq!(
- send_buf.len(),
- read_len,
- "Received data was wrong size (expected {} bytes, received {})",
- send_buf.len(),
- read_len,
- );
- assert_eq!(send_buf, recv_buf, "Received data does not match sent data");
-}
-
-#[test]
-fn recv_small_buf() {
- let mut connection = TipcChannel::connect(DEFAULT_DEVICE, ECHO_NAME)
- .expect("Failed to connect to Trusty service");
-
- // Send a long message to the echo service so that we can test receiving a long
- // message.
- let send_buf = [7u8; 2048];
- connection.send(send_buf.as_slice()).unwrap();
-
- // Attempt to receive the response message with a buffer that is too small to
- // contain the message.
- let mut recv_buf = [0u8; 32];
- let err = connection.recv_no_alloc(recv_buf.as_mut_slice()).unwrap_err();
-
- assert_eq!(
- Some(libc::EMSGSIZE),
- err.raw_os_error(),
- "Unexpected error err when receiving incoming message: {:?}",
- err,
- );
-}
-
-#[test]
-fn recv_empty_vec() {
- let mut connection = TipcChannel::connect(DEFAULT_DEVICE, ECHO_NAME)
- .expect("Failed to connect to Trusty service");
-
- // Send a message to the echo TA.
- let send_buf = [7u8; 2048];
- connection.send(send_buf.as_slice()).unwrap();
-
- // Receive the response message. `recv_buf` is initially empty, and `recv` is
- // responsible for allocating enough space to hold the message.
- let mut recv_buf = Vec::new();
- connection.recv(&mut recv_buf).unwrap();
-
- assert_eq!(send_buf.as_slice(), recv_buf, "Received data does not match sent data");
-}
-
-#[test]
-fn recv_vec_existing_capacity() {
- let mut connection = TipcChannel::connect(DEFAULT_DEVICE, ECHO_NAME)
- .expect("Failed to connect to Trusty service");
-
- // Send a message to the echo TA.
- let send_buf = [7u8; 2048];
- connection.send(send_buf.as_slice()).unwrap();
-
- // Receive the response message into a buffer that already has enough capacity
- // to hold the message. No additional capacity should be allocated when
- // receiving the message.
- let mut recv_buf = Vec::with_capacity(2048);
- connection.recv(&mut recv_buf).unwrap();
-
- assert_eq!(send_buf.as_slice(), recv_buf, "Received data does not match sent data");
- assert_eq!(2048, recv_buf.capacity(), "Additional capacity was allocated when not needed");
-}
diff --git a/trusty/libtrusty/include/trusty/ipc.h b/trusty/libtrusty/include/trusty/ipc.h
index 04e84c650..1fa6fe4aa 100644
--- a/trusty/libtrusty/include/trusty/ipc.h
+++ b/trusty/libtrusty/include/trusty/ipc.h
@@ -23,19 +23,15 @@
/**
* enum transfer_kind - How to send an fd to Trusty
- * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it
- * will be mapped as nonsecure. Suitable for shared memory.
- * The paired fd must be a "dma_buf".
- * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will
- * be transitioned to "Secure" memory if Trusty is in
- * TrustZone. This transfer kind is suitable for donating
- * video buffers or other similar resources. The paired fd
- * may need to come from a platform-specific allocator for
- * memory that may be transitioned to "Secure".
- * @TRUSTY_SEND_SECURE: Send memory that is already "Secure". Memory will be
- * accessible only to Trusty. The paired fd may need to
- * come from a platform-specific allocator that returns
- * "Secure" buffers.
+ * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it will
+ * be mapped as nonsecure. Suitable for shared memory. The paired
+ * fd must be a "memfd".
+ * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will be
+ * transitioned to "Secure" memory if Trusty is in TrustZone.
+ * This transfer kind is suitable for donating video buffers or
+ * other similar resources. The paired fd may need to come from a
+ * platform-specific allocator for memory that may be
+ * transitioned to "Secure".
*
* Describes how the user would like the resource in question to be sent to
* Trusty. Options may be valid only for certain kinds of fds.
@@ -43,7 +39,6 @@
enum transfer_kind {
TRUSTY_SHARE = 0,
TRUSTY_LEND = 1,
- TRUSTY_SEND_SECURE = 2,
};
/**
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index eb0acb5f5..29c6f939f 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -45,40 +45,36 @@ static const char *closer3_name = "com.android.ipc-unittest.srv.closer3";
static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
static const char* receiver_name = "com.android.trusty.memref.receiver";
-static const char* _sopts = "hsvDS:t:r:m:b:";
-/* clang-format off */
+static const char *_sopts = "hsvD:t:r:m:b:";
static const struct option _lopts[] = {
- {"help", no_argument, 0, 'h'},
- {"silent", no_argument, 0, 's'},
- {"variable",no_argument, 0, 'v'},
- {"dev", required_argument, 0, 'D'},
- {"srv", required_argument, 0, 'S'},
- {"repeat", required_argument, 0, 'r'},
- {"burst", required_argument, 0, 'b'},
- {"msgsize", required_argument, 0, 'm'},
- {0, 0, 0, 0}
+ {"help", no_argument, 0, 'h'},
+ {"silent", no_argument, 0, 's'},
+ {"variable",no_argument, 0, 'v'},
+ {"dev", required_argument, 0, 'D'},
+ {"repeat", required_argument, 0, 'r'},
+ {"burst", required_argument, 0, 'b'},
+ {"msgsize", required_argument, 0, 'm'},
+ {0, 0, 0, 0}
};
-/* clang-format on */
-static const char* usage =
- "Usage: %s [options]\n"
- "\n"
- "options:\n"
- " -h, --help prints this message and exit\n"
- " -D, --dev name device name\n"
- " -S, --srv name service name\n"
- " -t, --test name test to run\n"
- " -r, --repeat cnt repeat count\n"
- " -b, --burst cnt burst count\n"
- " -m, --msgsize size max message size\n"
- " -v, --variable variable message size\n"
- " -s, --silent silent\n"
- "\n";
+static const char *usage =
+"Usage: %s [options]\n"
+"\n"
+"options:\n"
+" -h, --help prints this message and exit\n"
+" -D, --dev name device name\n"
+" -t, --test name test to run\n"
+" -r, --repeat cnt repeat count\n"
+" -m, --msgsize size max message size\n"
+" -v, --variable variable message size\n"
+" -s, --silent silent\n"
+"\n"
+;
static const char* usage_long =
"\n"
"The following tests are available:\n"
- " connect - connect to specified service, defaults to echo+datasink\n"
+ " connect - connect to datasink service\n"
" connect_foo - connect to non existing service\n"
" burst_write - send messages to datasink service\n"
" echo - send/receive messages to echo service\n"
@@ -100,774 +96,798 @@ static uint opt_msgsize = 32;
static uint opt_msgburst = 32;
static bool opt_variable = false;
static bool opt_silent = false;
-static char* srv_name = NULL;
static void print_usage_and_exit(const char *prog, int code, bool verbose)
{
- fprintf(stderr, usage, prog);
- if (verbose) fprintf(stderr, "%s", usage_long);
- exit(code);
+ fprintf (stderr, usage, prog);
+ if (verbose)
+ fprintf (stderr, "%s", usage_long);
+ exit(code);
}
static void parse_options(int argc, char **argv)
{
- int c;
- int oidx = 0;
+ int c;
+ int oidx = 0;
- while (1) {
- c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
- if (c == -1) break; /* done */
+ while (1)
+ {
+ c = getopt_long (argc, argv, _sopts, _lopts, &oidx);
+ if (c == -1)
+ break; /* done */
- switch (c) {
- case 'D':
- dev_name = strdup(optarg);
- break;
+ switch (c) {
- case 'S':
- srv_name = strdup(optarg);
- break;
+ case 'D':
+ dev_name = strdup(optarg);
+ break;
- case 't':
- test_name = strdup(optarg);
- break;
+ case 't':
+ test_name = strdup(optarg);
+ break;
- case 'v':
- opt_variable = true;
- break;
+ case 'v':
+ opt_variable = true;
+ break;
- case 'r':
- opt_repeat = atoi(optarg);
- break;
+ case 'r':
+ opt_repeat = atoi(optarg);
+ break;
- case 'm':
- opt_msgsize = atoi(optarg);
- break;
+ case 'm':
+ opt_msgsize = atoi(optarg);
+ break;
- case 'b':
- opt_msgburst = atoi(optarg);
- break;
+ case 'b':
+ opt_msgburst = atoi(optarg);
+ break;
- case 's':
- opt_silent = true;
- break;
+ case 's':
+ opt_silent = true;
+ break;
- case 'h':
- print_usage_and_exit(argv[0], EXIT_SUCCESS, true);
- break;
+ case 'h':
+ print_usage_and_exit(argv[0], EXIT_SUCCESS, true);
+ break;
- default:
- print_usage_and_exit(argv[0], EXIT_FAILURE, false);
- }
- }
+ default:
+ print_usage_and_exit(argv[0], EXIT_FAILURE, false);
+ }
+ }
}
static int connect_test(uint repeat)
{
- uint i;
- int echo_fd;
- int dsink_fd;
- int custom_fd;
-
- if (!opt_silent) {
- printf("%s: repeat = %u\n", __func__, repeat);
- }
-
- for (i = 0; i < repeat; i++) {
- if (srv_name) {
- custom_fd = tipc_connect(dev_name, srv_name);
- if (custom_fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", srv_name);
- }
- if (custom_fd >= 0) {
- tipc_close(custom_fd);
- }
- } else {
- echo_fd = tipc_connect(dev_name, echo_name);
- if (echo_fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
- }
- dsink_fd = tipc_connect(dev_name, datasink_name);
- if (dsink_fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
- }
-
- if (echo_fd >= 0) {
- tipc_close(echo_fd);
- }
- if (dsink_fd >= 0) {
- tipc_close(dsink_fd);
- }
- }
- }
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i;
+ int echo_fd;
+ int dsink_fd;
+
+ if (!opt_silent) {
+ printf("%s: repeat = %u\n", __func__, repeat);
+ }
+
+ for (i = 0; i < repeat; i++) {
+ echo_fd = tipc_connect(dev_name, echo_name);
+ if (echo_fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "echo");
+ }
+ dsink_fd = tipc_connect(dev_name, datasink_name);
+ if (dsink_fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "datasink");
+ }
+
+ if (echo_fd >= 0) {
+ tipc_close(echo_fd);
+ }
+ if (dsink_fd >= 0) {
+ tipc_close(dsink_fd);
+ }
+ }
+
+ if (!opt_silent) {
+ printf("%s: done\n", __func__);
+ }
+
+ return 0;
}
static int connect_foo(uint repeat)
{
- uint i;
- int fd;
-
- if (!opt_silent) {
- printf("%s: repeat = %u\n", __func__, repeat);
- }
-
- for (i = 0; i < repeat; i++) {
- fd = tipc_connect(dev_name, "foo");
- if (fd >= 0) {
- fprintf(stderr, "succeeded to connect to '%s' service\n", "foo");
- tipc_close(fd);
- }
- }
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i;
+ int fd;
+
+ if (!opt_silent) {
+ printf("%s: repeat = %u\n", __func__, repeat);
+ }
+
+ for (i = 0; i < repeat; i++) {
+ fd = tipc_connect(dev_name, "foo");
+ if (fd >= 0) {
+ fprintf(stderr, "succeeded to connect to '%s' service\n",
+ "foo");
+ tipc_close(fd);
+ }
+ }
+
+ if (!opt_silent) {
+ printf("%s: done\n", __func__);
+ }
+
+ return 0;
}
static int closer1_test(uint repeat)
{
- uint i;
- int fd;
-
- if (!opt_silent) {
- printf("%s: repeat = %u\n", __func__, repeat);
- }
-
- for (i = 0; i < repeat; i++) {
- fd = tipc_connect(dev_name, closer1_name);
- if (fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "closer1");
- continue;
- }
- if (!opt_silent) {
- printf("%s: connected\n", __func__);
- }
- tipc_close(fd);
- }
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i;
+ int fd;
+
+ if (!opt_silent) {
+ printf("%s: repeat = %u\n", __func__, repeat);
+ }
+
+ for (i = 0; i < repeat; i++) {
+ fd = tipc_connect(dev_name, closer1_name);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "closer1");
+ continue;
+ }
+ if (!opt_silent) {
+ printf("%s: connected\n", __func__);
+ }
+ tipc_close(fd);
+ }
+
+ if (!opt_silent) {
+ printf("%s: done\n", __func__);
+ }
+
+ return 0;
}
static int closer2_test(uint repeat)
{
- uint i;
- int fd;
-
- if (!opt_silent) {
- printf("%s: repeat = %u\n", __func__, repeat);
- }
-
- for (i = 0; i < repeat; i++) {
- fd = tipc_connect(dev_name, closer2_name);
- if (fd < 0) {
- if (!opt_silent) {
- printf("failed to connect to '%s' service\n", "closer2");
- }
- } else {
- /* this should always fail */
- fprintf(stderr, "connected to '%s' service\n", "closer2");
- tipc_close(fd);
- }
- }
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i;
+ int fd;
+
+ if (!opt_silent) {
+ printf("%s: repeat = %u\n", __func__, repeat);
+ }
+
+ for (i = 0; i < repeat; i++) {
+ fd = tipc_connect(dev_name, closer2_name);
+ if (fd < 0) {
+ if (!opt_silent) {
+ printf("failed to connect to '%s' service\n", "closer2");
+ }
+ } else {
+ /* this should always fail */
+ fprintf(stderr, "connected to '%s' service\n", "closer2");
+ tipc_close(fd);
+ }
+ }
+
+ if (!opt_silent) {
+ printf("%s: done\n", __func__);
+ }
+
+ return 0;
}
static int closer3_test(uint repeat)
{
- uint i, j;
- ssize_t rc;
- int fd[4];
- char buf[64];
-
- if (!opt_silent) {
- printf("%s: repeat = %u\n", __func__, repeat);
- }
-
- for (i = 0; i < repeat; i++) {
- /* open 4 connections to closer3 service */
- for (j = 0; j < 4; j++) {
- fd[j] = tipc_connect(dev_name, closer3_name);
- if (fd[j] < 0) {
- fprintf(stderr, "fd[%d]: failed to connect to '%s' service\n", j, "closer3");
- } else {
- if (!opt_silent) {
- printf("%s: fd[%d]=%d: connected\n", __func__, j, fd[j]);
- }
- memset(buf, i + j, sizeof(buf));
- rc = write(fd[j], buf, sizeof(buf));
- if (rc != sizeof(buf)) {
- if (!opt_silent) {
- printf("%s: fd[%d]=%d: write returned = %zd\n", __func__, j, fd[j], rc);
- }
- perror("closer3_test: write");
- }
- }
- }
-
- /* sleep a bit */
- sleep(1);
-
- /* It is expected that they will be closed by remote */
- for (j = 0; j < 4; j++) {
- if (fd[j] < 0) continue;
- rc = write(fd[j], buf, sizeof(buf));
- if (rc != sizeof(buf)) {
- if (!opt_silent) {
- printf("%s: fd[%d]=%d: write returned = %zd\n", __func__, j, fd[j], rc);
- }
- perror("closer3_test: write");
- }
- }
-
- /* then they have to be closed by remote */
- for (j = 0; j < 4; j++) {
- if (fd[j] >= 0) {
- tipc_close(fd[j]);
- }
- }
- }
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i, j;
+ ssize_t rc;
+ int fd[4];
+ char buf[64];
+
+ if (!opt_silent) {
+ printf("%s: repeat = %u\n", __func__, repeat);
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ /* open 4 connections to closer3 service */
+ for (j = 0; j < 4; j++) {
+ fd[j] = tipc_connect(dev_name, closer3_name);
+ if (fd[j] < 0) {
+ fprintf(stderr, "fd[%d]: failed to connect to '%s' service\n", j, "closer3");
+ } else {
+ if (!opt_silent) {
+ printf("%s: fd[%d]=%d: connected\n", __func__, j, fd[j]);
+ }
+ memset(buf, i + j, sizeof(buf));
+ rc = write(fd[j], buf, sizeof(buf));
+ if (rc != sizeof(buf)) {
+ if (!opt_silent) {
+ printf("%s: fd[%d]=%d: write returned = %zd\n",
+ __func__, j, fd[j], rc);
+ }
+ perror("closer3_test: write");
+ }
+ }
+ }
+
+ /* sleep a bit */
+ sleep(1);
+
+ /* It is expected that they will be closed by remote */
+ for (j = 0; j < 4; j++) {
+ if (fd[j] < 0)
+ continue;
+ rc = write(fd[j], buf, sizeof(buf));
+ if (rc != sizeof(buf)) {
+ if (!opt_silent) {
+ printf("%s: fd[%d]=%d: write returned = %zd\n",
+ __func__, j, fd[j], rc);
+ }
+ perror("closer3_test: write");
+ }
+ }
+
+ /* then they have to be closed by remote */
+ for (j = 0; j < 4; j++) {
+ if (fd[j] >= 0) {
+ tipc_close(fd[j]);
+ }
+ }
+ }
+
+ if (!opt_silent) {
+ printf("%s: done\n", __func__);
+ }
+
+ return 0;
}
static int echo_test(uint repeat, uint msgsz, bool var)
{
- uint i;
- ssize_t rc;
- size_t msg_len;
- int echo_fd = -1;
- char tx_buf[msgsz];
- char rx_buf[msgsz];
-
- if (!opt_silent) {
- printf("%s: repeat %u: msgsz %u: variable %s\n", __func__, repeat, msgsz,
- var ? "true" : "false");
- }
-
- echo_fd = tipc_connect(dev_name, echo_name);
- if (echo_fd < 0) {
- fprintf(stderr, "Failed to connect to service\n");
- return echo_fd;
- }
-
- for (i = 0; i < repeat; i++) {
- msg_len = msgsz;
- if (opt_variable && msgsz) {
- msg_len = rand() % msgsz;
- }
-
- memset(tx_buf, i + 1, msg_len);
-
- rc = write(echo_fd, tx_buf, msg_len);
- if ((size_t)rc != msg_len) {
- perror("echo_test: write");
- break;
- }
-
- rc = read(echo_fd, rx_buf, msg_len);
- if (rc < 0) {
- perror("echo_test: read");
- break;
- }
-
- if ((size_t)rc != msg_len) {
- fprintf(stderr, "data truncated (%zu vs. %zu)\n", rc, msg_len);
- continue;
- }
-
- if (memcmp(tx_buf, rx_buf, (size_t)rc)) {
- fprintf(stderr, "data mismatch\n");
- continue;
- }
- }
-
- tipc_close(echo_fd);
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i;
+ ssize_t rc;
+ size_t msg_len;
+ int echo_fd =-1;
+ char tx_buf[msgsz];
+ char rx_buf[msgsz];
+
+ if (!opt_silent) {
+ printf("%s: repeat %u: msgsz %u: variable %s\n",
+ __func__, repeat, msgsz, var ? "true" : "false");
+ }
+
+ echo_fd = tipc_connect(dev_name, echo_name);
+ if (echo_fd < 0) {
+ fprintf(stderr, "Failed to connect to service\n");
+ return echo_fd;
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ msg_len = msgsz;
+ if (opt_variable && msgsz) {
+ msg_len = rand() % msgsz;
+ }
+
+ memset(tx_buf, i + 1, msg_len);
+
+ rc = write(echo_fd, tx_buf, msg_len);
+ if ((size_t)rc != msg_len) {
+ perror("echo_test: write");
+ break;
+ }
+
+ rc = read(echo_fd, rx_buf, msg_len);
+ if (rc < 0) {
+ perror("echo_test: read");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr, "data truncated (%zu vs. %zu)\n",
+ rc, msg_len);
+ continue;
+ }
+
+ if (memcmp(tx_buf, rx_buf, (size_t) rc)) {
+ fprintf(stderr, "data mismatch\n");
+ continue;
+ }
+ }
+
+ tipc_close(echo_fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
}
static int burst_write_test(uint repeat, uint msgburst, uint msgsz, bool var)
{
- int fd;
- uint i, j;
- ssize_t rc;
- size_t msg_len;
- char tx_buf[msgsz];
-
- if (!opt_silent) {
- printf("%s: repeat %u: burst %u: msgsz %u: variable %s\n", __func__, repeat, msgburst,
- msgsz, var ? "true" : "false");
- }
-
- for (i = 0; i < repeat; i++) {
- fd = tipc_connect(dev_name, datasink_name);
- if (fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
- break;
- }
-
- for (j = 0; j < msgburst; j++) {
- msg_len = msgsz;
- if (var && msgsz) {
- msg_len = rand() % msgsz;
- }
-
- memset(tx_buf, i + 1, msg_len);
- rc = write(fd, tx_buf, msg_len);
- if ((size_t)rc != msg_len) {
- perror("burst_test: write");
- break;
- }
- }
-
- tipc_close(fd);
- }
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ int fd;
+ uint i, j;
+ ssize_t rc;
+ size_t msg_len;
+ char tx_buf[msgsz];
+
+ if (!opt_silent) {
+ printf("%s: repeat %u: burst %u: msgsz %u: variable %s\n",
+ __func__, repeat, msgburst, msgsz,
+ var ? "true" : "false");
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ fd = tipc_connect(dev_name, datasink_name);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "datasink");
+ break;
+ }
+
+ for (j = 0; j < msgburst; j++) {
+ msg_len = msgsz;
+ if (var && msgsz) {
+ msg_len = rand() % msgsz;
+ }
+
+ memset(tx_buf, i + 1, msg_len);
+ rc = write(fd, tx_buf, msg_len);
+ if ((size_t)rc != msg_len) {
+ perror("burst_test: write");
+ break;
+ }
+ }
+
+ tipc_close(fd);
+ }
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
}
static int _wait_for_msg(int fd, uint msgsz, int timeout)
{
- int rc;
- fd_set rfds;
- uint msgcnt = 0;
- char rx_buf[msgsz];
- struct timeval tv;
-
- if (!opt_silent) {
- printf("waiting (%d) for msg\n", timeout);
- }
-
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- for (;;) {
- rc = select(fd + 1, &rfds, NULL, NULL, &tv);
-
- if (rc == 0) {
- if (!opt_silent) {
- printf("select timedout\n");
- }
- break;
- }
-
- if (rc == -1) {
- perror("select_test: select");
- return rc;
- }
-
- rc = read(fd, rx_buf, sizeof(rx_buf));
- if (rc < 0) {
- perror("select_test: read");
- return rc;
- } else {
- if (rc > 0) {
- msgcnt++;
- }
- }
- }
-
- if (!opt_silent) {
- printf("got %u messages\n", msgcnt);
- }
-
- return 0;
+ int rc;
+ fd_set rfds;
+ uint msgcnt = 0;
+ char rx_buf[msgsz];
+ struct timeval tv;
+
+ if (!opt_silent) {
+ printf("waiting (%d) for msg\n", timeout);
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ for(;;) {
+ rc = select(fd+1, &rfds, NULL, NULL, &tv);
+
+ if (rc == 0) {
+ if (!opt_silent) {
+ printf("select timedout\n");
+ }
+ break;
+ }
+
+ if (rc == -1) {
+ perror("select_test: select");
+ return rc;
+ }
+
+ rc = read(fd, rx_buf, sizeof(rx_buf));
+ if (rc < 0) {
+ perror("select_test: read");
+ return rc;
+ } else {
+ if (rc > 0) {
+ msgcnt++;
+ }
+ }
+ }
+
+ if (!opt_silent) {
+ printf("got %u messages\n", msgcnt);
+ }
+
+ return 0;
}
static int select_test(uint repeat, uint msgburst, uint msgsz)
{
- int fd;
- uint i, j;
- ssize_t rc;
- char tx_buf[msgsz];
-
- if (!opt_silent) {
- printf("%s: repeat %u\n", __func__, repeat);
- }
-
- fd = tipc_connect(dev_name, echo_name);
- if (fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
- return fd;
- }
-
- for (i = 0; i < repeat; i++) {
- _wait_for_msg(fd, msgsz, 1);
-
- if (!opt_silent) {
- printf("sending burst: %u msg\n", msgburst);
- }
-
- for (j = 0; j < msgburst; j++) {
- memset(tx_buf, i + j, msgsz);
- rc = write(fd, tx_buf, msgsz);
- if ((size_t)rc != msgsz) {
- perror("burst_test: write");
- break;
- }
- }
- }
-
- tipc_close(fd);
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ int fd;
+ uint i, j;
+ ssize_t rc;
+ char tx_buf[msgsz];
+
+ if (!opt_silent) {
+ printf("%s: repeat %u\n", __func__, repeat);
+ }
+
+ fd = tipc_connect(dev_name, echo_name);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "echo");
+ return fd;
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ _wait_for_msg(fd, msgsz, 1);
+
+ if (!opt_silent) {
+ printf("sending burst: %u msg\n", msgburst);
+ }
+
+ for (j = 0; j < msgburst; j++) {
+ memset(tx_buf, i + j, msgsz);
+ rc = write(fd, tx_buf, msgsz);
+ if ((size_t)rc != msgsz) {
+ perror("burst_test: write");
+ break;
+ }
+ }
+ }
+
+ tipc_close(fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
}
static int blocked_read_test(uint repeat)
{
- int fd;
- uint i;
- ssize_t rc;
- char rx_buf[512];
-
- if (!opt_silent) {
- printf("%s: repeat %u\n", __func__, repeat);
- }
-
- fd = tipc_connect(dev_name, echo_name);
- if (fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
- return fd;
- }
-
- for (i = 0; i < repeat; i++) {
- rc = read(fd, rx_buf, sizeof(rx_buf));
- if (rc < 0) {
- perror("select_test: read");
- break;
- } else {
- if (!opt_silent) {
- printf("got %zd bytes\n", rc);
- }
- }
- }
-
- tipc_close(fd);
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ int fd;
+ uint i;
+ ssize_t rc;
+ char rx_buf[512];
+
+ if (!opt_silent) {
+ printf("%s: repeat %u\n", __func__, repeat);
+ }
+
+ fd = tipc_connect(dev_name, echo_name);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "echo");
+ return fd;
+ }
+
+ for (i = 0; i < repeat; i++) {
+ rc = read(fd, rx_buf, sizeof(rx_buf));
+ if (rc < 0) {
+ perror("select_test: read");
+ break;
+ } else {
+ if (!opt_silent) {
+ printf("got %zd bytes\n", rc);
+ }
+ }
+ }
+
+ tipc_close(fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
}
static int ta2ta_ipc_test(void)
{
- enum test_message_header {
- TEST_PASSED = 0,
- TEST_FAILED = 1,
- TEST_MESSAGE = 2,
- };
-
- int fd;
- int ret;
- unsigned char rx_buf[256];
-
- if (!opt_silent) {
- printf("%s:\n", __func__);
- }
-
- fd = tipc_connect(dev_name, main_ctrl_name);
- if (fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "main_ctrl");
- return fd;
- }
-
- /* Wait for tests to complete and read status */
- while (true) {
- ret = read(fd, rx_buf, sizeof(rx_buf));
- if (ret <= 0 || ret >= (int)sizeof(rx_buf)) {
- fprintf(stderr, "%s: Read failed: %d\n", __func__, ret);
- tipc_close(fd);
- return -1;
- }
-
- if (rx_buf[0] == TEST_PASSED) {
- break;
- } else if (rx_buf[0] == TEST_FAILED) {
- break;
- } else if (rx_buf[0] == TEST_MESSAGE) {
- write(STDOUT_FILENO, rx_buf + 1, ret - 1);
- } else {
- fprintf(stderr, "%s: Bad message header: %d\n", __func__, rx_buf[0]);
- break;
- }
- }
-
- tipc_close(fd);
-
- return rx_buf[0] == TEST_PASSED ? 0 : -1;
+ enum test_message_header {
+ TEST_PASSED = 0,
+ TEST_FAILED = 1,
+ TEST_MESSAGE = 2,
+ };
+
+ int fd;
+ int ret;
+ unsigned char rx_buf[256];
+
+ if (!opt_silent) {
+ printf("%s:\n", __func__);
+ }
+
+ fd = tipc_connect(dev_name, main_ctrl_name);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "main_ctrl");
+ return fd;
+ }
+
+ /* Wait for tests to complete and read status */
+ while (true) {
+ ret = read(fd, rx_buf, sizeof(rx_buf));
+ if (ret <= 0 || ret >= (int)sizeof(rx_buf)) {
+ fprintf(stderr, "%s: Read failed: %d\n", __func__, ret);
+ tipc_close(fd);
+ return -1;
+ }
+
+ if (rx_buf[0] == TEST_PASSED) {
+ break;
+ } else if (rx_buf[0] == TEST_FAILED) {
+ break;
+ } else if (rx_buf[0] == TEST_MESSAGE) {
+ write(STDOUT_FILENO, rx_buf + 1, ret - 1);
+ } else {
+ fprintf(stderr, "%s: Bad message header: %d\n",
+ __func__, rx_buf[0]);
+ break;
+ }
+ }
+
+ tipc_close(fd);
+
+ return rx_buf[0] == TEST_PASSED ? 0 : -1;
}
typedef struct uuid
{
- uint32_t time_low;
- uint16_t time_mid;
- uint16_t time_hi_and_version;
- uint8_t clock_seq_and_node[8];
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_and_node[8];
} uuid_t;
static void print_uuid(const char *dev, uuid_t *uuid)
{
- printf("%s:", dev);
- printf("uuid: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", uuid->time_low,
- uuid->time_mid, uuid->time_hi_and_version, uuid->clock_seq_and_node[0],
- uuid->clock_seq_and_node[1], uuid->clock_seq_and_node[2], uuid->clock_seq_and_node[3],
- uuid->clock_seq_and_node[4], uuid->clock_seq_and_node[5], uuid->clock_seq_and_node[6],
- uuid->clock_seq_and_node[7]);
+ printf("%s:", dev);
+ printf("uuid: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ uuid->time_low,
+ uuid->time_mid,
+ uuid->time_hi_and_version,
+ uuid->clock_seq_and_node[0],
+ uuid->clock_seq_and_node[1],
+ uuid->clock_seq_and_node[2],
+ uuid->clock_seq_and_node[3],
+ uuid->clock_seq_and_node[4],
+ uuid->clock_seq_and_node[5],
+ uuid->clock_seq_and_node[6],
+ uuid->clock_seq_and_node[7]
+ );
}
static int dev_uuid_test(void)
{
- int fd;
- ssize_t rc;
- uuid_t uuid;
-
- fd = tipc_connect(dev_name, uuid_name);
- if (fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "uuid");
- return fd;
- }
-
- /* wait for test to complete */
- rc = read(fd, &uuid, sizeof(uuid));
- if (rc < 0) {
- perror("dev_uuid_test: read");
- } else if (rc != sizeof(uuid)) {
- fprintf(stderr, "unexpected uuid size (%d vs. %d)\n", (int)rc, (int)sizeof(uuid));
- } else {
- print_uuid(dev_name, &uuid);
- }
-
- tipc_close(fd);
-
- return 0;
+ int fd;
+ ssize_t rc;
+ uuid_t uuid;
+
+ fd = tipc_connect(dev_name, uuid_name);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "uuid");
+ return fd;
+ }
+
+ /* wait for test to complete */
+ rc = read(fd, &uuid, sizeof(uuid));
+ if (rc < 0) {
+ perror("dev_uuid_test: read");
+ } else if (rc != sizeof(uuid)) {
+ fprintf(stderr, "unexpected uuid size (%d vs. %d)\n",
+ (int)rc, (int)sizeof(uuid));
+ } else {
+ print_uuid(dev_name, &uuid);
+ }
+
+ tipc_close(fd);
+
+ return 0;
}
static int ta_access_test(void)
{
- int fd;
-
- if (!opt_silent) {
- printf("%s:\n", __func__);
- }
-
- fd = tipc_connect(dev_name, ta_only_name);
- if (fd >= 0) {
- fprintf(stderr, "Succeed to connect to '%s' service\n", "ta_only");
- tipc_close(fd);
- }
-
- fd = tipc_connect(dev_name, ns_only_name);
- if (fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "ns_only");
- return fd;
- }
- tipc_close(fd);
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ int fd;
+
+ if (!opt_silent) {
+ printf("%s:\n", __func__);
+ }
+
+ fd = tipc_connect(dev_name, ta_only_name);
+ if (fd >= 0) {
+ fprintf(stderr, "Succeed to connect to '%s' service\n",
+ "ta_only");
+ tipc_close(fd);
+ }
+
+ fd = tipc_connect(dev_name, ns_only_name);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n",
+ "ns_only");
+ return fd;
+ }
+ tipc_close(fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
}
static int writev_test(uint repeat, uint msgsz, bool var)
{
- uint i;
- ssize_t rc;
- size_t msg_len;
- int echo_fd = -1;
- char tx0_buf[msgsz];
- char tx1_buf[msgsz];
- char rx_buf[msgsz];
- struct iovec iovs[2] = {{tx0_buf, 0}, {tx1_buf, 0}};
-
- if (!opt_silent) {
- printf("%s: repeat %u: msgsz %u: variable %s\n", __func__, repeat, msgsz,
- var ? "true" : "false");
- }
-
- echo_fd = tipc_connect(dev_name, echo_name);
- if (echo_fd < 0) {
- fprintf(stderr, "Failed to connect to service\n");
- return echo_fd;
- }
-
- for (i = 0; i < repeat; i++) {
- msg_len = msgsz;
- if (opt_variable && msgsz) {
- msg_len = rand() % msgsz;
- }
-
- iovs[0].iov_len = msg_len / 3;
- iovs[1].iov_len = msg_len - iovs[0].iov_len;
-
- memset(tx0_buf, i + 1, iovs[0].iov_len);
- memset(tx1_buf, i + 2, iovs[1].iov_len);
- memset(rx_buf, i + 3, sizeof(rx_buf));
-
- rc = writev(echo_fd, iovs, 2);
- if (rc < 0) {
- perror("writev_test: writev");
- break;
- }
-
- if ((size_t)rc != msg_len) {
- fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "writev",
- (size_t)rc, msg_len);
- break;
- }
-
- rc = read(echo_fd, rx_buf, sizeof(rx_buf));
- if (rc < 0) {
- perror("writev_test: read");
- break;
- }
-
- if ((size_t)rc != msg_len) {
- fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "read",
- (size_t)rc, msg_len);
- break;
- }
-
- if (memcmp(tx0_buf, rx_buf, iovs[0].iov_len)) {
- fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
- break;
- }
-
- if (memcmp(tx1_buf, rx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
- fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
- break;
- }
- }
-
- tipc_close(echo_fd);
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i;
+ ssize_t rc;
+ size_t msg_len;
+ int echo_fd = -1;
+ char tx0_buf[msgsz];
+ char tx1_buf[msgsz];
+ char rx_buf [msgsz];
+ struct iovec iovs[2]= {{tx0_buf, 0}, {tx1_buf, 0}};
+
+ if (!opt_silent) {
+ printf("%s: repeat %u: msgsz %u: variable %s\n",
+ __func__, repeat, msgsz, var ? "true" : "false");
+ }
+
+ echo_fd = tipc_connect(dev_name, echo_name);
+ if (echo_fd < 0) {
+ fprintf(stderr, "Failed to connect to service\n");
+ return echo_fd;
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ msg_len = msgsz;
+ if (opt_variable && msgsz) {
+ msg_len = rand() % msgsz;
+ }
+
+ iovs[0].iov_len = msg_len / 3;
+ iovs[1].iov_len = msg_len - iovs[0].iov_len;
+
+ memset(tx0_buf, i + 1, iovs[0].iov_len);
+ memset(tx1_buf, i + 2, iovs[1].iov_len);
+ memset(rx_buf, i + 3, sizeof(rx_buf));
+
+ rc = writev(echo_fd, iovs, 2);
+ if (rc < 0) {
+ perror("writev_test: writev");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "writev", (size_t)rc, msg_len);
+ break;
+ }
+
+ rc = read(echo_fd, rx_buf, sizeof(rx_buf));
+ if (rc < 0) {
+ perror("writev_test: read");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "read", (size_t)rc, msg_len);
+ break;
+ }
+
+ if (memcmp(tx0_buf, rx_buf, iovs[0].iov_len)) {
+ fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
+ break;
+ }
+
+ if (memcmp(tx1_buf, rx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
+ fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
+ break;
+ }
+ }
+
+ tipc_close(echo_fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
}
static int readv_test(uint repeat, uint msgsz, bool var)
{
- uint i;
- ssize_t rc;
- size_t msg_len;
- int echo_fd = -1;
- char tx_buf[msgsz];
- char rx0_buf[msgsz];
- char rx1_buf[msgsz];
- struct iovec iovs[2] = {{rx0_buf, 0}, {rx1_buf, 0}};
-
- if (!opt_silent) {
- printf("%s: repeat %u: msgsz %u: variable %s\n", __func__, repeat, msgsz,
- var ? "true" : "false");
- }
-
- echo_fd = tipc_connect(dev_name, echo_name);
- if (echo_fd < 0) {
- fprintf(stderr, "Failed to connect to service\n");
- return echo_fd;
- }
-
- for (i = 0; i < repeat; i++) {
- msg_len = msgsz;
- if (opt_variable && msgsz) {
- msg_len = rand() % msgsz;
- }
-
- iovs[0].iov_len = msg_len / 3;
- iovs[1].iov_len = msg_len - iovs[0].iov_len;
-
- memset(tx_buf, i + 1, sizeof(tx_buf));
- memset(rx0_buf, i + 2, iovs[0].iov_len);
- memset(rx1_buf, i + 3, iovs[1].iov_len);
-
- rc = write(echo_fd, tx_buf, msg_len);
- if (rc < 0) {
- perror("readv_test: write");
- break;
- }
-
- if ((size_t)rc != msg_len) {
- fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "write",
- (size_t)rc, msg_len);
- break;
- }
-
- rc = readv(echo_fd, iovs, 2);
- if (rc < 0) {
- perror("readv_test: readv");
- break;
- }
-
- if ((size_t)rc != msg_len) {
- fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "write",
- (size_t)rc, msg_len);
- break;
- }
-
- if (memcmp(rx0_buf, tx_buf, iovs[0].iov_len)) {
- fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
- break;
- }
-
- if (memcmp(rx1_buf, tx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
- fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
- break;
- }
- }
-
- tipc_close(echo_fd);
-
- if (!opt_silent) {
- printf("%s: done\n", __func__);
- }
-
- return 0;
+ uint i;
+ ssize_t rc;
+ size_t msg_len;
+ int echo_fd = -1;
+ char tx_buf [msgsz];
+ char rx0_buf[msgsz];
+ char rx1_buf[msgsz];
+ struct iovec iovs[2]= {{rx0_buf, 0}, {rx1_buf, 0}};
+
+ if (!opt_silent) {
+ printf("%s: repeat %u: msgsz %u: variable %s\n",
+ __func__, repeat, msgsz, var ? "true" : "false");
+ }
+
+ echo_fd = tipc_connect(dev_name, echo_name);
+ if (echo_fd < 0) {
+ fprintf(stderr, "Failed to connect to service\n");
+ return echo_fd;
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ msg_len = msgsz;
+ if (opt_variable && msgsz) {
+ msg_len = rand() % msgsz;
+ }
+
+ iovs[0].iov_len = msg_len / 3;
+ iovs[1].iov_len = msg_len - iovs[0].iov_len;
+
+ memset(tx_buf, i + 1, sizeof(tx_buf));
+ memset(rx0_buf, i + 2, iovs[0].iov_len);
+ memset(rx1_buf, i + 3, iovs[1].iov_len);
+
+ rc = write(echo_fd, tx_buf, msg_len);
+ if (rc < 0) {
+ perror("readv_test: write");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "write", (size_t)rc, msg_len);
+ break;
+ }
+
+ rc = readv(echo_fd, iovs, 2);
+ if (rc < 0) {
+ perror("readv_test: readv");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "write", (size_t)rc, msg_len);
+ break;
+ }
+
+ if (memcmp(rx0_buf, tx_buf, iovs[0].iov_len)) {
+ fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
+ break;
+ }
+
+ if (memcmp(rx1_buf, tx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
+ fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
+ break;
+ }
+ }
+
+ tipc_close(echo_fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
}
static int send_fd_test(void) {
@@ -944,51 +964,51 @@ cleanup:
int main(int argc, char **argv)
{
- int rc = 0;
-
- if (argc <= 1) {
- print_usage_and_exit(argv[0], EXIT_FAILURE, false);
- }
-
- parse_options(argc, argv);
-
- if (!dev_name) {
- dev_name = TIPC_DEFAULT_DEVNAME;
- }
-
- if (!test_name) {
- fprintf(stderr, "need a Test to run\n");
- print_usage_and_exit(argv[0], EXIT_FAILURE, true);
- }
-
- if (strcmp(test_name, "connect") == 0) {
- rc = connect_test(opt_repeat);
- } else if (strcmp(test_name, "connect_foo") == 0) {
- rc = connect_foo(opt_repeat);
- } else if (strcmp(test_name, "burst_write") == 0) {
- rc = burst_write_test(opt_repeat, opt_msgburst, opt_msgsize, opt_variable);
- } else if (strcmp(test_name, "select") == 0) {
- rc = select_test(opt_repeat, opt_msgburst, opt_msgsize);
- } else if (strcmp(test_name, "blocked_read") == 0) {
- rc = blocked_read_test(opt_repeat);
- } else if (strcmp(test_name, "closer1") == 0) {
- rc = closer1_test(opt_repeat);
- } else if (strcmp(test_name, "closer2") == 0) {
- rc = closer2_test(opt_repeat);
- } else if (strcmp(test_name, "closer3") == 0) {
- rc = closer3_test(opt_repeat);
- } else if (strcmp(test_name, "echo") == 0) {
- rc = echo_test(opt_repeat, opt_msgsize, opt_variable);
- } else if (strcmp(test_name, "ta2ta-ipc") == 0) {
- rc = ta2ta_ipc_test();
- } else if (strcmp(test_name, "dev-uuid") == 0) {
- rc = dev_uuid_test();
- } else if (strcmp(test_name, "ta-access") == 0) {
- rc = ta_access_test();
- } else if (strcmp(test_name, "writev") == 0) {
- rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
- } else if (strcmp(test_name, "readv") == 0) {
- rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
+ int rc = 0;
+
+ if (argc <= 1) {
+ print_usage_and_exit(argv[0], EXIT_FAILURE, false);
+ }
+
+ parse_options(argc, argv);
+
+ if (!dev_name) {
+ dev_name = TIPC_DEFAULT_DEVNAME;
+ }
+
+ if (!test_name) {
+ fprintf(stderr, "need a Test to run\n");
+ print_usage_and_exit(argv[0], EXIT_FAILURE, true);
+ }
+
+ if (strcmp(test_name, "connect") == 0) {
+ rc = connect_test(opt_repeat);
+ } else if (strcmp(test_name, "connect_foo") == 0) {
+ rc = connect_foo(opt_repeat);
+ } else if (strcmp(test_name, "burst_write") == 0) {
+ rc = burst_write_test(opt_repeat, opt_msgburst, opt_msgsize, opt_variable);
+ } else if (strcmp(test_name, "select") == 0) {
+ rc = select_test(opt_repeat, opt_msgburst, opt_msgsize);
+ } else if (strcmp(test_name, "blocked_read") == 0) {
+ rc = blocked_read_test(opt_repeat);
+ } else if (strcmp(test_name, "closer1") == 0) {
+ rc = closer1_test(opt_repeat);
+ } else if (strcmp(test_name, "closer2") == 0) {
+ rc = closer2_test(opt_repeat);
+ } else if (strcmp(test_name, "closer3") == 0) {
+ rc = closer3_test(opt_repeat);
+ } else if (strcmp(test_name, "echo") == 0) {
+ rc = echo_test(opt_repeat, opt_msgsize, opt_variable);
+ } else if(strcmp(test_name, "ta2ta-ipc") == 0) {
+ rc = ta2ta_ipc_test();
+ } else if (strcmp(test_name, "dev-uuid") == 0) {
+ rc = dev_uuid_test();
+ } else if (strcmp(test_name, "ta-access") == 0) {
+ rc = ta_access_test();
+ } else if (strcmp(test_name, "writev") == 0) {
+ rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
+ } else if (strcmp(test_name, "readv") == 0) {
+ rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
} else if (strcmp(test_name, "send-fd") == 0) {
rc = send_fd_test();
} else {
diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h
index 3f1dcb8c6..b196d88b3 100644
--- a/trusty/storage/interface/include/trusty/interface/storage.h
+++ b/trusty/storage/interface/include/trusty/interface/storage.h
@@ -112,30 +112,26 @@ enum storage_file_open_flag {
/**
* enum storage_msg_flag - protocol-level flags in struct storage_msg
- * @STORAGE_MSG_FLAG_BATCH: if set, command belongs to a batch transaction.
- * No response will be sent by the server until
- * it receives a command with this flag unset, at
- * which point a cumulative result for all messages
- * sent with STORAGE_MSG_FLAG_BATCH will be sent.
- * This is only supported by the non-secure disk proxy
- * server.
- * @STORAGE_MSG_FLAG_PRE_COMMIT: if set, indicates that server need to commit
- * pending changes before processing this message.
- * @STORAGE_MSG_FLAG_POST_COMMIT: if set, indicates that server need to commit
- * pending changes after processing this message.
- * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit
- * current transaction after processing this message.
- * It is an alias for STORAGE_MSG_FLAG_POST_COMMIT.
- * @STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT: if set, indicates that server needs to ensure
- * that there is not a pending checkpoint for
- * userdata before processing this message.
+ * @STORAGE_MSG_FLAG_BATCH: if set, command belongs to a batch transaction.
+ * No response will be sent by the server until
+ * it receives a command with this flag unset, at
+ * which point a cummulative result for all messages
+ * sent with STORAGE_MSG_FLAG_BATCH will be sent.
+ * This is only supported by the non-secure disk proxy
+ * server.
+ * @STORAGE_MSG_FLAG_PRE_COMMIT: if set, indicates that server need to commit
+ * pending changes before processing this message.
+ * @STORAGE_MSG_FLAG_POST_COMMIT: if set, indicates that server need to commit
+ * pending changes after processing this message.
+ * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit
+ * current transaction after processing this message.
+ * It is an alias for STORAGE_MSG_FLAG_POST_COMMIT.
*/
enum storage_msg_flag {
- STORAGE_MSG_FLAG_BATCH = 0x1,
- STORAGE_MSG_FLAG_PRE_COMMIT = 0x2,
- STORAGE_MSG_FLAG_POST_COMMIT = 0x4,
- STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT,
- STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT = 0x8,
+ STORAGE_MSG_FLAG_BATCH = 0x1,
+ STORAGE_MSG_FLAG_PRE_COMMIT = 0x2,
+ STORAGE_MSG_FLAG_POST_COMMIT = 0x4,
+ STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT,
};
/*
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
index 94f26d8a6..d67089fb2 100644
--- a/trusty/storage/proxy/Android.bp
+++ b/trusty/storage/proxy/Android.bp
@@ -23,7 +23,6 @@ cc_binary {
vendor: true,
srcs: [
- "checkpoint_handling.cpp",
"ipc.c",
"rpmb.c",
"storage.c",
@@ -31,17 +30,12 @@ cc_binary {
],
shared_libs: [
- "libbase",
"liblog",
"libhardware_legacy",
],
- header_libs: [
- "libcutils_headers",
- "libgsi_headers",
- ],
+ header_libs: ["libcutils_headers"],
static_libs: [
- "libfstab",
"libtrustystorageinterface",
"libtrusty",
],
diff --git a/trusty/storage/proxy/checkpoint_handling.cpp b/trusty/storage/proxy/checkpoint_handling.cpp
deleted file mode 100644
index 3305d8da2..000000000
--- a/trusty/storage/proxy/checkpoint_handling.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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 "checkpoint_handling.h"
-#include "log.h"
-
-#include <fstab/fstab.h>
-#include <unistd.h>
-#include <cstring>
-#include <string>
-
-#include <libgsi/libgsi.h>
-
-namespace {
-
-bool checkpointingDoneForever = false;
-
-} // namespace
-
-int is_data_checkpoint_active(bool* active) {
- if (!active) {
- ALOGE("active out parameter is null");
- return 0;
- }
-
- *active = false;
-
- if (checkpointingDoneForever) {
- return 0;
- }
-
- android::fs_mgr::Fstab procMounts;
- bool success = android::fs_mgr::ReadFstabFromFile("/proc/mounts", &procMounts);
- if (!success) {
- ALOGE("Could not parse /proc/mounts\n");
- /* Really bad. Tell the caller to abort the write. */
- return -1;
- }
-
- android::fs_mgr::FstabEntry* dataEntry =
- android::fs_mgr::GetEntryForMountPoint(&procMounts, "/data");
- if (dataEntry == NULL) {
- ALOGE("/data is not mounted yet\n");
- return 0;
- }
-
- /* We can't handle e.g., ext4. Nothing we can do about it for now. */
- if (dataEntry->fs_type != "f2fs") {
- ALOGW("Checkpoint status not supported for filesystem %s\n", dataEntry->fs_type.c_str());
- checkpointingDoneForever = true;
- return 0;
- }
-
- /*
- * The data entry looks like "... blah,checkpoint=disable:0,blah ...".
- * checkpoint=disable means checkpointing is on (yes, arguably reversed).
- */
- size_t checkpointPos = dataEntry->fs_options.find("checkpoint=disable");
- if (checkpointPos == std::string::npos) {
- /* Assumption is that once checkpointing turns off, it stays off */
- checkpointingDoneForever = true;
- } else {
- *active = true;
- }
-
- return 0;
-}
-
-/**
- * is_gsi_running() - Check if a GSI image is running via DSU.
- *
- * This function is equivalent to android::gsi::IsGsiRunning(), but this API is
- * not yet vendor-accessible although the underlying metadata file is.
- *
- */
-bool is_gsi_running() {
- /* TODO(b/210501710): Expose GSI image running state to vendor storageproxyd */
- return !access(android::gsi::kGsiBootedIndicatorFile, F_OK);
-}
diff --git a/trusty/storage/proxy/checkpoint_handling.h b/trusty/storage/proxy/checkpoint_handling.h
deleted file mode 100644
index dfe294778..000000000
--- a/trusty/storage/proxy/checkpoint_handling.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * is_data_checkpoint_active() - Check for an active, uncommitted checkpoint of
- * /data. If a checkpoint is active, storage should not commit any
- * rollback-protected writes to /data.
- * @active: Out parameter that will be set to the result of the check.
- *
- * Return: 0 if active was set and is valid, non-zero otherwise.
- */
-int is_data_checkpoint_active(bool* active);
-
-bool is_gsi_running();
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 262003427..e23094183 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -26,7 +26,6 @@
#include <cutils/android_filesystem_config.h>
-#include "checkpoint_handling.h"
#include "ipc.h"
#include "log.h"
#include "rpmb.h"
@@ -104,11 +103,8 @@ static int drop_privs(void) {
return -1;
}
- /*
- * No access for group and other. We need execute access for user to create
- * an accessible directory.
- */
- umask(S_IRWXG | S_IRWXO);
+ /* no-execute for user, no access for group and other */
+ umask(S_IXUSR | S_IRWXG | S_IRWXO);
return 0;
}
@@ -134,21 +130,6 @@ static int handle_req(struct storage_msg* msg, const void* req, size_t req_len)
}
}
- if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT) {
- bool is_checkpoint_active = false;
-
- rc = is_data_checkpoint_active(&is_checkpoint_active);
- if (rc != 0) {
- ALOGE("is_data_checkpoint_active failed in an unexpected way. Aborting.\n");
- msg->result = STORAGE_ERR_GENERIC;
- return ipc_respond(msg, NULL, 0);
- } else if (is_checkpoint_active) {
- ALOGE("Checkpoint in progress, dropping write ...\n");
- msg->result = STORAGE_ERR_GENERIC;
- return ipc_respond(msg, NULL, 0);
- }
- }
-
switch (msg->cmd) {
case STORAGE_FILE_DELETE:
rc = storage_file_delete(msg, req, req_len);
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index c00c399d9..2fde30f84 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -16,7 +16,6 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <libgen.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -25,29 +24,26 @@
#include <sys/types.h>
#include <unistd.h>
-#include "checkpoint_handling.h"
-#include "ipc.h"
#include "log.h"
+#include "ipc.h"
#include "storage.h"
#define FD_TBL_SIZE 64
#define MAX_READ_SIZE 4096
-#define ALTERNATE_DATA_DIR "alternate/"
-
enum sync_state {
SS_UNUSED = -1,
SS_CLEAN = 0,
SS_DIRTY = 1,
};
+static int ssdir_fd = -1;
static const char *ssdir_name;
static enum sync_state fs_state;
+static enum sync_state dir_state;
static enum sync_state fd_state[FD_TBL_SIZE];
-static bool alternate_mode;
-
static struct {
struct storage_file_read_resp hdr;
uint8_t data[MAX_READ_SIZE];
@@ -57,6 +53,10 @@ static uint32_t insert_fd(int open_flags, int fd)
{
uint32_t handle = fd;
+ if (open_flags & O_CREAT) {
+ dir_state = SS_DIRTY;
+ }
+
if (handle < FD_TBL_SIZE) {
fd_state[fd] = SS_CLEAN; /* fd clean */
if (open_flags & O_TRUNC) {
@@ -187,6 +187,7 @@ int storage_file_delete(struct storage_msg *msg,
goto err_response;
}
+ dir_state = SS_DIRTY;
rc = unlink(path);
if (rc < 0) {
rc = errno;
@@ -210,21 +211,11 @@ err_response:
return ipc_respond(msg, NULL, 0);
}
-static void sync_parent(const char* path) {
- int parent_fd;
- char* parent_path = dirname(path);
- parent_fd = TEMP_FAILURE_RETRY(open(parent_path, O_RDONLY));
- if (parent_fd >= 0) {
- fsync(parent_fd);
- close(parent_fd);
- } else {
- ALOGE("%s: failed to open parent directory \"%s\" for sync: %s\n", __func__, parent_path,
- strerror(errno));
- }
-}
-int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len) {
- char* path = NULL;
+int storage_file_open(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ char *path = NULL;
const struct storage_file_open_req *req = r;
struct storage_file_open_resp resp = {0};
@@ -243,24 +234,6 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len) {
goto err_response;
}
- /*
- * TODO(b/210501710): Expose GSI image running state to vendor
- * storageproxyd. We want to control data file paths in vendor_init, but we
- * don't have access to the necessary property there yet. When we have
- * access to that property we can set the root data path read-only and only
- * allow creation of files in alternate/. Checking paths here temporarily
- * until that is fixed.
- *
- * We are just checking for "/" instead of "alternate/" because we still
- * want to still allow access to "persist/" in alternate mode (for now, this
- * may change in the future).
- */
- if (alternate_mode && !strchr(req->name, '/')) {
- ALOGE("%s: Cannot open root data file \"%s\" in alternate mode\n", __func__, req->name);
- msg->result = STORAGE_ERR_ACCESS;
- goto err_response;
- }
-
int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
if (rc < 0) {
ALOGE("%s: asprintf failed\n", __func__);
@@ -274,24 +247,6 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len) {
open_flags |= O_TRUNC;
if (req->flags & STORAGE_FILE_OPEN_CREATE) {
- /*
- * Create the alternate parent dir if needed & allowed.
- *
- * TODO(b/210501710): Expose GSI image running state to vendor
- * storageproxyd. This directory should be created by vendor_init, once
- * it has access to the necessary bit of information.
- */
- if (strstr(req->name, ALTERNATE_DATA_DIR) == req->name) {
- char* parent_path = dirname(path);
- rc = mkdir(parent_path, S_IRWXU);
- if (rc == 0) {
- sync_parent(parent_path);
- } else if (errno != EEXIST) {
- ALOGE("%s: Could not create parent directory \"%s\": %s\n", __func__, parent_path,
- strerror(errno));
- }
- }
-
/* open or create */
if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
/* create exclusive */
@@ -324,10 +279,6 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len) {
msg->result = translate_errno(rc);
goto err_response;
}
-
- if (open_flags & O_CREAT) {
- sync_parent(path);
- }
free(path);
/* at this point rc contains storage file fd */
@@ -516,14 +467,17 @@ err_response:
int storage_init(const char *dirname)
{
- /* If there is an active DSU image, use the alternate fs mode. */
- alternate_mode = is_gsi_running();
-
fs_state = SS_CLEAN;
+ dir_state = SS_CLEAN;
for (uint i = 0; i < FD_TBL_SIZE; i++) {
fd_state[i] = SS_UNUSED; /* uninstalled */
}
+ ssdir_fd = open(dirname, O_RDONLY);
+ if (ssdir_fd < 0) {
+ ALOGE("failed to open ss root dir \"%s\": %s\n",
+ dirname, strerror(errno));
+ }
ssdir_name = dirname;
return 0;
}
@@ -547,16 +501,25 @@ int storage_sync_checkpoint(void)
}
}
- /* check if we need to sync all filesystems */
+ /* check if we need to sync the directory */
+ if (dir_state == SS_DIRTY) {
+ if (fs_state == SS_CLEAN) {
+ rc = fsync(ssdir_fd);
+ if (rc < 0) {
+ ALOGE("fsync for ssdir failed: %s\n", strerror(errno));
+ return rc;
+ }
+ }
+ dir_state = SS_CLEAN; /* set to clean */
+ }
+
+ /* check if we need to sync the whole fs */
if (fs_state == SS_DIRTY) {
- /*
- * We sync all filesystems here because we don't know what filesystem
- * needs syncing if there happen to be other filesystems symlinked under
- * the root data directory. This should not happen in the normal case
- * because our fd table is large enough to handle the few open files we
- * use.
- */
- sync();
+ rc = syscall(SYS_syncfs, ssdir_fd);
+ if (rc < 0) {
+ ALOGE("syncfs failed: %s\n", strerror(errno));
+ return rc;
+ }
fs_state = SS_CLEAN;
}
diff --git a/trusty/test/driver/Android.bp b/trusty/test/driver/Android.bp
deleted file mode 100644
index b813a04cc..000000000
--- a/trusty/test/driver/Android.bp
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-python_test {
- name: "trusty_driver_test",
- srcs: [
- "**/*.py",
- ],
- test_suites: ["general-tests"],
- version: {
- py3: {
- embedded_launcher: true,
- enabled: true,
- },
- },
-}
diff --git a/trusty/test/driver/trusty_driver_test.py b/trusty/test/driver/trusty_driver_test.py
deleted file mode 100644
index 608fd470f..000000000
--- a/trusty/test/driver/trusty_driver_test.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2022 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Test cases for Trusty Linux Driver."""
-
-import os
-import unittest
-
-def ReadFile(file_path):
- with open(file_path, 'r') as f:
- # Strip all trailing spaces, newline and null characters.
- return f.read().rstrip(' \n\x00')
-
-def WriteFile(file_path, s):
- with open(file_path, 'w') as f:
- f.write(s)
-
-def IsTrustySupported():
- return os.path.exists("/dev/trusty-ipc-dev0")
-
-@unittest.skipIf(not IsTrustySupported(), "Device does not support Trusty")
-class TrustyDriverTest(unittest.TestCase):
- def testIrqDriverBinding(self):
- WriteFile("/sys/bus/platform/drivers/trusty-irq/unbind", "trusty:irq")
- WriteFile("/sys/bus/platform/drivers/trusty-irq/bind", "trusty:irq")
-
- def testLogDriverBinding(self):
- WriteFile("/sys/bus/platform/drivers/trusty-log/unbind", "trusty:log")
- WriteFile("/sys/bus/platform/drivers/trusty-log/bind", "trusty:log")
-
- @unittest.skip("TODO(b/142275662): virtio remove currently hangs")
- def testVirtioDriverBinding(self):
- WriteFile("/sys/bus/platform/drivers/trusty-virtio/unbind",
- "trusty:virtio")
- WriteFile("/sys/bus/platform/drivers/trusty-virtio/bind",
- "trusty:virtio")
-
- @unittest.skip("TODO(b/142275662): virtio remove currently hangs")
- def testTrustyDriverBinding(self):
- WriteFile("/sys/bus/platform/drivers/trusty/unbind", "trusty")
- WriteFile("/sys/bus/platform/drivers/trusty/bind", "trusty")
-
- def testTrustyDriverVersion(self):
- ver = ReadFile("/sys/bus/platform/devices/trusty/trusty_version")
- self.assertTrue(ver.startswith("Project:"))
-
- def testUntaintedLinux(self):
- tainted = ReadFile("/proc/sys/kernel/tainted")
- self.assertEqual(tainted, "0")
-
- # stdcall test with shared memory buffers.
- # Each test run takes up to 4 arguments:
- # <obj_size>,<obj_count=1>,<repeat_share=1>,<repeat_access=3>
- #
- # Test single 4K shared memory object.
- # Test 10 8MB objects, shared twice, each accessed twice. (8MB non-
- # contiguous object is large enough to need several 4KB messages to
- # describe)
- # Test sharing 2 8MB objects 100 times without accessing it.
- # Test 10 4K shared memory objects, shared 10 times, each accessed
- # 10 times.
- def testStdCall(self):
- test = "/sys/devices/platform/trusty/trusty:test/trusty_test_run"
- args = "0x1000 0x800000,10,2,2 0x800000,2,100,0 0x1000,10,10,10"
- WriteFile(test, args)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/trusty/trusty-base.mk b/trusty/trusty-base.mk
index d40a59e36..b42d665d8 100644
--- a/trusty/trusty-base.mk
+++ b/trusty/trusty-base.mk
@@ -28,9 +28,5 @@ PRODUCT_PACKAGES += \
trusty_apploader
PRODUCT_PROPERTY_OVERRIDES += \
- ro.hardware.keystore_desede=true \
ro.hardware.keystore=trusty \
ro.hardware.gatekeeper=trusty
-
-PRODUCT_COPY_FILES += \
- frameworks/native/data/etc/android.hardware.keystore.app_attest_key.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.keystore.app_attest_key.xml
diff --git a/trusty/trusty-test.mk b/trusty/trusty-test.mk
index 3a4377491..74106ec58 100644
--- a/trusty/trusty-test.mk
+++ b/trusty/trusty-test.mk
@@ -13,7 +13,7 @@
# limitations under the License.
PRODUCT_PACKAGES += \
- keymaster_soft_attestation_keys.xml \
spiproxyd \
- trusty_driver_test \
trusty_keymaster_set_attestation_key \
+ keymaster_soft_attestation_keys.xml \
+
diff --git a/trusty/utils/acvp/acvp_ipc.h b/trusty/utils/acvp/acvp_ipc.h
index 300e05acf..8b48ae3cd 100644
--- a/trusty/utils/acvp/acvp_ipc.h
+++ b/trusty/utils/acvp/acvp_ipc.h
@@ -27,7 +27,7 @@ extern "C" {
/*
* Maximum number of arguments
*/
-#define ACVP_MAX_NUM_ARGUMENTS 9
+#define ACVP_MAX_NUM_ARGUMENTS 8
/*
* Maximum length of an algorithm name
diff --git a/trusty/utils/rpmb_dev/Android.bp b/trusty/utils/rpmb_dev/Android.bp
index a2700876a..c5853efcb 100644
--- a/trusty/utils/rpmb_dev/Android.bp
+++ b/trusty/utils/rpmb_dev/Android.bp
@@ -12,7 +12,13 @@
// limitations under the License.
package {
- default_applicable_licenses: ["Android-Apache-2.0"],
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_core_trusty_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["system_core_trusty_license"],
}
cc_binary {
diff --git a/trusty/utils/rpmb_dev/rpmb_dev.c b/trusty/utils/rpmb_dev/rpmb_dev.c
index 0a9e6a13f..202562114 100644
--- a/trusty/utils/rpmb_dev/rpmb_dev.c
+++ b/trusty/utils/rpmb_dev/rpmb_dev.c
@@ -1,17 +1,25 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
#define LOG_TAG "rpmb_mock"
diff --git a/usbd/Android.bp b/usbd/Android.bp
index 27db0fa6b..22d171de4 100644
--- a/usbd/Android.bp
+++ b/usbd/Android.bp
@@ -13,5 +13,6 @@ cc_binary {
"libutils",
"libhardware",
"android.hardware.usb.gadget@1.0",
+ "libcutils",
],
}