summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-04 15:21:49 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-10-04 15:21:49 +0000
commit0ae6bbb1889ae56b291faf50667b006c12005e68 (patch)
tree26c17cc57f9b457b9ec14cc351810c153d48c88c
parentcca451588a16d338ff8b58456529a40a7c27e7bd (diff)
parent6b87cde39465cf8b7f42839d8e34d56dc509266d (diff)
downloadnative-0ae6bbb1889ae56b291faf50667b006c12005e68.tar.gz
Merge "Snap for 10900817 from efed5f1359e547e0afb60c1fa6335d9be9c44320 to sdk-release" into sdk-releaseplatform-tools-34.0.5
-rw-r--r--cmds/atrace/atrace.cpp6
-rw-r--r--cmds/atrace/atrace.rc24
-rw-r--r--cmds/cmd/Android.bp3
-rw-r--r--cmds/cmd/cmd.cpp23
-rw-r--r--cmds/dumpstate/DumpstateUtil.cpp9
-rw-r--r--cmds/dumpstate/DumpstateUtil.h8
-rw-r--r--cmds/dumpstate/dumpstate.cpp39
-rw-r--r--cmds/dumpsys/dumpsys.cpp4
-rw-r--r--cmds/installd/CrateManager.cpp3
-rw-r--r--cmds/installd/CrateManager.h1
-rw-r--r--cmds/installd/InstalldNativeService.cpp204
-rw-r--r--cmds/installd/InstalldNativeService.h31
-rw-r--r--cmds/installd/binder/android/os/CreateAppDataResult.aidl1
-rw-r--r--cmds/installd/binder/android/os/IInstalld.aidl16
-rw-r--r--cmds/installd/dexopt.h5
-rw-r--r--cmds/installd/otapreopt.cpp112
-rw-r--r--cmds/installd/otapreopt_chroot.cpp122
-rw-r--r--cmds/installd/otapreopt_script.sh59
-rw-r--r--cmds/installd/run_dex2oat.cpp37
-rw-r--r--cmds/installd/run_dex2oat_test.cpp18
-rw-r--r--cmds/installd/tests/installd_dexopt_test.cpp44
-rw-r--r--cmds/installd/tests/installd_service_test.cpp101
-rw-r--r--cmds/installd/utils.h1
-rw-r--r--cmds/servicemanager/Android.bp19
-rw-r--r--cmds/servicemanager/OWNERS3
-rw-r--r--cmds/servicemanager/ServiceManager.cpp21
-rw-r--r--cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp48
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4bin144 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42bin168 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43bin152 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44bin168 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8bin136 -> 0 bytes
-rw-r--r--cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9bin40 -> 0 bytes
-rw-r--r--cmds/servicemanager/main.cpp2
-rw-r--r--data/etc/Android.bp24
-rw-r--r--data/etc/android.hardware.thread_network.xml19
-rw-r--r--headers/media_plugin/media/openmax/OMX_AsString.h1
-rw-r--r--headers/media_plugin/media/openmax/OMX_IndexExt.h1
-rw-r--r--include/android/bitmap.h4
-rw-r--r--include/android/sharedmem.h4
-rw-r--r--include/android/thermal.h4
-rw-r--r--include/ftl/OWNERS1
-rw-r--r--libs/binder/Android.bp3
-rw-r--r--libs/binder/BpBinder.cpp4
-rw-r--r--libs/binder/IActivityManager.cpp4
-rw-r--r--libs/binder/IServiceManager.cpp14
-rw-r--r--libs/binder/MemoryDealer.cpp2
-rw-r--r--libs/binder/Parcel.cpp12
-rw-r--r--libs/binder/PermissionCache.cpp5
-rw-r--r--libs/binder/ProcessState.cpp6
-rw-r--r--libs/binder/RecordedTransaction.cpp2
-rw-r--r--libs/binder/include/binder/TextOutput.h2
-rw-r--r--libs/binder/ndk/.clang-format2
-rw-r--r--libs/binder/ndk/include_cpp/android/binder_auto_utils.h26
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_status.h1
-rw-r--r--libs/binder/ndk/tests/Android.bp22
-rw-r--r--libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp34
-rw-r--r--libs/binder/ndk/tests/libbinder_ndk_unit_test_host.cpp104
-rw-r--r--libs/binder/rust/Android.bp29
-rw-r--r--libs/binder/rust/binder_tokio/lib.rs7
-rw-r--r--libs/binder/rust/libbinder_ndk_bindgen_flags.txt11
-rw-r--r--libs/binder/rust/rpcbinder/src/server.rs21
-rw-r--r--libs/binder/rust/rpcbinder/src/session.rs16
-rw-r--r--libs/binder/rust/src/binder.rs74
-rw-r--r--libs/binder/rust/src/error.rs316
-rw-r--r--libs/binder/rust/src/lib.rs2
-rw-r--r--libs/binder/rust/src/native.rs189
-rw-r--r--libs/binder/rust/src/parcel.rs167
-rw-r--r--libs/binder/rust/src/parcel/file_descriptor.rs51
-rw-r--r--libs/binder/rust/src/parcel/parcelable.rs285
-rw-r--r--libs/binder/rust/src/parcel/parcelable_holder.rs14
-rw-r--r--libs/binder/rust/src/proxy.rs460
-rw-r--r--libs/binder/rust/src/state.rs24
-rw-r--r--libs/binder/rust/sys/lib.rs15
-rw-r--r--libs/binder/rust/tests/integration.rs5
-rw-r--r--libs/binder/rust/tests/ndk_rust_interop.rs10
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/Android.bp26
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs4
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp14
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs22
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp4
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/read_utils.rs3
-rw-r--r--libs/binder/rust/tests/serialization.rs40
-rw-r--r--libs/binder/tests/Android.bp2
-rw-r--r--libs/binder/tests/IBinderRpcBenchmark.aidl3
-rw-r--r--libs/binder/tests/binderAllocationLimits.cpp10
-rw-r--r--libs/binder/tests/binderRecordReplayTest.cpp127
-rw-r--r--libs/binder/tests/binderRpcBenchmark.cpp70
-rw-r--r--libs/binder/tests/binderRpcTest.cpp89
-rw-r--r--libs/binder/tests/binderRpcTestFixture.h35
-rw-r--r--libs/binder/tests/binderRpcTestTrusty.cpp33
-rw-r--r--libs/binder/tests/binderRpcUniversalTests.cpp2
-rw-r--r--libs/binder/tests/parcel_fuzzer/Android.bp40
-rw-r--r--libs/binder/tests/parcel_fuzzer/binder2corpus/README.md31
-rw-r--r--libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp90
-rw-r--r--libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h47
-rw-r--r--libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp23
-rw-r--r--libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp14
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_fd.cpp93
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp146
-rw-r--r--libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp46
-rwxr-xr-xlibs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh4
-rw-r--r--libs/binder/tests/rpc_fuzzer/main.cpp2
-rw-r--r--libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp1
-rw-r--r--libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp2
-rw-r--r--libs/binder/trusty/fuzzer/Android.bp39
-rw-r--r--libs/binder/trusty/rust/binder_ndk_sys/rules.mk38
-rw-r--r--libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp1
-rw-r--r--libs/fakeservicemanager/Android.bp39
-rw-r--r--libs/fakeservicemanager/FakeServiceManager.cpp39
-rw-r--r--libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h2
-rw-r--r--libs/fakeservicemanager/rust/src/lib.rs34
-rw-r--r--libs/fakeservicemanager/rust/wrappers/FakeServiceManagerWrapper.hpp25
-rw-r--r--libs/fakeservicemanager/test_sm.cpp36
-rw-r--r--libs/ftl/OWNERS1
-rw-r--r--libs/graphicsenv/GraphicsEnv.cpp22
-rw-r--r--libs/gui/BufferItemConsumer.cpp10
-rw-r--r--libs/gui/BufferQueueConsumer.cpp15
-rw-r--r--libs/gui/BufferQueueCore.cpp51
-rw-r--r--libs/gui/BufferQueueProducer.cpp23
-rw-r--r--libs/gui/ConsumerBase.cpp18
-rw-r--r--libs/gui/CpuConsumer.cpp10
-rw-r--r--libs/gui/GLConsumer.cpp10
-rw-r--r--libs/gui/OWNERS2
-rw-r--r--libs/gui/SurfaceComposerClient.cpp2
-rw-r--r--libs/gui/include/gui/BufferQueueCore.h14
-rw-r--r--libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h2
-rw-r--r--libs/gui/tests/GLTest.cpp24
-rw-r--r--libs/gui/tests/OWNERS6
-rw-r--r--libs/gui/tests/SurfaceTextureFBO_test.cpp2
-rw-r--r--libs/gui/tests/SurfaceTextureGL_test.cpp7
-rw-r--r--libs/gui/tests/Surface_test.cpp2
-rw-r--r--libs/input/KeyCharacterMap.cpp127
-rw-r--r--libs/input/KeyLayoutMap.cpp129
-rw-r--r--libs/input/Keyboard.cpp8
-rw-r--r--libs/input/PropertyMap.cpp32
-rw-r--r--libs/input/VirtualKeyMap.cpp19
-rw-r--r--libs/nativedisplay/surfacetexture/EGLConsumer.cpp8
-rw-r--r--libs/nativedisplay/surfacetexture/ImageConsumer.cpp2
-rw-r--r--libs/nativedisplay/surfacetexture/SurfaceTexture.cpp8
-rw-r--r--libs/nativewindow/include/android/data_space.h14
-rw-r--r--libs/nativewindow/include/android/hardware_buffer_aidl.h22
-rw-r--r--libs/renderengine/OWNERS2
-rw-r--r--libs/renderengine/gl/GLExtensions.cpp12
-rw-r--r--libs/renderengine/gl/ProgramCache.cpp4
-rw-r--r--libs/sensor/Sensor.cpp8
-rw-r--r--libs/sensor/SensorManager.cpp7
-rw-r--r--libs/ui/DebugUtils.cpp6
-rw-r--r--libs/ui/Fence.cpp2
-rw-r--r--libs/ui/include/ui/FatVector.h11
-rw-r--r--opengl/libs/EGL/egl_platform_entries.cpp15
-rw-r--r--services/gpuservice/GpuService.cpp2
-rw-r--r--services/gpuservice/gpumem/GpuMem.cpp2
-rw-r--r--services/gpuservice/gpumem/include/gpumem/GpuMem.h4
-rw-r--r--services/gpuservice/tests/unittests/GpuMemTest.cpp4
-rw-r--r--services/gpuservice/tests/unittests/GpuMemTracerTest.cpp4
-rw-r--r--services/gpuservice/tests/unittests/TestableGpuMem.h2
-rw-r--r--services/inputflinger/BlockingQueue.h3
-rw-r--r--services/inputflinger/OWNERS1
-rw-r--r--services/inputflinger/host/InputDriver.cpp6
-rw-r--r--services/inputflinger/host/InputFlinger.cpp2
-rw-r--r--services/inputflinger/reader/mapper/CursorInputMapper.cpp2
-rw-r--r--services/inputflinger/reader/mapper/TouchInputMapper.cpp16
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp2
-rw-r--r--services/sensorservice/RecentEventLogger.cpp2
-rw-r--r--services/sensorservice/SensorDevice.cpp2
-rw-r--r--services/sensorservice/SensorDirectConnection.cpp4
-rw-r--r--services/sensorservice/SensorEventConnection.cpp8
-rw-r--r--services/sensorservice/SensorFusion.cpp11
-rw-r--r--services/sensorservice/SensorList.cpp18
-rw-r--r--services/sensorservice/SensorRegistrationInfo.h2
-rw-r--r--services/sensorservice/SensorService.cpp48
-rw-r--r--services/sensorservice/aidl/SensorManager.cpp5
-rw-r--r--services/sensorservice/hidl/utils.cpp4
-rw-r--r--services/sensorservice/tests/sensorservicetest.cpp4
-rw-r--r--services/surfaceflinger/BufferLayerConsumer.cpp10
-rw-r--r--services/surfaceflinger/CompositionEngine/Android.bp14
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp2
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp30
-rw-r--r--services/surfaceflinger/OWNERS4
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp6
-rw-r--r--services/surfaceflinger/SurfaceInterceptor.cpp2
-rw-r--r--services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h2
-rw-r--r--services/surfaceflinger/tests/SurfaceInterceptor_test.cpp6
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp4
-rw-r--r--services/surfaceflinger/tests/utils/ScreenshotUtils.h2
-rw-r--r--services/vibratorservice/OWNERS2
-rw-r--r--services/vr/virtual_touchpad/VirtualTouchpadService.cpp2
-rw-r--r--vulkan/libvulkan/driver.cpp11
-rw-r--r--vulkan/libvulkan/layers_extensions.cpp4
-rw-r--r--vulkan/libvulkan/swapchain.cpp45
231 files changed, 3438 insertions, 1760 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 81056262c3..5719a09a16 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -692,7 +692,7 @@ static bool verifyKernelTraceFuncs(const char* funcs)
while (func) {
if (!strchr(func, '*')) {
String8 fancyFunc = String8::format("\n%s\n", func);
- bool found = funcList.find(fancyFunc.string(), 0) >= 0;
+ bool found = funcList.find(fancyFunc.c_str(), 0) >= 0;
if (!found || func[0] == '\0') {
fprintf(stderr, "error: \"%s\" is not a valid kernel function "
"to trace.\n", func);
@@ -796,11 +796,11 @@ static bool setCategoriesEnableFromFile(const char* categories_file)
bool ok = true;
while (!tokenizer->isEol()) {
String8 token = tokenizer->nextToken(" ");
- if (token.isEmpty()) {
+ if (token.empty()) {
tokenizer->skipDelimiters(" ");
continue;
}
- ok &= setCategoryEnable(token.string());
+ ok &= setCategoryEnable(token.c_str());
}
delete tokenizer;
return ok;
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index c3cf2c2a60..3e6d2e01f8 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -93,6 +93,10 @@ on late-init
chmod 0666 /sys/kernel/tracing/events/binder/binder_unlock/enable
chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_set_priority/enable
chmod 0666 /sys/kernel/tracing/events/binder/binder_set_priority/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_command/enable
+ chmod 0666 /sys/kernel/tracing/events/binder/binder_command/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_return/enable
+ chmod 0666 /sys/kernel/tracing/events/binder/binder_return/enable
chmod 0666 /sys/kernel/debug/tracing/events/i2c/enable
chmod 0666 /sys/kernel/tracing/events/i2c/enable
chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
@@ -228,10 +232,6 @@ on late-init
chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable
chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable
-# Tracing disabled by default
- write /sys/kernel/debug/tracing/tracing_on 0
- write /sys/kernel/tracing/tracing_on 0
-
# Read and truncate the kernel trace.
chmod 0666 /sys/kernel/debug/tracing/trace
chmod 0666 /sys/kernel/tracing/trace
@@ -310,11 +310,9 @@ on late-init
chmod 0666 /sys/kernel/tracing/events/synthetic/suspend_resume_minimal/enable
chmod 0666 /sys/kernel/debug/tracing/events/synthetic/suspend_resume_minimal/enable
-on late-init && property:ro.boot.fastboot.boottrace=enabled
- setprop debug.atrace.tags.enableflags 802922
- setprop persist.traced.enable 0
- write /sys/kernel/debug/tracing/tracing_on 1
- write /sys/kernel/tracing/tracing_on 1
+on late-init && property:ro.boot.fastboot.boottrace=
+ write /sys/kernel/debug/tracing/tracing_on 0
+ write /sys/kernel/tracing/tracing_on 0
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
@@ -527,7 +525,6 @@ on late-init && property:ro.boot.hypervisor.vm.supported=1
chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id
chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id
-
on property:persist.debug.atrace.boottrace=1
start boottrace
@@ -536,10 +533,3 @@ service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categ
user root
disabled
oneshot
-
-on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled
- setprop debug.atrace.tags.enableflags 0
- setprop persist.traced.enable 1
- write /sys/kernel/debug/tracing/tracing_on 0
- write /sys/kernel/tracing/tracing_on 0
-
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index c3d2601444..27ef78854c 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -27,6 +27,9 @@ cc_library_static {
"libselinux",
"libbinder",
],
+ whole_static_libs: [
+ "libc++fs",
+ ],
cflags: [
"-Wall",
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 8f1c01ab2c..0ce7711574 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -27,6 +27,7 @@
#include <utils/Mutex.h>
#include <utils/Vector.h>
+#include <filesystem>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
@@ -69,16 +70,14 @@ public:
virtual int openFile(const String16& path, const String16& seLinuxContext,
const String16& mode) {
String8 path8(path);
- char cwd[256];
- getcwd(cwd, 256);
- String8 fullPath(cwd);
- fullPath.appendPath(path8);
+ auto fullPath = std::filesystem::current_path();
+ fullPath /= path8.c_str();
if (!mActive) {
mErrorLog << "Open attempt after active for: " << fullPath << endl;
return -EPERM;
}
#if DEBUG
- ALOGD("openFile: %s, full=%s", path8.string(), fullPath.string());
+ ALOGD("openFile: %s, full=%s", path8.c_str(), fullPath.c_str());
#endif
int flags = 0;
bool checkRead = false;
@@ -96,10 +95,10 @@ public:
flags = O_RDWR;
checkRead = checkWrite = true;
} else {
- mErrorLog << "Invalid mode requested: " << mode.string() << endl;
+ mErrorLog << "Invalid mode requested: " << mode.c_str() << endl;
return -EINVAL;
}
- int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG);
+ int fd = open(fullPath.c_str(), flags, S_IRWXU|S_IRWXG);
#if DEBUG
ALOGD("openFile: fd=%d", fd);
#endif
@@ -109,29 +108,29 @@ public:
if (is_selinux_enabled() && seLinuxContext.size() > 0) {
String8 seLinuxContext8(seLinuxContext);
char* tmp = nullptr;
- getfilecon(fullPath.string(), &tmp);
+ getfilecon(fullPath.c_str(), &tmp);
Unique_SecurityContext context(tmp);
if (checkWrite) {
- int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+ int accessGranted = selinux_check_access(seLinuxContext8.c_str(), context.get(),
"file", "write", nullptr);
if (accessGranted != 0) {
#if DEBUG
ALOGD("openFile: failed selinux write check!");
#endif
close(fd);
- mErrorLog << "System server has no access to write file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl;
+ mErrorLog << "System server has no access to write file context " << context.get() << " (from path " << fullPath.c_str() << ", context " << seLinuxContext8.c_str() << ")" << endl;
return -EPERM;
}
}
if (checkRead) {
- int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+ int accessGranted = selinux_check_access(seLinuxContext8.c_str(), context.get(),
"file", "read", nullptr);
if (accessGranted != 0) {
#if DEBUG
ALOGD("openFile: failed selinux read check!");
#endif
close(fd);
- mErrorLog << "System server has no access to read file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl;
+ mErrorLog << "System server has no access to read file context " << context.get() << " (from path " << fullPath.c_str() << ", context " << seLinuxContext8.c_str() << ")" << endl;
return -EPERM;
}
}
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index aa42541a66..615701ccc1 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -207,6 +207,7 @@ std::string PropertiesHelper::build_type_ = "";
int PropertiesHelper::dry_run_ = -1;
int PropertiesHelper::unroot_ = -1;
int PropertiesHelper::parallel_run_ = -1;
+int PropertiesHelper::strict_run_ = -1;
bool PropertiesHelper::IsUserBuild() {
if (build_type_.empty()) {
@@ -237,6 +238,14 @@ bool PropertiesHelper::IsParallelRun() {
return parallel_run_ == 1;
}
+bool PropertiesHelper::IsStrictRun() {
+ if (strict_run_ == -1) {
+ // Defaults to using stricter timeouts.
+ strict_run_ = android::base::GetBoolProperty("dumpstate.strict_run", true) ? 1 : 0;
+ }
+ return strict_run_ == 1;
+}
+
int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
if (fd.get() < 0) {
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index b00c46e0db..9e955e3c04 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -193,11 +193,19 @@ class PropertiesHelper {
*/
static bool IsParallelRun();
+ /*
+ * Strict-run mode is determined by the `dumpstate.strict_run` sysprop which
+ * will default to true. This results in shortened timeouts for flaky
+ * sections.
+ */
+ static bool IsStrictRun();
+
private:
static std::string build_type_;
static int dry_run_;
static int unroot_;
static int parallel_run_;
+ static int strict_run_;
};
/*
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index dc0e26b9a3..e18c8e380d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -186,6 +186,7 @@ void add_mountinfo();
#define CGROUPFS_DIR "/sys/fs/cgroup"
#define SDK_EXT_INFO "/apex/com.android.sdkext/bin/derive_sdk"
#define DROPBOX_DIR "/data/system/dropbox"
+#define PRINT_FLAGS "/system/bin/printflags"
// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
@@ -820,9 +821,12 @@ void Dumpstate::PrintHeader() const {
RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
CommandOptions::WithTimeout(1).Always().Build());
printf("Bugreport format version: %s\n", version_.c_str());
- printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
- id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
- options_->args.c_str(), options_->bugreport_mode_string.c_str());
+ printf(
+ "Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d strict_run=%d args=%s "
+ "bugreport_mode=%s\n",
+ id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
+ PropertiesHelper::IsStrictRun(), options_->args.c_str(),
+ options_->bugreport_mode_string.c_str());
printf("\n");
}
@@ -1044,7 +1048,8 @@ static void DumpIncidentReport() {
MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
return;
}
- RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(20).Build());
+ RunCommandToFd(fd, "", {"incident", "-u"},
+ CommandOptions::WithTimeout(PropertiesHelper::IsStrictRun() ? 20 : 120).Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
if (!empty) {
// Use a different name from "incident.proto"
@@ -1414,12 +1419,12 @@ static void DumpHals(int out_fd = STDOUT_FILENO) {
auto ret = sm->list([&](const auto& interfaces) {
for (const std::string& interface : interfaces) {
std::string cleanName = interface;
- std::replace_if(cleanName.begin(),
- cleanName.end(),
- [](char c) {
- return !isalnum(c) &&
- std::string("@-_:.").find(c) == std::string::npos;
- }, '_');
+ std::replace_if(
+ cleanName.begin(), cleanName.end(),
+ [](char c) {
+ return !isalnum(c) && std::string("@-_.").find(c) == std::string::npos;
+ },
+ '_');
const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
bool empty = false;
@@ -1750,6 +1755,14 @@ static Dumpstate::RunStatus dumpstate() {
RunCommand("SYSTEM PROPERTIES", {"getprop"});
+ DumpFile("SYSTEM BUILD-TIME RELEASE FLAGS", "/system/etc/build_flags.json");
+ DumpFile("SYSTEM_EXT BUILD-TIME RELEASE FLAGS", "/system_ext/etc/build_flags.json");
+ DumpFile("PRODUCT BUILD-TIME RELEASE FLAGS", "/product/etc/build_flags.json");
+ DumpFile("VENDOR BUILD-TIME RELEASE FLAGS", "/vendor/etc/build_flags.json");
+
+ RunCommand("ACONFIG FLAGS", {PRINT_FLAGS},
+ CommandOptions::WithTimeout(10).Always().DropRoot().Build());
+
RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
@@ -3053,6 +3066,12 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
+ if (PropertiesHelper::IsStrictRun()) {
+ MYLOGI(
+ "Running on strict-run mode, which has shorter timeouts "
+ "(to disable, call 'setprop dumpstate.strict_run false')\n");
+ }
+
MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n",
id_, options_->args.c_str(), options_->bugreport_mode_string.c_str(), version_.c_str());
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 3d2bdf1d6f..6c4e4b3bc3 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -543,7 +543,7 @@ status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::mi
if ((status == TIMED_OUT) && (!asProto)) {
std::string msg = StringPrintf("\n*** SERVICE '%s' DUMP TIMEOUT (%llums) EXPIRED ***\n\n",
- String8(serviceName).string(), timeout.count());
+ String8(serviceName).c_str(), timeout.count());
WriteStringToFd(msg, fd);
}
@@ -562,6 +562,6 @@ void Dumpsys::writeDumpFooter(int fd, const String16& serviceName,
oss << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S");
std::string msg =
StringPrintf("--------- %.3fs was the duration of dumpsys %s, ending at: %s\n",
- elapsedDuration.count(), String8(serviceName).string(), oss.str().c_str());
+ elapsedDuration.count(), String8(serviceName).c_str(), oss.str().c_str());
WriteStringToFd(msg, fd);
}
diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp
index b17cba15d5..fd1df35aee 100644
--- a/cmds/installd/CrateManager.cpp
+++ b/cmds/installd/CrateManager.cpp
@@ -29,9 +29,10 @@
#include <sys/xattr.h>
#include <unistd.h>
+#include <utils.h>
#include <fstream>
+#include <functional>
#include <string>
-#include <utils.h>
#include "utils.h"
diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h
index 1f30b5dc79..d9b590f784 100644
--- a/cmds/installd/CrateManager.h
+++ b/cmds/installd/CrateManager.h
@@ -25,6 +25,7 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <functional>
#include <optional>
#include <string>
#include <vector>
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index c6132e8ceb..073d0c4854 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -19,6 +19,7 @@
#include <errno.h>
#include <fts.h>
#include <inttypes.h>
+#include <linux/fsverity.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -51,6 +52,7 @@
#include <android-base/unique_fd.h>
#include <cutils/ashmem.h>
#include <cutils/fs.h>
+#include <cutils/misc.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <linux/quota.h>
@@ -84,6 +86,8 @@
using android::base::ParseUint;
using android::base::Split;
using android::base::StringPrintf;
+using android::base::unique_fd;
+using android::os::ParcelFileDescriptor;
using std::endl;
namespace android {
@@ -229,6 +233,14 @@ binder::Status checkArgumentFileName(const std::string& path) {
return ok();
}
+binder::Status checkUidInAppRange(int32_t appUid) {
+ if (FIRST_APPLICATION_UID <= appUid && appUid <= LAST_APPLICATION_UID) {
+ return ok();
+ }
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("UID %d is outside of the range", appUid));
+}
+
#define ENFORCE_UID(uid) { \
binder::Status status = checkUid((uid)); \
if (!status.isOk()) { \
@@ -236,6 +248,22 @@ binder::Status checkArgumentFileName(const std::string& path) {
} \
}
+// we could have tighter checks, but this is only to avoid hard errors. Negative values are defined
+// in UserHandle.java and carry specific meanings that may not be handled by certain APIs here.
+#define ENFORCE_VALID_USER(userId) \
+ { \
+ if (static_cast<uid_t>(userId) >= std::numeric_limits<uid_t>::max() / AID_USER_OFFSET) { \
+ return error("userId invalid: " + std::to_string(userId)); \
+ } \
+ }
+
+#define ENFORCE_VALID_USER_OR_NULL(userId) \
+ { \
+ if (static_cast<uid_t>(userId) != USER_NULL) { \
+ ENFORCE_VALID_USER(userId); \
+ } \
+ }
+
#define CHECK_ARGUMENT_UUID(uuid) { \
binder::Status status = checkArgumentUuid((uuid)); \
if (!status.isOk()) { \
@@ -273,6 +301,14 @@ binder::Status checkArgumentFileName(const std::string& path) {
} \
}
+#define CHECK_ARGUMENT_UID_IN_APP_RANGE(uid) \
+ { \
+ binder::Status status = checkUidInAppRange((uid)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+ }
+
#ifdef GRANULAR_LOCKS
/**
@@ -373,6 +409,33 @@ using PackageLockGuard = std::lock_guard<PackageLock>;
} // namespace
+binder::Status InstalldNativeService::FsveritySetupAuthToken::authenticate(
+ const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId) {
+ int open_flags = fcntl(authFd.get(), F_GETFL);
+ if (open_flags < 0) {
+ return exception(binder::Status::EX_SERVICE_SPECIFIC, "fcntl failed");
+ }
+ if ((open_flags & O_ACCMODE) != O_WRONLY && (open_flags & O_ACCMODE) != O_RDWR) {
+ return exception(binder::Status::EX_SECURITY, "Received FD with unexpected open flag");
+ }
+ if (fstat(authFd.get(), &this->mStatFromAuthFd) < 0) {
+ return exception(binder::Status::EX_SERVICE_SPECIFIC, "fstat failed");
+ }
+ if (!S_ISREG(this->mStatFromAuthFd.st_mode)) {
+ return exception(binder::Status::EX_SECURITY, "Not a regular file");
+ }
+ // Don't accept a file owned by a different app.
+ uid_t uid = multiuser_get_uid(userId, appUid);
+ if (this->mStatFromAuthFd.st_uid != uid) {
+ return exception(binder::Status::EX_SERVICE_SPECIFIC, "File not owned by appUid");
+ }
+ return ok();
+}
+
+bool InstalldNativeService::FsveritySetupAuthToken::isSameStat(const struct stat& st) const {
+ return memcmp(&st, &mStatFromAuthFd, sizeof(st)) == 0;
+}
+
status_t InstalldNativeService::start() {
IPCThreadState::self()->disableBackgroundScheduling(true);
status_t ret = BinderService<InstalldNativeService>::publish();
@@ -694,8 +757,9 @@ static binder::Status createAppDataDirs(const std::string& path, int32_t uid, in
binder::Status InstalldNativeService::createAppDataLocked(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
- int32_t targetSdkVersion, int64_t* _aidl_return) {
+ int32_t targetSdkVersion, int64_t* ceDataInode, int64_t* deDataInode) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -703,7 +767,8 @@ binder::Status InstalldNativeService::createAppDataLocked(
const char* pkgname = packageName.c_str();
// Assume invalid inode unless filled in below
- if (_aidl_return != nullptr) *_aidl_return = -1;
+ if (ceDataInode != nullptr) *ceDataInode = -1;
+ if (deDataInode != nullptr) *deDataInode = -1;
int32_t uid = multiuser_get_uid(userId, appId);
@@ -741,12 +806,12 @@ binder::Status InstalldNativeService::createAppDataLocked(
// And return the CE inode of the top-level data directory so we can
// clear contents while CE storage is locked
- if (_aidl_return != nullptr) {
+ if (ceDataInode != nullptr) {
ino_t result;
if (get_path_inode(path, &result) != 0) {
return error("Failed to get_path_inode for " + path);
}
- *_aidl_return = static_cast<uint64_t>(result);
+ *ceDataInode = static_cast<uint64_t>(result);
}
}
if (flags & FLAG_STORAGE_DE) {
@@ -765,6 +830,14 @@ binder::Status InstalldNativeService::createAppDataLocked(
if (!prepare_app_profile_dir(packageName, appId, userId)) {
return error("Failed to prepare profiles for " + packageName);
}
+
+ if (deDataInode != nullptr) {
+ ino_t result;
+ if (get_path_inode(path, &result) != 0) {
+ return error("Failed to get_path_inode for " + path);
+ }
+ *deDataInode = static_cast<uint64_t>(result);
+ }
}
if (flags & FLAG_STORAGE_SDK) {
@@ -790,6 +863,8 @@ binder::Status InstalldNativeService::createAppDataLocked(
binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t appId, int32_t flags) {
+ ENFORCE_VALID_USER(userId);
+
int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
if (sdkSandboxUid == -1) {
// There no valid sdk sandbox process for this app. Skip creation of data directory
@@ -826,25 +901,30 @@ binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
binder::Status InstalldNativeService::createAppData(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
- int32_t targetSdkVersion, int64_t* _aidl_return) {
+ int32_t targetSdkVersion, int64_t* ceDataInode, int64_t* deDataInode) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
return createAppDataLocked(uuid, packageName, userId, flags, appId, previousAppId, seInfo,
- targetSdkVersion, _aidl_return);
+ targetSdkVersion, ceDataInode, deDataInode);
}
binder::Status InstalldNativeService::createAppData(
const android::os::CreateAppDataArgs& args,
android::os::CreateAppDataResult* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(args.userId);
// Locking is performed depeer in the callstack.
int64_t ceDataInode = -1;
+ int64_t deDataInode = -1;
auto status = createAppData(args.uuid, args.packageName, args.userId, args.flags, args.appId,
- args.previousAppId, args.seInfo, args.targetSdkVersion, &ceDataInode);
+ args.previousAppId, args.seInfo, args.targetSdkVersion,
+ &ceDataInode, &deDataInode);
_aidl_return->ceDataInode = ceDataInode;
+ _aidl_return->deDataInode = deDataInode;
_aidl_return->exceptionCode = status.exceptionCode();
_aidl_return->exceptionMessage = status.exceptionMessage();
return ok();
@@ -854,6 +934,10 @@ binder::Status InstalldNativeService::createAppDataBatched(
const std::vector<android::os::CreateAppDataArgs>& args,
std::vector<android::os::CreateAppDataResult>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ for (const auto& arg : args) {
+ ENFORCE_VALID_USER(arg.userId);
+ }
+
// Locking is performed depeer in the callstack.
std::vector<android::os::CreateAppDataResult> results;
@@ -868,6 +952,7 @@ binder::Status InstalldNativeService::createAppDataBatched(
binder::Status InstalldNativeService::reconcileSdkData(
const android::os::ReconcileSdkDataArgs& args) {
+ ENFORCE_VALID_USER(args.userId);
// Locking is performed depeer in the callstack.
return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
@@ -891,6 +976,7 @@ binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std::
int userId, int appId, int previousAppId,
const std::string& seInfo, int flags) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -974,6 +1060,7 @@ binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std::
binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -1041,6 +1128,7 @@ binder::Status InstalldNativeService::clearAppProfiles(const std::string& packag
binder::Status InstalldNativeService::clearAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -1132,6 +1220,7 @@ binder::Status InstalldNativeService::clearAppData(const std::optional<std::stri
binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags) {
+ ENFORCE_VALID_USER(userId);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -1218,6 +1307,7 @@ binder::Status InstalldNativeService::deleteReferenceProfile(const std::string&
binder::Status InstalldNativeService::destroyAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -1288,6 +1378,8 @@ binder::Status InstalldNativeService::destroyAppData(const std::optional<std::st
binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags) {
+ ENFORCE_VALID_USER(userId);
+
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -1435,6 +1527,7 @@ binder::Status InstalldNativeService::snapshotAppData(const std::optional<std::s
int32_t userId, int32_t snapshotId,
int32_t storageFlags, int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -1569,6 +1662,7 @@ binder::Status InstalldNativeService::restoreAppDataSnapshot(
const int32_t appId, const std::string& seInfo, const int32_t userId,
const int32_t snapshotId, int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -1641,6 +1735,7 @@ binder::Status InstalldNativeService::destroyAppDataSnapshot(
const int32_t userId, const int64_t ceSnapshotInode, const int32_t snapshotId,
int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -1674,6 +1769,7 @@ binder::Status InstalldNativeService::destroyCeSnapshotsNotSpecified(
const std::optional<std::string>& volumeUuid, const int32_t userId,
const std::vector<int32_t>& retainSnapshotIds) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
LOCK_USER();
@@ -1755,7 +1851,8 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::optional<std::s
}
if (!createAppDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
- appId, /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr)
+ appId, /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr,
+ nullptr)
.isOk()) {
res = error("Failed to create package target");
goto fail;
@@ -1864,6 +1961,7 @@ fail:
binder::Status InstalldNativeService::createUserData(const std::optional<std::string>& uuid,
int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
LOCK_USER();
@@ -1884,6 +1982,7 @@ binder::Status InstalldNativeService::createUserData(const std::optional<std::st
binder::Status InstalldNativeService::destroyUserData(const std::optional<std::string>& uuid,
int32_t userId, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
LOCK_USER();
@@ -2671,6 +2770,7 @@ binder::Status InstalldNativeService::getUserSize(const std::optional<std::strin
int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
// NOTE: Locking is relaxed on this method, since it's limited to
// read-only measurements without mutation.
@@ -2806,6 +2906,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::optional<std::s
int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
// NOTE: Locking is relaxed on this method, since it's limited to
// read-only measurements without mutation.
@@ -2926,6 +3027,7 @@ binder::Status InstalldNativeService::getAppCrates(
const std::vector<std::string>& packageNames, int32_t userId,
std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
for (const auto& packageName : packageNames) {
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -2975,6 +3077,7 @@ binder::Status InstalldNativeService::getUserCrates(
const std::optional<std::string>& uuid, int32_t userId,
std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
#ifdef ENABLE_STORAGE_CRATES
LOCK_USER();
@@ -3018,6 +3121,7 @@ binder::Status InstalldNativeService::getUserCrates(
binder::Status InstalldNativeService::setAppQuota(const std::optional<std::string>& uuid,
int32_t userId, int32_t appId, int64_t cacheQuota) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
@@ -3261,6 +3365,7 @@ binder::Status InstalldNativeService::restoreconAppData(const std::optional<std:
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
const std::string& seInfo) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
LOCK_PACKAGE_USER();
@@ -3271,6 +3376,7 @@ binder::Status InstalldNativeService::restoreconAppDataLocked(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, const std::string& seInfo) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -3302,6 +3408,7 @@ binder::Status InstalldNativeService::restoreconSdkDataLocked(
const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, const std::string& seInfo) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER(userId);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -3753,6 +3860,7 @@ binder::Status InstalldNativeService::prepareAppProfile(const std::string& packa
int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath,
const std::optional<std::string>& dexMetadata, bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ ENFORCE_VALID_USER_OR_NULL(userId);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(codePath);
LOCK_PACKAGE_USER();
@@ -3775,6 +3883,7 @@ binder::Status InstalldNativeService::migrateLegacyObbData() {
binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
const std::optional<std::string>& uuid, int32_t userId, int32_t flags) {
+ ENFORCE_VALID_USER(userId);
const char* uuid_cstr = uuid ? uuid->c_str() : nullptr;
if (flags & FLAG_STORAGE_CE) {
@@ -3814,5 +3923,84 @@ binder::Status InstalldNativeService::getOdexVisibility(
return *_aidl_return == -1 ? error() : ok();
}
+// Creates an auth token to be used in enableFsverity. This token is really to store a proof that
+// the caller can write to a file, represented by the authFd. Effectively, system_server as the
+// attacker-in-the-middle cannot enable fs-verity on arbitrary app files. If the FD is not writable,
+// return null.
+//
+// appUid and userId are passed for additional ownership check, such that one app can not be
+// authenticated for another app's file. These parameters are assumed trusted for this purpose of
+// consistency check.
+//
+// Notably, creating the token allows us to manage the writable FD easily during enableFsverity.
+// Since enabling fs-verity to a file requires no outstanding writable FD, passing the authFd to the
+// server allows the server to hold the only reference (as long as the client app doesn't).
+binder::Status InstalldNativeService::createFsveritySetupAuthToken(
+ const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId,
+ sp<IFsveritySetupAuthToken>* _aidl_return) {
+ CHECK_ARGUMENT_UID_IN_APP_RANGE(appUid);
+ ENFORCE_VALID_USER(userId);
+
+ auto token = sp<FsveritySetupAuthToken>::make();
+ binder::Status status = token->authenticate(authFd, appUid, userId);
+ if (!status.isOk()) {
+ return status;
+ }
+ *_aidl_return = token;
+ return ok();
+}
+
+// Enables fs-verity for filePath, which must be an absolute path and the same inode as in the auth
+// token previously returned from createFsveritySetupAuthToken, and owned by the app uid. As
+// installd is more privileged than its client / system server, we attempt to limit what a
+// (compromised) client can do.
+//
+// The reason for this app request to go through installd is to avoid exposing a risky area (PKCS#7
+// signature verification) in the kernel to the app as an attack surface (it can't be system server
+// because it can't override DAC and manipulate app files). Note that we should be able to drop
+// these hops and simply the app calls the ioctl, once all upgrading devices run with a kernel
+// without fs-verity built-in signature (https://r.android.com/2650402).
+binder::Status InstalldNativeService::enableFsverity(const sp<IFsveritySetupAuthToken>& authToken,
+ const std::string& filePath,
+ const std::string& packageName,
+ int32_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PATH(filePath);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ LOCK_PACKAGE();
+ if (authToken == nullptr) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Received a null auth token");
+ }
+
+ // Authenticate to check the targeting file is the same inode as the authFd.
+ sp<IBinder> authTokenBinder = IInterface::asBinder(authToken)->localBinder();
+ if (authTokenBinder == nullptr) {
+ return exception(binder::Status::EX_SECURITY, "Received a non-local auth token");
+ }
+ auto authTokenInstance = sp<FsveritySetupAuthToken>::cast(authTokenBinder);
+ unique_fd rfd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ struct stat stFromPath;
+ if (fstat(rfd.get(), &stFromPath) < 0) {
+ *_aidl_return = errno;
+ return ok();
+ }
+ if (!authTokenInstance->isSameStat(stFromPath)) {
+ LOG(DEBUG) << "FD authentication failed";
+ *_aidl_return = EPERM;
+ return ok();
+ }
+
+ fsverity_enable_arg arg = {};
+ arg.version = 1;
+ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
+ arg.block_size = 4096;
+ if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, &arg) < 0) {
+ *_aidl_return = errno;
+ } else {
+ *_aidl_return = 0;
+ }
+ return ok();
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 521afc3f97..1ec092d8b5 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -19,6 +19,7 @@
#define COMMANDS_H_
#include <inttypes.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <shared_mutex>
@@ -35,8 +36,26 @@
namespace android {
namespace installd {
+using IFsveritySetupAuthToken = android::os::IInstalld::IFsveritySetupAuthToken;
+
class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld {
public:
+ class FsveritySetupAuthToken : public os::IInstalld::BnFsveritySetupAuthToken {
+ public:
+ FsveritySetupAuthToken() : mStatFromAuthFd() {}
+
+ binder::Status authenticate(const android::os::ParcelFileDescriptor& authFd, int32_t appUid,
+ int32_t userId);
+ bool isSameStat(const struct stat& st) const;
+
+ private:
+ // Not copyable or movable
+ FsveritySetupAuthToken(const FsveritySetupAuthToken&) = delete;
+ FsveritySetupAuthToken& operator=(const FsveritySetupAuthToken&) = delete;
+
+ struct stat mStatFromAuthFd;
+ };
+
static status_t start();
static char const* getServiceName() { return "installd"; }
virtual status_t dump(int fd, const Vector<String16> &args) override;
@@ -49,7 +68,8 @@ public:
binder::Status createAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags,
int32_t appId, int32_t previousAppId, const std::string& seInfo,
- int32_t targetSdkVersion, int64_t* _aidl_return);
+ int32_t targetSdkVersion, int64_t* ceDataInode,
+ int64_t* deDataInode);
binder::Status createAppData(
const android::os::CreateAppDataArgs& args,
@@ -192,6 +212,13 @@ public:
const std::optional<std::string>& outputPath,
int32_t* _aidl_return);
+ binder::Status createFsveritySetupAuthToken(const android::os::ParcelFileDescriptor& authFd,
+ int32_t appUid, int32_t userId,
+ android::sp<IFsveritySetupAuthToken>* _aidl_return);
+ binder::Status enableFsverity(const android::sp<IFsveritySetupAuthToken>& authToken,
+ const std::string& filePath, const std::string& packageName,
+ int32_t* _aidl_return);
+
private:
std::recursive_mutex mLock;
std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock;
@@ -212,7 +239,7 @@ private:
const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, int32_t previousAppId,
const std::string& seInfo, int32_t targetSdkVersion,
- int64_t* _aidl_return);
+ int64_t* ceDataInode, int64_t* deDataInode);
binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId,
int32_t flags, int32_t appId, const std::string& seInfo);
diff --git a/cmds/installd/binder/android/os/CreateAppDataResult.aidl b/cmds/installd/binder/android/os/CreateAppDataResult.aidl
index 3b8fa6b9f2..463489e01e 100644
--- a/cmds/installd/binder/android/os/CreateAppDataResult.aidl
+++ b/cmds/installd/binder/android/os/CreateAppDataResult.aidl
@@ -19,6 +19,7 @@ package android.os;
/** {@hide} */
parcelable CreateAppDataResult {
long ceDataInode;
+ long deDataInode;
int exceptionCode;
@utf8InCpp String exceptionMessage;
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 9ad853b1df..8893e38c03 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -134,6 +134,22 @@ interface IInstalld {
int getOdexVisibility(@utf8InCpp String packageName, @utf8InCpp String apkPath,
@utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath);
+ interface IFsveritySetupAuthToken {
+ // Using an interface here is an easy way to create and maintain an IBinder object across
+ // the processes. When installd creates this binder object, it stores the file stat
+ // privately for later authentication, and only returns the reference to the caller process.
+ // Once the binder object has no reference count, it gets destructed automatically
+ // (alternatively, installd can maintain an internal mapping, but it is more error prone
+ // because the app may crash and not finish the fs-verity setup, keeping the memory unused
+ // forever).
+ //
+ // We don't necessarily need a method here, so it's left blank intentionally.
+ }
+ IFsveritySetupAuthToken createFsveritySetupAuthToken(in ParcelFileDescriptor authFd, int appUid,
+ int userId);
+ int enableFsverity(in IFsveritySetupAuthToken authToken, @utf8InCpp String filePath,
+ @utf8InCpp String packageName);
+
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
const int FLAG_STORAGE_EXTERNAL = 0x4;
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5cf402c54c..df02588a22 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -18,6 +18,7 @@
#define DEXOPT_H_
#include "installd_constants.h"
+#include "unique_file.h"
#include <sys/types.h>
@@ -156,6 +157,10 @@ const char* select_execution_binary(
// artifacts.
int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir);
+UniqueFile maybe_open_reference_profile(const std::string& pkgname, const std::string& dex_path,
+ const char* profile_name, bool profile_guided,
+ bool is_public, int uid, bool is_secondary_dex);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 7cabdb09e1..822ab7fbb7 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -14,20 +14,21 @@
** limitations under the License.
*/
-#include <algorithm>
#include <inttypes.h>
-#include <limits>
-#include <random>
-#include <regex>
#include <selinux/android.h>
#include <selinux/avc.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
+#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/stat.h>
-#include <sys/mman.h>
#include <sys/wait.h>
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <random>
+#include <regex>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -47,6 +48,7 @@
#include "otapreopt_parameters.h"
#include "otapreopt_utils.h"
#include "system_properties.h"
+#include "unique_file.h"
#include "utils.h"
#ifndef LOG_TAG
@@ -87,6 +89,9 @@ static_assert(DEXOPT_GENERATE_APP_IMAGE == 1 << 12, "DEXOPT_GENERATE_APP_IMAGE u
static_assert(DEXOPT_MASK == (0x3dfe | DEXOPT_IDLE_BACKGROUND_JOB),
"DEXOPT_MASK unexpected.");
+constexpr const char* kAotCompilerFilters[]{
+ "space-profile", "space", "speed-profile", "speed", "everything-profile", "everything",
+};
template<typename T>
static constexpr bool IsPowerOfTwo(T x) {
@@ -415,6 +420,36 @@ private:
return (strcmp(arg, "!") == 0) ? nullptr : arg;
}
+ bool IsAotCompilation() const {
+ if (std::find(std::begin(kAotCompilerFilters), std::end(kAotCompilerFilters),
+ std::string_view(parameters_.compiler_filter)) ==
+ std::end(kAotCompilerFilters)) {
+ return false;
+ }
+
+ int dexopt_flags = parameters_.dexopt_flags;
+ bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+ bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
+ bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
+
+ if (profile_guided) {
+ UniqueFile reference_profile =
+ maybe_open_reference_profile(parameters_.pkgName, parameters_.apk_path,
+ parameters_.profile_name, profile_guided,
+ is_public, parameters_.uid, is_secondary_dex);
+ // `maybe_open_reference_profile` installs a hook that clears the profile on
+ // destruction. Disable it.
+ reference_profile.DisableCleanup();
+ struct stat sbuf;
+ if (reference_profile.fd() == -1 ||
+ (fstat(reference_profile.fd(), &sbuf) != -1 && sbuf.st_size == 0)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
bool ShouldSkipPreopt() const {
// There's one thing we have to be careful about: we may/will be asked to compile an app
// living in the system image. This may be a valid request - if the app wasn't compiled,
@@ -439,9 +474,12 @@ private:
// (This is ugly as it's the only thing where we need to understand the contents
// of parameters_, but it beats postponing the decision or using the call-
// backs to do weird things.)
+
+ // In addition, no need to preopt for "verify". The existing vdex files in the OTA package
+ // and the /data partition will still be usable after the OTA update is applied.
const char* apk_path = parameters_.apk_path;
CHECK(apk_path != nullptr);
- if (StartsWith(apk_path, android_root_)) {
+ if (StartsWith(apk_path, android_root_) || !IsAotCompilation()) {
const char* last_slash = strrchr(apk_path, '/');
if (last_slash != nullptr) {
std::string path(apk_path, last_slash - apk_path + 1);
@@ -471,13 +509,18 @@ private:
// TODO(calin): embed the profile name in the parameters.
int Dexopt() {
std::string error;
+
+ int dexopt_flags = parameters_.dexopt_flags;
+ // Make sure dex2oat is run with background priority.
+ dexopt_flags |= DEXOPT_BOOTCOMPLETE | DEXOPT_IDLE_BACKGROUND_JOB;
+
int res = dexopt(parameters_.apk_path,
parameters_.uid,
parameters_.pkgName,
parameters_.instruction_set,
parameters_.dexopt_needed,
parameters_.oat_dir,
- parameters_.dexopt_flags,
+ dexopt_flags,
parameters_.compiler_filter,
parameters_.volume_uuid,
parameters_.shared_libraries,
@@ -521,61 +564,6 @@ private:
return Dexopt();
}
- ////////////////////////////////////
- // Helpers, mostly taken from ART //
- ////////////////////////////////////
-
- // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
- static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
- constexpr size_t kPageSize = PAGE_SIZE;
- static_assert(IsPowerOfTwo(kPageSize), "page size must be power of two");
- CHECK_EQ(min_delta % kPageSize, 0u);
- CHECK_EQ(max_delta % kPageSize, 0u);
- CHECK_LT(min_delta, max_delta);
-
- std::default_random_engine generator;
- generator.seed(GetSeed());
- std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
- int32_t r = distribution(generator);
- if (r % 2 == 0) {
- r = RoundUp(r, kPageSize);
- } else {
- r = RoundDown(r, kPageSize);
- }
- CHECK_LE(min_delta, r);
- CHECK_GE(max_delta, r);
- CHECK_EQ(r % kPageSize, 0u);
- return r;
- }
-
- static uint64_t GetSeed() {
-#ifdef __BIONIC__
- // Bionic exposes arc4random, use it.
- uint64_t random_data;
- arc4random_buf(&random_data, sizeof(random_data));
- return random_data;
-#else
-#error "This is only supposed to run with bionic. Otherwise, implement..."
-#endif
- }
-
- void AddCompilerOptionFromSystemProperty(const char* system_property,
- const char* prefix,
- bool runtime,
- std::vector<std::string>& out) const {
- const std::string* value = system_properties_.GetProperty(system_property);
- if (value != nullptr) {
- if (runtime) {
- out.push_back("--runtime-arg");
- }
- if (prefix != nullptr) {
- out.push_back(StringPrintf("%s%s", prefix, value->c_str()));
- } else {
- out.push_back(*value);
- }
- }
- }
-
static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA";
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index c86993cb06..c40caf56d8 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -19,9 +19,12 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#include <unistd.h>
+#include <algorithm>
#include <array>
#include <fstream>
+#include <iostream>
#include <sstream>
#include <android-base/file.h>
@@ -29,6 +32,7 @@
#include <android-base/macros.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <libdm/dm.h>
#include <selinux/android.h>
@@ -37,7 +41,7 @@
#include "otapreopt_utils.h"
#ifndef LOG_TAG
-#define LOG_TAG "otapreopt"
+#define LOG_TAG "otapreopt_chroot"
#endif
using android::base::StringPrintf;
@@ -49,20 +53,22 @@ namespace installd {
// so just try the possibilities one by one.
static constexpr std::array kTryMountFsTypes = {"ext4", "erofs"};
-static void CloseDescriptor(int fd) {
- if (fd >= 0) {
- int result = close(fd);
- UNUSED(result); // Ignore result. Printing to logcat will open a new descriptor
- // that we do *not* want.
- }
-}
-
static void CloseDescriptor(const char* descriptor_string) {
int fd = -1;
std::istringstream stream(descriptor_string);
stream >> fd;
if (!stream.fail()) {
- CloseDescriptor(fd);
+ if (fd >= 0) {
+ if (close(fd) < 0) {
+ PLOG(ERROR) << "Failed to close " << fd;
+ }
+ }
+ }
+}
+
+static void SetCloseOnExec(int fd) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+ PLOG(ERROR) << "Failed to set FD_CLOEXEC on " << fd;
}
}
@@ -129,24 +135,39 @@ static void TryExtraMount(const char* name, const char* slot, const char* target
}
// Entry for otapreopt_chroot. Expected parameters are:
-// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
-// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
-// be passed on to otapreopt in the chroot.
+//
+// [cmd] [status-fd] [target-slot-suffix]
+//
+// The file descriptor denoted by status-fd will be closed. Dexopt commands on
+// the form
+//
+// "dexopt" [dexopt-params]
+//
+// are then read from stdin until EOF and passed on to /system/bin/otapreopt one
+// by one. After each call a line with the current command count is written to
+// stdout and flushed.
static int otapreopt_chroot(const int argc, char **arg) {
// Validate arguments
- // We need the command, status channel and target slot, at a minimum.
- if(argc < 3) {
- PLOG(ERROR) << "Not enough arguments.";
+ if (argc == 2 && std::string_view(arg[1]) == "--version") {
+ // Accept a single --version flag, to allow the script to tell this binary
+ // from the earlier one.
+ std::cout << "2" << std::endl;
+ return 0;
+ }
+ if (argc != 3) {
+ LOG(ERROR) << "Wrong number of arguments: " << argc;
exit(208);
}
- // Close all file descriptors. They are coming from the caller, we do not want to pass them
- // on across our fork/exec into a different domain.
- // 1) Default descriptors.
- CloseDescriptor(STDIN_FILENO);
- CloseDescriptor(STDOUT_FILENO);
- CloseDescriptor(STDERR_FILENO);
- // 2) The status channel.
- CloseDescriptor(arg[1]);
+ const char* status_fd = arg[1];
+ const char* slot_suffix = arg[2];
+
+ // Set O_CLOEXEC on standard fds. They are coming from the caller, we do not
+ // want to pass them on across our fork/exec into a different domain.
+ SetCloseOnExec(STDIN_FILENO);
+ SetCloseOnExec(STDOUT_FILENO);
+ SetCloseOnExec(STDERR_FILENO);
+ // Close the status channel.
+ CloseDescriptor(status_fd);
// We need to run the otapreopt tool from the postinstall partition. As such, set up a
// mount namespace and change root.
@@ -185,20 +206,20 @@ static int otapreopt_chroot(const int argc, char **arg) {
// 2) We're in a mount namespace here, so when we die, this will be cleaned up.
// 3) Ignore errors. Printing anything at this stage will open a file descriptor
// for logging.
- if (!ValidateTargetSlotSuffix(arg[2])) {
- LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
+ if (!ValidateTargetSlotSuffix(slot_suffix)) {
+ LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
exit(207);
}
- TryExtraMount("vendor", arg[2], "/postinstall/vendor");
+ TryExtraMount("vendor", slot_suffix, "/postinstall/vendor");
// Try to mount the product partition. update_engine doesn't do this for us, but we
// want it for product APKs. Same notes as vendor above.
- TryExtraMount("product", arg[2], "/postinstall/product");
+ TryExtraMount("product", slot_suffix, "/postinstall/product");
// Try to mount the system_ext partition. update_engine doesn't do this for
// us, but we want it for system_ext APKs. Same notes as vendor and product
// above.
- TryExtraMount("system_ext", arg[2], "/postinstall/system_ext");
+ TryExtraMount("system_ext", slot_suffix, "/postinstall/system_ext");
constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig";
// Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot
@@ -329,30 +350,37 @@ static int otapreopt_chroot(const int argc, char **arg) {
exit(218);
}
- // Now go on and run otapreopt.
+ // Now go on and read dexopt lines from stdin and pass them on to otapreopt.
- // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc
- // Outgoing: cmd + target-slot + cmd... | Outgoing | = argc - 1
- std::vector<std::string> cmd;
- cmd.reserve(argc);
- cmd.push_back("/system/bin/otapreopt");
+ int count = 1;
+ for (std::array<char, 1000> linebuf;
+ std::cin.clear(), std::cin.getline(&linebuf[0], linebuf.size()); ++count) {
+ // Subtract one from gcount() since getline() counts the newline.
+ std::string line(&linebuf[0], std::cin.gcount() - 1);
- // The first parameter is the status file descriptor, skip.
- for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
- cmd.push_back(arg[i]);
- }
+ if (std::cin.fail()) {
+ LOG(ERROR) << "Command exceeds max length " << linebuf.size() << " - skipped: " << line;
+ continue;
+ }
- // Fork and execute otapreopt in its own process.
- std::string error_msg;
- bool exec_result = Exec(cmd, &error_msg);
- if (!exec_result) {
- LOG(ERROR) << "Running otapreopt failed: " << error_msg;
- }
+ std::vector<std::string> tokenized_line = android::base::Tokenize(line, " ");
+ std::vector<std::string> cmd{"/system/bin/otapreopt", slot_suffix};
+ std::move(tokenized_line.begin(), tokenized_line.end(), std::back_inserter(cmd));
- if (!exec_result) {
- exit(213);
+ LOG(INFO) << "Command " << count << ": " << android::base::Join(cmd, " ");
+
+ // Fork and execute otapreopt in its own process.
+ std::string error_msg;
+ bool exec_result = Exec(cmd, &error_msg);
+ if (!exec_result) {
+ LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+ }
+
+ // Print the count to stdout and flush to indicate progress.
+ std::cout << count << std::endl;
}
+ LOG(INFO) << "No more dexopt commands";
return 0;
}
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index db5c34edc2..28bd7932a2 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -16,7 +16,9 @@
# limitations under the License.
#
-# This script will run as a postinstall step to drive otapreopt.
+# This script runs as a postinstall step to drive otapreopt. It comes with the
+# OTA package, but runs /system/bin/otapreopt_chroot in the (old) active system
+# image. See system/extras/postinst/postinst.sh for some docs.
TARGET_SLOT="$1"
STATUS_FD="$2"
@@ -31,12 +33,11 @@ BOOT_PROPERTY_NAME="dev.bootcomplete"
BOOT_COMPLETE=$(getprop $BOOT_PROPERTY_NAME)
if [ "$BOOT_COMPLETE" != "1" ] ; then
- echo "Error: boot-complete not detected."
+ echo "$0: Error: boot-complete not detected."
# We must return 0 to not block sideload.
exit 0
fi
-
# Compute target slot suffix.
# TODO: Once bootctl is not restricted, we should query from there. Or get this from
# update_engine as a parameter.
@@ -45,45 +46,63 @@ if [ "$TARGET_SLOT" = "0" ] ; then
elif [ "$TARGET_SLOT" = "1" ] ; then
TARGET_SLOT_SUFFIX="_b"
else
- echo "Unknown target slot $TARGET_SLOT"
+ echo "$0: Unknown target slot $TARGET_SLOT"
exit 1
fi
+if [ "$(/system/bin/otapreopt_chroot --version)" != 2 ]; then
+ # We require an updated chroot wrapper that reads dexopt commands from stdin.
+ # Even if we kept compat with the old binary, the OTA preopt wouldn't work due
+ # to missing sepolicy rules, so there's no use spending time trying to dexopt
+ # (b/291974157).
+ echo "$0: Current system image is too old to work with OTA preopt - skipping."
+ exit 0
+fi
PREPARE=$(cmd otadexopt prepare)
# Note: Ignore preparation failures. Step and done will fail and exit this.
# This is necessary to support suspends - the OTA service will keep
# the state around for us.
-PROGRESS=$(cmd otadexopt progress)
-print -u${STATUS_FD} "global_progress $PROGRESS"
-
-i=0
-while ((i<MAXIMUM_PACKAGES)) ; do
+# Create an array with all dexopt commands in advance, to know how many there are.
+otadexopt_cmds=()
+while (( ${#otadexopt_cmds[@]} < MAXIMUM_PACKAGES )) ; do
DONE=$(cmd otadexopt done)
if [ "$DONE" = "OTA complete." ] ; then
break
fi
+ otadexopt_cmds+=("$(cmd otadexopt next)")
+done
- DEXOPT_PARAMS=$(cmd otadexopt next)
+DONE=$(cmd otadexopt done)
+cmd otadexopt cleanup
- /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX $DEXOPT_PARAMS >&- 2>&-
+echo "$0: Using streaming otapreopt_chroot on ${#otadexopt_cmds[@]} packages"
- PROGRESS=$(cmd otadexopt progress)
- print -u${STATUS_FD} "global_progress $PROGRESS"
+function print_otadexopt_cmds {
+ for cmd in "${otadexopt_cmds[@]}" ; do
+ print "$cmd"
+ done
+}
- sleep 1
- i=$((i+1))
-done
+function report_progress {
+ while read count ; do
+ # mksh can't do floating point arithmetic, so emulate a fixed point calculation.
+ (( permilles = 1000 * count / ${#otadexopt_cmds[@]} ))
+ printf 'global_progress %d.%03d\n' $((permilles / 1000)) $((permilles % 1000)) >&${STATUS_FD}
+ done
+}
+
+print_otadexopt_cmds | \
+ /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX | \
+ report_progress
-DONE=$(cmd otadexopt done)
if [ "$DONE" = "OTA incomplete." ] ; then
- echo "Incomplete."
+ echo "$0: Incomplete."
else
- echo "Complete or error."
+ echo "$0: Complete or error."
fi
print -u${STATUS_FD} "global_progress 1.0"
-cmd otadexopt cleanup
exit 0
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index 4221a3a593..7648265f0f 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -208,36 +208,13 @@ void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex,
}
// Compute compiler filter.
- {
- std::string dex2oat_compiler_filter_arg;
- {
- // If we are booting without the real /data, don't spend time compiling.
- std::string vold_decrypt = GetProperty("vold.decrypt", "");
- bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
- vold_decrypt == "1";
-
- bool have_dex2oat_relocation_skip_flag = false;
- if (skip_compilation) {
- dex2oat_compiler_filter_arg = "--compiler-filter=extract";
- have_dex2oat_relocation_skip_flag = true;
- } else if (compiler_filter != nullptr) {
- dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s",
- compiler_filter);
- }
- if (have_dex2oat_relocation_skip_flag) {
- AddRuntimeArg("-Xnorelocate");
- }
- }
-
- if (dex2oat_compiler_filter_arg.empty()) {
- dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
- "--compiler-filter=%s");
- }
- AddArg(dex2oat_compiler_filter_arg);
-
- if (compilation_reason != nullptr) {
- AddArg(std::string("--compilation-reason=") + compilation_reason);
- }
+ if (compiler_filter != nullptr) {
+ AddArg(StringPrintf("--compiler-filter=%s", compiler_filter));
+ } else {
+ AddArg(MapPropertyToArg("dalvik.vm.dex2oat-filter", "--compiler-filter=%s"));
+ }
+ if (compilation_reason != nullptr) {
+ AddArg(std::string("--compilation-reason=") + compilation_reason);
}
AddArg(MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp
index 304ba7b04f..56f84a5e12 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -441,24 +441,6 @@ TEST_F(RunDex2OatTest, Runtime) {
VerifyExpectedFlags();
}
-TEST_F(RunDex2OatTest, SkipRelocationInMinFramework) {
- setSystemProperty("vold.decrypt", "trigger_restart_min_framework");
- CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
-
- SetExpectedFlagUsed("--compiler-filter", "=extract");
- SetExpectedFlagUsed("-Xnorelocate", "");
- VerifyExpectedFlags();
-}
-
-TEST_F(RunDex2OatTest, SkipRelocationIfDecryptedWithFullDiskEncryption) {
- setSystemProperty("vold.decrypt", "1");
- CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
-
- SetExpectedFlagUsed("--compiler-filter", "=extract");
- SetExpectedFlagUsed("-Xnorelocate", "");
- VerifyExpectedFlags();
-}
-
TEST_F(RunDex2OatTest, DalvikVmDex2oatFilter) {
setSystemProperty("dalvik.vm.dex2oat-filter", "speed");
auto args = RunDex2OatArgs::MakeDefaultTestArgs();
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index c4071c6020..ee91d80a3b 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -197,6 +197,7 @@ protected:
std::string app_oat_dir_;
int64_t ce_data_inode_;
+ int64_t de_data_inode_;
std::string secondary_dex_ce_;
std::string secondary_dex_ce_link_;
@@ -261,16 +262,10 @@ protected:
}
// Create the app user data.
- binder::Status status = service_->createAppData(
- volume_uuid_,
- package_name_,
- kTestUserId,
- kAppDataFlags,
- kTestAppUid,
- 0 /* previousAppId */,
- se_info_,
- kOSdkVersion,
- &ce_data_inode_);
+ binder::Status status =
+ service_->createAppData(volume_uuid_, package_name_, kTestUserId, kAppDataFlags,
+ kTestAppUid, 0 /* previousAppId */, se_info_, kOSdkVersion,
+ &ce_data_inode_, &de_data_inode_);
if (!status.isOk()) {
return ::testing::AssertionFailure() << "Could not create app data: "
<< status.toString8().c_str();
@@ -1350,16 +1345,10 @@ TEST_F(ProfileTest, ProfileDirOkAfterFixup) {
ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
// Run createAppData again which will offer to fix-up the profile directories.
- ASSERT_BINDER_SUCCESS(service_->createAppData(
- volume_uuid_,
- package_name_,
- kTestUserId,
- kAppDataFlags,
- kTestAppUid,
- 0 /* previousAppId */,
- se_info_,
- kOSdkVersion,
- &ce_data_inode_));
+ ASSERT_BINDER_SUCCESS(service_->createAppData(volume_uuid_, package_name_, kTestUserId,
+ kAppDataFlags, kTestAppUid, 0 /* previousAppId */,
+ se_info_, kOSdkVersion, &ce_data_inode_,
+ &de_data_inode_));
// Check the file access.
CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
@@ -1492,18 +1481,13 @@ class BootProfileTest : public ProfileTest {
void createAppProfilesForBootMerge(size_t number_of_profiles) {
for (size_t i = 0; i < number_of_profiles; i++) {
int64_t ce_data_inode;
+ int64_t de_data_inode;
std::string package_name = "dummy_test_pkg" + std::to_string(i);
LOG(INFO) << package_name;
- ASSERT_BINDER_SUCCESS(service_->createAppData(
- volume_uuid_,
- package_name,
- kTestUserId,
- kAppDataFlags,
- kTestAppUid,
- 0 /* previousAppId */,
- se_info_,
- kOSdkVersion,
- &ce_data_inode));
+ ASSERT_BINDER_SUCCESS(
+ service_->createAppData(volume_uuid_, package_name, kTestUserId, kAppDataFlags,
+ kTestAppUid, 0 /* previousAppId */, se_info_,
+ kOSdkVersion, &ce_data_inode, &de_data_inode));
extra_apps_.push_back(package_name);
extra_ce_data_inodes_.push_back(ce_data_inode);
std::string profile = create_current_profile_path(
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 858a92cc65..4bc92afa18 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -42,9 +42,12 @@
#include "binder_test_utils.h"
#include "dexopt.h"
#include "globals.h"
+#include "unique_file.h"
#include "utils.h"
using android::base::StringPrintf;
+using android::base::unique_fd;
+using android::os::ParcelFileDescriptor;
using std::filesystem::is_empty;
namespace android {
@@ -136,6 +139,16 @@ static int create(const std::string& path, uid_t owner, gid_t group, mode_t mode
return fd;
}
+static void create_with_content(const std::string& path, uid_t owner, gid_t group, mode_t mode,
+ const std::string& content) {
+ int fd = ::open(path.c_str(), O_RDWR | O_CREAT, mode);
+ EXPECT_NE(fd, -1);
+ EXPECT_TRUE(android::base::WriteStringToFd(content, fd));
+ EXPECT_EQ(::fchown(fd, owner, group), 0);
+ EXPECT_EQ(::fchmod(fd, mode), 0);
+ close(fd);
+}
+
static void touch(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
EXPECT_EQ(::close(create(path.c_str(), owner, group, mode)), 0);
}
@@ -527,6 +540,94 @@ TEST_F(ServiceTest, GetAppSizeWrongSizes) {
externalStorageAppId, ceDataInodes, codePaths,
&externalStorageSize));
}
+
+class FsverityTest : public ServiceTest {
+protected:
+ binder::Status createFsveritySetupAuthToken(const std::string& path, int open_mode,
+ sp<IFsveritySetupAuthToken>* _aidl_return) {
+ unique_fd ufd(open(path.c_str(), open_mode));
+ EXPECT_GE(ufd.get(), 0) << "open failed: " << strerror(errno);
+ ParcelFileDescriptor rfd(std::move(ufd));
+ return service->createFsveritySetupAuthToken(std::move(rfd), kTestAppId, kTestUserId,
+ _aidl_return);
+ }
+};
+
+TEST_F(FsverityTest, enableFsverity) {
+ const std::string path = kTestPath + "/foo";
+ create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
+ UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
+
+ // Expect to fs-verity setup to succeed
+ sp<IFsveritySetupAuthToken> authToken;
+ binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(authToken != nullptr);
+
+ // Verity auth token works to enable fs-verity
+ int32_t errno_local;
+ status = service->enableFsverity(authToken, path, "fake.package.name", &errno_local);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(errno_local, 0);
+}
+
+TEST_F(FsverityTest, enableFsverity_nullAuthToken) {
+ const std::string path = kTestPath + "/foo";
+ create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
+ UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
+
+ // Verity null auth token fails
+ sp<IFsveritySetupAuthToken> authToken;
+ int32_t errno_local;
+ binder::Status status =
+ service->enableFsverity(authToken, path, "fake.package.name", &errno_local);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(FsverityTest, enableFsverity_differentFile) {
+ const std::string path = kTestPath + "/foo";
+ create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
+ UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
+
+ // Expect to fs-verity setup to succeed
+ sp<IFsveritySetupAuthToken> authToken;
+ binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(authToken != nullptr);
+
+ // Verity auth token does not work for a different file
+ const std::string anotherPath = kTestPath + "/bar";
+ ASSERT_TRUE(android::base::WriteStringToFile("content", anotherPath));
+ UniqueFile raii2(/*fd=*/-1, anotherPath, [](const std::string& path) { unlink(path.c_str()); });
+ int32_t errno_local;
+ status = service->enableFsverity(authToken, anotherPath, "fake.package.name", &errno_local);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_NE(errno_local, 0);
+}
+
+TEST_F(FsverityTest, createFsveritySetupAuthToken_ReadonlyFdDoesNotAuthenticate) {
+ const std::string path = kTestPath + "/foo";
+ create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content");
+ UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
+
+ // Expect the fs-verity setup to fail
+ sp<IFsveritySetupAuthToken> authToken;
+ binder::Status status = createFsveritySetupAuthToken(path, O_RDONLY, &authToken);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(FsverityTest, createFsveritySetupAuthToken_UnownedFile) {
+ const std::string path = kTestPath + "/foo";
+ // Simulate world-writable file owned by another app
+ create_with_content(path, kTestAppUid + 1, kTestAppUid + 1, 0666, "content");
+ UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); });
+
+ // Expect the fs-verity setup to fail
+ sp<IFsveritySetupAuthToken> authToken;
+ binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken);
+ EXPECT_FALSE(status.isOk());
+}
+
static bool mkdirs(const std::string& path, mode_t mode) {
struct stat sb;
if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index ecea1d2b1c..c43fdbd547 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -18,6 +18,7 @@
#ifndef UTILS_H_
#define UTILS_H_
+#include <functional>
#include <string>
#include <vector>
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index fb69513d24..d73a30bf9b 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -93,22 +93,9 @@ cc_fuzz {
libfuzzer_options: [
"max_len=50000",
],
- },
-}
-
-// Adding this new fuzzer to test the corpus generated by record_binder
-cc_fuzz {
- name: "servicemanager_test_fuzzer",
- defaults: [
- "servicemanager_defaults",
- "service_fuzzer_defaults",
- ],
- host_supported: true,
- srcs: ["fuzzers/ServiceManagerTestFuzzer.cpp"],
- fuzz_config: {
- libfuzzer_options: [
- "max_len=50000",
+ cc: [
+ "smoreland@google.com",
+ "waghpawan@google.com",
],
},
- corpus: ["fuzzers/servicemamanager_fuzzer_corpus/*"],
}
diff --git a/cmds/servicemanager/OWNERS b/cmds/servicemanager/OWNERS
new file mode 100644
index 0000000000..7f5a8115d1
--- /dev/null
+++ b/cmds/servicemanager/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 32456
+
+smoreland@google.com
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index cae9684cc4..facb8b133b 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
@@ -112,10 +113,26 @@ static bool isVintfDeclared(const std::string& name) {
});
if (!found) {
+ std::set<std::string> instances;
+ forEachManifest([&](const ManifestWithDescription& mwd) {
+ std::set<std::string> res = mwd.manifest->getAidlInstances(aname.package, aname.iface);
+ instances.insert(res.begin(), res.end());
+ return true;
+ });
+
+ std::string available;
+ if (instances.empty()) {
+ available = "No alternative instances declared in VINTF";
+ } else {
+ // for logging only. We can't return this information to the client
+ // because they may not have permissions to find or list those
+ // instances
+ available = "VINTF declared instances: " + base::Join(instances, ", ");
+ }
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- ALOGI("Could not find %s.%s/%s in the VINTF manifest.", aname.package.c_str(),
- aname.iface.c_str(), aname.instance.c_str());
+ ALOGI("Could not find %s.%s/%s in the VINTF manifest. %s.", aname.package.c_str(),
+ aname.iface.c_str(), aname.instance.c_str(), available.c_str());
}
return found;
diff --git a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp b/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp
deleted file mode 100644
index e19b6eb279..0000000000
--- a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fuzzbinder/libbinder_driver.h>
-#include <utils/StrongPointer.h>
-
-#include "Access.h"
-#include "ServiceManager.h"
-
-using ::android::Access;
-using ::android::Parcel;
-using ::android::ServiceManager;
-using ::android::sp;
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider provider(data, size);
- auto accessPtr = std::make_unique<Access>();
- auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr));
-
- // Reserved bytes
- provider.ConsumeBytes<uint8_t>(8);
- uint32_t code = provider.ConsumeIntegral<uint32_t>();
- uint32_t flag = provider.ConsumeIntegral<uint32_t>();
- std::vector<uint8_t> parcelData = provider.ConsumeRemainingBytes<uint8_t>();
-
- Parcel inputParcel;
- inputParcel.setData(parcelData.data(), parcelData.size());
-
- Parcel reply;
- serviceManager->transact(code, inputParcel, &reply, flag);
-
- serviceManager->clear();
-
- return 0;
-}
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10
deleted file mode 100644
index 07319f864e..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12
deleted file mode 100644
index 07319f864e..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14
deleted file mode 100644
index 07319f864e..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16
deleted file mode 100644
index 07319f864e..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18
deleted file mode 100644
index 88ad474f09..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19
deleted file mode 100644
index fae15a2fea..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2
deleted file mode 100644
index e69ab49d5d..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21
deleted file mode 100644
index 88ad474f09..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22
deleted file mode 100644
index fae15a2fea..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24
deleted file mode 100644
index 88ad474f09..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25
deleted file mode 100644
index fae15a2fea..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27
deleted file mode 100644
index 88ad474f09..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28
deleted file mode 100644
index fae15a2fea..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30
deleted file mode 100644
index 88ad474f09..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31
deleted file mode 100644
index fae15a2fea..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33
deleted file mode 100644
index 88ad474f09..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34
deleted file mode 100644
index fae15a2fea..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36
deleted file mode 100644
index 88ad474f09..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37
deleted file mode 100644
index fae15a2fea..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39
deleted file mode 100644
index b326907a58..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4
deleted file mode 100644
index 05b27bf413..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41
deleted file mode 100644
index b326907a58..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42
deleted file mode 100644
index cdaa1f01b1..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43
deleted file mode 100644
index ff0941b7a6..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44
deleted file mode 100644
index cdaa1f01b1..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46
deleted file mode 100644
index 7e5f948682..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6
deleted file mode 100644
index 07319f864e..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8
deleted file mode 100644
index 07319f864e..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9
deleted file mode 100644
index 39e5104927..0000000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 86a45e61ea..ae56cb0ed3 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -125,6 +125,8 @@ int main(int argc, char** argv) {
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+
sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
LOG(ERROR) << "Could not self register servicemanager";
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index a737bd3fb7..ca2cc2ac8c 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -77,6 +77,12 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "android.hardware.context_hub.prebuilt.xml",
+ src: "android.hardware.context_hub.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.ethernet.prebuilt.xml",
src: "android.hardware.ethernet.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -101,6 +107,18 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "android.hardware.nfc.prebuilt.xml",
+ src: "android.hardware.nfc.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.nfc.hce.prebuilt.xml",
+ src: "android.hardware.nfc.hce.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.reboot_escrow.prebuilt.xml",
src: "android.hardware.reboot_escrow.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -173,6 +191,12 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "android.hardware.thread_network.prebuilt.xml",
+ src: "android.hardware.thread_network.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.usb.accessory.prebuilt.xml",
src: "android.hardware.usb.accessory.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.thread_network.xml b/data/etc/android.hardware.thread_network.xml
new file mode 100644
index 0000000000..b116ed6bf8
--- /dev/null
+++ b/data/etc/android.hardware.thread_network.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Adds the feature indicating support for the Thread networking protocol -->
+<permissions>
+ <feature name="android.hardware.thread_network" />
+</permissions>
diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h
index ce30b417e0..165a868d57 100644
--- a/headers/media_plugin/media/openmax/OMX_AsString.h
+++ b/headers/media_plugin/media/openmax/OMX_AsString.h
@@ -561,6 +561,7 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") {
case OMX_IndexConfigPriority: return "ConfigPriority";
case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate";
case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits";
+ case OMX_IndexParamConsumerUsageBits64: return "ParamConsumerUsageBits64";
case OMX_IndexConfigLatency: return "ConfigLatency";
default: return asString((OMX_INDEXTYPE)i, def);
}
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 0af40dd28e..5ddd719ba1 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -105,6 +105,7 @@ typedef enum OMX_INDEXEXTTYPE {
OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */
OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */
OMX_IndexConfigAndroidTunnelPeekLegacyMode, /**< reference: OMX_CONFIG_BOOLEANTYPE */
+ OMX_IndexParamConsumerUsageBits64, /**< reference: OMX_PARAM_U64TYPE */
OMX_IndexExtOtherEndUnused,
/* Time configurations */
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 35f87f96ae..87a14c021d 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -196,7 +196,7 @@ enum AndroidBitmapCompressFormat {
*
* @param userContext Pointer to user-defined data passed to
* {@link AndroidBitmap_compress}.
- * @param data Compressed data of |size| bytes to write.
+ * @param data Compressed data of `size` bytes to write.
* @param size Length in bytes of data to write.
* @return Whether the operation succeeded.
*/
@@ -205,7 +205,7 @@ typedef bool (*AndroidBitmap_CompressWriteFunc)(void* userContext,
size_t size) __INTRODUCED_IN(30);
/**
- * Compress |pixels| as described by |info|.
+ * Compress `pixels` as described by `info`.
*
* Available since API level 30.
*
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index e0a8045d41..645fa8a5e7 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -53,7 +53,7 @@ extern "C" {
/**
* Create a shared memory region.
*
- * Create shared memory region and returns an file descriptor. The resulting file descriptor can be
+ * Create shared memory region and returns a file descriptor. The resulting file descriptor can be
* mmap'ed to process memory space with PROT_READ | PROT_WRITE | PROT_EXEC. Access to shared memory
* region can be restricted with {@link ASharedMemory_setProt}.
*
@@ -65,7 +65,7 @@ extern "C" {
* cmsg(3) man pages for more information.
*
* If you intend to share this file descriptor with a child process after
- * calling exec(3), note that you will need to use fcntl(2) with FD_SETFD
+ * calling exec(3), note that you will need to use fcntl(2) with F_SETFD
* to clear the FD_CLOEXEC flag for this to work on all versions of Android.
*
* Available since API level 26.
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 32580badc0..1f477f8233 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -188,13 +188,13 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
* Note that this only attempts to track the headroom of slow-moving sensors, such as
* the skin temperature sensor. This means that there is no benefit to calling this function
* more frequently than about once per second, and attempted to call significantly
- * more frequently may result in the function returning {@code NaN}.
+ * more frequently may result in the function returning `NaN`.
*
* In addition, in order to be able to provide an accurate forecast, the system does
* not attempt to forecast until it has multiple temperature samples from which to
* extrapolate. This should only take a few seconds from the time of the first call,
* but during this time, no forecasting will occur, and the current headroom will be
- * returned regardless of the value of {@code forecastSeconds}.
+ * returned regardless of the value of `forecastSeconds`.
*
* The value returned is a non-negative float that represents how much of the thermal envelope
* is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is
diff --git a/include/ftl/OWNERS b/include/ftl/OWNERS
new file mode 100644
index 0000000000..3f6129226a
--- /dev/null
+++ b/include/ftl/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/native:/services/surfaceflinger/OWNERS \ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index deff76b3a5..f634c1dcde 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -190,6 +190,9 @@ cc_defaults {
"-performance-move-const-arg", // b/273486801
"portability*",
],
+ lto: {
+ thin: true,
+ },
}
cc_library_headers {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 8d9955dd6b..589df9aceb 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -261,7 +261,7 @@ std::optional<int32_t> BpBinder::getDebugBinderHandle() const {
bool BpBinder::isDescriptorCached() const {
Mutex::Autolock _l(mLock);
- return mDescriptorCache.string() != kDescriptorUninit.string();
+ return mDescriptorCache.c_str() != kDescriptorUninit.c_str();
}
const String16& BpBinder::getInterfaceDescriptor() const
@@ -279,7 +279,7 @@ const String16& BpBinder::getInterfaceDescriptor() const
Mutex::Autolock _l(mLock);
// mDescriptorCache could have been assigned while the lock was
// released.
- if (mDescriptorCache.string() == kDescriptorUninit.string()) mDescriptorCache = res;
+ if (mDescriptorCache.c_str() == kDescriptorUninit.c_str()) mDescriptorCache = res;
}
}
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 08169f5538..5ec4e8b25a 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -52,8 +52,8 @@ public:
}
} else {
// An exception was thrown back; fall through to return failure
- ALOGD("openContentUri(%s) caught exception %d\n",
- String8(stringUri).string(), exceptionCode);
+ ALOGD("openContentUri(%s) caught exception %d\n", String8(stringUri).c_str(),
+ exceptionCode);
}
}
return fd;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 2408307459..6034f2b4ca 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -216,8 +216,8 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP
if (res) {
if (startTime != 0) {
ALOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
- (int)((uptimeMillis()-startTime)/1000),
- String8(permission).string(), uid, pid);
+ (int)((uptimeMillis() - startTime) / 1000), String8(permission).c_str(),
+ uid, pid);
}
return res;
}
@@ -225,7 +225,7 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP
// Is this a permission failure, or did the controller go away?
if (IInterface::asBinder(pc)->isBinderAlive()) {
if (logPermissionFailure) {
- ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(),
+ ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).c_str(),
uid, pid);
}
return false;
@@ -246,7 +246,7 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP
if (startTime == 0) {
startTime = uptimeMillis();
ALOGI("Waiting to check permission %s from uid=%d pid=%d",
- String8(permission).string(), uid, pid);
+ String8(permission).c_str(), uid, pid);
}
sleep(1);
} else {
@@ -295,7 +295,7 @@ sp<IBinder> ServiceManagerShim::getService(const String16& name) const
// retry interval in millisecond; note that vendor services stay at 100ms
const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100;
- ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+ ALOGI("Waiting for service '%s' on '%s'...", String8(name).c_str(),
ProcessState::self()->getDriverName().c_str());
int n = 0;
@@ -306,12 +306,12 @@ sp<IBinder> ServiceManagerShim::getService(const String16& name) const
sp<IBinder> svc = checkService(name);
if (svc != nullptr) {
ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms",
- String8(name).string(), ProcessState::self()->getDriverName().c_str(),
+ String8(name).c_str(), ProcessState::self()->getDriverName().c_str(),
uptimeMillis() - startTime);
return svc;
}
}
- ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
+ ALOGW("Service %s didn't start. Returning NULL", String8(name).c_str());
return nullptr;
}
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 03553f36e9..5b1cb7ea56 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -428,7 +428,7 @@ void SimpleBestFitAllocator::dump_l(const char* what) const
{
String8 result;
dump_l(result, what);
- ALOGD("%s", result.string());
+ ALOGD("%s", result.c_str());
}
void SimpleBestFitAllocator::dump(String8& result,
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 9b685f9145..5b34efc257 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -854,7 +854,7 @@ constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
{
- return writeInterfaceToken(interface.string(), interface.size());
+ return writeInterfaceToken(interface.c_str(), interface.size());
}
status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
@@ -918,7 +918,7 @@ bool Parcel::checkInterface(IBinder* binder) const
bool Parcel::enforceInterface(const String16& interface,
IPCThreadState* threadState) const
{
- return enforceInterface(interface.string(), interface.size(), threadState);
+ return enforceInterface(interface.c_str(), interface.size(), threadState);
}
bool Parcel::enforceInterface(const char16_t* interface,
@@ -977,8 +977,8 @@ bool Parcel::enforceInterface(const char16_t* interface,
return true;
} else {
ALOGW("**** enforceInterface() expected '%s' but read '%s'",
- String8(interface, len).string(),
- String8(parcel_interface, parcel_interface_len).string());
+ String8(interface, len).c_str(),
+ String8(parcel_interface, parcel_interface_len).c_str());
return false;
}
}
@@ -1376,7 +1376,7 @@ status_t Parcel::writeCString(const char* str)
status_t Parcel::writeString8(const String8& str)
{
- return writeString8(str.string(), str.size());
+ return writeString8(str.c_str(), str.size());
}
status_t Parcel::writeString8(const char* str, size_t len)
@@ -1399,7 +1399,7 @@ status_t Parcel::writeString8(const char* str, size_t len)
status_t Parcel::writeString16(const String16& str)
{
- return writeString16(str.string(), str.size());
+ return writeString16(str.c_str(), str.size());
}
status_t Parcel::writeString16(const char16_t* str, size_t len)
diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp
index 670fd55da3..658686d2db 100644
--- a/libs/binder/PermissionCache.cpp
+++ b/libs/binder/PermissionCache.cpp
@@ -101,9 +101,8 @@ bool PermissionCache::checkPermission(
nsecs_t t = -systemTime();
granted = android::checkPermission(permission, pid, uid);
t += systemTime();
- ALOGD("checking %s for uid=%d => %s (%d us)",
- String8(permission).string(), uid,
- granted?"granted":"denied", (int)ns2us(t));
+ ALOGD("checking %s for uid=%d => %s (%d us)", String8(permission).c_str(), uid,
+ granted ? "granted" : "denied", (int)ns2us(t));
pc.cache(permission, uid, granted);
}
return granted;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 02b0447304..8ec4af9945 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -401,9 +401,9 @@ void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
- ALOGV("Spawning new pooled thread, name=%s\n", name.string());
+ ALOGV("Spawning new pooled thread, name=%s\n", name.c_str());
sp<Thread> t = sp<PoolThread>::make(isMain);
- t->run(name.string());
+ t->run(name.c_str());
pthread_mutex_lock(&mThreadCountLock);
mKernelStartedThreads++;
pthread_mutex_unlock(&mThreadCountLock);
@@ -505,7 +505,7 @@ status_t ProcessState::enableOnewaySpamDetection(bool enable) {
}
void ProcessState::giveThreadPoolName() {
- androidSetThreadName( makeBinderThreadName().string() );
+ androidSetThreadName(makeBinderThreadName().c_str());
}
String8 ProcessState::getDriverName() {
diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp
index 44a9e3befa..324670633f 100644
--- a/libs/binder/RecordedTransaction.cpp
+++ b/libs/binder/RecordedTransaction.cpp
@@ -124,7 +124,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails(
static_cast<int32_t>(timestamp.tv_nsec),
0};
- t.mData.mInterfaceName = std::string(String8(interfaceName).string());
+ t.mData.mInterfaceName = std::string(String8(interfaceName).c_str());
if (interfaceName.size() != t.mData.mInterfaceName.size()) {
LOG(ERROR) << "Interface Name is not valid. Contains characters that aren't single byte "
"utf-8.";
diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h
index eb98042c42..50158c3072 100644
--- a/libs/binder/include/binder/TextOutput.h
+++ b/libs/binder/include/binder/TextOutput.h
@@ -147,7 +147,7 @@ inline TextOutput& operator<<(TextOutput& to, const bool &val)
inline TextOutput& operator<<(TextOutput& to, const String16& val)
{
- to << String8(val).string();
+ to << String8(val).c_str();
return to;
}
diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format
index 9a9d936f15..60774143ee 100644
--- a/libs/binder/ndk/.clang-format
+++ b/libs/binder/ndk/.clang-format
@@ -2,9 +2,7 @@ BasedOnStyle: Google
ColumnLimit: 100
IndentWidth: 4
ContinuationIndentWidth: 8
-PointerAlignment: Left
TabWidth: 4
AllowShortFunctionsOnASingleLine: Inline
PointerAlignment: Left
-TabWidth: 4
UseTab: Never
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index d6937c2c52..ed53891e3d 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -115,17 +115,29 @@ class SpAIBinder {
*/
AIBinder** getR() { return &mBinder; }
- bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
- bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
- bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
- bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
- bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
- bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
-
private:
AIBinder* mBinder = nullptr;
};
+#define SP_AIBINDER_COMPARE(_op_) \
+ static inline bool operator _op_(const SpAIBinder& lhs, const SpAIBinder& rhs) { \
+ return lhs.get() _op_ rhs.get(); \
+ } \
+ static inline bool operator _op_(const SpAIBinder& lhs, const AIBinder* rhs) { \
+ return lhs.get() _op_ rhs; \
+ } \
+ static inline bool operator _op_(const AIBinder* lhs, const SpAIBinder& rhs) { \
+ return lhs _op_ rhs.get(); \
+ }
+
+SP_AIBINDER_COMPARE(!=)
+SP_AIBINDER_COMPARE(<)
+SP_AIBINDER_COMPARE(<=)
+SP_AIBINDER_COMPARE(==)
+SP_AIBINDER_COMPARE(>)
+SP_AIBINDER_COMPARE(>=)
+#undef SP_AIBINDER_COMPARE
+
namespace impl {
/**
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 76c7aacb7c..4786c89c89 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -25,6 +25,7 @@
#pragma once
+#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp
index 8ee396e256..8fb755cdac 100644
--- a/libs/binder/ndk/tests/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -80,6 +80,28 @@ cc_test {
require_root: true,
}
+cc_test_host {
+ name: "libbinder_ndk_unit_test_host",
+ defaults: ["test_libbinder_ndk_defaults"],
+ srcs: ["libbinder_ndk_unit_test_host.cpp"],
+ test_suites: [
+ "general-tests",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ static_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libbinder",
+ "libcutils",
+ "libfakeservicemanager",
+ "libgmock",
+ "liblog",
+ "libutils",
+ ],
+}
+
cc_test {
name: "binderVendorDoubleLoadTest",
vendor: true,
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 27ce615565..15708ca738 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -39,7 +39,6 @@
#include <condition_variable>
#include <iostream>
#include <mutex>
-#include <optional>
#include <thread>
#include "android/binder_ibinder.h"
@@ -377,18 +376,24 @@ TEST(NdkBinder, CantHaveTwoLocalBinderClassesWithSameDescriptor) {
}
TEST(NdkBinder, GetTestServiceStressTest) {
- // libbinder has some complicated logic to make sure only one instance of
- // ABpBinder is associated with each binder.
-
constexpr size_t kNumThreads = 10;
constexpr size_t kNumCalls = 1000;
std::vector<std::thread> threads;
+ // this is not a lazy service, but we must make sure that it's started before calling
+ // checkService on it, since the other process serving it might not be started yet.
+ {
+ // getService, not waitForService, to take advantage of timeout
+ auto binder = ndk::SpAIBinder(AServiceManager_getService(IFoo::kSomeInstanceName));
+ ASSERT_NE(nullptr, binder.get());
+ }
+
for (size_t i = 0; i < kNumThreads; i++) {
threads.push_back(std::thread([&]() {
for (size_t j = 0; j < kNumCalls; j++) {
auto binder =
ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName));
+ ASSERT_NE(nullptr, binder.get());
EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}
}));
@@ -427,21 +432,6 @@ TEST(NdkBinder, GetLazyService) {
EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}
-TEST(NdkBinder, IsUpdatable) {
- bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default");
- EXPECT_EQ(isUpdatable, false);
-}
-
-TEST(NdkBinder, GetUpdatableViaApex) {
- std::optional<std::string> updatableViaApex;
- AServiceManager_getUpdatableApexName(
- "android.hardware.light.ILights/default", &updatableViaApex,
- [](const char* apexName, void* context) {
- *static_cast<std::optional<std::string>*>(context) = apexName;
- });
- EXPECT_EQ(updatableViaApex, std::nullopt) << *updatableViaApex;
-}
-
// This is too slow
TEST(NdkBinder, CheckLazyServiceShutDown) {
ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
@@ -755,9 +745,9 @@ TEST(NdkBinder, ConvertToPlatformBinder) {
// local
ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) {
// convert to platform binder
- EXPECT_NE(binder.get(), nullptr);
+ EXPECT_NE(binder, nullptr);
sp<IBinder> platformBinder = AIBinder_toPlatformBinder(binder.get());
- EXPECT_NE(platformBinder.get(), nullptr);
+ EXPECT_NE(platformBinder, nullptr);
auto proxy = interface_cast<IBinderNdkUnitTest>(platformBinder);
EXPECT_NE(proxy, nullptr);
@@ -768,7 +758,7 @@ TEST(NdkBinder, ConvertToPlatformBinder) {
// convert back
ndk::SpAIBinder backBinder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(platformBinder));
- EXPECT_EQ(backBinder.get(), binder.get());
+ EXPECT_EQ(backBinder, binder);
}
}
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test_host.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test_host.cpp
new file mode 100644
index 0000000000..0a3021d0b0
--- /dev/null
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test_host.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+#include <optional>
+
+#include "fakeservicemanager/FakeServiceManager.h"
+
+using android::FakeServiceManager;
+using android::setDefaultServiceManager;
+using android::sp;
+using android::String16;
+using android::String8;
+using testing::_;
+using testing::Eq;
+using testing::Mock;
+using testing::NiceMock;
+using testing::Optional;
+using testing::Return;
+
+struct MockServiceManager : FakeServiceManager {
+ MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
+};
+
+struct AServiceManager : testing::Test {
+ static sp<MockServiceManager> mockSM;
+
+ static void InitMock() {
+ mockSM = new NiceMock<MockServiceManager>;
+ setDefaultServiceManager(mockSM);
+ }
+
+ void TearDown() override { Mock::VerifyAndClear(mockSM.get()); }
+
+ void ExpectUpdatableViaApexReturns(std::optional<String16> apexName) {
+ EXPECT_CALL(*mockSM, updatableViaApex(_)).WillRepeatedly(Return(apexName));
+ }
+};
+
+sp<MockServiceManager> AServiceManager::mockSM;
+
+TEST_F(AServiceManager, isUpdatableViaApex) {
+ auto apexFoo = String16("com.android.hardware.foo");
+ ExpectUpdatableViaApexReturns(apexFoo);
+
+ bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.foo.IFoo/default");
+ EXPECT_EQ(isUpdatable, true);
+}
+
+TEST_F(AServiceManager, isUpdatableViaApex_Not) {
+ ExpectUpdatableViaApexReturns(std::nullopt);
+
+ bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.foo.IFoo/default");
+ EXPECT_EQ(isUpdatable, false);
+}
+
+void getUpdatableApexNameCallback(const char* apexName, void* context) {
+ *(static_cast<std::optional<std::string>*>(context)) = apexName;
+}
+
+TEST_F(AServiceManager, getUpdatableApexName) {
+ auto apexFoo = String16("com.android.hardware.foo");
+ ExpectUpdatableViaApexReturns(apexFoo);
+
+ std::optional<std::string> result;
+ AServiceManager_getUpdatableApexName("android.hardware.foo.IFoo/default", &result,
+ getUpdatableApexNameCallback);
+ EXPECT_THAT(result, Optional(std::string(String8(apexFoo))));
+}
+
+TEST_F(AServiceManager, getUpdatableApexName_Null) {
+ ExpectUpdatableViaApexReturns(std::nullopt);
+
+ std::optional<std::string> result;
+ AServiceManager_getUpdatableApexName("android.hardware.foo.IFoo/default", &result,
+ getUpdatableApexNameCallback);
+ EXPECT_THAT(result, Eq(std::nullopt));
+}
+
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ AServiceManager::InitMock();
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index d36ebac109..57a38dc480 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -11,9 +11,6 @@ rust_library {
name: "libbinder_rs",
crate_name: "binder",
srcs: ["src/lib.rs"],
- shared_libs: [
- "libutils",
- ],
rustlibs: [
"libbinder_ndk_sys",
"libdowncast_rs",
@@ -97,34 +94,12 @@ rust_bindgen {
crate_name: "binder_ndk_bindgen",
wrapper_src: "sys/BinderBindings.hpp",
source_stem: "bindings",
- bindgen_flags: [
+ bindgen_flag_files: [
// Unfortunately the only way to specify the rust_non_exhaustive enum
// style for a type is to make it the default
- "--default-enum-style",
- "rust_non_exhaustive",
// and then specify constified enums for the enums we don't want
// rustified
- "--constified-enum",
- "android::c_interface::consts::.*",
-
- "--allowlist-type",
- "android::c_interface::.*",
- "--allowlist-type",
- "AStatus",
- "--allowlist-type",
- "AIBinder_Class",
- "--allowlist-type",
- "AIBinder",
- "--allowlist-type",
- "AIBinder_Weak",
- "--allowlist-type",
- "AIBinder_DeathRecipient",
- "--allowlist-type",
- "AParcel",
- "--allowlist-type",
- "binder_status_t",
- "--allowlist-function",
- ".*",
+ "libbinder_ndk_bindgen_flags.txt",
],
shared_libs: [
"libbinder_ndk",
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 2d2bf7c582..1dc0b2471d 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -103,7 +103,12 @@ impl BinderAsyncPool for Tokio {
//
// This shouldn't cause issues with blocking the thread as only one task will run in a
// call to `block_on`, so there aren't other tasks to block.
- let result = spawn_me();
+ //
+ // If the `block_in_place` call fails, then you are driving a current-thread runtime on
+ // the binder threadpool. Instead, it is recommended to use `TokioRuntime<Handle>` when
+ // the runtime is a current-thread runtime, as the current-thread runtime can be driven
+ // only by `Runtime::block_on` calls and not by `Handle::block_on`.
+ let result = tokio::task::block_in_place(spawn_me);
Box::pin(after_spawn(result))
} else {
let handle = tokio::task::spawn_blocking(spawn_me);
diff --git a/libs/binder/rust/libbinder_ndk_bindgen_flags.txt b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt
new file mode 100644
index 0000000000..551c59f671
--- /dev/null
+++ b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt
@@ -0,0 +1,11 @@
+--default-enum-style=rust_non_exhaustive
+--constified-enum=android::c_interface::consts::.*
+--allowlist-type=android::c_interface::.*
+--allowlist-type=AStatus
+--allowlist-type=AIBinder_Class
+--allowlist-type=AIBinder
+--allowlist-type=AIBinder_Weak
+--allowlist-type=AIBinder_DeathRecipient
+--allowlist-type=AParcel
+--allowlist-type=binder_status_t
+--allowlist-function=.*
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 81f68f5a29..6fda878d07 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -33,9 +33,9 @@ foreign_type! {
pub struct RpcServerRef;
}
-/// SAFETY - The opaque handle can be cloned freely.
+/// SAFETY: The opaque handle can be cloned freely.
unsafe impl Send for RpcServer {}
-/// SAFETY - The underlying C++ RpcServer class is thread-safe.
+/// SAFETY: The underlying C++ RpcServer class is thread-safe.
unsafe impl Sync for RpcServer {}
impl RpcServer {
@@ -59,7 +59,10 @@ impl RpcServer {
/// Creates a binder RPC server, serving the supplied binder service implementation on the given
/// socket file descriptor. The socket should be bound to an address before calling this
/// function.
- pub fn new_bound_socket(mut service: SpIBinder, socket_fd: OwnedFd) -> Result<RpcServer, Error> {
+ pub fn new_bound_socket(
+ mut service: SpIBinder,
+ socket_fd: OwnedFd,
+ ) -> Result<RpcServer, Error> {
let service = service.as_native_mut();
// SAFETY: Service ownership is transferring to the server and won't be valid afterward.
@@ -67,7 +70,8 @@ impl RpcServer {
// The server takes ownership of the socket FD.
unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
- service, socket_fd.into_raw_fd(),
+ service,
+ socket_fd.into_raw_fd(),
))
}
}
@@ -120,7 +124,9 @@ impl RpcServer {
if ptr.is_null() {
return Err(Error::new(ErrorKind::Other, "Failed to start server"));
}
- Ok(RpcServer::from_ptr(ptr))
+ // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
+ // null.
+ Ok(unsafe { RpcServer::from_ptr(ptr) })
}
}
@@ -130,7 +136,7 @@ impl RpcServerRef {
&self,
modes: &[FileDescriptorTransportMode],
) {
- // SAFETY - Does not keep the pointer after returning does, nor does it
+ // SAFETY: Does not keep the pointer after returning does, nor does it
// read past its boundary. Only passes the 'self' pointer as an opaque handle.
unsafe {
binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
@@ -143,18 +149,21 @@ impl RpcServerRef {
/// Starts a new background thread and calls join(). Returns immediately.
pub fn start(&self) {
+ // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
}
/// Joins the RpcServer thread. The call blocks until the server terminates.
/// This must be called from exactly one thread.
pub fn join(&self) {
+ // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
}
/// Shuts down the running RpcServer. Can be called multiple times and from
/// multiple threads. Called automatically during drop().
pub fn shutdown(&self) -> Result<(), Error> {
+ // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
Ok(())
} else {
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
index 28c5390665..79a951073e 100644
--- a/libs/binder/rust/rpcbinder/src/session.rs
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -36,15 +36,15 @@ foreign_type! {
pub struct RpcSessionRef;
}
-/// SAFETY - The opaque handle can be cloned freely.
+/// SAFETY: The opaque handle can be cloned freely.
unsafe impl Send for RpcSession {}
-/// SAFETY - The underlying C++ RpcSession class is thread-safe.
+/// SAFETY: The underlying C++ RpcSession class is thread-safe.
unsafe impl Sync for RpcSession {}
impl RpcSession {
/// Allocates a new RpcSession object.
pub fn new() -> RpcSession {
- // SAFETY - Takes ownership of the returned handle, which has correct refcount.
+ // SAFETY: Takes ownership of the returned handle, which has correct refcount.
unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
}
}
@@ -58,7 +58,7 @@ impl Default for RpcSession {
impl RpcSessionRef {
/// Sets the file descriptor transport mode for this session.
pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
- // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ // SAFETY: Only passes the 'self' pointer as an opaque handle.
unsafe {
binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
self.as_ptr(),
@@ -69,7 +69,7 @@ impl RpcSessionRef {
/// Sets the maximum number of incoming threads.
pub fn set_max_incoming_threads(&self, threads: usize) {
- // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ // SAFETY: Only passes the 'self' pointer as an opaque handle.
unsafe {
binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
};
@@ -77,7 +77,7 @@ impl RpcSessionRef {
/// Sets the maximum number of outgoing connections.
pub fn set_max_outgoing_connections(&self, connections: usize) {
- // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ // SAFETY: Only passes the 'self' pointer as an opaque handle.
unsafe {
binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingConnections(
self.as_ptr(),
@@ -210,10 +210,10 @@ impl RpcSessionRef {
type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
+ let request_fd_ptr = param as *mut RequestFd;
// SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
// BinderFdFactory reference, with param being a properly aligned non-null pointer to an
// initialized instance.
- let request_fd_ptr = param as *mut RequestFd;
- let request_fd = request_fd_ptr.as_mut().unwrap();
+ let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
request_fd().unwrap_or(-1)
}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 993bdca4a5..463c210316 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -97,8 +97,8 @@ where
/// Interface stability promise
///
-/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
-/// makes no stability guarantees ([`Local`]). [`Local`] is
+/// An interface can promise to be a stable vendor interface ([`Stability::Vintf`]),
+/// or makes no stability guarantees ([`Stability::Local`]). [`Stability::Local`] is
/// currently the default stability.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum Stability {
@@ -139,8 +139,8 @@ impl TryFrom<i32> for Stability {
/// via `Binder::new(object)`.
///
/// This is a low-level interface that should normally be automatically
-/// generated from AIDL via the [`declare_binder_interface!`] macro. When using
-/// the AIDL backend, users need only implement the high-level AIDL-defined
+/// generated from AIDL via the [`crate::declare_binder_interface!`] macro.
+/// When using the AIDL backend, users need only implement the high-level AIDL-defined
/// interface. The AIDL compiler then generates a container struct that wraps
/// the user-defined service and implements `Remotable`.
pub trait Remotable: Send + Sync {
@@ -297,18 +297,17 @@ impl InterfaceClass {
/// Note: the returned pointer will not be constant. Calling this method
/// multiple times for the same type will result in distinct class
/// pointers. A static getter for this value is implemented in
- /// [`declare_binder_interface!`].
+ /// [`crate::declare_binder_interface!`].
pub fn new<I: InterfaceClassMethods>() -> InterfaceClass {
let descriptor = CString::new(I::get_descriptor()).unwrap();
+ // Safety: `AIBinder_Class_define` expects a valid C string, and three
+ // valid callback functions, all non-null pointers. The C string is
+ // copied and need not be valid for longer than the call, so we can drop
+ // it after the call. We can safely assign null to the onDump and
+ // handleShellCommand callbacks as long as the class pointer was
+ // non-null. Rust None for a Option<fn> is guaranteed to be a NULL
+ // pointer. Rust retains ownership of the pointer after it is defined.
let ptr = unsafe {
- // Safety: `AIBinder_Class_define` expects a valid C string, and
- // three valid callback functions, all non-null pointers. The C
- // string is copied and need not be valid for longer than the call,
- // so we can drop it after the call. We can safely assign null to
- // the onDump and handleShellCommand callbacks as long as the class
- // pointer was non-null. Rust None for a Option<fn> is guaranteed to
- // be a NULL pointer. Rust retains ownership of the pointer after it
- // is defined.
let class = sys::AIBinder_Class_define(
descriptor.as_ptr(),
Some(I::on_create),
@@ -338,13 +337,12 @@ impl InterfaceClass {
/// Get the interface descriptor string of this class.
pub fn get_descriptor(&self) -> String {
+ // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor is
+ // always a two-byte null terminated sequence of u16s. Thus, we can
+ // continue reading from the pointer until we hit a null value, and this
+ // pointer can be a valid slice if the slice length is <= the number of
+ // u16 elements before the null terminator.
unsafe {
- // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor
- // is always a two-byte null terminated sequence of u16s. Thus, we
- // can continue reading from the pointer until we hit a null value,
- // and this pointer can be a valid slice if the slice length is <=
- // the number of u16 elements before the null terminator.
-
let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
CStr::from_ptr(raw_descriptor)
.to_str()
@@ -542,17 +540,15 @@ macro_rules! binder_fn_get_class {
static CLASS_INIT: std::sync::Once = std::sync::Once::new();
static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
+ // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+ // variable, and therefore is thread-safe, as it can only occur
+ // once.
CLASS_INIT.call_once(|| unsafe {
- // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
- // variable, and therefore is thread-safe, as it can only occur
- // once.
CLASS = Some($constructor);
});
- unsafe {
- // Safety: The `CLASS` variable can only be mutated once, above,
- // and is subsequently safe to read from any thread.
- CLASS.unwrap()
- }
+ // Safety: The `CLASS` variable can only be mutated once, above, and
+ // is subsequently safe to read from any thread.
+ unsafe { CLASS.unwrap() }
}
};
}
@@ -664,6 +660,8 @@ pub unsafe trait AsNative<T> {
fn as_native_mut(&mut self) -> *mut T;
}
+// Safety: If V is a valid Android C++ type then we can either use that or a
+// null pointer.
unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> {
fn as_native(&self) -> *const T {
self.as_ref().map_or(ptr::null(), |v| v.as_native())
@@ -924,15 +922,15 @@ macro_rules! declare_binder_interface {
static CLASS_INIT: std::sync::Once = std::sync::Once::new();
static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
+ // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+ // variable, and therefore is thread-safe, as it can only occur
+ // once.
CLASS_INIT.call_once(|| unsafe {
- // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
- // variable, and therefore is thread-safe, as it can only occur
- // once.
CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>());
});
+ // Safety: The `CLASS` variable can only be mutated once, above,
+ // and is subsequently safe to read from any thread.
unsafe {
- // Safety: The `CLASS` variable can only be mutated once, above,
- // and is subsequently safe to read from any thread.
CLASS.unwrap()
}
}
@@ -1025,17 +1023,7 @@ macro_rules! declare_binder_interface {
}
if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
- let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
- std::convert::TryFrom::try_from(ibinder.clone());
- if let Ok(service) = service {
- // We were able to associate with our expected class and
- // the service is local.
- todo!()
- //return Ok($crate::Strong::new(Box::new(service)));
- } else {
- // Service is remote
- return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
- }
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
}
Err($crate::StatusCode::BAD_TYPE.into())
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
index ba260624bc..eb04cc3153 100644
--- a/libs/binder/rust/src/error.rs
+++ b/libs/binder/rust/src/error.rs
@@ -112,41 +112,35 @@ fn to_cstring<T: AsRef<str>>(message: T) -> Option<CString> {
impl Status {
/// Create a status object representing a successful transaction.
pub fn ok() -> Self {
- let ptr = unsafe {
- // Safety: `AStatus_newOk` always returns a new, heap allocated
- // pointer to an `ASTatus` object, so we know this pointer will be
- // valid.
- //
- // Rust takes ownership of the returned pointer.
- sys::AStatus_newOk()
- };
+ // Safety: `AStatus_newOk` always returns a new, heap allocated
+ // pointer to an `ASTatus` object, so we know this pointer will be
+ // valid.
+ //
+ // Rust takes ownership of the returned pointer.
+ let ptr = unsafe { sys::AStatus_newOk() };
Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
}
/// Create a status object from a service specific error
pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status {
let ptr = if let Some(message) = message {
- unsafe {
- // Safety: Any i32 is a valid service specific error for the
- // error code parameter. We construct a valid, null-terminated
- // `CString` from the message, which must be a valid C-style
- // string to pass as the message. This function always returns a
- // new, heap allocated pointer to an `AStatus` object, so we
- // know the returned pointer will be valid.
- //
- // Rust takes ownership of the returned pointer.
- sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr())
- }
+ // Safety: Any i32 is a valid service specific error for the
+ // error code parameter. We construct a valid, null-terminated
+ // `CString` from the message, which must be a valid C-style
+ // string to pass as the message. This function always returns a
+ // new, heap allocated pointer to an `AStatus` object, so we
+ // know the returned pointer will be valid.
+ //
+ // Rust takes ownership of the returned pointer.
+ unsafe { sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) }
} else {
- unsafe {
- // Safety: Any i32 is a valid service specific error for the
- // error code parameter. This function always returns a new,
- // heap allocated pointer to an `AStatus` object, so we know the
- // returned pointer will be valid.
- //
- // Rust takes ownership of the returned pointer.
- sys::AStatus_fromServiceSpecificError(err)
- }
+ // Safety: Any i32 is a valid service specific error for the
+ // error code parameter. This function always returns a new,
+ // heap allocated pointer to an `AStatus` object, so we know the
+ // returned pointer will be valid.
+ //
+ // Rust takes ownership of the returned pointer.
+ unsafe { sys::AStatus_fromServiceSpecificError(err) }
};
Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
}
@@ -159,6 +153,8 @@ impl Status {
/// Create a status object from an exception code
pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
if let Some(message) = message {
+ // Safety: the C string pointer is valid and not retained by the
+ // function.
let ptr = unsafe {
sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr())
};
@@ -187,37 +183,31 @@ impl Status {
/// Returns `true` if this status represents a successful transaction.
pub fn is_ok(&self) -> bool {
- unsafe {
- // Safety: `Status` always contains a valid `AStatus` pointer, so we
- // are always passing a valid pointer to `AStatus_isOk` here.
- sys::AStatus_isOk(self.as_native())
- }
+ // Safety: `Status` always contains a valid `AStatus` pointer, so we
+ // are always passing a valid pointer to `AStatus_isOk` here.
+ unsafe { sys::AStatus_isOk(self.as_native()) }
}
/// Returns a description of the status.
pub fn get_description(&self) -> String {
- let description_ptr = unsafe {
- // Safety: `Status` always contains a valid `AStatus` pointer, so we
- // are always passing a valid pointer to `AStatus_getDescription`
- // here.
- //
- // `AStatus_getDescription` always returns a valid pointer to a null
- // terminated C string. Rust is responsible for freeing this pointer
- // via `AStatus_deleteDescription`.
- sys::AStatus_getDescription(self.as_native())
- };
- let description = unsafe {
- // Safety: `AStatus_getDescription` always returns a valid C string,
- // which can be safely converted to a `CStr`.
- CStr::from_ptr(description_ptr)
- };
+ // Safety: `Status` always contains a valid `AStatus` pointer, so we
+ // are always passing a valid pointer to `AStatus_getDescription`
+ // here.
+ //
+ // `AStatus_getDescription` always returns a valid pointer to a null
+ // terminated C string. Rust is responsible for freeing this pointer
+ // via `AStatus_deleteDescription`.
+ let description_ptr = unsafe { sys::AStatus_getDescription(self.as_native()) };
+ // Safety: `AStatus_getDescription` always returns a valid C string,
+ // which can be safely converted to a `CStr`.
+ let description = unsafe { CStr::from_ptr(description_ptr) };
let description = description.to_string_lossy().to_string();
+ // Safety: `description_ptr` was returned from
+ // `AStatus_getDescription` above, and must be freed via
+ // `AStatus_deleteDescription`. We must not access the pointer after
+ // this call, so we copy it into an owned string above and return
+ // that string.
unsafe {
- // Safety: `description_ptr` was returned from
- // `AStatus_getDescription` above, and must be freed via
- // `AStatus_deleteDescription`. We must not access the pointer after
- // this call, so we copy it into an owned string above and return
- // that string.
sys::AStatus_deleteDescription(description_ptr);
}
description
@@ -225,12 +215,10 @@ impl Status {
/// Returns the exception code of the status.
pub fn exception_code(&self) -> ExceptionCode {
- let code = unsafe {
- // Safety: `Status` always contains a valid `AStatus` pointer, so we
- // are always passing a valid pointer to `AStatus_getExceptionCode`
- // here.
- sys::AStatus_getExceptionCode(self.as_native())
- };
+ // Safety: `Status` always contains a valid `AStatus` pointer, so we
+ // are always passing a valid pointer to `AStatus_getExceptionCode`
+ // here.
+ let code = unsafe { sys::AStatus_getExceptionCode(self.as_native()) };
parse_exception_code(code)
}
@@ -241,11 +229,9 @@ impl Status {
/// exception or a service specific error. To find out if this transaction
/// as a whole is okay, use [`is_ok`](Self::is_ok) instead.
pub fn transaction_error(&self) -> StatusCode {
- let code = unsafe {
- // Safety: `Status` always contains a valid `AStatus` pointer, so we
- // are always passing a valid pointer to `AStatus_getStatus` here.
- sys::AStatus_getStatus(self.as_native())
- };
+ // Safety: `Status` always contains a valid `AStatus` pointer, so we
+ // are always passing a valid pointer to `AStatus_getStatus` here.
+ let code = unsafe { sys::AStatus_getStatus(self.as_native()) };
parse_status_code(code)
}
@@ -258,12 +244,10 @@ impl Status {
/// find out if this transaction as a whole is okay, use
/// [`is_ok`](Self::is_ok) instead.
pub fn service_specific_error(&self) -> i32 {
- unsafe {
- // Safety: `Status` always contains a valid `AStatus` pointer, so we
- // are always passing a valid pointer to
- // `AStatus_getServiceSpecificError` here.
- sys::AStatus_getServiceSpecificError(self.as_native())
- }
+ // Safety: `Status` always contains a valid `AStatus` pointer, so we
+ // are always passing a valid pointer to
+ // `AStatus_getServiceSpecificError` here.
+ unsafe { sys::AStatus_getServiceSpecificError(self.as_native()) }
}
/// Calls `op` if the status was ok, otherwise returns an `Err` value of
@@ -321,24 +305,20 @@ impl From<StatusCode> for Status {
impl From<status_t> for Status {
fn from(status: status_t) -> Status {
- let ptr = unsafe {
- // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
- // this is a safe FFI call. Unknown values will be coerced into
- // UNKNOWN_ERROR.
- sys::AStatus_fromStatus(status)
- };
+ // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
+ // this is a safe FFI call. Unknown values will be coerced into
+ // UNKNOWN_ERROR.
+ let ptr = unsafe { sys::AStatus_fromStatus(status) };
Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
}
}
impl From<ExceptionCode> for Status {
fn from(code: ExceptionCode) -> Status {
- let ptr = unsafe {
- // Safety: `AStatus_fromExceptionCode` expects any
- // `binder_exception_t` (i32) integer, so this is a safe FFI call.
- // Unknown values will be coerced into EX_TRANSACTION_FAILED.
- sys::AStatus_fromExceptionCode(code as i32)
- };
+ // Safety: `AStatus_fromExceptionCode` expects any
+ // `binder_exception_t` (i32) integer, so this is a safe FFI call.
+ // Unknown values will be coerced into EX_TRANSACTION_FAILED.
+ let ptr = unsafe { sys::AStatus_fromExceptionCode(code as i32) };
Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
}
}
@@ -363,20 +343,18 @@ impl From<Status> for status_t {
impl Drop for Status {
fn drop(&mut self) {
+ // Safety: `Status` manages the lifetime of its inner `AStatus`
+ // pointee, so we need to delete it here. We know that the pointer
+ // will be valid here since `Status` always contains a valid pointer
+ // while it is alive.
unsafe {
- // Safety: `Status` manages the lifetime of its inner `AStatus`
- // pointee, so we need to delete it here. We know that the pointer
- // will be valid here since `Status` always contains a valid pointer
- // while it is alive.
sys::AStatus_delete(self.0.as_mut());
}
}
}
-/// # Safety
-///
-/// `Status` always contains a valid pointer to an `AStatus` object, so we can
-/// trivially convert it to a correctly-typed raw pointer.
+/// Safety: `Status` always contains a valid pointer to an `AStatus` object, so
+/// we can trivially convert it to a correctly-typed raw pointer.
///
/// Care must be taken that the returned pointer is only dereferenced while the
/// `Status` object is still alive.
@@ -386,11 +364,97 @@ unsafe impl AsNative<sys::AStatus> for Status {
}
fn as_native_mut(&mut self) -> *mut sys::AStatus {
- unsafe {
- // Safety: The pointer will be valid here since `Status` always
- // contains a valid and initialized pointer while it is alive.
- self.0.as_mut()
- }
+ // Safety: The pointer will be valid here since `Status` always contains
+ // a valid and initialized pointer while it is alive.
+ unsafe { self.0.as_mut() }
+ }
+}
+
+/// A conversion from `std::result::Result<T, E>` to `binder::Result<T>`. If this type is `Ok(T)`,
+/// it's returned as is. If this type is `Err(E)`, `E` is converted into `Status` which can be
+/// either a general binder exception, or a service-specific exception.
+///
+/// # Examples
+///
+/// ```
+/// // std::io::Error is formatted as the exception's message
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+/// std::fs::metadata(name)
+/// .or_service_specific_exception(NOT_FOUND)?
+/// }
+///
+/// // A custom function is used to create the exception's message
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+/// std::fs::metadata(name)
+/// .or_service_specific_exception_with(NOT_FOUND,
+/// |e| format!("file {} not found: {:?}", name, e))?
+/// }
+///
+/// // anyhow::Error is formatted as the exception's message
+/// use anyhow::{Context, Result};
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+/// std::fs::metadata(name)
+/// .context("file {} not found")
+/// .or_service_specific_exception(NOT_FOUND)?
+/// }
+///
+/// // General binder exceptions can be created similarly
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+/// std::fs::metadata(name)
+/// .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?
+/// }
+/// ```
+pub trait IntoBinderResult<T, E> {
+ /// Converts the embedded error into a general binder exception of code `exception`. The
+ /// message of the exception is set by formatting the error for debugging.
+ fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status>;
+
+ /// Converts the embedded error into a general binder exception of code `exception`. The
+ /// message of the exception is set by lazily evaluating the `op` function.
+ fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+ self,
+ exception: ExceptionCode,
+ op: O,
+ ) -> result::Result<T, Status>;
+
+ /// Converts the embedded error into a service-specific binder exception. `error_code` is used
+ /// to distinguish different service-specific binder exceptions. The message of the exception
+ /// is set by formatting the error for debugging.
+ fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status>;
+
+ /// Converts the embedded error into a service-specific binder exception. `error_code` is used
+ /// to distinguish different service-specific binder exceptions. The message of the exception
+ /// is set by lazily evaluating the `op` function.
+ fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+ self,
+ error_code: i32,
+ op: O,
+ ) -> result::Result<T, Status>;
+}
+
+impl<T, E: std::fmt::Debug> IntoBinderResult<T, E> for result::Result<T, E> {
+ fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status> {
+ self.or_binder_exception_with(exception, |e| format!("{:?}", e))
+ }
+
+ fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+ self,
+ exception: ExceptionCode,
+ op: O,
+ ) -> result::Result<T, Status> {
+ self.map_err(|e| Status::new_exception_str(exception, Some(op(e))))
+ }
+
+ fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status> {
+ self.or_service_specific_exception_with(error_code, |e| format!("{:?}", e))
+ }
+
+ fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+ self,
+ error_code: i32,
+ op: O,
+ ) -> result::Result<T, Status> {
+ self.map_err(|e| Status::new_service_specific_error_str(error_code, Some(op(e))))
}
}
@@ -430,4 +494,66 @@ mod tests {
assert_eq!(status.service_specific_error(), 0);
assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): ''".to_string());
}
+
+ #[test]
+ fn convert_to_service_specific_exception() {
+ let res: std::result::Result<(), Status> =
+ Err("message").or_service_specific_exception(-42);
+
+ assert!(res.is_err());
+ let status = res.unwrap_err();
+ assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
+ assert_eq!(status.service_specific_error(), -42);
+ assert_eq!(
+ status.get_description(),
+ "Status(-8, EX_SERVICE_SPECIFIC): '-42: \"message\"'".to_string()
+ );
+ }
+
+ #[test]
+ fn convert_to_service_specific_exception_with() {
+ let res: std::result::Result<(), Status> = Err("message")
+ .or_service_specific_exception_with(-42, |e| format!("outer message: {:?}", e));
+
+ assert!(res.is_err());
+ let status = res.unwrap_err();
+ assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
+ assert_eq!(status.service_specific_error(), -42);
+ assert_eq!(
+ status.get_description(),
+ "Status(-8, EX_SERVICE_SPECIFIC): '-42: outer message: \"message\"'".to_string()
+ );
+ }
+
+ #[test]
+ fn convert_to_binder_exception() {
+ let res: std::result::Result<(), Status> =
+ Err("message").or_binder_exception(ExceptionCode::ILLEGAL_STATE);
+
+ assert!(res.is_err());
+ let status = res.unwrap_err();
+ assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+ assert_eq!(status.service_specific_error(), 0);
+ assert_eq!(
+ status.get_description(),
+ "Status(-5, EX_ILLEGAL_STATE): '\"message\"'".to_string()
+ );
+ }
+
+ #[test]
+ fn convert_to_binder_exception_with() {
+ let res: std::result::Result<(), Status> = Err("message")
+ .or_binder_exception_with(ExceptionCode::ILLEGAL_STATE, |e| {
+ format!("outer message: {:?}", e)
+ });
+
+ assert!(res.is_err());
+ let status = res.unwrap_err();
+ assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+ assert_eq!(status.service_specific_error(), 0);
+ assert_eq!(
+ status.get_description(),
+ "Status(-5, EX_ILLEGAL_STATE): 'outer message: \"message\"'".to_string()
+ );
+ }
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 0c8b48f1f5..8841fe640b 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -106,7 +106,7 @@ use binder_ndk_sys as sys;
pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
-pub use error::{ExceptionCode, Status, StatusCode};
+pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
pub use native::{
add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
LazyServiceGuard,
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 5557168055..b248f5eb28 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -42,7 +42,7 @@ pub struct Binder<T: Remotable> {
rust_object: *mut T,
}
-/// # Safety
+/// Safety:
///
/// A `Binder<T>` is a pair of unique owning pointers to two values:
/// * a C++ ABBinder which the C++ API guarantees can be passed between threads
@@ -54,7 +54,7 @@ pub struct Binder<T: Remotable> {
/// to how `Box<T>` is `Send` if `T` is `Send`.
unsafe impl<T: Remotable> Send for Binder<T> {}
-/// # Safety
+/// Safety:
///
/// A `Binder<T>` is a pair of unique owning pointers to two values:
/// * a C++ ABBinder which is thread-safe, i.e. `Send + Sync`
@@ -89,15 +89,13 @@ impl<T: Remotable> Binder<T> {
pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
let class = T::get_class();
let rust_object = Box::into_raw(Box::new(rust_object));
- let ibinder = unsafe {
- // Safety: `AIBinder_new` expects a valid class pointer (which we
- // initialize via `get_class`), and an arbitrary pointer
- // argument. The caller owns the returned `AIBinder` pointer, which
- // is a strong reference to a `BBinder`. This reference should be
- // decremented via `AIBinder_decStrong` when the reference lifetime
- // ends.
- sys::AIBinder_new(class.into(), rust_object as *mut c_void)
- };
+ // Safety: `AIBinder_new` expects a valid class pointer (which we
+ // initialize via `get_class`), and an arbitrary pointer
+ // argument. The caller owns the returned `AIBinder` pointer, which
+ // is a strong reference to a `BBinder`. This reference should be
+ // decremented via `AIBinder_decStrong` when the reference lifetime
+ // ends.
+ let ibinder = unsafe { sys::AIBinder_new(class.into(), rust_object as *mut c_void) };
let mut binder = Binder { ibinder, rust_object };
binder.mark_stability(stability);
binder
@@ -176,15 +174,14 @@ impl<T: Remotable> Binder<T> {
/// }
/// # }
pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> {
- let status = unsafe {
- // Safety: `AIBinder_setExtension` expects two valid, mutable
- // `AIBinder` pointers. We are guaranteed that both `self` and
- // `extension` contain valid `AIBinder` pointers, because they
- // cannot be initialized without a valid
- // pointer. `AIBinder_setExtension` does not take ownership of
- // either parameter.
- sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut())
- };
+ let status =
+ // Safety: `AIBinder_setExtension` expects two valid, mutable
+ // `AIBinder` pointers. We are guaranteed that both `self` and
+ // `extension` contain valid `AIBinder` pointers, because they
+ // cannot be initialized without a valid
+ // pointer. `AIBinder_setExtension` does not take ownership of
+ // either parameter.
+ unsafe { sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) };
status_result(status)
}
@@ -199,9 +196,9 @@ impl<T: Remotable> Binder<T> {
match stability {
Stability::Local => self.mark_local_stability(),
Stability::Vintf => {
+ // Safety: Self always contains a valid `AIBinder` pointer, so
+ // we can always call this C API safely.
unsafe {
- // Safety: Self always contains a valid `AIBinder` pointer, so
- // we can always call this C API safely.
sys::AIBinder_markVintfStability(self.as_native_mut());
}
}
@@ -212,9 +209,9 @@ impl<T: Remotable> Binder<T> {
/// building for android_vendor and system otherwise.
#[cfg(android_vendor)]
fn mark_local_stability(&mut self) {
+ // Safety: Self always contains a valid `AIBinder` pointer, so we can
+ // always call this C API safely.
unsafe {
- // Safety: Self always contains a valid `AIBinder` pointer, so
- // we can always call this C API safely.
sys::AIBinder_markVendorStability(self.as_native_mut());
}
}
@@ -223,9 +220,9 @@ impl<T: Remotable> Binder<T> {
/// building for android_vendor and system otherwise.
#[cfg(not(android_vendor))]
fn mark_local_stability(&mut self) {
+ // Safety: Self always contains a valid `AIBinder` pointer, so we can
+ // always call this C API safely.
unsafe {
- // Safety: Self always contains a valid `AIBinder` pointer, so
- // we can always call this C API safely.
sys::AIBinder_markSystemStability(self.as_native_mut());
}
}
@@ -239,13 +236,13 @@ impl<T: Remotable> Interface for Binder<T> {
/// remotable object, which will prevent the object from being dropped while
/// the `SpIBinder` is alive.
fn as_binder(&self) -> SpIBinder {
+ // Safety: `self.ibinder` is guaranteed to always be a valid pointer
+ // to an `AIBinder` by the `Binder` constructor. We are creating a
+ // copy of the `self.ibinder` strong reference, but
+ // `SpIBinder::from_raw` assumes it receives an owned pointer with
+ // its own strong reference. We first increment the reference count,
+ // so that the new `SpIBinder` will be tracked as a new reference.
unsafe {
- // Safety: `self.ibinder` is guaranteed to always be a valid pointer
- // to an `AIBinder` by the `Binder` constructor. We are creating a
- // copy of the `self.ibinder` strong reference, but
- // `SpIBinder::from_raw` assumes it receives an owned pointer with
- // its own strong reference. We first increment the reference count,
- // so that the new `SpIBinder` will be tracked as a new reference.
sys::AIBinder_incStrong(self.ibinder);
SpIBinder::from_raw(self.ibinder).unwrap()
}
@@ -275,10 +272,20 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> {
reply: *mut sys::AParcel,
) -> status_t {
let res = {
- let mut reply = BorrowedParcel::from_raw(reply).unwrap();
- let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap();
- let object = sys::AIBinder_getUserData(binder);
- let binder: &T = &*(object as *const T);
+ // Safety: The caller must give us a parcel pointer which is either
+ // null or valid at least for the duration of this function call. We
+ // don't keep the resulting value beyond the function.
+ let mut reply = unsafe { BorrowedParcel::from_raw(reply).unwrap() };
+ // Safety: The caller must give us a parcel pointer which is either
+ // null or valid at least for the duration of this function call. We
+ // don't keep the resulting value beyond the function.
+ let data = unsafe { BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap() };
+ // Safety: Our caller promised that `binder` is a non-null, valid
+ // pointer to a local `AIBinder`.
+ let object = unsafe { sys::AIBinder_getUserData(binder) };
+ // Safety: Our caller promised that the binder has a `T` pointer in
+ // its user data.
+ let binder: &T = unsafe { &*(object as *const T) };
binder.on_transact(code, &data, &mut reply)
};
match res {
@@ -295,7 +302,9 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> {
/// Must be called with a valid pointer to a `T` object. After this call,
/// the pointer will be invalid and should not be dereferenced.
unsafe extern "C" fn on_destroy(object: *mut c_void) {
- drop(Box::from_raw(object as *mut T));
+ // Safety: Our caller promised that `object` is a valid pointer to a
+ // `T`.
+ drop(unsafe { Box::from_raw(object as *mut T) });
}
/// Called whenever a new, local `AIBinder` object is needed of a specific
@@ -320,7 +329,7 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> {
/// Must be called with a non-null, valid pointer to a local `AIBinder` that
/// contains a `T` pointer in its user data. fd should be a non-owned file
/// descriptor, and args must be an array of null-terminated string
- /// poiinters with length num_args.
+ /// pointers with length num_args.
unsafe extern "C" fn on_dump(
binder: *mut sys::AIBinder,
fd: i32,
@@ -330,8 +339,9 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> {
if fd < 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
}
- // We don't own this file, so we need to be careful not to drop it.
- let file = ManuallyDrop::new(File::from_raw_fd(fd));
+ // Safety: Our caller promised that fd is a file descriptor. We don't
+ // own this file descriptor, so we need to be careful not to drop it.
+ let file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd)) };
if args.is_null() && num_args != 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
@@ -340,14 +350,22 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> {
let args = if args.is_null() || num_args == 0 {
vec![]
} else {
- slice::from_raw_parts(args, num_args as usize)
- .iter()
- .map(|s| CStr::from_ptr(*s))
- .collect()
+ // Safety: Our caller promised that `args` is an array of
+ // null-terminated string pointers with length `num_args`.
+ unsafe {
+ slice::from_raw_parts(args, num_args as usize)
+ .iter()
+ .map(|s| CStr::from_ptr(*s))
+ .collect()
+ }
};
- let object = sys::AIBinder_getUserData(binder);
- let binder: &T = &*(object as *const T);
+ // Safety: Our caller promised that `binder` is a non-null, valid
+ // pointer to a local `AIBinder`.
+ let object = unsafe { sys::AIBinder_getUserData(binder) };
+ // Safety: Our caller promised that the binder has a `T` pointer in its
+ // user data.
+ let binder: &T = unsafe { &*(object as *const T) };
let res = binder.on_dump(&file, &args);
match res {
@@ -363,11 +381,11 @@ impl<T: Remotable> Drop for Binder<T> {
// actually destroys the object, it calls `on_destroy` and we can drop the
// `rust_object` then.
fn drop(&mut self) {
+ // Safety: When `self` is dropped, we can no longer access the
+ // reference, so can decrement the reference count. `self.ibinder` is
+ // always a valid `AIBinder` pointer, so is valid to pass to
+ // `AIBinder_decStrong`.
unsafe {
- // Safety: When `self` is dropped, we can no longer access the
- // reference, so can decrement the reference count. `self.ibinder`
- // is always a valid `AIBinder` pointer, so is valid to pass to
- // `AIBinder_decStrong`.
sys::AIBinder_decStrong(self.ibinder);
}
}
@@ -377,14 +395,11 @@ impl<T: Remotable> Deref for Binder<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
- unsafe {
- // Safety: While `self` is alive, the reference count of the
- // underlying object is > 0 and therefore `on_destroy` cannot be
- // called. Therefore while `self` is alive, we know that
- // `rust_object` is still a valid pointer to a heap allocated object
- // of type `T`.
- &*self.rust_object
- }
+ // Safety: While `self` is alive, the reference count of the underlying
+ // object is > 0 and therefore `on_destroy` cannot be called. Therefore
+ // while `self` is alive, we know that `rust_object` is still a valid
+ // pointer to a heap allocated object of type `T`.
+ unsafe { &*self.rust_object }
}
}
@@ -405,13 +420,10 @@ impl<B: Remotable> TryFrom<SpIBinder> for Binder<B> {
if Some(class) != ibinder.get_class() {
return Err(StatusCode::BAD_TYPE);
}
- let userdata = unsafe {
- // Safety: `SpIBinder` always holds a valid pointer pointer to an
- // `AIBinder`, which we can safely pass to
- // `AIBinder_getUserData`. `ibinder` retains ownership of the
- // returned pointer.
- sys::AIBinder_getUserData(ibinder.as_native_mut())
- };
+ // Safety: `SpIBinder` always holds a valid pointer pointer to an
+ // `AIBinder`, which we can safely pass to `AIBinder_getUserData`.
+ // `ibinder` retains ownership of the returned pointer.
+ let userdata = unsafe { sys::AIBinder_getUserData(ibinder.as_native_mut()) };
if userdata.is_null() {
return Err(StatusCode::UNEXPECTED_NULL);
}
@@ -422,12 +434,10 @@ impl<B: Remotable> TryFrom<SpIBinder> for Binder<B> {
}
}
-/// # Safety
-///
-/// The constructor for `Binder` guarantees that `self.ibinder` will contain a
-/// valid, non-null pointer to an `AIBinder`, so this implementation is type
-/// safe. `self.ibinder` will remain valid for the entire lifetime of `self`
-/// because we hold a strong reference to the `AIBinder` until `self` is
+/// Safety: The constructor for `Binder` guarantees that `self.ibinder` will
+/// contain a valid, non-null pointer to an `AIBinder`, so this implementation
+/// is type safe. `self.ibinder` will remain valid for the entire lifetime of
+/// `self` because we hold a strong reference to the `AIBinder` until `self` is
/// dropped.
unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> {
fn as_native(&self) -> *const sys::AIBinder {
@@ -447,14 +457,12 @@ unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> {
/// This function will panic if the identifier contains a 0 byte (NUL).
pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
- let status = unsafe {
- // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
- // string pointers. Caller retains ownership of both
- // pointers. `AServiceManager_addService` creates a new strong reference
- // and copies the string, so both pointers need only be valid until the
- // call returns.
- sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr())
- };
+ let status =
+ // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
+ // string pointers. Caller retains ownership of both pointers.
+ // `AServiceManager_addService` creates a new strong reference and copies
+ // the string, so both pointers need only be valid until the call returns.
+ unsafe { sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) };
status_result(status)
}
@@ -470,13 +478,12 @@ pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
/// This function will panic if the identifier contains a 0 byte (NUL).
pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
+ // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
+ // string pointers. Caller retains ownership of both
+ // pointers. `AServiceManager_registerLazyService` creates a new strong reference
+ // and copies the string, so both pointers need only be valid until the
+ // call returns.
let status = unsafe {
- // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
- // string pointers. Caller retains ownership of both
- // pointers. `AServiceManager_registerLazyService` creates a new strong reference
- // and copies the string, so both pointers need only be valid until the
- // call returns.
-
sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
};
status_result(status)
@@ -491,10 +498,8 @@ pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<
///
/// Consider using [`LazyServiceGuard`] rather than calling this directly.
pub fn force_lazy_services_persist(persist: bool) {
- unsafe {
- // Safety: No borrowing or transfer of ownership occurs here.
- sys::AServiceManager_forceLazyServicesPersist(persist)
- }
+ // Safety: No borrowing or transfer of ownership occurs here.
+ unsafe { sys::AServiceManager_forceLazyServicesPersist(persist) }
}
/// An RAII object to ensure a process which registers lazy services is not killed. During the
@@ -576,8 +581,6 @@ impl Interface for () {}
/// Determine whether the current thread is currently executing an incoming
/// transaction.
pub fn is_handling_transaction() -> bool {
- unsafe {
- // Safety: This method is always safe to call.
- sys::AIBinder_isHandlingTransaction()
- }
+ // Safety: This method is always safe to call.
+ unsafe { sys::AIBinder_isHandlingTransaction() }
}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index e4c568eab2..3c615edbc0 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -52,11 +52,8 @@ pub struct Parcel {
ptr: NonNull<sys::AParcel>,
}
-/// # Safety
-///
-/// This type guarantees that it owns the AParcel and that all access to
-/// the AParcel happens through the Parcel, so it is ok to send across
-/// threads.
+/// Safety: This type guarantees that it owns the AParcel and that all access to
+/// the AParcel happens through the Parcel, so it is ok to send across threads.
unsafe impl Send for Parcel {}
/// Container for a message (data and object references) that can be sent
@@ -73,11 +70,9 @@ pub struct BorrowedParcel<'a> {
impl Parcel {
/// Create a new empty `Parcel`.
pub fn new() -> Parcel {
- let ptr = unsafe {
- // Safety: If `AParcel_create` succeeds, it always returns
- // a valid pointer. If it fails, the process will crash.
- sys::AParcel_create()
- };
+ // Safety: If `AParcel_create` succeeds, it always returns
+ // a valid pointer. If it fails, the process will crash.
+ let ptr = unsafe { sys::AParcel_create() };
Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") }
}
@@ -171,10 +166,8 @@ impl<'a> BorrowedParcel<'a> {
}
}
-/// # Safety
-///
-/// The `Parcel` constructors guarantee that a `Parcel` object will always
-/// contain a valid pointer to an `AParcel`.
+/// Safety: The `Parcel` constructors guarantee that a `Parcel` object will
+/// always contain a valid pointer to an `AParcel`.
unsafe impl AsNative<sys::AParcel> for Parcel {
fn as_native(&self) -> *const sys::AParcel {
self.ptr.as_ptr()
@@ -185,10 +178,8 @@ unsafe impl AsNative<sys::AParcel> for Parcel {
}
}
-/// # Safety
-///
-/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object
-/// will always contain a valid pointer to an `AParcel`.
+/// Safety: The `BorrowedParcel` constructors guarantee that a `BorrowedParcel`
+/// object will always contain a valid pointer to an `AParcel`.
unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> {
fn as_native(&self) -> *const sys::AParcel {
self.ptr.as_ptr()
@@ -203,10 +194,8 @@ unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> {
impl<'a> BorrowedParcel<'a> {
/// Data written to parcelable is zero'd before being deleted or reallocated.
pub fn mark_sensitive(&mut self) {
- unsafe {
- // Safety: guaranteed to have a parcel object, and this method never fails
- sys::AParcel_markSensitive(self.as_native())
- }
+ // Safety: guaranteed to have a parcel object, and this method never fails
+ unsafe { sys::AParcel_markSensitive(self.as_native()) }
}
/// Write a type that implements [`Serialize`] to the parcel.
@@ -265,11 +254,15 @@ impl<'a> BorrowedParcel<'a> {
f(&mut subparcel)?;
}
let end = self.get_data_position();
+ // Safety: start is less than the current size of the parcel data
+ // buffer, because we just got it with `get_data_position`.
unsafe {
self.set_data_position(start)?;
}
assert!(end >= start);
self.write(&(end - start))?;
+ // Safety: end is less than the current size of the parcel data
+ // buffer, because we just got it with `get_data_position`.
unsafe {
self.set_data_position(end)?;
}
@@ -278,20 +271,16 @@ impl<'a> BorrowedParcel<'a> {
/// Returns the current position in the parcel data.
pub fn get_data_position(&self) -> i32 {
- unsafe {
- // Safety: `BorrowedParcel` always contains a valid pointer to an
- // `AParcel`, and this call is otherwise safe.
- sys::AParcel_getDataPosition(self.as_native())
- }
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
+ unsafe { sys::AParcel_getDataPosition(self.as_native()) }
}
/// Returns the total size of the parcel.
pub fn get_data_size(&self) -> i32 {
- unsafe {
- // Safety: `BorrowedParcel` always contains a valid pointer to an
- // `AParcel`, and this call is otherwise safe.
- sys::AParcel_getDataSize(self.as_native())
- }
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
+ unsafe { sys::AParcel_getDataSize(self.as_native()) }
}
/// Move the current read/write position in the parcel.
@@ -304,7 +293,9 @@ impl<'a> BorrowedParcel<'a> {
/// accesses are bounds checked, this call is still safe, but we can't rely
/// on that.
pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
- status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and the caller guarantees that `pos` is within bounds.
+ status_result(unsafe { sys::AParcel_setDataPosition(self.as_native(), pos) })
}
/// Append a subset of another parcel.
@@ -317,10 +308,10 @@ impl<'a> BorrowedParcel<'a> {
start: i32,
size: i32,
) -> Result<()> {
+ // Safety: `Parcel::appendFrom` from C++ checks that `start`
+ // and `size` are in bounds, and returns an error otherwise.
+ // Both `self` and `other` always contain valid pointers.
let status = unsafe {
- // Safety: `Parcel::appendFrom` from C++ checks that `start`
- // and `size` are in bounds, and returns an error otherwise.
- // Both `self` and `other` always contain valid pointers.
sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size)
};
status_result(status)
@@ -418,7 +409,9 @@ impl Parcel {
/// accesses are bounds checked, this call is still safe, but we can't rely
/// on that.
pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
- self.borrowed_ref().set_data_position(pos)
+ // Safety: We have the same safety requirements as
+ // `BorrowedParcel::set_data_position`.
+ unsafe { self.borrowed_ref().set_data_position(pos) }
}
/// Append a subset of another parcel.
@@ -461,7 +454,7 @@ impl<'a> BorrowedParcel<'a> {
/// and call a closure with the sub-parcel as its parameter.
/// The closure can keep reading data from the sub-parcel
/// until it runs out of input data. The closure is responsible
- /// for calling [`ReadableSubParcel::has_more_data`] to check for
+ /// for calling `ReadableSubParcel::has_more_data` to check for
/// more data before every read, at least until Rust generators
/// are stabilized.
/// After the closure returns, skip to the end of the current
@@ -504,7 +497,10 @@ impl<'a> BorrowedParcel<'a> {
f(subparcel)?;
// Advance the data position to the actual end,
- // in case the closure read less data than was available
+ // in case the closure read less data than was available.
+ //
+ // Safety: end must be less than the current size of the parcel, because
+ // we checked above against `get_data_size`.
unsafe {
self.set_data_position(end)?;
}
@@ -595,7 +591,7 @@ impl Parcel {
/// and call a closure with the sub-parcel as its parameter.
/// The closure can keep reading data from the sub-parcel
/// until it runs out of input data. The closure is responsible
- /// for calling [`ReadableSubParcel::has_more_data`] to check for
+ /// for calling `ReadableSubParcel::has_more_data` to check for
/// more data before every read, at least until Rust generators
/// are stabilized.
/// After the closure returns, skip to the end of the current
@@ -649,17 +645,17 @@ impl Parcel {
// Internal APIs
impl<'a> BorrowedParcel<'a> {
pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
+ // null or a valid pointer to an `AIBinder`, both of which are
+ // valid, safe inputs to `AParcel_writeStrongBinder`.
+ //
+ // This call does not take ownership of the binder. However, it does
+ // require a mutable pointer, which we cannot extract from an
+ // immutable reference, so we clone the binder, incrementing the
+ // refcount before the call. The refcount will be immediately
+ // decremented when this temporary is dropped.
unsafe {
- // Safety: `BorrowedParcel` always contains a valid pointer to an
- // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
- // null or a valid pointer to an `AIBinder`, both of which are
- // valid, safe inputs to `AParcel_writeStrongBinder`.
- //
- // This call does not take ownership of the binder. However, it does
- // require a mutable pointer, which we cannot extract from an
- // immutable reference, so we clone the binder, incrementing the
- // refcount before the call. The refcount will be immediately
- // decremented when this temporary is dropped.
status_result(sys::AParcel_writeStrongBinder(
self.as_native_mut(),
binder.cloned().as_native_mut(),
@@ -669,33 +665,28 @@ impl<'a> BorrowedParcel<'a> {
pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
let mut binder = ptr::null_mut();
- let status = unsafe {
- // Safety: `BorrowedParcel` always contains a valid pointer to an
- // `AParcel`. We pass a valid, mutable out pointer to the `binder`
- // parameter. After this call, `binder` will be either null or a
- // valid pointer to an `AIBinder` owned by the caller.
- sys::AParcel_readStrongBinder(self.as_native(), &mut binder)
- };
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`. We pass a valid, mutable out pointer to the `binder`
+ // parameter. After this call, `binder` will be either null or a
+ // valid pointer to an `AIBinder` owned by the caller.
+ let status = unsafe { sys::AParcel_readStrongBinder(self.as_native(), &mut binder) };
status_result(status)?;
- Ok(unsafe {
- // Safety: `binder` is either null or a valid, owned pointer at this
- // point, so can be safely passed to `SpIBinder::from_raw`.
- SpIBinder::from_raw(binder)
- })
+ // Safety: `binder` is either null or a valid, owned pointer at this
+ // point, so can be safely passed to `SpIBinder::from_raw`.
+ Ok(unsafe { SpIBinder::from_raw(binder) })
}
}
impl Drop for Parcel {
fn drop(&mut self) {
// Run the C++ Parcel complete object destructor
- unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. Since we own the parcel, we can safely delete it
- // here.
- sys::AParcel_delete(self.ptr.as_ptr())
- }
+ //
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. Since we own the parcel, we can safely delete it
+ // here.
+ unsafe { sys::AParcel_delete(self.ptr.as_ptr()) }
}
}
@@ -732,6 +723,8 @@ fn test_read_write() {
parcel.write(&1i32).unwrap();
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
parcel.set_data_position(start).unwrap();
}
@@ -748,6 +741,8 @@ fn test_read_data() {
parcel.write(&b"Hello, Binder!\0"[..]).unwrap();
// Skip over string length
+ // SAFETY: str_start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(str_start).is_ok());
}
@@ -756,42 +751,56 @@ fn test_read_data() {
assert!(parcel.read::<bool>().unwrap());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<i8>().unwrap(), 72i8);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<u16>().unwrap(), 25928);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<i32>().unwrap(), 1819043144);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<u32>().unwrap(), 1819043144);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<i64>().unwrap(), 4764857262830019912);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<u64>().unwrap(), 4764857262830019912);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -799,6 +808,8 @@ fn test_read_data() {
assert_eq!(parcel.read::<f32>().unwrap(), 1143139100000000000000000000.0);
assert_eq!(parcel.read::<f32>().unwrap(), 40.043392);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -806,6 +817,8 @@ fn test_read_data() {
assert_eq!(parcel.read::<f64>().unwrap(), 34732488246.197815);
// Skip back to before the string length
+ // SAFETY: str_start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(str_start).is_ok());
}
@@ -819,15 +832,21 @@ fn test_utf8_utf16_conversions() {
let start = parcel.get_data_position();
assert!(parcel.write("Hello, Binder!").is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<Option<String>>().unwrap().unwrap(), "Hello, Binder!",);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(parcel.write("Embedded null \0 inside a string").is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -835,6 +854,8 @@ fn test_utf8_utf16_conversions() {
parcel.read::<Option<String>>().unwrap().unwrap(),
"Embedded null \0 inside a string",
);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -849,6 +870,8 @@ fn test_utf8_utf16_conversions() {
let s3 = "Some more text here.";
assert!(parcel.write(&[s1, s2, s3][..]).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -874,6 +897,8 @@ fn test_sized_write() {
assert_eq!(parcel.get_data_position(), start + expected_len);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
parcel.set_data_position(start).unwrap();
}
@@ -893,6 +918,8 @@ fn test_append_from() {
assert_eq!(4, parcel2.get_data_size());
assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
assert_eq!(8, parcel2.get_data_size());
+ // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not
+ // empty.
unsafe {
parcel2.set_data_position(0).unwrap();
}
@@ -903,6 +930,8 @@ fn test_append_from() {
assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
assert_eq!(Ok(()), parcel2.append_from(&parcel1, 2, 2));
assert_eq!(4, parcel2.get_data_size());
+ // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not
+ // empty.
unsafe {
parcel2.set_data_position(0).unwrap();
}
@@ -911,6 +940,8 @@ fn test_append_from() {
let mut parcel2 = Parcel::new();
assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
assert_eq!(2, parcel2.get_data_size());
+ // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not
+ // empty.
unsafe {
parcel2.set_data_position(0).unwrap();
}
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 7fe37f3b68..5c688fa71b 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -73,14 +73,12 @@ impl Eq for ParcelFileDescriptor {}
impl Serialize for ParcelFileDescriptor {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let fd = self.0.as_raw_fd();
- let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a
- // valid file, so we can borrow a valid file
- // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take
- // ownership of the fd, so we need not duplicate it first.
- sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd)
- };
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a
+ // valid file, so we can borrow a valid file
+ // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take
+ // ownership of the fd, so we need not duplicate it first.
+ let status = unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) };
status_result(status)
}
}
@@ -92,13 +90,12 @@ impl SerializeOption for ParcelFileDescriptor {
if let Some(f) = this {
f.serialize(parcel)
} else {
- let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the
- // value `-1` as the file descriptor to signify serializing a
- // null file descriptor.
- sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32)
- };
+ let status =
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the
+ // value `-1` as the file descriptor to signify serializing a
+ // null file descriptor.
+ unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) };
status_result(status)
}
}
@@ -107,25 +104,23 @@ impl SerializeOption for ParcelFileDescriptor {
impl DeserializeOption for ParcelFileDescriptor {
fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
let mut fd = -1i32;
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. We pass a valid mutable pointer to an i32, which
+ // `AParcel_readParcelFileDescriptor` assigns the valid file
+ // descriptor into, or `-1` if deserializing a null file
+ // descriptor. The read function passes ownership of the file
+ // descriptor to its caller if it was non-null, so we must take
+ // ownership of the file and ensure that it is eventually closed.
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. We pass a valid mutable pointer to an i32, which
- // `AParcel_readParcelFileDescriptor` assigns the valid file
- // descriptor into, or `-1` if deserializing a null file
- // descriptor. The read function passes ownership of the file
- // descriptor to its caller if it was non-null, so we must take
- // ownership of the file and ensure that it is eventually closed.
status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?;
}
if fd < 0 {
Ok(None)
} else {
- let file = unsafe {
- // Safety: At this point, we know that the file descriptor was
- // not -1, so must be a valid, owned file descriptor which we
- // can safely turn into a `File`.
- File::from_raw_fd(fd)
- };
+ // Safety: At this point, we know that the file descriptor was
+ // not -1, so must be a valid, owned file descriptor which we
+ // can safely turn into a `File`.
+ let file = unsafe { File::from_raw_fd(fd) };
Ok(Some(ParcelFileDescriptor::new(file)))
}
}
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 5d8c11cf94..9008a3cc0e 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -50,14 +50,14 @@ pub trait Parcelable {
fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
}
-/// A struct whose instances can be written to a [`Parcel`].
+/// A struct whose instances can be written to a [`crate::parcel::Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Serialize {
- /// Serialize this instance into the given [`Parcel`].
+ /// Serialize this instance into the given [`crate::parcel::Parcel`].
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
}
-/// A struct whose instances can be restored from a [`Parcel`].
+/// A struct whose instances can be restored from a [`crate::parcel::Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Deserialize: Sized {
/// Type for the uninitialized value of this type. Will be either `Self`
@@ -80,10 +80,10 @@ pub trait Deserialize: Sized {
/// Convert an initialized value of type `Self` into `Self::UninitType`.
fn from_init(value: Self) -> Self::UninitType;
- /// Deserialize an instance from the given [`Parcel`].
+ /// Deserialize an instance from the given [`crate::parcel::Parcel`].
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>;
- /// Deserialize an instance from the given [`Parcel`] onto the
+ /// Deserialize an instance from the given [`crate::parcel::Parcel`] onto the
/// current object. This operation will overwrite the old value
/// partially or completely, depending on how much data is available.
fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
@@ -102,8 +102,8 @@ pub trait Deserialize: Sized {
pub trait SerializeArray: Serialize + Sized {
/// Serialize an array of this type into the given parcel.
fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // Safety: Safe FFI, slice will always be a safe pointer to pass.
let res = unsafe {
- // Safety: Safe FFI, slice will always be a safe pointer to pass.
sys::AParcel_writeParcelableArray(
parcel.as_native_mut(),
slice.as_ptr() as *const c_void,
@@ -117,7 +117,9 @@ pub trait SerializeArray: Serialize + Sized {
/// Callback to serialize an element of a generic parcelable array.
///
-/// Safety: We are relying on binder_ndk to not overrun our slice. As long as it
+/// # Safety
+///
+/// We are relying on binder_ndk to not overrun our slice. As long as it
/// doesn't provide an index larger than the length of the original slice in
/// serialize_array, this operation is safe. The index provided is zero-based.
unsafe extern "C" fn serialize_element<T: Serialize>(
@@ -125,9 +127,14 @@ unsafe extern "C" fn serialize_element<T: Serialize>(
array: *const c_void,
index: usize,
) -> status_t {
- let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1);
-
- let mut parcel = match BorrowedParcel::from_raw(parcel) {
+ // Safety: The caller guarantees that `array` is a valid pointer of the
+ // appropriate type.
+ let slice: &[T] = unsafe { slice::from_raw_parts(array.cast(), index + 1) };
+
+ // Safety: The caller must give us a parcel pointer which is either null or
+ // valid at least for the duration of this function call. We don't keep the
+ // resulting value beyond the function.
+ let mut parcel = match unsafe { BorrowedParcel::from_raw(parcel) } {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
@@ -142,9 +149,9 @@ pub trait DeserializeArray: Deserialize {
/// Deserialize an array of type from the given parcel.
fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
let mut vec: Option<Vec<Self::UninitType>> = None;
+ // Safety: Safe FFI, vec is the correct opaque type expected by
+ // allocate_vec and deserialize_element.
let res = unsafe {
- // Safety: Safe FFI, vec is the correct opaque type expected by
- // allocate_vec and deserialize_element.
sys::AParcel_readParcelableArray(
parcel.as_native(),
&mut vec as *mut _ as *mut c_void,
@@ -153,21 +160,21 @@ pub trait DeserializeArray: Deserialize {
)
};
status_result(res)?;
- let vec: Option<Vec<Self>> = unsafe {
- // Safety: We are assuming that the NDK correctly initialized every
- // element of the vector by now, so we know that all the
- // UninitTypes are now properly initialized. We can transmute from
- // Vec<T::UninitType> to Vec<T> because T::UninitType has the same
- // alignment and size as T, so the pointer to the vector allocation
- // will be compatible.
- mem::transmute(vec)
- };
+ // Safety: We are assuming that the NDK correctly initialized every
+ // element of the vector by now, so we know that all the
+ // UninitTypes are now properly initialized. We can transmute from
+ // Vec<T::UninitType> to Vec<T> because T::UninitType has the same
+ // alignment and size as T, so the pointer to the vector allocation
+ // will be compatible.
+ let vec: Option<Vec<Self>> = unsafe { mem::transmute(vec) };
Ok(vec)
}
}
/// Callback to deserialize a parcelable element.
///
+/// # Safety
+///
/// The opaque array data pointer must be a mutable pointer to an
/// `Option<Vec<T::UninitType>>` with at least enough elements for `index` to be valid
/// (zero-based).
@@ -176,13 +183,18 @@ unsafe extern "C" fn deserialize_element<T: Deserialize>(
array: *mut c_void,
index: usize,
) -> status_t {
- let vec = &mut *(array as *mut Option<Vec<T::UninitType>>);
+ // Safety: The caller guarantees that `array` is a valid pointer of the
+ // appropriate type.
+ let vec = unsafe { &mut *(array as *mut Option<Vec<T::UninitType>>) };
let vec = match vec {
Some(v) => v,
None => return StatusCode::BAD_INDEX as status_t,
};
- let parcel = match BorrowedParcel::from_raw(parcel as *mut _) {
+ // Safety: The caller must give us a parcel pointer which is either null or
+ // valid at least for the duration of this function call. We don't keep the
+ // resulting value beyond the function.
+ let parcel = match unsafe { BorrowedParcel::from_raw(parcel as *mut _) } {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
@@ -254,16 +266,21 @@ pub trait DeserializeOption: Deserialize {
///
/// The opaque data pointer passed to the array read function must be a mutable
/// pointer to an `Option<Vec<T::UninitType>>`. `buffer` will be assigned a mutable pointer
-/// to the allocated vector data if this function returns true.
+/// to the allocated vector data if this function returns true. `buffer` must be a valid pointer.
unsafe extern "C" fn allocate_vec_with_buffer<T: Deserialize>(
data: *mut c_void,
len: i32,
buffer: *mut *mut T,
) -> bool {
- let res = allocate_vec::<T>(data, len);
- let vec = &mut *(data as *mut Option<Vec<T::UninitType>>);
+ // Safety: We have the same safety requirements as `allocate_vec` for `data`.
+ let res = unsafe { allocate_vec::<T>(data, len) };
+ // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type.
+ let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) };
if let Some(new_vec) = vec {
- *buffer = new_vec.as_mut_ptr() as *mut T;
+ // Safety: The caller guarantees that `buffer` is a valid pointer.
+ unsafe {
+ *buffer = new_vec.as_mut_ptr() as *mut T;
+ }
}
res
}
@@ -275,7 +292,8 @@ unsafe extern "C" fn allocate_vec_with_buffer<T: Deserialize>(
/// The opaque data pointer passed to the array read function must be a mutable
/// pointer to an `Option<Vec<T::UninitType>>`.
unsafe extern "C" fn allocate_vec<T: Deserialize>(data: *mut c_void, len: i32) -> bool {
- let vec = &mut *(data as *mut Option<Vec<T::UninitType>>);
+ // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type.
+ let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) };
if len < 0 {
*vec = None;
return true;
@@ -286,7 +304,10 @@ unsafe extern "C" fn allocate_vec<T: Deserialize>(data: *mut c_void, len: i32) -
let mut new_vec: Vec<T::UninitType> = Vec::with_capacity(len as usize);
new_vec.resize_with(len as usize, T::uninit);
- ptr::write(vec, Some(new_vec));
+ // Safety: The caller guarantees that vec is a valid mutable pointer to the appropriate type.
+ unsafe {
+ ptr::write(vec, Some(new_vec));
+ }
true
}
@@ -305,21 +326,21 @@ unsafe fn vec_assume_init<T: Deserialize>(vec: Vec<T::UninitType>) -> Vec<T> {
// Assert at compile time that `T` and `T::UninitType` have the same size and alignment.
let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT;
- // We can convert from Vec<T::UninitType> to Vec<T> because T::UninitType
- // has the same alignment and size as T, so the pointer to the vector
- // allocation will be compatible.
let mut vec = ManuallyDrop::new(vec);
- Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity())
+ // Safety: We can convert from Vec<T::UninitType> to Vec<T> because
+ // T::UninitType has the same alignment and size as T, so the pointer to the
+ // vector allocation will be compatible.
+ unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) }
}
macro_rules! impl_parcelable {
{Serialize, $ty:ty, $write_fn:path} => {
impl Serialize for $ty {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`, and any `$ty` literal value is safe to pass to
+ // `$write_fn`.
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`, and any `$ty` literal value is safe to pass to
- // `$write_fn`.
status_result($write_fn(parcel.as_native_mut(), *self))
}
}
@@ -333,11 +354,11 @@ macro_rules! impl_parcelable {
fn from_init(value: Self) -> Self::UninitType { value }
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut val = Self::default();
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. We pass a valid, mutable pointer to `val`, a
+ // literal of type `$ty`, and `$read_fn` will write the
+ // value read into `val` if successful
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. We pass a valid, mutable pointer to `val`, a
- // literal of type `$ty`, and `$read_fn` will write the
- // value read into `val` if successful
status_result($read_fn(parcel.as_native(), &mut val))?
};
Ok(val)
@@ -348,13 +369,13 @@ macro_rules! impl_parcelable {
{SerializeArray, $ty:ty, $write_array_fn:path} => {
impl SerializeArray for $ty {
fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
+ // will be a valid pointer to an array of elements of type
+ // `$ty`. If the slice length is 0, `slice.as_ptr()` may be
+ // dangling, but this is safe since the pointer is not
+ // dereferenced if the length parameter is 0.
let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
- // will be a valid pointer to an array of elements of type
- // `$ty`. If the slice length is 0, `slice.as_ptr()` may be
- // dangling, but this is safe since the pointer is not
- // dereferenced if the length parameter is 0.
$write_array_fn(
parcel.as_native_mut(),
slice.as_ptr(),
@@ -373,11 +394,11 @@ macro_rules! impl_parcelable {
impl DeserializeArray for $ty {
fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
let mut vec: Option<Vec<Self::UninitType>> = None;
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. `allocate_vec<T>` expects the opaque pointer to
+ // be of type `*mut Option<Vec<T::UninitType>>`, so `&mut vec` is
+ // correct for it.
let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. `allocate_vec<T>` expects the opaque pointer to
- // be of type `*mut Option<Vec<T::UninitType>>`, so `&mut vec` is
- // correct for it.
$read_array_fn(
parcel.as_native(),
&mut vec as *mut _ as *mut c_void,
@@ -385,11 +406,11 @@ macro_rules! impl_parcelable {
)
};
status_result(status)?;
+ // Safety: We are assuming that the NDK correctly
+ // initialized every element of the vector by now, so we
+ // know that all the UninitTypes are now properly
+ // initialized.
let vec: Option<Vec<Self>> = unsafe {
- // Safety: We are assuming that the NDK correctly
- // initialized every element of the vector by now, so we
- // know that all the UninitTypes are now properly
- // initialized.
vec.map(|vec| vec_assume_init(vec))
};
Ok(vec)
@@ -479,13 +500,13 @@ impl Deserialize for u8 {
impl SerializeArray for u8 {
fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+ // valid pointer to an array of elements of type `$ty`. If the slice
+ // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+ // since the pointer is not dereferenced if the length parameter is
+ // 0.
let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
- // valid pointer to an array of elements of type `$ty`. If the slice
- // length is 0, `slice.as_ptr()` may be dangling, but this is safe
- // since the pointer is not dereferenced if the length parameter is
- // 0.
sys::AParcel_writeByteArray(
parcel.as_native_mut(),
slice.as_ptr() as *const i8,
@@ -518,13 +539,13 @@ impl Deserialize for i16 {
impl SerializeArray for i16 {
fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+ // valid pointer to an array of elements of type `$ty`. If the slice
+ // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+ // since the pointer is not dereferenced if the length parameter is
+ // 0.
let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
- // valid pointer to an array of elements of type `$ty`. If the slice
- // length is 0, `slice.as_ptr()` may be dangling, but this is safe
- // since the pointer is not dereferenced if the length parameter is
- // 0.
sys::AParcel_writeCharArray(
parcel.as_native_mut(),
slice.as_ptr() as *const u16,
@@ -538,22 +559,22 @@ impl SerializeArray for i16 {
impl SerializeOption for str {
fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
match this {
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. If the string pointer is null,
+ // `AParcel_writeString` requires that the length is -1 to
+ // indicate that we want to serialize a null string.
None => unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. If the string pointer is null,
- // `AParcel_writeString` requires that the length is -1 to
- // indicate that we want to serialize a null string.
status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1))
},
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
+ // string pointer of `length` bytes, which is what str in Rust
+ // is. The docstring for `AParcel_writeString` says that the
+ // string input should be null-terminated, but it doesn't
+ // actually rely on that fact in the code. If this ever becomes
+ // necessary, we will need to null-terminate the str buffer
+ // before sending it.
Some(s) => unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
- // string pointer of `length` bytes, which is what str in Rust
- // is. The docstring for `AParcel_writeString` says that the
- // string input should be null-terminated, but it doesn't
- // actually rely on that fact in the code. If this ever becomes
- // necessary, we will need to null-terminate the str buffer
- // before sending it.
status_result(sys::AParcel_writeString(
parcel.as_native_mut(),
s.as_ptr() as *const c_char,
@@ -597,11 +618,11 @@ impl Deserialize for Option<String> {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut vec: Option<Vec<u8>> = None;
+ // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
+ // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>`
+ // for `allocate_vec`, so `vec` is safe to pass as the opaque data
+ // pointer on platforms where char is signed.
let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
- // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>`
- // for `allocate_vec`, so `vec` is safe to pass as the opaque data
- // pointer on platforms where char is signed.
sys::AParcel_readString(
parcel.as_native(),
&mut vec as *mut _ as *mut c_void,
@@ -751,11 +772,11 @@ impl Deserialize for Stability {
impl Serialize for Status {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // Safety: `Parcel` always contains a valid pointer to an `AParcel`
+ // and `Status` always contains a valid pointer to an `AStatus`, so
+ // both parameters are valid and safe. This call does not take
+ // ownership of either of its parameters.
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an `AParcel`
- // and `Status` always contains a valid pointer to an `AStatus`, so
- // both parameters are valid and safe. This call does not take
- // ownership of either of its parameters.
status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native()))
}
}
@@ -772,21 +793,18 @@ impl Deserialize for Status {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut status_ptr = ptr::null_mut();
- let ret_status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. We pass a mutable out pointer which will be
- // assigned a valid `AStatus` pointer if the function returns
- // status OK. This function passes ownership of the status
- // pointer to the caller, if it was assigned.
- sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr)
- };
+ let ret_status =
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. We pass a mutable out pointer which will be
+ // assigned a valid `AStatus` pointer if the function returns
+ // status OK. This function passes ownership of the status
+ // pointer to the caller, if it was assigned.
+ unsafe { sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) };
status_result(ret_status)?;
- Ok(unsafe {
- // Safety: At this point, the return status of the read call was ok,
- // so we know that `status_ptr` is a valid, owned pointer to an
- // `AStatus`, from which we can safely construct a `Status` object.
- Status::from_ptr(status_ptr)
- })
+ // Safety: At this point, the return status of the read call was ok,
+ // so we know that `status_ptr` is a valid, owned pointer to an
+ // `AStatus`, from which we can safely construct a `Status` object.
+ Ok(unsafe { Status::from_ptr(status_ptr) })
}
}
@@ -880,7 +898,6 @@ impl<T: DeserializeOption> Deserialize for Option<T> {
/// `Serialize`, `SerializeArray` and `SerializeOption` for
/// structured parcelables. The target type must implement the
/// `Parcelable` trait.
-/// ```
#[macro_export]
macro_rules! impl_serialize_for_parcelable {
($parcelable:ident) => {
@@ -1070,6 +1087,8 @@ mod tests {
assert!(custom.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1092,6 +1111,8 @@ mod tests {
assert!(bools.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1101,6 +1122,8 @@ mod tests {
assert_eq!(parcel.read::<u32>().unwrap(), 0);
assert_eq!(parcel.read::<u32>().unwrap(), 0);
assert_eq!(parcel.read::<u32>().unwrap(), 1);
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1116,12 +1139,17 @@ mod tests {
assert!(parcel.write(&u8s[..]).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
+
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1131,18 +1159,25 @@ mod tests {
let i8s = [-128i8, 127, 42, -117];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(parcel.write(&i8s[..]).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
+
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1152,10 +1187,14 @@ mod tests {
let u16s = [u16::max_value(), 12_345, 42, 117];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(u16s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1165,6 +1204,9 @@ mod tests {
assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1175,10 +1217,14 @@ mod tests {
let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(i16s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1188,6 +1234,9 @@ mod tests {
assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
+
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1198,10 +1247,14 @@ mod tests {
let u32s = [u32::max_value(), 12_345, 42, 117];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(u32s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1211,6 +1264,9 @@ mod tests {
assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1221,10 +1277,14 @@ mod tests {
let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(i32s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1234,6 +1294,9 @@ mod tests {
assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
+
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1244,10 +1307,14 @@ mod tests {
let u64s = [u64::max_value(), 12_345, 42, 117];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(u64s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1258,10 +1325,14 @@ mod tests {
let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(i64s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1272,10 +1343,14 @@ mod tests {
let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(f32s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1288,10 +1363,14 @@ mod tests {
let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(f64s.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -1309,10 +1388,14 @@ mod tests {
let strs = [s1, s2, s3, s4];
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
assert!(strs.serialize(&mut parcel.borrowed()).is_ok());
+ // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+ // made it any shorter since we got the position.
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index eb82fb7fd6..f90611361f 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -133,8 +133,8 @@ impl ParcelableHolder {
}
}
ParcelableHolderData::Parcel(ref mut parcel) => {
+ // Safety: 0 should always be a valid position.
unsafe {
- // Safety: 0 should always be a valid position.
parcel.set_data_position(0)?;
}
@@ -214,15 +214,15 @@ impl Parcelable for ParcelableHolder {
parcelable.write_to_parcel(parcel)?;
let end = parcel.get_data_position();
+ // Safety: we got the position from `get_data_position`.
unsafe {
- // Safety: we got the position from `get_data_position`.
parcel.set_data_position(length_start)?;
}
assert!(end >= data_start);
parcel.write(&(end - data_start))?;
+ // Safety: we got the position from `get_data_position`.
unsafe {
- // Safety: we got the position from `get_data_position`.
parcel.set_data_position(end)?;
}
@@ -260,11 +260,11 @@ impl Parcelable for ParcelableHolder {
new_parcel.append_from(parcel, data_start, data_size)?;
*self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
+ // Safety: `append_from` checks if `data_size` overflows
+ // `parcel` and returns `BAD_VALUE` if that happens. We also
+ // explicitly check for negative and zero `data_size` above,
+ // so `data_end` is guaranteed to be greater than `data_start`.
unsafe {
- // Safety: `append_from` checks if `data_size` overflows
- // `parcel` and returns `BAD_VALUE` if that happens. We also
- // explicitly check for negative and zero `data_size` above,
- // so `data_end` is guaranteed to be greater than `data_start`.
parcel.set_data_position(data_end)?;
}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 036f6b4f01..dad3379bdc 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -49,14 +49,12 @@ impl fmt::Debug for SpIBinder {
}
}
-/// # Safety
-///
-/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
unsafe impl Send for SpIBinder {}
-/// # Safety
-///
-/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
unsafe impl Sync for SpIBinder {}
impl SpIBinder {
@@ -97,11 +95,9 @@ impl SpIBinder {
/// Return true if this binder object is hosted in a different process than
/// the current one.
pub fn is_remote(&self) -> bool {
- unsafe {
- // Safety: `SpIBinder` guarantees that it always contains a valid
- // `AIBinder` pointer.
- sys::AIBinder_isRemote(self.as_native())
- }
+ // Safety: `SpIBinder` guarantees that it always contains a valid
+ // `AIBinder` pointer.
+ unsafe { sys::AIBinder_isRemote(self.as_native()) }
}
/// Try to convert this Binder object into a trait object for the given
@@ -116,12 +112,12 @@ impl SpIBinder {
/// Return the interface class of this binder object, if associated with
/// one.
pub fn get_class(&mut self) -> Option<InterfaceClass> {
+ // Safety: `SpIBinder` guarantees that it always contains a valid
+ // `AIBinder` pointer. `AIBinder_getClass` returns either a null
+ // pointer or a valid pointer to an `AIBinder_Class`. After mapping
+ // null to None, we can safely construct an `InterfaceClass` if the
+ // pointer was non-null.
unsafe {
- // Safety: `SpIBinder` guarantees that it always contains a valid
- // `AIBinder` pointer. `AIBinder_getClass` returns either a null
- // pointer or a valid pointer to an `AIBinder_Class`. After mapping
- // null to None, we can safely construct an `InterfaceClass` if the
- // pointer was non-null.
let class = sys::AIBinder_getClass(self.as_native_mut());
class.as_ref().map(|p| InterfaceClass::from_ptr(p))
}
@@ -152,7 +148,8 @@ pub mod unstable_api {
///
/// See `SpIBinder::from_raw`.
pub unsafe fn new_spibinder(ptr: *mut sys::AIBinder) -> Option<SpIBinder> {
- SpIBinder::from_raw(ptr)
+ // Safety: The caller makes the same guarantees as this requires.
+ unsafe { SpIBinder::from_raw(ptr) }
}
}
@@ -171,30 +168,24 @@ pub trait AssociateClass {
impl AssociateClass for SpIBinder {
fn associate_class(&mut self, class: InterfaceClass) -> bool {
- unsafe {
- // Safety: `SpIBinder` guarantees that it always contains a valid
- // `AIBinder` pointer. An `InterfaceClass` can always be converted
- // into a valid `AIBinder_Class` pointer, so these parameters are
- // always safe.
- sys::AIBinder_associateClass(self.as_native_mut(), class.into())
- }
+ // Safety: `SpIBinder` guarantees that it always contains a valid
+ // `AIBinder` pointer. An `InterfaceClass` can always be converted
+ // into a valid `AIBinder_Class` pointer, so these parameters are
+ // always safe.
+ unsafe { sys::AIBinder_associateClass(self.as_native_mut(), class.into()) }
}
}
impl Ord for SpIBinder {
fn cmp(&self, other: &Self) -> Ordering {
- let less_than = unsafe {
- // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
- // this pointer is always safe to pass to `AIBinder_lt` (null is
- // also safe to pass to this function, but we should never do that).
- sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr())
- };
- let greater_than = unsafe {
- // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
- // this pointer is always safe to pass to `AIBinder_lt` (null is
- // also safe to pass to this function, but we should never do that).
- sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr())
- };
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this
+ // pointer is always safe to pass to `AIBinder_lt` (null is also safe to
+ // pass to this function, but we should never do that).
+ let less_than = unsafe { sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr()) };
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this
+ // pointer is always safe to pass to `AIBinder_lt` (null is also safe to
+ // pass to this function, but we should never do that).
+ let greater_than = unsafe { sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr()) };
if !less_than && !greater_than {
Ordering::Equal
} else if less_than {
@@ -221,10 +212,10 @@ impl Eq for SpIBinder {}
impl Clone for SpIBinder {
fn clone(&self) -> Self {
+ // Safety: Cloning a strong reference must increment the reference
+ // count. We are guaranteed by the `SpIBinder` constructor
+ // invariants that `self.0` is always a valid `AIBinder` pointer.
unsafe {
- // Safety: Cloning a strong reference must increment the reference
- // count. We are guaranteed by the `SpIBinder` constructor
- // invariants that `self.0` is always a valid `AIBinder` pointer.
sys::AIBinder_incStrong(self.0.as_ptr());
}
Self(self.0)
@@ -235,9 +226,9 @@ impl Drop for SpIBinder {
// We hold a strong reference to the IBinder in SpIBinder and need to give up
// this reference on drop.
fn drop(&mut self) {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
+ // know this pointer is safe to pass to `AIBinder_decStrong` here.
unsafe {
- // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
- // know this pointer is safe to pass to `AIBinder_decStrong` here.
sys::AIBinder_decStrong(self.as_native_mut());
}
}
@@ -246,26 +237,24 @@ impl Drop for SpIBinder {
impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
fn prepare_transact(&self) -> Result<Parcel> {
let mut input = ptr::null_mut();
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. It is safe to cast from an
+ // immutable pointer to a mutable pointer here, because
+ // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
+ // methods but the parameter is unfortunately not marked as const.
+ //
+ // After the call, input will be either a valid, owned `AParcel`
+ // pointer, or null.
let status = unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`. It is safe to cast from an
- // immutable pointer to a mutable pointer here, because
- // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
- // methods but the parameter is unfortunately not marked as const.
- //
- // After the call, input will be either a valid, owned `AParcel`
- // pointer, or null.
sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input)
};
status_result(status)?;
- unsafe {
- // Safety: At this point, `input` is either a valid, owned `AParcel`
- // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
- // taking ownership of the parcel.
- Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
- }
+ // Safety: At this point, `input` is either a valid, owned `AParcel`
+ // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
+ // taking ownership of the parcel.
+ unsafe { Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) }
}
fn submit_transact(
@@ -275,23 +264,23 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
flags: TransactionFlags,
) -> Result<Parcel> {
let mut reply = ptr::null_mut();
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. Although `IBinder::transact` is
+ // not a const method, it is still safe to cast our immutable
+ // pointer to mutable for the call. First, `IBinder::transact` is
+ // thread-safe, so concurrency is not an issue. The only way that
+ // `transact` can affect any visible, mutable state in the current
+ // process is by calling `onTransact` for a local service. However,
+ // in order for transactions to be thread-safe, this method must
+ // dynamically lock its data before modifying it. We enforce this
+ // property in Rust by requiring `Sync` for remotable objects and
+ // only providing `on_transact` with an immutable reference to
+ // `self`.
+ //
+ // This call takes ownership of the `data` parcel pointer, and
+ // passes ownership of the `reply` out parameter to its caller. It
+ // does not affect ownership of the `binder` parameter.
let status = unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`. Although `IBinder::transact` is
- // not a const method, it is still safe to cast our immutable
- // pointer to mutable for the call. First, `IBinder::transact` is
- // thread-safe, so concurrency is not an issue. The only way that
- // `transact` can affect any visible, mutable state in the current
- // process is by calling `onTransact` for a local service. However,
- // in order for transactions to be thread-safe, this method must
- // dynamically lock its data before modifying it. We enforce this
- // property in Rust by requiring `Sync` for remotable objects and
- // only providing `on_transact` with an immutable reference to
- // `self`.
- //
- // This call takes ownership of the `data` parcel pointer, and
- // passes ownership of the `reply` out parameter to its caller. It
- // does not affect ownership of the `binder` parameter.
sys::AIBinder_transact(
self.as_native() as *mut sys::AIBinder,
code,
@@ -302,45 +291,45 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
};
status_result(status)?;
- unsafe {
- // Safety: `reply` is either a valid `AParcel` pointer or null
- // after the call to `AIBinder_transact` above, so we can
- // construct a `Parcel` out of it. `AIBinder_transact` passes
- // ownership of the `reply` parcel to Rust, so we need to
- // construct an owned variant.
- Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
- }
+ // Safety: `reply` is either a valid `AParcel` pointer or null
+ // after the call to `AIBinder_transact` above, so we can
+ // construct a `Parcel` out of it. `AIBinder_transact` passes
+ // ownership of the `reply` parcel to Rust, so we need to
+ // construct an owned variant.
+ unsafe { Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) }
}
fn is_binder_alive(&self) -> bool {
- unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`.
- //
- // This call does not affect ownership of its pointer parameter.
- sys::AIBinder_isAlive(self.as_native())
- }
+ // Safety: `SpIBinder` guarantees that `self` always contains a valid
+ // pointer to an `AIBinder`.
+ //
+ // This call does not affect ownership of its pointer parameter.
+ unsafe { sys::AIBinder_isAlive(self.as_native()) }
}
#[cfg(not(android_vndk))]
fn set_requesting_sid(&mut self, enable: bool) {
+ // Safety: `SpIBinder` guarantees that `self` always contains a valid
+ // pointer to an `AIBinder`.
+ //
+ // This call does not affect ownership of its pointer parameter.
unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
}
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect();
let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
+ // file descriptor parameter is always be a valid open file. The
+ // `args` pointer parameter is a valid pointer to an array of C
+ // strings that will outlive the call since `args` lives for the
+ // whole function scope.
+ //
+ // This call does not affect ownership of its binder pointer
+ // parameter and does not take ownership of the file or args array
+ // parameters.
let status = unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
- // file descriptor parameter is always be a valid open file. The
- // `args` pointer parameter is a valid pointer to an array of C
- // strings that will outlive the call since `args` lives for the
- // whole function scope.
- //
- // This call does not affect ownership of its binder pointer
- // parameter and does not take ownership of the file or args array
- // parameters.
sys::AIBinder_dump(
self.as_native_mut(),
fp.as_raw_fd(),
@@ -353,22 +342,18 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
fn get_extension(&mut self) -> Result<Option<SpIBinder>> {
let mut out = ptr::null_mut();
- let status = unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`. After this call, the `out`
- // parameter will be either null, or a valid pointer to an
- // `AIBinder`.
- //
- // This call passes ownership of the out pointer to its caller
- // (assuming it is set to a non-null value).
- sys::AIBinder_getExtension(self.as_native_mut(), &mut out)
- };
- let ibinder = unsafe {
- // Safety: The call above guarantees that `out` is either null or a
- // valid, owned pointer to an `AIBinder`, both of which are safe to
- // pass to `SpIBinder::from_raw`.
- SpIBinder::from_raw(out)
- };
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. After this call, the `out`
+ // parameter will be either null, or a valid pointer to an
+ // `AIBinder`.
+ //
+ // This call passes ownership of the out pointer to its caller
+ // (assuming it is set to a non-null value).
+ let status = unsafe { sys::AIBinder_getExtension(self.as_native_mut(), &mut out) };
+ // Safety: The call above guarantees that `out` is either null or a
+ // valid, owned pointer to an `AIBinder`, both of which are safe to
+ // pass to `SpIBinder::from_raw`.
+ let ibinder = unsafe { SpIBinder::from_raw(out) };
status_result(status)?;
Ok(ibinder)
@@ -377,17 +362,17 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
impl<T: AsNative<sys::AIBinder>> IBinder for T {
fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. `recipient` can always be
+ // converted into a valid pointer to an
+ // `AIBinder_DeathRecipient`.
+ //
+ // The cookie is also the correct pointer, and by calling new_cookie,
+ // we have created a new ref-count to the cookie, which linkToDeath
+ // takes ownership of. Once the DeathRecipient is unlinked for any
+ // reason (including if this call fails), the onUnlinked callback
+ // will consume that ref-count.
status_result(unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`. `recipient` can always be
- // converted into a valid pointer to an
- // `AIBinder_DeathRecipient`.
- //
- // The cookie is also the correct pointer, and by calling new_cookie,
- // we have created a new ref-count to the cookie, which linkToDeath
- // takes ownership of. Once the DeathRecipient is unlinked for any
- // reason (including if this call fails), the onUnlinked callback
- // will consume that ref-count.
sys::AIBinder_linkToDeath(
self.as_native_mut(),
recipient.as_native_mut(),
@@ -397,13 +382,13 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T {
}
fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. `recipient` can always be
+ // converted into a valid pointer to an
+ // `AIBinder_DeathRecipient`. Any value is safe to pass as the
+ // cookie, although we depend on this value being set by
+ // `get_cookie` when the death recipient callback is called.
status_result(unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`. `recipient` can always be
- // converted into a valid pointer to an
- // `AIBinder_DeathRecipient`. Any value is safe to pass as the
- // cookie, although we depend on this value being set by
- // `get_cookie` when the death recipient callback is called.
sys::AIBinder_unlinkToDeath(
self.as_native_mut(),
recipient.as_native_mut(),
@@ -413,13 +398,11 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T {
}
fn ping_binder(&mut self) -> Result<()> {
- let status = unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`.
- //
- // This call does not affect ownership of its pointer parameter.
- sys::AIBinder_ping(self.as_native_mut())
- };
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`.
+ //
+ // This call does not affect ownership of its pointer parameter.
+ let status = unsafe { sys::AIBinder_ping(self.as_native_mut()) };
status_result(status)
}
}
@@ -472,35 +455,31 @@ impl fmt::Debug for WpIBinder {
}
}
-/// # Safety
-///
-/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
unsafe impl Send for WpIBinder {}
-/// # Safety
-///
-/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
unsafe impl Sync for WpIBinder {}
impl WpIBinder {
/// Create a new weak reference from an object that can be converted into a
/// raw `AIBinder` pointer.
fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder {
- let ptr = unsafe {
- // Safety: `SpIBinder` guarantees that `binder` always contains a
- // valid pointer to an `AIBinder`.
- sys::AIBinder_Weak_new(binder.as_native_mut())
- };
+ // Safety: `SpIBinder` guarantees that `binder` always contains a valid
+ // pointer to an `AIBinder`.
+ let ptr = unsafe { sys::AIBinder_Weak_new(binder.as_native_mut()) };
Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_new"))
}
/// Promote this weak reference to a strong reference to the binder object.
pub fn promote(&self) -> Option<SpIBinder> {
+ // Safety: `WpIBinder` always contains a valid weak reference, so we can
+ // pass this pointer to `AIBinder_Weak_promote`. Returns either null or
+ // an AIBinder owned by the caller, both of which are valid to pass to
+ // `SpIBinder::from_raw`.
unsafe {
- // Safety: `WpIBinder` always contains a valid weak reference, so we
- // can pass this pointer to `AIBinder_Weak_promote`. Returns either
- // null or an AIBinder owned by the caller, both of which are valid
- // to pass to `SpIBinder::from_raw`.
let ptr = sys::AIBinder_Weak_promote(self.0.as_ptr());
SpIBinder::from_raw(ptr)
}
@@ -509,35 +488,27 @@ impl WpIBinder {
impl Clone for WpIBinder {
fn clone(&self) -> Self {
- let ptr = unsafe {
- // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
- // so this pointer is always safe to pass to `AIBinder_Weak_clone`
- // (although null is also a safe value to pass to this API).
- //
- // We get ownership of the returned pointer, so can construct a new
- // WpIBinder object from it.
- sys::AIBinder_Weak_clone(self.0.as_ptr())
- };
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+ // this pointer is always safe to pass to `AIBinder_Weak_clone`
+ // (although null is also a safe value to pass to this API).
+ //
+ // We get ownership of the returned pointer, so can construct a new
+ // WpIBinder object from it.
+ let ptr = unsafe { sys::AIBinder_Weak_clone(self.0.as_ptr()) };
Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_clone"))
}
}
impl Ord for WpIBinder {
fn cmp(&self, other: &Self) -> Ordering {
- let less_than = unsafe {
- // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
- // so this pointer is always safe to pass to `AIBinder_Weak_lt`
- // (null is also safe to pass to this function, but we should never
- // do that).
- sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr())
- };
- let greater_than = unsafe {
- // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
- // so this pointer is always safe to pass to `AIBinder_Weak_lt`
- // (null is also safe to pass to this function, but we should never
- // do that).
- sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr())
- };
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+ // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ let less_than = unsafe { sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr()) };
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+ // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ let greater_than = unsafe { sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr()) };
if !less_than && !greater_than {
Ordering::Equal
} else if less_than {
@@ -564,9 +535,9 @@ impl Eq for WpIBinder {}
impl Drop for WpIBinder {
fn drop(&mut self) {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
+ // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
unsafe {
- // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
- // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
sys::AIBinder_Weak_delete(self.0.as_ptr());
}
}
@@ -574,7 +545,7 @@ impl Drop for WpIBinder {
/// Rust wrapper around DeathRecipient objects.
///
-/// The cookie in this struct represents an Arc<F> for the owned callback.
+/// The cookie in this struct represents an `Arc<F>` for the owned callback.
/// This struct owns a ref-count of it, and so does every binder that we
/// have been linked with.
///
@@ -592,17 +563,13 @@ struct DeathRecipientVtable {
cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
}
-/// # Safety
-///
-/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
-/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and
+/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As
/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
unsafe impl Send for DeathRecipient {}
-/// # Safety
-///
-/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
-/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and
+/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As
/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
unsafe impl Sync for DeathRecipient {}
@@ -614,19 +581,17 @@ impl DeathRecipient {
F: Fn() + Send + Sync + 'static,
{
let callback: *const F = Arc::into_raw(Arc::new(callback));
- let recipient = unsafe {
- // Safety: The function pointer is a valid death recipient callback.
- //
- // This call returns an owned `AIBinder_DeathRecipient` pointer
- // which must be destroyed via `AIBinder_DeathRecipient_delete` when
- // no longer needed.
- sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>))
- };
+ // Safety: The function pointer is a valid death recipient callback.
+ //
+ // This call returns an owned `AIBinder_DeathRecipient` pointer which
+ // must be destroyed via `AIBinder_DeathRecipient_delete` when no longer
+ // needed.
+ let recipient = unsafe { sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>)) };
+ // Safety: The function pointer is a valid onUnlinked callback.
+ //
+ // All uses of linkToDeath in this file correctly increment the
+ // ref-count that this onUnlinked callback will decrement.
unsafe {
- // Safety: The function pointer is a valid onUnlinked callback.
- //
- // All uses of linkToDeath in this file correctly increment the
- // ref-count that this onUnlinked callback will decrement.
sys::AIBinder_DeathRecipient_setOnUnlinked(
recipient,
Some(Self::cookie_decr_refcount::<F>),
@@ -648,7 +613,12 @@ impl DeathRecipient {
///
/// The caller must handle the returned ref-count correctly.
unsafe fn new_cookie(&self) -> *mut c_void {
- (self.vtable.cookie_incr_refcount)(self.cookie);
+ // Safety: `cookie_incr_refcount` points to
+ // `Self::cookie_incr_refcount`, and `self.cookie` is the cookie for an
+ // Arc<F>.
+ unsafe {
+ (self.vtable.cookie_incr_refcount)(self.cookie);
+ }
// Return a raw pointer with ownership of a ref-count
self.cookie
@@ -667,13 +637,14 @@ impl DeathRecipient {
///
/// # Safety
///
- /// The `cookie` parameter must be the cookie for an Arc<F> and
+ /// The `cookie` parameter must be the cookie for an `Arc<F>` and
/// the caller must hold a ref-count to it.
unsafe extern "C" fn binder_died<F>(cookie: *mut c_void)
where
F: Fn() + Send + Sync + 'static,
{
- let callback = (cookie as *const F).as_ref().unwrap();
+ // Safety: The caller promises that `cookie` is for an Arc<F>.
+ let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
callback();
}
@@ -682,34 +653,34 @@ impl DeathRecipient {
///
/// # Safety
///
- /// The `cookie` parameter must be the cookie for an Arc<F> and
+ /// The `cookie` parameter must be the cookie for an `Arc<F>` and
/// the owner must give up a ref-count to it.
unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
where
F: Fn() + Send + Sync + 'static,
{
- drop(Arc::from_raw(cookie as *const F));
+ // Safety: The caller promises that `cookie` is for an Arc<F>.
+ drop(unsafe { Arc::from_raw(cookie as *const F) });
}
/// Callback that increments the ref-count.
///
/// # Safety
///
- /// The `cookie` parameter must be the cookie for an Arc<F> and
+ /// The `cookie` parameter must be the cookie for an `Arc<F>` and
/// the owner must handle the created ref-count properly.
unsafe extern "C" fn cookie_incr_refcount<F>(cookie: *mut c_void)
where
F: Fn() + Send + Sync + 'static,
{
- let arc = mem::ManuallyDrop::new(Arc::from_raw(cookie as *const F));
+ // Safety: The caller promises that `cookie` is for an Arc<F>.
+ let arc = mem::ManuallyDrop::new(unsafe { Arc::from_raw(cookie as *const F) });
mem::forget(Arc::clone(&arc));
}
}
-/// # Safety
-///
-/// A `DeathRecipient` is always constructed with a valid raw pointer to an
-/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this
+/// Safety: A `DeathRecipient` is always constructed with a valid raw pointer to
+/// an `AIBinder_DeathRecipient`, so it is always type-safe to extract this
/// pointer.
unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient {
fn as_native(&self) -> *const sys::AIBinder_DeathRecipient {
@@ -723,18 +694,19 @@ unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient {
impl Drop for DeathRecipient {
fn drop(&mut self) {
+ // Safety: `self.recipient` is always a valid, owned
+ // `AIBinder_DeathRecipient` pointer returned by
+ // `AIBinder_DeathRecipient_new` when `self` was created. This delete
+ // method can only be called once when `self` is dropped.
unsafe {
- // Safety: `self.recipient` is always a valid, owned
- // `AIBinder_DeathRecipient` pointer returned by
- // `AIBinder_DeathRecipient_new` when `self` was created. This
- // delete method can only be called once when `self` is dropped.
sys::AIBinder_DeathRecipient_delete(self.recipient);
+ }
- // Safety: We own a ref-count to the cookie, and so does every
- // linked binder. This call gives up our ref-count. The linked
- // binders should already have given up their ref-count, or should
- // do so shortly.
- (self.vtable.cookie_decr_refcount)(self.cookie)
+ // Safety: We own a ref-count to the cookie, and so does every linked
+ // binder. This call gives up our ref-count. The linked binders should
+ // already have given up their ref-count, or should do so shortly.
+ unsafe {
+ (self.vtable.cookie_decr_refcount)(self.cookie);
}
}
}
@@ -754,11 +726,9 @@ pub trait Proxy: Sized + Interface {
fn from_binder(binder: SpIBinder) -> Result<Self>;
}
-/// # Safety
-///
-/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow
-/// invocation of `IBinder` methods directly from `Interface` objects. It shares
-/// the same safety as the implementation for `SpIBinder`.
+/// Safety: This is a convenience method that wraps `AsNative` for `SpIBinder`
+/// to allow invocation of `IBinder` methods directly from `Interface` objects.
+/// It shares the same safety as the implementation for `SpIBinder`.
unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T {
fn as_native(&self) -> *const sys::AIBinder {
self.as_binder().as_native()
@@ -773,24 +743,20 @@ unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T {
/// exist.
pub fn get_service(name: &str) -> Option<SpIBinder> {
let name = CString::new(name).ok()?;
- unsafe {
- // Safety: `AServiceManager_getService` returns either a null pointer or
- // a valid pointer to an owned `AIBinder`. Either of these values is
- // safe to pass to `SpIBinder::from_raw`.
- SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr()))
- }
+ // Safety: `AServiceManager_getService` returns either a null pointer or a
+ // valid pointer to an owned `AIBinder`. Either of these values is safe to
+ // pass to `SpIBinder::from_raw`.
+ unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) }
}
/// Retrieve an existing service, or start it if it is configured as a dynamic
/// service and isn't yet started.
pub fn wait_for_service(name: &str) -> Option<SpIBinder> {
let name = CString::new(name).ok()?;
- unsafe {
- // Safety: `AServiceManager_waitforService` returns either a null
- // pointer or a valid pointer to an owned `AIBinder`. Either of these
- // values is safe to pass to `SpIBinder::from_raw`.
- SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr()))
- }
+ // Safety: `AServiceManager_waitforService` returns either a null pointer or
+ // a valid pointer to an owned `AIBinder`. Either of these values is safe to
+ // pass to `SpIBinder::from_raw`.
+ unsafe { SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) }
}
/// Retrieve an existing service for a particular interface, blocking for a few
@@ -809,12 +775,10 @@ pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<
pub fn is_declared(interface: &str) -> Result<bool> {
let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
- unsafe {
- // Safety: `interface` is a valid null-terminated C-style string and is
- // only borrowed for the lifetime of the call. The `interface` local
- // outlives this call as it lives for the function scope.
- Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
- }
+ // Safety: `interface` is a valid null-terminated C-style string and is only
+ // borrowed for the lifetime of the call. The `interface` local outlives
+ // this call as it lives for the function scope.
+ unsafe { Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) }
}
/// Retrieve all declared instances for a particular interface
@@ -827,11 +791,13 @@ pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
// CString, and outlives this callback. The null handling here is just
// to avoid the possibility of unwinding across C code if this crate is
// ever compiled with panic=unwind.
- if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
+ if let Some(instances) = unsafe { opaque.cast::<Vec<CString>>().as_mut() } {
// Safety: instance is a valid null-terminated C string with a
// lifetime at least as long as this function, and we immediately
// copy it into an owned CString.
- instances.push(CStr::from_ptr(instance).to_owned());
+ unsafe {
+ instances.push(CStr::from_ptr(instance).to_owned());
+ }
} else {
eprintln!("Opaque pointer was null in get_declared_instances callback!");
}
@@ -839,10 +805,10 @@ pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
let mut instances: Vec<CString> = vec![];
+ // Safety: `interface` and `instances` are borrowed for the length of this
+ // call and both outlive the call. `interface` is guaranteed to be a valid
+ // null-terminated C-style string.
unsafe {
- // Safety: `interface` and `instances` are borrowed for the length of
- // this call and both outlive the call. `interface` is guaranteed to be
- // a valid null-terminated C-style string.
sys::AServiceManager_forEachDeclaredInstance(
interface.as_ptr(),
&mut instances as *mut _ as *mut c_void,
@@ -860,10 +826,8 @@ pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
})
}
-/// # Safety
-///
-/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
-/// `AIBinder`, so we can trivially extract this pointer here.
+/// Safety: `SpIBinder` guarantees that `binder` always contains a valid pointer
+/// to an `AIBinder`, so we can trivially extract this pointer here.
unsafe impl AsNative<sys::AIBinder> for SpIBinder {
fn as_native(&self) -> *const sys::AIBinder {
self.0.as_ptr()
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 4886c5fe86..a3a2562eb1 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -35,8 +35,8 @@ impl ProcessState {
/// not work: the callbacks will be queued but never called as there is no
/// thread to call them on.
pub fn start_thread_pool() {
+ // Safety: Safe FFI
unsafe {
- // Safety: Safe FFI
sys::ABinderProcess_startThreadPool();
}
}
@@ -48,8 +48,8 @@ impl ProcessState {
/// called, this is 15. If it is called additional times, the thread pool
/// size can only be increased.
pub fn set_thread_pool_max_thread_count(num_threads: u32) {
+ // Safety: Safe FFI
unsafe {
- // Safety: Safe FFI
sys::ABinderProcess_setThreadPoolMaxThreadCount(num_threads);
}
}
@@ -62,8 +62,8 @@ impl ProcessState {
/// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count)
/// and [`start_thread_pool`](Self::start_thread_pool).
pub fn join_thread_pool() {
+ // Safety: Safe FFI
unsafe {
- // Safety: Safe FFI
sys::ABinderProcess_joinThreadPool();
}
}
@@ -86,10 +86,8 @@ impl ThreadState {
/// \return calling uid or the current process's UID if this thread isn't
/// processing a transaction.
pub fn get_calling_uid() -> uid_t {
- unsafe {
- // Safety: Safe FFI
- sys::AIBinder_getCallingUid()
- }
+ // Safety: Safe FFI
+ unsafe { sys::AIBinder_getCallingUid() }
}
/// This returns the calling PID assuming that this thread is called from a
@@ -111,10 +109,8 @@ impl ThreadState {
/// If the transaction being processed is a oneway transaction, then this
/// method will return 0.
pub fn get_calling_pid() -> pid_t {
- unsafe {
- // Safety: Safe FFI
- sys::AIBinder_getCallingPid()
- }
+ // Safety: Safe FFI
+ unsafe { sys::AIBinder_getCallingPid() }
}
/// Determine whether the current thread is currently executing an incoming transaction.
@@ -122,10 +118,8 @@ impl ThreadState {
/// \return true if the current thread is currently executing an incoming transaction, and false
/// otherwise.
pub fn is_handling_transaction() -> bool {
- unsafe {
- // Safety: Safe FFI
- sys::AIBinder_isHandlingTransaction()
- }
+ // Safety: Safe FFI
+ unsafe { sys::AIBinder_isHandlingTransaction() }
}
/// This function makes the client's security context available to the
diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs
index 1d1a295221..c5c847b874 100644
--- a/libs/binder/rust/sys/lib.rs
+++ b/libs/binder/rust/sys/lib.rs
@@ -19,7 +19,20 @@
use std::error::Error;
use std::fmt;
-include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+#[cfg(not(target_os = "trusty"))]
+mod bindings {
+ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+}
+
+// Trusty puts the full path to the auto-generated file in BINDGEN_INC_FILE
+// and builds it with warnings-as-errors, so we need to use #[allow(bad_style)]
+#[cfg(target_os = "trusty")]
+#[allow(bad_style)]
+mod bindings {
+ include!(env!("BINDGEN_INC_FILE"));
+}
+
+pub use bindings::*;
impl Error for android_c_interface_StatusCode {}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index ca2cedc19d..c049b807df 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -545,6 +545,11 @@ mod tests {
}
fn get_expected_selinux_context() -> &'static str {
+ // SAFETY: The pointer we pass to `getcon` is valid because it comes from a reference, and
+ // `getcon` doesn't retain it after it returns. If `getcon` succeeds then `out_ptr` will
+ // point to a valid C string, otherwise it will remain null. We check for null, so the
+ // pointer we pass to `CStr::from_ptr` must be a valid pointer to a C string. There is a
+ // memory leak as we don't call `freecon`, but that's fine because this is just a test.
unsafe {
let mut out_ptr = ptr::null_mut();
assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 415ede1a7b..37f182eb08 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -28,10 +28,11 @@ use std::os::raw::{c_char, c_int};
///
/// # Safety
///
-/// service_name must be a valid, non-null C-style string (null-terminated).
+/// service_name must be a valid, non-null C-style string (nul-terminated).
#[no_mangle]
pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
- let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+ // SAFETY: Our caller promises that service_name is a valid C string.
+ let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap();
// The Rust class descriptor pointer will not match the NDK one, but the
// descriptor strings match so this needs to still associate.
@@ -85,10 +86,11 @@ impl IBinderRustNdkInteropTest for Service {
///
/// # Safety
///
-/// service_name must be a valid, non-null C-style string (null-terminated).
+/// service_name must be a valid, non-null C-style string (nul-terminated).
#[no_mangle]
pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
- let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+ // SAFETY: Our caller promises that service_name is a valid C string.
+ let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap();
let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
match binder::add_service(service_name, service.as_binder()) {
Ok(_) => StatusCode::OK as c_int,
diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
index ac968237a0..6eb707bcf7 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
@@ -3,19 +3,12 @@ package {
default_applicable_licenses: ["frameworks_native_license"],
}
-rust_fuzz {
- name: "parcel_fuzzer_rs",
- srcs: [
- "parcel_fuzzer.rs",
- ],
+rust_defaults {
+ name: "service_fuzzer_defaults_rs",
rustlibs: [
- "libarbitrary",
- "libnum_traits",
"libbinder_rs",
"libbinder_random_parcel_rs",
- "binderReadParcelIface-rust",
],
-
fuzz_config: {
cc: [
"waghpawan@google.com",
@@ -26,3 +19,18 @@ rust_fuzz {
hotlists: ["4637097"],
},
}
+
+rust_fuzz {
+ name: "parcel_fuzzer_rs",
+ srcs: [
+ "parcel_fuzzer.rs",
+ ],
+ defaults: [
+ "service_fuzzer_defaults_rs",
+ ],
+ rustlibs: [
+ "libarbitrary",
+ "libnum_traits",
+ "binderReadParcelIface-rust",
+ ],
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
index 29bf92cb97..ce0f742934 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -105,9 +105,9 @@ fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
for operation in read_operations {
match operation {
ReadOperation::SetDataPosition { pos } => {
+ // Safety: Safe if pos is less than current size of the parcel.
+ // It relies on C++ code for bound checks
unsafe {
- // Safety: Safe if pos is less than current size of the parcel.
- // It relies on C++ code for bound checks
match parcel.set_data_position(pos) {
Ok(result) => result,
Err(e) => println!("error occurred while setting data position: {:?}", e),
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
index 2537ce0bcb..84130c17e1 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
@@ -19,18 +19,10 @@ rust_fuzz {
srcs: [
"service_fuzzer.rs",
],
+ defaults: [
+ "service_fuzzer_defaults_rs",
+ ],
rustlibs: [
- "libbinder_rs",
- "libbinder_random_parcel_rs",
"testServiceInterface-rust",
],
- fuzz_config: {
- cc: [
- "waghpawan@google.com",
- "smoreland@google.com",
- ],
- triage_assignee: "waghpawan@google.com",
- // hotlist "AIDL fuzzers bugs" on buganizer
- hotlists: ["4637097"],
- },
}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
index 1bbd6742f2..896b78f488 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
@@ -35,10 +35,26 @@ pub fn create_random_parcel(fuzzer_data: &[u8]) -> Parcel {
/// This API automatically fuzzes provided service
pub fn fuzz_service(binder: &mut SpIBinder, fuzzer_data: &[u8]) {
- let ptr = binder.as_native_mut() as *mut c_void;
+ let mut binders = [binder];
+ fuzz_multiple_services(&mut binders, fuzzer_data);
+}
+
+/// This API automatically fuzzes provided services
+pub fn fuzz_multiple_services(binders: &mut [&mut SpIBinder], fuzzer_data: &[u8]) {
+ let mut cppBinders = vec![];
+ for binder in binders.iter_mut() {
+ let ptr = binder.as_native_mut() as *mut c_void;
+ cppBinders.push(ptr);
+ }
+
unsafe {
- // Safety: `SpIBinder::as_native_mut` and `slice::as_ptr` always
+ // Safety: `Vec::as_mut_ptr` and `slice::as_ptr` always
// return valid pointers.
- fuzzRustService(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+ fuzzRustService(
+ cppBinders.as_mut_ptr(),
+ cppBinders.len(),
+ fuzzer_data.as_ptr(),
+ fuzzer_data.len(),
+ );
}
}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
index 831bd5660c..cfdd2abd05 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
@@ -21,5 +21,5 @@ extern "C" {
void createRandomParcel(void* aParcel, const uint8_t* data, size_t len);
// This API is used by fuzzers to automatically fuzz aidl services
- void fuzzRustService(void* binder, const uint8_t* data, size_t len);
-} \ No newline at end of file
+ void fuzzRustService(void** binders, size_t numBinders, const uint8_t* data, size_t len);
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
index a2d48b6115..2c8d05facd 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
@@ -89,14 +89,17 @@ pub const READ_FUNCS: &[fn(&BorrowedParcel<'_>)] = &[
read_parcel_interface!(Option<Vec<u64>>),
read_parcel_interface!(Option<Vec<String>>),
read_parcel_interface!(ParcelFileDescriptor),
+ read_parcel_interface!(Vec<ParcelFileDescriptor>),
read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>),
read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>),
read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>),
read_parcel_interface!(SpIBinder),
+ read_parcel_interface!(Vec<SpIBinder>),
read_parcel_interface!(Vec<Option<SpIBinder>>),
read_parcel_interface!(Option<Vec<SpIBinder>>),
read_parcel_interface!(Option<Vec<Option<SpIBinder>>>),
read_parcel_interface!(SomeParcelable),
+ read_parcel_interface!(Vec<SomeParcelable>),
read_parcel_interface!(Vec<Option<SomeParcelable>>),
read_parcel_interface!(Option<Vec<SomeParcelable>>),
read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>),
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 6220db4b28..2b6c282530 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -26,7 +26,7 @@ use binder::{
use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode};
use std::ffi::{c_void, CStr, CString};
-use std::sync::Once;
+use std::sync::OnceLock;
#[allow(
non_camel_case_types,
@@ -70,20 +70,18 @@ macro_rules! assert {
};
}
-static SERVICE_ONCE: Once = Once::new();
-static mut SERVICE: Option<SpIBinder> = None;
+static SERVICE: OnceLock<SpIBinder> = OnceLock::new();
/// Start binder service and return a raw AIBinder pointer to it.
///
/// Safe to call multiple times, only creates the service once.
#[no_mangle]
pub extern "C" fn rust_service() -> *mut c_void {
- unsafe {
- SERVICE_ONCE.call_once(|| {
- SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder());
- });
- SERVICE.as_ref().unwrap().as_raw().cast()
- }
+ let service = SERVICE
+ .get_or_init(|| BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder());
+ // SAFETY: The SpIBinder will remain alive as long as the program is running because it is in
+ // the static SERVICE, so the pointer is valid forever.
+ unsafe { service.as_raw().cast() }
}
/// Empty interface just to use the declare_binder_interface macro
@@ -113,11 +111,13 @@ fn on_transact(
bindings::Transaction_TEST_BOOL => {
assert!(parcel.read::<bool>()?);
assert!(!parcel.read::<bool>()?);
+ // SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<bool>>()?, unsafe { bindings::TESTDATA_BOOL });
assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
reply.write(&true)?;
reply.write(&false)?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_BOOL }[..])?;
reply.write(&(None as Option<Vec<bool>>))?;
}
@@ -125,14 +125,18 @@ fn on_transact(
assert_eq!(parcel.read::<i8>()?, 0);
assert_eq!(parcel.read::<i8>()?, 1);
assert_eq!(parcel.read::<i8>()?, i8::max_value());
+ // SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i8>>()?, unsafe { bindings::TESTDATA_I8 });
+ // SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<u8>>()?, unsafe { bindings::TESTDATA_U8 });
assert_eq!(parcel.read::<Option<Vec<i8>>>()?, None);
reply.write(&0i8)?;
reply.write(&1i8)?;
reply.write(&i8::max_value())?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_U8 }[..])?;
reply.write(&(None as Option<Vec<i8>>))?;
}
@@ -140,12 +144,14 @@ fn on_transact(
assert_eq!(parcel.read::<u16>()?, 0);
assert_eq!(parcel.read::<u16>()?, 1);
assert_eq!(parcel.read::<u16>()?, u16::max_value());
+ // SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
reply.write(&0u16)?;
reply.write(&1u16)?;
reply.write(&u16::max_value())?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?;
reply.write(&(None as Option<Vec<u16>>))?;
}
@@ -153,12 +159,14 @@ fn on_transact(
assert_eq!(parcel.read::<i32>()?, 0);
assert_eq!(parcel.read::<i32>()?, 1);
assert_eq!(parcel.read::<i32>()?, i32::max_value());
+ // SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
reply.write(&0i32)?;
reply.write(&1i32)?;
reply.write(&i32::max_value())?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?;
reply.write(&(None as Option<Vec<i32>>))?;
}
@@ -166,12 +174,14 @@ fn on_transact(
assert_eq!(parcel.read::<i64>()?, 0);
assert_eq!(parcel.read::<i64>()?, 1);
assert_eq!(parcel.read::<i64>()?, i64::max_value());
+ // SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
reply.write(&0i64)?;
reply.write(&1i64)?;
reply.write(&i64::max_value())?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?;
reply.write(&(None as Option<Vec<i64>>))?;
}
@@ -179,12 +189,14 @@ fn on_transact(
assert_eq!(parcel.read::<u64>()?, 0);
assert_eq!(parcel.read::<u64>()?, 1);
assert_eq!(parcel.read::<u64>()?, u64::max_value());
+ // SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
reply.write(&0u64)?;
reply.write(&1u64)?;
reply.write(&u64::max_value())?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?;
reply.write(&(None as Option<Vec<u64>>))?;
}
@@ -192,10 +204,12 @@ fn on_transact(
assert_eq!(parcel.read::<f32>()?, 0f32);
let floats = parcel.read::<Vec<f32>>()?;
assert!(floats[0].is_nan());
+ // SAFETY: Just reading an extern constant.
assert_eq!(floats[1..], unsafe { bindings::TESTDATA_FLOAT }[1..]);
assert_eq!(parcel.read::<Option<Vec<f32>>>()?, None);
reply.write(&0f32)?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_FLOAT }[..])?;
reply.write(&(None as Option<Vec<f32>>))?;
}
@@ -203,10 +217,12 @@ fn on_transact(
assert_eq!(parcel.read::<f64>()?, 0f64);
let doubles = parcel.read::<Vec<f64>>()?;
assert!(doubles[0].is_nan());
+ // SAFETY: Just reading an extern constant.
assert_eq!(doubles[1..], unsafe { bindings::TESTDATA_DOUBLE }[1..]);
assert_eq!(parcel.read::<Option<Vec<f64>>>()?, None);
reply.write(&0f64)?;
+ // SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_DOUBLE }[..])?;
reply.write(&(None as Option<Vec<f64>>))?;
}
@@ -216,14 +232,17 @@ fn on_transact(
let s: Option<String> = parcel.read()?;
assert_eq!(s, None);
let s: Option<Vec<Option<String>>> = parcel.read()?;
+ // SAFETY: Just reading an extern constant.
for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) {
let expected =
+ // SAFETY: Just reading an extern constant.
unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) };
assert_eq!(s.as_deref(), expected);
}
let s: Option<Vec<Option<String>>> = parcel.read()?;
assert_eq!(s, None);
+ // SAFETY: Just reading an extern constant.
let strings: Vec<Option<String>> = unsafe {
bindings::TESTDATA_STRS
.iter()
@@ -258,8 +277,7 @@ fn on_transact(
assert!(ibinders[1].is_none());
assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
- let service =
- unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() };
+ let service = SERVICE.get().expect("Global binder service not initialized").clone();
reply.write(&service)?;
reply.write(&(None as Option<&SpIBinder>))?;
reply.write(&[Some(&service), None][..])?;
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 41856f9b79..cd3e7c0fef 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -77,6 +77,8 @@ cc_test {
static_libs: [
"binderRecordReplayTestIface-cpp",
"binderReadParcelIface-cpp",
+ "libbinder_random_parcel_seeds",
+ "libbinder_random_parcel",
],
test_suites: ["general-tests"],
require_root: true,
diff --git a/libs/binder/tests/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl
index 2baf68097a..100877847d 100644
--- a/libs/binder/tests/IBinderRpcBenchmark.aidl
+++ b/libs/binder/tests/IBinderRpcBenchmark.aidl
@@ -18,4 +18,7 @@ interface IBinderRpcBenchmark {
@utf8InCpp String repeatString(@utf8InCpp String str);
IBinder repeatBinder(IBinder binder);
byte[] repeatBytes(in byte[] bytes);
+
+ IBinder gimmeBinder();
+ void waitGimmesDestroyed();
}
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index bc40864020..6712c9cece 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -216,16 +216,16 @@ TEST(RpcBinderAllocation, SetupRpcServer) {
auto server = RpcServer::make();
server->setRootObject(sp<BBinder>::make());
- CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+ ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
std::thread([server]() { server->join(); }).detach();
- status_t status;
auto session = RpcSession::make();
- status = session->setupUnixDomainClient(addr.c_str());
- CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
+ status_t status = session->setupUnixDomainClient(addr.c_str());
+ ASSERT_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
auto remoteBinder = session->getRootObject();
+ ASSERT_NE(remoteBinder, nullptr);
size_t mallocs = 0, totalBytes = 0;
{
@@ -233,7 +233,7 @@ TEST(RpcBinderAllocation, SetupRpcServer) {
mallocs++;
totalBytes += bytes;
});
- CHECK_EQ(OK, remoteBinder->pingBinder());
+ ASSERT_EQ(OK, remoteBinder->pingBinder());
}
EXPECT_EQ(mallocs, 1);
EXPECT_EQ(totalBytes, 40);
diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp
index 17d5c8a219..6773c95ed6 100644
--- a/libs/binder/tests/binderRecordReplayTest.cpp
+++ b/libs/binder/tests/binderRecordReplayTest.cpp
@@ -15,6 +15,7 @@
*/
#include <BnBinderRecordReplayTest.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/Binder.h>
@@ -23,6 +24,11 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/RecordedTransaction.h>
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <fuzzseeds/random_parcel_seeds.h>
+
#include <gtest/gtest.h>
#include <sys/prctl.h>
@@ -30,6 +36,7 @@
#include "parcelables/SingleDataParcelable.h"
using namespace android;
+using android::generateSeedsFromRecording;
using android::binder::Status;
using android::binder::debug::RecordedTransaction;
using parcelables::SingleDataParcelable;
@@ -84,6 +91,44 @@ public:
GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>);
};
+std::vector<uint8_t> retrieveData(base::borrowed_fd fd) {
+ struct stat fdStat;
+ EXPECT_TRUE(fstat(fd.get(), &fdStat) != -1);
+ EXPECT_TRUE(fdStat.st_size != 0);
+
+ std::vector<uint8_t> buffer(fdStat.st_size);
+ auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size);
+ EXPECT_TRUE(readResult != 0);
+ return std::move(buffer);
+}
+
+void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
+ base::unique_fd seedFd(open("/data/local/tmp/replayFuzzService",
+ O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666));
+ ASSERT_TRUE(seedFd.ok());
+
+ // generate corpus from this transaction.
+ generateSeedsFromRecording(seedFd, transaction);
+
+ // Read the data which has been written to seed corpus
+ ASSERT_EQ(0, lseek(seedFd.get(), 0, SEEK_SET));
+ std::vector<uint8_t> seedData = retrieveData(seedFd);
+
+ // use fuzzService to replay the corpus
+ FuzzedDataProvider provider(seedData.data(), seedData.size());
+ fuzzService(binder, std::move(provider));
+}
+
+void replayBinder(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
+ // TODO: move logic to replay RecordedTransaction into RecordedTransaction
+ Parcel data;
+ data.setData(transaction.getDataParcel().data(), transaction.getDataParcel().dataSize());
+ auto result = binder->transact(transaction.getCode(), data, nullptr, transaction.getFlags());
+
+ // make sure recording does the thing we expect it to do
+ EXPECT_EQ(OK, result);
+}
+
class BinderRecordReplayTest : public ::testing::Test {
public:
void SetUp() override {
@@ -98,48 +143,46 @@ public:
template <typename T, typename U>
void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue,
Status (IBinderRecordReplayTest::*get)(U*), U changedValue) {
- base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec",
- O_RDWR | O_CREAT | O_CLOEXEC, 0666));
- ASSERT_TRUE(fd.ok());
-
- // record a transaction
- mBpBinder->startRecordingBinder(fd);
- auto status = (*mInterface.*set)(recordedValue);
- EXPECT_TRUE(status.isOk());
- mBpBinder->stopRecordingBinder();
-
- // test transaction does the thing we expect it to do
- U output;
- status = (*mInterface.*get)(&output);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(output, recordedValue);
-
- // write over the existing state
- status = (*mInterface.*set)(changedValue);
- EXPECT_TRUE(status.isOk());
-
- status = (*mInterface.*get)(&output);
- EXPECT_TRUE(status.isOk());
-
- EXPECT_EQ(output, changedValue);
-
- // replay transaction
- ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET));
- std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd);
- ASSERT_NE(transaction, std::nullopt);
-
- // TODO: move logic to replay RecordedTransaction into RecordedTransaction
- Parcel data;
- data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize());
- auto result =
- mBpBinder->transact(transaction->getCode(), data, nullptr, transaction->getFlags());
-
- // make sure recording does the thing we expect it to do
- EXPECT_EQ(OK, result);
-
- status = (*mInterface.*get)(&output);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(output, recordedValue);
+ auto replayFunctions = {&replayBinder, &replayFuzzService};
+ for (auto replayFunc : replayFunctions) {
+ base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec",
+ O_RDWR | O_CREAT | O_CLOEXEC, 0666));
+ ASSERT_TRUE(fd.ok());
+
+ // record a transaction
+ mBpBinder->startRecordingBinder(fd);
+ auto status = (*mInterface.*set)(recordedValue);
+ EXPECT_TRUE(status.isOk());
+ mBpBinder->stopRecordingBinder();
+
+ // test transaction does the thing we expect it to do
+ U output;
+ status = (*mInterface.*get)(&output);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(output, recordedValue);
+
+ // write over the existing state
+ status = (*mInterface.*set)(changedValue);
+ EXPECT_TRUE(status.isOk());
+
+ status = (*mInterface.*get)(&output);
+ EXPECT_TRUE(status.isOk());
+
+ EXPECT_EQ(output, changedValue);
+
+ // replay transaction
+ ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET));
+ std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd);
+ ASSERT_NE(transaction, std::nullopt);
+
+ const RecordedTransaction& recordedTransaction = *transaction;
+ // call replay function with recorded transaction
+ (*replayFunc)(mBpBinder, recordedTransaction);
+
+ status = (*mInterface.*get)(&output);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(output, recordedValue);
+ }
}
private:
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 9c96c4182d..4f10d7417f 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -74,6 +74,44 @@ class MyBinderRpcBenchmark : public BnBinderRpcBenchmark {
*out = bytes;
return Status::ok();
}
+
+ class CountedBinder : public BBinder {
+ public:
+ CountedBinder(const sp<MyBinderRpcBenchmark>& parent) : mParent(parent) {
+ std::lock_guard<std::mutex> l(mParent->mCountMutex);
+ mParent->mBinderCount++;
+ // std::cout << "Count + is now " << mParent->mBinderCount << std::endl;
+ }
+ ~CountedBinder() {
+ {
+ std::lock_guard<std::mutex> l(mParent->mCountMutex);
+ mParent->mBinderCount--;
+ // std::cout << "Count - is now " << mParent->mBinderCount << std::endl;
+
+ // skip notify
+ if (mParent->mBinderCount != 0) return;
+ }
+ mParent->mCountCv.notify_one();
+ }
+
+ private:
+ sp<MyBinderRpcBenchmark> mParent;
+ };
+
+ Status gimmeBinder(sp<IBinder>* out) override {
+ *out = sp<CountedBinder>::make(sp<MyBinderRpcBenchmark>::fromExisting(this));
+ return Status::ok();
+ }
+ Status waitGimmesDestroyed() override {
+ std::unique_lock<std::mutex> l(mCountMutex);
+ mCountCv.wait(l, [&] { return mBinderCount == 0; });
+ return Status::ok();
+ }
+
+ friend class CountedBinder;
+ std::mutex mCountMutex;
+ std::condition_variable mCountCv;
+ size_t mBinderCount;
};
enum Transport {
@@ -212,6 +250,38 @@ BENCHMARK(BM_throughputForTransportAndBytes)
->ArgsProduct({kTransportList,
{64, 1024, 2048, 4096, 8182, 16364, 32728, 65535, 65536, 65537}});
+void BM_collectProxies(benchmark::State& state) {
+ sp<IBinder> binder = getBinderForOptions(state);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ const size_t kNumIters = state.range(1);
+
+ while (state.KeepRunning()) {
+ std::vector<sp<IBinder>> out;
+ out.resize(kNumIters);
+
+ for (size_t i = 0; i < kNumIters; i++) {
+ Status ret = iface->gimmeBinder(&out[i]);
+ CHECK(ret.isOk()) << ret;
+ }
+
+ out.clear();
+
+ // we are using a thread up to wait, so make a call to
+ // force all refcounts to be updated first - current
+ // binder behavior means we really don't need to wait,
+ // so code which is waiting is really there to protect
+ // against any future changes that could delay destruction
+ android::IInterface::asBinder(iface)->pingBinder();
+
+ iface->waitGimmesDestroyed();
+ }
+
+ SetLabel(state);
+}
+BENCHMARK(BM_collectProxies)->ArgsProduct({kTransportList, {10, 100, 1000, 5000, 10000, 20000}});
+
void BM_repeatBinder(benchmark::State& state) {
sp<IBinder> binder = getBinderForOptions(state);
CHECK(binder != nullptr);
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index d352ce5bca..4c3c68e2e7 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -249,12 +249,12 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc(
CHECK_EQ(options.numIncomingConnectionsBySession.size(), options.numSessions);
}
- SocketType socketType = std::get<0>(GetParam());
- RpcSecurity rpcSecurity = std::get<1>(GetParam());
- uint32_t clientVersion = std::get<2>(GetParam());
- uint32_t serverVersion = std::get<3>(GetParam());
- bool singleThreaded = std::get<4>(GetParam());
- bool noKernel = std::get<5>(GetParam());
+ SocketType socketType = GetParam().type;
+ RpcSecurity rpcSecurity = GetParam().security;
+ uint32_t clientVersion = GetParam().clientVersion;
+ uint32_t serverVersion = GetParam().serverVersion;
+ bool singleThreaded = GetParam().singleThreaded;
+ bool noKernel = GetParam().noKernel;
std::string path = android::base::GetExecutableDirectory();
auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
@@ -674,7 +674,7 @@ TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) {
// session 0 - will check for leaks in destrutor of proc
// session 1 - we want to make sure it gets deleted when we drop all references to it
auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1, .numIncomingConnectionsBySession = {0, 1}, .numSessions = 2});
+ {.numThreads = 1, .numSessions = 2, .numIncomingConnectionsBySession = {0, 1}});
wp<RpcSession> session = proc.proc->sessions.at(1).session;
@@ -1121,12 +1121,27 @@ TEST_P(BinderRpc, Fds) {
}
#ifdef BINDER_RPC_TO_TRUSTY_TEST
-INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc,
- ::testing::Combine(::testing::Values(SocketType::TIPC),
- ::testing::Values(RpcSecurity::RAW),
- ::testing::ValuesIn(testVersions()),
- ::testing::ValuesIn(testVersions()),
- ::testing::Values(true), ::testing::Values(true)),
+
+static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() {
+ std::vector<BinderRpc::ParamType> ret;
+
+ for (const auto& clientVersion : testVersions()) {
+ for (const auto& serverVersion : testVersions()) {
+ ret.push_back(BinderRpc::ParamType{
+ .type = SocketType::TIPC,
+ .security = RpcSecurity::RAW,
+ .clientVersion = clientVersion,
+ .serverVersion = serverVersion,
+ .singleThreaded = true,
+ .noKernel = true,
+ });
+ }
+ }
+
+ return ret;
+}
+
+INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()),
BinderRpc::PrintParamInfo);
#else // BINDER_RPC_TO_TRUSTY_TEST
bool testSupportVsockLoopback() {
@@ -1246,13 +1261,47 @@ static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
return ret;
}
-INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
- ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
- ::testing::ValuesIn(RpcSecurityValues()),
- ::testing::ValuesIn(testVersions()),
- ::testing::ValuesIn(testVersions()),
- ::testing::Values(false, true),
- ::testing::Values(false, true)),
+static std::vector<BinderRpc::ParamType> getBinderRpcParams() {
+ std::vector<BinderRpc::ParamType> ret;
+
+ constexpr bool full = false;
+
+ for (const auto& type : testSocketTypes()) {
+ if (full || type == SocketType::UNIX) {
+ for (const auto& security : RpcSecurityValues()) {
+ for (const auto& clientVersion : testVersions()) {
+ for (const auto& serverVersion : testVersions()) {
+ for (bool singleThreaded : {false, true}) {
+ for (bool noKernel : {false, true}) {
+ ret.push_back(BinderRpc::ParamType{
+ .type = type,
+ .security = security,
+ .clientVersion = clientVersion,
+ .serverVersion = serverVersion,
+ .singleThreaded = singleThreaded,
+ .noKernel = noKernel,
+ });
+ }
+ }
+ }
+ }
+ }
+ } else {
+ ret.push_back(BinderRpc::ParamType{
+ .type = type,
+ .security = RpcSecurity::RAW,
+ .clientVersion = RPC_WIRE_PROTOCOL_VERSION,
+ .serverVersion = RPC_WIRE_PROTOCOL_VERSION,
+ .singleThreaded = false,
+ .noKernel = false,
+ });
+ }
+ }
+
+ return ret;
+}
+
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()),
BinderRpc::PrintParamInfo);
class BinderRpcServerRootObject
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 0b8920b5a6..2c9646b30e 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -106,15 +106,23 @@ struct BinderRpcTestProcessSession {
}
};
-class BinderRpc : public ::testing::TestWithParam<
- std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
+struct BinderRpcParam {
+ SocketType type;
+ RpcSecurity security;
+ uint32_t clientVersion;
+ uint32_t serverVersion;
+ bool singleThreaded;
+ bool noKernel;
+};
+class BinderRpc : public ::testing::TestWithParam<BinderRpcParam> {
public:
- SocketType socketType() const { return std::get<0>(GetParam()); }
- RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
- uint32_t clientVersion() const { return std::get<2>(GetParam()); }
- uint32_t serverVersion() const { return std::get<3>(GetParam()); }
- bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
- bool noKernel() const { return std::get<5>(GetParam()); }
+ // TODO: avoid unnecessary layer of indirection
+ SocketType socketType() const { return GetParam().type; }
+ RpcSecurity rpcSecurity() const { return GetParam().security; }
+ uint32_t clientVersion() const { return GetParam().clientVersion; }
+ uint32_t serverVersion() const { return GetParam().serverVersion; }
+ bool serverSingleThreaded() const { return GetParam().singleThreaded; }
+ bool noKernel() const { return GetParam().noKernel; }
bool clientOrServerSingleThreaded() const {
return !kEnableRpcThreads || serverSingleThreaded();
@@ -148,15 +156,16 @@ public:
}
static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
- auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
- std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
- if (singleThreaded) {
+ auto ret = PrintToString(info.param.type) + "_" +
+ newFactory(info.param.security)->toCString() + "_clientV" +
+ std::to_string(info.param.clientVersion) + "_serverV" +
+ std::to_string(info.param.serverVersion);
+ if (info.param.singleThreaded) {
ret += "_single_threaded";
} else {
ret += "_multi_threaded";
}
- if (noKernel) {
+ if (info.param.noKernel) {
ret += "_no_kernel";
} else {
ret += "_with_kernel";
diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp
index 28be10db76..fcb83bdabd 100644
--- a/libs/binder/tests/binderRpcTestTrusty.cpp
+++ b/libs/binder/tests/binderRpcTestTrusty.cpp
@@ -57,9 +57,9 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc(
[](size_t n) { return n != 0; }),
"Non-zero incoming connections on Trusty");
- RpcSecurity rpcSecurity = std::get<1>(GetParam());
- uint32_t clientVersion = std::get<2>(GetParam());
- uint32_t serverVersion = std::get<3>(GetParam());
+ RpcSecurity rpcSecurity = GetParam().security;
+ uint32_t clientVersion = GetParam().clientVersion;
+ uint32_t serverVersion = GetParam().serverVersion;
auto ret = std::make_unique<TrustyProcessSession>();
@@ -89,12 +89,27 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc(
return ret;
}
-INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc,
- ::testing::Combine(::testing::Values(SocketType::TIPC),
- ::testing::Values(RpcSecurity::RAW),
- ::testing::ValuesIn(testVersions()),
- ::testing::ValuesIn(testVersions()),
- ::testing::Values(false), ::testing::Values(true)),
+static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() {
+ std::vector<BinderRpc::ParamType> ret;
+
+ for (const auto& clientVersion : testVersions()) {
+ for (const auto& serverVersion : testVersions()) {
+ ret.push_back(BinderRpc::ParamType{
+ .type = SocketType::TIPC,
+ .security = RpcSecurity::RAW,
+ .clientVersion = clientVersion,
+ .serverVersion = serverVersion,
+ // TODO: should we test both versions here?
+ .singleThreaded = false,
+ .noKernel = true,
+ });
+ }
+ }
+
+ return ret;
+}
+
+INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()),
BinderRpc::PrintParamInfo);
} // namespace android
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index 1f4601010c..e43508ee79 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -84,7 +84,7 @@ TEST_P(BinderRpc, SeparateRootObject) {
GTEST_SKIP() << "This test requires a multi-threaded service";
}
- SocketType type = std::get<0>(GetParam());
+ SocketType type = GetParam().type;
if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) {
// we can't get port numbers for unix sockets
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 35866adf20..383795eff5 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -104,3 +104,43 @@ cc_library_static {
local_include_dirs: ["include_random_parcel"],
export_include_dirs: ["include_random_parcel"],
}
+
+cc_library {
+ name: "libbinder_random_parcel_seeds",
+ host_supported: true,
+ vendor_available: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "random_parcel_seeds.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libbinder_ndk",
+ "libcutils",
+ "libutils",
+ ],
+ local_include_dirs: [
+ "include_random_parcel_seeds",
+ ],
+ export_include_dirs: ["include_random_parcel_seeds"],
+}
+
+cc_binary_host {
+ name: "binder2corpus",
+ static_libs: [
+ "libbinder_random_parcel_seeds",
+ ],
+ srcs: [
+ "binder2corpus/binder2corpus.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libutils",
+ ],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md
new file mode 100644
index 0000000000..59bf9f31c0
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md
@@ -0,0 +1,31 @@
+# binder2corpus
+
+This tool converts recordings generated by record_binder tool to fuzzer seeds for fuzzService.
+
+# Steps to add corpus:
+
+## Start recording the service binder
+ex. record_binder start manager
+
+## Run test on device or keep device idle
+ex. atest servicemanager_test
+
+## Stop the recording
+record_binder stop manager
+
+## Pull the recording on host
+Recordings are present on device at /data/local/recordings/<service_name>. Use adb pull.
+Use inspect command of record_binder to check if there are some transactions captured.
+ex. record_binder inspect manager
+
+## run corpus generator tool
+binder2corpus <recording_path> <dir_to_write_corpus>
+
+## Build fuzzer and sync data directory
+ex. m servicemanager_fuzzer && adb sync data
+
+## Push corpus on device
+ex. adb push servicemanager_fuzzer_corpus/ /data/fuzz/x86_64/servicemanager_fuzzer/
+
+## Run fuzzer with corpus directory as argument
+ex. adb shell /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer_corpus \ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp
new file mode 100644
index 0000000000..c0fdaea0a8
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/RecordedTransaction.h>
+
+#include <fuzzseeds/random_parcel_seeds.h>
+
+#include <sys/prctl.h>
+
+using android::generateSeedsFromRecording;
+using android::status_t;
+using android::base::unique_fd;
+using android::binder::debug::RecordedTransaction;
+
+status_t generateCorpus(const char* recordingPath, const char* corpusDir) {
+ unique_fd fd(open(recordingPath, O_RDONLY));
+ if (!fd.ok()) {
+ std::cerr << "Failed to open recording file at path " << recordingPath
+ << " with error: " << strerror(errno) << '\n';
+ return android::BAD_VALUE;
+ }
+
+ if (auto res = mkdir(corpusDir, 0766); res != 0) {
+ std::cerr
+ << "Failed to create corpus directory at path. Delete directory if already exists: "
+ << corpusDir << std::endl;
+ return android::BAD_VALUE;
+ }
+
+ int transactionNumber = 0;
+ while (auto transaction = RecordedTransaction::fromFile(fd)) {
+ ++transactionNumber;
+ std::string filePath = std::string(corpusDir) + std::string("transaction_") +
+ std::to_string(transactionNumber);
+ constexpr int openFlags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC;
+ android::base::unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666));
+ if (!corpusFd.ok()) {
+ std::cerr << "Failed to open fd. Path " << filePath
+ << " with error: " << strerror(errno) << std::endl;
+ return android::UNKNOWN_ERROR;
+ }
+ generateSeedsFromRecording(corpusFd, transaction.value());
+ }
+
+ if (transactionNumber == 0) {
+ std::cerr << "No valid transaction has been found in recording file: " << recordingPath
+ << std::endl;
+ return android::BAD_VALUE;
+ }
+
+ return android::NO_ERROR;
+}
+
+void printHelp(const char* toolName) {
+ std::cout << "Usage: \n\n"
+ << toolName
+ << " <recording_path> <destination_directory> \n\n*Use "
+ "record_binder tool for recording binder transactions."
+ << std::endl;
+}
+
+int main(int argc, char** argv) {
+ if (argc != 3) {
+ printHelp(argv[0]);
+ return 1;
+ }
+ const char* sourcePath = argv[1];
+ const char* corpusDir = argv[2];
+ if (android::NO_ERROR != generateCorpus(sourcePath, corpusDir)) {
+ std::cerr << "Failed to generate fuzzer corpus." << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
new file mode 100644
index 0000000000..5755239c8b
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/hex.h>
+#include <android-base/logging.h>
+
+#include <binder/Binder.h>
+#include <binder/Parcel.h>
+#include <binder/RecordedTransaction.h>
+
+#include <private/android_filesystem_config.h>
+
+#include <vector>
+
+using android::Parcel;
+using android::base::HexString;
+using std::vector;
+
+namespace android {
+namespace impl {
+// computes the bytes so that if they are passed to FuzzedDataProvider and
+// provider.ConsumeIntegralInRange<T>(min, max) is called, it will return val
+template <typename T>
+void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T min, T max, T val);
+
+// Calls writeInBuffer method with min and max numeric limits of type T. This method
+// is reversal of ConsumeIntegral<T>() in FuzzedDataProvider
+template <typename T>
+void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T val);
+} // namespace impl
+void generateSeedsFromRecording(base::borrowed_fd fd,
+ const binder::debug::RecordedTransaction& transaction);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 45c3a90044..38e6f32cb9 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -21,6 +21,8 @@
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
@@ -33,6 +35,11 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p
.extraFds = {},
};
+ // Reserved bytes so that we don't have to change fuzzers and seed corpus if
+ // we introduce anything new in fuzzService.
+ std::vector<uint8_t> reservedBytes = provider.ConsumeBytes<uint8_t>(8);
+ (void)reservedBytes;
+
// always refresh the calling identity, because we sometimes set it below, but also,
// the code we're fuzzing might reset it
IPCThreadState::self()->clearCallingIdentity();
@@ -40,7 +47,12 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p
// Always take so that a perturbation of just the one ConsumeBool byte will always
// take the same path, but with a different UID. Without this, the fuzzer needs to
// guess both the change in value and the shift at the same time.
- int64_t maybeSetUid = provider.ConsumeIntegral<int64_t>();
+ int64_t maybeSetUid = provider.PickValueInArray<int64_t>(
+ {static_cast<int64_t>(AID_ROOT) << 32, static_cast<int64_t>(AID_SYSTEM) << 32,
+ provider.ConsumeIntegralInRange<int64_t>(static_cast<int64_t>(AID_ROOT) << 32,
+ static_cast<int64_t>(AID_USER) << 32),
+ provider.ConsumeIntegral<int64_t>()});
+
if (provider.ConsumeBool()) {
// set calling uid
IPCThreadState::self()->restoreCallingIdentity(maybeSetUid);
@@ -48,8 +60,15 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p
while (provider.remaining_bytes() > 0) {
// Most of the AIDL services will have small set of transaction codes.
+ // TODO(b/295942369) : Add remaining transact codes from IBinder.h
uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral<uint32_t>()
- : provider.ConsumeIntegralInRange<uint32_t>(0, 100);
+ : provider.ConsumeBool()
+ ? provider.ConsumeIntegralInRange<uint32_t>(0, 100)
+ : provider.PickValueInArray<uint32_t>(
+ {IBinder::DUMP_TRANSACTION, IBinder::PING_TRANSACTION,
+ IBinder::SHELL_COMMAND_TRANSACTION, IBinder::INTERFACE_TRANSACTION,
+ IBinder::SYSPROPS_TRANSACTION, IBinder::EXTENSION_TRANSACTION,
+ IBinder::TWEET_TRANSACTION, IBinder::LIKE_TRANSACTION});
uint32_t flags = provider.ConsumeIntegral<uint32_t>();
Parcel data;
// for increased fuzz coverage
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
index 0b0ca34586..84b9ff684f 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -22,6 +22,9 @@
// and APEX users, but we need access to it to fuzz.
#include "../../ndk/ibinder_internal.h"
+using android::IBinder;
+using android::sp;
+
namespace android {
void fuzzService(const std::vector<ndk::SpAIBinder>& binders, FuzzedDataProvider&& provider) {
@@ -41,9 +44,14 @@ void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) {
extern "C" {
// This API is used by fuzzers to automatically fuzz aidl services
-void fuzzRustService(void* binder, const uint8_t* data, size_t len) {
- AIBinder* aiBinder = static_cast<AIBinder*>(binder);
+void fuzzRustService(void** binders, size_t numBinders, const uint8_t* data, size_t len) {
+ std::vector<sp<IBinder>> cppBinders;
+ for (size_t binderIndex = 0; binderIndex < numBinders; ++binderIndex) {
+ AIBinder* aiBinder = static_cast<AIBinder*>(binders[binderIndex]);
+ cppBinders.push_back(aiBinder->getBinder());
+ }
+
FuzzedDataProvider provider(data, len);
- android::fuzzService(aiBinder, std::move(provider));
+ android::fuzzService(cppBinders, std::move(provider));
}
} // extern "C"
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index e4dbb2d955..7390d497c4 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -29,40 +29,65 @@ std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) {
const char* fdType;
std::vector<unique_fd> fds = provider->PickValueInArray<
- std::function<std::vector<unique_fd>()>>({
- [&]() {
- fdType = "ashmem";
- std::vector<unique_fd> ret;
- ret.push_back(unique_fd(
- ashmem_create_region("binder test region",
- provider->ConsumeIntegralInRange<size_t>(0, 4096))));
- return ret;
- },
- [&]() {
- fdType = "/dev/null";
- std::vector<unique_fd> ret;
- ret.push_back(unique_fd(open("/dev/null", O_RDWR)));
- return ret;
- },
- [&]() {
- fdType = "pipefd";
-
- int pipefds[2];
-
- int flags = O_CLOEXEC;
- if (provider->ConsumeBool()) flags |= O_DIRECT;
- if (provider->ConsumeBool()) flags |= O_NONBLOCK;
-
- CHECK_EQ(0, pipe2(pipefds, flags)) << flags;
-
- if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]);
-
- std::vector<unique_fd> ret;
- ret.push_back(unique_fd(pipefds[0]));
- ret.push_back(unique_fd(pipefds[1]));
- return ret;
- },
- })();
+ std::function<std::vector<unique_fd>()>>(
+ {[&]() {
+ fdType = "ashmem";
+ std::vector<unique_fd> ret;
+ ret.push_back(unique_fd(
+ ashmem_create_region("binder test region",
+ provider->ConsumeIntegralInRange<size_t>(0, 4096))));
+ return ret;
+ },
+ [&]() {
+ fdType = "/dev/null";
+ std::vector<unique_fd> ret;
+ ret.push_back(unique_fd(open("/dev/null", O_RDWR)));
+ return ret;
+ },
+ [&]() {
+ fdType = "pipefd";
+
+ int pipefds[2];
+
+ int flags = O_CLOEXEC;
+ if (provider->ConsumeBool()) flags |= O_DIRECT;
+ if (provider->ConsumeBool()) flags |= O_NONBLOCK;
+
+ CHECK_EQ(0, pipe2(pipefds, flags)) << flags;
+
+ if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]);
+
+ std::vector<unique_fd> ret;
+ ret.push_back(unique_fd(pipefds[0]));
+ ret.push_back(unique_fd(pipefds[1]));
+ return ret;
+ },
+ [&]() {
+ fdType = "tempfd";
+ char name[PATH_MAX];
+#if defined(__ANDROID__)
+ snprintf(name, sizeof(name), "/data/local/tmp/android-tempfd-test-%d-XXXXXX",
+ getpid());
+#else
+ snprintf(name, sizeof(name), "/tmp/android-tempfd-test-%d-XXXXXX", getpid());
+#endif
+ int fd = mkstemp(name);
+ CHECK_NE(fd, -1) << "Failed to create file " << name << ", errno: " << errno;
+ unlink(name);
+ if (provider->ConsumeBool()) {
+ CHECK_NE(TEMP_FAILURE_RETRY(
+ ftruncate(fd,
+ provider->ConsumeIntegralInRange<size_t>(0, 4096))),
+ -1)
+ << "Failed to truncate file, errno: " << errno;
+ }
+
+ std::vector<unique_fd> ret;
+ ret.push_back(unique_fd(fd));
+ return ret;
+ }
+
+ })();
for (const auto& fd : fds) CHECK(fd.ok()) << fd.get() << " " << fdType;
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
new file mode 100644
index 0000000000..9e3e2aba77
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+
+#include <binder/RecordedTransaction.h>
+
+#include <fuzzseeds/random_parcel_seeds.h>
+
+using android::base::WriteFully;
+
+namespace android {
+namespace impl {
+template <typename T>
+std::vector<uint8_t> reverseBytes(T min, T max, T val) {
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = val - min;
+ size_t offset = 0;
+
+ std::vector<uint8_t> reverseData;
+ uint8_t reversed = 0;
+ reversed |= result;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0) {
+ reverseData.push_back(reversed);
+ reversed = 0;
+ reversed |= (result >> CHAR_BIT);
+ result = result >> CHAR_BIT;
+ offset += CHAR_BIT;
+ }
+
+ return std::move(reverseData);
+}
+
+template <typename T>
+void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T min, T max, T val) {
+ std::vector<uint8_t> reversedData = reverseBytes(min, max, val);
+ // ConsumeIntegral Calls read buffer from the end. Keep inserting at the front of the buffer
+ // so that we can align fuzzService operations with seed generation for readability.
+ integralBuffer.insert(integralBuffer.begin(), reversedData.begin(), reversedData.end());
+}
+
+template <typename T>
+void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) {
+ // For ConsumeIntegral<T>() calls, FuzzedDataProvider uses numeric limits min and max
+ // as range
+ writeReversedBuffer(integralBuffer, std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max(), val);
+}
+
+} // namespace impl
+
+void generateSeedsFromRecording(base::borrowed_fd fd,
+ const binder::debug::RecordedTransaction& transaction) {
+ // Write Reserved bytes for future use
+ std::vector<uint8_t> reservedBytes(8);
+ CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get();
+
+ std::vector<uint8_t> integralBuffer;
+
+ // Write UID array : Array elements are initialized in the order that they are declared
+ // UID array index 2 element
+ // int64_t aidRoot = 0;
+ impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32,
+ static_cast<int64_t>(AID_USER) << 32,
+ static_cast<int64_t>(AID_ROOT) << 32);
+
+ // UID array index 3 element
+ impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32);
+
+ // always pick AID_ROOT -> index 0
+ size_t uidIndex = 0;
+ impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(3),
+ uidIndex);
+
+ // Never set uid in seed corpus
+ uint8_t writeUid = 0;
+ impl::writeReversedBuffer(integralBuffer, writeUid);
+
+ // Read random code. this will be from recorded transaction
+ uint8_t selectCode = 1;
+ impl::writeReversedBuffer(integralBuffer, selectCode);
+
+ // Get from recorded transaction
+ uint32_t code = transaction.getCode();
+ impl::writeReversedBuffer(integralBuffer, code);
+
+ // Get from recorded transaction
+ uint32_t flags = transaction.getFlags();
+ impl::writeReversedBuffer(integralBuffer, flags);
+
+ // always fuzz primary binder
+ size_t extraBindersIndex = 0;
+ impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(0),
+ extraBindersIndex);
+
+ const Parcel& dataParcel = transaction.getDataParcel();
+
+ // This buffer holds the bytes which will be used for fillRandomParcel API
+ std::vector<uint8_t> fillParcelBuffer;
+
+ // Don't take rpc path
+ uint8_t rpcBranch = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, rpcBranch);
+
+ // Implicit branch on this path -> options->writeHeader(p, provider)
+ uint8_t writeHeaderInternal = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, writeHeaderInternal);
+
+ // Choose to write data in parcel
+ size_t fillFuncIndex = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
+ fillFuncIndex);
+
+ // Write parcel data size from recorded transaction
+ size_t toWrite = transaction.getDataParcel().dataBufferSize();
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), toWrite, toWrite);
+
+ // Write parcel data with size towrite from recorded transaction
+ CHECK(WriteFully(fd, dataParcel.data(), toWrite)) << fd.get();
+
+ // Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data
+ size_t subDataSize = toWrite + fillParcelBuffer.size();
+ impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), subDataSize, subDataSize);
+
+ // Write fill parcel buffer
+ CHECK(WriteFully(fd, fillParcelBuffer.data(), fillParcelBuffer.size())) << fd.get();
+
+ // Write the integralBuffer to data
+ CHECK(WriteFully(fd, integralBuffer.data(), integralBuffer.size())) << fd.get();
+}
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
index 7fbf2d0670..d2fa581822 100644
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
@@ -20,6 +20,8 @@
#include <binder/IPCThreadState.h>
#include <log/log.h>
+#include <private/android_filesystem_config.h>
+
using android::binder::Status;
namespace android {
@@ -29,6 +31,11 @@ enum class CrashType {
ON_PLAIN,
ON_BINDER,
ON_KNOWN_UID,
+ ON_SYSTEM_AID,
+ ON_ROOT_AID,
+ ON_DUMP_TRANSACT,
+ ON_SHELL_CMD_TRANSACT,
+ CRASH_ALWAYS,
};
// This service is to verify that fuzzService is functioning properly
@@ -48,6 +55,18 @@ public:
}
break;
}
+ case CrashType::ON_SYSTEM_AID: {
+ if (IPCThreadState::self()->getCallingUid() == AID_SYSTEM) {
+ LOG_ALWAYS_FATAL("Expected crash, AID_SYSTEM.");
+ }
+ break;
+ }
+ case CrashType::ON_ROOT_AID: {
+ if (IPCThreadState::self()->getCallingUid() == AID_ROOT) {
+ LOG_ALWAYS_FATAL("Expected crash, AID_ROOT.");
+ }
+ break;
+ }
default:
break;
}
@@ -76,6 +95,16 @@ public:
return Status::ok();
}
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override {
+ if (mCrash == CrashType::ON_DUMP_TRANSACT && code == DUMP_TRANSACTION) {
+ LOG_ALWAYS_FATAL("Expected crash, DUMP.");
+ } else if (mCrash == CrashType::ON_SHELL_CMD_TRANSACT &&
+ code == SHELL_COMMAND_TRANSACTION) {
+ LOG_ALWAYS_FATAL("Expected crash, SHELL_CMD.");
+ }
+ return BnTestService::onTransact(code, data, reply, flags);
+ }
+
private:
CrashType mCrash;
};
@@ -84,8 +113,10 @@ CrashType gCrashType = CrashType::NONE;
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
if (*argc < 2) {
- printf("You must specify at least one argument\n");
- exit(0); // success because this is a crash test
+ // This fuzzer is also used as test fuzzer to check infra pipeline.
+ // It should always run and find a crash in TestService.
+ gCrashType = CrashType::CRASH_ALWAYS;
+ return 0;
}
std::string arg = std::string((*argv)[1]);
@@ -99,8 +130,16 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
gCrashType = CrashType::ON_PLAIN;
} else if (arg == "KNOWN_UID") {
gCrashType = CrashType::ON_KNOWN_UID;
+ } else if (arg == "AID_SYSTEM") {
+ gCrashType = CrashType::ON_SYSTEM_AID;
+ } else if (arg == "AID_ROOT") {
+ gCrashType = CrashType::ON_ROOT_AID;
} else if (arg == "BINDER") {
gCrashType = CrashType::ON_BINDER;
+ } else if (arg == "DUMP") {
+ gCrashType = CrashType::ON_DUMP_TRANSACT;
+ } else if (arg == "SHELL_CMD") {
+ gCrashType = CrashType::ON_SHELL_CMD_TRANSACT;
} else {
printf("INVALID ARG\n");
exit(0); // success because this is a crash test
@@ -110,6 +149,9 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (gCrashType == CrashType::CRASH_ALWAYS) {
+ LOG_ALWAYS_FATAL("Expected crash, This fuzzer will always crash.");
+ }
auto service = sp<TestService>::make(gCrashType);
fuzzService(service, FuzzedDataProvider(data, size));
return 0;
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
index e568035af1..5d68fe172e 100755
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
@@ -27,10 +27,10 @@ then
exit 1
fi
-for CRASH_TYPE in PLAIN KNOWN_UID BINDER; do
+for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER DUMP SHELL_CMD; do
echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE"
- ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT"
+ ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=60 &>"$FUZZER_OUT"
echo "INFO: Searching fuzzer output for expected crashes"
if grep -q "Expected crash, $CRASH_TYPE." "$FUZZER_OUT"
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index b8ae84d5c0..dcc8b8ebf7 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -135,7 +135,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// b/260736889 - limit arbitrarily, due to thread resource exhaustion, which currently
// aborts. Servers should consider RpcServer::setConnectionFilter instead.
- constexpr size_t kMaxConnections = 1000;
+ constexpr size_t kMaxConnections = 10;
while (provider.remaining_bytes() > 0) {
if (connections.empty() ||
diff --git a/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp b/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp
index 09cb2162f7..b80ac53ba2 100644
--- a/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp
@@ -16,6 +16,7 @@
#include <commonFuzzHelpers.h>
#include <fuzzer/FuzzedDataProvider.h>
+#include <functional>
#include <string>
#include <vector>
#include "BufferedTextOutput.h"
diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp
index 943fb9f285..33a653eb33 100644
--- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp
@@ -54,7 +54,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (transaction.has_value()) {
std::FILE* intermediateFile = std::tmpfile();
- android::base::unique_fd fdForWriting(fileno(intermediateFile));
+ android::base::unique_fd fdForWriting(dup(fileno(intermediateFile)));
auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting);
std::fclose(intermediateFile);
diff --git a/libs/binder/trusty/fuzzer/Android.bp b/libs/binder/trusty/fuzzer/Android.bp
new file mode 100644
index 0000000000..2f1f54b0a6
--- /dev/null
+++ b/libs/binder/trusty/fuzzer/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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_fuzz {
+ name: "trusty_binder_fuzzer",
+ defaults: ["trusty_fuzzer_defaults"],
+ srcs: [":trusty_tipc_fuzzer"],
+ cflags: [
+ "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"",
+ "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"",
+ "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"",
+ ],
+}
+
+cc_fuzz {
+ name: "trusty_binder_rpc_fuzzer",
+ defaults: ["trusty_fuzzer_defaults"],
+ srcs: [":trusty_tipc_fuzzer"],
+ cflags: [
+ "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"",
+ "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"",
+ "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"",
+ ],
+}
diff --git a/libs/binder/trusty/rust/binder_ndk_sys/rules.mk b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk
new file mode 100644
index 0000000000..672d9b75ec
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../..
+LIBBINDER_NDK_BINDGEN_FLAG_FILE := \
+ $(LIBBINDER_DIR)/rust/libbinder_ndk_bindgen_flags.txt
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LIBBINDER_DIR)/rust/sys/lib.rs
+
+MODULE_CRATE_NAME := binder_ndk_sys
+
+MODULE_LIBRARY_DEPS += \
+ $(LIBBINDER_DIR)/trusty \
+ $(LIBBINDER_DIR)/trusty/ndk \
+ trusty/user/base/lib/trusty-sys \
+
+MODULE_BINDGEN_SRC_HEADER := $(LIBBINDER_DIR)/rust/sys/BinderBindings.hpp
+
+# Add the flags from the flag file
+MODULE_BINDGEN_FLAGS += $(shell cat $(LIBBINDER_NDK_BINDGEN_FLAG_FILE))
+MODULE_SRCDEPS += $(LIBBINDER_NDK_BINDGEN_FLAG_FILE)
+
+include make/library.mk
diff --git a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp
index f835997187..9df5632e97 100644
--- a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp
+++ b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp
@@ -20,6 +20,7 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <android-base/unique_fd.h>
#include <cputimeinstate.h>
+#include <functional>
using namespace android::bpf;
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
index 96dcce11ea..38233934c8 100644
--- a/libs/fakeservicemanager/Android.bp
+++ b/libs/fakeservicemanager/Android.bp
@@ -17,6 +17,7 @@ cc_defaults {
shared_libs: [
"libbinder",
"libutils",
+ "liblog",
],
target: {
darwin: {
@@ -40,3 +41,41 @@ cc_test_host {
static_libs: ["libgmock"],
local_include_dirs: ["include"],
}
+
+rust_bindgen {
+ name: "libfakeservicemanager_bindgen",
+ crate_name: "fakeservicemanager_bindgen",
+ host_supported: true,
+ wrapper_src: "rust/wrappers/FakeServiceManagerWrapper.hpp",
+ source_stem: "bindings",
+ visibility: [":__subpackages__"],
+ bindgen_flags: [
+ "--allowlist-function",
+ "setupFakeServiceManager",
+ "--allowlist-function",
+ "clearFakeServiceManager",
+ ],
+ shared_libs: [
+ "libc++",
+ "libbinder",
+ "libfakeservicemanager",
+ ],
+}
+
+rust_library {
+ name: "libfakeservicemanager_rs",
+ crate_name: "fakeservicemanager_rs",
+ host_supported: true,
+ srcs: [
+ "rust/src/lib.rs",
+ ],
+ shared_libs: [
+ "libc++",
+ "libfakeservicemanager",
+ ],
+ rustlibs: [
+ "libfakeservicemanager_bindgen",
+ ],
+ lints: "none",
+ clippy_lints: "none",
+}
diff --git a/libs/fakeservicemanager/FakeServiceManager.cpp b/libs/fakeservicemanager/FakeServiceManager.cpp
index 3272bbc1aa..ae242f32a3 100644
--- a/libs/fakeservicemanager/FakeServiceManager.cpp
+++ b/libs/fakeservicemanager/FakeServiceManager.cpp
@@ -16,6 +16,10 @@
#include "fakeservicemanager/FakeServiceManager.h"
+using android::sp;
+using android::FakeServiceManager;
+using android::setDefaultServiceManager;
+
namespace android {
FakeServiceManager::FakeServiceManager() {}
@@ -26,6 +30,8 @@ sp<IBinder> FakeServiceManager::getService( const String16& name) const {
}
sp<IBinder> FakeServiceManager::checkService( const String16& name) const {
+ std::lock_guard<std::mutex> l(mMutex);
+
auto it = mNameToService.find(name);
if (it == mNameToService.end()) {
return nullptr;
@@ -36,6 +42,8 @@ sp<IBinder> FakeServiceManager::checkService( const String16& name) const {
status_t FakeServiceManager::addService(const String16& name, const sp<IBinder>& service,
bool /*allowIsolated*/,
int /*dumpsysFlags*/) {
+ std::lock_guard<std::mutex> l(mMutex);
+
if (service == nullptr) {
return UNEXPECTED_NULL;
}
@@ -44,6 +52,8 @@ status_t FakeServiceManager::addService(const String16& name, const sp<IBinder>&
}
Vector<String16> FakeServiceManager::listServices(int /*dumpsysFlags*/) {
+ std::lock_guard<std::mutex> l(mMutex);
+
Vector<String16> services;
for (auto const& [name, service] : mNameToService) {
(void) service;
@@ -61,16 +71,20 @@ sp<IBinder> FakeServiceManager::waitForService(const String16& name) {
}
bool FakeServiceManager::isDeclared(const String16& name) {
+ std::lock_guard<std::mutex> l(mMutex);
+
return mNameToService.find(name) != mNameToService.end();
}
Vector<String16> FakeServiceManager::getDeclaredInstances(const String16& name) {
+ std::lock_guard<std::mutex> l(mMutex);
+
Vector<String16> out;
const String16 prefix = name + String16("/");
for (const auto& [registeredName, service] : mNameToService) {
(void) service;
if (registeredName.startsWith(prefix)) {
- out.add(String16(registeredName.string() + prefix.size()));
+ out.add(String16(registeredName.c_str() + prefix.size()));
}
}
return out;
@@ -108,6 +122,29 @@ std::vector<IServiceManager::ServiceDebugInfo> FakeServiceManager::getServiceDeb
}
void FakeServiceManager::clear() {
+ std::lock_guard<std::mutex> l(mMutex);
+
mNameToService.clear();
}
} // namespace android
+
+[[clang::no_destroy]] static sp<FakeServiceManager> gFakeServiceManager;
+[[clang::no_destroy]] static std::once_flag gSmOnce;
+
+extern "C" {
+
+// Setup FakeServiceManager to mock dependencies in test using this API for rust backend
+void setupFakeServiceManager() {
+ /* Create a FakeServiceManager instance and add required services */
+ std::call_once(gSmOnce, [&]() {
+ gFakeServiceManager = new FakeServiceManager();
+ android::setDefaultServiceManager(gFakeServiceManager);
+ });
+}
+
+// Clear existing services from Fake SM for rust backend
+void clearFakeServiceManager() {
+ LOG_ALWAYS_FATAL_IF(gFakeServiceManager == nullptr, "Fake Service Manager is not available. Forgot to call setupFakeServiceManager?");
+ gFakeServiceManager->clear();
+}
+} //extern "C" \ No newline at end of file
diff --git a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
index 97add24ac8..f62241d9c2 100644
--- a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
+++ b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
@@ -19,6 +19,7 @@
#include <binder/IServiceManager.h>
#include <map>
+#include <mutex>
#include <optional>
#include <vector>
@@ -68,6 +69,7 @@ public:
void clear();
private:
+ mutable std::mutex mMutex;
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/libs/fakeservicemanager/rust/src/lib.rs b/libs/fakeservicemanager/rust/src/lib.rs
new file mode 100644
index 0000000000..5b7e756914
--- /dev/null
+++ b/libs/fakeservicemanager/rust/src/lib.rs
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use fakeservicemanager_bindgen::{clearFakeServiceManager, setupFakeServiceManager};
+// Setup FakeServiceManager for testing and fuzzing purposes
+pub fn setup_fake_service_manager() {
+ unsafe {
+ // Safety: This API creates a new FakeSm object which will be always valid and sets up
+ // defaultServiceManager
+ setupFakeServiceManager();
+ }
+}
+
+// Setup FakeServiceManager for testing and fuzzing purposes
+pub fn clear_fake_service_manager() {
+ unsafe {
+ // Safety: This API clears all registered services with Fake SM. This should be only used
+ // setupFakeServiceManager is already called.
+ clearFakeServiceManager();
+ }
+}
diff --git a/libs/fakeservicemanager/rust/wrappers/FakeServiceManagerWrapper.hpp b/libs/fakeservicemanager/rust/wrappers/FakeServiceManagerWrapper.hpp
new file mode 100644
index 0000000000..1f5923afba
--- /dev/null
+++ b/libs/fakeservicemanager/rust/wrappers/FakeServiceManagerWrapper.hpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fakeservicemanager/FakeServiceManager.h"
+
+extern "C" {
+ // Setup FakeServiceManager to mock dependencies in test using this API
+ void setupFakeServiceManager();
+
+ // Clear existing services from Fake SM.
+ void clearFakeServiceManager();
+} // extern "C"
diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp
index 6fc21c65d1..cb6784c04a 100644
--- a/libs/fakeservicemanager/test_sm.cpp
+++ b/libs/fakeservicemanager/test_sm.cpp
@@ -22,6 +22,7 @@
#include <binder/IServiceManager.h>
#include "fakeservicemanager/FakeServiceManager.h"
+#include "rust/wrappers/FakeServiceManagerWrapper.hpp"
using android::sp;
using android::BBinder;
@@ -31,6 +32,7 @@ using android::status_t;
using android::FakeServiceManager;
using android::String16;
using android::IServiceManager;
+using android::defaultServiceManager;
using testing::ElementsAre;
static sp<IBinder> getBinder() {
@@ -83,7 +85,7 @@ TEST(GetService, HappyHappy) {
EXPECT_EQ(sm->getService(String16("foo")), service);
}
-TEST(GetService, NonExistant) {
+TEST(GetService, NonExistent) {
auto sm = new FakeServiceManager();
EXPECT_EQ(sm->getService(String16("foo")), nullptr);
@@ -108,7 +110,7 @@ TEST(ListServices, AllServices) {
String16("sd")));
}
-TEST(WaitForService, NonExistant) {
+TEST(WaitForService, NonExistent) {
auto sm = new FakeServiceManager();
EXPECT_EQ(sm->waitForService(String16("foo")), nullptr);
@@ -124,7 +126,7 @@ TEST(WaitForService, HappyHappy) {
EXPECT_EQ(sm->waitForService(String16("foo")), service);
}
-TEST(IsDeclared, NonExistant) {
+TEST(IsDeclared, NonExistent) {
auto sm = new FakeServiceManager();
EXPECT_FALSE(sm->isDeclared(String16("foo")));
@@ -139,3 +141,31 @@ TEST(IsDeclared, HappyHappy) {
EXPECT_TRUE(sm->isDeclared(String16("foo")));
}
+
+TEST(SetupFakeServiceManager, NonExistent) {
+ setupFakeServiceManager();
+
+ EXPECT_EQ(defaultServiceManager()->getService(String16("foo")), nullptr);
+}
+
+TEST(SetupFakeServiceManager, GetExistingService) {
+ setupFakeServiceManager();
+ sp<IBinder> service = getBinder();
+
+ EXPECT_EQ(defaultServiceManager()->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ EXPECT_EQ(defaultServiceManager()->getService(String16("foo")), service);
+ clearFakeServiceManager();
+}
+
+TEST(ClearFakeServiceManager, GetServiceAfterClear) {
+ setupFakeServiceManager();
+
+ sp<IBinder> service = getBinder();
+ EXPECT_EQ(defaultServiceManager()->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ clearFakeServiceManager();
+ EXPECT_EQ(defaultServiceManager()->getService(String16("foo")), nullptr);
+} \ No newline at end of file
diff --git a/libs/ftl/OWNERS b/libs/ftl/OWNERS
new file mode 100644
index 0000000000..3f6129226a
--- /dev/null
+++ b/libs/ftl/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/native:/services/surfaceflinger/OWNERS \ No newline at end of file
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 5f5f85a2ad..701a3b2f77 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -60,6 +60,16 @@ typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rulesHandle, int rulesVe
typedef bool (*fpANGLEFreeRulesHandle)(void* handle);
typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle);
+namespace {
+static bool isVndkEnabled() {
+#ifdef __BIONIC__
+ static bool isVndkEnabled = android::base::GetProperty("ro.vndk.version", "") != "";
+ return isVndkEnabled;
+#endif
+ return false;
+}
+} // namespace
+
namespace android {
enum NativeLibrary {
@@ -71,6 +81,8 @@ static constexpr const char* kNativeLibrariesSystemConfigPath[] =
{"/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt",
"/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt"};
+static const char* kLlndkLibrariesTxtPath = "/system/etc/llndk.libraries.txt";
+
static std::string vndkVersionStr() {
#ifdef __BIONIC__
return base::GetProperty("ro.vndk.version", "");
@@ -108,8 +120,14 @@ static bool readConfig(const std::string& configFile, std::vector<std::string>*
}
static const std::string getSystemNativeLibraries(NativeLibrary type) {
- std::string nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type];
- insertVndkVersionStr(&nativeLibrariesSystemConfig);
+ std::string nativeLibrariesSystemConfig = "";
+
+ if (!isVndkEnabled() && type == NativeLibrary::LLNDK) {
+ nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath;
+ } else {
+ nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type];
+ insertVndkVersionStr(&nativeLibrariesSystemConfig);
+ }
std::vector<std::string> soNames;
if (!readConfig(nativeLibrariesSystemConfig, &soNames)) {
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index f50bc203e8..e6331e7282 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -24,11 +24,11 @@
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
-#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
namespace android {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 7f7a0437f1..db513561fb 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -46,23 +46,23 @@ namespace android {
// Macros for include BufferQueueCore information in log messages
#define BQ_LOGV(x, ...) \
- ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGD(x, ...) \
- ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGI(x, ...) \
- ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGW(x, ...) \
- ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGE(x, ...) \
- ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
@@ -297,8 +297,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
// decrease.
mCore->mDequeueCondition.notify_all();
- ATRACE_INT(mCore->mConsumerName.string(),
- static_cast<int32_t>(mCore->mQueue.size()));
+ ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
@@ -717,7 +716,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
status_t BufferQueueConsumer::setConsumerName(const String8& name) {
ATRACE_CALL();
- BQ_LOGV("setConsumerName: '%s'", name.string());
+ BQ_LOGV("setConsumerName: '%s'", name.c_str());
std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mConsumerName = name;
mConsumerName = name;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 2930154ad4..648db67fc1 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -41,20 +41,20 @@
namespace android {
// Macros for include BufferQueueCore information in log messages
-#define BQ_LOGV(x, ...) \
- ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+#define BQ_LOGV(x, ...) \
+ ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
-#define BQ_LOGD(x, ...) \
- ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+#define BQ_LOGD(x, ...) \
+ ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
-#define BQ_LOGI(x, ...) \
- ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+#define BQ_LOGI(x, ...) \
+ ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
-#define BQ_LOGW(x, ...) \
- ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+#define BQ_LOGW(x, ...) \
+ ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
-#define BQ_LOGE(x, ...) \
- ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \
+#define BQ_LOGE(x, ...) \
+ ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \
mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__)
static String8 getUniqueName() {
@@ -146,23 +146,23 @@ BufferQueueCore::~BufferQueueCore() {}
void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
std::lock_guard<std::mutex> lock(mMutex);
- outResult->appendFormat("%s- BufferQueue ", prefix.string());
+ outResult->appendFormat("%s- BufferQueue ", prefix.c_str());
outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
- outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
+ outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.c_str(),
mDequeueBufferCannotBlock, mAsyncMode);
- outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.string(),
+ outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.c_str(),
mQueueBufferCanDrop, mLegacyBufferDrop);
- outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(),
+ outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.c_str(),
mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
- outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(),
+ outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.c_str(),
mTransformHint, mFrameCounter);
- outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(),
+ outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.c_str(),
mTransformHintInUse, mAutoPrerotation);
- outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size());
+ outResult->appendFormat("%sFIFO(%zu):\n", prefix.c_str(), mQueue.size());
- outResult->appendFormat("%s(mConsumerName=%s, ", prefix.string(), mConsumerName.string());
+ outResult->appendFormat("%s(mConsumerName=%s, ", prefix.c_str(), mConsumerName.c_str());
outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi,
mConsumerUsageBits);
@@ -173,12 +173,11 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const
getProcessName(mConnectedPid, producerProcName);
getProcessName(pid, consumerProcName);
outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId,
- mConnectedPid, producerProcName.string(), pid,
- consumerProcName.string());
+ mConnectedPid, producerProcName.c_str(), pid, consumerProcName.c_str());
Fifo::const_iterator current(mQueue.begin());
while (current != mQueue.end()) {
double timestamp = current->mTimestamp / 1e9;
- outResult->appendFormat("%s %02d:%p ", prefix.string(), current->mSlot,
+ outResult->appendFormat("%s %02d:%p ", prefix.c_str(), current->mSlot,
current->mGraphicBuffer.get());
outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top,
current->mCrop.right, current->mCrop.bottom);
@@ -187,12 +186,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const
++current;
}
- outResult->appendFormat("%sSlots:\n", prefix.string());
+ outResult->appendFormat("%sSlots:\n", prefix.c_str());
for (int s : mActiveBuffers) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
// A dequeued buffer might be null if it's still being allocated
if (buffer.get()) {
- outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(),
+ outResult->appendFormat("%s %s[%02d:%p] ", prefix.c_str(),
(mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
buffer.get());
outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
@@ -200,14 +199,14 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const
outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
buffer->stride, buffer->format);
} else {
- outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get());
+ outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get());
outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n",
mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber);
}
}
for (int s : mFreeBuffers) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
- outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get());
+ outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get());
outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
buffer->handle, mSlots[s].mFrameNumber);
outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
@@ -216,7 +215,7 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const
for (int s : mFreeSlots) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
- outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(),
+ outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.c_str(), s, buffer.get(),
mSlots[s].mBufferState.string());
}
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index f93468036f..36c2e5891e 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -46,23 +46,23 @@ namespace android {
// Macros for include BufferQueueCore information in log messages
#define BQ_LOGV(x, ...) \
- ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGD(x, ...) \
- ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGI(x, ...) \
- ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGW(x, ...) \
- ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
#define BQ_LOGE(x, ...) \
- ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \
+ ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
@@ -554,9 +554,9 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
- width, height, format, BQ_LAYER_COUNT, usage,
- {mConsumerName.string(), mConsumerName.size()});
+ sp<GraphicBuffer> graphicBuffer =
+ new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage,
+ {mConsumerName.c_str(), mConsumerName.size()});
status_t error = graphicBuffer->initCheck();
@@ -1018,8 +1018,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
- ATRACE_INT(mCore->mConsumerName.string(),
- static_cast<int32_t>(mCore->mQueue.size()));
+ ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
@@ -1446,7 +1445,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
allocUsage = usage | mCore->mConsumerUsageBits;
- allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size());
+ allocName.assign(mCore->mConsumerName.c_str(), mCore->mConsumerName.size());
mCore->mIsAllocating = true;
} // Autolock scope
@@ -1548,7 +1547,7 @@ status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) {
String8 BufferQueueProducer::getConsumerName() const {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mCore->mMutex);
- BQ_LOGV("getConsumerName: %s", mConsumerName.string());
+ BQ_LOGV("getConsumerName: %s", mConsumerName.c_str());
return mConsumerName;
}
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 9f91d9d3aa..b625c3f75e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -41,11 +41,11 @@
#include <utils/Trace.h>
// Macros for including the ConsumerBase name in log messages
-#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
namespace android {
@@ -86,8 +86,10 @@ ConsumerBase::~ConsumerBase() {
// be done by ConsumerBase::onLastStrongRef(), but it's possible for a
// derived class to override that method and not call
// ConsumerBase::onLastStrongRef().
- LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the "
- "consumer is not abandoned!", mName.string());
+ LOG_ALWAYS_FATAL_IF(!mAbandoned,
+ "[%s] ~ConsumerBase was called, but the "
+ "consumer is not abandoned!",
+ mName.c_str());
}
void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) {
@@ -451,7 +453,7 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot,
// them to get an accurate timestamp.
if (currentStatus == incomingStatus) {
char fenceName[32] = {};
- snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot);
+ snprintf(fenceName, 32, "%.28s:%d", mName.c_str(), slot);
sp<Fence> mergedFence = Fence::merge(
fenceName, mSlots[slot].mFence, fence);
if (!mergedFence.get()) {
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index a62697064b..3031fa11fc 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -23,11 +23,11 @@
#include <gui/BufferItem.h>
#include <utils/Log.h>
-#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
namespace android {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index b3647d6126..d49489c5a8 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -52,11 +52,11 @@
namespace android {
// Macros for including the GLConsumer name in log messages
-#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
static const struct {
uint32_t width, height;
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 826a418aab..070f6bf532 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075131
+
chrisforbes@google.com
jreck@google.com
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 05beb07891..6d44f1079c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1056,7 +1056,7 @@ sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, boo
sp<IBinder> display = nullptr;
binder::Status status =
ComposerServiceAIDL::getComposerService()->createDisplay(std::string(
- displayName.string()),
+ displayName.c_str()),
secure, &display);
return status.isOk() ? display : nullptr;
}
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 8d0828d88e..22c2be7bc7 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -34,13 +34,13 @@
#include <mutex>
#include <condition_variable>
-#define ATRACE_BUFFER_INDEX(index) \
- do { \
- if (ATRACE_ENABLED()) { \
- char ___traceBuf[1024]; \
- snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \
- android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
- } \
+#define ATRACE_BUFFER_INDEX(index) \
+ do { \
+ if (ATRACE_ENABLED()) { \
+ char ___traceBuf[1024]; \
+ snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.c_str(), (index)); \
+ android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
+ } \
} while (false)
namespace android {
diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
index 004d87574a..32dc88ba84 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
@@ -298,7 +298,7 @@ struct TWGraphicBufferProducer : public BASE {
}
Return<void> getConsumerName(HGraphicBufferProducer::getConsumerName_cb _hidl_cb) override {
- _hidl_cb(mBase->getConsumerName().string());
+ _hidl_cb(mBase->getConsumerName().c_str());
return Void();
}
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index a1405fcb11..449cbf9f75 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -185,31 +185,31 @@ EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config,
while ((err = glGetError()) != GL_NO_ERROR) {
msg += String8::format(", %#x", err);
}
- return ::testing::AssertionFailure(::testing::Message(msg.string()));
+ return ::testing::AssertionFailure(::testing::Message(msg.c_str()));
}
if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
msg += String8::format("r(%d isn't %d)", pixel[0], r);
}
if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
- if (!msg.isEmpty()) {
+ if (!msg.empty()) {
msg += " ";
}
msg += String8::format("g(%d isn't %d)", pixel[1], g);
}
if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
- if (!msg.isEmpty()) {
+ if (!msg.empty()) {
msg += " ";
}
msg += String8::format("b(%d isn't %d)", pixel[2], b);
}
if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
- if (!msg.isEmpty()) {
+ if (!msg.empty()) {
msg += " ";
}
msg += String8::format("a(%d isn't %d)", pixel[3], a);
}
- if (!msg.isEmpty()) {
- return ::testing::AssertionFailure(::testing::Message(msg.string()));
+ if (!msg.empty()) {
+ return ::testing::AssertionFailure(::testing::Message(msg.c_str()));
} else {
return ::testing::AssertionSuccess();
}
@@ -223,29 +223,29 @@ EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config,
msg += String8::format("left(%d isn't %d)", r1.left, r2.left);
}
if (abs(r1.top - r2.top) > tolerance) {
- if (!msg.isEmpty()) {
+ if (!msg.empty()) {
msg += " ";
}
msg += String8::format("top(%d isn't %d)", r1.top, r2.top);
}
if (abs(r1.right - r2.right) > tolerance) {
- if (!msg.isEmpty()) {
+ if (!msg.empty()) {
msg += " ";
}
msg += String8::format("right(%d isn't %d)", r1.right, r2.right);
}
if (abs(r1.bottom - r2.bottom) > tolerance) {
- if (!msg.isEmpty()) {
+ if (!msg.empty()) {
msg += " ";
}
msg += String8::format("bottom(%d isn't %d)", r1.bottom, r2.bottom);
}
- if (!msg.isEmpty()) {
+ if (!msg.empty()) {
msg += String8::format(" R1: [%d %d %d %d] R2: [%d %d %d %d]",
r1.left, r1.top, r1.right, r1.bottom,
r2.left, r2.top, r2.right, r2.bottom);
- fprintf(stderr, "assertRectEq: %s\n", msg.string());
- return ::testing::AssertionFailure(::testing::Message(msg.string()));
+ fprintf(stderr, "assertRectEq: %s\n", msg.c_str());
+ return ::testing::AssertionFailure(::testing::Message(msg.c_str()));
} else {
return ::testing::AssertionSuccess();
}
diff --git a/libs/gui/tests/OWNERS b/libs/gui/tests/OWNERS
new file mode 100644
index 0000000000..48cd30d39d
--- /dev/null
+++ b/libs/gui/tests/OWNERS
@@ -0,0 +1,6 @@
+# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > Surfaces
+# Bug component: 316245 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp
+# Buganizer template url: https://b.corp.google.com/issues/new?component=316245&template=1018194 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp
+
+# Android > Android OS & Apps > graphics > Core Graphics Stack (CoGS)
+# Bug component: 1075130
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index f34561f668..ccd0e59616 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -59,7 +59,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
for (int i = 0; i < 4; i++) {
- SCOPED_TRACE(String8::format("frame %d", i).string());
+ SCOPED_TRACE(String8::format("frame %d", i).c_str());
ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
&anb));
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index e2b4f3d035..f76c0be265 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -147,8 +147,9 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
for (int i = 0; i < 5; i++) {
const android_native_rect_t& crop(crops[i]);
- SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }",
- crop.left, crop.top, crop.right, crop.bottom).string());
+ SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left, crop.top,
+ crop.right, crop.bottom)
+ .c_str());
ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
@@ -308,7 +309,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
mFW->waitForFrame();
for (int i = 0; i < numFrames; i++) {
- SCOPED_TRACE(String8::format("frame %d", i).string());
+ SCOPED_TRACE(String8::format("frame %d", i).c_str());
// We must wait for each frame to come in because if we ever do an
// updateTexImage call that doesn't consume a newly available buffer
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 065cd7a5c7..cb977f04c9 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -408,7 +408,7 @@ TEST_F(SurfaceTest, GetConsumerName) {
sp<ANativeWindow> window(surface);
native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
- EXPECT_STREQ("TestConsumer", surface->getConsumerName().string());
+ EXPECT_STREQ("TestConsumer", surface->getConsumerName().c_str());
}
TEST_F(SurfaceTest, GetWideColorSupport) {
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 2039fa6553..f98de34632 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -209,7 +209,7 @@ status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
+ tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
#endif
if (status != OK) {
ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
@@ -363,8 +363,8 @@ char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_
ExactMatch: ;
}
#if DEBUG_MAPPING
- ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
- keyCode, toString(chars, numChars).string(), metaState, result);
+ ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", keyCode,
+ toString(chars, numChars).c_str(), metaState, result);
#endif
return result;
}
@@ -379,7 +379,7 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t
if (!findKey(ch, &keyCode, &metaState)) {
#if DEBUG_MAPPING
ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
- deviceId, toString(chars, numChars).string(), ch);
+ deviceId, toString(chars, numChars).c_str(), ch);
#endif
return false;
}
@@ -391,8 +391,8 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t
addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
}
#if DEBUG_MAPPING
- ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
- deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
+ ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId,
+ toString(chars, numChars).c_str(), int32_t(outEvents.size()));
for (size_t i = 0; i < outEvents.size(); i++) {
ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
@@ -849,8 +849,8 @@ KeyCharacterMap::Parser::~Parser() {
status_t KeyCharacterMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
+ mTokenizer->peekRemainderOfLine().c_str());
#endif
mTokenizer->skipDelimiters(WHITESPACE);
@@ -872,8 +872,8 @@ status_t KeyCharacterMap::Parser::parse() {
status_t status = parseKey();
if (status) return status;
} else {
- ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
- keywordToken.string());
+ ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
+ keywordToken.c_str());
return BAD_VALUE;
}
break;
@@ -889,8 +889,7 @@ status_t KeyCharacterMap::Parser::parse() {
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
return BAD_VALUE;
}
}
@@ -900,27 +899,27 @@ status_t KeyCharacterMap::Parser::parse() {
if (mState != STATE_TOP) {
ALOGE("%s: Unterminated key description at end of file.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
if (mMap->mType == KeyboardType::UNKNOWN) {
ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
if (mFormat == Format::BASE) {
if (mMap->mType == KeyboardType::OVERLAY) {
ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
} else if (mFormat == Format::OVERLAY) {
if (mMap->mType != KeyboardType::OVERLAY) {
ALOGE("%s: Overlay keyboard layout missing required keyboard "
- "'type OVERLAY' declaration.",
- mTokenizer->getLocation().string());
+ "'type OVERLAY' declaration.",
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
}
@@ -930,8 +929,7 @@ status_t KeyCharacterMap::Parser::parse() {
status_t KeyCharacterMap::Parser::parseType() {
if (mMap->mType != KeyboardType::UNKNOWN) {
- ALOGE("%s: Duplicate keyboard 'type' declaration.",
- mTokenizer->getLocation().string());
+ ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
@@ -953,8 +951,8 @@ status_t KeyCharacterMap::Parser::parseType() {
} else if (typeToken == "OVERLAY") {
type = KeyboardType::OVERLAY;
} else {
- ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
- typeToken.string());
+ ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(),
+ typeToken.c_str());
return BAD_VALUE;
}
@@ -971,8 +969,8 @@ status_t KeyCharacterMap::Parser::parseMap() {
mTokenizer->skipDelimiters(WHITESPACE);
return parseMapKey();
}
- ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
- keywordToken.string());
+ ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(),
+ keywordToken.c_str());
return BAD_VALUE;
}
@@ -986,26 +984,26 @@ status_t KeyCharacterMap::Parser::parseMapKey() {
}
char* end;
- int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
+ int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
if (*end) {
- ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
+ ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
+ mapUsage ? "usage" : "scan code", codeToken.c_str());
return BAD_VALUE;
}
KeyedVector<int32_t, int32_t>& map =
mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
if (map.indexOfKey(code) >= 0) {
- ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
+ ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
+ mapUsage ? "usage" : "scan code", codeToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
+ int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
if (!keyCode) {
- ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
+ ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
+ keyCodeToken.c_str());
return BAD_VALUE;
}
@@ -1019,23 +1017,23 @@ status_t KeyCharacterMap::Parser::parseMapKey() {
status_t KeyCharacterMap::Parser::parseKey() {
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
+ int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
if (!keyCode) {
- ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
+ ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
+ keyCodeToken.c_str());
return BAD_VALUE;
}
if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
- ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
+ ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(),
+ keyCodeToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
if (openBraceToken != "{") {
- ALOGE("%s: Expected '{' after key code label, got '%s'.",
- mTokenizer->getLocation().string(), openBraceToken.string());
+ ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(),
+ openBraceToken.c_str());
return BAD_VALUE;
}
@@ -1066,10 +1064,10 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
properties.add(Property(PROPERTY_NUMBER));
} else {
int32_t metaState;
- status_t status = parseModifier(token.string(), &metaState);
+ status_t status = parseModifier(token.c_str(), &metaState);
if (status) {
ALOGE("%s: Expected a property name or modifier, got '%s'.",
- mTokenizer->getLocation().string(), token.string());
+ mTokenizer->getLocation().c_str(), token.c_str());
return status;
}
properties.add(Property(PROPERTY_META, metaState));
@@ -1087,8 +1085,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
}
}
- ALOGE("%s: Expected ',' or ':' after property name.",
- mTokenizer->getLocation().string());
+ ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
@@ -1106,18 +1103,17 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
char16_t character;
status_t status = parseCharacterLiteral(&character);
if (status || !character) {
- ALOGE("%s: Invalid character literal for key.",
- mTokenizer->getLocation().string());
+ ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
if (haveCharacter) {
ALOGE("%s: Cannot combine multiple character literals or 'none'.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
if (haveReplacement) {
ALOGE("%s: Cannot combine character literal with replace action.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
behavior.character = character;
@@ -1127,28 +1123,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
if (token == "none") {
if (haveCharacter) {
ALOGE("%s: Cannot combine multiple character literals or 'none'.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
if (haveReplacement) {
ALOGE("%s: Cannot combine 'none' with replace action.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
haveCharacter = true;
} else if (token == "fallback") {
mTokenizer->skipDelimiters(WHITESPACE);
token = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
+ int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
if (!keyCode) {
ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
- mTokenizer->getLocation().string(),
- token.string());
+ mTokenizer->getLocation().c_str(), token.c_str());
return BAD_VALUE;
}
if (haveFallback || haveReplacement) {
ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
behavior.fallbackKeyCode = keyCode;
@@ -1156,29 +1151,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
} else if (token == "replace") {
mTokenizer->skipDelimiters(WHITESPACE);
token = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
+ int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
if (!keyCode) {
ALOGE("%s: Invalid key code label for replace, got '%s'.",
- mTokenizer->getLocation().string(),
- token.string());
+ mTokenizer->getLocation().c_str(), token.c_str());
return BAD_VALUE;
}
if (haveCharacter) {
ALOGE("%s: Cannot combine character literal with replace action.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
if (haveFallback || haveReplacement) {
ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
behavior.replacementKeyCode = keyCode;
haveReplacement = true;
} else {
- ALOGE("%s: Expected a key behavior after ':'.",
- mTokenizer->getLocation().string());
+ ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
}
@@ -1192,8 +1185,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
switch (property.property) {
case PROPERTY_LABEL:
if (key->label) {
- ALOGE("%s: Duplicate label for key.",
- mTokenizer->getLocation().string());
+ ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
key->label = behavior.character;
@@ -1203,8 +1195,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
break;
case PROPERTY_NUMBER:
if (key->number) {
- ALOGE("%s: Duplicate number for key.",
- mTokenizer->getLocation().string());
+ ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
key->number = behavior.character;
@@ -1216,7 +1207,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
for (Behavior* b = key->firstBehavior; b; b = b->next) {
if (b->metaState == property.metaState) {
ALOGE("%s: Duplicate key behavior for modifier.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
}
@@ -1285,8 +1276,8 @@ status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_
return BAD_VALUE;
}
if (combinedMeta & metaState) {
- ALOGE("%s: Duplicate modifier combination '%s'.",
- mTokenizer->getLocation().string(), token.c_str());
+ ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(),
+ token.c_str());
return BAD_VALUE;
}
@@ -1354,12 +1345,12 @@ status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter)
}
// Ensure that we consumed the entire token.
- if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
+ if (mTokenizer->nextToken(WHITESPACE).empty()) {
return NO_ERROR;
}
Error:
- ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
+ ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 250c0dd9a9..79b6cea292 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -161,7 +161,7 @@ base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(Tokenizer* tokeni
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ tokenizer->getFilename().c_str(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (!status) {
@@ -289,8 +289,8 @@ KeyLayoutMap::Parser::~Parser() {
status_t KeyLayoutMap::Parser::parse() {
while (!mTokenizer->isEof()) {
- ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
+ mTokenizer->peekRemainderOfLine().c_str());
mTokenizer->skipDelimiters(WHITESPACE);
@@ -317,16 +317,15 @@ status_t KeyLayoutMap::Parser::parse() {
status_t status = parseRequiredKernelConfig();
if (status) return status;
} else {
- ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
- keywordToken.string());
+ ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
+ keywordToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
return BAD_VALUE;
}
}
@@ -346,26 +345,26 @@ status_t KeyLayoutMap::Parser::parseKey() {
}
char* end;
- int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
+ int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
if (*end) {
- ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
+ ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
+ mapUsage ? "usage" : "scan code", codeToken.c_str());
return BAD_VALUE;
}
std::unordered_map<int32_t, Key>& map =
mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
if (map.find(code) != map.end()) {
- ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
+ ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
+ mapUsage ? "usage" : "scan code", codeToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
- int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
+ int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
if (!keyCode) {
- ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
- keyCodeToken.string());
+ ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
+ keyCodeToken.c_str());
return BAD_VALUE;
}
@@ -375,15 +374,15 @@ status_t KeyLayoutMap::Parser::parseKey() {
if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
String8 flagToken = mTokenizer->nextToken(WHITESPACE);
- uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string());
+ uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.c_str());
if (!flag) {
- ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
- flagToken.string());
+ ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().c_str(),
+ flagToken.c_str());
return BAD_VALUE;
}
if (flags & flag) {
- ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
- flagToken.string());
+ ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().c_str(),
+ flagToken.c_str());
return BAD_VALUE;
}
flags |= flag;
@@ -402,15 +401,15 @@ status_t KeyLayoutMap::Parser::parseKey() {
status_t KeyLayoutMap::Parser::parseAxis() {
String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
char* end;
- int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
+ int32_t scanCode = int32_t(strtol(scanCodeToken.c_str(), &end, 0));
if (*end) {
- ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
- scanCodeToken.string());
+ ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().c_str(),
+ scanCodeToken.c_str());
return BAD_VALUE;
}
if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) {
- ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
- scanCodeToken.string());
+ ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().c_str(),
+ scanCodeToken.c_str());
return BAD_VALUE;
}
@@ -423,10 +422,10 @@ status_t KeyLayoutMap::Parser::parseAxis() {
mTokenizer->skipDelimiters(WHITESPACE);
String8 axisToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string());
+ axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.c_str());
if (axisInfo.axis < 0) {
- ALOGE("%s: Expected inverted axis label, got '%s'.",
- mTokenizer->getLocation().string(), axisToken.string());
+ ALOGE("%s: Expected inverted axis label, got '%s'.", mTokenizer->getLocation().c_str(),
+ axisToken.c_str());
return BAD_VALUE;
}
} else if (token == "split") {
@@ -434,35 +433,35 @@ status_t KeyLayoutMap::Parser::parseAxis() {
mTokenizer->skipDelimiters(WHITESPACE);
String8 splitToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
+ axisInfo.splitValue = int32_t(strtol(splitToken.c_str(), &end, 0));
if (*end) {
- ALOGE("%s: Expected split value, got '%s'.",
- mTokenizer->getLocation().string(), splitToken.string());
+ ALOGE("%s: Expected split value, got '%s'.", mTokenizer->getLocation().c_str(),
+ splitToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string());
+ axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.c_str());
if (axisInfo.axis < 0) {
- ALOGE("%s: Expected low axis label, got '%s'.",
- mTokenizer->getLocation().string(), lowAxisToken.string());
+ ALOGE("%s: Expected low axis label, got '%s'.", mTokenizer->getLocation().c_str(),
+ lowAxisToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string());
+ axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.c_str());
if (axisInfo.highAxis < 0) {
- ALOGE("%s: Expected high axis label, got '%s'.",
- mTokenizer->getLocation().string(), highAxisToken.string());
+ ALOGE("%s: Expected high axis label, got '%s'.", mTokenizer->getLocation().c_str(),
+ highAxisToken.c_str());
return BAD_VALUE;
}
} else {
- axisInfo.axis = InputEventLookup::getAxisByLabel(token.string());
+ axisInfo.axis = InputEventLookup::getAxisByLabel(token.c_str());
if (axisInfo.axis < 0) {
ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
- mTokenizer->getLocation().string(), token.string());
+ mTokenizer->getLocation().c_str(), token.c_str());
return BAD_VALUE;
}
}
@@ -476,15 +475,15 @@ status_t KeyLayoutMap::Parser::parseAxis() {
if (keywordToken == "flat") {
mTokenizer->skipDelimiters(WHITESPACE);
String8 flatToken = mTokenizer->nextToken(WHITESPACE);
- axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
+ axisInfo.flatOverride = int32_t(strtol(flatToken.c_str(), &end, 0));
if (*end) {
- ALOGE("%s: Expected flat value, got '%s'.",
- mTokenizer->getLocation().string(), flatToken.string());
+ ALOGE("%s: Expected flat value, got '%s'.", mTokenizer->getLocation().c_str(),
+ flatToken.c_str());
return BAD_VALUE;
}
} else {
- ALOGE("%s: Expected keyword 'flat', got '%s'.",
- mTokenizer->getLocation().string(), keywordToken.string());
+ ALOGE("%s: Expected keyword 'flat', got '%s'.", mTokenizer->getLocation().c_str(),
+ keywordToken.c_str());
return BAD_VALUE;
}
}
@@ -507,27 +506,27 @@ status_t KeyLayoutMap::Parser::parseLed() {
codeToken = mTokenizer->nextToken(WHITESPACE);
}
char* end;
- int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
+ int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
if (*end) {
- ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
+ ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().c_str(),
+ mapUsage ? "usage" : "scan code", codeToken.c_str());
return BAD_VALUE;
}
std::unordered_map<int32_t, Led>& map =
mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
if (map.find(code) != map.end()) {
- ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
- mapUsage ? "usage" : "scan code", codeToken.string());
+ ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().c_str(),
+ mapUsage ? "usage" : "scan code", codeToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
- int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string());
+ int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.c_str());
if (ledCode < 0) {
- ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(),
- ledCodeToken.string());
+ ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().c_str(),
+ ledCodeToken.c_str());
return BAD_VALUE;
}
@@ -549,7 +548,7 @@ static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
}
static std::optional<int32_t> getSensorDataIndex(String8 token) {
- std::string tokenStr(token.string());
+ std::string tokenStr(token.c_str());
if (tokenStr == "X") {
return 0;
} else if (tokenStr == "Y") {
@@ -575,26 +574,26 @@ static std::optional<int32_t> getSensorDataIndex(String8 token) {
status_t KeyLayoutMap::Parser::parseSensor() {
String8 codeToken = mTokenizer->nextToken(WHITESPACE);
char* end;
- int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
+ int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
if (*end) {
- ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(),
- "abs code", codeToken.string());
+ ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().c_str(),
+ "abs code", codeToken.c_str());
return BAD_VALUE;
}
std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode;
if (map.find(code) != map.end()) {
- ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(),
- "abs code", codeToken.string());
+ ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().c_str(),
+ "abs code", codeToken.c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE);
- std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.string());
+ std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.c_str());
if (!typeOpt) {
- ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(),
- sensorTypeToken.string());
+ ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().c_str(),
+ sensorTypeToken.c_str());
return BAD_VALUE;
}
InputDeviceSensorType sensorType = typeOpt.value();
@@ -602,8 +601,8 @@ status_t KeyLayoutMap::Parser::parseSensor() {
String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE);
std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken);
if (!indexOpt) {
- ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(),
- sensorDataIndexToken.string());
+ ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().c_str(),
+ sensorDataIndexToken.c_str());
return BAD_VALUE;
}
int32_t sensorDataIndex = indexOpt.value();
@@ -624,12 +623,12 @@ status_t KeyLayoutMap::Parser::parseSensor() {
// requires_kernel_config CONFIG_HID_PLAYSTATION
status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
String8 codeToken = mTokenizer->nextToken(WHITESPACE);
- std::string configName = codeToken.string();
+ std::string configName = codeToken.c_str();
const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
if (!result.second) {
ALOGE("%s: Duplicate entry for required kernel config %s.",
- mTokenizer->getLocation().string(), configName.c_str());
+ mTokenizer->getLocation().c_str(), configName.c_str());
return BAD_VALUE;
}
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index c3f5151fd1..5f06efaf50 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -55,8 +55,8 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
- "it was not found.",
- deviceIdentifier.name.c_str(), keyLayoutName.string());
+ "it was not found.",
+ deviceIdentifier.name.c_str(), keyLayoutName.c_str());
}
}
@@ -66,8 +66,8 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
- "map '%s' but it was not found.",
- deviceIdentifier.name.c_str(), keyCharacterMapName.string());
+ "map '%s' but it was not found.",
+ deviceIdentifier.name.c_str(), keyCharacterMapName.c_str());
}
}
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index a842166761..9f72c86a11 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -74,10 +74,10 @@ bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
}
char* end;
- int value = strtol(stringValue.string(), &end, 10);
+ int value = strtol(stringValue.c_str(), &end, 10);
if (*end != '\0') {
- ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.string(),
- stringValue.string());
+ ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(),
+ stringValue.c_str());
return false;
}
outValue = value;
@@ -91,10 +91,10 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
}
char* end;
- float value = strtof(stringValue.string(), &end);
+ float value = strtof(stringValue.c_str(), &end);
if (*end != '\0') {
- ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.string(),
- stringValue.string());
+ ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(),
+ stringValue.c_str());
return false;
}
outValue = value;
@@ -127,7 +127,7 @@ android::base::Result<std::unique_ptr<PropertyMap>> PropertyMap::load(const char
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed property file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ tokenizer->getFilename().c_str(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (status) {
@@ -147,16 +147,16 @@ PropertyMap::Parser::~Parser() {}
status_t PropertyMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
+ mTokenizer->peekRemainderOfLine().c_str());
#endif
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
- if (keyToken.isEmpty()) {
- ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
+ if (keyToken.empty()) {
+ ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
@@ -164,7 +164,7 @@ status_t PropertyMap::Parser::parse() {
if (mTokenizer->nextChar() != '=') {
ALOGE("%s: Expected '=' between property key and value.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
@@ -173,20 +173,20 @@ status_t PropertyMap::Parser::parse() {
String8 valueToken = mTokenizer->nextToken(WHITESPACE);
if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) {
ALOGE("%s: Found reserved character '\\' or '\"' in property value.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol()) {
- ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(),
+ mTokenizer->peekRemainderOfLine().c_str());
return BAD_VALUE;
}
if (mMap->hasProperty(keyToken)) {
ALOGE("%s: Duplicate property value for key '%s'.",
- mTokenizer->getLocation().string(), keyToken.string());
+ mTokenizer->getLocation().c_str(), keyToken.c_str());
return BAD_VALUE;
}
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 865366bcb2..8b8af4290f 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -79,8 +79,8 @@ VirtualKeyMap::Parser::~Parser() {
status_t VirtualKeyMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
+ mTokenizer->peekRemainderOfLine().c_str());
#endif
mTokenizer->skipDelimiters(WHITESPACE);
@@ -91,7 +91,7 @@ status_t VirtualKeyMap::Parser::parse() {
String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
if (token != "0x01") {
ALOGE("%s: Unknown virtual key type, expected 0x01.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
@@ -103,7 +103,7 @@ status_t VirtualKeyMap::Parser::parse() {
&& parseNextIntField(&defn.height);
if (!success) {
ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
- mTokenizer->getLocation().string());
+ mTokenizer->getLocation().c_str());
return BAD_VALUE;
}
@@ -116,9 +116,8 @@ status_t VirtualKeyMap::Parser::parse() {
} while (consumeFieldDelimiterAndSkipWhitespace());
if (!mTokenizer->isEol()) {
- ALOGE("%s: Expected end of line, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
+ ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(),
+ mTokenizer->peekRemainderOfLine().c_str());
return BAD_VALUE;
}
}
@@ -146,9 +145,9 @@ bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
char* end;
- *outValue = strtol(token.string(), &end, 0);
- if (token.isEmpty() || *end != '\0') {
- ALOGE("Expected an integer, got '%s'.", token.string());
+ *outValue = strtol(token.c_str(), &end, 0);
+ if (token.empty() || *end != '\0') {
+ ALOGE("Expected an integer, got '%s'.", token.c_str());
return false;
}
return true;
diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 0128859ca6..275b7a4888 100644
--- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -38,10 +38,10 @@
namespace android {
// Macros for including the SurfaceTexture name in log messages
-#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
+#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
+#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
+#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
static const struct {
uint32_t width, height;
diff --git a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
index cf16739e89..32b229d77c 100644
--- a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
@@ -19,7 +19,7 @@
#include <surfacetexture/SurfaceTexture.h>
// Macro for including the SurfaceTexture name in log messages
-#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
namespace android {
diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
index d3d4cbafdf..9f610e1a50 100644
--- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -26,10 +26,10 @@
namespace android {
// Macros for including the SurfaceTexture name in log messages
-#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
static const mat4 mtxIdentity;
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 771844f4fe..968c114ed4 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -450,7 +450,7 @@ enum ADataSpace {
*
* Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard
*/
- ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
+ ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
/**
* Adobe RGB
@@ -471,20 +471,20 @@ enum ADataSpace {
ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
/**
- * ITU-R Recommendation 601 (BT.601) - 525-line
+ * ITU-R Recommendation 601 (BT.601) - 625-line
*
- * Standard-definition television, 525 Lines (NTSC)
+ * Standard-definition television, 625 Lines (PAL)
*
- * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
+ * Use limited range, SMPTE 170M transfer and BT.601_625 standard.
*/
ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
/**
- * ITU-R Recommendation 709 (BT.709)
+ * ITU-R Recommendation 601 (BT.601) - 525-line
*
- * High-definition television
+ * Standard-definition television, 525 Lines (NTSC)
*
- * Use limited range, SMPTE 170M transfer and BT.709 standard.
+ * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
*/
ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h
index e269f0dddf..3f77c78096 100644
--- a/libs/nativewindow/include/android/hardware_buffer_aidl.h
+++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h
@@ -95,14 +95,22 @@ public:
binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
reset();
- return AHardwareBuffer_readFromParcel(parcel, &mBuffer);
+ if (__builtin_available(android __ANDROID_API_U__, *)) {
+ return AHardwareBuffer_readFromParcel(parcel, &mBuffer);
+ } else {
+ return STATUS_FAILED_TRANSACTION;
+ }
}
binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
if (!mBuffer) {
return STATUS_BAD_VALUE;
}
- return AHardwareBuffer_writeToParcel(mBuffer, parcel);
+ if (__builtin_available(android __ANDROID_API_U__, *)) {
+ return AHardwareBuffer_writeToParcel(mBuffer, parcel);
+ } else {
+ return STATUS_FAILED_TRANSACTION;
+ }
}
/**
@@ -150,9 +158,13 @@ public:
if (!mBuffer) {
return "<HardwareBuffer: Invalid>";
}
- uint64_t id = 0;
- AHardwareBuffer_getId(mBuffer, &id);
- return "<HardwareBuffer " + std::to_string(id) + ">";
+ if (__builtin_available(android __ANDROID_API_S__, *)) {
+ uint64_t id = 0;
+ AHardwareBuffer_getId(mBuffer, &id);
+ return "<HardwareBuffer " + std::to_string(id) + ">";
+ } else {
+ return "<HardwareBuffer (unknown)>";
+ }
}
private:
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 5d23a5ef8d..66e1aa1ca1 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075131
+
adyabr@google.com
alecmouri@google.com
djsollen@google.com
diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
index 3dd534e602..b479400a06 100644
--- a/libs/renderengine/gl/GLExtensions.cpp
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -68,19 +68,19 @@ void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* rende
}
char const* GLExtensions::getVendor() const {
- return mVendor.string();
+ return mVendor.c_str();
}
char const* GLExtensions::getRenderer() const {
- return mRenderer.string();
+ return mRenderer.c_str();
}
char const* GLExtensions::getVersion() const {
- return mVersion.string();
+ return mVersion.c_str();
}
char const* GLExtensions::getExtensions() const {
- return mExtensions.string();
+ return mExtensions.c_str();
}
void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
@@ -127,11 +127,11 @@ void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExt
}
char const* GLExtensions::getEGLVersion() const {
- return mEGLVersion.string();
+ return mEGLVersion.c_str();
}
char const* GLExtensions::getEGLExtensions() const {
- return mEGLExtensions.string();
+ return mEGLExtensions.c_str();
}
} // namespace gl
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 5ff92402dc..b1bfa3a22e 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -62,7 +62,7 @@ public:
return out;
}
friend inline Formatter& operator<<(Formatter& out, const String8& in) {
- return operator<<(out, in.string());
+ return operator<<(out, in.c_str());
}
friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
return (*func)(to);
@@ -797,7 +797,7 @@ std::unique_ptr<Program> ProgramCache::generateProgram(const Key& needs) {
// fragment shader
String8 fs = generateFragmentShader(needs);
- return std::make_unique<Program>(needs, vs.string(), fs.string());
+ return std::make_unique<Program>(needs, vs.c_str(), fs.c_str());
}
void ProgramCache::useProgram(EGLContext context, const Description& description) {
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index b865c4d5d6..1d61805204 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -74,7 +74,7 @@ Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersi
if (hwSensor.maxDelay > INT_MAX) {
// Max delay is declared as a 64 bit integer for 64 bit architectures. But it should
// always fit in a 32 bit integer, log error and cap it to INT_MAX.
- ALOGE("Sensor maxDelay overflow error %s %" PRId64, mName.string(),
+ ALOGE("Sensor maxDelay overflow error %s %" PRId64, mName.c_str(),
static_cast<int64_t>(hwSensor.maxDelay));
mMaxDelay = INT_MAX;
} else {
@@ -339,7 +339,7 @@ Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersi
if (actualReportingMode != expectedReportingMode) {
ALOGE("Reporting Mode incorrect: sensor %s handle=%#010" PRIx32 " type=%" PRId32 " "
"actual=%d expected=%d",
- mName.string(), mHandle, mType, actualReportingMode, expectedReportingMode);
+ mName.c_str(), mHandle, mType, actualReportingMode, expectedReportingMode);
}
}
@@ -617,7 +617,7 @@ void Sensor::flattenString8(void*& buffer, size_t& size,
const String8& string8) {
uint32_t len = static_cast<uint32_t>(string8.length());
FlattenableUtils::write(buffer, size, len);
- memcpy(static_cast<char*>(buffer), string8.string(), len);
+ memcpy(static_cast<char*>(buffer), string8.c_str(), len);
FlattenableUtils::advance(buffer, size, len);
size -= FlattenableUtils::align<4>(buffer);
}
@@ -631,7 +631,7 @@ bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& output
if (size < len) {
return false;
}
- outputString8.setTo(static_cast<char const*>(buffer), len);
+ outputString8 = String8(static_cast<char const*>(buffer), len);
if (size < FlattenableUtils::align<4>(len)) {
ALOGE("Malformed Sensor String8 field. Should be in a 4-byte aligned buffer but is not.");
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 40061cde61..9f814f1c48 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -176,11 +176,8 @@ status_t SensorManager::assertStateLocked() {
mSensors = mSensorServer->getSensorList(mOpPackageName);
size_t count = mSensors.size();
- if (count == 0) {
- ALOGE("Failed to get Sensor list");
- mSensorServer.clear();
- return UNKNOWN_ERROR;
- }
+ // If count is 0, mSensorList will be non-null. This is old
+ // existing behavior and callers expect this.
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 073da89758..8675f14d43 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -304,6 +304,12 @@ std::string decodePixelFormat(android::PixelFormat format) {
return std::string("BGRA_8888");
case android::PIXEL_FORMAT_R_8:
return std::string("R_8");
+ case android::PIXEL_FORMAT_R_16_UINT:
+ return std::string("R_16_UINT");
+ case android::PIXEL_FORMAT_RG_1616_UINT:
+ return std::string("RG_1616_UINT");
+ case android::PIXEL_FORMAT_RGBA_10101010:
+ return std::string("RGBA_10101010");
default:
return StringPrintf("Unknown %#08x", format);
}
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index cc96f83578..4be0a3a9d9 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -115,7 +115,7 @@ sp<Fence> Fence::merge(const char* name, const sp<Fence>& f1,
sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1,
const sp<Fence>& f2) {
- return merge(name.string(), f1, f2);
+ return merge(name.c_str(), f1, f2);
}
int Fence::dup() const {
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
index cb61e6a320..494272b1a8 100644
--- a/libs/ui/include/ui/FatVector.h
+++ b/libs/ui/include/ui/FatVector.h
@@ -65,6 +65,17 @@ public:
free(p);
}
}
+
+ // The STL checks that this member type is present so that
+ // std::allocator_traits<InlineStdAllocator<T, SIZE>>::rebind_alloc<Other>
+ // works. std::vector won't be able to construct an
+ // InlineStdAllocator<Other, SIZE>, because InlineStdAllocator has no
+ // default constructor, but vector presumably doesn't rebind the allocator
+ // because it doesn't allocate internal node types.
+ template <class Other>
+ struct rebind {
+ typedef InlineStdAllocator<Other, SIZE> other;
+ };
Allocation& mAllocation;
};
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 5f441ee84e..4b637dc60b 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -49,6 +49,7 @@
#include "egl_trace.h"
using namespace android;
+using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
// ----------------------------------------------------------------------------
@@ -406,7 +407,7 @@ EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config, EGLint attri
// ----------------------------------------------------------------------------
// Translates EGL color spaces to Android data spaces.
-static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) {
+static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace, PixelFormat pixelFormat) {
if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
return HAL_DATASPACE_UNKNOWN;
} else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
@@ -422,7 +423,13 @@ static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) {
} else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
return HAL_DATASPACE_V0_SCRGB_LINEAR;
} else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) {
- return HAL_DATASPACE_BT2020_LINEAR;
+ if (pixelFormat == PixelFormat::RGBA_FP16) {
+ return static_cast<android_dataspace>(HAL_DATASPACE_STANDARD_BT2020 |
+ HAL_DATASPACE_TRANSFER_LINEAR |
+ HAL_DATASPACE_RANGE_EXTENDED);
+ } else {
+ return HAL_DATASPACE_BT2020_LINEAR;
+ }
} else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) {
return HAL_DATASPACE_BT2020_PQ;
}
@@ -566,8 +573,6 @@ void convertAttribs(const EGLAttrib* attribList, std::vector<EGLint>& newList) {
newList.push_back(EGL_NONE);
}
-using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
-
// Gets the native pixel format corrsponding to the passed EGLConfig.
void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config,
PixelFormat* format) {
@@ -707,7 +712,7 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx,
return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
- android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
+ android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace, format);
// Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN.
// HAL_DATASPACE_UNKNOWN is the default value, but it may have changed
// at this point.
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 7b9782f4e8..9171534ed6 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -107,7 +107,7 @@ status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<Stri
ALOGV("shellCommand");
for (size_t i = 0, n = args.size(); i < n; i++)
- ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string());
+ ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).c_str());
if (args.size() >= 1) {
if (args[0] == String16("vkjson")) return cmdVkjson(out, err);
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
index dd3cc3bd86..141fe021ee 100644
--- a/services/gpuservice/gpumem/GpuMem.cpp
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -77,7 +77,7 @@ void GpuMem::initialize() {
mInitialized.store(true);
}
-void GpuMem::setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
+void GpuMem::setGpuMemTotalMap(bpf::BpfMapRO<uint64_t, uint64_t>& map) {
mGpuMemTotalMap = std::move(map);
}
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
index 7588b54818..9aa74d6863 100644
--- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -44,12 +44,12 @@ private:
friend class TestableGpuMem;
// set gpu memory total map
- void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map);
+ void setGpuMemTotalMap(bpf::BpfMapRO<uint64_t, uint64_t>& map);
// indicate whether ebpf has been initialized
std::atomic<bool> mInitialized = false;
// bpf map for GPU memory total data
- android::bpf::BpfMap<uint64_t, uint64_t> mGpuMemTotalMap;
+ android::bpf::BpfMapRO<uint64_t, uint64_t> mGpuMemTotalMap;
// gpu memory tracepoint event category
static constexpr char kGpuMemTraceGroup[] = "gpu_mem";
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index 8dabe4fbdb..1f5b2889d1 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -66,9 +66,7 @@ public:
mTestableGpuMem = TestableGpuMem(mGpuMem.get());
mTestableGpuMem.setInitialized();
errno = 0;
- mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
- TEST_MAP_SIZE,
- BPF_F_NO_PREALLOC));
+ mTestMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
EXPECT_EQ(0, errno);
EXPECT_TRUE(mTestMap.isValid());
diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
index 5c042102b2..6550df9e58 100644
--- a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
@@ -65,9 +65,7 @@ public:
mTestableGpuMem = TestableGpuMem(mGpuMem.get());
errno = 0;
- mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
- TEST_MAP_SIZE,
- BPF_F_NO_PREALLOC));
+ mTestMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
EXPECT_EQ(0, errno);
EXPECT_TRUE(mTestMap.isValid());
diff --git a/services/gpuservice/tests/unittests/TestableGpuMem.h b/services/gpuservice/tests/unittests/TestableGpuMem.h
index 6c8becb075..f21843fe1a 100644
--- a/services/gpuservice/tests/unittests/TestableGpuMem.h
+++ b/services/gpuservice/tests/unittests/TestableGpuMem.h
@@ -28,7 +28,7 @@ public:
void setInitialized() { mGpuMem->mInitialized.store(true); }
- void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
+ void setGpuMemTotalMap(bpf::BpfMapRO<uint64_t, uint64_t>& map) {
mGpuMem->setGpuMemTotalMap(map);
}
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index 8300e8a3da..032cb6dea3 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -17,10 +17,11 @@
#ifndef _UI_INPUT_BLOCKING_QUEUE_H
#define _UI_INPUT_BLOCKING_QUEUE_H
-#include "android-base/thread_annotations.h"
#include <condition_variable>
+#include <functional>
#include <mutex>
#include <vector>
+#include "android-base/thread_annotations.h"
namespace android {
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
index c88bfe97ca..21d208f577 100644
--- a/services/inputflinger/OWNERS
+++ b/services/inputflinger/OWNERS
@@ -1 +1,2 @@
+# Bug component: 136048
include platform/frameworks/base:/INPUT_OWNERS
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 2ebdbcfcc4..94c839f761 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -259,14 +259,14 @@ input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map,
const char* InputDriver::inputGetPropertyKey(input_property_t* property) {
if (property != nullptr) {
- return property->key.string();
+ return property->key.c_str();
}
return nullptr;
}
const char* InputDriver::inputGetPropertyValue(input_property_t* property) {
if (property != nullptr) {
- return property->value.string();
+ return property->value.c_str();
}
return nullptr;
}
@@ -284,7 +284,7 @@ void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) {
}
void InputDriver::dump(String8& result) {
- result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string());
+ result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.c_str());
}
} // namespace android
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
index 2da2a70c03..d974c43d78 100644
--- a/services/inputflinger/host/InputFlinger.cpp
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -57,7 +57,7 @@ status_t InputFlinger::dump(int fd, const Vector<String16>& args) {
} else {
dumpInternal(result);
}
- write(fd, result.string(), result.size());
+ write(fd, result.c_str(), result.size());
return OK;
}
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index f4f3ae95a1..09b20fd8e1 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -251,7 +251,7 @@ void CursorInputMapper::configureParameters() {
if (cursorModeString == "navigation") {
mParameters.mode = Parameters::Mode::NAVIGATION;
} else if (cursorModeString != "pointer" && cursorModeString != "default") {
- ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
+ ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.c_str());
}
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index ed3b0eccf0..bc1add59d7 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -429,7 +429,7 @@ void TouchInputMapper::configureParameters() {
} else if (gestureModeString == "multi-touch") {
mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH;
} else if (gestureModeString != "default") {
- ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
+ ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str());
}
}
@@ -463,7 +463,7 @@ void TouchInputMapper::configureParameters() {
} else if (deviceTypeString == "pointer") {
mParameters.deviceType = Parameters::DeviceType::POINTER;
} else if (deviceTypeString != "default") {
- ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
+ ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str());
}
}
@@ -484,7 +484,7 @@ void TouchInputMapper::configureParameters() {
} else if (orientationString == "ORIENTATION_270") {
mParameters.orientation = Parameters::Orientation::ORIENTATION_270;
} else if (orientationString != "ORIENTATION_0") {
- ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string());
+ ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str());
}
}
@@ -1204,7 +1204,7 @@ void TouchInputMapper::parseCalibration() {
} else if (sizeCalibrationString == "area") {
out.sizeCalibration = Calibration::SizeCalibration::AREA;
} else if (sizeCalibrationString != "default") {
- ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string());
+ ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str());
}
}
@@ -1224,7 +1224,7 @@ void TouchInputMapper::parseCalibration() {
out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE;
} else if (pressureCalibrationString != "default") {
ALOGW("Invalid value for touch.pressure.calibration: '%s'",
- pressureCalibrationString.string());
+ pressureCalibrationString.c_str());
}
}
@@ -1242,7 +1242,7 @@ void TouchInputMapper::parseCalibration() {
out.orientationCalibration = Calibration::OrientationCalibration::VECTOR;
} else if (orientationCalibrationString != "default") {
ALOGW("Invalid value for touch.orientation.calibration: '%s'",
- orientationCalibrationString.string());
+ orientationCalibrationString.c_str());
}
}
@@ -1256,7 +1256,7 @@ void TouchInputMapper::parseCalibration() {
out.distanceCalibration = Calibration::DistanceCalibration::SCALED;
} else if (distanceCalibrationString != "default") {
ALOGW("Invalid value for touch.distance.calibration: '%s'",
- distanceCalibrationString.string());
+ distanceCalibrationString.c_str());
}
}
@@ -1271,7 +1271,7 @@ void TouchInputMapper::parseCalibration() {
out.coverageCalibration = Calibration::CoverageCalibration::BOX;
} else if (coverageCalibrationString != "default") {
ALOGW("Invalid value for touch.coverage.calibration: '%s'",
- coverageCalibrationString.string());
+ coverageCalibrationString.c_str());
}
}
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 03fbf07b16..ad6cf01340 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2784,7 +2784,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe
String8 propertyValue;
ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue))
<< "Device should have read configuration during configuration phase.";
- ASSERT_STREQ("value", propertyValue.string());
+ ASSERT_STREQ("value", propertyValue.c_str());
ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled());
ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled());
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
index d7ca6e1dbf..47fa8b39ac 100644
--- a/services/sensorservice/RecentEventLogger.cpp
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -83,7 +83,7 @@ std::string RecentEventLogger::dump() const {
}
buffer.append("\n");
}
- return std::string(buffer.string());
+ return std::string(buffer.c_str());
}
/**
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index de050e02d0..184fa7614d 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -299,7 +299,7 @@ std::string SensorDevice::dump() const {
result.appendFormat("}, selected = %.2f ms\n", info.bestBatchParams.mTBatch / 1e6f);
}
- return result.string();
+ return result.c_str();
}
/**
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 2dd12e9446..7548742e28 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -63,7 +63,7 @@ void SensorService::SensorDirectConnection::onFirstRef() {
void SensorService::SensorDirectConnection::dump(String8& result) const {
Mutex::Autolock _l(mConnectionLock);
result.appendFormat("\tPackage %s, HAL channel handle %d, total sensor activated %zu\n",
- String8(mOpPackageName).string(), getHalChannelHandle(), mActivated.size());
+ String8(mOpPackageName).c_str(), getHalChannelHandle(), mActivated.size());
for (auto &i : mActivated) {
result.appendFormat("\t\tSensor %#08x, rate %d\n", i.first, i.second);
}
@@ -79,7 +79,7 @@ void SensorService::SensorDirectConnection::dump(String8& result) const {
void SensorService::SensorDirectConnection::dump(ProtoOutputStream* proto) const {
using namespace service::SensorDirectConnectionProto;
Mutex::Autolock _l(mConnectionLock);
- proto->write(PACKAGE_NAME, std::string(String8(mOpPackageName).string()));
+ proto->write(PACKAGE_NAME, std::string(String8(mOpPackageName).c_str()));
proto->write(HAL_CHANNEL_HANDLE, getHalChannelHandle());
proto->write(NUM_SENSOR_ACTIVATED, int(mActivated.size()));
for (auto &i : mActivated) {
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index f06f9472bd..aa9637719f 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -90,12 +90,12 @@ void SensorService::SensorEventConnection::dump(String8& result) {
result.append("NORMAL\n");
}
result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
- "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
+ "max cache size %d\n", mPackageName.c_str(), mWakeLockRefCount, mUid, mCacheSize,
mMaxCacheSize);
for (auto& it : mSensorInfo) {
const FlushInfo& flushInfo = it.second;
result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n",
- mService->getSensorName(it.first).string(),
+ mService->getSensorName(it.first).c_str(),
it.first,
flushInfo.mFirstFlushPending ? "First flush pending" :
"active",
@@ -131,7 +131,7 @@ void SensorService::SensorEventConnection::dump(util::ProtoOutputStream* proto)
} else {
proto->write(OPERATING_MODE, OP_MODE_NORMAL);
}
- proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+ proto->write(PACKAGE_NAME, std::string(mPackageName.c_str()));
proto->write(WAKE_LOCK_REF_COUNT, int32_t(mWakeLockRefCount));
proto->write(UID, int32_t(mUid));
proto->write(CACHE_SIZE, int32_t(mCacheSize));
@@ -846,7 +846,7 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void*
if (numBytesRead == sizeof(sensors_event_t)) {
if (!mDataInjectionMode) {
ALOGE("Data injected in normal mode, dropping event"
- "package=%s uid=%d", mPackageName.string(), mUid);
+ "package=%s uid=%d", mPackageName.c_str(), mUid);
// Unregister call backs.
return 0;
}
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index e27b52b23e..5c00260008 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -19,6 +19,7 @@
#include "SensorService.h"
#include <android/util/ProtoOutputStream.h>
+#include <cutils/properties.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
namespace android {
@@ -60,10 +61,12 @@ SensorFusion::SensorFusion()
mGyro = uncalibratedGyro;
}
- // 200 Hz for gyro events is a good compromise between precision
- // and power/cpu usage.
- mEstimatedGyroRate = 200;
- mTargetDelayNs = 1000000000LL/mEstimatedGyroRate;
+ // Wearable devices will want to tune this parameter
+ // to 100 (Hz) in device.mk to save some power.
+ int32_t value = property_get_int32(
+ "sensors.aosp_low_power_sensor_fusion.maximum_rate", 200);
+ mEstimatedGyroRate = static_cast<float>(value);
+ mTargetDelayNs = 1000000000LL / mEstimatedGyroRate;
for (int i = 0; i<NUM_FUSION_MODE; ++i) {
mFusions[i].init(i);
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index 85ce0f0018..02f22c5c4a 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -134,12 +134,12 @@ std::string SensorList::dump() const {
"%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32
") | perm: %s | flags: 0x%08x\n",
s.getHandle(),
- s.getName().string(),
- s.getVendor().string(),
+ s.getName().c_str(),
+ s.getVendor().c_str(),
s.getVersion(),
- s.getStringType().string(),
+ s.getStringType().c_str(),
s.getType(),
- s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a",
+ s.getRequiredPermission().size() ? s.getRequiredPermission().c_str() : "n/a",
static_cast<int>(s.getFlags()));
result.append("\t");
@@ -208,7 +208,7 @@ std::string SensorList::dump() const {
}
return true;
});
- return std::string(result.string());
+ return std::string(result.c_str());
}
/**
@@ -225,13 +225,13 @@ void SensorList::dump(util::ProtoOutputStream* proto) const {
forEachSensor([&proto] (const Sensor& s) -> bool {
const uint64_t token = proto->start(SENSORS);
proto->write(HANDLE, s.getHandle());
- proto->write(NAME, std::string(s.getName().string()));
- proto->write(VENDOR, std::string(s.getVendor().string()));
+ proto->write(NAME, std::string(s.getName().c_str()));
+ proto->write(VENDOR, std::string(s.getVendor().c_str()));
proto->write(VERSION, s.getVersion());
- proto->write(STRING_TYPE, std::string(s.getStringType().string()));
+ proto->write(STRING_TYPE, std::string(s.getStringType().c_str()));
proto->write(TYPE, s.getType());
proto->write(REQUIRED_PERMISSION, std::string(s.getRequiredPermission().size() ?
- s.getRequiredPermission().string() : ""));
+ s.getRequiredPermission().c_str() : ""));
proto->write(FLAGS, int(s.getFlags()));
switch (s.getReportingMode()) {
case AREPORTING_MODE_CONTINUOUS:
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index a34a65bbdd..dc9e8215e7 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -93,7 +93,7 @@ public:
using namespace service::SensorRegistrationInfoProto;
proto->write(TIMESTAMP_SEC, int64_t(mRealtimeSec));
proto->write(SENSOR_HANDLE, mSensorHandle);
- proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+ proto->write(PACKAGE_NAME, std::string(mPackageName.c_str()));
proto->write(PID, int32_t(mPid));
proto->write(UID, int32_t(mUid));
proto->write(SAMPLING_RATE_US, mSamplingRateUs);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index e0a4f034cb..3d613596f5 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -472,7 +472,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) {
mCurrentOperatingMode = RESTRICTED;
// temporarily stop all sensor direct report and disable sensors
disableAllSensorsLocked(&connLock);
- mWhiteListedPackage.setTo(String8(args[1]));
+ mWhiteListedPackage = String8(args[1]);
return status_t(NO_ERROR);
} else if (args.size() == 1 && args[0] == String16("enable")) {
// If currently in restricted mode, reset back to NORMAL mode else ignore.
@@ -496,7 +496,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) {
// Re-enable sensors.
dev.enableAllSensors();
}
- mWhiteListedPackage.setTo(String8(args[1]));
+ mWhiteListedPackage = String8(args[1]);
return NO_ERROR;
} else if (mCurrentOperatingMode == DATA_INJECTION) {
// Already in DATA_INJECTION mode. Treat this as a no_op.
@@ -531,13 +531,13 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) {
for (auto&& i : mRecentEvent) {
sp<SensorInterface> s = mSensors.getInterface(i.first);
if (!i.second->isEmpty()) {
- if (privileged || s->getSensor().getRequiredPermission().isEmpty()) {
+ if (privileged || s->getSensor().getRequiredPermission().empty()) {
i.second->setFormat("normal");
} else {
i.second->setFormat("mask_data");
}
// if there is events and sensor does not need special permission.
- result.appendFormat("%s: ", s->getSensor().getName().string());
+ result.appendFormat("%s: ", s->getSensor().getName().c_str());
result.append(i.second->dump().c_str());
}
}
@@ -548,7 +548,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) {
int handle = mActiveSensors.keyAt(i);
if (dev.isSensorActive(handle)) {
result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
- getSensorName(handle).string(),
+ getSensorName(handle).c_str(),
handle,
mActiveSensors.valueAt(i)->getNumConnections());
}
@@ -564,10 +564,10 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) {
result.appendFormat(" NORMAL\n");
break;
case RESTRICTED:
- result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string());
+ result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.c_str());
break;
case DATA_INJECTION:
- result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string());
+ result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.c_str());
}
result.appendFormat("Sensor Privacy: %s\n",
mSensorPrivacyPolicy->isSensorPrivacyEnabled() ? "enabled" : "disabled");
@@ -605,7 +605,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) {
} while(startIndex != currentIndex);
}
}
- write(fd, result.string(), result.size());
+ write(fd, result.c_str(), result.size());
return NO_ERROR;
}
@@ -649,11 +649,11 @@ status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock
for (auto&& i : mRecentEvent) {
sp<SensorInterface> s = mSensors.getInterface(i.first);
if (!i.second->isEmpty()) {
- i.second->setFormat(privileged || s->getSensor().getRequiredPermission().isEmpty() ?
+ i.second->setFormat(privileged || s->getSensor().getRequiredPermission().empty() ?
"normal" : "mask_data");
const uint64_t mToken = proto.start(service::SensorEventsProto::RECENT_EVENTS_LOGS);
proto.write(service::SensorEventsProto::RecentEventsLog::NAME,
- std::string(s->getSensor().getName().string()));
+ std::string(s->getSensor().getName().c_str()));
i.second->dump(&proto);
proto.end(mToken);
}
@@ -667,7 +667,7 @@ status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock
if (dev.isSensorActive(handle)) {
token = proto.start(ACTIVE_SENSORS);
proto.write(service::ActiveSensorProto::NAME,
- std::string(getSensorName(handle).string()));
+ std::string(getSensorName(handle).c_str()));
proto.write(service::ActiveSensorProto::HANDLE, handle);
proto.write(service::ActiveSensorProto::NUM_CONNECTIONS,
int(mActiveSensors.valueAt(i)->getNumConnections()));
@@ -685,11 +685,11 @@ status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock
break;
case RESTRICTED:
proto.write(OPERATING_MODE, OP_MODE_RESTRICTED);
- proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+ proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.c_str()));
break;
case DATA_INJECTION:
proto.write(OPERATING_MODE, OP_MODE_DATA_INJECTION);
- proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+ proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.c_str()));
break;
default:
proto.write(OPERATING_MODE, OP_MODE_UNKNOWN);
@@ -832,8 +832,8 @@ static status_t getUidForPackage(String16 packageName, int userId, /*inout*/uid_
PermissionController pc;
uid = pc.getPackageUid(packageName, 0);
if (uid <= 0) {
- ALOGE("Unknown package: '%s'", String8(packageName).string());
- dprintf(err, "Unknown package: '%s'\n", String8(packageName).string());
+ ALOGE("Unknown package: '%s'", String8(packageName).c_str());
+ dprintf(err, "Unknown package: '%s'\n", String8(packageName).c_str());
return BAD_VALUE;
}
@@ -858,7 +858,7 @@ status_t SensorService::handleSetUidState(Vector<String16>& args, int err) {
if (args[2] == String16("active")) {
active = true;
} else if ((args[2] != String16("idle"))) {
- ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
+ ALOGE("Expected active or idle but got: '%s'", String8(args[2]).c_str());
return BAD_VALUE;
}
@@ -1351,8 +1351,8 @@ Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName
accessibleSensorList.add(sensor);
} else if (sensor.getType() != SENSOR_TYPE_HEAD_TRACKER) {
ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32,
- sensor.getName().string(),
- sensor.getRequiredPermission().string(),
+ sensor.getName().c_str(),
+ sensor.getRequiredPermission().c_str(),
sensor.getRequiredAppOp());
}
}
@@ -1996,10 +1996,10 @@ bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
!isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) {
if (!mHtRestricted) {
ALOGI("Permitting access to HT sensor type outside system (%s)",
- String8(opPackageName).string());
+ String8(opPackageName).c_str());
} else {
- ALOGW("%s %s a sensor (%s) as a non-system client", String8(opPackageName).string(),
- operation, sensor.getName().string());
+ ALOGW("%s %s a sensor (%s) as a non-system client", String8(opPackageName).c_str(),
+ operation, sensor.getName().c_str());
return false;
}
}
@@ -2032,8 +2032,8 @@ bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
}
if (!canAccess) {
- ALOGE("%s %s a sensor (%s) without holding %s", String8(opPackageName).string(),
- operation, sensor.getName().string(), sensor.getRequiredPermission().string());
+ ALOGE("%s %s a sensor (%s) without holding %s", String8(opPackageName).c_str(),
+ operation, sensor.getName().c_str(), sensor.getRequiredPermission().c_str());
}
return canAccess;
@@ -2124,7 +2124,7 @@ void SensorService::sendEventsFromCache(const sp<SensorEventConnection>& connect
}
bool SensorService::isWhiteListedPackage(const String8& packageName) {
- return (packageName.contains(mWhiteListedPackage.string()));
+ return (packageName.contains(mWhiteListedPackage.c_str()));
}
bool SensorService::isOperationRestrictedLocked(const String16& opPackageName) {
diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp
index 9b0334443b..ee4c5f819c 100644
--- a/services/sensorservice/aidl/SensorManager.cpp
+++ b/services/sensorservice/aidl/SensorManager.cpp
@@ -197,6 +197,11 @@ ndk::ScopedAStatus SensorManagerAidl::getSensorList(std::vector<SensorInfo>* _ai
sp<Looper> SensorManagerAidl::getLooper() {
std::lock_guard<std::mutex> lock(mThreadMutex);
+ if (!mJavaVm) {
+ LOG(ERROR) << "No Java VM. This must be running in a test or fuzzer.";
+ return mLooper;
+ }
+
if (!mPollThread.joinable()) {
// if thread not initialized, start thread
mStopThread = false;
diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp
index 5fa594d01d..d338d02675 100644
--- a/services/sensorservice/hidl/utils.cpp
+++ b/services/sensorservice/hidl/utils.cpp
@@ -32,8 +32,8 @@ SensorInfo convertSensor(const Sensor& src) {
SensorInfo dst;
const String8& name = src.getName();
const String8& vendor = src.getVendor();
- dst.name = hidl_string{name.string(), name.size()};
- dst.vendor = hidl_string{vendor.string(), vendor.size()};
+ dst.name = hidl_string{name.c_str(), name.size()};
+ dst.vendor = hidl_string{vendor.c_str(), vendor.size()};
dst.version = src.getVersion();
dst.sensorHandle = src.getHandle();
dst.type = static_cast<::android::hardware::sensors::V1_0::SensorType>(
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index caf7f03361..8b4b3f61b0 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -105,7 +105,7 @@ int main() {
Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
printf("accelerometer=%p (%s)\n",
- accelerometer, accelerometer->getName().string());
+ accelerometer, accelerometer->getName().c_str());
sStartTime = systemTime();
@@ -130,7 +130,7 @@ int main() {
printf("ALOOPER_POLL_TIMEOUT\n");
break;
case ALOOPER_POLL_ERROR:
- printf("ALOOPER_POLL_TIMEOUT\n");
+ printf("ALOOPER_POLL_ERROR\n");
break;
default:
printf("ugh? poll returned %d\n", ret);
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 7361a4fdef..a1035f01bf 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -49,11 +49,11 @@
namespace android {
// Macros for including the BufferLayerConsumer name in log messages
-#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+// #define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
+#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
static const mat4 mtxIdentity;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 11a9e19db8..f12d7b6a17 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -140,18 +140,6 @@ cc_test {
"libgtest",
],
sanitize: {
- // By using the address sanitizer, we not only uncover any issues
- // with the test, but also any issues with the code under test.
- //
- // Note: If you get an runtime link error like:
- //
- // CANNOT LINK EXECUTABLE "/data/local/tmp/libcompositionengine_test": library "libclang_rt.asan-aarch64-android.so" not found
- //
- // it is because the address sanitizer shared objects are not installed
- // by default in the system image.
- //
- // You can either "make dist tests" before flashing, or set this
- // option to false temporarily.
- address: true,
+ hwaddress: true,
},
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index f439caf9e1..8dab6ce61b 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -34,7 +34,7 @@ LayerState::LayerState(compositionengine::OutputLayer* layer)
[](const mat4& mat) {
using namespace std::string_literals;
std::vector<std::string> split =
- base::Split(std::string(mat.asString().string()), "\n"s);
+ base::Split(std::string(mat.asString().c_str()), "\n"s);
split.pop_back(); // Strip the last (empty) line
return split;
}}) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 54133d92b0..5e6cade56f 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -216,32 +216,32 @@ void Planner::dump(const Vector<String16>& args, std::string& result) {
base::StringAppendF(&result,
"Expected two layer stack hashes, e.g. '--planner %s "
"<left_hash> <right_hash>'\n",
- command.string());
+ command.c_str());
return;
}
if (args.size() > 4) {
base::StringAppendF(&result,
"Too many arguments found, expected '--planner %s <left_hash> "
"<right_hash>'\n",
- command.string());
+ command.c_str());
return;
}
const String8 leftHashString(args[2]);
size_t leftHash = 0;
- int fieldsRead = sscanf(leftHashString.string(), "%zx", &leftHash);
+ int fieldsRead = sscanf(leftHashString.c_str(), "%zx", &leftHash);
if (fieldsRead != 1) {
base::StringAppendF(&result, "Failed to parse %s as a size_t\n",
- leftHashString.string());
+ leftHashString.c_str());
return;
}
const String8 rightHashString(args[3]);
size_t rightHash = 0;
- fieldsRead = sscanf(rightHashString.string(), "%zx", &rightHash);
+ fieldsRead = sscanf(rightHashString.c_str(), "%zx", &rightHash);
if (fieldsRead != 1) {
base::StringAppendF(&result, "Failed to parse %s as a size_t\n",
- rightHashString.string());
+ rightHashString.c_str());
return;
}
@@ -252,22 +252,22 @@ void Planner::dump(const Vector<String16>& args, std::string& result) {
if (args.size() < 3) {
base::StringAppendF(&result,
"Expected a layer stack hash, e.g. '--planner %s <hash>'\n",
- command.string());
+ command.c_str());
return;
}
if (args.size() > 3) {
base::StringAppendF(&result,
"Too many arguments found, expected '--planner %s <hash>'\n",
- command.string());
+ command.c_str());
return;
}
const String8 hashString(args[2]);
size_t hash = 0;
- const int fieldsRead = sscanf(hashString.string(), "%zx", &hash);
+ const int fieldsRead = sscanf(hashString.c_str(), "%zx", &hash);
if (fieldsRead != 1) {
base::StringAppendF(&result, "Failed to parse %s as a size_t\n",
- hashString.string());
+ hashString.c_str());
return;
}
@@ -279,20 +279,20 @@ void Planner::dump(const Vector<String16>& args, std::string& result) {
} else if (command == "--similar" || command == "-s") {
if (args.size() < 3) {
base::StringAppendF(&result, "Expected a plan string, e.g. '--planner %s <plan>'\n",
- command.string());
+ command.c_str());
return;
}
if (args.size() > 3) {
base::StringAppendF(&result,
"Too many arguments found, expected '--planner %s <plan>'\n",
- command.string());
+ command.c_str());
return;
}
const String8 planString(args[2]);
- std::optional<Plan> plan = Plan::fromString(std::string(planString.string()));
+ std::optional<Plan> plan = Plan::fromString(std::string(planString.c_str()));
if (!plan) {
- base::StringAppendF(&result, "Failed to parse %s as a Plan\n", planString.string());
+ base::StringAppendF(&result, "Failed to parse %s as a Plan\n", planString.c_str());
return;
}
@@ -302,7 +302,7 @@ void Planner::dump(const Vector<String16>& args, std::string& result) {
} else if (command == "--layers" || command == "-l") {
mFlattener.dumpLayers(result);
} else {
- base::StringAppendF(&result, "Unknown command '%s'\n\n", command.string());
+ base::StringAppendF(&result, "Unknown command '%s'\n\n", command.c_str());
dumpUsage(result);
}
return;
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 4e7da829f2..0aee7d497c 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,6 +1,10 @@
+# Bug component: 1075131
+
adyabr@google.com
alecmouri@google.com
chaviw@google.com
+domlaskowski@google.com
+jreck@google.com
lpy@google.com
pdwilliams@google.com
racarr@google.com
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8c46515bf1..314b4cd57b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5141,7 +5141,7 @@ void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result)
if (args.size() > 1) {
const auto name = String8(args[1]);
mCurrentState.traverseInZOrder([&](Layer* layer) {
- if (layer->getName() == name.string()) {
+ if (layer->getName() == name.c_str()) {
layer->dumpFrameStats(result);
}
});
@@ -5155,7 +5155,7 @@ void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
const auto name = clearAll ? String8() : String8(args[1]);
mCurrentState.traverse([&](Layer* layer) {
- if (clearAll || layer->getName() == name.string()) {
+ if (clearAll || layer->getName() == name.c_str()) {
layer->clearFrameStats();
}
});
@@ -6755,7 +6755,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
if (captureListener) {
// TODO: The future returned by std::async blocks the main thread. Return a chain of
// futures to the Binder thread instead.
- std::async([=]() mutable {
+ (void)std::async([=]() mutable {
ATRACE_NAME("captureListener is nonnull!");
auto fenceResult = renderFuture.get();
// TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult.
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 0782fef8ea..bace6cc6a6 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -559,7 +559,7 @@ void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32
DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
DispSurfaceChange* surfaceChange(dispChange->mutable_surface());
surfaceChange->set_buffer_queue_id(bufferQueueId);
- surfaceChange->set_buffer_queue_name(surface->getConsumerName().string());
+ surfaceChange->set_buffer_queue_name(surface->getConsumerName().c_str());
}
else {
ALOGE("invalid graphic buffer producer received while tracing a display change (%s)",
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 867a1985bd..c679b14d7b 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -278,7 +278,7 @@ private:
// MessageQueue overrides:
void scheduleFrame() override {}
- void postMessage(sp<MessageHandler>&&) override {}
+ void postMessage(sp<MessageHandler>&& handler) override { handler->handleMessage(Message()); }
};
} // namespace scheduler
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 28e8b8c78b..7a98bc27a9 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -359,7 +359,7 @@ void SurfaceInterceptorTest::backgroundBlurRadiusUpdate(Transaction& t) {
}
void SurfaceInterceptorTest::blurRegionsUpdate(Transaction& t) {
- BLUR_REGIONS_UPDATE.empty();
+ BLUR_REGIONS_UPDATE.clear();
BLUR_REGIONS_UPDATE.push_back(BlurRegion());
t.setBlurRegions(mBGSurfaceControl, BLUR_REGIONS_UPDATE);
}
@@ -775,7 +775,7 @@ bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment,
}
bool SurfaceInterceptorTest::displayCreationFound(const Increment& increment, bool foundDisplay) {
- bool isMatch(increment.display_creation().name() == DISPLAY_NAME.string() &&
+ bool isMatch(increment.display_creation().name() == DISPLAY_NAME.c_str() &&
!increment.display_creation().is_secure());
if (isMatch && !foundDisplay) {
foundDisplay = true;
@@ -816,7 +816,7 @@ bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace,
break;
case Increment::IncrementCase::kDisplayDeletion:
// Find the id of created display.
- targetId = getDisplayId(trace, DISPLAY_NAME.string());
+ targetId = getDisplayId(trace, DISPLAY_NAME.c_str());
foundIncrement = displayDeletionFound(increment, targetId, foundIncrement);
break;
default:
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index f7d34ac5da..e20818cd56 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -46,7 +46,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) {
const auto& display = getCurrentDisplayState(displayToken);
EXPECT_TRUE(display.isVirtual());
EXPECT_FALSE(display.isSecure);
- EXPECT_EQ(name.string(), display.displayName);
+ EXPECT_EQ(name.c_str(), display.displayName);
// --------------------------------------------------------------------
// Cleanup conditions
@@ -81,7 +81,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) {
const auto& display = getCurrentDisplayState(displayToken);
EXPECT_TRUE(display.isVirtual());
EXPECT_TRUE(display.isSecure);
- EXPECT_EQ(name.string(), display.displayName);
+ EXPECT_EQ(name.c_str(), display.displayName);
// --------------------------------------------------------------------
// Cleanup conditions
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index f879430db0..b75cf085cb 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -161,7 +161,7 @@ public:
String8 err(String8::format("pixel @ (%3d, %3d): "
"expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
- EXPECT_EQ(String8(), err) << err.string();
+ EXPECT_EQ(String8(), err) << err.c_str();
}
}
diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS
index d073e2bd46..031b333fab 100644
--- a/services/vibratorservice/OWNERS
+++ b/services/vibratorservice/OWNERS
@@ -1 +1,3 @@
+# Bug component: 345036
+
include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 523f890ce7..d0a9da1ff5 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -113,7 +113,7 @@ status_t VirtualTouchpadService::dump(
static_cast<long>(client_pid_));
touchpad_->dumpInternal(result);
}
- write(fd, result.string(), result.size());
+ write(fd, result.c_str(), result.size());
return OK;
}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a99355f047..f92078d8dc 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -747,6 +747,17 @@ void CreateInfoWrapper::FilterExtension(const char* name) {
if (strcmp(name, props.extensionName) != 0)
continue;
+ // Ignore duplicate extensions (see: b/288929054)
+ bool duplicate_entry = false;
+ for (uint32_t j = 0; j < filter.name_count; j++) {
+ if (strcmp(name, filter.names[j]) == 0) {
+ duplicate_entry = true;
+ break;
+ }
+ }
+ if (duplicate_entry == true)
+ continue;
+
filter.names[filter.name_count++] = name;
if (ext_bit != ProcHook::EXTENSION_UNKNOWN) {
if (ext_bit == ProcHook::ANDROID_native_buffer)
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index a14fed222a..d059f8fe4c 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -23,6 +23,7 @@
#include <dlfcn.h>
#include <string.h>
#include <sys/prctl.h>
+#include <unistd.h>
#include <mutex>
#include <string>
@@ -362,6 +363,7 @@ template <typename Functor>
void ForEachFileInZip(const std::string& zipname,
const std::string& dir_in_zip,
Functor functor) {
+ static const size_t kPageSize = getpagesize();
int32_t err;
ZipArchiveHandle zip = nullptr;
if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) {
@@ -389,7 +391,7 @@ void ForEachFileInZip(const std::string& zipname,
// the APK. Loading still may fail for other reasons, but this at least
// lets us avoid failed-to-load log messages in the typical case of
// compressed and/or unaligned libraries.
- if (entry.method != kCompressStored || entry.offset % PAGE_SIZE != 0)
+ if (entry.method != kCompressStored || entry.offset % kPageSize != 0)
continue;
functor(filename);
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index c46036a5e2..570c01eb4b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -16,6 +16,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <android/hardware/graphics/common/1.0/types.h>
#include <grallocusage/GrallocUsageConversion.h>
#include <graphicsenv/GraphicsEnv.h>
@@ -25,8 +26,6 @@
#include <sync/sync.h>
#include <system/window.h>
#include <ui/BufferQueueDefs.h>
-#include <ui/DebugUtils.h>
-#include <ui/PixelFormat.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -37,6 +36,7 @@
#include "driver.h"
+using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
using android::hardware::graphics::common::V1_0::BufferUsage;
namespace vulkan {
@@ -489,27 +489,27 @@ void copy_ready_timings(Swapchain& swapchain,
*count = num_copied;
}
-android::PixelFormat GetNativePixelFormat(VkFormat format) {
- android::PixelFormat native_format = android::PIXEL_FORMAT_RGBA_8888;
+PixelFormat GetNativePixelFormat(VkFormat format) {
+ PixelFormat native_format = PixelFormat::RGBA_8888;
switch (format) {
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SRGB:
- native_format = android::PIXEL_FORMAT_RGBA_8888;
+ native_format = PixelFormat::RGBA_8888;
break;
case VK_FORMAT_R5G6B5_UNORM_PACK16:
- native_format = android::PIXEL_FORMAT_RGB_565;
+ native_format = PixelFormat::RGB_565;
break;
case VK_FORMAT_R16G16B16A16_SFLOAT:
- native_format = android::PIXEL_FORMAT_RGBA_FP16;
+ native_format = PixelFormat::RGBA_FP16;
break;
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
- native_format = android::PIXEL_FORMAT_RGBA_1010102;
+ native_format = PixelFormat::RGBA_1010102;
break;
case VK_FORMAT_R8_UNORM:
- native_format = android::PIXEL_FORMAT_R_8;
+ native_format = PixelFormat::R_8;
break;
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
- native_format = android::PIXEL_FORMAT_RGBA_10101010;
+ native_format = PixelFormat::RGBA_10101010;
break;
default:
ALOGV("unsupported swapchain format %d", format);
@@ -518,7 +518,8 @@ android::PixelFormat GetNativePixelFormat(VkFormat format) {
return native_format;
}
-android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
+android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace,
+ PixelFormat pixelFormat) {
switch (colorspace) {
case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
return HAL_DATASPACE_V0_SRGB;
@@ -537,7 +538,14 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
return HAL_DATASPACE_V0_SRGB;
case VK_COLOR_SPACE_BT2020_LINEAR_EXT:
- return HAL_DATASPACE_BT2020_LINEAR;
+ if (pixelFormat == PixelFormat::RGBA_FP16) {
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_BT2020 |
+ HAL_DATASPACE_TRANSFER_LINEAR |
+ HAL_DATASPACE_RANGE_EXTENDED);
+ } else {
+ return HAL_DATASPACE_BT2020_LINEAR;
+ }
case VK_COLOR_SPACE_HDR10_ST2084_EXT:
return static_cast<android_dataspace>(
HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
@@ -547,9 +555,7 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
HAL_DATASPACE_RANGE_FULL);
case VK_COLOR_SPACE_HDR10_HLG_EXT:
- return static_cast<android_dataspace>(
- HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG |
- HAL_DATASPACE_RANGE_FULL);
+ return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG);
case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
return static_cast<android_dataspace>(
HAL_DATASPACE_STANDARD_ADOBE_RGB |
@@ -1256,10 +1262,10 @@ VkResult CreateSwapchainKHR(VkDevice device,
if (!allocator)
allocator = &GetData(device).allocator;
- android::PixelFormat native_pixel_format =
+ PixelFormat native_pixel_format =
GetNativePixelFormat(create_info->imageFormat);
android_dataspace native_dataspace =
- GetNativeDataspace(create_info->imageColorSpace);
+ GetNativeDataspace(create_info->imageColorSpace, native_pixel_format);
if (native_dataspace == HAL_DATASPACE_UNKNOWN) {
ALOGE(
"CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) "
@@ -1351,10 +1357,11 @@ VkResult CreateSwapchainKHR(VkDevice device,
const auto& dispatch = GetData(device).driver;
- err = native_window_set_buffers_format(window, native_pixel_format);
+ err = native_window_set_buffers_format(
+ window, static_cast<int>(native_pixel_format));
if (err != android::OK) {
ALOGE("native_window_set_buffers_format(%s) failed: %s (%d)",
- decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err);
+ toString(native_pixel_format).c_str(), strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}